1 /* X509CertPath.java -- an X.509 certificate path.
2 Copyright (C) 2004 Free Software Fonudation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.java
.security
.x509
;
41 import java
.io
.ByteArrayInputStream
;
42 import java
.io
.ByteArrayOutputStream
;
43 import java
.io
.InputStream
;
44 import java
.io
.IOException
;
46 import java
.math
.BigInteger
;
48 import java
.security
.cert
.Certificate
;
49 import java
.security
.cert
.CertificateEncodingException
;
50 import java
.security
.cert
.CertificateException
;
51 import java
.security
.cert
.CertPath
;
53 import java
.util
.ArrayList
;
54 import java
.util
.Arrays
;
55 import java
.util
.Collections
;
56 import java
.util
.Iterator
;
57 import java
.util
.LinkedList
;
58 import java
.util
.List
;
60 import gnu
.java
.security
.OID
;
61 import gnu
.java
.security
.der
.DER
;
62 import gnu
.java
.security
.der
.DEREncodingException
;
63 import gnu
.java
.security
.der
.DERReader
;
64 import gnu
.java
.security
.der
.DERValue
;
67 * A certificate path (or certificate chain) of X509Certificates.
69 * @author Casey Marshall (rsdio@metastatic.org)
71 public class X509CertPath
extends CertPath
75 // -------------------------------------------------------------------------
77 public static final List ENCODINGS
= Collections
.unmodifiableList(
78 Arrays
.asList(new String
[] { "PkiPath", "PKCS7" }));
80 private static final OID PKCS7_SIGNED_DATA
= new OID("1.2.840.113549.1.7.2");
81 private static final OID PKCS7_DATA
= new OID("1.2.840.113549.1.7.1");
83 /** The certificate path. */
86 /** The cached PKCS #7 encoded bytes. */
87 private byte[] pkcs_encoded
;
89 /** The cached PkiPath encoded bytes. */
90 private byte[] pki_encoded
;
93 // -------------------------------------------------------------------------
95 public X509CertPath(List path
)
98 this.path
= Collections
.unmodifiableList(path
);
101 public X509CertPath(InputStream in
) throws CertificateEncodingException
103 this(in
, (String
) ENCODINGS
.get(0));
106 public X509CertPath(InputStream in
, String encoding
)
107 throws CertificateEncodingException
114 catch (IOException ioe
)
116 throw new CertificateEncodingException();
121 // -------------------------------------------------------------------------
123 public List
getCertificates()
125 return path
; // already unmodifiable
128 public byte[] getEncoded() throws CertificateEncodingException
130 return getEncoded((String
) ENCODINGS
.get(0));
133 public byte[] getEncoded(String encoding
) throws CertificateEncodingException
135 if (encoding
.equalsIgnoreCase("PkiPath"))
137 if (pki_encoded
== null)
141 pki_encoded
= encodePki();
143 catch (IOException ioe
)
145 throw new CertificateEncodingException();
148 return (byte[]) pki_encoded
.clone();
150 else if (encoding
.equalsIgnoreCase("PKCS7"))
152 if (pkcs_encoded
== null)
156 pkcs_encoded
= encodePKCS();
158 catch (IOException ioe
)
160 throw new CertificateEncodingException();
163 return (byte[]) pkcs_encoded
.clone();
166 throw new CertificateEncodingException("unknown encoding: " + encoding
);
169 public Iterator
getEncodings()
171 return ENCODINGS
.iterator(); // already unmodifiable
175 // -------------------------------------------------------------------------
177 private void parse(InputStream in
, String encoding
)
178 throws CertificateEncodingException
, IOException
180 DERReader der
= new DERReader(in
);
181 DERValue path
= null;
182 if (encoding
.equalsIgnoreCase("PkiPath"))
184 // PKI encoding is just a SEQUENCE of X.509 certificates.
186 if (!path
.isConstructed())
187 throw new DEREncodingException("malformed PkiPath");
189 else if (encoding
.equalsIgnoreCase("PKCS7"))
191 // PKCS #7 encoding means that the certificates are contained in a
192 // SignedData PKCS #7 type.
194 // ContentInfo ::= SEQUENCE {
195 // contentType ::= ContentType,
196 // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
198 // ContentType ::= OBJECT IDENTIFIER
200 // SignedData ::= SEQUENCE {
202 // digestAlgorithms DigestAlgorithmIdentifiers,
203 // contentInfo ContentInfo,
204 // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates
206 // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
207 // signerInfos SignerInfos }
209 // Version ::= INTEGER
211 DERValue value
= der
.read();
212 if (!value
.isConstructed())
213 throw new DEREncodingException("malformed ContentInfo");
215 if (!(value
.getValue() instanceof OID
) ||
216 ((OID
) value
.getValue()).equals(PKCS7_SIGNED_DATA
))
217 throw new DEREncodingException("not a SignedData");
219 if (!value
.isConstructed() || value
.getTag() != 0)
220 throw new DEREncodingException("malformed content");
222 if (value
.getTag() != DER
.INTEGER
)
223 throw new DEREncodingException("malformed Version");
225 if (!value
.isConstructed() || value
.getTag() != DER
.SET
)
226 throw new DEREncodingException("malformed DigestAlgorithmIdentifiers");
227 der
.skip(value
.getLength());
229 if (!value
.isConstructed())
230 throw new DEREncodingException("malformed ContentInfo");
231 der
.skip(value
.getLength());
233 if (!path
.isConstructed() || path
.getTag() != 0)
234 throw new DEREncodingException("no certificates");
237 throw new CertificateEncodingException("unknown encoding: " + encoding
);
239 LinkedList certs
= new LinkedList();
241 while (len
< path
.getLength())
243 DERValue cert
= der
.read();
246 certs
.add(new X509Certificate(new ByteArrayInputStream(cert
.getEncoded())));
248 catch (CertificateException ce
)
250 throw new CertificateEncodingException(ce
.getMessage());
252 len
+= cert
.getEncodedLength();
253 der
.skip(cert
.getLength());
256 this.path
= Collections
.unmodifiableList(certs
);
259 private byte[] encodePki()
260 throws CertificateEncodingException
, IOException
264 ByteArrayOutputStream out
= new ByteArrayOutputStream();
265 for (Iterator i
= path
.iterator(); i
.hasNext(); )
267 out
.write(((Certificate
) i
.next()).getEncoded());
269 byte[] b
= out
.toByteArray();
270 DERValue val
= new DERValue(DER
.CONSTRUCTED
| DER
.SEQUENCE
,
272 return val
.getEncoded();
276 private byte[] encodePKCS()
277 throws CertificateEncodingException
, IOException
281 ArrayList signedData
= new ArrayList(5);
282 signedData
.add(new DERValue(DER
.INTEGER
, BigInteger
.ONE
));
283 signedData
.add(new DERValue(DER
.CONSTRUCTED
| DER
.SET
,
284 Collections
.EMPTY_SET
));
285 signedData
.add(new DERValue(DER
.CONSTRUCTED
| DER
.SEQUENCE
,
286 Collections
.singletonList(
287 new DERValue(DER
.OBJECT_IDENTIFIER
, PKCS7_DATA
))));
288 ByteArrayOutputStream out
= new ByteArrayOutputStream();
289 for (Iterator i
= path
.iterator(); i
.hasNext(); )
291 out
.write(((Certificate
) i
.next()).getEncoded());
293 byte[] b
= out
.toByteArray();
294 signedData
.add(new DERValue(DER
.CONSTRUCTED
| DER
.CONTEXT
,
296 DERValue sdValue
= new DERValue(DER
.CONSTRUCTED
| DER
.SEQUENCE
,
299 ArrayList contentInfo
= new ArrayList(2);
300 contentInfo
.add(new DERValue(DER
.OBJECT_IDENTIFIER
, PKCS7_SIGNED_DATA
));
301 contentInfo
.add(new DERValue(DER
.CONSTRUCTED
| DER
.CONTEXT
, sdValue
));
302 return new DERValue(DER
.CONSTRUCTED
| DER
.SEQUENCE
,
303 contentInfo
).getEncoded();