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         byte[] dup = new byte[tbsCertList.length];
    752         System.arraycopy(tbsCertList, 0, dup, 0, dup.length);
    753         return dup;
    754     }
    755 
    756     /**
    757      * Gets the raw Signature bits from the CRL.
    758      *
    759      * @return the signature.
    760      */
    761     public byte[] getSignature() {
    762         if (signature == null)
    763             return null;
    764         byte[] dup = new byte[signature.length];
    765         System.arraycopy(signature, 0, dup, 0, dup.length);
    766         return dup;
    767     }
    768 
    769     /**
    770      * Gets the signature algorithm name for the CRL
    771      * signature algorithm. For example, the string "SHA1withDSA".
    772      * The ASN.1 definition for this is:
    773      * <pre>
    774      * AlgorithmIdentifier  ::=  SEQUENCE  {
    775      *     algorithm               OBJECT IDENTIFIER,
    776      *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
    777      *                             -- contains a value of the type
    778      *                             -- registered for use with the
    779      *                             -- algorithm object identifier value
    780      * </pre>
    781      *
    782      * @return the signature algorithm name.
    783      */
    784     public String getSigAlgName() {
    785         if (sigAlgId == null)
    786             return null;
    787         return sigAlgId.getName();
    788     }
    789 
    790     /**
    791      * Gets the signature algorithm OID string from the CRL.
    792      * An OID is represented by a set of positive whole number separated
    793      * by ".", that means,<br>
    794      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
    795      * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
    796      * with DSA signature algorithm defined in
    797      * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
    798      * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
    799      * and CRL Profile</a>.
    800      *
    801      * @return the signature algorithm oid string.
    802      */
    803     public String getSigAlgOID() {
    804         if (sigAlgId == null)
    805             return null;
    806         ObjectIdentifier oid = sigAlgId.getOID();
    807         return oid.toString();
    808     }
    809 
    810     /**
    811      * Gets the DER encoded signature algorithm parameters from this
    812      * CRL's signature algorithm. In most cases, the signature
    813      * algorithm parameters are null, the parameters are usually
    814      * supplied with the Public Key.
    815      *
    816      * @return the DER encoded signature algorithm parameters, or
    817      *         null if no parameters are present.
    818      */
    819     public byte[] getSigAlgParams() {
    820         if (sigAlgId == null)
    821             return null;
    822         try {
    823             return sigAlgId.getEncodedParams();
    824         } catch (IOException e) {
    825             return null;
    826         }
    827     }
    828 
    829     /**
    830      * Gets the signature AlgorithmId from the CRL.
    831      *
    832      * @return the signature AlgorithmId
    833      */
    834     public AlgorithmId getSigAlgId() {
    835         return sigAlgId;
    836     }
    837 
    838     /**
    839      * return the AuthorityKeyIdentifier, if any.
    840      *
    841      * @returns AuthorityKeyIdentifier or null
    842      *          (if no AuthorityKeyIdentifierExtension)
    843      * @throws IOException on error
    844      */
    845     public KeyIdentifier getAuthKeyId() throws IOException {
    846         AuthorityKeyIdentifierExtension aki = getAuthKeyIdExtension();
    847         if (aki != null) {
    848             KeyIdentifier keyId = (KeyIdentifier)aki.get(
    849                     AuthorityKeyIdentifierExtension.KEY_ID);
    850             return keyId;
    851         } else {
    852             return null;
    853         }
    854     }
    855 
    856     /**
    857      * return the AuthorityKeyIdentifierExtension, if any.
    858      *
    859      * @returns AuthorityKeyIdentifierExtension or null (if no such extension)
    860      * @throws IOException on error
    861      */
    862     public AuthorityKeyIdentifierExtension getAuthKeyIdExtension()
    863         throws IOException {
    864         Object obj = getExtension(PKIXExtensions.AuthorityKey_Id);
    865         return (AuthorityKeyIdentifierExtension)obj;
    866     }
    867 
    868     /**
    869      * return the CRLNumberExtension, if any.
    870      *
    871      * @returns CRLNumberExtension or null (if no such extension)
    872      * @throws IOException on error
    873      */
    874     public CRLNumberExtension getCRLNumberExtension() throws IOException {
    875         Object obj = getExtension(PKIXExtensions.CRLNumber_Id);
    876         return (CRLNumberExtension)obj;
    877     }
    878 
    879     /**
    880      * return the CRL number from the CRLNumberExtension, if any.
    881      *
    882      * @returns number or null (if no such extension)
    883      * @throws IOException on error
    884      */
    885     public BigInteger getCRLNumber() throws IOException {
    886         CRLNumberExtension numExt = getCRLNumberExtension();
    887         if (numExt != null) {
    888             BigInteger num = numExt.get(CRLNumberExtension.NUMBER);
    889             return num;
    890         } else {
    891             return null;
    892         }
    893     }
    894 
    895     /**
    896      * return the DeltaCRLIndicatorExtension, if any.
    897      *
    898      * @returns DeltaCRLIndicatorExtension or null (if no such extension)
    899      * @throws IOException on error
    900      */
    901     public DeltaCRLIndicatorExtension getDeltaCRLIndicatorExtension()
    902         throws IOException {
    903 
    904         Object obj = getExtension(PKIXExtensions.DeltaCRLIndicator_Id);
    905         return (DeltaCRLIndicatorExtension)obj;
    906     }
    907 
    908     /**
    909      * return the base CRL number from the DeltaCRLIndicatorExtension, if any.
    910      *
    911      * @returns number or null (if no such extension)
    912      * @throws IOException on error
    913      */
    914     public BigInteger getBaseCRLNumber() throws IOException {
    915         DeltaCRLIndicatorExtension dciExt = getDeltaCRLIndicatorExtension();
    916         if (dciExt != null) {
    917             BigInteger num = dciExt.get(DeltaCRLIndicatorExtension.NUMBER);
    918             return num;
    919         } else {
    920             return null;
    921         }
    922     }
    923 
    924     /**
    925      * return the IssuerAlternativeNameExtension, if any.
    926      *
    927      * @returns IssuerAlternativeNameExtension or null (if no such extension)
    928      * @throws IOException on error
    929      */
    930     public IssuerAlternativeNameExtension getIssuerAltNameExtension()
    931         throws IOException {
    932         Object obj = getExtension(PKIXExtensions.IssuerAlternativeName_Id);
    933         return (IssuerAlternativeNameExtension)obj;
    934     }
    935 
    936     /**
    937      * return the IssuingDistributionPointExtension, if any.
    938      *
    939      * @returns IssuingDistributionPointExtension or null
    940      *          (if no such extension)
    941      * @throws IOException on error
    942      */
    943     public IssuingDistributionPointExtension
    944         getIssuingDistributionPointExtension() throws IOException {
    945 
    946         Object obj = getExtension(PKIXExtensions.IssuingDistributionPoint_Id);
    947         return (IssuingDistributionPointExtension) obj;
    948     }
    949 
    950     /**
    951      * Return true if a critical extension is found that is
    952      * not supported, otherwise return false.
    953      */
    954     public boolean hasUnsupportedCriticalExtension() {
    955         if (extensions == null)
    956             return false;
    957         return extensions.hasUnsupportedCriticalExtension();
    958     }
    959 
    960     /**
    961      * Gets a Set of the extension(s) marked CRITICAL in the
    962      * CRL. In the returned set, each extension is represented by
    963      * its OID string.
    964      *
    965      * @return a set of the extension oid strings in the
    966      * CRL that are marked critical.
    967      */
    968     public Set<String> getCriticalExtensionOIDs() {
    969         if (extensions == null) {
    970             return null;
    971         }
    972         Set<String> extSet = new TreeSet<>();
    973         for (Extension ex : extensions.getAllExtensions()) {
    974             if (ex.isCritical()) {
    975                 extSet.add(ex.getExtensionId().toString());
    976             }
    977         }
    978         return extSet;
    979     }
    980 
    981     /**
    982      * Gets a Set of the extension(s) marked NON-CRITICAL in the
    983      * CRL. In the returned set, each extension is represented by
    984      * its OID string.
    985      *
    986      * @return a set of the extension oid strings in the
    987      * CRL that are NOT marked critical.
    988      */
    989     public Set<String> getNonCriticalExtensionOIDs() {
    990         if (extensions == null) {
    991             return null;
    992         }
    993         Set<String> extSet = new TreeSet<>();
    994         for (Extension ex : extensions.getAllExtensions()) {
    995             if (!ex.isCritical()) {
    996                 extSet.add(ex.getExtensionId().toString());
    997             }
    998         }
    999         return extSet;
   1000     }
   1001 
   1002     /**
   1003      * Gets the DER encoded OCTET string for the extension value
   1004      * (<code>extnValue</code>) identified by the passed in oid String.
   1005      * The <code>oid</code> string is
   1006      * represented by a set of positive whole number separated
   1007      * by ".", that means,<br>
   1008      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
   1009      *
   1010      * @param oid the Object Identifier value for the extension.
   1011      * @return the der encoded octet string of the extension value.
   1012      */
   1013     public byte[] getExtensionValue(String oid) {
   1014         if (extensions == null)
   1015             return null;
   1016         try {
   1017             String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
   1018             Extension crlExt = null;
   1019 
   1020             if (extAlias == null) { // may be unknown
   1021                 ObjectIdentifier findOID = new ObjectIdentifier(oid);
   1022                 Extension ex = null;
   1023                 ObjectIdentifier inCertOID;
   1024                 for (Enumeration<Extension> e = extensions.getElements();
   1025                                                  e.hasMoreElements();) {
   1026                     ex = e.nextElement();
   1027                     inCertOID = ex.getExtensionId();
   1028                     if (inCertOID.equals((Object)findOID)) {
   1029                         crlExt = ex;
   1030                         break;
   1031                     }
   1032                 }
   1033             } else
   1034                 crlExt = extensions.get(extAlias);
   1035             if (crlExt == null)
   1036                 return null;
   1037             byte[] extData = crlExt.getExtensionValue();
   1038             if (extData == null)
   1039                 return null;
   1040             DerOutputStream out = new DerOutputStream();
   1041             out.putOctetString(extData);
   1042             return out.toByteArray();
   1043         } catch (Exception e) {
   1044             return null;
   1045         }
   1046     }
   1047 
   1048     /**
   1049      * get an extension
   1050      *
   1051      * @param oid ObjectIdentifier of extension desired
   1052      * @returns Object of type <extension> or null, if not found
   1053      * @throws IOException on error
   1054      */
   1055     public Object getExtension(ObjectIdentifier oid) {
   1056         if (extensions == null)
   1057             return null;
   1058 
   1059         // XXX Consider cloning this
   1060         return extensions.get(OIDMap.getName(oid));
   1061     }
   1062 
   1063     /*
   1064      * Parses an X.509 CRL, should be used only by constructors.
   1065      */
   1066     private void parse(DerValue val) throws CRLException, IOException {
   1067         // check if can over write the certificate
   1068         if (readOnly)
   1069             throw new CRLException("cannot over-write existing CRL");
   1070 
   1071         if ( val.getData() == null || val.tag != DerValue.tag_Sequence)
   1072             throw new CRLException("Invalid DER-encoded CRL data");
   1073 
   1074         signedCRL = val.toByteArray();
   1075         DerValue seq[] = new DerValue[3];
   1076 
   1077         seq[0] = val.data.getDerValue();
   1078         seq[1] = val.data.getDerValue();
   1079         seq[2] = val.data.getDerValue();
   1080 
   1081         if (val.data.available() != 0)
   1082             throw new CRLException("signed overrun, bytes = "
   1083                                      + val.data.available());
   1084 
   1085         if (seq[0].tag != DerValue.tag_Sequence)
   1086             throw new CRLException("signed CRL fields invalid");
   1087 
   1088         sigAlgId = AlgorithmId.parse(seq[1]);
   1089         signature = seq[2].getBitString();
   1090 
   1091         if (seq[1].data.available() != 0)
   1092             throw new CRLException("AlgorithmId field overrun");
   1093 
   1094         if (seq[2].data.available() != 0)
   1095             throw new CRLException("Signature field overrun");
   1096 
   1097         // the tbsCertsList
   1098         tbsCertList = seq[0].toByteArray();
   1099 
   1100         // parse the information
   1101         DerInputStream derStrm = seq[0].data;
   1102         DerValue       tmp;
   1103         byte           nextByte;
   1104 
   1105         // version (optional if v1)
   1106         version = 0;   // by default, version = v1 == 0
   1107         nextByte = (byte)derStrm.peekByte();
   1108         if (nextByte == DerValue.tag_Integer) {
   1109             version = derStrm.getInteger();
   1110             if (version != 1)  // i.e. v2
   1111                 throw new CRLException("Invalid version");
   1112         }
   1113         tmp = derStrm.getDerValue();
   1114 
   1115         // signature
   1116         AlgorithmId tmpId = AlgorithmId.parse(tmp);
   1117 
   1118         // the "inner" and "outer" signature algorithms must match
   1119         if (! tmpId.equals(sigAlgId))
   1120             throw new CRLException("Signature algorithm mismatch");
   1121         infoSigAlgId = tmpId;
   1122 
   1123         // issuer
   1124         issuer = new X500Name(derStrm);
   1125         if (issuer.isEmpty()) {
   1126             throw new CRLException("Empty issuer DN not allowed in X509CRLs");
   1127         }
   1128 
   1129         // thisUpdate
   1130         // check if UTCTime encoded or GeneralizedTime
   1131 
   1132         nextByte = (byte)derStrm.peekByte();
   1133         if (nextByte == DerValue.tag_UtcTime) {
   1134             thisUpdate = derStrm.getUTCTime();
   1135         } else if (nextByte == DerValue.tag_GeneralizedTime) {
   1136             thisUpdate = derStrm.getGeneralizedTime();
   1137         } else {
   1138             throw new CRLException("Invalid encoding for thisUpdate"
   1139                                    + " (tag=" + nextByte + ")");
   1140         }
   1141 
   1142         if (derStrm.available() == 0)
   1143            return;     // done parsing no more optional fields present
   1144 
   1145         // nextUpdate (optional)
   1146         nextByte = (byte)derStrm.peekByte();
   1147         if (nextByte == DerValue.tag_UtcTime) {
   1148             nextUpdate = derStrm.getUTCTime();
   1149         } else if (nextByte == DerValue.tag_GeneralizedTime) {
   1150             nextUpdate = derStrm.getGeneralizedTime();
   1151         } // else it is not present
   1152 
   1153         if (derStrm.available() == 0)
   1154             return;     // done parsing no more optional fields present
   1155 
   1156         // revokedCertificates (optional)
   1157         nextByte = (byte)derStrm.peekByte();
   1158         if ((nextByte == DerValue.tag_SequenceOf)
   1159             && (! ((nextByte & 0x0c0) == 0x080))) {
   1160             DerValue[] badCerts = derStrm.getSequence(4);
   1161 
   1162             X500Principal crlIssuer = getIssuerX500Principal();
   1163             X500Principal badCertIssuer = crlIssuer;
   1164             for (int i = 0; i < badCerts.length; i++) {
   1165                 X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
   1166                 badCertIssuer = getCertIssuer(entry, badCertIssuer);
   1167                 entry.setCertificateIssuer(crlIssuer, badCertIssuer);
   1168                 X509IssuerSerial issuerSerial = new X509IssuerSerial
   1169                     (badCertIssuer, entry.getSerialNumber());
   1170                 revokedMap.put(issuerSerial, entry);
   1171                 revokedList.add(entry);
   1172             }
   1173         }
   1174 
   1175         if (derStrm.available() == 0)
   1176             return;     // done parsing no extensions
   1177 
   1178         // crlExtensions (optional)
   1179         tmp = derStrm.getDerValue();
   1180         if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
   1181             extensions = new CRLExtensions(tmp.data);
   1182         }
   1183         readOnly = true;
   1184     }
   1185 
   1186     /**
   1187      * Extract the issuer X500Principal from an X509CRL. Parses the encoded
   1188      * form of the CRL to preserve the principal's ASN.1 encoding.
   1189      *
   1190      * Called by java.security.cert.X509CRL.getIssuerX500Principal().
   1191      */
   1192     public static X500Principal getIssuerX500Principal(X509CRL crl) {
   1193         try {
   1194             byte[] encoded = crl.getEncoded();
   1195             DerInputStream derIn = new DerInputStream(encoded);
   1196             DerValue tbsCert = derIn.getSequence(3)[0];
   1197             DerInputStream tbsIn = tbsCert.data;
   1198 
   1199             DerValue tmp;
   1200             // skip version number if present
   1201             byte nextByte = (byte)tbsIn.peekByte();
   1202             if (nextByte == DerValue.tag_Integer) {
   1203                 tmp = tbsIn.getDerValue();
   1204             }
   1205 
   1206             tmp = tbsIn.getDerValue();  // skip signature
   1207             tmp = tbsIn.getDerValue();  // issuer
   1208             byte[] principalBytes = tmp.toByteArray();
   1209             return new X500Principal(principalBytes);
   1210         } catch (Exception e) {
   1211             throw new RuntimeException("Could not parse issuer", e);
   1212         }
   1213     }
   1214 
   1215     /**
   1216      * Returned the encoding of the given certificate for internal use.
   1217      * Callers must guarantee that they neither modify it nor expose it
   1218      * to untrusted code. Uses getEncodedInternal() if the certificate
   1219      * is instance of X509CertImpl, getEncoded() otherwise.
   1220      */
   1221     public static byte[] getEncodedInternal(X509CRL crl) throws CRLException {
   1222         if (crl instanceof X509CRLImpl) {
   1223             return ((X509CRLImpl)crl).getEncodedInternal();
   1224         } else {
   1225             return crl.getEncoded();
   1226         }
   1227     }
   1228 
   1229     /**
   1230      * Utility method to convert an arbitrary instance of X509CRL
   1231      * to a X509CRLImpl. Does a cast if possible, otherwise reparses
   1232      * the encoding.
   1233      */
   1234     public static X509CRLImpl toImpl(X509CRL crl)
   1235             throws CRLException {
   1236         if (crl instanceof X509CRLImpl) {
   1237             return (X509CRLImpl)crl;
   1238         } else {
   1239             return X509Factory.intern(crl);
   1240         }
   1241     }
   1242 
   1243     /**
   1244      * Returns the X500 certificate issuer DN of a CRL entry.
   1245      *
   1246      * @param entry the entry to check
   1247      * @param prevCertIssuer the previous entry's certificate issuer
   1248      * @return the X500Principal in a CertificateIssuerExtension, or
   1249      *   prevCertIssuer if it does not exist
   1250      */
   1251     private X500Principal getCertIssuer(X509CRLEntryImpl entry,
   1252         X500Principal prevCertIssuer) throws IOException {
   1253 
   1254         CertificateIssuerExtension ciExt =
   1255             entry.getCertificateIssuerExtension();
   1256         if (ciExt != null) {
   1257             GeneralNames names = ciExt.get(CertificateIssuerExtension.ISSUER);
   1258             X500Name issuerDN = (X500Name) names.get(0).getName();
   1259             return issuerDN.asX500Principal();
   1260         } else {
   1261             return prevCertIssuer;
   1262         }
   1263     }
   1264 
   1265     @Override
   1266     public void derEncode(OutputStream out) throws IOException {
   1267         if (signedCRL == null)
   1268             throw new IOException("Null CRL to encode");
   1269         out.write(signedCRL.clone());
   1270     }
   1271 
   1272     /**
   1273      * Immutable X.509 Certificate Issuer DN and serial number pair
   1274      */
   1275     private final static class X509IssuerSerial
   1276             implements Comparable<X509IssuerSerial> {
   1277         final X500Principal issuer;
   1278         final BigInteger serial;
   1279         volatile int hashcode = 0;
   1280 
   1281         /**
   1282          * Create an X509IssuerSerial.
   1283          *
   1284          * @param issuer the issuer DN
   1285          * @param serial the serial number
   1286          */
   1287         X509IssuerSerial(X500Principal issuer, BigInteger serial) {
   1288             this.issuer = issuer;
   1289             this.serial = serial;
   1290         }
   1291 
   1292         /**
   1293          * Construct an X509IssuerSerial from an X509Certificate.
   1294          */
   1295         X509IssuerSerial(X509Certificate cert) {
   1296             this(cert.getIssuerX500Principal(), cert.getSerialNumber());
   1297         }
   1298 
   1299         /**
   1300          * Returns the issuer.
   1301          *
   1302          * @return the issuer
   1303          */
   1304         X500Principal getIssuer() {
   1305             return issuer;
   1306         }
   1307 
   1308         /**
   1309          * Returns the serial number.
   1310          *
   1311          * @return the serial number
   1312          */
   1313         BigInteger getSerial() {
   1314             return serial;
   1315         }
   1316 
   1317         /**
   1318          * Compares this X509Serial with another and returns true if they
   1319          * are equivalent.
   1320          *
   1321          * @param o the other object to compare with
   1322          * @return true if equal, false otherwise
   1323          */
   1324         public boolean equals(Object o) {
   1325             if (o == this) {
   1326                 return true;
   1327             }
   1328 
   1329             if (!(o instanceof X509IssuerSerial)) {
   1330                 return false;
   1331             }
   1332 
   1333             X509IssuerSerial other = (X509IssuerSerial) o;
   1334             if (serial.equals(other.getSerial()) &&
   1335                 issuer.equals(other.getIssuer())) {
   1336                 return true;
   1337             }
   1338             return false;
   1339         }
   1340 
   1341         /**
   1342          * Returns a hash code value for this X509IssuerSerial.
   1343          *
   1344          * @return the hash code value
   1345          */
   1346         public int hashCode() {
   1347             if (hashcode == 0) {
   1348                 int result = 17;
   1349                 result = 37*result + issuer.hashCode();
   1350                 result = 37*result + serial.hashCode();
   1351                 hashcode = result;
   1352             }
   1353             return hashcode;
   1354         }
   1355 
   1356         @Override
   1357         public int compareTo(X509IssuerSerial another) {
   1358             int cissuer = issuer.toString()
   1359                     .compareTo(another.issuer.toString());
   1360             if (cissuer != 0) return cissuer;
   1361             return this.serial.compareTo(another.serial);
   1362         }
   1363     }
   1364 }
   1365