004-11-15 Andreas Tobler <a.tobler@schweiz.ch>
[official-gcc.git] / libjava / gnu / java / security / x509 / X509CertPath.java
blob0990abda0593d7395c9b3afb09db09f178f6b7d8
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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 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;
66 /**
67 * A certificate path (or certificate chain) of X509Certificates.
69 * @author Casey Marshall (rsdio@metastatic.org)
71 public class X509CertPath extends CertPath
74 // Fields.
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. */
84 private List path;
86 /** The cached PKCS #7 encoded bytes. */
87 private byte[] pkcs_encoded;
89 /** The cached PkiPath encoded bytes. */
90 private byte[] pki_encoded;
92 // Constructor.
93 // -------------------------------------------------------------------------
95 public X509CertPath(List path)
97 super("X.509");
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
109 super("X.509");
112 parse(in, encoding);
114 catch (IOException ioe)
116 throw new CertificateEncodingException();
120 // Instance methods.
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();
165 else
166 throw new CertificateEncodingException("unknown encoding: " + encoding);
169 public Iterator getEncodings()
171 return ENCODINGS.iterator(); // already unmodifiable
174 // Own methods.
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.
185 path = der.read();
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 {
201 // version Version,
202 // digestAlgorithms DigestAlgorithmIdentifiers,
203 // contentInfo ContentInfo,
204 // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates
205 // OPTIONAL,
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");
214 value = der.read();
215 if (!(value.getValue() instanceof OID) ||
216 ((OID) value.getValue()).equals(PKCS7_SIGNED_DATA))
217 throw new DEREncodingException("not a SignedData");
218 value = der.read();
219 if (!value.isConstructed() || value.getTag() != 0)
220 throw new DEREncodingException("malformed content");
221 value = der.read();
222 if (value.getTag() != DER.INTEGER)
223 throw new DEREncodingException("malformed Version");
224 value = der.read();
225 if (!value.isConstructed() || value.getTag() != DER.SET)
226 throw new DEREncodingException("malformed DigestAlgorithmIdentifiers");
227 der.skip(value.getLength());
228 value = der.read();
229 if (!value.isConstructed())
230 throw new DEREncodingException("malformed ContentInfo");
231 der.skip(value.getLength());
232 path = der.read();
233 if (!path.isConstructed() || path.getTag() != 0)
234 throw new DEREncodingException("no certificates");
236 else
237 throw new CertificateEncodingException("unknown encoding: " + encoding);
239 LinkedList certs = new LinkedList();
240 int len = 0;
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
262 synchronized (path)
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,
271 b.length, b, null);
272 return val.getEncoded();
276 private byte[] encodePKCS()
277 throws CertificateEncodingException, IOException
279 synchronized (path)
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,
295 b.length, b, null));
296 DERValue sdValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
297 signedData);
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();