19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.net.http;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstromimport com.android.org.conscrypt.SSLParametersImpl;
20e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstromimport com.android.org.conscrypt.TrustManagerImpl;
21e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom
22da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Rootimport android.util.Slog;
232269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackborn
2428b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Rootimport java.io.ByteArrayInputStream;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
26da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Rootimport java.lang.reflect.Method;
27866666071bc49bd0c4fcd1776c9d9036d4e29fecBrian Carlstromimport java.security.GeneralSecurityException;
28587a9455ded22165127e1a91cba5057f7c59a6fcKenny Rootimport java.security.KeyStore;
29587a9455ded22165127e1a91cba5057f7c59a6fcKenny Rootimport java.security.KeyStoreException;
30da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Rootimport java.security.NoSuchAlgorithmException;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.security.cert.Certificate;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.security.cert.CertificateException;
3328b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Rootimport java.security.cert.CertificateFactory;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.security.cert.X509Certificate;
35da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root
36da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Rootimport javax.net.ssl.HostnameVerifier;
37da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Rootimport javax.net.ssl.HttpsURLConnection;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.net.ssl.SSLHandshakeException;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.net.ssl.SSLSession;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.net.ssl.SSLSocket;
41da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Rootimport javax.net.ssl.TrustManager;
42da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Rootimport javax.net.ssl.TrustManagerFactory;
43e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstromimport javax.net.ssl.X509TrustManager;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Class responsible for all server certificate validation functionality
4752cd299eef703030f8fcf7a92f413791301771ccJesse Wilson *
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide}
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
5093ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurunpublic class CertificateChainValidator {
51da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root    private static final String TAG = "CertificateChainValidator";
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
53da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root    private static class NoPreloadHolder {
54da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        /**
55da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root         * The singleton instance of the certificate chain validator.
56da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root         */
57da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        private static final CertificateChainValidator sInstance = new CertificateChainValidator();
58da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root
59da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        /**
60da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root         * The singleton instance of the hostname verifier.
61da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root         */
62da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        private static final HostnameVerifier sVerifier = HttpsURLConnection
63da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                .getDefaultHostnameVerifier();
64da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root    }
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
66e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom    private X509TrustManager mTrustManager;
6752cd299eef703030f8fcf7a92f413791301771ccJesse Wilson
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
69c4e834dc47885c8dbd3a2911ce4b9fccde21c800Huahui Wu     * @return The singleton instance of the certificates chain validator
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static CertificateChainValidator getInstance() {
72da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        return NoPreloadHolder.sInstance;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
76c4e834dc47885c8dbd3a2911ce4b9fccde21c800Huahui Wu     * Creates a new certificate chain validator. This is a private constructor.
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If you need a Certificate chain validator, call getInstance().
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
79da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root    private CertificateChainValidator() {
80da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        try {
81da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
82587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root            tmf.init((KeyStore) null);
83da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            for (TrustManager tm : tmf.getTrustManagers()) {
84e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom                if (tm instanceof X509TrustManager) {
85e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom                    mTrustManager = (X509TrustManager) tm;
86da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                }
87da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            }
88da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        } catch (NoSuchAlgorithmException e) {
89587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root            throw new RuntimeException("X.509 TrustManagerFactory must be available", e);
90587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root        } catch (KeyStoreException e) {
91587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root            throw new RuntimeException("X.509 TrustManagerFactory cannot be initialized", e);
92da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        }
93da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root
94da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        if (mTrustManager == null) {
95da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            throw new RuntimeException(
96e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom                    "None of the X.509 TrustManagers are X509TrustManager");
97da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        }
98da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root    }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Performs the handshake and server certificates validation
102c4e834dc47885c8dbd3a2911ce4b9fccde21c800Huahui Wu     * Notice a new chain will be rebuilt by tracing the issuer and subject
103c4e834dc47885c8dbd3a2911ce4b9fccde21c800Huahui Wu     * before calling checkServerTrusted().
104c4e834dc47885c8dbd3a2911ce4b9fccde21c800Huahui Wu     * And if the last traced certificate is self issued and it is expired, it
105c4e834dc47885c8dbd3a2911ce4b9fccde21c800Huahui Wu     * will be dropped.
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param sslSocket The secure connection socket
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param domain The website domain
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return An SSL error object if there is an error and null otherwise
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SslError doHandshakeAndValidateServerCertificates(
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HttpsConnection connection, SSLSocket sslSocket, String domain)
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
113e103355d9332e2fab9d5c408e824ac8ab3b915a7Brian Carlstrom        // get a valid SSLSession, close the socket if we fail
11485ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        SSLSession sslSession = sslSocket.getSession();
115e103355d9332e2fab9d5c408e824ac8ab3b915a7Brian Carlstrom        if (!sslSession.isValid()) {
116e103355d9332e2fab9d5c408e824ac8ab3b915a7Brian Carlstrom            closeSocketThrowException(sslSocket, "failed to perform SSL handshake");
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // retrieve the chain of the server peer certificates
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Certificate[] peerCertificates =
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sslSocket.getSession().getPeerCertificates();
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12385ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        if (peerCertificates == null || peerCertificates.length == 0) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            closeSocketThrowException(
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sslSocket, "failed to retrieve peer certificates");
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // update the SSL certificate associated with the connection
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (connection != null) {
12985ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu                if (peerCertificates[0] != null) {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    connection.setCertificate(
13185ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu                        new SslCertificate((X509Certificate)peerCertificates[0]));
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1368234bdb36a951c1265b2bc702c06bab09509a615Huahui Wu        return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain, "RSA");
13785ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu    }
13885ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu
13985ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu    /**
14085ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * Similar to doHandshakeAndValidateServerCertificates but exposed to JNI for use
14185ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * by Chromium HTTPS stack to validate the cert chain.
1428234bdb36a951c1265b2bc702c06bab09509a615Huahui Wu     * @param certChain The bytes for certificates in ASN.1 DER encoded certificates format.
14385ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * @param domain The full website hostname and domain
1448234bdb36a951c1265b2bc702c06bab09509a615Huahui Wu     * @param authType The authentication type for the cert chain
14585ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * @return An SSL error object if there is an error and null otherwise
14685ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     */
14785ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu    public static SslError verifyServerCertificates(
14885ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        byte[][] certChain, String domain, String authType)
14985ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        throws IOException {
15085ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu
15185ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        if (certChain == null || certChain.length == 0) {
15285ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu            throw new IllegalArgumentException("bad certificate chain");
15385ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        }
15485ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu
15585ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        X509Certificate[] serverCertificates = new X509Certificate[certChain.length];
15685ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu
15728b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root        try {
15828b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root            CertificateFactory cf = CertificateFactory.getInstance("X.509");
15928b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root            for (int i = 0; i < certChain.length; ++i) {
16028b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root                serverCertificates[i] = (X509Certificate) cf.generateCertificate(
16128b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root                        new ByteArrayInputStream(certChain[i]));
16228b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root            }
16328b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root        } catch (CertificateException e) {
16428b1f0ee02e14241ffb81f431fc54053771c1c90Kenny Root            throw new IOException("can't read certificate", e);
16585ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        }
16685ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu
1678234bdb36a951c1265b2bc702c06bab09509a615Huahui Wu        return verifyServerDomainAndCertificates(serverCertificates, domain, authType);
16885ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu    }
16985ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu
17085ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu    /**
17193ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun     * Handles updates to credential storage.
17293ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun     */
17393ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun    public static void handleTrustStorageUpdate() {
174da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        TrustManagerFactory tmf;
175866666071bc49bd0c4fcd1776c9d9036d4e29fecBrian Carlstrom        try {
176da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            tmf = TrustManagerFactory.getInstance("X.509");
177587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root            tmf.init((KeyStore) null);
178da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        } catch (NoSuchAlgorithmException e) {
179da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
180da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            return;
181587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root        } catch (KeyStoreException e) {
182587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root            Slog.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
183587a9455ded22165127e1a91cba5057f7c59a6fcKenny Root            return;
184da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        }
185da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root
186da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        TrustManager[] tms = tmf.getTrustManagers();
187da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        boolean sentUpdate = false;
188da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        for (TrustManager tm : tms) {
189da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            try {
190da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                Method updateMethod = tm.getClass().getDeclaredMethod("handleTrustStorageUpdate");
191da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                updateMethod.setAccessible(true);
192da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                updateMethod.invoke(tm);
193da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                sentUpdate = true;
194da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            } catch (Exception e) {
195866666071bc49bd0c4fcd1776c9d9036d4e29fecBrian Carlstrom            }
196da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        }
197da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        if (!sentUpdate) {
198da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root            Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
19993ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun        }
20093ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun    }
20193ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun
20293ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun    /**
20385ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates.
2048234bdb36a951c1265b2bc702c06bab09509a615Huahui Wu     * Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.
20585ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * @param chain the cert chain in X509 cert format.
20685ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * @param domain The full website hostname and domain
2078234bdb36a951c1265b2bc702c06bab09509a615Huahui Wu     * @param authType The authentication type for the cert chain
20885ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     * @return An SSL error object if there is an error and null otherwise
20985ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu     */
21085ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu    private static SslError verifyServerDomainAndCertificates(
2118234bdb36a951c1265b2bc702c06bab09509a615Huahui Wu            X509Certificate[] chain, String domain, String authType)
21285ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu            throws IOException {
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // check if the first certificate in the chain is for this site
21485ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        X509Certificate currCertificate = chain[0];
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (currCertificate == null) {
21685ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu            throw new IllegalArgumentException("certificate for this site is null");
21785ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu        }
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21952cd299eef703030f8fcf7a92f413791301771ccJesse Wilson        boolean valid = domain != null
22052cd299eef703030f8fcf7a92f413791301771ccJesse Wilson                && !domain.isEmpty()
221da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                && NoPreloadHolder.sVerifier.verify(domain,
222da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root                        new DelegatingSSLSession.CertificateWrap(currCertificate));
22352cd299eef703030f8fcf7a92f413791301771ccJesse Wilson        if (!valid) {
22485ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu            if (HttpLog.LOGV) {
22585ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu                HttpLog.v("certificate not for this host: " + domain);
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22785ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu            return new SslError(SslError.SSL_IDMISMATCH, currCertificate);
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
231e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom            X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
232e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom            if (x509TrustManager instanceof TrustManagerImpl) {
233e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom                TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
234e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom                trustManager.checkServerTrusted(chain, authType, domain);
235e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom            } else {
236e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom                x509TrustManager.checkServerTrusted(chain, authType);
237e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom            }
23885ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu            return null;  // No errors.
239866666071bc49bd0c4fcd1776c9d9036d4e29fecBrian Carlstrom        } catch (GeneralSecurityException e) {
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (HttpLog.LOGV) {
24185ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu                HttpLog.v("failed to validate the certificate chain, error: " +
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    e.getMessage());
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24485ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu            return new SslError(SslError.SSL_UNTRUSTED, currCertificate);
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
248da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root    /**
249e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom     * Returns the platform default {@link X509TrustManager}.
250da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root     */
251e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom    private X509TrustManager getTrustManager() {
252da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root        return mTrustManager;
253da776c872e8880b48dfac4a9e9a2d90e398e4608Kenny Root    }
25485ffa26f67efad30912e1561b5123b6f8f5827eeHuahui Wu
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void closeSocketThrowException(
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SSLSocket socket, String errorMessage, String defaultErrorMessage)
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        closeSocketThrowException(
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            socket, errorMessage != null ? errorMessage : defaultErrorMessage);
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void closeSocketThrowException(SSLSocket socket,
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String errorMessage) throws IOException {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (HttpLog.LOGV) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HttpLog.v("validation error: " + errorMessage);
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (socket != null) {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SSLSession session = socket.getSession();
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (session != null) {
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                session.invalidate();
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            socket.close();
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw new SSLHandshakeException(errorMessage);
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
279e2dd396cef8c3b1c22b799ac931e207fdc729154Brian Carlstrom}
280