diff options
author | michaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-11 16:05:56 +0000 |
---|---|---|
committer | michaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-11 16:05:56 +0000 |
commit | 6dbdaa892d120c6fbb1355aeb0ba8810dad12840 (patch) | |
tree | 59b446fad4cccc144953888d0c2861d44782458b /net | |
parent | b20c447c5d17bb563498c710445627ae4bfb6137 (diff) | |
download | chromium_src-6dbdaa892d120c6fbb1355aeb0ba8810dad12840.zip chromium_src-6dbdaa892d120c6fbb1355aeb0ba8810dad12840.tar.gz chromium_src-6dbdaa892d120c6fbb1355aeb0ba8810dad12840.tar.bz2 |
Upstream certificate and mime Android implementation.
BUG=
TEST=
Review URL: http://codereview.chromium.org/7538029
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96401 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/DEPS | 1 | ||||
-rw-r--r-- | net/android/network_library.cc | 109 | ||||
-rw-r--r-- | net/android/network_library.h | 58 | ||||
-rw-r--r-- | net/base/openssl_private_key_store_android.cc | 71 | ||||
-rw-r--r-- | net/base/platform_mime_util_linux.cc | 17 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 6 | ||||
-rw-r--r-- | net/base/x509_certificate_openssl.cc | 4 | ||||
-rw-r--r-- | net/base/x509_certificate_openssl_android.cc | 63 |
8 files changed, 329 insertions, 0 deletions
@@ -1,5 +1,6 @@ include_rules = [ "+crypto", + "+jni", "+third_party/apple_apsl", "+third_party/libevent", "+third_party/nss", diff --git a/net/android/network_library.cc b/net/android/network_library.cc new file mode 100644 index 0000000..6fbcd30 --- /dev/null +++ b/net/android/network_library.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2010 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. + +#include "net/android/network_library.h" + +#include "base/android/auto_jobject.h" +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/logging.h" +#include "jni/android_network_library_jni.h" + +using base::android::AttachCurrentThread; +using base::android::AutoJObject; +using base::android::CheckException; +using base::android::ConvertJavaStringToUTF8; +using base::android::ConvertUTF8ToJavaString; +using base::android::GetApplicationContext; +using base::android::ToJavaArrayOfByteArray; +using base::android::ToJavaByteArray; + +namespace net { +namespace android { + +VerifyResult VerifyX509CertChain(const std::vector<std::string>& cert_chain, + const std::string& hostname, + const std::string& auth_type) { + JNIEnv* env = AttachCurrentThread(); + if (!env) { + // TODO(husky): Maybe initialize the JVM in unit tests? + LOG(WARNING) << "JNI initialization failed"; + return VERIFY_INVOCATION_ERROR; + } + + AutoJObject chain_byte_array = AutoJObject::FromLocalRef( + env, ToJavaArrayOfByteArray(env, cert_chain)); + DCHECK(chain_byte_array.obj()); + + AutoJObject host_string = AutoJObject::FromLocalRef( + env, ConvertUTF8ToJavaString(env, hostname)); + DCHECK(host_string.obj()); + + AutoJObject auth_string = AutoJObject::FromLocalRef( + env, ConvertUTF8ToJavaString(env, auth_type)); + DCHECK(auth_string.obj()); + + jint error = Java_AndroidNetworkLibrary_verifyServerCertificates( + env, static_cast<jobjectArray>(chain_byte_array.obj()), + static_cast<jstring>(host_string.obj()), + static_cast<jstring>(auth_string.obj())); + + switch (error) { + case 0: + return VERIFY_OK; + case 1: + return VERIFY_BAD_HOSTNAME; + case 2: + return VERIFY_NO_TRUSTED_ROOT; + } + return VERIFY_INVOCATION_ERROR; +} + +bool StoreKeyPair(const uint8* public_key, + size_t public_len, + const uint8* private_key, + size_t private_len) { + JNIEnv* env = AttachCurrentThread(); + AutoJObject public_array = AutoJObject::FromLocalRef( + env, ToJavaByteArray(env, public_key, public_len)); + AutoJObject private_array = AutoJObject::FromLocalRef( + env, ToJavaByteArray(env, private_key, private_len)); + jboolean ret = Java_AndroidNetworkLibrary_storeKeyPair(env, + GetApplicationContext(), + static_cast<jbyteArray>(public_array.obj()), + static_cast<jbyteArray>(private_array.obj())); + if (CheckException(env) || !ret) { + LOG(WARNING) << "Call to Java_AndroidNetworkLibrary_storeKeyPair failed"; + return false; + } + return true; +} + +bool GetMimeTypeFromExtension(const std::string& extension, + std::string* result) { + JNIEnv* env = AttachCurrentThread(); + + AutoJObject extension_string = AutoJObject::FromLocalRef( + env, ConvertUTF8ToJavaString(env, extension)); + AutoJObject ret = AutoJObject::FromLocalRef( + env, Java_AndroidNetworkLibrary_getMimeTypeFromExtension( + env, static_cast<jstring>(extension_string.obj()))); + + if (CheckException(env) || !ret.obj()) { + LOG(WARNING) << "Call to getMimeTypeFromExtension failed"; + return false; + } + *result = ConvertJavaStringToUTF8(env, static_cast<jstring>(ret.obj())); + return true; +} + +bool RegisterNetworkLibrary(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace net + + diff --git a/net/android/network_library.h b/net/android/network_library.h new file mode 100644 index 0000000..0694de6 --- /dev/null +++ b/net/android/network_library.h @@ -0,0 +1,58 @@ +// Copyright (c) 2010 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_NETWORK_LIBRARY_H_ +#define NET_ANDROID_NETWORK_LIBRARY_H_ +#pragma once + +#include <jni.h> + +#include <string> +#include <vector> + +#include "base/basictypes.h" + +namespace net { +namespace android { + +enum VerifyResult { + // Certificate verification was successful. + VERIFY_OK, + // Certificate domain name doesn't match host name. + VERIFY_BAD_HOSTNAME, + // 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. +// |hostname| is validated against the supplied cert. |auth_type| is as per +// the Java X509Certificate.checkServerTrusted method. + +VerifyResult VerifyX509CertChain(const std::vector<std::string>& cert_chain, + const std::string& hostname, + const std::string& auth_type); + +// Helper for the <keygen> handler. Passes the DER-encoded key pair via +// JNI to the Credentials store. +bool StoreKeyPair(const uint8* public_key, + size_t public_len, + const uint8* private_key, + size_t private_len); + +// Get the mime type (if any) that is associated with the file extension. +// Returns true if a corresponding mime type exists. +bool GetMimeTypeFromExtension(const std::string& extension, + std::string* result); + +// Register JNI methods +bool RegisterNetworkLibrary(JNIEnv* env); + +} // namespace android +} // namespace net + +#endif // NET_ANDROID_NETWORK_LIBRARY_H_ diff --git a/net/base/openssl_private_key_store_android.cc b/net/base/openssl_private_key_store_android.cc new file mode 100644 index 0000000..6349ecc --- /dev/null +++ b/net/base/openssl_private_key_store_android.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2010 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. + +#include "net/base/openssl_private_key_store.h" + +#include <openssl/evp.h> + +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "crypto/openssl_util.h" +#include "net/android/network_library.h" + +namespace net { + +namespace { + +class OpenSSLKeyStoreAndroid : public OpenSSLPrivateKeyStore { + public: + ~OpenSSLKeyStoreAndroid() {} + + // TODO(joth): Use the |url| to help identify this key to the user. + // Currently Android has no UI to list these stored private keys (and no + // API to associate a name with them), so this is a non-issue. + virtual bool StorePrivateKey(const GURL& url, EVP_PKEY* pkey) { + uint8* public_key = NULL; + int public_len = i2d_PublicKey(pkey, &public_key); + uint8* private_key = NULL; + int private_len = i2d_PrivateKey(pkey, &private_key); + + bool ret = false; + if (public_len && private_len) { + ret = net::android::StoreKeyPair(public_key, public_len, private_key, + private_len); + } + LOG_IF(ERROR, !ret) << "StorePrivateKey failed. pub len = " << public_len + << " priv len = " << private_len; + OPENSSL_free(public_key); + OPENSSL_free(private_key); + return ret; + } + + virtual EVP_PKEY* FetchPrivateKey(EVP_PKEY* pkey) { + // TODO(joth): Implement when client authentication is required. + NOTIMPLEMENTED(); + return NULL; + } + + static OpenSSLKeyStoreAndroid* GetInstance(); + + private: + OpenSSLKeyStoreAndroid() {} + friend struct DefaultSingletonTraits<OpenSSLKeyStoreAndroid>; + + DISALLOW_COPY_AND_ASSIGN(OpenSSLKeyStoreAndroid); +}; + +} // namespace + +// static +OpenSSLKeyStoreAndroid* OpenSSLKeyStoreAndroid::GetInstance() { + return Singleton<OpenSSLKeyStoreAndroid>::get(); +} + +#if 0 +// TODO(MERGE): Conflict with openssl_memory_private_key_store.cc +OpenSSLPrivateKeyStore* OpenSSLPrivateKeyStore::GetInstance() { + return OpenSSLKeyStoreAndroid::GetInstance(); +} +#endif +} // namespace net diff --git a/net/base/platform_mime_util_linux.cc b/net/base/platform_mime_util_linux.cc index 8892668..19b315c 100644 --- a/net/base/platform_mime_util_linux.cc +++ b/net/base/platform_mime_util_linux.cc @@ -6,10 +6,25 @@ #include <string> +#include "build/build_config.h" + +#if defined(OS_ANDROID) +#include "net/android/network_library.h" +#else #include "base/mime_util.h" +#endif namespace net { +#if defined(OS_ANDROID) + +bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension( + const FilePath::StringType& ext, std::string* result) const { + return android::GetMimeTypeFromExtension(ext, result); +} + +#else + bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension( const FilePath::StringType& ext, std::string* result) const { // TODO(thestig) This is a temporary hack until we can fix this @@ -39,6 +54,8 @@ bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension( return true; } +#endif // defined(OS_ANDROID) + struct MimeToExt { const char* mime_type; const char* ext; diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index ca2abec..4ef8003 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -295,6 +295,12 @@ class NET_API X509Certificate static HCERTSTORE cert_store(); #endif +#if defined(OS_ANDROID) + // |chain_bytes| will contain the chain (including this certificate) encoded + // using GetChainDEREncodedBytes below. + void GetChainDEREncodedBytes(std::vector<std::string>* chain_bytes) const; +#endif + #if defined(USE_OPENSSL) // Returns a handle to a global, in-memory certificate store. We // use it for test code, e.g. importing the test server's certificate. diff --git a/net/base/x509_certificate_openssl.cc b/net/base/x509_certificate_openssl.cc index 68fcf91..f23ede9 100644 --- a/net/base/x509_certificate_openssl.cc +++ b/net/base/x509_certificate_openssl.cc @@ -425,6 +425,8 @@ X509_STORE* X509Certificate::cert_store() { return X509InitSingleton::GetInstance()->store(); } +#if !defined(OS_ANDROID) + int X509Certificate::VerifyInternal(const std::string& hostname, int flags, CertVerifyResult* verify_result) const { @@ -504,6 +506,8 @@ int X509Certificate::VerifyInternal(const std::string& hostname, return OK; } +#endif // !defined(OS_ANDROID) + bool X509Certificate::GetDEREncoded(std::string* encoded) { DERCache der_cache; if (!GetDERAndCacheIfNeeded(cert_handle_, &der_cache)) diff --git a/net/base/x509_certificate_openssl_android.cc b/net/base/x509_certificate_openssl_android.cc new file mode 100644 index 0000000..4e1bbd2 --- /dev/null +++ b/net/base/x509_certificate_openssl_android.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2010 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. + +#include "net/base/x509_certificate.h" + +#include "base/logging.h" +#include "net/android/network_library.h" +#include "net/base/cert_status_flags.h" +#include "net/base/cert_verify_result.h" +#include "net/base/net_errors.h" + +namespace net { + +int X509Certificate::VerifyInternal(const std::string& hostname, + int flags, + CertVerifyResult* verify_result) const { + if (!VerifyNameMatch(hostname)) + verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; + + std::vector<std::string> cert_bytes; + GetChainDEREncodedBytes(&cert_bytes); + + // TODO(joth): Fetch the authentication type from SSL rather than hardcode. + android::VerifyResult result = + android::VerifyX509CertChain(cert_bytes, hostname, "RSA"); + switch (result) { + case android::VERIFY_OK: + return OK; + case android::VERIFY_BAD_HOSTNAME: + verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; + break; + case android::VERIFY_NO_TRUSTED_ROOT: + verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; + break; + case android::VERIFY_INVOCATION_ERROR: + default: + verify_result->cert_status |= ERR_CERT_INVALID; + break; + } + return MapCertStatusToNetError(verify_result->cert_status); +} + +void X509Certificate::GetChainDEREncodedBytes( + std::vector<std::string>* chain_bytes) const { + OSCertHandles cert_handles(intermediate_ca_certs_); + // Make sure the peer's own cert is the first in the chain, if it's not + // already there. + if (cert_handles.empty()) + cert_handles.insert(cert_handles.begin(), cert_handle_); + + chain_bytes->reserve(cert_handles.size()); + for (OSCertHandles::const_iterator it = cert_handles.begin(); + it != cert_handles.end(); ++it) { + DERCache der_cache = {0}; + GetDERAndCacheIfNeeded(*it, &der_cache); + std::string cert_bytes ( + reinterpret_cast<const char*>(der_cache.data), der_cache.data_length); + chain_bytes->push_back(cert_bytes); + } +} + +} // namespace net |