1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.net;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import android.content.BroadcastReceiver;
81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import android.content.Context;
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import android.content.Intent;
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import android.content.IntentFilter;
111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import android.security.KeyChain;
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import org.chromium.base.JNINamespace;
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.ByteArrayInputStream;
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.io.IOException;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.KeyStore;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.KeyStoreException;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.NoSuchAlgorithmException;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.cert.CertificateException;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.security.cert.CertificateExpiredException;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.cert.CertificateFactory;
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import java.security.cert.CertificateNotYetValidException;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.cert.X509Certificate;
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import java.util.List;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import javax.net.ssl.TrustManager;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import javax.net.ssl.TrustManagerFactory;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import javax.net.ssl.X509TrustManager;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)@JNINamespace("net")
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public class X509Util {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    private static final String TAG = "X509Util";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    public static final class TrustStorageListener extends BroadcastReceiver {
381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        @Override public void onReceive(Context context, Intent intent) {
391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                try {
411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    reloadDefaultTrustManager();
421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                }
431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                catch (CertificateException e) {
441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    Log.e(TAG, "Unable to reload the default TrustManager", e);
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                }
461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                catch (KeyStoreException e) {
471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    Log.e(TAG, "Unable to reload the default TrustManager", e);
481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                }
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                catch (NoSuchAlgorithmException e) {
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    Log.e(TAG, "Unable to reload the default TrustManager", e);
511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                }
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            }
531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        }
541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static CertificateFactory sCertificateFactory;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static final String OID_TLS_SERVER_AUTH = "1.3.6.1.5.5.7.3.1";
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static final String OID_ANY_EKU = "2.5.29.37.0";
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Server-Gated Cryptography (necessary to support a few legacy issuers):
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    //    Netscape:
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static final String OID_SERVER_GATED_NETSCAPE = "2.16.840.1.113730.4.1";
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    //    Microsoft:
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static final String OID_SERVER_GATED_MICROSOFT = "1.3.6.1.4.1.311.10.3.3";
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Trust manager backed up by the read-only system certificate store.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static X509TrustManager sDefaultTrustManager;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * BroadcastReceiver that listens to change in the system keystore to invalidate certificate
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * caches.
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     */
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    private static TrustStorageListener sTrustStorageListener;
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    /**
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Trust manager backed up by a custom certificate store. We need such manager to plant test
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * root CA to the trust store in testing.
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static X509TrustManager sTestTrustManager;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static KeyStore sTestKeyStore;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Lock object used to synchronize all calls that modify or depend on the trust managers.
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final Object sLock = new Object();
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    /*
901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * Allow disabling registering the observer for the certificat changes. Net unit tests do not
911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * load native libraries which prevent this to succeed. Moreover, the system does not allow to
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * interact with the certificate store without user interaction.
931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     */
941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    private static boolean sDisableCertificateObservationForTest = false;
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Ensures that the trust managers and certificate factory are initialized.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static void ensureInitialized() throws CertificateException,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            KeyStoreException, NoSuchAlgorithmException {
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        synchronized (sLock) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (sCertificateFactory == null) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sCertificateFactory = CertificateFactory.getInstance("X.509");
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (sDefaultTrustManager == null) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sDefaultTrustManager = X509Util.createTrustManager(null);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (sTestKeyStore == null) {
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sTestKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                try {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    sTestKeyStore.load(null);
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                } catch (IOException e) {
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    // No IO operation is attempted.
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (sTestTrustManager == null) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sTestTrustManager = X509Util.createTrustManager(sTestKeyStore);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            if (!sDisableCertificateObservationForTest &&
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    sTrustStorageListener == null) {
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                sTrustStorageListener = new TrustStorageListener();
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                nativeGetApplicationContext().registerReceiver(sTrustStorageListener,
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        new IntentFilter(KeyChain.ACTION_STORAGE_CHANGED));
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Creates a X509TrustManager backed up by the given key store. When null is passed as a key
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * store, system default trust store is used.
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @throws KeyStoreException, NoSuchAlgorithmException on error initializing the TrustManager.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static X509TrustManager createTrustManager(KeyStore keyStore) throws KeyStoreException,
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            NoSuchAlgorithmException {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String algorithm = TrustManagerFactory.getDefaultAlgorithm();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        tmf.init(keyStore);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (TrustManager tm : tmf.getTrustManagers()) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (tm instanceof X509TrustManager) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return (X509TrustManager) tm;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return null;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * After each modification of test key store, trust manager has to be generated again.
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static void reloadTestTrustManager() throws KeyStoreException,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            NoSuchAlgorithmException {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sTestTrustManager = X509Util.createTrustManager(sTestKeyStore);
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * After each modification by the system of the key store, trust manager has to be regenerated.
1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     */
1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    private static void reloadDefaultTrustManager() throws KeyStoreException,
1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            NoSuchAlgorithmException, CertificateException {
1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        sDefaultTrustManager = null;
1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        nativeNotifyKeyChainChanged();
1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        ensureInitialized();
1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    /**
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Convert a DER encoded certificate to an X509Certificate.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static X509Certificate createCertificateFromBytes(byte[] derBytes) throws
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            CertificateException, KeyStoreException, NoSuchAlgorithmException {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ensureInitialized();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return (X509Certificate) sCertificateFactory.generateCertificate(
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                new ByteArrayInputStream(derBytes));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static void addTestRootCertificate(byte[] rootCertBytes) throws CertificateException,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            KeyStoreException, NoSuchAlgorithmException {
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ensureInitialized();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        X509Certificate rootCert = createCertificateFromBytes(rootCertBytes);
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        synchronized (sLock) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            sTestKeyStore.setCertificateEntry(
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    "root_cert_" + Integer.toString(sTestKeyStore.size()), rootCert);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            reloadTestTrustManager();
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static void clearTestRootCertificates() throws NoSuchAlgorithmException,
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            CertificateException, KeyStoreException {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ensureInitialized();
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        synchronized (sLock) {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            try {
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sTestKeyStore.load(null);
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                reloadTestTrustManager();
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            } catch (IOException e) {
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                // No IO operation is attempted.
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * If an EKU extension is present in the end-entity certificate, it MUST contain either the
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * anyEKU or serverAuth or netscapeSGC or Microsoft SGC EKUs.
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     *
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @return true if there is no EKU extension or if any of the EKU extensions is one of the valid
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * OIDs for web server certificates.
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     *
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * TODO(palmer): This can be removed after the equivalent change is made to the Android default
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * TrustManager and that change is shipped to a large majority of Android users.
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    static boolean verifyKeyUsage(X509Certificate certificate) throws CertificateException {
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        List<String> ekuOids;
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        try {
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            ekuOids = certificate.getExtendedKeyUsage();
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        } catch (NullPointerException e) {
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // getExtendedKeyUsage() can crash due to an Android platform bug. This probably
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // happens when the EKU extension data is malformed so return false here.
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // See http://crbug.com/233610
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return false;
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (ekuOids == null)
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return true;
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        for (String ekuOid : ekuOids) {
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            if (ekuOid.equals(OID_TLS_SERVER_AUTH) ||
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                ekuOid.equals(OID_ANY_EKU) ||
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                ekuOid.equals(OID_SERVER_GATED_NETSCAPE) ||
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                ekuOid.equals(OID_SERVER_GATED_MICROSOFT)) {
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                return true;
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            }
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static int verifyServerCertificates(byte[][] certChain, String authType)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            throws KeyStoreException, NoSuchAlgorithmException {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (certChain == null || certChain.length == 0 || certChain[0] == null) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new IllegalArgumentException("Expected non-null and non-empty certificate " +
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "chain passed as |certChain|. |certChain|=" + certChain);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        try {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ensureInitialized();
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (CertificateException e) {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return CertVerifyResultAndroid.VERIFY_FAILED;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        X509Certificate[] serverCertificates = new X509Certificate[certChain.length];
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            for (int i = 0; i < certChain.length; ++i) {
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                serverCertificates[i] = createCertificateFromBytes(certChain[i]);
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } catch (CertificateException e) {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return CertVerifyResultAndroid.VERIFY_UNABLE_TO_PARSE;
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Expired and not yet valid certificates would be rejected by the trust managers, but the
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // trust managers report all certificate errors using the general CertificateException. In
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // order to get more granular error information, cert validity time range is being checked
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // separately.
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        try {
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            serverCertificates[0].checkValidity();
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            if (!verifyKeyUsage(serverCertificates[0]))
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                return CertVerifyResultAndroid.VERIFY_INCORRECT_KEY_USAGE;
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (CertificateExpiredException e) {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return CertVerifyResultAndroid.VERIFY_EXPIRED;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (CertificateNotYetValidException e) {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return CertVerifyResultAndroid.VERIFY_NOT_YET_VALID;
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        } catch (CertificateException e) {
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return CertVerifyResultAndroid.VERIFY_FAILED;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        synchronized (sLock) {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            try {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sDefaultTrustManager.checkServerTrusted(serverCertificates, authType);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                return CertVerifyResultAndroid.VERIFY_OK;
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            } catch (CertificateException eDefaultManager) {
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                try {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    sTestTrustManager.checkServerTrusted(serverCertificates, authType);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    return CertVerifyResultAndroid.VERIFY_OK;
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                } catch (CertificateException eTestManager) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    // Neither of the trust managers confirms the validity of the certificate chain,
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    // log the error message returned by the system trust manager.
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    Log.i(TAG, "Failed to validate the certificate chain, error: " +
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              eDefaultManager.getMessage());
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    return CertVerifyResultAndroid.VERIFY_NO_TRUSTED_ROOT;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                }
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    public static void setDisableCertificateObservationForTest(boolean disabled) {
2921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        sDisableCertificateObservationForTest = disabled;
2931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
2941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    /**
2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * Notify the native net::CertDatabase instance that the system database has been updated.
2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     */
2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    private static native void nativeNotifyKeyChainChanged();
2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    /**
3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     * Returns the application context.
3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     */
3021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    private static native Context nativeGetApplicationContext();
3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305