1 package org.bouncycastle.jcajce.provider.asymmetric.x509; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.PushbackInputStream; 6 import java.security.cert.CRL; 7 import java.security.cert.CRLException; 8 import java.security.cert.CertPath; 9 import java.security.cert.CertificateException; 10 import java.security.cert.CertificateFactorySpi; 11 import java.security.cert.CertificateParsingException; 12 import java.security.cert.X509Certificate; 13 import java.util.ArrayList; 14 import java.util.Collection; 15 import java.util.Iterator; 16 import java.util.List; 17 18 import org.bouncycastle.asn1.ASN1InputStream; 19 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 20 import org.bouncycastle.asn1.ASN1Sequence; 21 import org.bouncycastle.asn1.ASN1Set; 22 import org.bouncycastle.asn1.ASN1TaggedObject; 23 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 24 import org.bouncycastle.asn1.pkcs.SignedData; 25 import org.bouncycastle.asn1.x509.Certificate; 26 import org.bouncycastle.asn1.x509.CertificateList; 27 28 /** 29 * class for dealing with X509 certificates. 30 * <p> 31 * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----" 32 * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7 33 * objects. 34 */ 35 public class CertificateFactory 36 extends CertificateFactorySpi 37 { 38 private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE"); 39 private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL"); 40 41 private ASN1Set sData = null; 42 private int sDataObjectCount = 0; 43 private InputStream currentStream = null; 44 45 private ASN1Set sCrlData = null; 46 private int sCrlDataObjectCount = 0; 47 private InputStream currentCrlStream = null; 48 49 private java.security.cert.Certificate readDERCertificate( 50 ASN1InputStream dIn) 51 throws IOException, CertificateParsingException 52 { 53 ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); 54 55 if (seq.size() > 1 56 && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier) 57 { 58 if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData)) 59 { 60 sData = SignedData.getInstance(ASN1Sequence.getInstance( 61 (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates(); 62 63 return getCertificate(); 64 } 65 } 66 67 return new X509CertificateObject( 68 Certificate.getInstance(seq)); 69 } 70 71 private java.security.cert.Certificate getCertificate() 72 throws CertificateParsingException 73 { 74 if (sData != null) 75 { 76 while (sDataObjectCount < sData.size()) 77 { 78 Object obj = sData.getObjectAt(sDataObjectCount++); 79 80 if (obj instanceof ASN1Sequence) 81 { 82 return new X509CertificateObject( 83 Certificate.getInstance(obj)); 84 } 85 } 86 } 87 88 return null; 89 } 90 91 private java.security.cert.Certificate readPEMCertificate( 92 InputStream in) 93 throws IOException, CertificateParsingException 94 { 95 ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in); 96 97 if (seq != null) 98 { 99 return new X509CertificateObject( 100 Certificate.getInstance(seq)); 101 } 102 103 return null; 104 } 105 106 protected CRL createCRL(CertificateList c) 107 throws CRLException 108 { 109 return new X509CRLObject(c); 110 } 111 112 private CRL readPEMCRL( 113 InputStream in) 114 throws IOException, CRLException 115 { 116 ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in); 117 118 if (seq != null) 119 { 120 return createCRL( 121 CertificateList.getInstance(seq)); 122 } 123 124 return null; 125 } 126 127 private CRL readDERCRL( 128 ASN1InputStream aIn) 129 throws IOException, CRLException 130 { 131 ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); 132 133 if (seq.size() > 1 134 && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier) 135 { 136 if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData)) 137 { 138 sCrlData = SignedData.getInstance(ASN1Sequence.getInstance( 139 (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs(); 140 141 return getCRL(); 142 } 143 } 144 145 return createCRL( 146 CertificateList.getInstance(seq)); 147 } 148 149 private CRL getCRL() 150 throws CRLException 151 { 152 if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size()) 153 { 154 return null; 155 } 156 157 return createCRL( 158 CertificateList.getInstance( 159 sCrlData.getObjectAt(sCrlDataObjectCount++))); 160 } 161 162 /** 163 * Generates a certificate object and initializes it with the data 164 * read from the input stream inStream. 165 */ 166 public java.security.cert.Certificate engineGenerateCertificate( 167 InputStream in) 168 throws CertificateException 169 { 170 if (currentStream == null) 171 { 172 currentStream = in; 173 sData = null; 174 sDataObjectCount = 0; 175 } 176 else if (currentStream != in) // reset if input stream has changed 177 { 178 currentStream = in; 179 sData = null; 180 sDataObjectCount = 0; 181 } 182 183 try 184 { 185 if (sData != null) 186 { 187 if (sDataObjectCount != sData.size()) 188 { 189 return getCertificate(); 190 } 191 else 192 { 193 sData = null; 194 sDataObjectCount = 0; 195 return null; 196 } 197 } 198 199 PushbackInputStream pis = new PushbackInputStream(in); 200 int tag = pis.read(); 201 202 if (tag == -1) 203 { 204 return null; 205 } 206 207 pis.unread(tag); 208 209 if (tag != 0x30) // assume ascii PEM encoded. 210 { 211 return readPEMCertificate(pis); 212 } 213 else 214 { 215 return readDERCertificate(new ASN1InputStream(pis)); 216 } 217 } 218 catch (Exception e) 219 { 220 throw new ExCertificateException(e); 221 } 222 } 223 224 /** 225 * Returns a (possibly empty) collection view of the certificates 226 * read from the given input stream inStream. 227 */ 228 public Collection engineGenerateCertificates( 229 InputStream inStream) 230 throws CertificateException 231 { 232 java.security.cert.Certificate cert; 233 List certs = new ArrayList(); 234 235 while ((cert = engineGenerateCertificate(inStream)) != null) 236 { 237 certs.add(cert); 238 } 239 240 return certs; 241 } 242 243 /** 244 * Generates a certificate revocation list (CRL) object and initializes 245 * it with the data read from the input stream inStream. 246 */ 247 public CRL engineGenerateCRL( 248 InputStream inStream) 249 throws CRLException 250 { 251 if (currentCrlStream == null) 252 { 253 currentCrlStream = inStream; 254 sCrlData = null; 255 sCrlDataObjectCount = 0; 256 } 257 else if (currentCrlStream != inStream) // reset if input stream has changed 258 { 259 currentCrlStream = inStream; 260 sCrlData = null; 261 sCrlDataObjectCount = 0; 262 } 263 264 try 265 { 266 if (sCrlData != null) 267 { 268 if (sCrlDataObjectCount != sCrlData.size()) 269 { 270 return getCRL(); 271 } 272 else 273 { 274 sCrlData = null; 275 sCrlDataObjectCount = 0; 276 return null; 277 } 278 } 279 280 PushbackInputStream pis = new PushbackInputStream(inStream); 281 int tag = pis.read(); 282 283 if (tag == -1) 284 { 285 return null; 286 } 287 288 pis.unread(tag); 289 290 if (tag != 0x30) // assume ascii PEM encoded. 291 { 292 return readPEMCRL(pis); 293 } 294 else 295 { // lazy evaluate to help processing of large CRLs 296 return readDERCRL(new ASN1InputStream(pis, true)); 297 } 298 } 299 catch (CRLException e) 300 { 301 throw e; 302 } 303 catch (Exception e) 304 { 305 throw new CRLException(e.toString()); 306 } 307 } 308 309 /** 310 * Returns a (possibly empty) collection view of the CRLs read from 311 * the given input stream inStream. 312 * 313 * The inStream may contain a sequence of DER-encoded CRLs, or 314 * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the 315 * only signficant field being crls. In particular the signature 316 * and the contents are ignored. 317 */ 318 public Collection engineGenerateCRLs( 319 InputStream inStream) 320 throws CRLException 321 { 322 CRL crl; 323 List crls = new ArrayList(); 324 325 while ((crl = engineGenerateCRL(inStream)) != null) 326 { 327 crls.add(crl); 328 } 329 330 return crls; 331 } 332 333 public Iterator engineGetCertPathEncodings() 334 { 335 return PKIXCertPath.certPathEncodings.iterator(); 336 } 337 338 public CertPath engineGenerateCertPath( 339 InputStream inStream) 340 throws CertificateException 341 { 342 return engineGenerateCertPath(inStream, "PkiPath"); 343 } 344 345 public CertPath engineGenerateCertPath( 346 InputStream inStream, 347 String encoding) 348 throws CertificateException 349 { 350 return new PKIXCertPath(inStream, encoding); 351 } 352 353 public CertPath engineGenerateCertPath( 354 List certificates) 355 throws CertificateException 356 { 357 Iterator iter = certificates.iterator(); 358 Object obj; 359 while (iter.hasNext()) 360 { 361 obj = iter.next(); 362 if (obj != null) 363 { 364 if (!(obj instanceof X509Certificate)) 365 { 366 throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString()); 367 } 368 } 369 } 370 return new PKIXCertPath(certificates); 371 } 372 373 private class ExCertificateException 374 extends CertificateException 375 { 376 private Throwable cause; 377 378 public ExCertificateException(Throwable cause) 379 { 380 this.cause = cause; 381 } 382 383 public ExCertificateException(String msg, Throwable cause) 384 { 385 super(msg); 386 387 this.cause = cause; 388 } 389 390 public Throwable getCause() 391 { 392 return cause; 393 } 394 } 395 } 396