12efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry/*
22efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * Copyright 2018 The Android Open Source Project
32efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry *
42efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * Licensed under the Apache License, Version 2.0 (the "License");
52efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * you may not use this file except in compliance with the License.
62efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * You may obtain a copy of the License at
72efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry *
82efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry *      http://www.apache.org/licenses/LICENSE-2.0
92efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry *
102efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * Unless required by applicable law or agreed to in writing, software
112efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * distributed under the License is distributed on an "AS IS" BASIS,
122efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * See the License for the specific language governing permissions and
142efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * limitations under the License.
152efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry */
162efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry
17c5c4a0e9481cdb7e40eddf31d53becb9ea82aca6Bo Zhupackage android.security.keystore.recovery;
182efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry
192efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berryimport java.io.ByteArrayInputStream;
202efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berryimport java.io.InputStream;
212efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berryimport java.security.cert.CertificateException;
222efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berryimport java.security.cert.CertificateFactory;
232efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berryimport java.security.cert.X509Certificate;
242efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berryimport java.util.Base64;
252efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry
262efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry/**
272efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * Static helper methods for decoding {@link X509Certificate} instances.
282efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry *
292efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry * @hide
302efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry */
312efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berrypublic class X509CertificateParsingUtils {
322efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    private static final String CERT_FORMAT = "X.509";
332efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry
342efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    /**
352efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * Decodes an {@link X509Certificate} encoded as a base-64 string.
362efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     */
372efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    public static X509Certificate decodeBase64Cert(String string) throws CertificateException {
382efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        try {
392efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry            return decodeCert(decodeBase64(string));
402efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        } catch (IllegalArgumentException e) {
412efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry            throw new CertificateException(e);
422efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        }
432efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    }
442efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry
452efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    /**
462efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * Decodes a base-64 string.
472efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     *
482efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * @throws IllegalArgumentException if not a valid base-64 string.
492efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     */
502efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    private static byte[] decodeBase64(String string) {
512efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        return Base64.getDecoder().decode(string);
522efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    }
532efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry
542efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    /**
552efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * Decodes a byte array containing an encoded X509 certificate.
562efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     *
572efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * @param certBytes the byte array containing the encoded X509 certificate
582efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * @return the decoded X509 certificate
592efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * @throws CertificateException if any parsing error occurs
602efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     */
612efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    private static X509Certificate decodeCert(byte[] certBytes) throws CertificateException {
622efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        return decodeCert(new ByteArrayInputStream(certBytes));
632efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    }
642efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry
652efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    /**
662efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * Decodes an X509 certificate from an {@code InputStream}.
672efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     *
682efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * @param inStream the input stream containing the encoded X509 certificate
692efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * @return the decoded X509 certificate
702efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     * @throws CertificateException if any parsing error occurs
712efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry     */
722efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    private static X509Certificate decodeCert(InputStream inStream) throws CertificateException {
732efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        CertificateFactory certFactory;
742efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        try {
752efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry            certFactory = CertificateFactory.getInstance(CERT_FORMAT);
762efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        } catch (CertificateException e) {
772efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry            // Should not happen, as X.509 is mandatory for all providers.
782efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry            throw new RuntimeException(e);
792efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        }
802efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry        return (X509Certificate) certFactory.generateCertificate(inStream);
812efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry    }
822efe66b6498a5e873b55d8ccbd4ac9d3dddaeb54Robert Berry}
83