Skip to content

Commit

Permalink
Upstream certificate and mime Android implementation.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
michaelbai@google.com committed Aug 11, 2011
1 parent b20c447 commit 6dbdaa8
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 0 deletions.
1 change: 1 addition & 0 deletions net/DEPS
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include_rules = [
"+crypto",
"+jni",
"+third_party/apple_apsl",
"+third_party/libevent",
"+third_party/nss",
Expand Down
109 changes: 109 additions & 0 deletions net/android/network_library.cc
Original file line number Diff line number Diff line change
@@ -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


58 changes: 58 additions & 0 deletions net/android/network_library.h
Original file line number Diff line number Diff line change
@@ -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_
71 changes: 71 additions & 0 deletions net/base/openssl_private_key_store_android.cc
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions net/base/platform_mime_util_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -39,6 +54,8 @@ bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension(
return true;
}

#endif // defined(OS_ANDROID)

struct MimeToExt {
const char* mime_type;
const char* ext;
Expand Down
6 changes: 6 additions & 0 deletions net/base/x509_certificate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions net/base/x509_certificate_openssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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))
Expand Down
63 changes: 63 additions & 0 deletions net/base/x509_certificate_openssl_android.cc
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 6dbdaa8

Please sign in to comment.