1 package org.bouncycastle.jce.provider; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.math.BigInteger; 6 import java.security.InvalidKeyException; 7 import java.security.NoSuchAlgorithmException; 8 import java.security.NoSuchProviderException; 9 import java.security.Principal; 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.X509CRL; 16 import java.security.cert.X509CRLEntry; 17 import java.security.cert.X509Certificate; 18 import java.util.Date; 19 import java.util.Enumeration; 20 import java.util.HashSet; 21 import java.util.Set; 22 23 import javax.security.auth.x500.X500Principal; 24 25 import org.bouncycastle.asn1.ASN1Encodable; 26 import org.bouncycastle.asn1.ASN1OutputStream; 27 import org.bouncycastle.asn1.DERObjectIdentifier; 28 import org.bouncycastle.asn1.DEROutputStream; 29 import org.bouncycastle.asn1.x509.CertificateList; 30 import org.bouncycastle.asn1.x509.IssuingDistributionPoint; 31 import org.bouncycastle.asn1.x509.TBSCertList; 32 import org.bouncycastle.asn1.x509.X509Extension; 33 import org.bouncycastle.asn1.x509.X509Extensions; 34 import org.bouncycastle.jce.X509Principal; 35 import org.bouncycastle.x509.extension.X509ExtensionUtil; 36 37 /** 38 * The following extensions are listed in RFC 2459 as relevant to CRLs 39 * 40 * Authority Key Identifier 41 * Issuer Alternative Name 42 * CRL Number 43 * Delta CRL Indicator (critical) 44 * Issuing Distribution Point (critical) 45 */ 46 public class X509CRLObject 47 extends X509CRL 48 { 49 private CertificateList c; 50 private String sigAlgName; 51 private byte[] sigAlgParams; 52 53 public X509CRLObject( 54 CertificateList c) 55 throws CRLException 56 { 57 this.c = c; 58 59 try 60 { 61 this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); 62 63 if (c.getSignatureAlgorithm().getParameters() != null) 64 { 65 this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).getDEREncoded(); 66 } 67 else 68 { 69 this.sigAlgParams = null; 70 } 71 } 72 catch (Exception e) 73 { 74 throw new CRLException("CRL contents invalid: " + e); 75 } 76 } 77 78 /** 79 * Will return true if any extensions are present and marked 80 * as critical as we currently dont handle any extensions! 81 */ 82 public boolean hasUnsupportedCriticalExtension() 83 { 84 Set extns = getCriticalExtensionOIDs(); 85 if (extns != null && !extns.isEmpty()) 86 { 87 return true; 88 } 89 90 return false; 91 } 92 93 private Set getExtensionOIDs(boolean critical) 94 { 95 if (this.getVersion() == 2) 96 { 97 Set set = new HashSet(); 98 X509Extensions extensions = c.getTBSCertList().getExtensions(); 99 Enumeration e = extensions.oids(); 100 101 while (e.hasMoreElements()) 102 { 103 DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement(); 104 X509Extension ext = extensions.getExtension(oid); 105 106 if (critical == ext.isCritical()) 107 { 108 set.add(oid.getId()); 109 } 110 } 111 112 return set; 113 } 114 115 return null; 116 } 117 118 public Set getCriticalExtensionOIDs() 119 { 120 return getExtensionOIDs(true); 121 } 122 123 public Set getNonCriticalExtensionOIDs() 124 { 125 return getExtensionOIDs(false); 126 } 127 128 public byte[] getExtensionValue(String oid) 129 { 130 X509Extensions exts = c.getTBSCertList().getExtensions(); 131 132 if (exts != null) 133 { 134 X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid)); 135 136 if (ext != null) 137 { 138 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 139 DEROutputStream dOut = new DEROutputStream(bOut); 140 141 try 142 { 143 dOut.writeObject(ext.getValue()); 144 145 return bOut.toByteArray(); 146 } 147 catch (Exception e) 148 { 149 throw new RuntimeException("error encoding " + e.toString()); 150 } 151 } 152 } 153 154 return null; 155 } 156 157 public byte[] getEncoded() 158 throws CRLException 159 { 160 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 161 DEROutputStream dOut = new DEROutputStream(bOut); 162 163 try 164 { 165 dOut.writeObject(c); 166 167 return bOut.toByteArray(); 168 } 169 catch (IOException e) 170 { 171 throw new CRLException(e.toString()); 172 } 173 } 174 175 public void verify(PublicKey key) 176 throws CRLException, NoSuchAlgorithmException, 177 InvalidKeyException, NoSuchProviderException, SignatureException 178 { 179 verify(key, "BC"); 180 } 181 182 public void verify(PublicKey key, String sigProvider) 183 throws CRLException, NoSuchAlgorithmException, 184 InvalidKeyException, NoSuchProviderException, SignatureException 185 { 186 if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature())) 187 { 188 throw new CRLException("Signature algorithm on CertifcateList does not match TBSCertList."); 189 } 190 191 Signature sig = Signature.getInstance(getSigAlgName(), sigProvider); 192 193 sig.initVerify(key); 194 sig.update(this.getTBSCertList()); 195 if (!sig.verify(this.getSignature())) 196 { 197 throw new SignatureException("CRL does not verify with supplied public key."); 198 } 199 } 200 201 public int getVersion() 202 { 203 return c.getVersion(); 204 } 205 206 public Principal getIssuerDN() 207 { 208 return new X509Principal(c.getIssuer()); 209 } 210 211 public X500Principal getIssuerX500Principal() 212 { 213 try 214 { 215 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 216 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 217 218 aOut.writeObject(c.getIssuer()); 219 220 return new X500Principal(bOut.toByteArray()); 221 } 222 catch (IOException e) 223 { 224 throw new IllegalStateException("can't encode issuer DN"); 225 } 226 } 227 228 public Date getThisUpdate() 229 { 230 return c.getThisUpdate().getDate(); 231 } 232 233 public Date getNextUpdate() 234 { 235 if (c.getNextUpdate() != null) 236 { 237 return c.getNextUpdate().getDate(); 238 } 239 240 return null; 241 } 242 243 public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) 244 { 245 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); 246 boolean isIndirect = isIndirectCRL(); 247 if (certs != null) 248 { 249 X500Principal previousCertificateIssuer = getIssuerX500Principal(); 250 for (int i = 0; i < certs.length; i++) 251 { 252 X509CRLEntryObject crlentry = new X509CRLEntryObject(certs[i], 253 isIndirect, previousCertificateIssuer); 254 previousCertificateIssuer = crlentry.getCertificateIssuer(); 255 if (crlentry.getSerialNumber().equals(serialNumber)) 256 { 257 return crlentry; 258 } 259 } 260 } 261 262 return null; 263 } 264 265 private boolean isIndirectCRL() 266 { 267 byte[] idp = getExtensionValue(X509Extensions.IssuingDistributionPoint.getId()); 268 boolean isIndirect = false; 269 try 270 { 271 if (idp != null) 272 { 273 isIndirect = IssuingDistributionPoint.getInstance( 274 X509ExtensionUtil.fromExtensionValue(idp)) 275 .isIndirectCRL(); 276 } 277 } 278 catch (IOException e) 279 { 280 throw new RuntimeException( 281 "Exception reading IssuingDistributionPoint" + e); 282 } 283 284 return isIndirect; 285 } 286 287 public Set getRevokedCertificates() 288 { 289 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); 290 boolean isIndirect = isIndirectCRL(); 291 if (certs != null) 292 { 293 Set set = new HashSet(); 294 X500Principal previousCertificateIssuer = getIssuerX500Principal(); 295 for (int i = 0; i < certs.length; i++) 296 { 297 X509CRLEntryObject crlentry = new X509CRLEntryObject(certs[i], 298 isIndirect, previousCertificateIssuer); 299 set.add(crlentry); 300 previousCertificateIssuer = crlentry.getCertificateIssuer(); 301 } 302 303 return set; 304 } 305 306 return null; 307 } 308 309 public byte[] getTBSCertList() 310 throws CRLException 311 { 312 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 313 DEROutputStream dOut = new DEROutputStream(bOut); 314 315 try 316 { 317 dOut.writeObject(c.getTBSCertList()); 318 319 return bOut.toByteArray(); 320 } 321 catch (IOException e) 322 { 323 throw new CRLException(e.toString()); 324 } 325 } 326 327 public byte[] getSignature() 328 { 329 return c.getSignature().getBytes(); 330 } 331 332 public String getSigAlgName() 333 { 334 return sigAlgName; 335 } 336 337 public String getSigAlgOID() 338 { 339 return c.getSignatureAlgorithm().getObjectId().getId(); 340 } 341 342 public byte[] getSigAlgParams() 343 { 344 if (sigAlgParams != null) 345 { 346 byte[] tmp = new byte[sigAlgParams.length]; 347 348 System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length); 349 350 return tmp; 351 } 352 353 return null; 354 } 355 356 /** 357 * Returns a string representation of this CRL. 358 * 359 * @return a string representation of this CRL. 360 */ 361 public String toString() 362 { 363 return "X.509 CRL"; 364 } 365 366 /** 367 * Checks whether the given certificate is on this CRL. 368 * 369 * @param cert the certificate to check for. 370 * @return true if the given certificate is on this CRL, 371 * false otherwise. 372 */ 373 public boolean isRevoked(Certificate cert) 374 { 375 if (!cert.getType().equals("X.509")) 376 { 377 throw new RuntimeException("X.509 CRL used with non X.509 Cert"); 378 } 379 380 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); 381 382 if (certs != null) 383 { 384 BigInteger serial = ((X509Certificate)cert).getSerialNumber(); 385 386 for (int i = 0; i < certs.length; i++) 387 { 388 if (certs[i].getUserCertificate().getValue().equals(serial)) 389 { 390 return true; 391 } 392 } 393 } 394 395 return false; 396 } 397 } 398 399