Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.net; | 5 package org.chromium.net; |
| 6 | 6 |
| 7 import android.util.Log; | 7 import android.util.Log; |
| 8 | 8 |
| 9 import java.io.ByteArrayInputStream; | 9 import java.io.ByteArrayInputStream; |
| 10 import java.io.IOException; | |
| 10 import java.security.KeyStore; | 11 import java.security.KeyStore; |
| 11 import java.security.KeyStoreException; | 12 import java.security.KeyStoreException; |
| 12 import java.security.NoSuchAlgorithmException; | 13 import java.security.NoSuchAlgorithmException; |
| 13 import java.security.cert.CertificateException; | 14 import java.security.cert.CertificateException; |
| 14 import java.security.cert.CertificateFactory; | 15 import java.security.cert.CertificateFactory; |
| 15 import java.security.cert.X509Certificate; | 16 import java.security.cert.X509Certificate; |
| 16 | 17 |
| 17 import javax.net.ssl.TrustManager; | 18 import javax.net.ssl.TrustManager; |
| 18 import javax.net.ssl.TrustManagerFactory; | 19 import javax.net.ssl.TrustManagerFactory; |
| 19 import javax.net.ssl.X509TrustManager; | 20 import javax.net.ssl.X509TrustManager; |
| 20 | 21 |
| 21 public class X509Util { | 22 public class X509Util { |
| 22 | 23 |
| 23 private static final String TAG = X509Util.class.getName(); | 24 private static final String TAG = X509Util.class.getName(); |
| 24 | 25 |
| 25 private static CertificateFactory sCertificateFactory; | 26 private static CertificateFactory sCertificateFactory; |
| 26 | 27 |
| 27 /** | 28 /** |
| 28 * Default sources of authentication trust decisions and certificate object | 29 * Trust manager backed up by the read-only system certificate store. |
| 29 * creation. | |
| 30 */ | 30 */ |
| 31 private static X509TrustManager sDefaultTrustManager; | 31 private static X509TrustManager sDefaultTrustManager; |
| 32 | 32 |
| 33 /** | 33 /** |
| 34 * Ensures that |sCertificateFactory| and |sDefaultTrustManager| are | 34 * Trust manager backed up by a custom certificate store. |
| 35 * initialized. | |
| 36 */ | 35 */ |
| 37 private static synchronized void ensureInitialized() throws CertificateExcep tion, | 36 private static X509TrustManager sLocalTrustManager; |
| 37 private static KeyStore sLocalKeyStore; | |
| 38 | |
| 39 /** | |
| 40 * The trust manager used to make trust decisions. If |sLocalKeyStore| is no nempty, this is | |
| 41 * |sLocalTrustManager|, otherwise this is |sDefaultTrustManager|. | |
| 42 */ | |
| 43 private static X509TrustManager sTrustManager; | |
|
Ryan Sleevi
2012/12/03 02:29:03
Note: On all other platforms, TestRootCerts is add
digit1
2012/12/03 13:44:13
Ah, my bad, I was the one advising ppi to implemen
| |
| 44 | |
| 45 /** | |
| 46 * Lock used to synchronize all calls that initialize or modify the trust ma nagers or | |
| 47 * certificate factory. | |
| 48 */ | |
| 49 private static final Object sLock = new Object(); | |
| 50 | |
| 51 /** | |
| 52 * Ensures that the trust managers and certificate factory are initialized. | |
| 53 */ | |
| 54 private static void ensureInitialized() throws CertificateException, | |
| 38 KeyStoreException, NoSuchAlgorithmException { | 55 KeyStoreException, NoSuchAlgorithmException { |
| 39 if (sCertificateFactory == null) { | 56 synchronized(sLock) { |
| 40 sCertificateFactory = CertificateFactory.getInstance("X.509"); | 57 if (sCertificateFactory == null) { |
| 41 } | 58 sCertificateFactory = CertificateFactory.getInstance("X.509"); |
| 42 if (sDefaultTrustManager == null) { | 59 } |
| 43 sDefaultTrustManager = X509Util.createDefaultTrustManager(); | 60 if (sDefaultTrustManager == null) { |
| 61 sDefaultTrustManager = X509Util.createTrustManager(null); | |
| 62 } | |
| 63 if (sLocalKeyStore == null) { | |
| 64 sLocalKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()) ; | |
| 65 try { | |
| 66 sLocalKeyStore.load(null); | |
| 67 } catch(IOException e) {} // No IO operation is attempted. | |
| 68 } | |
| 69 if (sLocalTrustManager == null) { | |
| 70 sLocalTrustManager = X509Util.createTrustManager(sLocalKeyStore) ; | |
| 71 } | |
| 72 sTrustManager = sLocalKeyStore.size() > 0 ? sLocalTrustManager : sDe faultTrustManager; | |
| 44 } | 73 } |
| 45 } | 74 } |
| 46 | 75 |
| 47 /** | 76 /** |
| 48 * Creates a TrustManagerFactory and returns the X509TrustManager instance | 77 * Creates a X509TrustManager backed up by the given key store. When null is passed as a key |
| 49 * if one can be found. | 78 * store, system default trust store is used. |
| 50 * | 79 * @throws KeyStoreException, NoSuchAlgorithmException on error initializing the TrustManager. |
| 51 * @throws CertificateException,KeyStoreException,NoSuchAlgorithmException | |
| 52 * on error initializing the TrustManager. | |
| 53 */ | 80 */ |
| 54 private static X509TrustManager createDefaultTrustManager() | 81 private static X509TrustManager createTrustManager(KeyStore keyStore) throws KeyStoreException, |
| 55 throws KeyStoreException, NoSuchAlgorithmException { | 82 NoSuchAlgorithmException { |
| 56 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); | 83 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); |
| 57 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); | 84 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); |
| 58 tmf.init((KeyStore) null); | 85 tmf.init(keyStore); |
| 59 | 86 |
| 60 for (TrustManager tm : tmf.getTrustManagers()) { | 87 for (TrustManager tm : tmf.getTrustManagers()) { |
| 61 if (tm instanceof X509TrustManager) { | 88 if (tm instanceof X509TrustManager) { |
| 62 return (X509TrustManager) tm; | 89 return (X509TrustManager) tm; |
| 63 } | 90 } |
| 64 } | 91 } |
| 65 return null; | 92 return null; |
| 66 } | 93 } |
| 67 | 94 |
| 68 /** | 95 /** |
| 69 * Convert a DER encoded certificate to an X509Certificate | 96 * Convert a DER encoded certificate to an X509Certificate. |
| 70 */ | 97 */ |
| 71 public static X509Certificate createCertificateFromBytes(byte[] derBytes) th rows | 98 public static X509Certificate createCertificateFromBytes(byte[] derBytes) th rows |
| 72 CertificateException, KeyStoreException, NoSuchAlgorithmException { | 99 CertificateException, KeyStoreException, NoSuchAlgorithmException { |
| 73 ensureInitialized(); | 100 ensureInitialized(); |
| 74 return (X509Certificate) sCertificateFactory.generateCertificate( | 101 return (X509Certificate) sCertificateFactory.generateCertificate( |
| 75 new ByteArrayInputStream(derBytes)); | 102 new ByteArrayInputStream(derBytes)); |
| 76 } | 103 } |
| 77 | 104 |
| 105 public static void addTestRootCertificate(byte[] rootCertBytes) throws Certi ficateException, | |
| 106 KeyStoreException, NoSuchAlgorithmException { | |
| 107 ensureInitialized(); | |
| 108 X509Certificate rootCert = createCertificateFromBytes(rootCertBytes); | |
| 109 synchronized(sLock) { | |
| 110 sLocalKeyStore.setCertificateEntry( | |
| 111 "root_cert_" + Integer.toString(sLocalKeyStore.size()), root Cert); | |
| 112 | |
| 113 sTrustManager = sLocalTrustManager; | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 public static void clearTestRootCertificates() throws NoSuchAlgorithmExcepti on, | |
| 118 CertificateException, KeyStoreException { | |
| 119 ensureInitialized(); | |
| 120 synchronized(sLock) { | |
| 121 try { | |
| 122 sLocalKeyStore.load(null); | |
| 123 } catch(IOException e) {} // No IO operation is attempted. | |
| 124 | |
| 125 sTrustManager = sDefaultTrustManager; | |
| 126 } | |
| 127 } | |
| 128 | |
| 78 public static boolean verifyServerCertificates(byte[][] certChain, String au thType) | 129 public static boolean verifyServerCertificates(byte[][] certChain, String au thType) |
| 79 throws CertificateException, KeyStoreException, NoSuchAlgorithmExcep tion { | 130 throws CertificateException, KeyStoreException, NoSuchAlgorithmExcep tion { |
| 80 if (certChain == null || certChain.length == 0 || certChain[0] == null) { | 131 if (certChain == null || certChain.length == 0 || certChain[0] == null) { |
| 81 throw new IllegalArgumentException("Expected non-null and non-empty certificate " + | 132 throw new IllegalArgumentException("Expected non-null and non-empty certificate " + |
| 82 "chain passed as |certChain|. |certChain|=" + certChain); | 133 "chain passed as |certChain|. |certChain|=" + certChain); |
| 83 } | 134 } |
| 84 | 135 |
| 85 ensureInitialized(); | 136 ensureInitialized(); |
| 86 X509Certificate[] serverCertificates = new X509Certificate[certChain.len gth]; | 137 X509Certificate[] serverCertificates = new X509Certificate[certChain.len gth]; |
| 87 for (int i = 0; i < certChain.length; ++i) { | 138 for (int i = 0; i < certChain.length; ++i) { |
| 88 serverCertificates[i] = createCertificateFromBytes(certChain[i]); | 139 serverCertificates[i] = createCertificateFromBytes(certChain[i]); |
| 89 } | 140 } |
| 90 | 141 |
| 91 try { | 142 try { |
| 92 sDefaultTrustManager.checkServerTrusted(serverCertificates, authType ); | 143 synchronized (sLock) { |
| 144 sTrustManager.checkServerTrusted(serverCertificates, authType); | |
| 145 } | |
| 93 return true; | 146 return true; |
| 94 } catch (CertificateException e) { | 147 } catch (CertificateException e) { |
| 95 Log.i(TAG, "failed to validate the certificate chain, error: " + | 148 Log.i(TAG, "failed to validate the certificate chain, error: " + e.g etMessage()); |
| 96 e.getMessage()); | |
| 97 } | 149 } |
| 98 return false; | 150 return false; |
| 99 } | 151 } |
| 100 | 152 } |
| 101 } | |
| OLD | NEW |