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