Home | History | Annotate | Download | only in x509
      1 /*
      2  * Copyright (c) 1997, 2010, 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.Security;
     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      * Encodes an X.509 CRL, and signs it using the given key.
    404      *
    405      * @param key the private key used for signing.
    406      * @param algorithm the name of the signature algorithm used.
    407      *
    408      * @exception NoSuchAlgorithmException on unsupported signature
    409      * algorithms.
    410      * @exception InvalidKeyException on incorrect key.
    411      * @exception NoSuchProviderException on incorrect provider.
    412      * @exception SignatureException on signature errors.
    413      * @exception CRLException if any mandatory data was omitted.
    414      */
    415     public void sign(PrivateKey key, String algorithm)
    416     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
    417         NoSuchProviderException, SignatureException {
    418         sign(key, algorithm, null);
    419     }
    420 
    421     /**
    422      * Encodes an X.509 CRL, and signs it using the given key.
    423      *
    424      * @param key the private key used for signing.
    425      * @param algorithm the name of the signature algorithm used.
    426      * @param provider the name of the provider.
    427      *
    428      * @exception NoSuchAlgorithmException on unsupported signature
    429      * algorithms.
    430      * @exception InvalidKeyException on incorrect key.
    431      * @exception NoSuchProviderException on incorrect provider.
    432      * @exception SignatureException on signature errors.
    433      * @exception CRLException if any mandatory data was omitted.
    434      */
    435     public void sign(PrivateKey key, String algorithm, String provider)
    436     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
    437         NoSuchProviderException, SignatureException {
    438         try {
    439             if (readOnly)
    440                 throw new CRLException("cannot over-write existing CRL");
    441             Signature sigEngine = null;
    442             if ((provider == null) || (provider.length() == 0))
    443                 sigEngine = Signature.getInstance(algorithm);
    444             else
    445                 sigEngine = Signature.getInstance(algorithm, provider);
    446 
    447             sigEngine.initSign(key);
    448 
    449                                 // in case the name is reset
    450             sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
    451             infoSigAlgId = sigAlgId;
    452 
    453             DerOutputStream out = new DerOutputStream();
    454             DerOutputStream tmp = new DerOutputStream();
    455 
    456             // encode crl info
    457             encodeInfo(tmp);
    458 
    459             // encode algorithm identifier
    460             sigAlgId.encode(tmp);
    461 
    462             // Create and encode the signature itself.
    463             sigEngine.update(tbsCertList, 0, tbsCertList.length);
    464             signature = sigEngine.sign();
    465             tmp.putBitString(signature);
    466 
    467             // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
    468             out.write(DerValue.tag_Sequence, tmp);
    469             signedCRL = out.toByteArray();
    470             readOnly = true;
    471 
    472         } catch (IOException e) {
    473             throw new CRLException("Error while encoding data: " +
    474                                    e.getMessage());
    475         }
    476     }
    477 
    478     /**
    479      * Returns a printable string of this CRL.
    480      *
    481      * @return value of this CRL in a printable form.
    482      */
    483     public String toString() {
    484         StringBuffer sb = new StringBuffer();
    485         sb.append("X.509 CRL v" + (version+1) + "\n");
    486         if (sigAlgId != null)
    487             sb.append("Signature Algorithm: " + sigAlgId.toString() +
    488                   ", OID=" + (sigAlgId.getOID()).toString() + "\n");
    489         if (issuer != null)
    490             sb.append("Issuer: " + issuer.toString() + "\n");
    491         if (thisUpdate != null)
    492             sb.append("\nThis Update: " + thisUpdate.toString() + "\n");
    493         if (nextUpdate != null)
    494             sb.append("Next Update: " + nextUpdate.toString() + "\n");
    495         if (revokedList.isEmpty())
    496             sb.append("\nNO certificates have been revoked\n");
    497         else {
    498             sb.append("\nRevoked Certificates: " + revokedList.size());
    499             int i = 1;
    500             for (X509CRLEntry entry: revokedList) {
    501                 sb.append("\n[" + i++ + "] " + entry.toString());
    502             }
    503         }
    504         if (extensions != null) {
    505             Collection<Extension> allExts = extensions.getAllExtensions();
    506             Object[] objs = allExts.toArray();
    507             sb.append("\nCRL Extensions: " + objs.length);
    508             for (int i = 0; i < objs.length; i++) {
    509                 sb.append("\n[" + (i+1) + "]: ");
    510                 Extension ext = (Extension)objs[i];
    511                 try {
    512                    if (OIDMap.getClass(ext.getExtensionId()) == null) {
    513                        sb.append(ext.toString());
    514                        byte[] extValue = ext.getExtensionValue();
    515                        if (extValue != null) {
    516                            DerOutputStream out = new DerOutputStream();
    517                            out.putOctetString(extValue);
    518                            extValue = out.toByteArray();
    519                            HexDumpEncoder enc = new HexDumpEncoder();
    520                            sb.append("Extension unknown: "
    521                                      + "DER encoded OCTET string =\n"
    522                                      + enc.encodeBuffer(extValue) + "\n");
    523                       }
    524                    } else
    525                        sb.append(ext.toString()); // sub-class exists
    526                 } catch (Exception e) {
    527                     sb.append(", Error parsing this extension");
    528                 }
    529             }
    530         }
    531         if (signature != null) {
    532             HexDumpEncoder encoder = new HexDumpEncoder();
    533             sb.append("\nSignature:\n" + encoder.encodeBuffer(signature)
    534                       + "\n");
    535         } else
    536             sb.append("NOT signed yet\n");
    537         return sb.toString();
    538     }
    539 
    540     /**
    541      * Checks whether the given certificate is on this CRL.
    542      *
    543      * @param cert the certificate to check for.
    544      * @return true if the given certificate is on this CRL,
    545      * false otherwise.
    546      */
    547     public boolean isRevoked(Certificate cert) {
    548         if (revokedMap.isEmpty() || (!(cert instanceof X509Certificate))) {
    549             return false;
    550         }
    551         X509Certificate xcert = (X509Certificate) cert;
    552         X509IssuerSerial issuerSerial = new X509IssuerSerial(xcert);
    553         return revokedMap.containsKey(issuerSerial);
    554     }
    555 
    556     /**
    557      * Gets the version number from this CRL.
    558      * The ASN.1 definition for this is:
    559      * <pre>
    560      * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
    561      *             -- v3 does not apply to CRLs but appears for consistency
    562      *             -- with definition of Version for certs
    563      * </pre>
    564      * @return the version number, i.e. 1 or 2.
    565      */
    566     public int getVersion() {
    567         return version+1;
    568     }
    569 
    570     /**
    571      * Gets the issuer distinguished name from this CRL.
    572      * The issuer name identifies the entity who has signed (and
    573      * issued the CRL). The issuer name field contains an
    574      * X.500 distinguished name (DN).
    575      * The ASN.1 definition for this is:
    576      * <pre>
    577      * issuer    Name
    578      *
    579      * Name ::= CHOICE { RDNSequence }
    580      * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
    581      * RelativeDistinguishedName ::=
    582      *     SET OF AttributeValueAssertion
    583      *
    584      * AttributeValueAssertion ::= SEQUENCE {
    585      *                               AttributeType,
    586      *                               AttributeValue }
    587      * AttributeType ::= OBJECT IDENTIFIER
    588      * AttributeValue ::= ANY
    589      * </pre>
    590      * The Name describes a hierarchical name composed of attributes,
    591      * such as country name, and corresponding values, such as US.
    592      * The type of the component AttributeValue is determined by the
    593      * AttributeType; in general it will be a directoryString.
    594      * A directoryString is usually one of PrintableString,
    595      * TeletexString or UniversalString.
    596      * @return the issuer name.
    597      */
    598     public Principal getIssuerDN() {
    599         return (Principal)issuer;
    600     }
    601 
    602     /**
    603      * Return the issuer as X500Principal. Overrides method in X509CRL
    604      * to provide a slightly more efficient version.
    605      */
    606     public X500Principal getIssuerX500Principal() {
    607         if (issuerPrincipal == null) {
    608             issuerPrincipal = issuer.asX500Principal();
    609         }
    610         return issuerPrincipal;
    611     }
    612 
    613     /**
    614      * Gets the thisUpdate date from the CRL.
    615      * The ASN.1 definition for this is:
    616      *
    617      * @return the thisUpdate date from the CRL.
    618      */
    619     public Date getThisUpdate() {
    620         return (new Date(thisUpdate.getTime()));
    621     }
    622 
    623     /**
    624      * Gets the nextUpdate date from the CRL.
    625      *
    626      * @return the nextUpdate date from the CRL, or null if
    627      * not present.
    628      */
    629     public Date getNextUpdate() {
    630         if (nextUpdate == null)
    631             return null;
    632         return (new Date(nextUpdate.getTime()));
    633     }
    634 
    635     /**
    636      * Gets the CRL entry with the given serial number from this CRL.
    637      *
    638      * @return the entry with the given serial number, or <code>null</code> if
    639      * no such entry exists in the CRL.
    640      * @see X509CRLEntry
    641      */
    642     public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
    643         if (revokedMap.isEmpty()) {
    644             return null;
    645         }
    646         // assume this is a direct CRL entry (cert and CRL issuer are the same)
    647         X509IssuerSerial issuerSerial = new X509IssuerSerial
    648             (getIssuerX500Principal(), serialNumber);
    649         return revokedMap.get(issuerSerial);
    650     }
    651 
    652     /**
    653      * Gets the CRL entry for the given certificate.
    654      */
    655     public X509CRLEntry getRevokedCertificate(X509Certificate cert) {
    656         if (revokedMap.isEmpty()) {
    657             return null;
    658         }
    659         X509IssuerSerial issuerSerial = new X509IssuerSerial(cert);
    660         return revokedMap.get(issuerSerial);
    661     }
    662 
    663     /**
    664      * Gets all the revoked certificates from the CRL.
    665      * A Set of X509CRLEntry.
    666      *
    667      * @return all the revoked certificates or <code>null</code> if there are
    668      * none.
    669      * @see X509CRLEntry
    670      */
    671     public Set<X509CRLEntry> getRevokedCertificates() {
    672         if (revokedList.isEmpty()) {
    673             return null;
    674         } else {
    675             return new TreeSet<X509CRLEntry>(revokedList);
    676         }
    677     }
    678 
    679     /**
    680      * Gets the DER encoded CRL information, the
    681      * <code>tbsCertList</code> from this CRL.
    682      * This can be used to verify the signature independently.
    683      *
    684      * @return the DER encoded CRL information.
    685      * @exception CRLException on encoding errors.
    686      */
    687     public byte[] getTBSCertList() throws CRLException {
    688         if (tbsCertList == null)
    689             throw new CRLException("Uninitialized CRL");
    690         byte[] dup = new byte[tbsCertList.length];
    691         System.arraycopy(tbsCertList, 0, dup, 0, dup.length);
    692         return dup;
    693     }
    694 
    695     /**
    696      * Gets the raw Signature bits from the CRL.
    697      *
    698      * @return the signature.
    699      */
    700     public byte[] getSignature() {
    701         if (signature == null)
    702             return null;
    703         byte[] dup = new byte[signature.length];
    704         System.arraycopy(signature, 0, dup, 0, dup.length);
    705         return dup;
    706     }
    707 
    708     /**
    709      * Gets the signature algorithm name for the CRL
    710      * signature algorithm. For example, the string "SHA1withDSA".
    711      * The ASN.1 definition for this is:
    712      * <pre>
    713      * AlgorithmIdentifier  ::=  SEQUENCE  {
    714      *     algorithm               OBJECT IDENTIFIER,
    715      *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
    716      *                             -- contains a value of the type
    717      *                             -- registered for use with the
    718      *                             -- algorithm object identifier value
    719      * </pre>
    720      *
    721      * @return the signature algorithm name.
    722      */
    723     public String getSigAlgName() {
    724         if (sigAlgId == null)
    725             return null;
    726         return sigAlgId.getName();
    727     }
    728 
    729     /**
    730      * Gets the signature algorithm OID string from the CRL.
    731      * An OID is represented by a set of positive whole number separated
    732      * by ".", that means,<br>
    733      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
    734      * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
    735      * with DSA signature algorithm defined in
    736      * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
    737      * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
    738      * and CRL Profile</a>.
    739      *
    740      * @return the signature algorithm oid string.
    741      */
    742     public String getSigAlgOID() {
    743         if (sigAlgId == null)
    744             return null;
    745         ObjectIdentifier oid = sigAlgId.getOID();
    746         return oid.toString();
    747     }
    748 
    749     /**
    750      * Gets the DER encoded signature algorithm parameters from this
    751      * CRL's signature algorithm. In most cases, the signature
    752      * algorithm parameters are null, the parameters are usually
    753      * supplied with the Public Key.
    754      *
    755      * @return the DER encoded signature algorithm parameters, or
    756      *         null if no parameters are present.
    757      */
    758     public byte[] getSigAlgParams() {
    759         if (sigAlgId == null)
    760             return null;
    761         try {
    762             return sigAlgId.getEncodedParams();
    763         } catch (IOException e) {
    764             return null;
    765         }
    766     }
    767 
    768     /**
    769      * Gets the signature AlgorithmId from the CRL.
    770      *
    771      * @return the signature AlgorithmId
    772      */
    773     public AlgorithmId getSigAlgId() {
    774         return sigAlgId;
    775     }
    776 
    777     /**
    778      * return the AuthorityKeyIdentifier, if any.
    779      *
    780      * @returns AuthorityKeyIdentifier or null
    781      *          (if no AuthorityKeyIdentifierExtension)
    782      * @throws IOException on error
    783      */
    784     public KeyIdentifier getAuthKeyId() throws IOException {
    785         AuthorityKeyIdentifierExtension aki = getAuthKeyIdExtension();
    786         if (aki != null) {
    787             KeyIdentifier keyId = (KeyIdentifier)aki.get(aki.KEY_ID);
    788             return keyId;
    789         } else {
    790             return null;
    791         }
    792     }
    793 
    794     /**
    795      * return the AuthorityKeyIdentifierExtension, if any.
    796      *
    797      * @returns AuthorityKeyIdentifierExtension or null (if no such extension)
    798      * @throws IOException on error
    799      */
    800     public AuthorityKeyIdentifierExtension getAuthKeyIdExtension()
    801         throws IOException {
    802         Object obj = getExtension(PKIXExtensions.AuthorityKey_Id);
    803         return (AuthorityKeyIdentifierExtension)obj;
    804     }
    805 
    806     /**
    807      * return the CRLNumberExtension, if any.
    808      *
    809      * @returns CRLNumberExtension or null (if no such extension)
    810      * @throws IOException on error
    811      */
    812     public CRLNumberExtension getCRLNumberExtension() throws IOException {
    813         Object obj = getExtension(PKIXExtensions.CRLNumber_Id);
    814         return (CRLNumberExtension)obj;
    815     }
    816 
    817     /**
    818      * return the CRL number from the CRLNumberExtension, if any.
    819      *
    820      * @returns number or null (if no such extension)
    821      * @throws IOException on error
    822      */
    823     public BigInteger getCRLNumber() throws IOException {
    824         CRLNumberExtension numExt = getCRLNumberExtension();
    825         if (numExt != null) {
    826             BigInteger num = (BigInteger)numExt.get(numExt.NUMBER);
    827             return num;
    828         } else {
    829             return null;
    830         }
    831     }
    832 
    833     /**
    834      * return the DeltaCRLIndicatorExtension, if any.
    835      *
    836      * @returns DeltaCRLIndicatorExtension or null (if no such extension)
    837      * @throws IOException on error
    838      */
    839     public DeltaCRLIndicatorExtension getDeltaCRLIndicatorExtension()
    840         throws IOException {
    841 
    842         Object obj = getExtension(PKIXExtensions.DeltaCRLIndicator_Id);
    843         return (DeltaCRLIndicatorExtension)obj;
    844     }
    845 
    846     /**
    847      * return the base CRL number from the DeltaCRLIndicatorExtension, if any.
    848      *
    849      * @returns number or null (if no such extension)
    850      * @throws IOException on error
    851      */
    852     public BigInteger getBaseCRLNumber() throws IOException {
    853         DeltaCRLIndicatorExtension dciExt = getDeltaCRLIndicatorExtension();
    854         if (dciExt != null) {
    855             BigInteger num = (BigInteger)dciExt.get(dciExt.NUMBER);
    856             return num;
    857         } else {
    858             return null;
    859         }
    860     }
    861 
    862     /**
    863      * return the IssuerAlternativeNameExtension, if any.
    864      *
    865      * @returns IssuerAlternativeNameExtension or null (if no such extension)
    866      * @throws IOException on error
    867      */
    868     public IssuerAlternativeNameExtension getIssuerAltNameExtension()
    869         throws IOException {
    870         Object obj = getExtension(PKIXExtensions.IssuerAlternativeName_Id);
    871         return (IssuerAlternativeNameExtension)obj;
    872     }
    873 
    874     /**
    875      * return the IssuingDistributionPointExtension, if any.
    876      *
    877      * @returns IssuingDistributionPointExtension or null
    878      *          (if no such extension)
    879      * @throws IOException on error
    880      */
    881     public IssuingDistributionPointExtension
    882         getIssuingDistributionPointExtension() throws IOException {
    883 
    884         Object obj = getExtension(PKIXExtensions.IssuingDistributionPoint_Id);
    885         return (IssuingDistributionPointExtension) obj;
    886     }
    887 
    888     /**
    889      * Return true if a critical extension is found that is
    890      * not supported, otherwise return false.
    891      */
    892     public boolean hasUnsupportedCriticalExtension() {
    893         if (extensions == null)
    894             return false;
    895         return extensions.hasUnsupportedCriticalExtension();
    896     }
    897 
    898     /**
    899      * Gets a Set of the extension(s) marked CRITICAL in the
    900      * CRL. In the returned set, each extension is represented by
    901      * its OID string.
    902      *
    903      * @return a set of the extension oid strings in the
    904      * CRL that are marked critical.
    905      */
    906     public Set<String> getCriticalExtensionOIDs() {
    907         if (extensions == null) {
    908             return null;
    909         }
    910         Set<String> extSet = new TreeSet<>();
    911         for (Extension ex : extensions.getAllExtensions()) {
    912             if (ex.isCritical()) {
    913                 extSet.add(ex.getExtensionId().toString());
    914             }
    915         }
    916         return extSet;
    917     }
    918 
    919     /**
    920      * Gets a Set of the extension(s) marked NON-CRITICAL in the
    921      * CRL. In the returned set, each extension is represented by
    922      * its OID string.
    923      *
    924      * @return a set of the extension oid strings in the
    925      * CRL that are NOT marked critical.
    926      */
    927     public Set<String> getNonCriticalExtensionOIDs() {
    928         if (extensions == null) {
    929             return null;
    930         }
    931         Set<String> extSet = new TreeSet<>();
    932         for (Extension ex : extensions.getAllExtensions()) {
    933             if (!ex.isCritical()) {
    934                 extSet.add(ex.getExtensionId().toString());
    935             }
    936         }
    937         return extSet;
    938     }
    939 
    940     /**
    941      * Gets the DER encoded OCTET string for the extension value
    942      * (<code>extnValue</code>) identified by the passed in oid String.
    943      * The <code>oid</code> string is
    944      * represented by a set of positive whole number separated
    945      * by ".", that means,<br>
    946      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
    947      *
    948      * @param oid the Object Identifier value for the extension.
    949      * @return the der encoded octet string of the extension value.
    950      */
    951     public byte[] getExtensionValue(String oid) {
    952         if (extensions == null)
    953             return null;
    954         try {
    955             String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
    956             Extension crlExt = null;
    957 
    958             if (extAlias == null) { // may be unknown
    959                 ObjectIdentifier findOID = new ObjectIdentifier(oid);
    960                 Extension ex = null;
    961                 ObjectIdentifier inCertOID;
    962                 for (Enumeration<Extension> e = extensions.getElements();
    963                                                  e.hasMoreElements();) {
    964                     ex = e.nextElement();
    965                     inCertOID = ex.getExtensionId();
    966                     if (inCertOID.equals(findOID)) {
    967                         crlExt = ex;
    968                         break;
    969                     }
    970                 }
    971             } else
    972                 crlExt = extensions.get(extAlias);
    973             if (crlExt == null)
    974                 return null;
    975             byte[] extData = crlExt.getExtensionValue();
    976             if (extData == null)
    977                 return null;
    978             DerOutputStream out = new DerOutputStream();
    979             out.putOctetString(extData);
    980             return out.toByteArray();
    981         } catch (Exception e) {
    982             return null;
    983         }
    984     }
    985 
    986     /**
    987      * get an extension
    988      *
    989      * @param oid ObjectIdentifier of extension desired
    990      * @returns Object of type <extension> or null, if not found
    991      * @throws IOException on error
    992      */
    993     public Object getExtension(ObjectIdentifier oid) {
    994         if (extensions == null)
    995             return null;
    996 
    997         // XXX Consider cloning this
    998         return extensions.get(OIDMap.getName(oid));
    999     }
   1000 
   1001     /*
   1002      * Parses an X.509 CRL, should be used only by constructors.
   1003      */
   1004     private void parse(DerValue val) throws CRLException, IOException {
   1005         // check if can over write the certificate
   1006         if (readOnly)
   1007             throw new CRLException("cannot over-write existing CRL");
   1008 
   1009         if ( val.getData() == null || val.tag != DerValue.tag_Sequence)
   1010             throw new CRLException("Invalid DER-encoded CRL data");
   1011 
   1012         signedCRL = val.toByteArray();
   1013         DerValue seq[] = new DerValue[3];
   1014 
   1015         seq[0] = val.data.getDerValue();
   1016         seq[1] = val.data.getDerValue();
   1017         seq[2] = val.data.getDerValue();
   1018 
   1019         if (val.data.available() != 0)
   1020             throw new CRLException("signed overrun, bytes = "
   1021                                      + val.data.available());
   1022 
   1023         if (seq[0].tag != DerValue.tag_Sequence)
   1024             throw new CRLException("signed CRL fields invalid");
   1025 
   1026         sigAlgId = AlgorithmId.parse(seq[1]);
   1027         signature = seq[2].getBitString();
   1028 
   1029         if (seq[1].data.available() != 0)
   1030             throw new CRLException("AlgorithmId field overrun");
   1031 
   1032         if (seq[2].data.available() != 0)
   1033             throw new CRLException("Signature field overrun");
   1034 
   1035         // the tbsCertsList
   1036         tbsCertList = seq[0].toByteArray();
   1037 
   1038         // parse the information
   1039         DerInputStream derStrm = seq[0].data;
   1040         DerValue       tmp;
   1041         byte           nextByte;
   1042 
   1043         // version (optional if v1)
   1044         version = 0;   // by default, version = v1 == 0
   1045         nextByte = (byte)derStrm.peekByte();
   1046         if (nextByte == DerValue.tag_Integer) {
   1047             version = derStrm.getInteger();
   1048             if (version != 1)  // i.e. v2
   1049                 throw new CRLException("Invalid version");
   1050         }
   1051         tmp = derStrm.getDerValue();
   1052 
   1053         // signature
   1054         AlgorithmId tmpId = AlgorithmId.parse(tmp);
   1055 
   1056         // the "inner" and "outer" signature algorithms must match
   1057         if (! tmpId.equals(sigAlgId))
   1058             throw new CRLException("Signature algorithm mismatch");
   1059         infoSigAlgId = tmpId;
   1060 
   1061         // issuer
   1062         issuer = new X500Name(derStrm);
   1063         if (issuer.isEmpty()) {
   1064             throw new CRLException("Empty issuer DN not allowed in X509CRLs");
   1065         }
   1066 
   1067         // thisUpdate
   1068         // check if UTCTime encoded or GeneralizedTime
   1069 
   1070         nextByte = (byte)derStrm.peekByte();
   1071         if (nextByte == DerValue.tag_UtcTime) {
   1072             thisUpdate = derStrm.getUTCTime();
   1073         } else if (nextByte == DerValue.tag_GeneralizedTime) {
   1074             thisUpdate = derStrm.getGeneralizedTime();
   1075         } else {
   1076             throw new CRLException("Invalid encoding for thisUpdate"
   1077                                    + " (tag=" + nextByte + ")");
   1078         }
   1079 
   1080         if (derStrm.available() == 0)
   1081            return;     // done parsing no more optional fields present
   1082 
   1083         // nextUpdate (optional)
   1084         nextByte = (byte)derStrm.peekByte();
   1085         if (nextByte == DerValue.tag_UtcTime) {
   1086             nextUpdate = derStrm.getUTCTime();
   1087         } else if (nextByte == DerValue.tag_GeneralizedTime) {
   1088             nextUpdate = derStrm.getGeneralizedTime();
   1089         } // else it is not present
   1090 
   1091         if (derStrm.available() == 0)
   1092             return;     // done parsing no more optional fields present
   1093 
   1094         // revokedCertificates (optional)
   1095         nextByte = (byte)derStrm.peekByte();
   1096         if ((nextByte == DerValue.tag_SequenceOf)
   1097             && (! ((nextByte & 0x0c0) == 0x080))) {
   1098             DerValue[] badCerts = derStrm.getSequence(4);
   1099 
   1100             X500Principal crlIssuer = getIssuerX500Principal();
   1101             X500Principal badCertIssuer = crlIssuer;
   1102             for (int i = 0; i < badCerts.length; i++) {
   1103                 X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
   1104                 badCertIssuer = getCertIssuer(entry, badCertIssuer);
   1105                 entry.setCertificateIssuer(crlIssuer, badCertIssuer);
   1106                 X509IssuerSerial issuerSerial = new X509IssuerSerial
   1107                     (badCertIssuer, entry.getSerialNumber());
   1108                 revokedMap.put(issuerSerial, entry);
   1109                 revokedList.add(entry);
   1110             }
   1111         }
   1112 
   1113         if (derStrm.available() == 0)
   1114             return;     // done parsing no extensions
   1115 
   1116         // crlExtensions (optional)
   1117         tmp = derStrm.getDerValue();
   1118         if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
   1119             extensions = new CRLExtensions(tmp.data);
   1120         }
   1121         readOnly = true;
   1122     }
   1123 
   1124     /**
   1125      * Extract the issuer X500Principal from an X509CRL. Parses the encoded
   1126      * form of the CRL to preserve the principal's ASN.1 encoding.
   1127      *
   1128      * Called by java.security.cert.X509CRL.getIssuerX500Principal().
   1129      */
   1130     public static X500Principal getIssuerX500Principal(X509CRL crl) {
   1131         try {
   1132             byte[] encoded = crl.getEncoded();
   1133             DerInputStream derIn = new DerInputStream(encoded);
   1134             DerValue tbsCert = derIn.getSequence(3)[0];
   1135             DerInputStream tbsIn = tbsCert.data;
   1136 
   1137             DerValue tmp;
   1138             // skip version number if present
   1139             byte nextByte = (byte)tbsIn.peekByte();
   1140             if (nextByte == DerValue.tag_Integer) {
   1141                 tmp = tbsIn.getDerValue();
   1142             }
   1143 
   1144             tmp = tbsIn.getDerValue();  // skip signature
   1145             tmp = tbsIn.getDerValue();  // issuer
   1146             byte[] principalBytes = tmp.toByteArray();
   1147             return new X500Principal(principalBytes);
   1148         } catch (Exception e) {
   1149             throw new RuntimeException("Could not parse issuer", e);
   1150         }
   1151     }
   1152 
   1153     /**
   1154      * Returned the encoding of the given certificate for internal use.
   1155      * Callers must guarantee that they neither modify it nor expose it
   1156      * to untrusted code. Uses getEncodedInternal() if the certificate
   1157      * is instance of X509CertImpl, getEncoded() otherwise.
   1158      */
   1159     public static byte[] getEncodedInternal(X509CRL crl) throws CRLException {
   1160         if (crl instanceof X509CRLImpl) {
   1161             return ((X509CRLImpl)crl).getEncodedInternal();
   1162         } else {
   1163             return crl.getEncoded();
   1164         }
   1165     }
   1166 
   1167     /**
   1168      * Utility method to convert an arbitrary instance of X509CRL
   1169      * to a X509CRLImpl. Does a cast if possible, otherwise reparses
   1170      * the encoding.
   1171      */
   1172     public static X509CRLImpl toImpl(X509CRL crl)
   1173             throws CRLException {
   1174         if (crl instanceof X509CRLImpl) {
   1175             return (X509CRLImpl)crl;
   1176         } else {
   1177             return X509Factory.intern(crl);
   1178         }
   1179     }
   1180 
   1181     /**
   1182      * Returns the X500 certificate issuer DN of a CRL entry.
   1183      *
   1184      * @param entry the entry to check
   1185      * @param prevCertIssuer the previous entry's certificate issuer
   1186      * @return the X500Principal in a CertificateIssuerExtension, or
   1187      *   prevCertIssuer if it does not exist
   1188      */
   1189     private X500Principal getCertIssuer(X509CRLEntryImpl entry,
   1190         X500Principal prevCertIssuer) throws IOException {
   1191 
   1192         CertificateIssuerExtension ciExt =
   1193             entry.getCertificateIssuerExtension();
   1194         if (ciExt != null) {
   1195             GeneralNames names = (GeneralNames)
   1196                 ciExt.get(CertificateIssuerExtension.ISSUER);
   1197             X500Name issuerDN = (X500Name) names.get(0).getName();
   1198             return issuerDN.asX500Principal();
   1199         } else {
   1200             return prevCertIssuer;
   1201         }
   1202     }
   1203 
   1204     @Override
   1205     public void derEncode(OutputStream out) throws IOException {
   1206         if (signedCRL == null)
   1207             throw new IOException("Null CRL to encode");
   1208         out.write(signedCRL.clone());
   1209     }
   1210 
   1211     /**
   1212      * Immutable X.509 Certificate Issuer DN and serial number pair
   1213      */
   1214     private final static class X509IssuerSerial
   1215             implements Comparable<X509IssuerSerial> {
   1216         final X500Principal issuer;
   1217         final BigInteger serial;
   1218         volatile int hashcode = 0;
   1219 
   1220         /**
   1221          * Create an X509IssuerSerial.
   1222          *
   1223          * @param issuer the issuer DN
   1224          * @param serial the serial number
   1225          */
   1226         X509IssuerSerial(X500Principal issuer, BigInteger serial) {
   1227             this.issuer = issuer;
   1228             this.serial = serial;
   1229         }
   1230 
   1231         /**
   1232          * Construct an X509IssuerSerial from an X509Certificate.
   1233          */
   1234         X509IssuerSerial(X509Certificate cert) {
   1235             this(cert.getIssuerX500Principal(), cert.getSerialNumber());
   1236         }
   1237 
   1238         /**
   1239          * Returns the issuer.
   1240          *
   1241          * @return the issuer
   1242          */
   1243         X500Principal getIssuer() {
   1244             return issuer;
   1245         }
   1246 
   1247         /**
   1248          * Returns the serial number.
   1249          *
   1250          * @return the serial number
   1251          */
   1252         BigInteger getSerial() {
   1253             return serial;
   1254         }
   1255 
   1256         /**
   1257          * Compares this X509Serial with another and returns true if they
   1258          * are equivalent.
   1259          *
   1260          * @param o the other object to compare with
   1261          * @return true if equal, false otherwise
   1262          */
   1263         public boolean equals(Object o) {
   1264             if (o == this) {
   1265                 return true;
   1266             }
   1267 
   1268             if (!(o instanceof X509IssuerSerial)) {
   1269                 return false;
   1270             }
   1271 
   1272             X509IssuerSerial other = (X509IssuerSerial) o;
   1273             if (serial.equals(other.getSerial()) &&
   1274                 issuer.equals(other.getIssuer())) {
   1275                 return true;
   1276             }
   1277             return false;
   1278         }
   1279 
   1280         /**
   1281          * Returns a hash code value for this X509IssuerSerial.
   1282          *
   1283          * @return the hash code value
   1284          */
   1285         public int hashCode() {
   1286             if (hashcode == 0) {
   1287                 int result = 17;
   1288                 result = 37*result + issuer.hashCode();
   1289                 result = 37*result + serial.hashCode();
   1290                 hashcode = result;
   1291             }
   1292             return hashcode;
   1293         }
   1294 
   1295         @Override
   1296         public int compareTo(X509IssuerSerial another) {
   1297             int cissuer = issuer.toString()
   1298                     .compareTo(another.issuer.toString());
   1299             if (cissuer != 0) return cissuer;
   1300             return this.serial.compareTo(another.serial);
   1301         }
   1302     }
   1303 }
   1304