Home | History | Annotate | Download | only in x509
      1 /*
      2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.security.x509;
     27 
     28 import java.io.InputStream;
     29 import java.io.OutputStream;
     30 import java.io.IOException;
     31 import java.math.BigInteger;
     32 import java.security.Principal;
     33 import java.security.PublicKey;
     34 import java.security.PrivateKey;
     35 import java.security.Provider;
     36 import java.security.Signature;
     37 import java.security.NoSuchAlgorithmException;
     38 import java.security.InvalidKeyException;
     39 import java.security.NoSuchProviderException;
     40 import java.security.SignatureException;
     41 import java.security.cert.Certificate;
     42 import java.security.cert.X509CRL;
     43 import java.security.cert.X509Certificate;
     44 import java.security.cert.X509CRLEntry;
     45 import java.security.cert.CRLException;
     46 import java.util.*;
     47 
     48 import javax.security.auth.x500.X500Principal;
     49 
     50 import sun.security.provider.X509Factory;
     51 import sun.security.util.*;
     52 import sun.misc.HexDumpEncoder;
     53 
     54 /**
     55  * <p>
     56  * An implementation for X509 CRL (Certificate Revocation List).
     57  * <p>
     58  * The X.509 v2 CRL format is described below in ASN.1:
     59  * <pre>
     60  * CertificateList  ::=  SEQUENCE  {
     61  *     tbsCertList          TBSCertList,
     62  *     signatureAlgorithm   AlgorithmIdentifier,
     63  *     signature            BIT STRING  }
     64  * </pre>
     65  * More information can be found in
     66  * <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
     67  * Public Key Infrastructure Certificate and CRL Profile</a>.
     68  * <p>
     69  * The ASN.1 definition of <code>tbsCertList</code> is:
     70  * <pre>
     71  * TBSCertList  ::=  SEQUENCE  {
     72  *     version                 Version OPTIONAL,
     73  *                             -- if present, must be v2
     74  *     signature               AlgorithmIdentifier,
     75  *     issuer                  Name,
     76  *     thisUpdate              ChoiceOfTime,
     77  *     nextUpdate              ChoiceOfTime OPTIONAL,
     78  *     revokedCertificates     SEQUENCE OF SEQUENCE  {
     79  *         userCertificate         CertificateSerialNumber,
     80  *         revocationDate          ChoiceOfTime,
     81  *         crlEntryExtensions      Extensions OPTIONAL
     82  *                                 -- if present, must be v2
     83  *         }  OPTIONAL,
     84  *     crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
     85  *                                  -- if present, must be v2
     86  *     }
     87  * </pre>
     88  *
     89  * @author Hemma Prafullchandra
     90  * @see X509CRL
     91  */
     92 public class X509CRLImpl extends X509CRL implements DerEncoder {
     93 
     94     // CRL data, and its envelope
     95     private byte[]      signedCRL = null; // DER encoded crl
     96     private byte[]      signature = null; // raw signature bits
     97     private byte[]      tbsCertList = null; // DER encoded "to-be-signed" CRL
     98     private AlgorithmId sigAlgId = null; // sig alg in CRL
     99 
    100     // crl information
    101     private int              version;
    102     private AlgorithmId      infoSigAlgId; // sig alg in "to-be-signed" crl
    103     private X500Name         issuer = null;
    104     private X500Principal    issuerPrincipal = null;
    105     private Date             thisUpdate = null;
    106     private Date             nextUpdate = null;
    107     private Map<X509IssuerSerial,X509CRLEntry> revokedMap = new TreeMap<>();
    108     private List<X509CRLEntry> revokedList = new LinkedList<>();
    109     private CRLExtensions    extensions = null;
    110     private final static boolean isExplicit = true;
    111     private static final long YR_2050 = 2524636800000L;
    112 
    113     private boolean readOnly = false;
    114 
    115     /**
    116      * PublicKey that has previously been used to successfully verify
    117      * the signature of this CRL. Null if the CRL has not
    118      * yet been verified (successfully).
    119      */
    120     private PublicKey verifiedPublicKey;
    121     /**
    122      * If verifiedPublicKey is not null, name of the provider used to
    123      * successfully verify the signature of this CRL, or the
    124      * empty String if no provider was explicitly specified.
    125      */
    126     private String verifiedProvider;
    127 
    128     /**
    129      * Not to be used. As it would lead to cases of uninitialized
    130      * CRL objects.
    131      */
    132     private X509CRLImpl() { }
    133 
    134     /**
    135      * Unmarshals an X.509 CRL from its encoded form, parsing the encoded
    136      * bytes.  This form of constructor is used by agents which
    137      * need to examine and use CRL contents. Note that the buffer
    138      * must include only one CRL, and no "garbage" may be left at
    139      * the end.
    140      *
    141      * @param crlData the encoded bytes, with no trailing padding.
    142      * @exception CRLException on parsing errors.
    143      */
    144     public X509CRLImpl(byte[] crlData) throws CRLException {
    145         try {
    146             parse(new DerValue(crlData));
    147         } catch (IOException e) {
    148             signedCRL = null;
    149             throw new CRLException("Parsing error: " + e.getMessage());
    150         }
    151     }
    152 
    153     /**
    154      * Unmarshals an X.509 CRL from an DER value.
    155      *
    156      * @param val a DER value holding at least one CRL
    157      * @exception CRLException on parsing errors.
    158      */
    159     public X509CRLImpl(DerValue val) throws CRLException {
    160         try {
    161             parse(val);
    162         } catch (IOException e) {
    163             signedCRL = null;
    164             throw new CRLException("Parsing error: " + e.getMessage());
    165         }
    166     }
    167 
    168     /**
    169      * Unmarshals an X.509 CRL from an input stream. Only one CRL
    170      * is expected at the end of the input stream.
    171      *
    172      * @param inStrm an input stream holding at least one CRL
    173      * @exception CRLException on parsing errors.
    174      */
    175     public X509CRLImpl(InputStream inStrm) throws CRLException {
    176         try {
    177             parse(new DerValue(inStrm));
    178         } catch (IOException e) {
    179             signedCRL = null;
    180             throw new CRLException("Parsing error: " + e.getMessage());
    181         }
    182     }
    183 
    184     /**
    185      * Initial CRL constructor, no revoked certs, and no extensions.
    186      *
    187      * @param issuer the name of the CA issuing this CRL.
    188      * @param thisUpdate the Date of this issue.
    189      * @param nextUpdate the Date of the next CRL.
    190      */
    191     public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) {
    192         this.issuer = issuer;
    193         this.thisUpdate = thisDate;
    194         this.nextUpdate = nextDate;
    195     }
    196 
    197     /**
    198      * CRL constructor, revoked certs, no extensions.
    199      *
    200      * @param issuer the name of the CA issuing this CRL.
    201      * @param thisUpdate the Date of this issue.
    202      * @param nextUpdate the Date of the next CRL.
    203      * @param badCerts the array of CRL entries.
    204      *
    205      * @exception CRLException on parsing/construction errors.
    206      */
    207     public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
    208                        X509CRLEntry[] badCerts)
    209         throws CRLException
    210     {
    211         this.issuer = issuer;
    212         this.thisUpdate = thisDate;
    213         this.nextUpdate = nextDate;
    214         if (badCerts != null) {
    215             X500Principal crlIssuer = getIssuerX500Principal();
    216             X500Principal badCertIssuer = crlIssuer;
    217             for (int i = 0; i < badCerts.length; i++) {
    218                 X509CRLEntryImpl badCert = (X509CRLEntryImpl)badCerts[i];
    219                 try {
    220                     badCertIssuer = getCertIssuer(badCert, badCertIssuer);
    221                 } catch (IOException ioe) {
    222                     throw new CRLException(ioe);
    223                 }
    224                 badCert.setCertificateIssuer(crlIssuer, badCertIssuer);
    225                 X509IssuerSerial issuerSerial = new X509IssuerSerial
    226                     (badCertIssuer, badCert.getSerialNumber());
    227                 this.revokedMap.put(issuerSerial, badCert);
    228                 this.revokedList.add(badCert);
    229                 if (badCert.hasExtensions()) {
    230                     this.version = 1;
    231                 }
    232             }
    233         }
    234     }
    235 
    236     /**
    237      * CRL constructor, revoked certs and extensions.
    238      *
    239      * @param issuer the name of the CA issuing this CRL.
    240      * @param thisUpdate the Date of this issue.
    241      * @param nextUpdate the Date of the next CRL.
    242      * @param badCerts the array of CRL entries.
    243      * @param crlExts the CRL extensions.
    244      *
    245      * @exception CRLException on parsing/construction errors.
    246      */
    247     public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
    248                X509CRLEntry[] badCerts, CRLExtensions crlExts)
    249         throws CRLException
    250     {
    251         this(issuer, thisDate, nextDate, badCerts);
    252         if (crlExts != null) {
    253             this.extensions = crlExts;
    254             this.version = 1;
    255         }
    256     }
    257 
    258     /**
    259      * Returned the encoding as an uncloned byte array. Callers must
    260      * guarantee that they neither modify it nor expose it to untrusted
    261      * code.
    262      */
    263     public byte[] getEncodedInternal() throws CRLException {
    264         if (signedCRL == null) {
    265             throw new CRLException("Null CRL to encode");
    266         }
    267         return signedCRL;
    268     }
    269 
    270     /**
    271      * Returns the ASN.1 DER encoded form of this CRL.
    272      *
    273      * @exception CRLException if an encoding error occurs.
    274      */
    275     public byte[] getEncoded() throws CRLException {
    276         return getEncodedInternal().clone();
    277     }
    278 
    279     /**
    280      * Encodes the "to-be-signed" CRL to the OutputStream.
    281      *
    282      * @param out the OutputStream to write to.
    283      * @exception CRLException on encoding errors.
    284      */
    285     public void encodeInfo(OutputStream out) throws CRLException {
    286         try {
    287             DerOutputStream tmp = new DerOutputStream();
    288             DerOutputStream rCerts = new DerOutputStream();
    289             DerOutputStream seq = new DerOutputStream();
    290 
    291             if (version != 0) // v2 crl encode version
    292                 tmp.putInteger(version);
    293             infoSigAlgId.encode(tmp);
    294             if ((version == 0) && (issuer.toString() == null))
    295                 throw new CRLException("Null Issuer DN not allowed in v1 CRL");
    296             issuer.encode(tmp);
    297 
    298             if (thisUpdate.getTime() < YR_2050)
    299                 tmp.putUTCTime(thisUpdate);
    300             else
    301                 tmp.putGeneralizedTime(thisUpdate);
    302 
    303             if (nextUpdate != null) {
    304                 if (nextUpdate.getTime() < YR_2050)
    305                     tmp.putUTCTime(nextUpdate);
    306                 else
    307                     tmp.putGeneralizedTime(nextUpdate);
    308             }
    309 
    310             if (!revokedList.isEmpty()) {
    311                 for (X509CRLEntry entry : revokedList) {
    312                     ((X509CRLEntryImpl)entry).encode(rCerts);
    313                 }
    314                 tmp.write(DerValue.tag_Sequence, rCerts);
    315             }
    316 
    317             if (extensions != null)
    318                 extensions.encode(tmp, isExplicit);
    319 
    320             seq.write(DerValue.tag_Sequence, tmp);
    321 
    322             tbsCertList = seq.toByteArray();
    323             out.write(tbsCertList);
    324         } catch (IOException e) {
    325              throw new CRLException("Encoding error: " + e.getMessage());
    326         }
    327     }
    328 
    329     /**
    330      * Verifies that this CRL was signed using the
    331      * private key that corresponds to the given public key.
    332      *
    333      * @param key the PublicKey used to carry out the verification.
    334      *
    335      * @exception NoSuchAlgorithmException on unsupported signature
    336      * algorithms.
    337      * @exception InvalidKeyException on incorrect key.
    338      * @exception NoSuchProviderException if there's no default provider.
    339      * @exception SignatureException on signature errors.
    340      * @exception CRLException on encoding errors.
    341      */
    342     public void verify(PublicKey key)
    343     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
    344            NoSuchProviderException, SignatureException {
    345         verify(key, "");
    346     }
    347 
    348     /**
    349      * Verifies that this CRL was signed using the
    350      * private key that corresponds to the given public key,
    351      * and that the signature verification was computed by
    352      * the given provider.
    353      *
    354      * @param key the PublicKey used to carry out the verification.
    355      * @param sigProvider the name of the signature provider.
    356      *
    357      * @exception NoSuchAlgorithmException on unsupported signature
    358      * algorithms.
    359      * @exception InvalidKeyException on incorrect key.
    360      * @exception NoSuchProviderException on incorrect provider.
    361      * @exception SignatureException on signature errors.
    362      * @exception CRLException on encoding errors.
    363      */
    364     public synchronized void verify(PublicKey key, String sigProvider)
    365             throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
    366             NoSuchProviderException, SignatureException {
    367 
    368         if (sigProvider == null) {
    369             sigProvider = "";
    370         }
    371         if ((verifiedPublicKey != null) && verifiedPublicKey.equals(key)) {
    372             // this CRL has already been successfully verified using
    373             // this public key. Make sure providers match, too.
    374             if (sigProvider.equals(verifiedProvider)) {
    375                 return;
    376             }
    377         }
    378         if (signedCRL == null) {
    379             throw new CRLException("Uninitialized CRL");
    380         }
    381         Signature   sigVerf = null;
    382         if (sigProvider.length() == 0) {
    383             sigVerf = Signature.getInstance(sigAlgId.getName());
    384         } else {
    385             sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider);
    386         }
    387         sigVerf.initVerify(key);
    388 
    389         if (tbsCertList == null) {
    390             throw new CRLException("Uninitialized CRL");
    391         }
    392 
    393         sigVerf.update(tbsCertList, 0, tbsCertList.length);
    394 
    395         if (!sigVerf.verify(signature)) {
    396             throw new SignatureException("Signature does not match.");
    397         }
    398         verifiedPublicKey = key;
    399         verifiedProvider = sigProvider;
    400     }
    401 
    402     /**
    403      * Verifies that this CRL was signed using the
    404      * private key that corresponds to the given public key,
    405      * and that the signature verification was computed by
    406      * the given provider. Note that the specified Provider object
    407      * does not have to be registered in the provider list.
    408      *
    409      * @param key the PublicKey used to carry out the verification.
    410      * @param sigProvider the signature provider.
    411      *
    412      * @exception NoSuchAlgorithmException on unsupported signature
    413      * algorithms.
    414      * @exception InvalidKeyException on incorrect key.
    415      * @exception SignatureException on signature errors.
    416      * @exception CRLException on encoding errors.
    417      */
    418     public synchronized void verify(PublicKey key, Provider sigProvider)
    419             throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
    420             SignatureException {
    421 
    422         if (signedCRL == null) {
    423             throw new CRLException("Uninitialized CRL");
    424         }
    425         Signature sigVerf = null;
    426         if (sigProvider == null) {
    427             sigVerf = Signature.getInstance(sigAlgId.getName());
    428         } else {
    429             sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider);
    430         }
    431         sigVerf.initVerify(key);
    432 
    433         if (tbsCertList == null) {
    434             throw new CRLException("Uninitialized CRL");
    435         }
    436 
    437         sigVerf.update(tbsCertList, 0, tbsCertList.length);
    438 
    439         if (!sigVerf.verify(signature)) {
    440             throw new SignatureException("Signature does not match.");
    441         }
    442         verifiedPublicKey = key;
    443     }
    444 
    445     /**
    446      * This static method is the default implementation of the
    447      * verify(PublicKey key, Provider sigProvider) method in X509CRL.
    448      * Called from java.security.cert.X509CRL.verify(PublicKey key,
    449      * Provider sigProvider)
    450      */
    451     // BEGIN Android-removed
    452     // TODO(31294527): in its only usage (the one mentioned in the javadoc) it causes an infinite
    453     // loop. Then, the caller has been modified to throw UnsupportedOperationException.
    454     /*
    455     public static void verify(X509CRL crl, PublicKey key,
    456             Provider sigProvider) throws CRLException,
    457             NoSuchAlgorithmException, InvalidKeyException, SignatureException {
    458         crl.verify(key, sigProvider);
    459     }
    460     */
    461     // END Android-removed
    462 
    463     /**
    464      * Encodes an X.509 CRL, and signs it using the given key.
    465      *
    466      * @param key the private key used for signing.
    467      * @param algorithm the name of the signature algorithm used.
    468      *
    469      * @exception NoSuchAlgorithmException on unsupported signature
    470      * algorithms.
    471      * @exception InvalidKeyException on incorrect key.
    472      * @exception NoSuchProviderException on incorrect provider.
    473      * @exception SignatureException on signature errors.
    474      * @exception CRLException if any mandatory data was omitted.
    475      */
    476     public void sign(PrivateKey key, String algorithm)
    477     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
    478         NoSuchProviderException, SignatureException {
    479         sign(key, algorithm, null);
    480     }
    481 
    482     /**
    483      * Encodes an X.509 CRL, and signs it using the given key.
    484      *
    485      * @param key the private key used for signing.
    486      * @param algorithm the name of the signature algorithm used.
    487      * @param provider the name of the provider.
    488      *
    489      * @exception NoSuchAlgorithmException on unsupported signature
    490      * algorithms.
    491      * @exception InvalidKeyException on incorrect key.
    492      * @exception NoSuchProviderException on incorrect provider.
    493      * @exception SignatureException on signature errors.
    494      * @exception CRLException if any mandatory data was omitted.
    495      */
    496     public void sign(PrivateKey key, String algorithm, String provider)
    497     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
    498         NoSuchProviderException, SignatureException {
    499         try {
    500             if (readOnly)
    501                 throw new CRLException("cannot over-write existing CRL");
    502             Signature sigEngine = null;
    503             if ((provider == null) || (provider.length() == 0))
    504                 sigEngine = Signature.getInstance(algorithm);
    505             else
    506                 sigEngine = Signature.getInstance(algorithm, provider);
    507 
    508             sigEngine.initSign(key);
    509 
    510                                 // in case the name is reset
    511             sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
    512             infoSigAlgId = sigAlgId;
    513 
    514             DerOutputStream out = new DerOutputStream();
    515             DerOutputStream tmp = new DerOutputStream();
    516 
    517             // encode crl info
    518             encodeInfo(tmp);
    519 
    520             // encode algorithm identifier
    521             sigAlgId.encode(tmp);
    522 
    523             // Create and encode the signature itself.
    524             sigEngine.update(tbsCertList, 0, tbsCertList.length);
    525             signature = sigEngine.sign();
    526             tmp.putBitString(signature);
    527 
    528             // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
    529             out.write(DerValue.tag_Sequence, tmp);
    530             signedCRL = out.toByteArray();
    531             readOnly = true;
    532 
    533         } catch (IOException e) {
    534             throw new CRLException("Error while encoding data: " +
    535                                    e.getMessage());
    536         }
    537     }
    538 
    539     /**
    540      * Returns a printable string of this CRL.
    541      *
    542      * @return value of this CRL in a printable form.
    543      */
    544     public String toString() {
    545         StringBuffer sb = new StringBuffer();
    546         sb.append("X.509 CRL v" + (version+1) + "\n");
    547         if (sigAlgId != null)
    548             sb.append("Signature Algorithm: " + sigAlgId.toString() +
    549                   ", OID=" + (sigAlgId.getOID()).toString() + "\n");
    550         if (issuer != null)
    551             sb.append("Issuer: " + issuer.toString() + "\n");
    552         if (thisUpdate != null)
    553             sb.append("\nThis Update: " + thisUpdate.toString() + "\n");
    554         if (nextUpdate != null)
    555             sb.append("Next Update: " + nextUpdate.toString() + "\n");
    556         if (revokedList.isEmpty())
    557             sb.append("\nNO certificates have been revoked\n");
    558         else {
    559             sb.append("\nRevoked Certificates: " + revokedList.size());
    560             int i = 1;
    561             for (X509CRLEntry entry: revokedList) {
    562                 sb.append("\n[" + i++ + "] " + entry.toString());
    563             }
    564         }
    565         if (extensions != null) {
    566             Collection<Extension> allExts = extensions.getAllExtensions();
    567             Object[] objs = allExts.toArray();
    568             sb.append("\nCRL Extensions: " + objs.length);
    569             for (int i = 0; i < objs.length; i++) {
    570                 sb.append("\n[" + (i+1) + "]: ");
    571                 Extension ext = (Extension)objs[i];
    572                 try {
    573                    if (OIDMap.getClass(ext.getExtensionId()) == null) {
    574                        sb.append(ext.toString());
    575                        byte[] extValue = ext.getExtensionValue();
    576                        if (extValue != null) {
    577                            DerOutputStream out = new DerOutputStream();
    578                            out.putOctetString(extValue);
    579                            extValue = out.toByteArray();
    580                            HexDumpEncoder enc = new HexDumpEncoder();
    581                            sb.append("Extension unknown: "
    582                                      + "DER encoded OCTET string =\n"
    583                                      + enc.encodeBuffer(extValue) + "\n");
    584                       }
    585                    } else
    586                        sb.append(ext.toString()); // sub-class exists
    587                 } catch (Exception e) {
    588                     sb.append(", Error parsing this extension");
    589                 }
    590             }
    591         }
    592         if (signature != null) {
    593             HexDumpEncoder encoder = new HexDumpEncoder();
    594             sb.append("\nSignature:\n" + encoder.encodeBuffer(signature)
    595                       + "\n");
    596         } else
    597             sb.append("NOT signed yet\n");
    598         return sb.toString();
    599     }
    600 
    601     /**
    602      * Checks whether the given certificate is on this CRL.
    603      *
    604      * @param cert the certificate to check for.
    605      * @return true if the given certificate is on this CRL,
    606      * false otherwise.
    607      */
    608     public boolean isRevoked(Certificate cert) {
    609         if (revokedMap.isEmpty() || (!(cert instanceof X509Certificate))) {
    610             return false;
    611         }
    612         X509Certificate xcert = (X509Certificate) cert;
    613         X509IssuerSerial issuerSerial = new X509IssuerSerial(xcert);
    614         return revokedMap.containsKey(issuerSerial);
    615     }
    616 
    617     /**
    618      * Gets the version number from this CRL.
    619      * The ASN.1 definition for this is:
    620      * <pre>
    621      * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
    622      *             -- v3 does not apply to CRLs but appears for consistency
    623      *             -- with definition of Version for certs
    624      * </pre>
    625      * @return the version number, i.e. 1 or 2.
    626      */
    627     public int getVersion() {
    628         return version+1;
    629     }
    630 
    631     /**
    632      * Gets the issuer distinguished name from this CRL.
    633      * The issuer name identifies the entity who has signed (and
    634      * issued the CRL). The issuer name field contains an
    635      * X.500 distinguished name (DN).
    636      * The ASN.1 definition for this is:
    637      * <pre>
    638      * issuer    Name
    639      *
    640      * Name ::= CHOICE { RDNSequence }
    641      * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
    642      * RelativeDistinguishedName ::=
    643      *     SET OF AttributeValueAssertion
    644      *
    645      * AttributeValueAssertion ::= SEQUENCE {
    646      *                               AttributeType,
    647      *                               AttributeValue }
    648      * AttributeType ::= OBJECT IDENTIFIER
    649      * AttributeValue ::= ANY
    650      * </pre>
    651      * The Name describes a hierarchical name composed of attributes,
    652      * such as country name, and corresponding values, such as US.
    653      * The type of the component AttributeValue is determined by the
    654      * AttributeType; in general it will be a directoryString.
    655      * A directoryString is usually one of PrintableString,
    656      * TeletexString or UniversalString.
    657      * @return the issuer name.
    658      */
    659     public Principal getIssuerDN() {
    660         return (Principal)issuer;
    661     }
    662 
    663     /**
    664      * Return the issuer as X500Principal. Overrides method in X509CRL
    665      * to provide a slightly more efficient version.
    666      */
    667     public X500Principal getIssuerX500Principal() {
    668         if (issuerPrincipal == null) {
    669             issuerPrincipal = issuer.asX500Principal();
    670         }
    671         return issuerPrincipal;
    672     }
    673 
    674     /**
    675      * Gets the thisUpdate date from the CRL.
    676      * The ASN.1 definition for this is:
    677      *
    678      * @return the thisUpdate date from the CRL.
    679      */
    680     public Date getThisUpdate() {
    681         return (new Date(thisUpdate.getTime()));
    682     }
    683 
    684     /**
    685      * Gets the nextUpdate date from the CRL.
    686      *
    687      * @return the nextUpdate date from the CRL, or null if
    688      * not present.
    689      */
    690     public Date getNextUpdate() {
    691         if (nextUpdate == null)
    692             return null;
    693         return (new Date(nextUpdate.getTime()));
    694     }
    695 
    696     /**
    697      * Gets the CRL entry with the given serial number from this CRL.
    698      *
    699      * @return the entry with the given serial number, or <code>null</code> if
    700      * no such entry exists in the CRL.
    701      * @see X509CRLEntry
    702      */
    703     public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
    704         if (revokedMap.isEmpty()) {
    705             return null;
    706         }
    707         // assume this is a direct CRL entry (cert and CRL issuer are the same)
    708         X509IssuerSerial issuerSerial = new X509IssuerSerial
    709             (getIssuerX500Principal(), serialNumber);
    710         return revokedMap.get(issuerSerial);
    711     }
    712 
    713     /**
    714      * Gets the CRL entry for the given certificate.
    715      */
    716     public X509CRLEntry getRevokedCertificate(X509Certificate cert) {
    717         if (revokedMap.isEmpty()) {
    718             return null;
    719         }
    720         X509IssuerSerial issuerSerial = new X509IssuerSerial(cert);
    721         return revokedMap.get(issuerSerial);
    722     }
    723 
    724     /**
    725      * Gets all the revoked certificates from the CRL.
    726      * A Set of X509CRLEntry.
    727      *
    728      * @return all the revoked certificates or <code>null</code> if there are
    729      * none.
    730      * @see X509CRLEntry
    731      */
    732     public Set<X509CRLEntry> getRevokedCertificates() {
    733         if (revokedList.isEmpty()) {
    734             return null;
    735         } else {
    736             return new TreeSet<X509CRLEntry>(revokedList);
    737         }
    738     }
    739 
    740     /**
    741      * Gets the DER encoded CRL information, the
    742      * <code>tbsCertList</code> from this CRL.
    743      * This can be used to verify the signature independently.
    744      *
    745      * @return the DER encoded CRL information.
    746      * @exception CRLException on encoding errors.
    747      */
    748     public byte[] getTBSCertList() throws CRLException {
    749         if (tbsCertList == null)
    750             throw new CRLException("Uninitialized CRL");
    751         return tbsCertList.clone();
    752     }
    753 
    754     /**
    755      * Gets the raw Signature bits from the CRL.
    756      *
    757      * @return the signature.
    758      */
    759     public byte[] getSignature() {
    760         if (signature == null)
    761             return null;
    762         return signature.clone();
    763     }
    764 
    765     /**
    766      * Gets the signature algorithm name for the CRL
    767      * signature algorithm. For example, the string "SHA1withDSA".
    768      * The ASN.1 definition for this is:
    769      * <pre>
    770      * AlgorithmIdentifier  ::=  SEQUENCE  {
    771      *     algorithm               OBJECT IDENTIFIER,
    772      *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
    773      *                             -- contains a value of the type
    774      *                             -- registered for use with the
    775      *                             -- algorithm object identifier value
    776      * </pre>
    777      *
    778      * @return the signature algorithm name.
    779      */
    780     public String getSigAlgName() {
    781         if (sigAlgId == null)
    782             return null;
    783         return sigAlgId.getName();
    784     }
    785 
    786     /**
    787      * Gets the signature algorithm OID string from the CRL.
    788      * An OID is represented by a set of positive whole number separated
    789      * by ".", that means,<br>
    790      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
    791      * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
    792      * with DSA signature algorithm defined in
    793      * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
    794      * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
    795      * and CRL Profile</a>.
    796      *
    797      * @return the signature algorithm oid string.
    798      */
    799     public String getSigAlgOID() {
    800         if (sigAlgId == null)
    801             return null;
    802         ObjectIdentifier oid = sigAlgId.getOID();
    803         return oid.toString();
    804     }
    805 
    806     /**
    807      * Gets the DER encoded signature algorithm parameters from this
    808      * CRL's signature algorithm. In most cases, the signature
    809      * algorithm parameters are null, the parameters are usually
    810      * supplied with the Public Key.
    811      *
    812      * @return the DER encoded signature algorithm parameters, or
    813      *         null if no parameters are present.
    814      */
    815     public byte[] getSigAlgParams() {
    816         if (sigAlgId == null)
    817             return null;
    818         try {
    819             return sigAlgId.getEncodedParams();
    820         } catch (IOException e) {
    821             return null;
    822         }
    823     }
    824 
    825     /**
    826      * Gets the signature AlgorithmId from the CRL.
    827      *
    828      * @return the signature AlgorithmId
    829      */
    830     public AlgorithmId getSigAlgId() {
    831         return sigAlgId;
    832     }
    833 
    834     /**
    835      * return the AuthorityKeyIdentifier, if any.
    836      *
    837      * @returns AuthorityKeyIdentifier or null
    838      *          (if no AuthorityKeyIdentifierExtension)
    839      * @throws IOException on error
    840      */
    841     public KeyIdentifier getAuthKeyId() throws IOException {
    842         AuthorityKeyIdentifierExtension aki = getAuthKeyIdExtension();
    843         if (aki != null) {
    844             KeyIdentifier keyId = (KeyIdentifier)aki.get(
    845                     AuthorityKeyIdentifierExtension.KEY_ID);
    846             return keyId;
    847         } else {
    848             return null;
    849         }
    850     }
    851 
    852     /**
    853      * return the AuthorityKeyIdentifierExtension, if any.
    854      *
    855      * @returns AuthorityKeyIdentifierExtension or null (if no such extension)
    856      * @throws IOException on error
    857      */
    858     public AuthorityKeyIdentifierExtension getAuthKeyIdExtension()
    859         throws IOException {
    860         Object obj = getExtension(PKIXExtensions.AuthorityKey_Id);
    861         return (AuthorityKeyIdentifierExtension)obj;
    862     }
    863 
    864     /**
    865      * return the CRLNumberExtension, if any.
    866      *
    867      * @returns CRLNumberExtension or null (if no such extension)
    868      * @throws IOException on error
    869      */
    870     public CRLNumberExtension getCRLNumberExtension() throws IOException {
    871         Object obj = getExtension(PKIXExtensions.CRLNumber_Id);
    872         return (CRLNumberExtension)obj;
    873     }
    874 
    875     /**
    876      * return the CRL number from the CRLNumberExtension, if any.
    877      *
    878      * @returns number or null (if no such extension)
    879      * @throws IOException on error
    880      */
    881     public BigInteger getCRLNumber() throws IOException {
    882         CRLNumberExtension numExt = getCRLNumberExtension();
    883         if (numExt != null) {
    884             BigInteger num = numExt.get(CRLNumberExtension.NUMBER);
    885             return num;
    886         } else {
    887             return null;
    888         }
    889     }
    890 
    891     /**
    892      * return the DeltaCRLIndicatorExtension, if any.
    893      *
    894      * @returns DeltaCRLIndicatorExtension or null (if no such extension)
    895      * @throws IOException on error
    896      */
    897     public DeltaCRLIndicatorExtension getDeltaCRLIndicatorExtension()
    898         throws IOException {
    899 
    900         Object obj = getExtension(PKIXExtensions.DeltaCRLIndicator_Id);
    901         return (DeltaCRLIndicatorExtension)obj;
    902     }
    903 
    904     /**
    905      * return the base CRL number from the DeltaCRLIndicatorExtension, if any.
    906      *
    907      * @returns number or null (if no such extension)
    908      * @throws IOException on error
    909      */
    910     public BigInteger getBaseCRLNumber() throws IOException {
    911         DeltaCRLIndicatorExtension dciExt = getDeltaCRLIndicatorExtension();
    912         if (dciExt != null) {
    913             BigInteger num = dciExt.get(DeltaCRLIndicatorExtension.NUMBER);
    914             return num;
    915         } else {
    916             return null;
    917         }
    918     }
    919 
    920     /**
    921      * return the IssuerAlternativeNameExtension, if any.
    922      *
    923      * @returns IssuerAlternativeNameExtension or null (if no such extension)
    924      * @throws IOException on error
    925      */
    926     public IssuerAlternativeNameExtension getIssuerAltNameExtension()
    927         throws IOException {
    928         Object obj = getExtension(PKIXExtensions.IssuerAlternativeName_Id);
    929         return (IssuerAlternativeNameExtension)obj;
    930     }
    931 
    932     /**
    933      * return the IssuingDistributionPointExtension, if any.
    934      *
    935      * @returns IssuingDistributionPointExtension or null
    936      *          (if no such extension)
    937      * @throws IOException on error
    938      */
    939     public IssuingDistributionPointExtension
    940         getIssuingDistributionPointExtension() throws IOException {
    941 
    942         Object obj = getExtension(PKIXExtensions.IssuingDistributionPoint_Id);
    943         return (IssuingDistributionPointExtension) obj;
    944     }
    945 
    946     /**
    947      * Return true if a critical extension is found that is
    948      * not supported, otherwise return false.
    949      */
    950     public boolean hasUnsupportedCriticalExtension() {
    951         if (extensions == null)
    952             return false;
    953         return extensions.hasUnsupportedCriticalExtension();
    954     }
    955 
    956     /**
    957      * Gets a Set of the extension(s) marked CRITICAL in the
    958      * CRL. In the returned set, each extension is represented by
    959      * its OID string.
    960      *
    961      * @return a set of the extension oid strings in the
    962      * CRL that are marked critical.
    963      */
    964     public Set<String> getCriticalExtensionOIDs() {
    965         if (extensions == null) {
    966             return null;
    967         }
    968         Set<String> extSet = new TreeSet<>();
    969         for (Extension ex : extensions.getAllExtensions()) {
    970             if (ex.isCritical()) {
    971                 extSet.add(ex.getExtensionId().toString());
    972             }
    973         }
    974         return extSet;
    975     }
    976 
    977     /**
    978      * Gets a Set of the extension(s) marked NON-CRITICAL in the
    979      * CRL. In the returned set, each extension is represented by
    980      * its OID string.
    981      *
    982      * @return a set of the extension oid strings in the
    983      * CRL that are NOT marked critical.
    984      */
    985     public Set<String> getNonCriticalExtensionOIDs() {
    986         if (extensions == null) {
    987             return null;
    988         }
    989         Set<String> extSet = new TreeSet<>();
    990         for (Extension ex : extensions.getAllExtensions()) {
    991             if (!ex.isCritical()) {
    992                 extSet.add(ex.getExtensionId().toString());
    993             }
    994         }
    995         return extSet;
    996     }
    997 
    998     /**
    999      * Gets the DER encoded OCTET string for the extension value
   1000      * (<code>extnValue</code>) identified by the passed in oid String.
   1001      * The <code>oid</code> string is
   1002      * represented by a set of positive whole number separated
   1003      * by ".", that means,<br>
   1004      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
   1005      *
   1006      * @param oid the Object Identifier value for the extension.
   1007      * @return the der encoded octet string of the extension value.
   1008      */
   1009     public byte[] getExtensionValue(String oid) {
   1010         if (extensions == null)
   1011             return null;
   1012         try {
   1013             String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
   1014             Extension crlExt = null;
   1015 
   1016             if (extAlias == null) { // may be unknown
   1017                 ObjectIdentifier findOID = new ObjectIdentifier(oid);
   1018                 Extension ex = null;
   1019                 ObjectIdentifier inCertOID;
   1020                 for (Enumeration<Extension> e = extensions.getElements();
   1021                                                  e.hasMoreElements();) {
   1022                     ex = e.nextElement();
   1023                     inCertOID = ex.getExtensionId();
   1024                     if (inCertOID.equals((Object)findOID)) {
   1025                         crlExt = ex;
   1026                         break;
   1027                     }
   1028                 }
   1029             } else
   1030                 crlExt = extensions.get(extAlias);
   1031             if (crlExt == null)
   1032                 return null;
   1033             byte[] extData = crlExt.getExtensionValue();
   1034             if (extData == null)
   1035                 return null;
   1036             DerOutputStream out = new DerOutputStream();
   1037             out.putOctetString(extData);
   1038             return out.toByteArray();
   1039         } catch (Exception e) {
   1040             return null;
   1041         }
   1042     }
   1043 
   1044     /**
   1045      * get an extension
   1046      *
   1047      * @param oid ObjectIdentifier of extension desired
   1048      * @returns Object of type <extension> or null, if not found
   1049      * @throws IOException on error
   1050      */
   1051     public Object getExtension(ObjectIdentifier oid) {
   1052         if (extensions == null)
   1053             return null;
   1054 
   1055         // XXX Consider cloning this
   1056         return extensions.get(OIDMap.getName(oid));
   1057     }
   1058 
   1059     /*
   1060      * Parses an X.509 CRL, should be used only by constructors.
   1061      */
   1062     private void parse(DerValue val) throws CRLException, IOException {
   1063         // check if can over write the certificate
   1064         if (readOnly)
   1065             throw new CRLException("cannot over-write existing CRL");
   1066 
   1067         if ( val.getData() == null || val.tag != DerValue.tag_Sequence)
   1068             throw new CRLException("Invalid DER-encoded CRL data");
   1069 
   1070         signedCRL = val.toByteArray();
   1071         DerValue seq[] = new DerValue[3];
   1072 
   1073         seq[0] = val.data.getDerValue();
   1074         seq[1] = val.data.getDerValue();
   1075         seq[2] = val.data.getDerValue();
   1076 
   1077         if (val.data.available() != 0)
   1078             throw new CRLException("signed overrun, bytes = "
   1079                                      + val.data.available());
   1080 
   1081         if (seq[0].tag != DerValue.tag_Sequence)
   1082             throw new CRLException("signed CRL fields invalid");
   1083 
   1084         sigAlgId = AlgorithmId.parse(seq[1]);
   1085         signature = seq[2].getBitString();
   1086 
   1087         if (seq[1].data.available() != 0)
   1088             throw new CRLException("AlgorithmId field overrun");
   1089 
   1090         if (seq[2].data.available() != 0)
   1091             throw new CRLException("Signature field overrun");
   1092 
   1093         // the tbsCertsList
   1094         tbsCertList = seq[0].toByteArray();
   1095 
   1096         // parse the information
   1097         DerInputStream derStrm = seq[0].data;
   1098         DerValue       tmp;
   1099         byte           nextByte;
   1100 
   1101         // version (optional if v1)
   1102         version = 0;   // by default, version = v1 == 0
   1103         nextByte = (byte)derStrm.peekByte();
   1104         if (nextByte == DerValue.tag_Integer) {
   1105             version = derStrm.getInteger();
   1106             if (version != 1)  // i.e. v2
   1107                 throw new CRLException("Invalid version");
   1108         }
   1109         tmp = derStrm.getDerValue();
   1110 
   1111         // signature
   1112         AlgorithmId tmpId = AlgorithmId.parse(tmp);
   1113 
   1114         // the "inner" and "outer" signature algorithms must match
   1115         if (! tmpId.equals(sigAlgId))
   1116             throw new CRLException("Signature algorithm mismatch");
   1117         infoSigAlgId = tmpId;
   1118 
   1119         // issuer
   1120         issuer = new X500Name(derStrm);
   1121         if (issuer.isEmpty()) {
   1122             throw new CRLException("Empty issuer DN not allowed in X509CRLs");
   1123         }
   1124 
   1125         // thisUpdate
   1126         // check if UTCTime encoded or GeneralizedTime
   1127 
   1128         nextByte = (byte)derStrm.peekByte();
   1129         if (nextByte == DerValue.tag_UtcTime) {
   1130             thisUpdate = derStrm.getUTCTime();
   1131         } else if (nextByte == DerValue.tag_GeneralizedTime) {
   1132             thisUpdate = derStrm.getGeneralizedTime();
   1133         } else {
   1134             throw new CRLException("Invalid encoding for thisUpdate"
   1135                                    + " (tag=" + nextByte + ")");
   1136         }
   1137 
   1138         if (derStrm.available() == 0)
   1139            return;     // done parsing no more optional fields present
   1140 
   1141         // nextUpdate (optional)
   1142         nextByte = (byte)derStrm.peekByte();
   1143         if (nextByte == DerValue.tag_UtcTime) {
   1144             nextUpdate = derStrm.getUTCTime();
   1145         } else if (nextByte == DerValue.tag_GeneralizedTime) {
   1146             nextUpdate = derStrm.getGeneralizedTime();
   1147         } // else it is not present
   1148 
   1149         if (derStrm.available() == 0)
   1150             return;     // done parsing no more optional fields present
   1151 
   1152         // revokedCertificates (optional)
   1153         nextByte = (byte)derStrm.peekByte();
   1154         if ((nextByte == DerValue.tag_SequenceOf)
   1155             && (! ((nextByte & 0x0c0) == 0x080))) {
   1156             DerValue[] badCerts = derStrm.getSequence(4);
   1157 
   1158             X500Principal crlIssuer = getIssuerX500Principal();
   1159             X500Principal badCertIssuer = crlIssuer;
   1160             for (int i = 0; i < badCerts.length; i++) {
   1161                 X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
   1162                 badCertIssuer = getCertIssuer(entry, badCertIssuer);
   1163                 entry.setCertificateIssuer(crlIssuer, badCertIssuer);
   1164                 X509IssuerSerial issuerSerial = new X509IssuerSerial
   1165                     (badCertIssuer, entry.getSerialNumber());
   1166                 revokedMap.put(issuerSerial, entry);
   1167                 revokedList.add(entry);
   1168             }
   1169         }
   1170 
   1171         if (derStrm.available() == 0)
   1172             return;     // done parsing no extensions
   1173 
   1174         // crlExtensions (optional)
   1175         tmp = derStrm.getDerValue();
   1176         if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
   1177             extensions = new CRLExtensions(tmp.data);
   1178         }
   1179         readOnly = true;
   1180     }
   1181 
   1182     /**
   1183      * Extract the issuer X500Principal from an X509CRL. Parses the encoded
   1184      * form of the CRL to preserve the principal's ASN.1 encoding.
   1185      *
   1186      * Called by java.security.cert.X509CRL.getIssuerX500Principal().
   1187      */
   1188     public static X500Principal getIssuerX500Principal(X509CRL crl) {
   1189         try {
   1190             byte[] encoded = crl.getEncoded();
   1191             DerInputStream derIn = new DerInputStream(encoded);
   1192             DerValue tbsCert = derIn.getSequence(3)[0];
   1193             DerInputStream tbsIn = tbsCert.data;
   1194 
   1195             DerValue tmp;
   1196             // skip version number if present
   1197             byte nextByte = (byte)tbsIn.peekByte();
   1198             if (nextByte == DerValue.tag_Integer) {
   1199                 tmp = tbsIn.getDerValue();
   1200             }
   1201 
   1202             tmp = tbsIn.getDerValue();  // skip signature
   1203             tmp = tbsIn.getDerValue();  // issuer
   1204             byte[] principalBytes = tmp.toByteArray();
   1205             return new X500Principal(principalBytes);
   1206         } catch (Exception e) {
   1207             throw new RuntimeException("Could not parse issuer", e);
   1208         }
   1209     }
   1210 
   1211     /**
   1212      * Returned the encoding of the given certificate for internal use.
   1213      * Callers must guarantee that they neither modify it nor expose it
   1214      * to untrusted code. Uses getEncodedInternal() if the certificate
   1215      * is instance of X509CertImpl, getEncoded() otherwise.
   1216      */
   1217     public static byte[] getEncodedInternal(X509CRL crl) throws CRLException {
   1218         if (crl instanceof X509CRLImpl) {
   1219             return ((X509CRLImpl)crl).getEncodedInternal();
   1220         } else {
   1221             return crl.getEncoded();
   1222         }
   1223     }
   1224 
   1225     /**
   1226      * Utility method to convert an arbitrary instance of X509CRL
   1227      * to a X509CRLImpl. Does a cast if possible, otherwise reparses
   1228      * the encoding.
   1229      */
   1230     public static X509CRLImpl toImpl(X509CRL crl)
   1231             throws CRLException {
   1232         if (crl instanceof X509CRLImpl) {
   1233             return (X509CRLImpl)crl;
   1234         } else {
   1235             return X509Factory.intern(crl);
   1236         }
   1237     }
   1238 
   1239     /**
   1240      * Returns the X500 certificate issuer DN of a CRL entry.
   1241      *
   1242      * @param entry the entry to check
   1243      * @param prevCertIssuer the previous entry's certificate issuer
   1244      * @return the X500Principal in a CertificateIssuerExtension, or
   1245      *   prevCertIssuer if it does not exist
   1246      */
   1247     private X500Principal getCertIssuer(X509CRLEntryImpl entry,
   1248         X500Principal prevCertIssuer) throws IOException {
   1249 
   1250         CertificateIssuerExtension ciExt =
   1251             entry.getCertificateIssuerExtension();
   1252         if (ciExt != null) {
   1253             GeneralNames names = ciExt.get(CertificateIssuerExtension.ISSUER);
   1254             X500Name issuerDN = (X500Name) names.get(0).getName();
   1255             return issuerDN.asX500Principal();
   1256         } else {
   1257             return prevCertIssuer;
   1258         }
   1259     }
   1260 
   1261     @Override
   1262     public void derEncode(OutputStream out) throws IOException {
   1263         if (signedCRL == null)
   1264             throw new IOException("Null CRL to encode");
   1265         out.write(signedCRL.clone());
   1266     }
   1267 
   1268     /**
   1269      * Immutable X.509 Certificate Issuer DN and serial number pair
   1270      */
   1271     private final static class X509IssuerSerial
   1272             implements Comparable<X509IssuerSerial> {
   1273         final X500Principal issuer;
   1274         final BigInteger serial;
   1275         volatile int hashcode = 0;
   1276 
   1277         /**
   1278          * Create an X509IssuerSerial.
   1279          *
   1280          * @param issuer the issuer DN
   1281          * @param serial the serial number
   1282          */
   1283         X509IssuerSerial(X500Principal issuer, BigInteger serial) {
   1284             this.issuer = issuer;
   1285             this.serial = serial;
   1286         }
   1287 
   1288         /**
   1289          * Construct an X509IssuerSerial from an X509Certificate.
   1290          */
   1291         X509IssuerSerial(X509Certificate cert) {
   1292             this(cert.getIssuerX500Principal(), cert.getSerialNumber());
   1293         }
   1294 
   1295         /**
   1296          * Returns the issuer.
   1297          *
   1298          * @return the issuer
   1299          */
   1300         X500Principal getIssuer() {
   1301             return issuer;
   1302         }
   1303 
   1304         /**
   1305          * Returns the serial number.
   1306          *
   1307          * @return the serial number
   1308          */
   1309         BigInteger getSerial() {
   1310             return serial;
   1311         }
   1312 
   1313         /**
   1314          * Compares this X509Serial with another and returns true if they
   1315          * are equivalent.
   1316          *
   1317          * @param o the other object to compare with
   1318          * @return true if equal, false otherwise
   1319          */
   1320         public boolean equals(Object o) {
   1321             if (o == this) {
   1322                 return true;
   1323             }
   1324 
   1325             if (!(o instanceof X509IssuerSerial)) {
   1326                 return false;
   1327             }
   1328 
   1329             X509IssuerSerial other = (X509IssuerSerial) o;
   1330             if (serial.equals(other.getSerial()) &&
   1331                 issuer.equals(other.getIssuer())) {
   1332                 return true;
   1333             }
   1334             return false;
   1335         }
   1336 
   1337         /**
   1338          * Returns a hash code value for this X509IssuerSerial.
   1339          *
   1340          * @return the hash code value
   1341          */
   1342         public int hashCode() {
   1343             if (hashcode == 0) {
   1344                 int result = 17;
   1345                 result = 37*result + issuer.hashCode();
   1346                 result = 37*result + serial.hashCode();
   1347                 hashcode = result;
   1348             }
   1349             return hashcode;
   1350         }
   1351 
   1352         @Override
   1353         public int compareTo(X509IssuerSerial another) {
   1354             int cissuer = issuer.toString()
   1355                     .compareTo(another.issuer.toString());
   1356             if (cissuer != 0) return cissuer;
   1357             return this.serial.compareTo(another.serial);
   1358         }
   1359     }
   1360 }
   1361