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