1/*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.security.keystore.recovery;
18
19import java.io.ByteArrayInputStream;
20import java.io.InputStream;
21import java.security.cert.CertificateException;
22import java.security.cert.CertificateFactory;
23import java.security.cert.X509Certificate;
24import java.util.Base64;
25
26/**
27 * Static helper methods for decoding {@link X509Certificate} instances.
28 *
29 * @hide
30 */
31public class X509CertificateParsingUtils {
32    private static final String CERT_FORMAT = "X.509";
33
34    /**
35     * Decodes an {@link X509Certificate} encoded as a base-64 string.
36     */
37    public static X509Certificate decodeBase64Cert(String string) throws CertificateException {
38        try {
39            return decodeCert(decodeBase64(string));
40        } catch (IllegalArgumentException e) {
41            throw new CertificateException(e);
42        }
43    }
44
45    /**
46     * Decodes a base-64 string.
47     *
48     * @throws IllegalArgumentException if not a valid base-64 string.
49     */
50    private static byte[] decodeBase64(String string) {
51        return Base64.getDecoder().decode(string);
52    }
53
54    /**
55     * Decodes a byte array containing an encoded X509 certificate.
56     *
57     * @param certBytes the byte array containing the encoded X509 certificate
58     * @return the decoded X509 certificate
59     * @throws CertificateException if any parsing error occurs
60     */
61    private static X509Certificate decodeCert(byte[] certBytes) throws CertificateException {
62        return decodeCert(new ByteArrayInputStream(certBytes));
63    }
64
65    /**
66     * Decodes an X509 certificate from an {@code InputStream}.
67     *
68     * @param inStream the input stream containing the encoded X509 certificate
69     * @return the decoded X509 certificate
70     * @throws CertificateException if any parsing error occurs
71     */
72    private static X509Certificate decodeCert(InputStream inStream) throws CertificateException {
73        CertificateFactory certFactory;
74        try {
75            certFactory = CertificateFactory.getInstance(CERT_FORMAT);
76        } catch (CertificateException e) {
77            // Should not happen, as X.509 is mandatory for all providers.
78            throw new RuntimeException(e);
79        }
80        return (X509Certificate) certFactory.generateCertificate(inStream);
81    }
82}
83