1 package org.bouncycastle.jce.provider; 2 3 import java.io.IOException; 4 import java.math.BigInteger; 5 import java.security.InvalidKeyException; 6 import java.security.NoSuchAlgorithmException; 7 import java.security.NoSuchProviderException; 8 import java.security.Principal; 9 import java.security.Provider; 10 import java.security.PublicKey; 11 import java.security.Signature; 12 import java.security.SignatureException; 13 import java.security.cert.CRLException; 14 import java.security.cert.Certificate; 15 import java.security.cert.CertificateEncodingException; 16 import java.security.cert.X509CRL; 17 import java.security.cert.X509CRLEntry; 18 import java.security.cert.X509Certificate; 19 import java.util.Collections; 20 import java.util.Date; 21 import java.util.Enumeration; 22 import java.util.HashSet; 23 import java.util.Iterator; 24 import java.util.Set; 25 26 import javax.security.auth.x500.X500Principal; 27 28 import org.bouncycastle.asn1.ASN1Encodable; 29 import org.bouncycastle.asn1.ASN1Encoding; 30 import org.bouncycastle.asn1.ASN1InputStream; 31 import org.bouncycastle.asn1.ASN1Integer; 32 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 33 import org.bouncycastle.asn1.ASN1OctetString; 34 import org.bouncycastle.asn1.util.ASN1Dump; 35 import org.bouncycastle.asn1.x500.X500Name; 36 import org.bouncycastle.asn1.x509.CRLDistPoint; 37 import org.bouncycastle.asn1.x509.CRLNumber; 38 import org.bouncycastle.asn1.x509.CertificateList; 39 import org.bouncycastle.asn1.x509.Extension; 40 import org.bouncycastle.asn1.x509.Extensions; 41 import org.bouncycastle.asn1.x509.GeneralNames; 42 import org.bouncycastle.asn1.x509.IssuingDistributionPoint; 43 import org.bouncycastle.asn1.x509.TBSCertList; 44 import org.bouncycastle.jce.X509Principal; 45 import org.bouncycastle.util.Strings; 46 import org.bouncycastle.util.encoders.Hex; 47 48 /** 49 * The following extensions are listed in RFC 2459 as relevant to CRLs 50 * 51 * Authority Key Identifier 52 * Issuer Alternative Name 53 * CRL Number 54 * Delta CRL Indicator (critical) 55 * Issuing Distribution Point (critical) 56 * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory. 57 */ 58 public class X509CRLObject 59 extends X509CRL 60 { 61 private CertificateList c; 62 private String sigAlgName; 63 private byte[] sigAlgParams; 64 private boolean isIndirect; 65 private boolean isHashCodeSet = false; 66 private int hashCodeValue; 67 68 public static boolean isIndirectCRL(X509CRL crl) 69 throws CRLException 70 { 71 try 72 { 73 byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId()); 74 return idp != null 75 && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL(); 76 } 77 catch (Exception e) 78 { 79 throw new ExtCRLException( 80 "Exception reading IssuingDistributionPoint", e); 81 } 82 } 83 84 public X509CRLObject( 85 CertificateList c) 86 throws CRLException 87 { 88 this.c = c; 89 90 try 91 { 92 this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); 93 94 if (c.getSignatureAlgorithm().getParameters() != null) 95 { 96 this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER); 97 } 98 else 99 { 100 this.sigAlgParams = null; 101 } 102 103 this.isIndirect = isIndirectCRL(this); 104 } 105 catch (Exception e) 106 { 107 throw new CRLException("CRL contents invalid: " + e); 108 } 109 } 110 111 /** 112 * Will return true if any extensions are present and marked 113 * as critical as we currently dont handle any extensions! 114 */ 115 public boolean hasUnsupportedCriticalExtension() 116 { 117 Set extns = getCriticalExtensionOIDs(); 118 119 if (extns == null) 120 { 121 return false; 122 } 123 124 extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); 125 extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); 126 127 return !extns.isEmpty(); 128 } 129 130 private Set getExtensionOIDs(boolean critical) 131 { 132 if (this.getVersion() == 2) 133 { 134 Extensions extensions = c.getTBSCertList().getExtensions(); 135 136 if (extensions != null) 137 { 138 Set set = new HashSet(); 139 Enumeration e = extensions.oids(); 140 141 while (e.hasMoreElements()) 142 { 143 ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); 144 Extension ext = extensions.getExtension(oid); 145 146 if (critical == ext.isCritical()) 147 { 148 set.add(oid.getId()); 149 } 150 } 151 152 return set; 153 } 154 } 155 156 return null; 157 } 158 159 public Set getCriticalExtensionOIDs() 160 { 161 return getExtensionOIDs(true); 162 } 163 164 public Set getNonCriticalExtensionOIDs() 165 { 166 return getExtensionOIDs(false); 167 } 168 169 public byte[] getExtensionValue(String oid) 170 { 171 Extensions exts = c.getTBSCertList().getExtensions(); 172 173 if (exts != null) 174 { 175 Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); 176 177 if (ext != null) 178 { 179 try 180 { 181 return ext.getExtnValue().getEncoded(); 182 } 183 catch (Exception e) 184 { 185 throw new IllegalStateException("error parsing " + e.toString()); 186 } 187 } 188 } 189 190 return null; 191 } 192 193 public byte[] getEncoded() 194 throws CRLException 195 { 196 try 197 { 198 return c.getEncoded(ASN1Encoding.DER); 199 } 200 catch (IOException e) 201 { 202 throw new CRLException(e.toString()); 203 } 204 } 205 206 public void verify(PublicKey key) 207 throws CRLException, NoSuchAlgorithmException, 208 InvalidKeyException, NoSuchProviderException, SignatureException 209 { 210 Signature sig; 211 212 try 213 { 214 sig = Signature.getInstance(getSigAlgName(), BouncyCastleProvider.PROVIDER_NAME); 215 } 216 catch (Exception e) 217 { 218 sig = Signature.getInstance(getSigAlgName()); 219 } 220 221 doVerify(key, sig); 222 } 223 224 public void verify(PublicKey key, String sigProvider) 225 throws CRLException, NoSuchAlgorithmException, 226 InvalidKeyException, NoSuchProviderException, SignatureException 227 { 228 Signature sig; 229 230 if (sigProvider != null) 231 { 232 sig = Signature.getInstance(getSigAlgName(), sigProvider); 233 } 234 else 235 { 236 sig = Signature.getInstance(getSigAlgName()); 237 } 238 239 doVerify(key, sig); 240 } 241 242 public void verify(PublicKey key, Provider sigProvider) 243 throws CRLException, NoSuchAlgorithmException, 244 InvalidKeyException, SignatureException 245 { 246 Signature sig; 247 248 if (sigProvider != null) 249 { 250 sig = Signature.getInstance(getSigAlgName(), sigProvider); 251 } 252 else 253 { 254 sig = Signature.getInstance(getSigAlgName()); 255 } 256 257 doVerify(key, sig); 258 } 259 260 private void doVerify(PublicKey key, Signature sig) 261 throws CRLException, NoSuchAlgorithmException, 262 InvalidKeyException, SignatureException 263 { 264 if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature())) 265 { 266 throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList."); 267 } 268 269 sig.initVerify(key); 270 sig.update(this.getTBSCertList()); 271 272 if (!sig.verify(this.getSignature())) 273 { 274 throw new SignatureException("CRL does not verify with supplied public key."); 275 } 276 } 277 278 public int getVersion() 279 { 280 return c.getVersionNumber(); 281 } 282 283 public Principal getIssuerDN() 284 { 285 return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive())); 286 } 287 288 public X500Principal getIssuerX500Principal() 289 { 290 try 291 { 292 return new X500Principal(c.getIssuer().getEncoded()); 293 } 294 catch (IOException e) 295 { 296 throw new IllegalStateException("can't encode issuer DN"); 297 } 298 } 299 300 public Date getThisUpdate() 301 { 302 return c.getThisUpdate().getDate(); 303 } 304 305 public Date getNextUpdate() 306 { 307 if (c.getNextUpdate() != null) 308 { 309 return c.getNextUpdate().getDate(); 310 } 311 312 return null; 313 } 314 315 private Set loadCRLEntries() 316 { 317 Set entrySet = new HashSet(); 318 Enumeration certs = c.getRevokedCertificateEnumeration(); 319 320 X500Name previousCertificateIssuer = null; // the issuer 321 while (certs.hasMoreElements()) 322 { 323 TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); 324 X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); 325 entrySet.add(crlEntry); 326 if (isIndirect && entry.hasExtensions()) 327 { 328 Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); 329 330 if (currentCaName != null) 331 { 332 previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); 333 } 334 } 335 } 336 337 return entrySet; 338 } 339 340 public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) 341 { 342 Enumeration certs = c.getRevokedCertificateEnumeration(); 343 344 X500Name previousCertificateIssuer = null; // the issuer 345 while (certs.hasMoreElements()) 346 { 347 TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); 348 349 if (serialNumber.equals(entry.getUserCertificate().getValue())) 350 { 351 return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); 352 } 353 354 if (isIndirect && entry.hasExtensions()) 355 { 356 Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); 357 358 if (currentCaName != null) 359 { 360 previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); 361 } 362 } 363 } 364 365 return null; 366 } 367 368 public Set getRevokedCertificates() 369 { 370 Set entrySet = loadCRLEntries(); 371 372 if (!entrySet.isEmpty()) 373 { 374 return Collections.unmodifiableSet(entrySet); 375 } 376 377 return null; 378 } 379 380 public byte[] getTBSCertList() 381 throws CRLException 382 { 383 try 384 { 385 return c.getTBSCertList().getEncoded("DER"); 386 } 387 catch (IOException e) 388 { 389 throw new CRLException(e.toString()); 390 } 391 } 392 393 public byte[] getSignature() 394 { 395 return c.getSignature().getOctets(); 396 } 397 398 public String getSigAlgName() 399 { 400 return sigAlgName; 401 } 402 403 public String getSigAlgOID() 404 { 405 return c.getSignatureAlgorithm().getAlgorithm().getId(); 406 } 407 408 public byte[] getSigAlgParams() 409 { 410 if (sigAlgParams != null) 411 { 412 byte[] tmp = new byte[sigAlgParams.length]; 413 414 System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length); 415 416 return tmp; 417 } 418 419 return null; 420 } 421 422 /** 423 * Returns a string representation of this CRL. 424 * 425 * @return a string representation of this CRL. 426 */ 427 public String toString() 428 { 429 StringBuffer buf = new StringBuffer(); 430 String nl = Strings.lineSeparator(); 431 432 buf.append(" Version: ").append(this.getVersion()).append( 433 nl); 434 buf.append(" IssuerDN: ").append(this.getIssuerDN()) 435 .append(nl); 436 buf.append(" This update: ").append(this.getThisUpdate()) 437 .append(nl); 438 buf.append(" Next update: ").append(this.getNextUpdate()) 439 .append(nl); 440 buf.append(" Signature Algorithm: ").append(this.getSigAlgName()) 441 .append(nl); 442 443 byte[] sig = this.getSignature(); 444 445 buf.append(" Signature: ").append( 446 new String(Hex.encode(sig, 0, 20))).append(nl); 447 for (int i = 20; i < sig.length; i += 20) 448 { 449 if (i < sig.length - 20) 450 { 451 buf.append(" ").append( 452 new String(Hex.encode(sig, i, 20))).append(nl); 453 } 454 else 455 { 456 buf.append(" ").append( 457 new String(Hex.encode(sig, i, sig.length - i))).append(nl); 458 } 459 } 460 461 Extensions extensions = c.getTBSCertList().getExtensions(); 462 463 if (extensions != null) 464 { 465 Enumeration e = extensions.oids(); 466 467 if (e.hasMoreElements()) 468 { 469 buf.append(" Extensions: ").append(nl); 470 } 471 472 while (e.hasMoreElements()) 473 { 474 ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement(); 475 Extension ext = extensions.getExtension(oid); 476 477 if (ext.getExtnValue() != null) 478 { 479 byte[] octs = ext.getExtnValue().getOctets(); 480 ASN1InputStream dIn = new ASN1InputStream(octs); 481 buf.append(" critical(").append( 482 ext.isCritical()).append(") "); 483 try 484 { 485 if (oid.equals(Extension.cRLNumber)) 486 { 487 buf.append( 488 new CRLNumber(ASN1Integer.getInstance( 489 dIn.readObject()).getPositiveValue())) 490 .append(nl); 491 } 492 else if (oid.equals(Extension.deltaCRLIndicator)) 493 { 494 buf.append( 495 "Base CRL: " 496 + new CRLNumber(ASN1Integer.getInstance( 497 dIn.readObject()).getPositiveValue())) 498 .append(nl); 499 } 500 else if (oid 501 .equals(Extension.issuingDistributionPoint)) 502 { 503 buf.append( 504 IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl); 505 } 506 else if (oid 507 .equals(Extension.cRLDistributionPoints)) 508 { 509 buf.append( 510 CRLDistPoint.getInstance(dIn.readObject())).append(nl); 511 } 512 else if (oid.equals(Extension.freshestCRL)) 513 { 514 buf.append( 515 CRLDistPoint.getInstance(dIn.readObject())).append(nl); 516 } 517 else 518 { 519 buf.append(oid.getId()); 520 buf.append(" value = ").append( 521 ASN1Dump.dumpAsString(dIn.readObject())) 522 .append(nl); 523 } 524 } 525 catch (Exception ex) 526 { 527 buf.append(oid.getId()); 528 buf.append(" value = ").append("*****").append(nl); 529 } 530 } 531 else 532 { 533 buf.append(nl); 534 } 535 } 536 } 537 Set set = getRevokedCertificates(); 538 if (set != null) 539 { 540 Iterator it = set.iterator(); 541 while (it.hasNext()) 542 { 543 buf.append(it.next()); 544 buf.append(nl); 545 } 546 } 547 return buf.toString(); 548 } 549 550 /** 551 * Checks whether the given certificate is on this CRL. 552 * 553 * @param cert the certificate to check for. 554 * @return true if the given certificate is on this CRL, 555 * false otherwise. 556 */ 557 public boolean isRevoked(Certificate cert) 558 { 559 if (!cert.getType().equals("X.509")) 560 { 561 throw new RuntimeException("X.509 CRL used with non X.509 Cert"); 562 } 563 564 Enumeration certs = c.getRevokedCertificateEnumeration(); 565 566 X500Name caName = c.getIssuer(); 567 568 if (certs != null) 569 { 570 BigInteger serial = ((X509Certificate)cert).getSerialNumber(); 571 572 while (certs.hasMoreElements()) 573 { 574 TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement()); 575 576 if (isIndirect && entry.hasExtensions()) 577 { 578 Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); 579 580 if (currentCaName != null) 581 { 582 caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); 583 } 584 } 585 586 if (entry.getUserCertificate().getValue().equals(serial)) 587 { 588 X500Name issuer; 589 590 if (cert instanceof X509Certificate) 591 { 592 issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded()); 593 } 594 else 595 { 596 try 597 { 598 issuer = org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer(); 599 } 600 catch (CertificateEncodingException e) 601 { 602 throw new RuntimeException("Cannot process certificate"); 603 } 604 } 605 606 if (!caName.equals(issuer)) 607 { 608 return false; 609 } 610 611 return true; 612 } 613 } 614 } 615 616 return false; 617 } 618 619 public boolean equals(Object other) 620 { 621 if (this == other) 622 { 623 return true; 624 } 625 626 if (!(other instanceof X509CRL)) 627 { 628 return false; 629 } 630 631 if (other instanceof X509CRLObject) 632 { 633 X509CRLObject crlObject = (X509CRLObject)other; 634 635 if (isHashCodeSet) 636 { 637 boolean otherIsHashCodeSet = crlObject.isHashCodeSet; 638 if (otherIsHashCodeSet) 639 { 640 if (crlObject.hashCodeValue != hashCodeValue) 641 { 642 return false; 643 } 644 } 645 } 646 647 return this.c.equals(crlObject.c); 648 } 649 650 return super.equals(other); 651 } 652 653 public int hashCode() 654 { 655 if (!isHashCodeSet) 656 { 657 isHashCodeSet = true; 658 hashCodeValue = super.hashCode(); 659 } 660 661 return hashCodeValue; 662 } 663 } 664 665