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