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 |