1 package org.bouncycastle.cert; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.OutputStream; 7 import java.math.BigInteger; 8 import java.util.ArrayList; 9 import java.util.Collection; 10 import java.util.Enumeration; 11 import java.util.List; 12 import java.util.Set; 13 14 import org.bouncycastle.asn1.ASN1InputStream; 15 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 16 import org.bouncycastle.asn1.ASN1Primitive; 17 import org.bouncycastle.asn1.DEROutputStream; 18 import org.bouncycastle.asn1.x500.X500Name; 19 import org.bouncycastle.asn1.x509.CertificateList; 20 import org.bouncycastle.asn1.x509.Extension; 21 import org.bouncycastle.asn1.x509.Extensions; 22 import org.bouncycastle.asn1.x509.GeneralName; 23 import org.bouncycastle.asn1.x509.GeneralNames; 24 import org.bouncycastle.asn1.x509.IssuingDistributionPoint; 25 import org.bouncycastle.asn1.x509.TBSCertList; 26 import org.bouncycastle.operator.ContentVerifier; 27 import org.bouncycastle.operator.ContentVerifierProvider; 28 import org.bouncycastle.util.Encodable; 29 30 /** 31 * Holding class for an X.509 CRL structure. 32 */ 33 public class X509CRLHolder 34 implements Encodable 35 { 36 private CertificateList x509CRL; 37 private boolean isIndirect; 38 private Extensions extensions; 39 private GeneralNames issuerName; 40 parseStream(InputStream stream)41 private static CertificateList parseStream(InputStream stream) 42 throws IOException 43 { 44 try 45 { 46 ASN1Primitive obj = new ASN1InputStream(stream, true).readObject(); 47 if (obj == null) 48 { 49 throw new IOException("no content found"); 50 } 51 return CertificateList.getInstance(obj); 52 } 53 catch (ClassCastException e) 54 { 55 throw new CertIOException("malformed data: " + e.getMessage(), e); 56 } 57 catch (IllegalArgumentException e) 58 { 59 throw new CertIOException("malformed data: " + e.getMessage(), e); 60 } 61 } 62 isIndirectCRL(Extensions extensions)63 private static boolean isIndirectCRL(Extensions extensions) 64 { 65 if (extensions == null) 66 { 67 return false; 68 } 69 70 Extension ext = extensions.getExtension(Extension.issuingDistributionPoint); 71 72 return ext != null && IssuingDistributionPoint.getInstance(ext.getParsedValue()).isIndirectCRL(); 73 } 74 75 /** 76 * Create a X509CRLHolder from the passed in bytes. 77 * 78 * @param crlEncoding BER/DER encoding of the CRL 79 * @throws IOException in the event of corrupted data, or an incorrect structure. 80 */ X509CRLHolder(byte[] crlEncoding)81 public X509CRLHolder(byte[] crlEncoding) 82 throws IOException 83 { 84 this(parseStream(new ByteArrayInputStream(crlEncoding))); 85 } 86 87 /** 88 * Create a X509CRLHolder from the passed in InputStream. 89 * 90 * @param crlStream BER/DER encoded InputStream of the CRL 91 * @throws IOException in the event of corrupted data, or an incorrect structure. 92 */ X509CRLHolder(InputStream crlStream)93 public X509CRLHolder(InputStream crlStream) 94 throws IOException 95 { 96 this(parseStream(crlStream)); 97 } 98 99 /** 100 * Create a X509CRLHolder from the passed in ASN.1 structure. 101 * 102 * @param x509CRL an ASN.1 CertificateList structure. 103 */ X509CRLHolder(CertificateList x509CRL)104 public X509CRLHolder(CertificateList x509CRL) 105 { 106 this.x509CRL = x509CRL; 107 this.extensions = x509CRL.getTBSCertList().getExtensions(); 108 this.isIndirect = isIndirectCRL(extensions); 109 this.issuerName = new GeneralNames(new GeneralName(x509CRL.getIssuer())); 110 } 111 112 /** 113 * Return the ASN.1 encoding of this holder's CRL. 114 * 115 * @return a DER encoded byte array. 116 * @throws IOException if an encoding cannot be generated. 117 */ getEncoded()118 public byte[] getEncoded() 119 throws IOException 120 { 121 return x509CRL.getEncoded(); 122 } 123 124 /** 125 * Return the issuer of this holder's CRL. 126 * 127 * @return the CRL issuer. 128 */ getIssuer()129 public X500Name getIssuer() 130 { 131 return X500Name.getInstance(x509CRL.getIssuer()); 132 } 133 getRevokedCertificate(BigInteger serialNumber)134 public X509CRLEntryHolder getRevokedCertificate(BigInteger serialNumber) 135 { 136 GeneralNames currentCA = issuerName; 137 for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();) 138 { 139 TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement(); 140 141 if (entry.getUserCertificate().getValue().equals(serialNumber)) 142 { 143 return new X509CRLEntryHolder(entry, isIndirect, currentCA); 144 } 145 146 if (isIndirect && entry.hasExtensions()) 147 { 148 Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); 149 150 if (currentCaName != null) 151 { 152 currentCA = GeneralNames.getInstance(currentCaName.getParsedValue()); 153 } 154 } 155 } 156 157 return null; 158 } 159 160 /** 161 * Return a collection of X509CRLEntryHolder objects, giving the details of the 162 * revoked certificates that appear on this CRL. 163 * 164 * @return the revoked certificates as a collection of X509CRLEntryHolder objects. 165 */ getRevokedCertificates()166 public Collection getRevokedCertificates() 167 { 168 TBSCertList.CRLEntry[] entries = x509CRL.getRevokedCertificates(); 169 List l = new ArrayList(entries.length); 170 GeneralNames currentCA = issuerName; 171 172 for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();) 173 { 174 TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement(); 175 X509CRLEntryHolder crlEntry = new X509CRLEntryHolder(entry, isIndirect, currentCA); 176 177 l.add(crlEntry); 178 179 currentCA = crlEntry.getCertificateIssuer(); 180 } 181 182 return l; 183 } 184 185 /** 186 * Return whether or not the holder's CRL contains extensions. 187 * 188 * @return true if extension are present, false otherwise. 189 */ hasExtensions()190 public boolean hasExtensions() 191 { 192 return extensions != null; 193 } 194 195 /** 196 * Look up the extension associated with the passed in OID. 197 * 198 * @param oid the OID of the extension of interest. 199 * 200 * @return the extension if present, null otherwise. 201 */ getExtension(ASN1ObjectIdentifier oid)202 public Extension getExtension(ASN1ObjectIdentifier oid) 203 { 204 if (extensions != null) 205 { 206 return extensions.getExtension(oid); 207 } 208 209 return null; 210 } 211 212 /** 213 * Return the extensions block associated with this CRL if there is one. 214 * 215 * @return the extensions block, null otherwise. 216 */ getExtensions()217 public Extensions getExtensions() 218 { 219 return extensions; 220 } 221 222 /** 223 * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the 224 * extensions contained in this holder's CRL. 225 * 226 * @return a list of extension OIDs. 227 */ getExtensionOIDs()228 public List getExtensionOIDs() 229 { 230 return CertUtils.getExtensionOIDs(extensions); 231 } 232 233 /** 234 * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the 235 * critical extensions contained in this holder's CRL. 236 * 237 * @return a set of critical extension OIDs. 238 */ getCriticalExtensionOIDs()239 public Set getCriticalExtensionOIDs() 240 { 241 return CertUtils.getCriticalExtensionOIDs(extensions); 242 } 243 244 /** 245 * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the 246 * non-critical extensions contained in this holder's CRL. 247 * 248 * @return a set of non-critical extension OIDs. 249 */ getNonCriticalExtensionOIDs()250 public Set getNonCriticalExtensionOIDs() 251 { 252 return CertUtils.getNonCriticalExtensionOIDs(extensions); 253 } 254 255 /** 256 * Return the underlying ASN.1 structure for the CRL in this holder. 257 * 258 * @return a CertificateList object. 259 */ toASN1Structure()260 public CertificateList toASN1Structure() 261 { 262 return x509CRL; 263 } 264 265 /** 266 * Validate the signature on the CRL. 267 * 268 * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature. 269 * @return true if the signature is valid, false otherwise. 270 * @throws CertException if the signature cannot be processed or is inappropriate. 271 */ isSignatureValid(ContentVerifierProvider verifierProvider)272 public boolean isSignatureValid(ContentVerifierProvider verifierProvider) 273 throws CertException 274 { 275 TBSCertList tbsCRL = x509CRL.getTBSCertList(); 276 277 if (!CertUtils.isAlgIdEqual(tbsCRL.getSignature(), x509CRL.getSignatureAlgorithm())) 278 { 279 throw new CertException("signature invalid - algorithm identifier mismatch"); 280 } 281 282 ContentVerifier verifier; 283 284 try 285 { 286 verifier = verifierProvider.get((tbsCRL.getSignature())); 287 288 OutputStream sOut = verifier.getOutputStream(); 289 DEROutputStream dOut = new DEROutputStream(sOut); 290 291 dOut.writeObject(tbsCRL); 292 293 sOut.close(); 294 } 295 catch (Exception e) 296 { 297 throw new CertException("unable to process signature: " + e.getMessage(), e); 298 } 299 300 return verifier.verify(x509CRL.getSignature().getOctets()); 301 } 302 equals( Object o)303 public boolean equals( 304 Object o) 305 { 306 if (o == this) 307 { 308 return true; 309 } 310 311 if (!(o instanceof X509CRLHolder)) 312 { 313 return false; 314 } 315 316 X509CRLHolder other = (X509CRLHolder)o; 317 318 return this.x509CRL.equals(other.x509CRL); 319 } 320 hashCode()321 public int hashCode() 322 { 323 return this.x509CRL.hashCode(); 324 } 325 } 326