From 3b45550dbaca21fc86d6fa79f1e061d6e8090f85 Mon Sep 17 00:00:00 2001 From: "digit@chromium.org" Date: Tue, 11 Dec 2012 18:22:58 +0000 Subject: Fix certificate and keychain installation on Android. This patch is necessary to allow Chrome on Android to properly install CA certificates and PKCS#12 keychains. This feature is not supported on other platforms, but necessary on mobile. It does modify the content client API to deal with the new file types, i.e. the AddNewCertificate() method is renamed AddCryptoFile(), and its signature changed to receive the file data directly (along with a file type enum). It is now the reponsability of the browser / content embedder to perform certificate verification. More specifically: - Modify net/base/mime_util.h to provide two new functions: * IsSupportedCertificateMimeType(), which returns true iff a mime type corresponds to a supported crypto file (only "application/x-x509-user-cert" is supported, except on Android, which adds ".../x-x509-ca-cert" and ".../x-pkcs12"). * GetCertificateMimeTypeForMimeType() which translates a mime type string into an enum value that is also understood from Java (see below), describing the type of file. Note that "net/base/mime_util_certificate_list.h" is used to hold the list of certificate mime type constants, both for C++ and Java (i.e. it is used to auto-generate org.chromium.net.CertificateMimeType.java at build time, under out/$BUILDTYPE/gen/template/). - Rename X509UserCertResourceHandler to CertificateResourceHandler under content/browser/loader/ in order to deal with all certificate mime types. Modify buffered_resource_handler.cc appropriately. - Add net::android::StoreCertificate(), and the Java org.chromium.net.AndroidNetworkLibrary.storeCertificate() method to send the certificate data for installation through the system's CertInstaller activity. - Add chrome::SSLAddCertificate() to implement the platform-specific code that used to be in content::ContentBrowserClient::AddNewCertificate(). - Rename content::ContentBrowserClient::AddNewCertificate() to ::AddCertificate(), and change its signature to accept resource file bytes directly and a net::CertificateMimeType (was an X509Certificate pointer). This change shall not modify the behaviour of Chromium on other platforms. BUG=149306 TEST=Manual test with ChromiumTestShell, see internal b/6668254 for details. Review URL: https://chromiumcodereview.appspot.com/11266008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@172350 0039d316-1c4b-4281-b951-d872f2087c98 --- net/android/java/CertificateMimeType.template | 11 ++++++ .../org/chromium/net/AndroidNetworkLibrary.java | 42 ++++++++++++++++++++++ net/android/network_library.cc | 16 +++++++++ net/android/network_library.h | 7 ++++ 4 files changed, 76 insertions(+) create mode 100644 net/android/java/CertificateMimeType.template (limited to 'net/android') diff --git a/net/android/java/CertificateMimeType.template b/net/android/java/CertificateMimeType.template new file mode 100644 index 0000000..5a21171 --- /dev/null +++ b/net/android/java/CertificateMimeType.template @@ -0,0 +1,11 @@ +// Copyright (c) 2012 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 CertificateMimeType { +#define CERTIFICATE_MIME_TYPE(name, value) public static final int name = value; +#include "net/base/mime_util_certificate_type_list.h" +#undef CERTIFICATE_MIME_TYPE +} diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java index ff05ec8..73225bd 100644 --- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java +++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java @@ -10,6 +10,7 @@ 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; @@ -61,6 +62,47 @@ class AndroidNetworkLibrary { } /** + * Adds a cryptographic file (User certificate, a CA certificate or + * 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 data: certificate/keychain data bytes. + * @return true on success, false on failure. + * + * Note that failure only indicates that the function couldn't launch the + * CertInstaller activity, not that the certificate/keychain was properly + * installed to the keystore. + */ + @CalledByNative + static public boolean storeCertificate(Context context, int cert_type, byte[] data) { + try { + Intent intent = KeyChain.createInstallIntent(); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + switch (cert_type) { + case CertificateMimeType.X509_USER_CERT: + case CertificateMimeType.X509_CA_CERT: + intent.putExtra(KeyChain.EXTRA_CERTIFICATE, data); + break; + + case CertificateMimeType.PKCS12_ARCHIVE: + intent.putExtra(KeyChain.EXTRA_PKCS12, data); + break; + + default: + Log.w(TAG, "invalid certificate type: " + cert_type); + return false; + } + context.startActivity(intent); + return true; + } catch (ActivityNotFoundException e) { + Log.w(TAG, "could not store crypto file: " + e); + } + return false; + } + + /** * @return the mime type (if any) that is associated with the file * extension. Returns null if no corresponding mime type exists. */ diff --git a/net/android/network_library.cc b/net/android/network_library.cc index b53cefe..ed538a2 100644 --- a/net/android/network_library.cc +++ b/net/android/network_library.cc @@ -59,6 +59,22 @@ bool StoreKeyPair(const uint8* public_key, return ret; } +void StoreCertificate(net::CertificateMimeType cert_type, + const void* data, + size_t data_len) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef data_array = + ToJavaByteArray(env, reinterpret_cast(data), data_len); + jboolean ret = Java_AndroidNetworkLibrary_storeCertificate(env, + GetApplicationContext(), cert_type, data_array.obj()); + LOG_IF(WARNING, !ret) << + "Call to Java_AndroidNetworkLibrary_storeCertificate" + " failed"; + // Intentionally do not return 'ret', there is little the caller can + // do in case of failure (the CertInstaller itself will deal with + // incorrect data and display the appropriate toast). +} + bool HaveOnlyLoopbackAddresses() { JNIEnv* env = AttachCurrentThread(); return Java_AndroidNetworkLibrary_haveOnlyLoopbackAddresses(env); diff --git a/net/android/network_library.h b/net/android/network_library.h index c505202..955603d 100644 --- a/net/android/network_library.h +++ b/net/android/network_library.h @@ -11,6 +11,7 @@ #include #include "base/basictypes.h" +#include "net/base/mime_util.h" #include "net/base/net_export.h" namespace net { @@ -47,6 +48,12 @@ bool StoreKeyPair(const uint8* public_key, const uint8* private_key, size_t private_len); +// Helper used to pass the DER-encoded bytes of an X.509 certificate or +// a PKCS#12 archive holding a private key to the CertInstaller activity. +void StoreCertificate(net::CertificateMimeType cert_type, + const void* data, + size_t data_len); + // Returns true if it can determine that only loopback addresses are configured. // i.e. if only 127.0.0.1 and ::1 are routable. // Also returns false if it cannot determine this. -- cgit v1.1