Imported GNU Classpath 0.19 + gcj-import-20051115.
[official-gcc.git] / libjava / classpath / gnu / java / security / x509 / X509CertPath.java
blobe8ed6bf35d1a60785dab0a9455e76dd5c3901a6f
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)
9 any later version.
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
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
24 combination.
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 gnu.java.security.OID;
42 import gnu.java.security.der.DER;
43 import gnu.java.security.der.DEREncodingException;
44 import gnu.java.security.der.DERReader;
45 import gnu.java.security.der.DERValue;
47 import java.io.ByteArrayInputStream;
48 import java.io.ByteArrayOutputStream;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.math.BigInteger;
52 import java.security.cert.CertPath;
53 import java.security.cert.Certificate;
54 import java.security.cert.CertificateEncodingException;
55 import java.security.cert.CertificateException;
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.Collections;
59 import java.util.Iterator;
60 import java.util.LinkedList;
61 import java.util.List;
63 /**
64 * A certificate path (or certificate chain) of X509Certificates.
66 * @author Casey Marshall (rsdio@metastatic.org)
68 public class X509CertPath extends CertPath
71 // Fields.
72 // -------------------------------------------------------------------------
74 public static final List ENCODINGS = Collections.unmodifiableList(
75 Arrays.asList(new String[] { "PkiPath", "PKCS7" }));
77 private static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2");
78 private static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1");
80 /** The certificate path. */
81 private List path;
83 /** The cached PKCS #7 encoded bytes. */
84 private byte[] pkcs_encoded;
86 /** The cached PkiPath encoded bytes. */
87 private byte[] pki_encoded;
89 // Constructor.
90 // -------------------------------------------------------------------------
92 public X509CertPath(List path)
94 super("X.509");
95 this.path = Collections.unmodifiableList(path);
98 public X509CertPath(InputStream in) throws CertificateEncodingException
100 this(in, (String) ENCODINGS.get(0));
103 public X509CertPath(InputStream in, String encoding)
104 throws CertificateEncodingException
106 super("X.509");
109 parse(in, encoding);
111 catch (IOException ioe)
113 throw new CertificateEncodingException();
117 // Instance methods.
118 // -------------------------------------------------------------------------
120 public List getCertificates()
122 return path; // already unmodifiable
125 public byte[] getEncoded() throws CertificateEncodingException
127 return getEncoded((String) ENCODINGS.get(0));
130 public byte[] getEncoded(String encoding) throws CertificateEncodingException
132 if (encoding.equalsIgnoreCase("PkiPath"))
134 if (pki_encoded == null)
138 pki_encoded = encodePki();
140 catch (IOException ioe)
142 throw new CertificateEncodingException();
145 return (byte[]) pki_encoded.clone();
147 else if (encoding.equalsIgnoreCase("PKCS7"))
149 if (pkcs_encoded == null)
153 pkcs_encoded = encodePKCS();
155 catch (IOException ioe)
157 throw new CertificateEncodingException();
160 return (byte[]) pkcs_encoded.clone();
162 else
163 throw new CertificateEncodingException("unknown encoding: " + encoding);
166 public Iterator getEncodings()
168 return ENCODINGS.iterator(); // already unmodifiable
171 // Own methods.
172 // -------------------------------------------------------------------------
174 private void parse(InputStream in, String encoding)
175 throws CertificateEncodingException, IOException
177 DERReader der = new DERReader(in);
178 DERValue path = null;
179 if (encoding.equalsIgnoreCase("PkiPath"))
181 // PKI encoding is just a SEQUENCE of X.509 certificates.
182 path = der.read();
183 if (!path.isConstructed())
184 throw new DEREncodingException("malformed PkiPath");
186 else if (encoding.equalsIgnoreCase("PKCS7"))
188 // PKCS #7 encoding means that the certificates are contained in a
189 // SignedData PKCS #7 type.
191 // ContentInfo ::= SEQUENCE {
192 // contentType ::= ContentType,
193 // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
195 // ContentType ::= OBJECT IDENTIFIER
197 // SignedData ::= SEQUENCE {
198 // version Version,
199 // digestAlgorithms DigestAlgorithmIdentifiers,
200 // contentInfo ContentInfo,
201 // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates
202 // OPTIONAL,
203 // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
204 // signerInfos SignerInfos }
206 // Version ::= INTEGER
208 DERValue value = der.read();
209 if (!value.isConstructed())
210 throw new DEREncodingException("malformed ContentInfo");
211 value = der.read();
212 if (!(value.getValue() instanceof OID) ||
213 ((OID) value.getValue()).equals(PKCS7_SIGNED_DATA))
214 throw new DEREncodingException("not a SignedData");
215 value = der.read();
216 if (!value.isConstructed() || value.getTag() != 0)
217 throw new DEREncodingException("malformed content");
218 value = der.read();
219 if (value.getTag() != DER.INTEGER)
220 throw new DEREncodingException("malformed Version");
221 value = der.read();
222 if (!value.isConstructed() || value.getTag() != DER.SET)
223 throw new DEREncodingException("malformed DigestAlgorithmIdentifiers");
224 der.skip(value.getLength());
225 value = der.read();
226 if (!value.isConstructed())
227 throw new DEREncodingException("malformed ContentInfo");
228 der.skip(value.getLength());
229 path = der.read();
230 if (!path.isConstructed() || path.getTag() != 0)
231 throw new DEREncodingException("no certificates");
233 else
234 throw new CertificateEncodingException("unknown encoding: " + encoding);
236 LinkedList certs = new LinkedList();
237 int len = 0;
238 while (len < path.getLength())
240 DERValue cert = der.read();
243 certs.add(new X509Certificate(new ByteArrayInputStream(cert.getEncoded())));
245 catch (CertificateException ce)
247 throw new CertificateEncodingException(ce.getMessage());
249 len += cert.getEncodedLength();
250 der.skip(cert.getLength());
253 this.path = Collections.unmodifiableList(certs);
256 private byte[] encodePki()
257 throws CertificateEncodingException, IOException
259 synchronized (path)
261 ByteArrayOutputStream out = new ByteArrayOutputStream();
262 for (Iterator i = path.iterator(); i.hasNext(); )
264 out.write(((Certificate) i.next()).getEncoded());
266 byte[] b = out.toByteArray();
267 DERValue val = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
268 b.length, b, null);
269 return val.getEncoded();
273 private byte[] encodePKCS()
274 throws CertificateEncodingException, IOException
276 synchronized (path)
278 ArrayList signedData = new ArrayList(5);
279 signedData.add(new DERValue(DER.INTEGER, BigInteger.ONE));
280 signedData.add(new DERValue(DER.CONSTRUCTED | DER.SET,
281 Collections.EMPTY_SET));
282 signedData.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
283 Collections.singletonList(
284 new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_DATA))));
285 ByteArrayOutputStream out = new ByteArrayOutputStream();
286 for (Iterator i = path.iterator(); i.hasNext(); )
288 out.write(((Certificate) i.next()).getEncoded());
290 byte[] b = out.toByteArray();
291 signedData.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT,
292 b.length, b, null));
293 DERValue sdValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
294 signedData);
296 ArrayList contentInfo = new ArrayList(2);
297 contentInfo.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA));
298 contentInfo.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, sdValue));
299 return new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
300 contentInfo).getEncoded();