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