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