1e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root/*
2e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * Copyright (C) 2013 The Android Open Source Project
3e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root *
4e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
5e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * you may not use this file except in compliance with the License.
6e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * You may obtain a copy of the License at
7e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root *
8e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
9e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root *
10e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * Unless required by applicable law or agreed to in writing, software
11e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
12e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * See the License for the specific language governing permissions and
14e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root * limitations under the License.
15e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root */
16e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
18e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
19e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.io.IOException;
20e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.io.InputStream;
21e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.io.PushbackInputStream;
22e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.security.cert.CertPath;
23e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.security.cert.Certificate;
24e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.security.cert.CertificateEncodingException;
25e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.security.cert.CertificateException;
26e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.security.cert.X509Certificate;
27f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Rootimport java.util.ArrayList;
28e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.util.Arrays;
29e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.util.Collections;
30e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.util.Iterator;
31e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootimport java.util.List;
32860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
33e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
34e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Rootpublic class OpenSSLX509CertPath extends CertPath {
353e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root    private static final byte[] PKCS7_MARKER = new byte[] {
363e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            '-', '-', '-', '-', '-', 'B', 'E', 'G', 'I', 'N', ' ', 'P', 'K', 'C', 'S', '7'
373e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root    };
38e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
39e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    private static final int PUSHBACK_SIZE = 64;
40e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
41e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    /**
42e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root     * Supported encoding types for CerthPath. Used by the various APIs that
43e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root     * encode this into bytes such as {@link #getEncoded()}.
44e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root     */
45e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    private enum Encoding {
46f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        PKI_PATH("PkiPath"),
47e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        PKCS7("PKCS7");
48e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
49e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        private final String apiName;
50e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
51e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        Encoding(String apiName) {
52e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            this.apiName = apiName;
53e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
54e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
55e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        static Encoding findByApiName(String apiName) throws CertificateEncodingException {
56e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            for (Encoding element : values()) {
57e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                if (element.apiName.equals(apiName)) {
58e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                    return element;
59e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                }
60e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            }
61e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
62e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            return null;
63e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
64e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
65e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
66e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    /** Unmodifiable list of encodings for the API. */
67e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    private static final List<String> ALL_ENCODINGS = Collections.unmodifiableList(Arrays
68e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            .asList(new String[] {
69f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                    Encoding.PKI_PATH.apiName,
70f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                    Encoding.PKCS7.apiName,
71e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            }));
72e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
73f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root    private static final Encoding DEFAULT_ENCODING = Encoding.PKI_PATH;
74e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
75e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    private final List<? extends X509Certificate> mCertificates;
76e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
77e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    static Iterator<String> getEncodingsIterator() {
78e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        return ALL_ENCODINGS.iterator();
79e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
80e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
81e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    protected OpenSSLX509CertPath(List<? extends X509Certificate> certificates) {
82e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        super("X.509");
83e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
84e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        mCertificates = certificates;
85e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
86e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
87e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    @Override
88e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    public List<? extends Certificate> getCertificates() {
89e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        return Collections.unmodifiableList(mCertificates);
90e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
91e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
92e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    private byte[] getEncoded(Encoding encoding) throws CertificateEncodingException {
93e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        final OpenSSLX509Certificate[] certs = new OpenSSLX509Certificate[mCertificates.size()];
94e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        final long[] certRefs = new long[certs.length];
95e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
96f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        for (int i = 0, j = certs.length - 1; j >= 0; i++, j--) {
97f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            final X509Certificate cert = mCertificates.get(i);
98f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root
99f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            if (cert instanceof OpenSSLX509Certificate) {
100f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                certs[j] = (OpenSSLX509Certificate) cert;
101e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            } else {
102f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                certs[j] = OpenSSLX509Certificate.fromX509Der(cert.getEncoded());
103e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            }
104f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root
105f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            certRefs[j] = certs[j].getContext();
106e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
107e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
108f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        switch (encoding) {
109f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            case PKI_PATH:
110f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                return NativeCrypto.ASN1_seq_pack_X509(certRefs);
111f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            case PKCS7:
112f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                return NativeCrypto.i2d_PKCS7(certRefs);
113f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            default:
114f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                throw new CertificateEncodingException("Unknown encoding");
115f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        }
116e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
117e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
118e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    @Override
119e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    public byte[] getEncoded() throws CertificateEncodingException {
120e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        return getEncoded(DEFAULT_ENCODING);
121e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
122e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
123e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    @Override
124e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    public byte[] getEncoded(String encoding) throws CertificateEncodingException {
125e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        Encoding enc = Encoding.findByApiName(encoding);
126e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        if (enc == null) {
127e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            throw new CertificateEncodingException("Invalid encoding: " + encoding);
128e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
129e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
130f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        return getEncoded(enc);
131e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
132e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
133e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    @Override
134e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    public Iterator<String> getEncodings() {
135e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        return getEncodingsIterator();
136e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
137e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
138f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root    private static CertPath fromPkiPathEncoding(InputStream inStream) throws CertificateException {
139f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(inStream);
140f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root
141881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root        final boolean markable = inStream.markSupported();
142881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root        if (markable) {
143881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root            inStream.mark(PUSHBACK_SIZE);
144881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root        }
145881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root
146f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        final long[] certRefs;
147f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        try {
148f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            certRefs = NativeCrypto.ASN1_seq_unpack_X509_bio(bis.getBioContext());
149f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        } catch (Exception e) {
150881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root            if (markable) {
151881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root                try {
152881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root                    inStream.reset();
153881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root                } catch (IOException ignored) {
154881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root                }
155881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root            }
156f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            throw new CertificateException(e);
157f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        } finally {
15819fdf1af6bada9ebf4820839780d8713ac3824faKenny Root            bis.release();
159f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        }
160f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root
161f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        if (certRefs == null) {
162f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList());
163f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        }
164f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root
165f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        final List<OpenSSLX509Certificate> certs =
166f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                new ArrayList<OpenSSLX509Certificate>(certRefs.length);
167f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        for (int i = certRefs.length - 1; i >= 0; i--) {
168f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            if (certRefs[i] == 0) {
169f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                continue;
170f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            }
171f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            certs.add(new OpenSSLX509Certificate(certRefs[i]));
172f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        }
173f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root
174f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root        return new OpenSSLX509CertPath(certs);
175f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root    }
176f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root
177e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    private static CertPath fromPkcs7Encoding(InputStream inStream) throws CertificateException {
178e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        try {
179e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            if (inStream == null || inStream.available() == 0) {
180e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList());
181e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            }
182e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        } catch (IOException e) {
183e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            throw new CertificateException("Problem reading input stream", e);
184e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
185e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
186e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        final boolean markable = inStream.markSupported();
187e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        if (markable) {
188e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            inStream.mark(PUSHBACK_SIZE);
189e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
190e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
191e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        /* Attempt to see if this is a PKCS#7 bag. */
192e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE);
193e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        try {
194e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            final byte[] buffer = new byte[PKCS7_MARKER.length];
195e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
196e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            final int len = pbis.read(buffer);
197e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            if (len < 0) {
198e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                /* No need to reset here. The stream was empty or EOF. */
199e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                throw new ParsingException("inStream is empty");
200e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            }
201e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            pbis.unread(buffer, 0, len);
202e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
203e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) {
204e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7PemInputStream(pbis));
205e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            }
206e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
207e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7DerInputStream(pbis));
208e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        } catch (Exception e) {
209e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            if (markable) {
210e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                try {
211e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                    inStream.reset();
212e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                } catch (IOException ignored) {
213e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                }
214e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            }
215e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            throw new CertificateException(e);
216e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
217e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
218e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
219e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    private static CertPath fromEncoding(InputStream inStream, Encoding encoding)
220e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            throws CertificateException {
221e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        switch (encoding) {
222f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root            case PKI_PATH:
223f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root                return fromPkiPathEncoding(inStream);
224e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            case PKCS7:
225e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                return fromPkcs7Encoding(inStream);
226e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            default:
227e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root                throw new CertificateEncodingException("Unknown encoding");
228e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
229e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
230e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
231e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    public static CertPath fromEncoding(InputStream inStream, String encoding)
232e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            throws CertificateException {
233881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root        if (inStream == null) {
2346faa71701f8f8a985db5e914369c97d511532886Kenny Root            throw new CertificateException("inStream == null");
235881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root        }
236881c794faa5fd0a4498a5f331c2fc92dd23b26a2Kenny Root
237e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        Encoding enc = Encoding.findByApiName(encoding);
238e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        if (enc == null) {
239e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            throw new CertificateException("Invalid encoding: " + encoding);
240e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
241e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
242e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        return fromEncoding(inStream, enc);
243e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
244e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
245e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    public static CertPath fromEncoding(InputStream inStream) throws CertificateException {
246e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        return fromEncoding(inStream, DEFAULT_ENCODING);
247e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
248e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root}
249