diff options
author | ppi@chromium.org <ppi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-13 19:13:49 +0000 |
---|---|---|
committer | ppi@chromium.org <ppi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-13 19:13:49 +0000 |
commit | 71f4b2782acf7b0608bb596f1d980afe26255254 (patch) | |
tree | 35859c98136212a257d70808ed11666082380396 /net/android | |
parent | 3f83628a86e6be3dd2bf90a441477e9ab7fb2f9f (diff) | |
download | chromium_src-71f4b2782acf7b0608bb596f1d980afe26255254.zip chromium_src-71f4b2782acf7b0608bb596f1d980afe26255254.tar.gz chromium_src-71f4b2782acf7b0608bb596f1d980afe26255254.tar.bz2 |
Return specific cert verification errors on Android
To implement CertVerifyProc on Android we refer to the Java
side to query the platform trust managers. Currently the
information we get from the platform is binary - each
certificate chain is either identified as trusted or not, in
which case we assume that this is due to not-trusted root.
This patch provides better granularity distinguishing the
following cases: expired, not yet valid, incorrect (could not
be parsed), not trusted root.
This allowed to reenable two net unittests:
- CertVerifyProcTest.ExtraneousMD5RootCert
- CertVerifyProcTest.IntermediateCARequireExplicitPolicy
The following net unittest had to be disabled as it joins
the club of CertVerifyProc tests failing on bots with
incorrect time/date settings:
- CertVerifyProcTest.InvalidKeyUsage
BUG=169762
Review URL: https://chromiumcodereview.appspot.com/12212135
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182280 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/android')
-rw-r--r-- | net/android/cert_verify_result_android.h | 26 | ||||
-rw-r--r-- | net/android/cert_verify_result_android_list.h | 27 | ||||
-rw-r--r-- | net/android/java/CertVerifyResultAndroid.template | 10 | ||||
-rw-r--r-- | net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java | 25 | ||||
-rw-r--r-- | net/android/java/src/org/chromium/net/X509Util.java | 59 | ||||
-rw-r--r-- | net/android/network_library.cc | 11 | ||||
-rw-r--r-- | net/android/network_library.h | 17 |
7 files changed, 127 insertions, 48 deletions
diff --git a/net/android/cert_verify_result_android.h b/net/android/cert_verify_result_android.h new file mode 100644 index 0000000..ac18c21 --- /dev/null +++ b/net/android/cert_verify_result_android.h @@ -0,0 +1,26 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_ANDROID_CERT_VERIFY_RESULT_ANDROID_H_ +#define NET_ANDROID_CERT_VERIFY_RESULT_ANDROID_H_ + +#include "base/basictypes.h" +#include "base/platform_file.h" +#include "net/base/net_export.h" + +namespace net { + +namespace android { + +enum CertVerifyResultAndroid { +#define CERT_VERIFY_RESULT_ANDROID(label, value) VERIFY_ ## label = value, +#include "net/android/cert_verify_result_android_list.h" +#undef CERT_VERIFY_RESULT_ANDROID +}; + +} // namespace android + +} // namespace net + +#endif // NET_ANDROID_CERT_VERIFY_RESULT_ANDROID_H_ diff --git a/net/android/cert_verify_result_android_list.h b/net/android/cert_verify_result_android_list.h new file mode 100644 index 0000000..201ea5a --- /dev/null +++ b/net/android/cert_verify_result_android_list.h @@ -0,0 +1,27 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file intentionally does not have header guards, it's included +// inside a macro to generate enum. + +// This file contains the list of certificate verification results returned +// from Java side to the C++ side. + +// Certificate is trusted. +CERT_VERIFY_RESULT_ANDROID(OK, 0) + +// Certificate verification could not be conducted. +CERT_VERIFY_RESULT_ANDROID(FAILED, -1) + +// Certificate is not trusted due to non-trusted root of the certificate chain. +CERT_VERIFY_RESULT_ANDROID(NO_TRUSTED_ROOT, -2) + +// Certificate is not trusted because it has expired. +CERT_VERIFY_RESULT_ANDROID(EXPIRED, -3) + +// Certificate is not trusted because it is not valid yet. +CERT_VERIFY_RESULT_ANDROID(NOT_YET_VALID, -4) + +// Certificate is not trusted because it could not be parsed. +CERT_VERIFY_RESULT_ANDROID(UNABLE_TO_PARSE, -5) diff --git a/net/android/java/CertVerifyResultAndroid.template b/net/android/java/CertVerifyResultAndroid.template new file mode 100644 index 0000000..b19e937 --- /dev/null +++ b/net/android/java/CertVerifyResultAndroid.template @@ -0,0 +1,10 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.net; + +public class CertVerifyResultAndroid { +#define CERT_VERIFY_RESULT_ANDROID(name, value) public static final int VERIFY_##name = value; +#include "net/android/cert_verify_result_android_list.h" +} diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java index 69a5722..a075685 100644 --- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java +++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java @@ -10,9 +10,10 @@ import android.content.Intent; import android.security.KeyChain; import android.util.Log; -import org.chromium.net.CertificateMimeType; import org.chromium.base.CalledByNative; import org.chromium.base.CalledByNativeUnchecked; +import org.chromium.net.CertVerifyResultAndroid; +import org.chromium.net.CertificateMimeType; import java.net.Inet6Address; import java.net.InetAddress; @@ -66,7 +67,7 @@ class AndroidNetworkLibrary { * PKCS#12 keychain) through the system's CertInstaller activity. * * @param context: current application context. - * @param file_type: cryptographic file type. E.g. CertificateMimeType.X509_USER_CERT + * @param cert_type: cryptographic file type. E.g. CertificateMimeType.X509_USER_CERT * @param data: certificate/keychain data bytes. * @return true on success, false on failure. * @@ -196,15 +197,17 @@ class AndroidNetworkLibrary { * * @param certChain The ASN.1 DER encoded bytes for certificates. * @param authType The key exchange algorithm name (e.g. RSA) - * @return true if the server is trusted - * @throws CertificateException,KeyStoreException,NoSuchAlgorithmException - * on error initializing the TrustManager or reading the - * certChain + * @return Android certificate verification result code. */ - @CalledByNativeUnchecked - public static boolean verifyServerCertificates(byte[][] certChain, String authType) - throws CertificateException, KeyStoreException, NoSuchAlgorithmException { - return X509Util.verifyServerCertificates(certChain, authType); + @CalledByNative + public static int verifyServerCertificates(byte[][] certChain, String authType) { + try { + return X509Util.verifyServerCertificates(certChain, authType); + } catch (KeyStoreException e) { + return CertVerifyResultAndroid.VERIFY_FAILED; + } catch (NoSuchAlgorithmException e) { + return CertVerifyResultAndroid.VERIFY_FAILED; + } } /** @@ -226,4 +229,4 @@ class AndroidNetworkLibrary { CertificateException, KeyStoreException { X509Util.clearTestRootCertificates(); } -}
\ No newline at end of file +} diff --git a/net/android/java/src/org/chromium/net/X509Util.java b/net/android/java/src/org/chromium/net/X509Util.java index cbd4f4cf..6bbf171 100644 --- a/net/android/java/src/org/chromium/net/X509Util.java +++ b/net/android/java/src/org/chromium/net/X509Util.java @@ -6,12 +6,16 @@ package org.chromium.net; import android.util.Log; +import org.chromium.net.CertVerifyResultAndroid; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -107,7 +111,7 @@ public class X509Util { KeyStoreException, NoSuchAlgorithmException { ensureInitialized(); X509Certificate rootCert = createCertificateFromBytes(rootCertBytes); - synchronized(sLock) { + synchronized (sLock) { sTestKeyStore.setCertificateEntry( "root_cert_" + Integer.toString(sTestKeyStore.size()), rootCert); reloadTestTrustManager(); @@ -117,45 +121,64 @@ public class X509Util { public static void clearTestRootCertificates() throws NoSuchAlgorithmException, CertificateException, KeyStoreException { ensureInitialized(); - synchronized(sLock) { + synchronized (sLock) { try { sTestKeyStore.load(null); reloadTestTrustManager(); - } catch(IOException e) {} // No IO operation is attempted. + } catch (IOException e) {} // No IO operation is attempted. } } - public static boolean verifyServerCertificates(byte[][] certChain, String authType) - throws CertificateException, KeyStoreException, NoSuchAlgorithmException { + public static int verifyServerCertificates(byte[][] certChain, String authType) + throws KeyStoreException, NoSuchAlgorithmException { if (certChain == null || certChain.length == 0 || certChain[0] == null) { throw new IllegalArgumentException("Expected non-null and non-empty certificate " + "chain passed as |certChain|. |certChain|=" + certChain); } - ensureInitialized(); + try { + ensureInitialized(); + } catch (CertificateException e) { + return CertVerifyResultAndroid.VERIFY_FAILED; + } + X509Certificate[] serverCertificates = new X509Certificate[certChain.length]; - for (int i = 0; i < certChain.length; ++i) { - serverCertificates[i] = createCertificateFromBytes(certChain[i]); + try { + for (int i = 0; i < certChain.length; ++i) { + serverCertificates[i] = createCertificateFromBytes(certChain[i]); + } + } catch (CertificateException e) { + return CertVerifyResultAndroid.VERIFY_UNABLE_TO_PARSE; + } + + // Expired and not yet valid certificates would be rejected by the trust managers, but the + // trust managers report all certificate errors using the general CertificateException. In + // order to get more granular error information, cert validity time range is being checked + // separately. + try { + serverCertificates[0].checkValidity(); + } catch (CertificateExpiredException e) { + return CertVerifyResultAndroid.VERIFY_EXPIRED; + } catch (CertificateNotYetValidException e) { + return CertVerifyResultAndroid.VERIFY_NOT_YET_VALID; } synchronized (sLock) { try { sDefaultTrustManager.checkServerTrusted(serverCertificates, authType); - return true; + return CertVerifyResultAndroid.VERIFY_OK; } catch (CertificateException eDefaultManager) { try { sTestTrustManager.checkServerTrusted(serverCertificates, authType); - return true; + return CertVerifyResultAndroid.VERIFY_OK; } 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()); + // Neither of the trust managers confirms the validity of the certificate chain, + // log the error message returned by the system trust manager. + Log.i(TAG, "Failed to validate the certificate chain, error: " + + eDefaultManager.getMessage()); + return CertVerifyResultAndroid.VERIFY_NO_TRUSTED_ROOT; } } } - return false; } -}
\ No newline at end of file +} diff --git a/net/android/network_library.cc b/net/android/network_library.cc index c1c4d5d..2407100 100644 --- a/net/android/network_library.cc +++ b/net/android/network_library.cc @@ -23,8 +23,9 @@ using base::android::ToJavaByteArray; namespace net { namespace android { -VerifyResult VerifyX509CertChain(const std::vector<std::string>& cert_chain, - const std::string& auth_type) { +CertVerifyResultAndroid VerifyX509CertChain( + const std::vector<std::string>& cert_chain, + const std::string& auth_type) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobjectArray> chain_byte_array = @@ -35,12 +36,10 @@ VerifyResult VerifyX509CertChain(const std::vector<std::string>& cert_chain, ConvertUTF8ToJavaString(env, auth_type); DCHECK(!auth_string.is_null()); - jboolean trusted = Java_AndroidNetworkLibrary_verifyServerCertificates( + jint result = Java_AndroidNetworkLibrary_verifyServerCertificates( env, chain_byte_array.obj(), auth_string.obj()); - if (ClearException(env)) - return VERIFY_INVOCATION_ERROR; - return trusted ? VERIFY_OK : VERIFY_NO_TRUSTED_ROOT; + return static_cast<CertVerifyResultAndroid>(result); } void AddTestRootCertificate(const uint8* cert, size_t len) { diff --git a/net/android/network_library.h b/net/android/network_library.h index 9db3e0e..451834e 100644 --- a/net/android/network_library.h +++ b/net/android/network_library.h @@ -11,28 +11,19 @@ #include <vector> #include "base/basictypes.h" +#include "net/android/cert_verify_result_android.h" #include "net/base/mime_util.h" #include "net/base/net_export.h" namespace net { namespace android { -enum VerifyResult { - // Certificate verification was successful. - VERIFY_OK, - // Certificate verification was failed. There is no detail error information - // given by Android API. - VERIFY_NO_TRUSTED_ROOT, - // Error occurs when invoke JNI methods. - VERIFY_INVOCATION_ERROR, -}; - // |cert_chain| is DER encoded chain of certificates, with the server's own // certificate listed first. // |auth_type| is as per the Java X509Certificate.checkServerTrusted method. - -VerifyResult VerifyX509CertChain(const std::vector<std::string>& cert_chain, - const std::string& auth_type); +CertVerifyResultAndroid VerifyX509CertChain( + const std::vector<std::string>& cert_chain, + const std::string& auth_type); // Adds a certificate as a root trust certificate to the trust manager. // |cert| is DER encoded certificate, |len| is its length in bytes. |