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. | 35 */ |
36 private static X509TrustManager sLocalTrustManager; | |
37 private static KeyStore sLocalKeyStore; | |
38 | |
39 /** | |
40 * Ensures that the trust managers and certificate factory are initialized. | |
36 */ | 41 */ |
37 private static synchronized void ensureInitialized() throws CertificateExcep tion, | 42 private static synchronized void ensureInitialized() throws CertificateExcep tion, |
38 KeyStoreException, NoSuchAlgorithmException { | 43 KeyStoreException, NoSuchAlgorithmException { |
39 if (sCertificateFactory == null) { | 44 if (sCertificateFactory == null) { |
40 sCertificateFactory = CertificateFactory.getInstance("X.509"); | 45 sCertificateFactory = CertificateFactory.getInstance("X.509"); |
41 } | 46 } |
42 if (sDefaultTrustManager == null) { | 47 if (sDefaultTrustManager == null) { |
43 sDefaultTrustManager = X509Util.createDefaultTrustManager(); | 48 sDefaultTrustManager = X509Util.createTrustManager(null); |
49 } | |
50 if (sLocalKeyStore == null) { | |
51 sLocalKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | |
52 try { | |
53 sLocalKeyStore.load(null); | |
54 } catch(IOException e) {} // No IO operation is attempted. | |
55 } | |
56 if (sLocalTrustManager == null) { | |
57 sLocalTrustManager = X509Util.createTrustManager(sLocalKeyStore); | |
44 } | 58 } |
45 } | 59 } |
46 | 60 |
47 /** | 61 /** |
48 * Creates a TrustManagerFactory and returns the X509TrustManager instance | 62 * Creates a X509TrustManager backed up by the given key store. When null |
49 * if one can be found. | 63 * is passed as a key store, system default trust store is used. |
50 * | 64 * @throws KeyStoreException, NoSuchAlgorithmException on error |
51 * @throws CertificateException,KeyStoreException,NoSuchAlgorithmException | 65 * initializing the TrustManager. |
52 * on error initializing the TrustManager. | |
53 */ | 66 */ |
54 private static X509TrustManager createDefaultTrustManager() | 67 private static X509TrustManager createTrustManager(KeyStore keyStore) |
55 throws KeyStoreException, NoSuchAlgorithmException { | 68 throws KeyStoreException, NoSuchAlgorithmException { |
56 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); | 69 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); |
57 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); | 70 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); |
58 tmf.init((KeyStore) null); | 71 tmf.init(keyStore); |
59 | 72 |
60 for (TrustManager tm : tmf.getTrustManagers()) { | 73 for (TrustManager tm : tmf.getTrustManagers()) { |
61 if (tm instanceof X509TrustManager) { | 74 if (tm instanceof X509TrustManager) { |
62 return (X509TrustManager) tm; | 75 return (X509TrustManager) tm; |
63 } | 76 } |
64 } | 77 } |
65 return null; | 78 return null; |
66 } | 79 } |
67 | 80 |
68 /** | 81 /** |
69 * Convert a DER encoded certificate to an X509Certificate | 82 * Convert a DER encoded certificate to an X509Certificate. |
70 */ | 83 */ |
71 public static X509Certificate createCertificateFromBytes(byte[] derBytes) th rows | 84 public static X509Certificate createCertificateFromBytes(byte[] derBytes) th rows |
72 CertificateException, KeyStoreException, NoSuchAlgorithmException { | 85 CertificateException, KeyStoreException, NoSuchAlgorithmException { |
73 ensureInitialized(); | 86 ensureInitialized(); |
74 return (X509Certificate) sCertificateFactory.generateCertificate( | 87 return (X509Certificate) sCertificateFactory.generateCertificate( |
75 new ByteArrayInputStream(derBytes)); | 88 new ByteArrayInputStream(derBytes)); |
76 } | 89 } |
77 | 90 |
91 public static void addLocalRootCertificate(byte[] rootCertBytes) | |
92 throws CertificateException, KeyStoreException, | |
93 NoSuchAlgorithmException { | |
94 ensureInitialized(); | |
95 X509Certificate rootCert = createCertificateFromBytes(rootCertBytes); | |
96 sLocalKeyStore.setCertificateEntry( | |
97 "root_cert_" + Integer.toString(sLocalKeyStore.size()), | |
98 rootCert); | |
99 } | |
100 | |
101 public static void clearLocalRootCertificates() | |
102 throws NoSuchAlgorithmException, CertificateException, KeyStoreExcep tion { | |
103 ensureInitialized(); | |
104 try { | |
105 sLocalKeyStore.load(null); | |
106 } catch(IOException e) {} // No IO operation is attempted. | |
107 | |
108 } | |
109 | |
78 public static boolean verifyServerCertificates(byte[][] certChain, String au thType) | 110 public static boolean verifyServerCertificates(byte[][] certChain, String au thType) |
79 throws CertificateException, KeyStoreException, NoSuchAlgorithmExcep tion { | 111 throws CertificateException, KeyStoreException, NoSuchAlgorithmExcep tion { |
80 if (certChain == null || certChain.length == 0 || certChain[0] == null) { | 112 if (certChain == null || certChain.length == 0 || certChain[0] == null) { |
81 throw new IllegalArgumentException("Expected non-null and non-empty certificate " + | 113 throw new IllegalArgumentException("Expected non-null and non-empty certificate " + |
82 "chain passed as |certChain|. |certChain|=" + certChain); | 114 "chain passed as |certChain|. |certChain|=" + certChain); |
83 } | 115 } |
84 | 116 |
85 ensureInitialized(); | 117 ensureInitialized(); |
86 X509Certificate[] serverCertificates = new X509Certificate[certChain.len gth]; | 118 X509Certificate[] serverCertificates = new X509Certificate[certChain.len gth]; |
87 for (int i = 0; i < certChain.length; ++i) { | 119 for (int i = 0; i < certChain.length; ++i) { |
88 serverCertificates[i] = createCertificateFromBytes(certChain[i]); | 120 serverCertificates[i] = createCertificateFromBytes(certChain[i]); |
89 } | 121 } |
90 | 122 |
91 try { | 123 try { |
92 sDefaultTrustManager.checkServerTrusted(serverCertificates, authType ); | 124 sDefaultTrustManager.checkServerTrusted(serverCertificates, authType ); |
93 return true; | 125 return true; |
94 } catch (CertificateException e) { | 126 } catch (CertificateException e) { |
95 Log.i(TAG, "failed to validate the certificate chain, error: " + | 127 try { |
digit1
2012/11/28 10:42:34
I think it'd be preferable to separate the usage o
ppi
2012/11/28 13:37:31
Sounds right, thanks.
In patch set 2 I use additi
| |
96 e.getMessage()); | 128 sLocalTrustManager.checkServerTrusted(serverCertificates, authTy pe); |
129 return true; | |
130 } | |
131 catch (CertificateException eInner) { | |
132 Log.i(TAG, "failed to validate the certificate chain, error: " + | |
133 eInner.getMessage()); | |
digit1
2012/11/28 10:42:34
Doesn't this lose the exception message from the d
ppi
2012/11/28 13:37:31
Thanks, n/a in patch set 2.
On 2012/11/28 10:42:3
| |
134 } | |
97 } | 135 } |
98 return false; | 136 return false; |
99 } | 137 } |
100 | 138 |
101 } | 139 } |
OLD | NEW |