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