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