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