132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root/*
232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * Copyright (C) 2012 The Android Open Source Project
332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root *
432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * you may not use this file except in compliance with the License.
632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * You may obtain a copy of the License at
732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root *
832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root *      http://www.apache.org/licenses/LICENSE-2.0
932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root *
1032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * Unless required by applicable law or agreed to in writing, software
1132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * See the License for the specific language governing permissions and
1432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root * limitations under the License.
1532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root */
1632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
1832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
1932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.io.ByteArrayOutputStream;
2032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.io.InputStream;
2132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.math.BigInteger;
2232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.InvalidKeyException;
2332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.KeyFactory;
2432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.NoSuchAlgorithmException;
2532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.NoSuchProviderException;
2632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.Principal;
2732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.PublicKey;
2832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.Signature;
2932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.SignatureException;
300e9746b7b132058651155b33f219c7789997985bKenny Rootimport java.security.cert.Certificate;
3132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.cert.CertificateEncodingException;
3232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.cert.CertificateException;
3332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.cert.CertificateExpiredException;
3432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.cert.CertificateNotYetValidException;
3532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.cert.CertificateParsingException;
3632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.cert.X509Certificate;
3732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.spec.InvalidKeySpecException;
3832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.security.spec.X509EncodedKeySpec;
3932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.ArrayList;
4032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.Arrays;
4132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.Calendar;
4232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.Collection;
4332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.Collections;
4432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.Date;
4532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.HashSet;
4632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.List;
4732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.Set;
4832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport java.util.TimeZone;
497c3263f16bae0f1b2125de2c3c1c683303e768ceKenny Rootimport javax.crypto.BadPaddingException;
5032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootimport javax.security.auth.x500.X500Principal;
51860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport org.apache.harmony.security.utils.AlgNameMapper;
52860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
5332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
5432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootpublic class OpenSSLX509Certificate extends X509Certificate {
5532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    private final long mContext;
5632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
57e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    OpenSSLX509Certificate(long ctx) {
5832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        mContext = ctx;
5932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
6032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
6132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public static OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
6232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throws ParsingException {
63209c986cfe42dbaa5497c6e68d1b5db96b28db78Kenny Root        @SuppressWarnings("resource")
6432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
6532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
6632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
6732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            final long certCtx = NativeCrypto.d2i_X509_bio(bis.getBioContext());
6832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            if (certCtx == 0) {
6932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                return null;
7032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            }
7132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return new OpenSSLX509Certificate(certCtx);
7232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } catch (Exception e) {
7332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throw new ParsingException(e);
7432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } finally {
7519fdf1af6bada9ebf4820839780d8713ac3824faKenny Root            bis.release();
7632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
7732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
7832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
79e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    public static OpenSSLX509Certificate fromX509Der(byte[] encoded) {
80e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        final long certCtx = NativeCrypto.d2i_X509(encoded);
81e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        if (certCtx == 0) {
82e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            return null;
83e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
84e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        return new OpenSSLX509Certificate(certCtx);
85e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root    }
86e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
8732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public static List<OpenSSLX509Certificate> fromPkcs7DerInputStream(InputStream is)
8832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throws ParsingException {
89209c986cfe42dbaa5497c6e68d1b5db96b28db78Kenny Root        @SuppressWarnings("resource")
9032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
9132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
9232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final long[] certRefs;
9332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
9432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CERTS);
9532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } catch (Exception e) {
9632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throw new ParsingException(e);
9732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } finally {
9819fdf1af6bada9ebf4820839780d8713ac3824faKenny Root            bis.release();
9932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
10032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
101e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        if (certRefs == null) {
102e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root            return Collections.emptyList();
103e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root        }
104e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root
10532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>(
10632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                certRefs.length);
10732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        for (int i = 0; i < certRefs.length; i++) {
10832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            if (certRefs[i] == 0) {
10932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                continue;
11032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            }
11132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            certs.add(new OpenSSLX509Certificate(certRefs[i]));
11232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
11332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return certs;
11432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
11532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
11632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public static OpenSSLX509Certificate fromX509PemInputStream(InputStream is)
11732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throws ParsingException {
118209c986cfe42dbaa5497c6e68d1b5db96b28db78Kenny Root        @SuppressWarnings("resource")
11932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
12032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
12132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
12232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            final long certCtx = NativeCrypto.PEM_read_bio_X509(bis.getBioContext());
12332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            if (certCtx == 0L) {
12432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                return null;
12532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            }
12632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return new OpenSSLX509Certificate(certCtx);
12732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } catch (Exception e) {
12832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throw new ParsingException(e);
12932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } finally {
13019fdf1af6bada9ebf4820839780d8713ac3824faKenny Root            bis.release();
13132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
13232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
13332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
13432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public static List<OpenSSLX509Certificate> fromPkcs7PemInputStream(InputStream is)
13532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throws ParsingException {
136209c986cfe42dbaa5497c6e68d1b5db96b28db78Kenny Root        @SuppressWarnings("resource")
13732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
13832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
13932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final long[] certRefs;
14032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
14132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(),
14232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                    NativeCrypto.PKCS7_CERTS);
14332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } catch (Exception e) {
14432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throw new ParsingException(e);
14532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } finally {
14619fdf1af6bada9ebf4820839780d8713ac3824faKenny Root            bis.release();
14732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
14832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
14932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>(
15032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                certRefs.length);
15132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        for (int i = 0; i < certRefs.length; i++) {
15232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            if (certRefs[i] == 0) {
15332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                continue;
15432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            }
15532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            certs.add(new OpenSSLX509Certificate(certRefs[i]));
15632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
15732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return certs;
15832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
15932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
1600e9746b7b132058651155b33f219c7789997985bKenny Root    public static OpenSSLX509Certificate fromCertificate(Certificate cert)
1610e9746b7b132058651155b33f219c7789997985bKenny Root            throws CertificateEncodingException {
1620e9746b7b132058651155b33f219c7789997985bKenny Root        if (cert instanceof OpenSSLX509Certificate) {
1630e9746b7b132058651155b33f219c7789997985bKenny Root            return (OpenSSLX509Certificate) cert;
1640e9746b7b132058651155b33f219c7789997985bKenny Root        } else if (cert instanceof X509Certificate) {
1650e9746b7b132058651155b33f219c7789997985bKenny Root            return fromX509Der(cert.getEncoded());
1660e9746b7b132058651155b33f219c7789997985bKenny Root        } else {
1670e9746b7b132058651155b33f219c7789997985bKenny Root            throw new CertificateEncodingException("Only X.509 certificates are supported");
1680e9746b7b132058651155b33f219c7789997985bKenny Root        }
1690e9746b7b132058651155b33f219c7789997985bKenny Root    }
1700e9746b7b132058651155b33f219c7789997985bKenny Root
17132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
17232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Set<String> getCriticalExtensionOIDs() {
17332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        String[] critOids =
17432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL);
17532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
17632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        /*
17732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * This API has a special case that if there are no extensions, we
17832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * should return null. So if we have no critical extensions, we'll check
17932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * non-critical extensions.
18032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         */
18132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if ((critOids.length == 0)
18232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                && (NativeCrypto.get_X509_ext_oids(mContext,
18332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                        NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
18432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return null;
18532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
18632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
18732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return new HashSet<String>(Arrays.asList(critOids));
18832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
18932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
19032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
19132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public byte[] getExtensionValue(String oid) {
19232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.X509_get_ext_oid(mContext, oid);
19332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
19432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
19532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
19632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Set<String> getNonCriticalExtensionOIDs() {
19732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        String[] nonCritOids =
19832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
19932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
20032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        /*
20132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * This API has a special case that if there are no extensions, we
20232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * should return null. So if we have no non-critical extensions, we'll
20332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * check critical extensions.
20432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         */
20532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if ((nonCritOids.length == 0)
20632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                && (NativeCrypto.get_X509_ext_oids(mContext,
20732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                        NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
20832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return null;
20932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
21032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
21132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return new HashSet<String>(Arrays.asList(nonCritOids));
21232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
21332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
21432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
21532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public boolean hasUnsupportedCriticalExtension() {
21632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return (NativeCrypto.get_X509_ex_flags(mContext) & NativeCrypto.EXFLAG_CRITICAL) != 0;
21732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
21832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
21932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
22032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public void checkValidity() throws CertificateExpiredException,
22132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            CertificateNotYetValidException {
22232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        checkValidity(new Date());
22332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
22432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
22532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
22632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public void checkValidity(Date date) throws CertificateExpiredException,
22732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            CertificateNotYetValidException {
22832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (getNotBefore().compareTo(date) > 0) {
229cb713c076de9b3d458727ecb2ae2658859a893e2Kenny Root            throw new CertificateNotYetValidException("Certificate not valid until "
230cb713c076de9b3d458727ecb2ae2658859a893e2Kenny Root                    + getNotBefore().toString() + " (compared to " + date.toString() + ")");
23132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
23232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
23332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (getNotAfter().compareTo(date) < 0) {
234cb713c076de9b3d458727ecb2ae2658859a893e2Kenny Root            throw new CertificateExpiredException("Certificate expired at "
235cb713c076de9b3d458727ecb2ae2658859a893e2Kenny Root                    + getNotAfter().toString() + " (compared to " + date.toString() + ")");
23632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
23732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
23832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
23932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
24032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public int getVersion() {
24132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return (int) NativeCrypto.X509_get_version(mContext) + 1;
24232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
24332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
24432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
24532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public BigInteger getSerialNumber() {
2461744cf2b54cc7183ff83a3a2eab3a92a8d95ff55Kenny Root        return new BigInteger(NativeCrypto.X509_get_serialNumber(mContext));
24732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
24832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
24932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
25032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Principal getIssuerDN() {
25132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return getIssuerX500Principal();
25232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
25332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
25432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
25532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Principal getSubjectDN() {
25632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return getSubjectX500Principal();
25732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
25832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
25932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
26032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Date getNotBefore() {
2614c87dc62be38bf5b5378c494a225316cb3101f2cKenny Root        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
2624c87dc62be38bf5b5378c494a225316cb3101f2cKenny Root        calendar.set(Calendar.MILLISECOND, 0);
26332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notBefore(mContext), calendar);
26432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return calendar.getTime();
26532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
26632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
26732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
26832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Date getNotAfter() {
2694c87dc62be38bf5b5378c494a225316cb3101f2cKenny Root        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
2704c87dc62be38bf5b5378c494a225316cb3101f2cKenny Root        calendar.set(Calendar.MILLISECOND, 0);
27132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notAfter(mContext), calendar);
27232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return calendar.getTime();
27332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
27432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
27532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
27632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public byte[] getTBSCertificate() throws CertificateEncodingException {
27732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.get_X509_cert_info_enc(mContext);
27832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
27932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
28032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
28132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public byte[] getSignature() {
28232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.get_X509_signature(mContext);
28332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
28432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
28532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
28632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public String getSigAlgName() {
28732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return AlgNameMapper.map2AlgName(getSigAlgOID());
28832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
28932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
29032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
29132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public String getSigAlgOID() {
29232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.get_X509_sig_alg_oid(mContext);
29332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
29432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
29532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
29632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public byte[] getSigAlgParams() {
29732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.get_X509_sig_alg_parameter(mContext);
29832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
29932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
30032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
30132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public boolean[] getIssuerUniqueID() {
30232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.get_X509_issuerUID(mContext);
30332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
30432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
30532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
30632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public boolean[] getSubjectUniqueID() {
30732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.get_X509_subjectUID(mContext);
30832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
30932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
31032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
31132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public boolean[] getKeyUsage() {
31232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final boolean[] kusage = NativeCrypto.get_X509_ex_kusage(mContext);
31315c727fbf84cea10d0f64065a4f8f541acd6f647Kenny Root        if (kusage == null) {
31415c727fbf84cea10d0f64065a4f8f541acd6f647Kenny Root            return null;
31515c727fbf84cea10d0f64065a4f8f541acd6f647Kenny Root        }
31615c727fbf84cea10d0f64065a4f8f541acd6f647Kenny Root
31732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (kusage.length >= 9) {
31832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return kusage;
31932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
32032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
32132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final boolean resized[] = new boolean[9];
32232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        System.arraycopy(kusage, 0, resized, 0, kusage.length);
32332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return resized;
32432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
32532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
32632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
32732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public int getBasicConstraints() {
3289ec4f876b0b8e2b659728d0468492cde3763ad5dKenny Root        if ((NativeCrypto.get_X509_ex_flags(mContext) & NativeCrypto.EXFLAG_CA) == 0) {
32932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return -1;
33032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
33132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
33232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final int pathLen = NativeCrypto.get_X509_ex_pathlen(mContext);
33332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (pathLen == -1) {
33432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return Integer.MAX_VALUE;
33532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
33632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
33732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return pathLen;
33832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
33932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
34032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
34132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public byte[] getEncoded() throws CertificateEncodingException {
34232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.i2d_X509(mContext);
34332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
34432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
34532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    private void verifyOpenSSL(OpenSSLKey pkey) throws CertificateException,
34632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
34732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            SignatureException {
348d12d4d481246a06df6b4cbc9f49106bdf615610fKenny Root        try {
349d12d4d481246a06df6b4cbc9f49106bdf615610fKenny Root            NativeCrypto.X509_verify(mContext, pkey.getPkeyContext());
350d12d4d481246a06df6b4cbc9f49106bdf615610fKenny Root        } catch (RuntimeException e) {
351d12d4d481246a06df6b4cbc9f49106bdf615610fKenny Root            throw new CertificateException(e);
3527c3263f16bae0f1b2125de2c3c1c683303e768ceKenny Root        } catch (BadPaddingException e) {
353cea9ec153ef5bf27e3eee74d7c503bce02084bc2Kenny Root            throw new SignatureException();
354d12d4d481246a06df6b4cbc9f49106bdf615610fKenny Root        }
35532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
35632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
35732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    private void verifyInternal(PublicKey key, String sigProvider) throws CertificateException,
35832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
35932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            SignatureException {
36032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        String sigAlg = getSigAlgName();
36132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (sigAlg == null) {
36232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            sigAlg = getSigAlgOID();
36332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
36432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
36532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final Signature sig;
36632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (sigProvider == null) {
36732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            sig = Signature.getInstance(sigAlg);
36832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } else {
36932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            sig = Signature.getInstance(sigAlg, sigProvider);
37032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
37132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
37232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        sig.initVerify(key);
37332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        sig.update(getTBSCertificate());
37432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (!sig.verify(getSignature())) {
37532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            throw new SignatureException("signature did not verify");
37632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
37732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
37832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
37932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
38032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
38132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            InvalidKeyException, NoSuchProviderException, SignatureException {
38232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (key instanceof OpenSSLKeyHolder) {
38332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey();
38432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            verifyOpenSSL(pkey);
38532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return;
38632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
38732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
38832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        verifyInternal(key, null);
38932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
39032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
39132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
39232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public void verify(PublicKey key, String sigProvider) throws CertificateException,
39332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
39432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            SignatureException {
39532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        verifyInternal(key, sigProvider);
39632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
39732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
39832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
39932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public String toString() {
40032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        ByteArrayOutputStream os = new ByteArrayOutputStream();
40132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
40232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
40332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            NativeCrypto.X509_print_ex(bioCtx, mContext, 0, 0);
40432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return os.toString();
40532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } finally {
40619fdf1af6bada9ebf4820839780d8713ac3824faKenny Root            NativeCrypto.BIO_free_all(bioCtx);
40732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
40832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
40932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
41032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
41132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public PublicKey getPublicKey() {
41232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        /* First try to generate the key from supported OpenSSL key types. */
41332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
41432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            OpenSSLKey pkey = new OpenSSLKey(NativeCrypto.X509_get_pubkey(mContext));
41532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return pkey.getPublicKey();
41632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } catch (NoSuchAlgorithmException ignored) {
41732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
41832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
41932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        /* Try generating the key using other Java providers. */
42032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        String oid = NativeCrypto.get_X509_pubkey_oid(mContext);
42132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        byte[] encoded = NativeCrypto.i2d_X509_PUBKEY(mContext);
42232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
42332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            KeyFactory kf = KeyFactory.getInstance(oid);
42432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return kf.generatePublic(new X509EncodedKeySpec(encoded));
42532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } catch (NoSuchAlgorithmException ignored) {
42632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } catch (InvalidKeySpecException ignored) {
42732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
42832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
42932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        /*
43032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * We couldn't find anything else, so just return a nearly-unusable
43132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         * X.509-encoded key.
43232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root         */
4337d97b2cee4acabea6c8cb795d25fb1fb564f016cKenny Root        return new X509PublicKey(oid, encoded);
43432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
43532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
43632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
43732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public X500Principal getIssuerX500Principal() {
43832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final byte[] issuer = NativeCrypto.X509_get_issuer_name(mContext);
43932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return new X500Principal(issuer);
44032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
44132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
44232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
44332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public X500Principal getSubjectX500Principal() {
44432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        final byte[] subject = NativeCrypto.X509_get_subject_name(mContext);
44532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return new X500Principal(subject);
44632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
44732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
44832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
44932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public List<String> getExtendedKeyUsage() throws CertificateParsingException {
45032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        String[] extUsage = NativeCrypto.get_X509_ex_xkusage(mContext);
45132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (extUsage == null) {
45232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return null;
45332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
45432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
45532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return Arrays.asList(extUsage);
45632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
45732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
45832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    private static Collection<List<?>> alternativeNameArrayToList(Object[][] altNameArray) {
45932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (altNameArray == null) {
46032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return null;
46132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
46232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
46332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        Collection<List<?>> coll = new ArrayList<List<?>>(altNameArray.length);
46432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        for (int i = 0; i < altNameArray.length; i++) {
46532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            coll.add(Collections.unmodifiableList(Arrays.asList(altNameArray[i])));
46632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
46732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
46832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return Collections.unmodifiableCollection(coll);
46932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
47032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
47132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
47232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
47332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext,
47432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                NativeCrypto.GN_STACK_SUBJECT_ALT_NAME));
47532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
47632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
47732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
47832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
47932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext,
48032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                NativeCrypto.GN_STACK_ISSUER_ALT_NAME));
48132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
48232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
48332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
48432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public boolean equals(Object other) {
48532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        if (other instanceof OpenSSLX509Certificate) {
48632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            OpenSSLX509Certificate o = (OpenSSLX509Certificate) other;
48732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
48832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            return NativeCrypto.X509_cmp(mContext, o.mContext) == 0;
48932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
49032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
49132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return super.equals(other);
49232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
49332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
49432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
49532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    public int hashCode() {
49632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        /* Make this faster since we might be in hash-based structures. */
49732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return NativeCrypto.get_X509_hashCode(mContext);
49832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
49932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
50016c041fa20ef70221f487631f07eaf53d39ae51cKenny Root    /**
50116c041fa20ef70221f487631f07eaf53d39ae51cKenny Root     * Returns the raw pointer to the X509 context for use in JNI calls. The
50216c041fa20ef70221f487631f07eaf53d39ae51cKenny Root     * life cycle of this native pointer is managed by the
50316c041fa20ef70221f487631f07eaf53d39ae51cKenny Root     * {@code OpenSSLX509Certificate} instance and must not be destroyed or
50416c041fa20ef70221f487631f07eaf53d39ae51cKenny Root     * freed by users of this API.
50516c041fa20ef70221f487631f07eaf53d39ae51cKenny Root     */
50616c041fa20ef70221f487631f07eaf53d39ae51cKenny Root    public long getContext() {
50732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        return mContext;
50832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
50932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root
51032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    @Override
51132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    protected void finalize() throws Throwable {
51232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        try {
51332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            if (mContext != 0) {
51432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root                NativeCrypto.X509_free(mContext);
51532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            }
51632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        } finally {
51732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root            super.finalize();
51832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root        }
51932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root    }
52032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root}
521