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