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