001: package org.bouncycastle.jce.provider;
002:
003: import org.bouncycastle.asn1.ASN1InputStream;
004: import org.bouncycastle.asn1.ASN1Sequence;
005: import org.bouncycastle.asn1.ASN1Set;
006: import org.bouncycastle.asn1.ASN1TaggedObject;
007: import org.bouncycastle.asn1.DERObjectIdentifier;
008: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
009: import org.bouncycastle.asn1.pkcs.SignedData;
010: import org.bouncycastle.asn1.x509.CertificateList;
011: import org.bouncycastle.asn1.x509.X509CertificateStructure;
012:
013: import java.io.BufferedInputStream;
014: import java.io.IOException;
015: import java.io.InputStream;
016: import java.security.cert.CRL;
017: import java.security.cert.CRLException;
018: import java.security.cert.CertPath;
019: import java.security.cert.Certificate;
020: import java.security.cert.CertificateException;
021: import java.security.cert.CertificateFactorySpi;
022: import java.security.cert.CertificateParsingException;
023: import java.security.cert.X509Certificate;
024: import java.util.ArrayList;
025: import java.util.Collection;
026: import java.util.Iterator;
027: import java.util.List;
028:
029: /**
030: * class for dealing with X509 certificates.
031: * <p>
032: * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
033: * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
034: * objects.
035: */
036: public class JDKX509CertificateFactory extends CertificateFactorySpi {
037: private static final PEMUtil PEM_CERT_PARSER = new PEMUtil(
038: "CERTIFICATE");
039: private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
040:
041: private ASN1Set sData = null;
042: private int sDataObjectCount = 0;
043: private InputStream currentStream = null;
044:
045: private ASN1Set sCrlData = null;
046: private int sCrlDataObjectCount = 0;
047: private InputStream currentCrlStream = null;
048:
049: private Certificate readDERCertificate(ASN1InputStream dIn)
050: throws IOException, CertificateParsingException {
051: ASN1Sequence seq = (ASN1Sequence) dIn.readObject();
052:
053: if (seq.size() > 1
054: && seq.getObjectAt(0) instanceof DERObjectIdentifier) {
055: if (seq.getObjectAt(0).equals(
056: PKCSObjectIdentifiers.signedData)) {
057: sData = new SignedData(ASN1Sequence.getInstance(
058: (ASN1TaggedObject) seq.getObjectAt(1), true))
059: .getCertificates();
060:
061: return getCertificate();
062: }
063: }
064:
065: return new X509CertificateObject(X509CertificateStructure
066: .getInstance(seq));
067: }
068:
069: private Certificate getCertificate()
070: throws CertificateParsingException {
071: if (sData != null) {
072: while (sDataObjectCount < sData.size()) {
073: Object obj = sData.getObjectAt(sDataObjectCount++);
074:
075: if (obj instanceof ASN1Sequence) {
076: return new X509CertificateObject(
077: X509CertificateStructure.getInstance(obj));
078: }
079: }
080: }
081:
082: return null;
083: }
084:
085: private Certificate readPEMCertificate(InputStream in)
086: throws IOException, CertificateParsingException {
087: ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
088:
089: if (seq != null) {
090: return new X509CertificateObject(X509CertificateStructure
091: .getInstance(seq));
092: }
093:
094: return null;
095: }
096:
097: private CRL readPEMCRL(InputStream in) throws IOException,
098: CRLException {
099: ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
100:
101: if (seq != null) {
102: return new X509CRLObject(CertificateList.getInstance(seq));
103: }
104:
105: return null;
106: }
107:
108: private CRL readDERCRL(ASN1InputStream aIn) throws IOException,
109: CRLException {
110: ASN1Sequence seq = (ASN1Sequence) aIn.readObject();
111:
112: if (seq.size() > 1
113: && seq.getObjectAt(0) instanceof DERObjectIdentifier) {
114: if (seq.getObjectAt(0).equals(
115: PKCSObjectIdentifiers.signedData)) {
116: sCrlData = new SignedData(ASN1Sequence.getInstance(
117: (ASN1TaggedObject) seq.getObjectAt(1), true))
118: .getCRLs();
119:
120: return getCRL();
121: }
122: }
123:
124: return new X509CRLObject(CertificateList.getInstance(seq));
125: }
126:
127: private CRL getCRL() throws CRLException {
128: if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size()) {
129: return null;
130: }
131:
132: return new X509CRLObject(CertificateList.getInstance(sCrlData
133: .getObjectAt(sCrlDataObjectCount++)));
134: }
135:
136: /**
137: * Generates a certificate object and initializes it with the data
138: * read from the input stream inStream.
139: */
140: public Certificate engineGenerateCertificate(InputStream in)
141: throws CertificateException {
142: if (currentStream == null) {
143: currentStream = in;
144: sData = null;
145: sDataObjectCount = 0;
146: } else if (currentStream != in) // reset if input stream has changed
147: {
148: currentStream = in;
149: sData = null;
150: sDataObjectCount = 0;
151: }
152:
153: try {
154: if (sData != null) {
155: if (sDataObjectCount != sData.size()) {
156: return getCertificate();
157: } else {
158: sData = null;
159: sDataObjectCount = 0;
160: return null;
161: }
162: }
163:
164: if (!in.markSupported()) {
165: in = new BufferedInputStream(in);
166: }
167:
168: in.mark(10);
169: int tag = in.read();
170:
171: if (tag == -1) {
172: return null;
173: }
174:
175: if (tag != 0x30) // assume ascii PEM encoded.
176: {
177: in.reset();
178: return readPEMCertificate(in);
179: } else {
180: in.reset();
181: return readDERCertificate(new ASN1InputStream(in,
182: ProviderUtil.getReadLimit(in)));
183: }
184: } catch (Exception e) {
185: throw new CertificateException(e.toString());
186: }
187: }
188:
189: /**
190: * Returns a (possibly empty) collection view of the certificates
191: * read from the given input stream inStream.
192: */
193: public Collection engineGenerateCertificates(InputStream inStream)
194: throws CertificateException {
195: Certificate cert;
196: List certs = new ArrayList();
197:
198: while ((cert = engineGenerateCertificate(inStream)) != null) {
199: certs.add(cert);
200: }
201:
202: return certs;
203: }
204:
205: /**
206: * Generates a certificate revocation list (CRL) object and initializes
207: * it with the data read from the input stream inStream.
208: */
209: public CRL engineGenerateCRL(InputStream inStream)
210: throws CRLException {
211: if (currentCrlStream == null) {
212: currentCrlStream = inStream;
213: sCrlData = null;
214: sCrlDataObjectCount = 0;
215: } else if (currentCrlStream != inStream) // reset if input stream has changed
216: {
217: currentCrlStream = inStream;
218: sCrlData = null;
219: sCrlDataObjectCount = 0;
220: }
221:
222: try {
223: if (sCrlData != null) {
224: if (sCrlDataObjectCount != sCrlData.size()) {
225: return getCRL();
226: } else {
227: sCrlData = null;
228: sCrlDataObjectCount = 0;
229: return null;
230: }
231: }
232:
233: if (!inStream.markSupported()) {
234: inStream = new BufferedInputStream(inStream);
235: }
236:
237: inStream.mark(10);
238: if (inStream.read() != 0x30) // assume ascii PEM encoded.
239: {
240: inStream.reset();
241: return readPEMCRL(inStream);
242: } else {
243: inStream.reset();
244: return readDERCRL(new ASN1InputStream(inStream,
245: ProviderUtil.getReadLimit(inStream)));
246: }
247: } catch (CRLException e) {
248: throw e;
249: } catch (Exception e) {
250: throw new CRLException(e.toString());
251: }
252: }
253:
254: /**
255: * Returns a (possibly empty) collection view of the CRLs read from
256: * the given input stream inStream.
257: *
258: * The inStream may contain a sequence of DER-encoded CRLs, or
259: * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
260: * only signficant field being crls. In particular the signature
261: * and the contents are ignored.
262: */
263: public Collection engineGenerateCRLs(InputStream inStream)
264: throws CRLException {
265: CRL crl;
266: List crls = new ArrayList();
267:
268: while ((crl = engineGenerateCRL(inStream)) != null) {
269: crls.add(crl);
270: }
271:
272: return crls;
273: }
274:
275: public Iterator engineGetCertPathEncodings() {
276: return PKIXCertPath.certPathEncodings.iterator();
277: }
278:
279: public CertPath engineGenerateCertPath(InputStream inStream)
280: throws CertificateException {
281: return engineGenerateCertPath(inStream, "PkiPath");
282: }
283:
284: public CertPath engineGenerateCertPath(InputStream inStream,
285: String encoding) throws CertificateException {
286: return new PKIXCertPath(inStream, encoding);
287: }
288:
289: public CertPath engineGenerateCertPath(List certificates)
290: throws CertificateException {
291: Iterator iter = certificates.iterator();
292: Object obj;
293: while (iter.hasNext()) {
294: obj = iter.next();
295: if (obj != null) {
296: if (!(obj instanceof X509Certificate)) {
297: throw new CertificateException(
298: "list contains non X509Certificate object while creating CertPath\n"
299: + obj.toString());
300: }
301: }
302: }
303: return new PKIXCertPath(certificates);
304: }
305: }
|