175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root/*
275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * Copyright (C) 2012 The Android Open Source Project
375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root *
475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * you may not use this file except in compliance with the License.
675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * You may obtain a copy of the License at
775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root *
875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root *
1075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * Unless required by applicable law or agreed to in writing, software
1175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * See the License for the specific language governing permissions and
1475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root * limitations under the License.
1575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root */
1675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
1738375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootpackage org.conscrypt;
1875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
1975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.io.ByteArrayOutputStream;
2075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.io.InputStream;
2175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.math.BigInteger;
2275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.InvalidKeyException;
2375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.KeyFactory;
2475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.NoSuchAlgorithmException;
2575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.NoSuchProviderException;
2675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.Principal;
2775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.PublicKey;
2875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.Signature;
2975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.SignatureException;
3075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.cert.CertificateEncodingException;
3175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.cert.CertificateException;
3275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.cert.CertificateExpiredException;
3375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.cert.CertificateNotYetValidException;
3475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.cert.CertificateParsingException;
3575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.cert.X509Certificate;
3675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.spec.InvalidKeySpecException;
3775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.security.spec.X509EncodedKeySpec;
3875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.ArrayList;
3975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.Arrays;
4075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.Calendar;
4175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.Collection;
4275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.Collections;
4375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.Date;
4475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.HashSet;
4575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.List;
4675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.Set;
4775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport java.util.TimeZone;
4875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootimport javax.security.auth.x500.X500Principal;
4938375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootimport org.apache.harmony.security.utils.AlgNameMapper;
5038375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootimport org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
5175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
5275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Rootpublic class OpenSSLX509Certificate extends X509Certificate {
5375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    private final long mContext;
5475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
5552055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root    OpenSSLX509Certificate(long ctx) {
5675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        mContext = ctx;
5775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
5875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
5975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public static OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
6075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throws ParsingException {
618a7427fa40d7fec1eb0298e20688c5751111091fKenny Root        @SuppressWarnings("resource")
6275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
6375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
6475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
6575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            final long certCtx = NativeCrypto.d2i_X509_bio(bis.getBioContext());
6675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            if (certCtx == 0) {
6775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                return null;
6875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            }
6975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return new OpenSSLX509Certificate(certCtx);
7075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } catch (Exception e) {
7175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throw new ParsingException(e);
7275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } finally {
7375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NativeCrypto.BIO_free(bis.getBioContext());
7475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
7575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
7675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
7752055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root    public static OpenSSLX509Certificate fromX509Der(byte[] encoded) {
7852055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root        final long certCtx = NativeCrypto.d2i_X509(encoded);
7952055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root        if (certCtx == 0) {
8052055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root            return null;
8152055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root        }
8252055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root        return new OpenSSLX509Certificate(certCtx);
8352055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root    }
8452055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root
8575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public static List<OpenSSLX509Certificate> fromPkcs7DerInputStream(InputStream is)
8675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throws ParsingException {
878a7427fa40d7fec1eb0298e20688c5751111091fKenny Root        @SuppressWarnings("resource")
8875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
8975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
9075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final long[] certRefs;
9175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
9275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CERTS);
9375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } catch (Exception e) {
9475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throw new ParsingException(e);
9575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } finally {
9675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NativeCrypto.BIO_free(bis.getBioContext());
9775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
9875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
9952055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root        if (certRefs == null) {
10052055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root            return Collections.emptyList();
10152055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root        }
10252055836ff1f8c235a558b3754b3f3dd25f5d38cKenny Root
10375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>(
10475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                certRefs.length);
10575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        for (int i = 0; i < certRefs.length; i++) {
10675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            if (certRefs[i] == 0) {
10775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                continue;
10875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            }
10975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            certs.add(new OpenSSLX509Certificate(certRefs[i]));
11075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
11175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return certs;
11275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
11375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
11475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public static OpenSSLX509Certificate fromX509PemInputStream(InputStream is)
11575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throws ParsingException {
1168a7427fa40d7fec1eb0298e20688c5751111091fKenny Root        @SuppressWarnings("resource")
11775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
11875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
11975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
12075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            final long certCtx = NativeCrypto.PEM_read_bio_X509(bis.getBioContext());
12175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            if (certCtx == 0L) {
12275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                return null;
12375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            }
12475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return new OpenSSLX509Certificate(certCtx);
12575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } catch (Exception e) {
12675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throw new ParsingException(e);
12775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } finally {
12875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NativeCrypto.BIO_free(bis.getBioContext());
12975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
13075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
13175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
13275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public static List<OpenSSLX509Certificate> fromPkcs7PemInputStream(InputStream is)
13375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throws ParsingException {
1348a7427fa40d7fec1eb0298e20688c5751111091fKenny Root        @SuppressWarnings("resource")
13575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
13675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
13775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final long[] certRefs;
13875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
13975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(),
14075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                    NativeCrypto.PKCS7_CERTS);
14175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } catch (Exception e) {
14275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throw new ParsingException(e);
14375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } finally {
14475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NativeCrypto.BIO_free(bis.getBioContext());
14575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
14675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
14775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>(
14875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                certRefs.length);
14975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        for (int i = 0; i < certRefs.length; i++) {
15075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            if (certRefs[i] == 0) {
15175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                continue;
15275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            }
15375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            certs.add(new OpenSSLX509Certificate(certRefs[i]));
15475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
15575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return certs;
15675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
15775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
15875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
15975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Set<String> getCriticalExtensionOIDs() {
16075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        String[] critOids =
16175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL);
16275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
16375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        /*
16475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * This API has a special case that if there are no extensions, we
16575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * should return null. So if we have no critical extensions, we'll check
16675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * non-critical extensions.
16775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         */
16875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if ((critOids.length == 0)
16975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                && (NativeCrypto.get_X509_ext_oids(mContext,
17075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                        NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
17175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return null;
17275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
17375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
17475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return new HashSet<String>(Arrays.asList(critOids));
17575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
17675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
17775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
17875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public byte[] getExtensionValue(String oid) {
17975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.X509_get_ext_oid(mContext, oid);
18075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
18175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
18275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
18375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Set<String> getNonCriticalExtensionOIDs() {
18475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        String[] nonCritOids =
18575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
18675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
18775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        /*
18875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * This API has a special case that if there are no extensions, we
18975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * should return null. So if we have no non-critical extensions, we'll
19075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * check critical extensions.
19175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         */
19275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if ((nonCritOids.length == 0)
19375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                && (NativeCrypto.get_X509_ext_oids(mContext,
19475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                        NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
19575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return null;
19675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
19775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
19875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return new HashSet<String>(Arrays.asList(nonCritOids));
19975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
20075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
20175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
20275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public boolean hasUnsupportedCriticalExtension() {
20375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return (NativeCrypto.get_X509_ex_flags(mContext) & NativeCrypto.EXFLAG_CRITICAL) != 0;
20475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
20575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
20675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
20775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public void checkValidity() throws CertificateExpiredException,
20875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            CertificateNotYetValidException {
20975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        checkValidity(new Date());
21075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
21175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
21275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
21375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public void checkValidity(Date date) throws CertificateExpiredException,
21475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            CertificateNotYetValidException {
21575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (getNotBefore().compareTo(date) > 0) {
21675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throw new CertificateNotYetValidException();
21775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
21875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
21975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (getNotAfter().compareTo(date) < 0) {
22075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throw new CertificateExpiredException();
22175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
22275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
22375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
22475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
22575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public int getVersion() {
22675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return (int) NativeCrypto.X509_get_version(mContext) + 1;
22775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
22875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
22975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
23075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public BigInteger getSerialNumber() {
23175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return new BigInteger(NativeCrypto.X509_get_serialNumber(mContext));
23275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
23375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
23475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
23575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Principal getIssuerDN() {
23675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return getIssuerX500Principal();
23775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
23875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
23975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
24075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Principal getSubjectDN() {
24175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return getSubjectX500Principal();
24275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
24375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
24475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
24575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Date getNotBefore() {
246674979bffe6f45df0beaf79128b86770d7f7cec9Kenny Root        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
247674979bffe6f45df0beaf79128b86770d7f7cec9Kenny Root        calendar.set(Calendar.MILLISECOND, 0);
24875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notBefore(mContext), calendar);
24975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return calendar.getTime();
25075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
25175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
25275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
25375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Date getNotAfter() {
254674979bffe6f45df0beaf79128b86770d7f7cec9Kenny Root        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
255674979bffe6f45df0beaf79128b86770d7f7cec9Kenny Root        calendar.set(Calendar.MILLISECOND, 0);
25675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notAfter(mContext), calendar);
25775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return calendar.getTime();
25875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
25975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
26075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
26175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public byte[] getTBSCertificate() throws CertificateEncodingException {
26275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.get_X509_cert_info_enc(mContext);
26375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
26475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
26575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
26675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public byte[] getSignature() {
26775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.get_X509_signature(mContext);
26875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
26975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
27075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
27175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public String getSigAlgName() {
27275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return AlgNameMapper.map2AlgName(getSigAlgOID());
27375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
27475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
27575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
27675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public String getSigAlgOID() {
27775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.get_X509_sig_alg_oid(mContext);
27875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
27975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
28075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
28175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public byte[] getSigAlgParams() {
28275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.get_X509_sig_alg_parameter(mContext);
28375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
28475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
28575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
28675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public boolean[] getIssuerUniqueID() {
28775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.get_X509_issuerUID(mContext);
28875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
28975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
29075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
29175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public boolean[] getSubjectUniqueID() {
29275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.get_X509_subjectUID(mContext);
29375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
29475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
29575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
29675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public boolean[] getKeyUsage() {
29775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final boolean[] kusage = NativeCrypto.get_X509_ex_kusage(mContext);
298e6de385bae91943cae91d88ad8e1bfdd951930f4Kenny Root        if (kusage == null) {
299e6de385bae91943cae91d88ad8e1bfdd951930f4Kenny Root            return null;
300e6de385bae91943cae91d88ad8e1bfdd951930f4Kenny Root        }
301e6de385bae91943cae91d88ad8e1bfdd951930f4Kenny Root
30275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (kusage.length >= 9) {
30375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return kusage;
30475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
30575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
30675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final boolean resized[] = new boolean[9];
30775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        System.arraycopy(kusage, 0, resized, 0, kusage.length);
30875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return resized;
30975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
31075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
31175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
31275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public int getBasicConstraints() {
313cd59afd3e34cb6b3645babdace22c03882e0ec19Kenny Root        if ((NativeCrypto.get_X509_ex_flags(mContext) & NativeCrypto.EXFLAG_CA) == 0) {
31475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return -1;
31575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
31675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
31775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final int pathLen = NativeCrypto.get_X509_ex_pathlen(mContext);
31875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (pathLen == -1) {
31975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return Integer.MAX_VALUE;
32075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
32175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
32275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return pathLen;
32375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
32475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
32575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
32675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public byte[] getEncoded() throws CertificateEncodingException {
32775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.i2d_X509(mContext);
32875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
32975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
33075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    private void verifyOpenSSL(OpenSSLKey pkey) throws CertificateException,
33175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
33275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            SignatureException {
333f04fc33c88d2ad1f06d58d50a0734c0ef511c5b9Kenny Root        try {
334f04fc33c88d2ad1f06d58d50a0734c0ef511c5b9Kenny Root            NativeCrypto.X509_verify(mContext, pkey.getPkeyContext());
335f04fc33c88d2ad1f06d58d50a0734c0ef511c5b9Kenny Root        } catch (RuntimeException e) {
336f04fc33c88d2ad1f06d58d50a0734c0ef511c5b9Kenny Root            throw new CertificateException(e);
337f04fc33c88d2ad1f06d58d50a0734c0ef511c5b9Kenny Root        }
33875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
33975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
34075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    private void verifyInternal(PublicKey key, String sigProvider) throws CertificateException,
34175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
34275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            SignatureException {
34375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        String sigAlg = getSigAlgName();
34475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (sigAlg == null) {
34575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            sigAlg = getSigAlgOID();
34675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
34775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
34875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final Signature sig;
34975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (sigProvider == null) {
35075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            sig = Signature.getInstance(sigAlg);
35175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } else {
35275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            sig = Signature.getInstance(sigAlg, sigProvider);
35375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
35475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
35575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        sig.initVerify(key);
35675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        sig.update(getTBSCertificate());
35775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (!sig.verify(getSignature())) {
35875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            throw new SignatureException("signature did not verify");
35975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
36075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
36175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
36275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
36375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
36475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            InvalidKeyException, NoSuchProviderException, SignatureException {
36575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (key instanceof OpenSSLKeyHolder) {
36675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey();
36775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            verifyOpenSSL(pkey);
36875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return;
36975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
37075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
37175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        verifyInternal(key, null);
37275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
37375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
37475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
37575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public void verify(PublicKey key, String sigProvider) throws CertificateException,
37675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
37775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            SignatureException {
37875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        verifyInternal(key, sigProvider);
37975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
38075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
38175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
38275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public String toString() {
38375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        ByteArrayOutputStream os = new ByteArrayOutputStream();
38475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
38575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
38675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NativeCrypto.X509_print_ex(bioCtx, mContext, 0, 0);
38775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return os.toString();
38875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } finally {
38975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            NativeCrypto.BIO_free(bioCtx);
39075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
39175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
39275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
39375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
39475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public PublicKey getPublicKey() {
39575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        /* First try to generate the key from supported OpenSSL key types. */
39675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
39775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            OpenSSLKey pkey = new OpenSSLKey(NativeCrypto.X509_get_pubkey(mContext));
39875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return pkey.getPublicKey();
39975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } catch (NoSuchAlgorithmException ignored) {
40075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
40175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
40275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        /* Try generating the key using other Java providers. */
40375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        String oid = NativeCrypto.get_X509_pubkey_oid(mContext);
40475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        byte[] encoded = NativeCrypto.i2d_X509_PUBKEY(mContext);
40575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
40675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            KeyFactory kf = KeyFactory.getInstance(oid);
40775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return kf.generatePublic(new X509EncodedKeySpec(encoded));
40875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } catch (NoSuchAlgorithmException ignored) {
40975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } catch (InvalidKeySpecException ignored) {
41075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
41175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
41275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        /*
41375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * We couldn't find anything else, so just return a nearly-unusable
41475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         * X.509-encoded key.
41575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root         */
416bd788522b36f03dc12750c69fd8b3733ef3801bdKenny Root        return new X509PublicKey(oid, encoded);
41775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
41875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
41975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
42075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public X500Principal getIssuerX500Principal() {
42175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final byte[] issuer = NativeCrypto.X509_get_issuer_name(mContext);
42275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return new X500Principal(issuer);
42375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
42475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
42575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
42675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public X500Principal getSubjectX500Principal() {
42775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        final byte[] subject = NativeCrypto.X509_get_subject_name(mContext);
42875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return new X500Principal(subject);
42975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
43075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
43175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
43275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public List<String> getExtendedKeyUsage() throws CertificateParsingException {
43375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        String[] extUsage = NativeCrypto.get_X509_ex_xkusage(mContext);
43475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (extUsage == null) {
43575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return null;
43675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
43775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
43875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return Arrays.asList(extUsage);
43975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
44075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
44175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    private static Collection<List<?>> alternativeNameArrayToList(Object[][] altNameArray) {
44275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (altNameArray == null) {
44375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return null;
44475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
44575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
44675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        Collection<List<?>> coll = new ArrayList<List<?>>(altNameArray.length);
44775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        for (int i = 0; i < altNameArray.length; i++) {
44875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            coll.add(Collections.unmodifiableList(Arrays.asList(altNameArray[i])));
44975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
45075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
45175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return Collections.unmodifiableCollection(coll);
45275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
45375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
45475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
45575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
45675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext,
45775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                NativeCrypto.GN_STACK_SUBJECT_ALT_NAME));
45875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
45975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
46075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
46175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
46275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext,
46375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                NativeCrypto.GN_STACK_ISSUER_ALT_NAME));
46475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
46575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
46675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
46775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public boolean equals(Object other) {
46875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        if (other instanceof OpenSSLX509Certificate) {
46975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            OpenSSLX509Certificate o = (OpenSSLX509Certificate) other;
47075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
47175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            return NativeCrypto.X509_cmp(mContext, o.mContext) == 0;
47275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
47375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
47475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return super.equals(other);
47575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
47675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
47775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
47875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    public int hashCode() {
47975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        /* Make this faster since we might be in hash-based structures. */
48075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return NativeCrypto.get_X509_hashCode(mContext);
48175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
48275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
48375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    long getContext() {
48475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        return mContext;
48575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
48675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root
48775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    @Override
48875dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    protected void finalize() throws Throwable {
48975dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        try {
49075dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            if (mContext != 0) {
49175dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root                NativeCrypto.X509_free(mContext);
49275dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            }
49375dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        } finally {
49475dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root            super.finalize();
49575dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root        }
49675dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root    }
49775dc9601af8ab3c65114e3c8c57d29ce5ac64125Kenny Root}
498