Index: net/android/java/src/org/chromium/net/X509Util.java |
diff --git a/net/android/java/src/org/chromium/net/X509Util.java b/net/android/java/src/org/chromium/net/X509Util.java |
index 0c43b29b65e9bb860b5305d9a9dc357b940c4ad3..cbd4f4cf80f3a334bbc96aadb03708a49e539134 100644 |
--- a/net/android/java/src/org/chromium/net/X509Util.java |
+++ b/net/android/java/src/org/chromium/net/X509Util.java |
@@ -7,6 +7,7 @@ package org.chromium.net; |
import android.util.Log; |
import java.io.ByteArrayInputStream; |
+import java.io.IOException; |
import java.security.KeyStore; |
import java.security.KeyStoreException; |
import java.security.NoSuchAlgorithmException; |
@@ -25,37 +26,56 @@ public class X509Util { |
private static CertificateFactory sCertificateFactory; |
/** |
- * Default sources of authentication trust decisions and certificate object |
- * creation. |
+ * Trust manager backed up by the read-only system certificate store. |
*/ |
private static X509TrustManager sDefaultTrustManager; |
/** |
- * Ensures that |sCertificateFactory| and |sDefaultTrustManager| are |
- * initialized. |
+ * Trust manager backed up by a custom certificate store. We need such manager to plant test |
+ * root CA to the trust store in testing. |
*/ |
- private static synchronized void ensureInitialized() throws CertificateException, |
+ private static X509TrustManager sTestTrustManager; |
+ private static KeyStore sTestKeyStore; |
+ |
+ /** |
+ * Lock object used to synchronize all calls that modify or depend on the trust managers. |
+ */ |
+ private static final Object sLock = new Object(); |
+ |
+ /** |
+ * Ensures that the trust managers and certificate factory are initialized. |
+ */ |
+ private static void ensureInitialized() throws CertificateException, |
KeyStoreException, NoSuchAlgorithmException { |
- if (sCertificateFactory == null) { |
- sCertificateFactory = CertificateFactory.getInstance("X.509"); |
- } |
- if (sDefaultTrustManager == null) { |
- sDefaultTrustManager = X509Util.createDefaultTrustManager(); |
+ synchronized(sLock) { |
+ if (sCertificateFactory == null) { |
+ sCertificateFactory = CertificateFactory.getInstance("X.509"); |
+ } |
+ if (sDefaultTrustManager == null) { |
+ sDefaultTrustManager = X509Util.createTrustManager(null); |
+ } |
+ if (sTestKeyStore == null) { |
+ sTestKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); |
+ try { |
+ sTestKeyStore.load(null); |
+ } catch(IOException e) {} // No IO operation is attempted. |
+ } |
+ if (sTestTrustManager == null) { |
+ sTestTrustManager = X509Util.createTrustManager(sTestKeyStore); |
+ } |
} |
} |
/** |
- * Creates a TrustManagerFactory and returns the X509TrustManager instance |
- * if one can be found. |
- * |
- * @throws CertificateException,KeyStoreException,NoSuchAlgorithmException |
- * on error initializing the TrustManager. |
+ * Creates a X509TrustManager backed up by the given key store. When null is passed as a key |
+ * store, system default trust store is used. |
+ * @throws KeyStoreException, NoSuchAlgorithmException on error initializing the TrustManager. |
*/ |
- private static X509TrustManager createDefaultTrustManager() |
- throws KeyStoreException, NoSuchAlgorithmException { |
+ private static X509TrustManager createTrustManager(KeyStore keyStore) throws KeyStoreException, |
+ NoSuchAlgorithmException { |
String algorithm = TrustManagerFactory.getDefaultAlgorithm(); |
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); |
- tmf.init((KeyStore) null); |
+ tmf.init(keyStore); |
for (TrustManager tm : tmf.getTrustManagers()) { |
if (tm instanceof X509TrustManager) { |
@@ -66,7 +86,15 @@ public class X509Util { |
} |
/** |
- * Convert a DER encoded certificate to an X509Certificate |
+ * After each modification of test key store, trust manager has to be generated again. |
+ */ |
+ private static void reloadTestTrustManager() throws KeyStoreException, |
+ NoSuchAlgorithmException { |
+ sTestTrustManager = X509Util.createTrustManager(sTestKeyStore); |
+ } |
+ |
+ /** |
+ * Convert a DER encoded certificate to an X509Certificate. |
*/ |
public static X509Certificate createCertificateFromBytes(byte[] derBytes) throws |
CertificateException, KeyStoreException, NoSuchAlgorithmException { |
@@ -75,6 +103,28 @@ public class X509Util { |
new ByteArrayInputStream(derBytes)); |
} |
+ public static void addTestRootCertificate(byte[] rootCertBytes) throws CertificateException, |
+ KeyStoreException, NoSuchAlgorithmException { |
+ ensureInitialized(); |
+ X509Certificate rootCert = createCertificateFromBytes(rootCertBytes); |
+ synchronized(sLock) { |
+ sTestKeyStore.setCertificateEntry( |
+ "root_cert_" + Integer.toString(sTestKeyStore.size()), rootCert); |
+ reloadTestTrustManager(); |
+ } |
+ } |
+ |
+ public static void clearTestRootCertificates() throws NoSuchAlgorithmException, |
+ CertificateException, KeyStoreException { |
+ ensureInitialized(); |
+ synchronized(sLock) { |
+ try { |
+ sTestKeyStore.load(null); |
+ reloadTestTrustManager(); |
+ } catch(IOException e) {} // No IO operation is attempted. |
+ } |
+ } |
+ |
public static boolean verifyServerCertificates(byte[][] certChain, String authType) |
throws CertificateException, KeyStoreException, NoSuchAlgorithmException { |
if (certChain == null || certChain.length == 0 || certChain[0] == null) { |
@@ -88,14 +138,24 @@ public class X509Util { |
serverCertificates[i] = createCertificateFromBytes(certChain[i]); |
} |
- try { |
- sDefaultTrustManager.checkServerTrusted(serverCertificates, authType); |
- return true; |
- } catch (CertificateException e) { |
- Log.i(TAG, "failed to validate the certificate chain, error: " + |
- e.getMessage()); |
+ synchronized (sLock) { |
+ try { |
+ sDefaultTrustManager.checkServerTrusted(serverCertificates, authType); |
+ return true; |
+ } catch (CertificateException eDefaultManager) { |
+ try { |
+ sTestTrustManager.checkServerTrusted(serverCertificates, authType); |
+ return true; |
+ } catch (CertificateException eTestManager) { |
+ /* |
+ * Neither of the trust managers confirms the validity of the certificate |
+ * chain, we emit the error message returned by the system trust manager. |
+ */ |
+ Log.i(TAG, "failed to validate the certificate chain, error: " + |
+ eDefaultManager.getMessage()); |
+ } |
+ } |
} |
return false; |
} |
- |
-} |
+} |