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