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