120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang/*
220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * Copyright (C) 2013 The Android Open Source Project
338ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang *
420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * Licensed under the Apache License, Version 2.0 (the "License");
520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * you may not use this file except in compliance with the License.
620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * You may obtain a copy of the License at
720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang *
820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang *      http://www.apache.org/licenses/LICENSE-2.0
920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang *
1020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * Unless required by applicable law or agreed to in writing, software
1120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * distributed under the License is distributed on an "AS IS" BASIS,
1220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * See the License for the specific language governing permissions and
1420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * limitations under the License.
1520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang */
1620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
1720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changpackage org.conscrypt;
1820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
1920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.io.IOException;
2020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.io.InputStream;
2120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.io.PushbackInputStream;
2220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.security.cert.CertPath;
2338ef2572d26fc760c584a1855a3d002f34eb0231Jiho Changimport java.security.cert.Certificate;
2420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.security.cert.CertificateEncodingException;
2538ef2572d26fc760c584a1855a3d002f34eb0231Jiho Changimport java.security.cert.CertificateException;
2620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.security.cert.X509Certificate;
2720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.util.ArrayList;
2820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.util.Arrays;
2920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.util.Collections;
3020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.util.Iterator;
3120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport java.util.List;
3220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changimport org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
3320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
3420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Changpublic class OpenSSLX509CertPath extends CertPath {
3520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private static final byte[] PKCS7_MARKER = "-----BEGIN PKCS7".getBytes();
3620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
3720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private static final int PUSHBACK_SIZE = 64;
3820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
3920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    /**
4020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang     * Supported encoding types for CerthPath. Used by the various APIs that
4120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang     * encode this into bytes such as {@link #getEncoded()}.
4220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang     */
4320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private enum Encoding {
4420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        PKI_PATH("PkiPath"),
4520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        PKCS7("PKCS7");
4638ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang
4720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        private final String apiName;
4820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
4920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        Encoding(String apiName) {
5020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            this.apiName = apiName;
5120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
5220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
5320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        static Encoding findByApiName(String apiName) throws CertificateEncodingException {
5420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            for (Encoding element : values()) {
5520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                if (element.apiName.equals(apiName)) {
5620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                    return element;
5720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                }
5820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
5920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
6020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            return null;
6120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
6220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
6320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
6420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    /** Unmodifiable list of encodings for the API. */
6520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private static final List<String> ALL_ENCODINGS = Collections.unmodifiableList(Arrays
6620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            .asList(new String[] {
6720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                    Encoding.PKI_PATH.apiName,
6820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                    Encoding.PKCS7.apiName,
6920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }));
7020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
7120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private static final Encoding DEFAULT_ENCODING = Encoding.PKI_PATH;
7220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
7320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private final List<? extends X509Certificate> mCertificates;
7420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
7520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    static Iterator<String> getEncodingsIterator() {
7620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        return ALL_ENCODINGS.iterator();
7720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
7820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
7920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    protected OpenSSLX509CertPath(List<? extends X509Certificate> certificates) {
8020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        super("X.509");
8120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
8220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        mCertificates = certificates;
8320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
8420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
8520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    @Override
8620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    public List<? extends Certificate> getCertificates() {
8720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        return Collections.unmodifiableList(mCertificates);
8820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
8920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
9020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private byte[] getEncoded(Encoding encoding) throws CertificateEncodingException {
9120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        final OpenSSLX509Certificate[] certs = new OpenSSLX509Certificate[mCertificates.size()];
9220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        final long[] certRefs = new long[certs.length];
9320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
9420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        for (int i = 0, j = certs.length - 1; j >= 0; i++, j--) {
9520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            final X509Certificate cert = mCertificates.get(i);
9620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
9720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            if (cert instanceof OpenSSLX509Certificate) {
9820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                certs[j] = (OpenSSLX509Certificate) cert;
9920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            } else {
10020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                certs[j] = OpenSSLX509Certificate.fromX509Der(cert.getEncoded());
10120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
10220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
10320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            certRefs[j] = certs[j].getContext();
10420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
10520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
10620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        switch (encoding) {
10720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            case PKI_PATH:
10820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                return NativeCrypto.ASN1_seq_pack_X509(certRefs);
10920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            case PKCS7:
11020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                return NativeCrypto.i2d_PKCS7(certRefs);
11120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            default:
11220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                throw new CertificateEncodingException("Unknown encoding");
11320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
11420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
11520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
11620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    @Override
11720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    public byte[] getEncoded() throws CertificateEncodingException {
11820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        return getEncoded(DEFAULT_ENCODING);
11920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
12020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
12120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    @Override
12220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    public byte[] getEncoded(String encoding) throws CertificateEncodingException {
12320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        Encoding enc = Encoding.findByApiName(encoding);
12420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        if (enc == null) {
12520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            throw new CertificateEncodingException("Invalid encoding: " + encoding);
12620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
12720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
12820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        return getEncoded(enc);
12920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
13020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
13120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    @Override
13220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    public Iterator<String> getEncodings() {
13320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        return getEncodingsIterator();
13420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
13520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
13620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private static CertPath fromPkiPathEncoding(InputStream inStream) throws CertificateException {
13720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(inStream);
13820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
13920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        final boolean markable = inStream.markSupported();
14020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        if (markable) {
14120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            inStream.mark(PUSHBACK_SIZE);
14220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
14320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
14420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        final long[] certRefs;
14520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        try {
14620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            certRefs = NativeCrypto.ASN1_seq_unpack_X509_bio(bis.getBioContext());
14720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        } catch (Exception e) {
14820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            if (markable) {
14920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                try {
15020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                    inStream.reset();
15120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                } catch (IOException ignored) {
15220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                }
15320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
15420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            throw new CertificateException(e);
15520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        } finally {
15620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            NativeCrypto.BIO_free(bis.getBioContext());
15720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
15820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
15920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        if (certRefs == null) {
16020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList());
16120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
16220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
16320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        final List<OpenSSLX509Certificate> certs =
16420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                new ArrayList<OpenSSLX509Certificate>(certRefs.length);
16520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        for (int i = certRefs.length - 1; i >= 0; i--) {
16620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            if (certRefs[i] == 0) {
16720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                continue;
16820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
16920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            certs.add(new OpenSSLX509Certificate(certRefs[i]));
17020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
17120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
17220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        return new OpenSSLX509CertPath(certs);
17320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
17420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
17520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private static CertPath fromPkcs7Encoding(InputStream inStream) throws CertificateException {
17620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        try {
17720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            if (inStream == null || inStream.available() == 0) {
17820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList());
17920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
18020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        } catch (IOException e) {
18120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            throw new CertificateException("Problem reading input stream", e);
18220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
18320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
18420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        final boolean markable = inStream.markSupported();
18520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        if (markable) {
18620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            inStream.mark(PUSHBACK_SIZE);
18720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
18820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
18920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        /* Attempt to see if this is a PKCS#7 bag. */
19020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE);
19120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        try {
19220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            final byte[] buffer = new byte[PKCS7_MARKER.length];
19320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
1946201909bad11eab8339ec8dbef4d0152231308afDima Zavin            final int len = pbis.read(buffer);
19520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            if (len < 0) {
19620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                /* No need to reset here. The stream was empty or EOF. */
19720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                throw new ParsingException("inStream is empty");
19820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
19920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            pbis.unread(buffer, 0, len);
20020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
20120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) {
20220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7PemInputStream(pbis));
20320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
20420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang
2050996d9d5d25dcf3c90e40288a2e151dfbbf16959Dima Zavin            return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7DerInputStream(pbis));
20620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        } catch (Exception e) {
20720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            if (markable) {
20820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                try {
20920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                    inStream.reset();
21020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                } catch (IOException ignored) {
21120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang                }
21220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            }
21320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang            throw new CertificateException(e);
21420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
21520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
21638ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang
21720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    private static CertPath fromEncoding(InputStream inStream, Encoding encoding)
21838ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang            throws CertificateException {
21938ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang        switch (encoding) {
22038ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang            case PKI_PATH:
22138ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang                return fromPkiPathEncoding(inStream);
22238ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang            case PKCS7:
22338ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang                return fromPkcs7Encoding(inStream);
22438ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang            default:
22538ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang                throw new CertificateEncodingException("Unknown encoding");
22638ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang        }
22720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    }
22838ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang
22938ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang    public static CertPath fromEncoding(InputStream inStream, String encoding)
23038ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang            throws CertificateException {
23120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        if (inStream == null) {
23238ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang            throw new CertificateException("inStream == null");
23320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        }
23438ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang
23538ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang        Encoding enc = Encoding.findByApiName(encoding);
23620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        if (enc == null) {
23738ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang            throw new CertificateException("Invalid encoding: " + encoding);
23838ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang        }
23938ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang
240d866f455acab131be8f058733abd9c1ede2fcfeaSeungBeom Kim        return fromEncoding(inStream, enc);
24138ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang    }
24238ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang
24320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang    public static CertPath fromEncoding(InputStream inStream) throws CertificateException {
24420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang        return fromEncoding(inStream, DEFAULT_ENCODING);
24538ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang    }
24638ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang}
24738ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang