1 /*
2  * Copyright (c) 1997, 2020, 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.cert.Certificate;
33 import java.security.cert.X509CRL;
34 import java.security.cert.X509Certificate;
35 import java.security.cert.X509CRLEntry;
36 import java.security.cert.CRLException;
37 import java.security.*;
38 import java.util.*;
39 
40 import javax.security.auth.x500.X500Principal;
41 
42 import sun.security.provider.X509Factory;
43 import sun.security.util.*;
44 
45 /**
46  * <p>
47  * An implementation for X509 CRL (Certificate Revocation List).
48  * <p>
49  * The X.509 v2 CRL format is described below in ASN.1:
50  * <pre>
51  * CertificateList  ::=  SEQUENCE  {
52  *     tbsCertList          TBSCertList,
53  *     signatureAlgorithm   AlgorithmIdentifier,
54  *     signature            BIT STRING  }
55  * </pre>
56  * More information can be found in
57  * <a href="http://tools.ietf.org/html/rfc5280">RFC 5280: Internet X.509
58  * Public Key Infrastructure Certificate and CRL Profile</a>.
59  * <p>
60  * The ASN.1 definition of <code>tbsCertList</code> is:
61  * <pre>
62  * TBSCertList  ::=  SEQUENCE  {
63  *     version                 Version OPTIONAL,
64  *                             -- if present, must be v2
65  *     signature               AlgorithmIdentifier,
66  *     issuer                  Name,
67  *     thisUpdate              ChoiceOfTime,
68  *     nextUpdate              ChoiceOfTime OPTIONAL,
69  *     revokedCertificates     SEQUENCE OF SEQUENCE  {
70  *         userCertificate         CertificateSerialNumber,
71  *         revocationDate          ChoiceOfTime,
72  *         crlEntryExtensions      Extensions OPTIONAL
73  *                                 -- if present, must be v2
74  *         }  OPTIONAL,
75  *     crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
76  *                                  -- if present, must be v2
77  *     }
78  * </pre>
79  *
80  * @author Hemma Prafullchandra
81  * @see X509CRL
82  */
83 public class X509CRLImpl extends X509CRL implements DerEncoder {
84 
85     // CRL data, and its envelope
86     private byte[]      signedCRL = null; // DER encoded crl
87     private byte[]      signature = null; // raw signature bits
88     private byte[]      tbsCertList = null; // DER encoded "to-be-signed" CRL
89     private AlgorithmId sigAlgId = null; // sig alg in CRL
90 
91     // crl information
92     private int              version;
93     private AlgorithmId      infoSigAlgId; // sig alg in "to-be-signed" crl
94     private X500Name         issuer = null;
95     private X500Principal    issuerPrincipal = null;
96     private Date             thisUpdate = null;
97     private Date             nextUpdate = null;
98     private Map<X509IssuerSerial,X509CRLEntry> revokedMap = new TreeMap<>();
99     private List<X509CRLEntry> revokedList = new LinkedList<>();
100     private CRLExtensions    extensions = null;
101     private static final boolean isExplicit = true;
102 
103     private boolean readOnly = false;
104 
105     /**
106      * PublicKey that has previously been used to successfully verify
107      * the signature of this CRL. Null if the CRL has not
108      * yet been verified (successfully).
109      */
110     private PublicKey verifiedPublicKey;
111     /**
112      * If verifiedPublicKey is not null, name of the provider used to
113      * successfully verify the signature of this CRL, or the
114      * empty String if no provider was explicitly specified.
115      */
116     private String verifiedProvider;
117 
118     /**
119      * Not to be used. As it would lead to cases of uninitialized
120      * CRL objects.
121      */
X509CRLImpl()122     private X509CRLImpl() { }
123 
124     /**
125      * Unmarshals an X.509 CRL from its encoded form, parsing the encoded
126      * bytes.  This form of constructor is used by agents which
127      * need to examine and use CRL contents. Note that the buffer
128      * must include only one CRL, and no "garbage" may be left at
129      * the end.
130      *
131      * @param crlData the encoded bytes, with no trailing padding.
132      * @exception CRLException on parsing errors.
133      */
X509CRLImpl(byte[] crlData)134     public X509CRLImpl(byte[] crlData) throws CRLException {
135         try {
136             parse(new DerValue(crlData));
137         } catch (IOException e) {
138             signedCRL = null;
139             throw new CRLException("Parsing error: " + e.getMessage());
140         }
141     }
142 
143     /**
144      * Unmarshals an X.509 CRL from an DER value.
145      *
146      * @param val a DER value holding at least one CRL
147      * @exception CRLException on parsing errors.
148      */
X509CRLImpl(DerValue val)149     public X509CRLImpl(DerValue val) throws CRLException {
150         try {
151             parse(val);
152         } catch (IOException e) {
153             signedCRL = null;
154             throw new CRLException("Parsing error: " + e.getMessage());
155         }
156     }
157 
158     /**
159      * Unmarshals an X.509 CRL from an input stream. Only one CRL
160      * is expected at the end of the input stream.
161      *
162      * @param inStrm an input stream holding at least one CRL
163      * @exception CRLException on parsing errors.
164      */
X509CRLImpl(InputStream inStrm)165     public X509CRLImpl(InputStream inStrm) throws CRLException {
166         try {
167             parse(new DerValue(inStrm));
168         } catch (IOException e) {
169             signedCRL = null;
170             throw new CRLException("Parsing error: " + e.getMessage());
171         }
172     }
173 
174     /**
175      * Initial CRL constructor, no revoked certs, and no extensions.
176      *
177      * @param issuer the name of the CA issuing this CRL.
178      * @param thisDate the Date of this issue.
179      * @param nextDate the Date of the next CRL.
180      */
X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate)181     public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) {
182         this.issuer = issuer;
183         this.thisUpdate = thisDate;
184         this.nextUpdate = nextDate;
185     }
186 
187     /**
188      * CRL constructor, revoked certs, no extensions.
189      *
190      * @param issuer the name of the CA issuing this CRL.
191      * @param thisDate the Date of this issue.
192      * @param nextDate the Date of the next CRL.
193      * @param badCerts the array of CRL entries.
194      *
195      * @exception CRLException on parsing/construction errors.
196      */
X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate, X509CRLEntry[] badCerts)197     public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
198                        X509CRLEntry[] badCerts)
199         throws CRLException
200     {
201         this.issuer = issuer;
202         this.thisUpdate = thisDate;
203         this.nextUpdate = nextDate;
204         if (badCerts != null) {
205             X500Principal crlIssuer = getIssuerX500Principal();
206             X500Principal badCertIssuer = crlIssuer;
207             for (int i = 0; i < badCerts.length; i++) {
208                 X509CRLEntryImpl badCert = (X509CRLEntryImpl)badCerts[i];
209                 try {
210                     badCertIssuer = getCertIssuer(badCert, badCertIssuer);
211                 } catch (IOException ioe) {
212                     throw new CRLException(ioe);
213                 }
214                 badCert.setCertificateIssuer(crlIssuer, badCertIssuer);
215                 X509IssuerSerial issuerSerial = new X509IssuerSerial
216                     (badCertIssuer, badCert.getSerialNumber());
217                 this.revokedMap.put(issuerSerial, badCert);
218                 this.revokedList.add(badCert);
219                 if (badCert.hasExtensions()) {
220                     this.version = 1;
221                 }
222             }
223         }
224     }
225 
226     /**
227      * CRL constructor, revoked certs and extensions.
228      *
229      * @param issuer the name of the CA issuing this CRL.
230      * @param thisDate the Date of this issue.
231      * @param nextDate the Date of the next CRL.
232      * @param badCerts the array of CRL entries.
233      * @param crlExts the CRL extensions.
234      *
235      * @exception CRLException on parsing/construction errors.
236      */
X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate, X509CRLEntry[] badCerts, CRLExtensions crlExts)237     public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
238                X509CRLEntry[] badCerts, CRLExtensions crlExts)
239         throws CRLException
240     {
241         this(issuer, thisDate, nextDate, badCerts);
242         if (crlExts != null) {
243             this.extensions = crlExts;
244             this.version = 1;
245         }
246     }
247 
248     /**
249      * Returned the encoding as an uncloned byte array. Callers must
250      * guarantee that they neither modify it nor expose it to untrusted
251      * code.
252      */
getEncodedInternal()253     public byte[] getEncodedInternal() throws CRLException {
254         if (signedCRL == null) {
255             throw new CRLException("Null CRL to encode");
256         }
257         return signedCRL;
258     }
259 
260     /**
261      * Returns the ASN.1 DER encoded form of this CRL.
262      *
263      * @exception CRLException if an encoding error occurs.
264      */
getEncoded()265     public byte[] getEncoded() throws CRLException {
266         return getEncodedInternal().clone();
267     }
268 
269     /**
270      * Encodes the "to-be-signed" CRL to the OutputStream.
271      *
272      * @param out the OutputStream to write to.
273      * @exception CRLException on encoding errors.
274      */
encodeInfo(OutputStream out)275     public void encodeInfo(OutputStream out) throws CRLException {
276         try {
277             DerOutputStream tmp = new DerOutputStream();
278             DerOutputStream rCerts = new DerOutputStream();
279             DerOutputStream seq = new DerOutputStream();
280 
281             if (version != 0) // v2 crl encode version
282                 tmp.putInteger(version);
283             infoSigAlgId.encode(tmp);
284             if ((version == 0) && (issuer.toString() == null))
285                 throw new CRLException("Null Issuer DN not allowed in v1 CRL");
286             issuer.encode(tmp);
287 
288             if (thisUpdate.getTime() < CertificateValidity.YR_2050)
289                 tmp.putUTCTime(thisUpdate);
290             else
291                 tmp.putGeneralizedTime(thisUpdate);
292 
293             if (nextUpdate != null) {
294                 if (nextUpdate.getTime() < CertificateValidity.YR_2050)
295                     tmp.putUTCTime(nextUpdate);
296                 else
297                     tmp.putGeneralizedTime(nextUpdate);
298             }
299 
300             if (!revokedList.isEmpty()) {
301                 for (X509CRLEntry entry : revokedList) {
302                     ((X509CRLEntryImpl)entry).encode(rCerts);
303                 }
304                 tmp.write(DerValue.tag_Sequence, rCerts);
305             }
306 
307             if (extensions != null)
308                 extensions.encode(tmp, isExplicit);
309 
310             seq.write(DerValue.tag_Sequence, tmp);
311 
312             tbsCertList = seq.toByteArray();
313             out.write(tbsCertList);
314         } catch (IOException e) {
315              throw new CRLException("Encoding error: " + e.getMessage());
316         }
317     }
318 
319     /**
320      * Verifies that this CRL was signed using the
321      * private key that corresponds to the given public key.
322      *
323      * @param key the PublicKey used to carry out the verification.
324      *
325      * @exception NoSuchAlgorithmException on unsupported signature
326      * algorithms.
327      * @exception InvalidKeyException on incorrect key.
328      * @exception NoSuchProviderException if there's no default provider.
329      * @exception SignatureException on signature errors.
330      * @exception CRLException on encoding errors.
331      */
verify(PublicKey key)332     public void verify(PublicKey key)
333     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
334            NoSuchProviderException, SignatureException {
335         verify(key, "");
336     }
337 
338     /**
339      * Verifies that this CRL was signed using the
340      * private key that corresponds to the given public key,
341      * and that the signature verification was computed by
342      * the given provider.
343      *
344      * @param key the PublicKey used to carry out the verification.
345      * @param sigProvider the name of the signature provider.
346      *
347      * @exception NoSuchAlgorithmException on unsupported signature
348      * algorithms.
349      * @exception InvalidKeyException on incorrect key.
350      * @exception NoSuchProviderException on incorrect provider.
351      * @exception SignatureException on signature errors.
352      * @exception CRLException on encoding errors.
353      */
verify(PublicKey key, String sigProvider)354     public synchronized void verify(PublicKey key, String sigProvider)
355             throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
356             NoSuchProviderException, SignatureException {
357 
358         if (sigProvider == null) {
359             sigProvider = "";
360         }
361         if ((verifiedPublicKey != null) && verifiedPublicKey.equals(key)) {
362             // this CRL has already been successfully verified using
363             // this public key. Make sure providers match, too.
364             if (sigProvider.equals(verifiedProvider)) {
365                 return;
366             }
367         }
368         if (signedCRL == null) {
369             throw new CRLException("Uninitialized CRL");
370         }
371         Signature   sigVerf = null;
372         String sigName = sigAlgId.getName();
373         if (sigProvider.isEmpty()) {
374             sigVerf = Signature.getInstance(sigName);
375         } else {
376             sigVerf = Signature.getInstance(sigName, sigProvider);
377         }
378 
379         try {
380             SignatureUtil.initVerifyWithParam(sigVerf, key,
381                 SignatureUtil.getParamSpec(sigName, getSigAlgParams()));
382         } catch (ProviderException e) {
383             throw new CRLException(e.getMessage(), e.getCause());
384         } catch (InvalidAlgorithmParameterException e) {
385             throw new CRLException(e);
386         }
387 
388         if (tbsCertList == null) {
389             throw new CRLException("Uninitialized CRL");
390         }
391 
392         sigVerf.update(tbsCertList, 0, tbsCertList.length);
393 
394         if (!sigVerf.verify(signature)) {
395             throw new SignatureException("Signature does not match.");
396         }
397         verifiedPublicKey = key;
398         verifiedProvider = sigProvider;
399     }
400 
401     /**
402      * Verifies that this CRL was signed using the
403      * private key that corresponds to the given public key,
404      * and that the signature verification was computed by
405      * the given provider. Note that the specified Provider object
406      * does not have to be registered in the provider list.
407      *
408      * @param key the PublicKey used to carry out the verification.
409      * @param sigProvider the signature provider.
410      *
411      * @exception NoSuchAlgorithmException on unsupported signature
412      * algorithms.
413      * @exception InvalidKeyException on incorrect key.
414      * @exception SignatureException on signature errors.
415      * @exception CRLException on encoding errors.
416      */
verify(PublicKey key, Provider sigProvider)417     public synchronized void verify(PublicKey key, Provider sigProvider)
418             throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
419             SignatureException {
420 
421         if (signedCRL == null) {
422             throw new CRLException("Uninitialized CRL");
423         }
424         Signature sigVerf = null;
425         String sigName = sigAlgId.getName();
426         if (sigProvider == null) {
427             sigVerf = Signature.getInstance(sigName);
428         } else {
429             sigVerf = Signature.getInstance(sigName, sigProvider);
430         }
431 
432         try {
433             SignatureUtil.initVerifyWithParam(sigVerf, key,
434                 SignatureUtil.getParamSpec(sigName, getSigAlgParams()));
435         } catch (ProviderException e) {
436             throw new CRLException(e.getMessage(), e.getCause());
437         } catch (InvalidAlgorithmParameterException e) {
438             throw new CRLException(e);
439         }
440 
441         if (tbsCertList == null) {
442             throw new CRLException("Uninitialized CRL");
443         }
444 
445         sigVerf.update(tbsCertList, 0, tbsCertList.length);
446 
447         if (!sigVerf.verify(signature)) {
448             throw new SignatureException("Signature does not match.");
449         }
450         verifiedPublicKey = key;
451     }
452 
453     /**
454      * Encodes an X.509 CRL, and signs it using the given key.
455      *
456      * @param key the private key used for signing.
457      * @param algorithm the name of the signature algorithm used.
458      *
459      * @exception NoSuchAlgorithmException on unsupported signature algorithms.
460      * @exception InvalidKeyException on incorrect key.
461      * @exception NoSuchProviderException on incorrect provider.
462      * @exception SignatureException on signature errors.
463      * @exception CRLException if any mandatory data was omitted.
464      */
sign(PrivateKey key, String algorithm)465     public void sign(PrivateKey key, String algorithm)
466             throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
467                    NoSuchProviderException, SignatureException {
468         sign(key, algorithm, null);
469     }
470 
471     /**
472      * Encodes an X.509 CRL, and signs it using the given key.
473      *
474      * @param key the private key used for signing.
475      * @param algorithm the name of the signature algorithm used.
476      * @param provider (optional) the name of the provider.
477      *
478      * @exception NoSuchAlgorithmException on unsupported signature algorithms.
479      * @exception InvalidKeyException on incorrect key.
480      * @exception NoSuchProviderException on incorrect provider.
481      * @exception SignatureException on signature errors.
482      * @exception CRLException if any mandatory data was omitted.
483      */
sign(PrivateKey key, String algorithm, String provider)484     public void sign(PrivateKey key, String algorithm, String provider)
485             throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
486                    NoSuchProviderException, SignatureException {
487         try {
488             if (readOnly)
489                 throw new CRLException("cannot over-write existing CRL");
490 
491             Signature sigEngine = SignatureUtil.fromKey(algorithm, key, provider);
492             sigAlgId = SignatureUtil.fromSignature(sigEngine, key);
493             infoSigAlgId = sigAlgId;
494 
495             DerOutputStream out = new DerOutputStream();
496             DerOutputStream tmp = new DerOutputStream();
497 
498             // encode crl info
499             encodeInfo(tmp);
500 
501             // encode algorithm identifier
502             sigAlgId.encode(tmp);
503 
504             // Create and encode the signature itself.
505             sigEngine.update(tbsCertList, 0, tbsCertList.length);
506             signature = sigEngine.sign();
507             tmp.putBitString(signature);
508 
509             // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
510             out.write(DerValue.tag_Sequence, tmp);
511             signedCRL = out.toByteArray();
512             readOnly = true;
513 
514         } catch (IOException e) {
515             throw new CRLException("Error while encoding data: " +
516                                    e.getMessage());
517         }
518     }
519 
520     /**
521      * Returns a printable string of this CRL.
522      *
523      * @return value of this CRL in a printable form.
524      */
toString()525     public String toString() {
526         return toStringWithAlgName("" + sigAlgId);
527     }
528 
529     // Specifically created for keytool to append a (weak) label to sigAlg
toStringWithAlgName(String name)530     public String toStringWithAlgName(String name) {
531         StringBuilder sb = new StringBuilder();
532         sb.append("X.509 CRL v")
533             .append(version+1)
534             .append('\n');
535         if (sigAlgId != null)
536             sb.append("Signature Algorithm: ")
537                 .append(name)
538                 .append(", OID=")
539                 .append(sigAlgId.getOID())
540                 .append('\n');
541         if (issuer != null)
542             sb.append("Issuer: ")
543                 .append(issuer)
544                 .append('\n');
545         if (thisUpdate != null)
546             sb.append("\nThis Update: ")
547                 .append(thisUpdate)
548                 .append('\n');
549         if (nextUpdate != null)
550             sb.append("Next Update: ")
551                 .append(nextUpdate)
552                 .append('\n');
553         if (revokedList.isEmpty())
554             sb.append("\nNO certificates have been revoked\n");
555         else {
556             sb.append("\nRevoked Certificates: ")
557                 .append(revokedList.size());
558             int i = 1;
559             for (X509CRLEntry entry: revokedList) {
560                 sb.append("\n[")
561                     .append(i++)
562                     .append("] ")
563                     .append(entry);
564             }
565         }
566         if (extensions != null) {
567             Collection<Extension> allExts = extensions.getAllExtensions();
568             Object[] objs = allExts.toArray();
569             sb.append("\nCRL Extensions: ")
570                 .append(objs.length);
571             for (int i = 0; i < objs.length; i++) {
572                 sb.append("\n[").append(i+1).append("]: ");
573                 Extension ext = (Extension)objs[i];
574                 try {
575                     if (OIDMap.getClass(ext.getExtensionId()) == null) {
576                         sb.append(ext);
577                         byte[] extValue = ext.getExtensionValue();
578                         if (extValue != null) {
579                             DerOutputStream out = new DerOutputStream();
580                             out.putOctetString(extValue);
581                             extValue = out.toByteArray();
582                             HexDumpEncoder enc = new HexDumpEncoder();
583                             sb.append("Extension unknown: ")
584                                 .append("DER encoded OCTET string =\n")
585                                 .append(enc.encodeBuffer(extValue))
586                                 .append('\n');
587                         }
588                     } else {
589                         sb.append(ext); // sub-class exists
590                     }
591                 } catch (Exception e) {
592                     sb.append(", Error parsing this extension");
593                 }
594             }
595         }
596         if (signature != null) {
597             HexDumpEncoder encoder = new HexDumpEncoder();
598             sb.append("\nSignature:\n")
599                 .append(encoder.encodeBuffer(signature))
600                 .append('\n');
601         } else {
602             sb.append("NOT signed yet\n");
603         }
604         return sb.toString();
605     }
606 
607     /**
608      * Checks whether the given certificate is on this CRL.
609      *
610      * @param cert the certificate to check for.
611      * @return true if the given certificate is on this CRL,
612      * false otherwise.
613      */
isRevoked(Certificate cert)614     public boolean isRevoked(Certificate cert) {
615         if (revokedMap.isEmpty() || (!(cert instanceof X509Certificate))) {
616             return false;
617         }
618         X509Certificate xcert = (X509Certificate) cert;
619         X509IssuerSerial issuerSerial = new X509IssuerSerial(xcert);
620         return revokedMap.containsKey(issuerSerial);
621     }
622 
623     /**
624      * Gets the version number from this CRL.
625      * The ASN.1 definition for this is:
626      * <pre>
627      * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
628      *             -- v3 does not apply to CRLs but appears for consistency
629      *             -- with definition of Version for certs
630      * </pre>
631      * @return the version number, i.e. 1 or 2.
632      */
getVersion()633     public int getVersion() {
634         return version+1;
635     }
636 
637     /**
638      * Gets the issuer distinguished name from this CRL.
639      * The issuer name identifies the entity who has signed (and
640      * issued the CRL). The issuer name field contains an
641      * X.500 distinguished name (DN).
642      * The ASN.1 definition for this is:
643      * <pre>
644      * issuer    Name
645      *
646      * Name ::= CHOICE { RDNSequence }
647      * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
648      * RelativeDistinguishedName ::=
649      *     SET OF AttributeValueAssertion
650      *
651      * AttributeValueAssertion ::= SEQUENCE {
652      *                               AttributeType,
653      *                               AttributeValue }
654      * AttributeType ::= OBJECT IDENTIFIER
655      * AttributeValue ::= ANY
656      * </pre>
657      * The Name describes a hierarchical name composed of attributes,
658      * such as country name, and corresponding values, such as US.
659      * The type of the component AttributeValue is determined by the
660      * AttributeType; in general it will be a directoryString.
661      * A directoryString is usually one of PrintableString,
662      * TeletexString or UniversalString.
663      * @return the issuer name.
664      */
665     @SuppressWarnings("deprecation")
getIssuerDN()666     public Principal getIssuerDN() {
667         return issuer;
668     }
669 
670     /**
671      * Return the issuer as X500Principal. Overrides method in X509CRL
672      * to provide a slightly more efficient version.
673      */
getIssuerX500Principal()674     public X500Principal getIssuerX500Principal() {
675         if (issuerPrincipal == null) {
676             issuerPrincipal = issuer.asX500Principal();
677         }
678         return issuerPrincipal;
679     }
680 
681     /**
682      * Gets the thisUpdate date from the CRL.
683      * The ASN.1 definition for this is:
684      *
685      * @return the thisUpdate date from the CRL.
686      */
getThisUpdate()687     public Date getThisUpdate() {
688         return (new Date(thisUpdate.getTime()));
689     }
690 
691     /**
692      * Gets the nextUpdate date from the CRL.
693      *
694      * @return the nextUpdate date from the CRL, or null if
695      * not present.
696      */
getNextUpdate()697     public Date getNextUpdate() {
698         if (nextUpdate == null)
699             return null;
700         return (new Date(nextUpdate.getTime()));
701     }
702 
703     /**
704      * Gets the CRL entry with the given serial number from this CRL.
705      *
706      * @return the entry with the given serial number, or <code>null</code> if
707      * no such entry exists in the CRL.
708      * @see X509CRLEntry
709      */
getRevokedCertificate(BigInteger serialNumber)710     public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
711         if (revokedMap.isEmpty()) {
712             return null;
713         }
714         // assume this is a direct CRL entry (cert and CRL issuer are the same)
715         X509IssuerSerial issuerSerial = new X509IssuerSerial
716             (getIssuerX500Principal(), serialNumber);
717         return revokedMap.get(issuerSerial);
718     }
719 
720     /**
721      * Gets the CRL entry for the given certificate.
722      */
getRevokedCertificate(X509Certificate cert)723     public X509CRLEntry getRevokedCertificate(X509Certificate cert) {
724         if (revokedMap.isEmpty()) {
725             return null;
726         }
727         X509IssuerSerial issuerSerial = new X509IssuerSerial(cert);
728         return revokedMap.get(issuerSerial);
729     }
730 
731     /**
732      * Gets all the revoked certificates from the CRL.
733      * A Set of X509CRLEntry.
734      *
735      * @return all the revoked certificates or <code>null</code> if there are
736      * none.
737      * @see X509CRLEntry
738      */
getRevokedCertificates()739     public Set<X509CRLEntry> getRevokedCertificates() {
740         if (revokedList.isEmpty()) {
741             return null;
742         } else {
743             return new TreeSet<X509CRLEntry>(revokedList);
744         }
745     }
746 
747     /**
748      * Gets the DER encoded CRL information, the
749      * <code>tbsCertList</code> from this CRL.
750      * This can be used to verify the signature independently.
751      *
752      * @return the DER encoded CRL information.
753      * @exception CRLException on encoding errors.
754      */
getTBSCertList()755     public byte[] getTBSCertList() throws CRLException {
756         if (tbsCertList == null)
757             throw new CRLException("Uninitialized CRL");
758         return tbsCertList.clone();
759     }
760 
761     /**
762      * Gets the raw Signature bits from the CRL.
763      *
764      * @return the signature.
765      */
getSignature()766     public byte[] getSignature() {
767         if (signature == null)
768             return null;
769         return signature.clone();
770     }
771 
772     /**
773      * Gets the signature algorithm name for the CRL
774      * signature algorithm. For example, the string "SHA1withDSA".
775      * The ASN.1 definition for this is:
776      * <pre>
777      * AlgorithmIdentifier  ::=  SEQUENCE  {
778      *     algorithm               OBJECT IDENTIFIER,
779      *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
780      *                             -- contains a value of the type
781      *                             -- registered for use with the
782      *                             -- algorithm object identifier value
783      * </pre>
784      *
785      * @return the signature algorithm name.
786      */
getSigAlgName()787     public String getSigAlgName() {
788         if (sigAlgId == null)
789             return null;
790         return sigAlgId.getName();
791     }
792 
793     /**
794      * Gets the signature algorithm OID string from the CRL.
795      * An OID is represented by a set of positive whole number separated
796      * by ".", that means,<br>
797      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
798      * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
799      * with DSA signature algorithm defined in
800      * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
801      * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
802      * and CRL Profile</a>.
803      *
804      * @return the signature algorithm oid string.
805      */
getSigAlgOID()806     public String getSigAlgOID() {
807         if (sigAlgId == null)
808             return null;
809         ObjectIdentifier oid = sigAlgId.getOID();
810         return oid.toString();
811     }
812 
813     /**
814      * Gets the DER encoded signature algorithm parameters from this
815      * CRL's signature algorithm. In most cases, the signature
816      * algorithm parameters are null, the parameters are usually
817      * supplied with the Public Key.
818      *
819      * @return the DER encoded signature algorithm parameters, or
820      *         null if no parameters are present.
821      */
getSigAlgParams()822     public byte[] getSigAlgParams() {
823         if (sigAlgId == null)
824             return null;
825         try {
826             return sigAlgId.getEncodedParams();
827         } catch (IOException e) {
828             return null;
829         }
830     }
831 
832     /**
833      * Gets the signature AlgorithmId from the CRL.
834      *
835      * @return the signature AlgorithmId
836      */
getSigAlgId()837     public AlgorithmId getSigAlgId() {
838         return sigAlgId;
839     }
840 
841     /**
842      * return the AuthorityKeyIdentifier, if any.
843      *
844      * @return AuthorityKeyIdentifier or null
845      *         (if no AuthorityKeyIdentifierExtension)
846      * @throws IOException on error
847      */
getAuthKeyId()848     public KeyIdentifier getAuthKeyId() throws IOException {
849         AuthorityKeyIdentifierExtension aki = getAuthKeyIdExtension();
850         if (aki != null) {
851             KeyIdentifier keyId = (KeyIdentifier)aki.get(
852                     AuthorityKeyIdentifierExtension.KEY_ID);
853             return keyId;
854         } else {
855             return null;
856         }
857     }
858 
859     /**
860      * return the AuthorityKeyIdentifierExtension, if any.
861      *
862      * @return AuthorityKeyIdentifierExtension or null (if no such extension)
863      * @throws IOException on error
864      */
getAuthKeyIdExtension()865     public AuthorityKeyIdentifierExtension getAuthKeyIdExtension()
866         throws IOException {
867         Object obj = getExtension(PKIXExtensions.AuthorityKey_Id);
868         return (AuthorityKeyIdentifierExtension)obj;
869     }
870 
871     /**
872      * return the CRLNumberExtension, if any.
873      *
874      * @return CRLNumberExtension or null (if no such extension)
875      * @throws IOException on error
876      */
getCRLNumberExtension()877     public CRLNumberExtension getCRLNumberExtension() throws IOException {
878         Object obj = getExtension(PKIXExtensions.CRLNumber_Id);
879         return (CRLNumberExtension)obj;
880     }
881 
882     /**
883      * return the CRL number from the CRLNumberExtension, if any.
884      *
885      * @return number or null (if no such extension)
886      * @throws IOException on error
887      */
getCRLNumber()888     public BigInteger getCRLNumber() throws IOException {
889         CRLNumberExtension numExt = getCRLNumberExtension();
890         if (numExt != null) {
891             BigInteger num = numExt.get(CRLNumberExtension.NUMBER);
892             return num;
893         } else {
894             return null;
895         }
896     }
897 
898     /**
899      * return the DeltaCRLIndicatorExtension, if any.
900      *
901      * @return DeltaCRLIndicatorExtension or null (if no such extension)
902      * @throws IOException on error
903      */
getDeltaCRLIndicatorExtension()904     public DeltaCRLIndicatorExtension getDeltaCRLIndicatorExtension()
905         throws IOException {
906 
907         Object obj = getExtension(PKIXExtensions.DeltaCRLIndicator_Id);
908         return (DeltaCRLIndicatorExtension)obj;
909     }
910 
911     /**
912      * return the base CRL number from the DeltaCRLIndicatorExtension, if any.
913      *
914      * @return number or null (if no such extension)
915      * @throws IOException on error
916      */
getBaseCRLNumber()917     public BigInteger getBaseCRLNumber() throws IOException {
918         DeltaCRLIndicatorExtension dciExt = getDeltaCRLIndicatorExtension();
919         if (dciExt != null) {
920             BigInteger num = dciExt.get(DeltaCRLIndicatorExtension.NUMBER);
921             return num;
922         } else {
923             return null;
924         }
925     }
926 
927     /**
928      * return the IssuerAlternativeNameExtension, if any.
929      *
930      * @return IssuerAlternativeNameExtension or null (if no such extension)
931      * @throws IOException on error
932      */
getIssuerAltNameExtension()933     public IssuerAlternativeNameExtension getIssuerAltNameExtension()
934         throws IOException {
935         Object obj = getExtension(PKIXExtensions.IssuerAlternativeName_Id);
936         return (IssuerAlternativeNameExtension)obj;
937     }
938 
939     /**
940      * return the IssuingDistributionPointExtension, if any.
941      *
942      * @return IssuingDistributionPointExtension or null
943      *         (if no such extension)
944      * @throws IOException on error
945      */
946     public IssuingDistributionPointExtension
getIssuingDistributionPointExtension()947         getIssuingDistributionPointExtension() throws IOException {
948 
949         Object obj = getExtension(PKIXExtensions.IssuingDistributionPoint_Id);
950         return (IssuingDistributionPointExtension) obj;
951     }
952 
953     /**
954      * Return true if a critical extension is found that is
955      * not supported, otherwise return false.
956      */
hasUnsupportedCriticalExtension()957     public boolean hasUnsupportedCriticalExtension() {
958         if (extensions == null)
959             return false;
960         return extensions.hasUnsupportedCriticalExtension();
961     }
962 
963     /**
964      * Gets a Set of the extension(s) marked CRITICAL in the
965      * CRL. In the returned set, each extension is represented by
966      * its OID string.
967      *
968      * @return a set of the extension oid strings in the
969      * CRL that are marked critical.
970      */
getCriticalExtensionOIDs()971     public Set<String> getCriticalExtensionOIDs() {
972         if (extensions == null) {
973             return null;
974         }
975         Set<String> extSet = new TreeSet<>();
976         for (Extension ex : extensions.getAllExtensions()) {
977             if (ex.isCritical()) {
978                 extSet.add(ex.getExtensionId().toString());
979             }
980         }
981         return extSet;
982     }
983 
984     /**
985      * Gets a Set of the extension(s) marked NON-CRITICAL in the
986      * CRL. In the returned set, each extension is represented by
987      * its OID string.
988      *
989      * @return a set of the extension oid strings in the
990      * CRL that are NOT marked critical.
991      */
getNonCriticalExtensionOIDs()992     public Set<String> getNonCriticalExtensionOIDs() {
993         if (extensions == null) {
994             return null;
995         }
996         Set<String> extSet = new TreeSet<>();
997         for (Extension ex : extensions.getAllExtensions()) {
998             if (!ex.isCritical()) {
999                 extSet.add(ex.getExtensionId().toString());
1000             }
1001         }
1002         return extSet;
1003     }
1004 
1005     /**
1006      * Gets the DER encoded OCTET string for the extension value
1007      * (<code>extnValue</code>) identified by the passed in oid String.
1008      * The <code>oid</code> string is
1009      * represented by a set of positive whole number separated
1010      * by ".", that means,<br>
1011      * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
1012      *
1013      * @param oid the Object Identifier value for the extension.
1014      * @return the der encoded octet string of the extension value.
1015      */
getExtensionValue(String oid)1016     public byte[] getExtensionValue(String oid) {
1017         if (extensions == null)
1018             return null;
1019         try {
1020             String extAlias = OIDMap.getName(ObjectIdentifier.of(oid));
1021             Extension crlExt = null;
1022 
1023             if (extAlias == null) { // may be unknown
1024                 ObjectIdentifier findOID = ObjectIdentifier.of(oid);
1025                 Extension ex = null;
1026                 ObjectIdentifier inCertOID;
1027                 for (Enumeration<Extension> e = extensions.getElements();
1028                                                  e.hasMoreElements();) {
1029                     ex = e.nextElement();
1030                     inCertOID = ex.getExtensionId();
1031                     if (inCertOID.equals(findOID)) {
1032                         crlExt = ex;
1033                         break;
1034                     }
1035                 }
1036             } else
1037                 crlExt = extensions.get(extAlias);
1038             if (crlExt == null)
1039                 return null;
1040             byte[] extData = crlExt.getExtensionValue();
1041             if (extData == null)
1042                 return null;
1043             DerOutputStream out = new DerOutputStream();
1044             out.putOctetString(extData);
1045             return out.toByteArray();
1046         } catch (Exception e) {
1047             return null;
1048         }
1049     }
1050 
1051     /**
1052      * get an extension
1053      *
1054      * @param oid ObjectIdentifier of extension desired
1055      * @return Object of type {@code <extension>} or null, if not found
1056      * @throws IOException on error
1057      */
getExtension(ObjectIdentifier oid)1058     public Object getExtension(ObjectIdentifier oid) {
1059         if (extensions == null)
1060             return null;
1061 
1062         // XXX Consider cloning this
1063         return extensions.get(OIDMap.getName(oid));
1064     }
1065 
1066     /*
1067      * Parses an X.509 CRL, should be used only by constructors.
1068      */
parse(DerValue val)1069     private void parse(DerValue val) throws CRLException, IOException {
1070         // check if can over write the certificate
1071         if (readOnly)
1072             throw new CRLException("cannot over-write existing CRL");
1073 
1074         if ( val.getData() == null || val.tag != DerValue.tag_Sequence)
1075             throw new CRLException("Invalid DER-encoded CRL data");
1076 
1077         signedCRL = val.toByteArray();
1078         DerValue[] seq = new DerValue[3];
1079 
1080         seq[0] = val.data.getDerValue();
1081         seq[1] = val.data.getDerValue();
1082         seq[2] = val.data.getDerValue();
1083 
1084         if (val.data.available() != 0)
1085             throw new CRLException("signed overrun, bytes = "
1086                                      + val.data.available());
1087 
1088         if (seq[0].tag != DerValue.tag_Sequence)
1089             throw new CRLException("signed CRL fields invalid");
1090 
1091         sigAlgId = AlgorithmId.parse(seq[1]);
1092         signature = seq[2].getBitString();
1093 
1094         if (seq[1].data.available() != 0)
1095             throw new CRLException("AlgorithmId field overrun");
1096 
1097         if (seq[2].data.available() != 0)
1098             throw new CRLException("Signature field overrun");
1099 
1100         // the tbsCertsList
1101         tbsCertList = seq[0].toByteArray();
1102 
1103         // parse the information
1104         DerInputStream derStrm = seq[0].data;
1105         DerValue       tmp;
1106         byte           nextByte;
1107 
1108         // version (optional if v1)
1109         version = 0;   // by default, version = v1 == 0
1110         nextByte = (byte)derStrm.peekByte();
1111         if (nextByte == DerValue.tag_Integer) {
1112             version = derStrm.getInteger();
1113             if (version != 1)  // i.e. v2
1114                 throw new CRLException("Invalid version");
1115         }
1116         tmp = derStrm.getDerValue();
1117 
1118         // signature
1119         AlgorithmId tmpId = AlgorithmId.parse(tmp);
1120 
1121         // the "inner" and "outer" signature algorithms must match
1122         if (! tmpId.equals(sigAlgId))
1123             throw new CRLException("Signature algorithm mismatch");
1124         infoSigAlgId = tmpId;
1125 
1126         // issuer
1127         issuer = new X500Name(derStrm);
1128         if (issuer.isEmpty()) {
1129             throw new CRLException("Empty issuer DN not allowed in X509CRLs");
1130         }
1131 
1132         // thisUpdate
1133         // check if UTCTime encoded or GeneralizedTime
1134 
1135         nextByte = (byte)derStrm.peekByte();
1136         if (nextByte == DerValue.tag_UtcTime) {
1137             thisUpdate = derStrm.getUTCTime();
1138         } else if (nextByte == DerValue.tag_GeneralizedTime) {
1139             thisUpdate = derStrm.getGeneralizedTime();
1140         } else {
1141             throw new CRLException("Invalid encoding for thisUpdate"
1142                                    + " (tag=" + nextByte + ")");
1143         }
1144 
1145         if (derStrm.available() == 0)
1146            return;     // done parsing no more optional fields present
1147 
1148         // nextUpdate (optional)
1149         nextByte = (byte)derStrm.peekByte();
1150         if (nextByte == DerValue.tag_UtcTime) {
1151             nextUpdate = derStrm.getUTCTime();
1152         } else if (nextByte == DerValue.tag_GeneralizedTime) {
1153             nextUpdate = derStrm.getGeneralizedTime();
1154         } // else it is not present
1155 
1156         if (derStrm.available() == 0)
1157             return;     // done parsing no more optional fields present
1158 
1159         // revokedCertificates (optional)
1160         nextByte = (byte)derStrm.peekByte();
1161         if ((nextByte == DerValue.tag_SequenceOf)
1162             && (! ((nextByte & 0x0c0) == 0x080))) {
1163             DerValue[] badCerts = derStrm.getSequence(4);
1164 
1165             X500Principal crlIssuer = getIssuerX500Principal();
1166             X500Principal badCertIssuer = crlIssuer;
1167             for (int i = 0; i < badCerts.length; i++) {
1168                 X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
1169                 badCertIssuer = getCertIssuer(entry, badCertIssuer);
1170                 entry.setCertificateIssuer(crlIssuer, badCertIssuer);
1171                 X509IssuerSerial issuerSerial = new X509IssuerSerial
1172                     (badCertIssuer, entry.getSerialNumber());
1173                 revokedMap.put(issuerSerial, entry);
1174                 revokedList.add(entry);
1175             }
1176         }
1177 
1178         if (derStrm.available() == 0)
1179             return;     // done parsing no extensions
1180 
1181         // crlExtensions (optional)
1182         tmp = derStrm.getDerValue();
1183         if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
1184             extensions = new CRLExtensions(tmp.data);
1185         }
1186         readOnly = true;
1187     }
1188 
1189     /**
1190      * Extract the issuer X500Principal from an X509CRL. Parses the encoded
1191      * form of the CRL to preserve the principal's ASN.1 encoding.
1192      *
1193      * Called by java.security.cert.X509CRL.getIssuerX500Principal().
1194      */
getIssuerX500Principal(X509CRL crl)1195     public static X500Principal getIssuerX500Principal(X509CRL crl) {
1196         try {
1197             byte[] encoded = crl.getEncoded();
1198             DerInputStream derIn = new DerInputStream(encoded);
1199             DerValue tbsCert = derIn.getSequence(3)[0];
1200             DerInputStream tbsIn = tbsCert.data;
1201 
1202             DerValue tmp;
1203             // skip version number if present
1204             byte nextByte = (byte)tbsIn.peekByte();
1205             if (nextByte == DerValue.tag_Integer) {
1206                 tmp = tbsIn.getDerValue();
1207             }
1208 
1209             tmp = tbsIn.getDerValue();  // skip signature
1210             tmp = tbsIn.getDerValue();  // issuer
1211             byte[] principalBytes = tmp.toByteArray();
1212             return new X500Principal(principalBytes);
1213         } catch (Exception e) {
1214             throw new RuntimeException("Could not parse issuer", e);
1215         }
1216     }
1217 
1218     /**
1219      * Returned the encoding of the given certificate for internal use.
1220      * Callers must guarantee that they neither modify it nor expose it
1221      * to untrusted code. Uses getEncodedInternal() if the certificate
1222      * is instance of X509CertImpl, getEncoded() otherwise.
1223      */
getEncodedInternal(X509CRL crl)1224     public static byte[] getEncodedInternal(X509CRL crl) throws CRLException {
1225         if (crl instanceof X509CRLImpl) {
1226             return ((X509CRLImpl)crl).getEncodedInternal();
1227         } else {
1228             return crl.getEncoded();
1229         }
1230     }
1231 
1232     /**
1233      * Utility method to convert an arbitrary instance of X509CRL
1234      * to a X509CRLImpl. Does a cast if possible, otherwise reparses
1235      * the encoding.
1236      */
toImpl(X509CRL crl)1237     public static X509CRLImpl toImpl(X509CRL crl)
1238             throws CRLException {
1239         if (crl instanceof X509CRLImpl) {
1240             return (X509CRLImpl)crl;
1241         } else {
1242             return X509Factory.intern(crl);
1243         }
1244     }
1245 
1246     /**
1247      * Returns the X500 certificate issuer DN of a CRL entry.
1248      *
1249      * @param entry the entry to check
1250      * @param prevCertIssuer the previous entry's certificate issuer
1251      * @return the X500Principal in a CertificateIssuerExtension, or
1252      *   prevCertIssuer if it does not exist
1253      */
getCertIssuer(X509CRLEntryImpl entry, X500Principal prevCertIssuer)1254     private X500Principal getCertIssuer(X509CRLEntryImpl entry,
1255         X500Principal prevCertIssuer) throws IOException {
1256 
1257         CertificateIssuerExtension ciExt =
1258             entry.getCertificateIssuerExtension();
1259         if (ciExt != null) {
1260             GeneralNames names = ciExt.get(CertificateIssuerExtension.ISSUER);
1261             X500Name issuerDN = (X500Name) names.get(0).getName();
1262             return issuerDN.asX500Principal();
1263         } else {
1264             return prevCertIssuer;
1265         }
1266     }
1267 
1268     @Override
derEncode(OutputStream out)1269     public void derEncode(OutputStream out) throws IOException {
1270         if (signedCRL == null)
1271             throw new IOException("Null CRL to encode");
1272         out.write(signedCRL.clone());
1273     }
1274 
1275     /**
1276      * Immutable X.509 Certificate Issuer DN and serial number pair
1277      */
1278     private static final class X509IssuerSerial
1279             implements Comparable<X509IssuerSerial> {
1280         final X500Principal issuer;
1281         final BigInteger serial;
1282         volatile int hashcode;
1283 
1284         /**
1285          * Create an X509IssuerSerial.
1286          *
1287          * @param issuer the issuer DN
1288          * @param serial the serial number
1289          */
X509IssuerSerial(X500Principal issuer, BigInteger serial)1290         X509IssuerSerial(X500Principal issuer, BigInteger serial) {
1291             this.issuer = issuer;
1292             this.serial = serial;
1293         }
1294 
1295         /**
1296          * Construct an X509IssuerSerial from an X509Certificate.
1297          */
X509IssuerSerial(X509Certificate cert)1298         X509IssuerSerial(X509Certificate cert) {
1299             this(cert.getIssuerX500Principal(), cert.getSerialNumber());
1300         }
1301 
1302         /**
1303          * Returns the issuer.
1304          *
1305          * @return the issuer
1306          */
getIssuer()1307         X500Principal getIssuer() {
1308             return issuer;
1309         }
1310 
1311         /**
1312          * Returns the serial number.
1313          *
1314          * @return the serial number
1315          */
getSerial()1316         BigInteger getSerial() {
1317             return serial;
1318         }
1319 
1320         /**
1321          * Compares this X509Serial with another and returns true if they
1322          * are equivalent.
1323          *
1324          * @param o the other object to compare with
1325          * @return true if equal, false otherwise
1326          */
equals(Object o)1327         public boolean equals(Object o) {
1328             if (o == this) {
1329                 return true;
1330             }
1331 
1332             if (!(o instanceof X509IssuerSerial)) {
1333                 return false;
1334             }
1335 
1336             X509IssuerSerial other = (X509IssuerSerial) o;
1337             if (serial.equals(other.getSerial()) &&
1338                 issuer.equals(other.getIssuer())) {
1339                 return true;
1340             }
1341             return false;
1342         }
1343 
1344         /**
1345          * Returns a hash code value for this X509IssuerSerial.
1346          *
1347          * @return the hash code value
1348          */
hashCode()1349         public int hashCode() {
1350             int h = hashcode;
1351             if (h == 0) {
1352                 h = 17;
1353                 h = 37*h + issuer.hashCode();
1354                 h = 37*h + serial.hashCode();
1355                 if (h != 0) {
1356                     hashcode = h;
1357                 }
1358             }
1359             return h;
1360         }
1361 
1362         @Override
compareTo(X509IssuerSerial another)1363         public int compareTo(X509IssuerSerial another) {
1364             int cissuer = issuer.toString()
1365                     .compareTo(another.issuer.toString());
1366             if (cissuer != 0) return cissuer;
1367             return this.serial.compareTo(another.serial);
1368         }
1369     }
1370 }
1371