| 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;
|
| }
|
| -
|
| -}
|
| +}
|
|
|