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