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