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