• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
X509CRLImpl()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      */
X509CRLImpl(byte[] crlData)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      */
X509CRLImpl(DerValue val)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      */
X509CRLImpl(InputStream inStrm)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      */
X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate)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      */
X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate, X509CRLEntry[] badCerts)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      */
X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate, X509CRLEntry[] badCerts, CRLExtensions crlExts)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      */
getEncodedInternal()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      */
getEncoded()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      */
encodeInfo(OutputStream out)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      */
verify(PublicKey key)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      */
verify(PublicKey key, String sigProvider)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      */
sign(PrivateKey key, String algorithm)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      */
sign(PrivateKey key, String algorithm, String provider)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      */
toString()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      */
isRevoked(Certificate cert)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      */
getVersion()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      */
getIssuerDN()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      */
getIssuerX500Principal()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      */
getThisUpdate()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      */
getNextUpdate()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      */
getRevokedCertificate(BigInteger serialNumber)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      */
getRevokedCertificate(X509Certificate cert)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      */
getRevokedCertificates()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      */
getTBSCertList()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      */
getSignature()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      */
getSigAlgName()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      */
getSigAlgOID()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      */
getSigAlgParams()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      */
getSigAlgId()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      */
getAuthKeyId()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      */
getAuthKeyIdExtension()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      */
getCRLNumberExtension()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      */
getCRLNumber()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      */
getDeltaCRLIndicatorExtension()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      */
getBaseCRLNumber()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      */
getIssuerAltNameExtension()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
getIssuingDistributionPointExtension()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      */
hasUnsupportedCriticalExtension()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      */
getCriticalExtensionOIDs()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      */
getNonCriticalExtensionOIDs()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      */
getExtensionValue(String oid)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      */
getExtension(ObjectIdentifier oid)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      */
parse(DerValue val)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      */
getIssuerX500Principal(X509CRL crl)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      */
getEncodedInternal(X509CRL crl)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      */
toImpl(X509CRL crl)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      */
getCertIssuer(X509CRLEntryImpl entry, X500Principal prevCertIssuer)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
derEncode(OutputStream out)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          */
X509IssuerSerial(X500Principal issuer, BigInteger serial)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          */
X509IssuerSerial(X509Certificate cert)1234         X509IssuerSerial(X509Certificate cert) {
1235             this(cert.getIssuerX500Principal(), cert.getSerialNumber());
1236         }
1237 
1238         /**
1239          * Returns the issuer.
1240          *
1241          * @return the issuer
1242          */
getIssuer()1243         X500Principal getIssuer() {
1244             return issuer;
1245         }
1246 
1247         /**
1248          * Returns the serial number.
1249          *
1250          * @return the serial number
1251          */
getSerial()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          */
equals(Object o)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          */
hashCode()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
compareTo(X509IssuerSerial another)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