diff options
| author | digit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-11 18:22:58 +0000 | 
|---|---|---|
| committer | digit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-11 18:22:58 +0000 | 
| commit | 3b45550dbaca21fc86d6fa79f1e061d6e8090f85 (patch) | |
| tree | 0b0a4ca0a8526ecdb04f288158f88e7e9744de60 | |
| parent | 0f613db3a659bba8cc7b4b9f1df228cc9fb2fdea (diff) | |
| download | chromium_src-3b45550dbaca21fc86d6fa79f1e061d6e8090f85.zip chromium_src-3b45550dbaca21fc86d6fa79f1e061d6e8090f85.tar.gz chromium_src-3b45550dbaca21fc86d6fa79f1e061d6e8090f85.tar.bz2 | |
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
22 files changed, 412 insertions, 74 deletions
| diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 2850fef3..6c4f0b3 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -63,7 +63,7 @@  #include "chrome/browser/search_engines/search_provider_install_state_message_filter.h"  #include "chrome/browser/speech/chrome_speech_recognition_manager_delegate.h"  #include "chrome/browser/spellchecker/spellcheck_message_filter.h" -#include "chrome/browser/ssl/ssl_add_cert_handler.h" +#include "chrome/browser/ssl/ssl_add_certificate.h"  #include "chrome/browser/ssl/ssl_blocking_page.h"  #include "chrome/browser/ssl/ssl_tab_helper.h"  #include "chrome/browser/tab_contents/tab_util.h" @@ -105,6 +105,7 @@  #include "grit/generated_resources.h"  #include "grit/ui_resources.h"  #include "net/base/escape.h" +#include "net/base/mime_util.h"  #include "net/base/ssl_cert_request_info.h"  #include "net/cookies/canonical_cookie.h"  #include "net/cookies/cookie_options.h" @@ -1327,13 +1328,15 @@ void ChromeContentBrowserClient::SelectClientCertificate(        network_session, cert_request_info, callback);  } -void ChromeContentBrowserClient::AddNewCertificate( +void ChromeContentBrowserClient::AddCertificate(      net::URLRequest* request, -    net::X509Certificate* cert, +    net::CertificateMimeType cert_type, +    const void* cert_data, +    size_t cert_size,      int render_process_id,      int render_view_id) { -  // The handler will run the UI and delete itself when it's finished. -  new SSLAddCertHandler(request, cert, render_process_id, render_view_id); +  chrome::SSLAddCertificate(request, cert_type, cert_data, cert_size, +      render_process_id, render_view_id);  }  content::MediaObserver* ChromeContentBrowserClient::GetMediaObserver() { diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 53a89f3..973ea17 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h @@ -152,9 +152,11 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {        const net::HttpNetworkSession* network_session,        net::SSLCertRequestInfo* cert_request_info,        const base::Callback<void(net::X509Certificate*)>& callback) OVERRIDE; -  virtual void AddNewCertificate( +  virtual void AddCertificate(        net::URLRequest* request, -      net::X509Certificate* cert, +      net::CertificateMimeType cert_type, +      const void* cert_data, +      size_t cert_size,        int render_process_id,        int render_view_id) OVERRIDE;    virtual content::MediaObserver* GetMediaObserver() OVERRIDE; diff --git a/chrome/browser/ssl/ssl_add_certificate.cc b/chrome/browser/ssl/ssl_add_certificate.cc new file mode 100644 index 0000000..a21c843 --- /dev/null +++ b/chrome/browser/ssl/ssl_add_certificate.cc @@ -0,0 +1,37 @@ +// 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. + +#include "chrome/browser/ssl/ssl_add_certificate.h" + +#include "chrome/browser/ssl/ssl_add_cert_handler.h" +#include "net/base/x509_certificate.h" + +namespace chrome { + +void SSLAddCertificate( +    net::URLRequest* request, +    net::CertificateMimeType cert_type, +    const void* cert_data, +    size_t cert_size, +    int render_process_id, +    int render_view_id) { +  // Chromium only supports X.509 User certificates on non-Android +  // platforms. Note that this method should not be called for other +  // certificate mime types. +  if (cert_type != net::CERTIFICATE_MIME_TYPE_X509_USER_CERT) +    return; + +  scoped_refptr<net::X509Certificate> cert; +  if (cert_data != NULL) { +    cert = net::X509Certificate::CreateFromBytes( +        reinterpret_cast<const char*>(cert_data), cert_size); +  } +  // NOTE: Passing a NULL cert pointer if |cert_data| was NULL is +  // intentional here. + +  // The handler will run the UI and delete itself when it's finished. +  new SSLAddCertHandler(request, cert, render_process_id, render_view_id); +} + +}  // namespace chrome diff --git a/chrome/browser/ssl/ssl_add_certificate.h b/chrome/browser/ssl/ssl_add_certificate.h new file mode 100644 index 0000000..3711089 --- /dev/null +++ b/chrome/browser/ssl/ssl_add_certificate.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef CHROME_BROWSER_SSL_SSL_ADD_CERTIFICATE_H_ +#define CHROME_BROWSER_SSL_SSL_ADD_CERTIFICATE_H_ + +#include "base/basictypes.h" +#include "net/base/mime_util.h" + +namespace net { +class URLRequest; +}  // namespace net + +namespace chrome { + +// This method is used to add a new certificate file. +// +void SSLAddCertificate( +    net::URLRequest* request, +    net::CertificateMimeType cert_type, +    const void* cert_data, +    size_t cert_size, +    int render_process_id, +    int render_view_id); + +}  // namespace chrome + +#endif  // CHROME_BROWSER_SSL_SSL_ADD_CERTIFICATE_H_ diff --git a/chrome/browser/ssl/ssl_add_certificate_android.cc b/chrome/browser/ssl/ssl_add_certificate_android.cc new file mode 100644 index 0000000..460980e --- /dev/null +++ b/chrome/browser/ssl/ssl_add_certificate_android.cc @@ -0,0 +1,42 @@ +// 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. + +#include "chrome/browser/ssl/ssl_add_certificate.h" + +#include "net/android/network_library.h" + +namespace chrome { + +// Special case for Android here for several reasons: +// +// - The SSLAddCertHandler implementation currently only supports +//   CERTIFICATE_TYPE_X509_USER_CERT, but not other types, like +//   CERTIFICATE_TYPE_PKCS12_ARCHIVE which are required on this +//   platform. +// +// - Besides, SSLAddCertHandler tries to parse the certificate +//   by calling net::CertDatabase::CheckUserCert() which is not +//   implemented on Android, mainly because there is no API +//   provided by the system to do that properly. +// +// - The Android CertInstaller activity will check the certificate file +//   and display a toast (small fading dialog) to the user if it is +//   not valid, so the UI performed by SSLAddCertHandler would +//   be redundant. +void SSLAddCertificate( +    net::URLRequest* /* request */, +    net::CertificateMimeType cert_type, +    const void* cert_data, +    size_t cert_size, +    int /* render_process_id */, +    int /* render_view_id */) { +  if (cert_size > 0) { +    // This launches a new activity which will run in a different process. +    // It handles all user interaction, so no need to do anything in the +    // browser UI thread here. +    net::android::StoreCertificate(cert_type, cert_data, cert_size); +  } +} + +}  //  namespace chrome diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index f225107..706e13c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1873,6 +1873,8 @@          'browser/spellchecker/spellcheck_service.h',          'browser/spellchecker/spelling_service_client.cc',          'browser/spellchecker/spelling_service_client.h', +        'browser/ssl/ssl_add_certificate.cc', +        'browser/ssl/ssl_add_certificate.h',          'browser/ssl/ssl_add_cert_handler.cc',          'browser/ssl/ssl_add_cert_handler.h',          'browser/ssl/ssl_add_cert_handler_mac.mm', @@ -2757,6 +2759,7 @@            'sources': [              'browser/sessions/in_memory_tab_restore_service.cc',              'browser/sessions/in_memory_tab_restore_service.h', +            'browser/ssl/ssl_add_certificate_android.cc',              'browser/web_resource/notification_promo_mobile_ntp.cc',              'browser/web_resource/notification_promo_mobile_ntp.h',            ], @@ -2764,6 +2767,7 @@              # Bookmark export/import are handled via the BookmarkColumns              # ContentProvider.              'browser/bookmarks/bookmark_html_writer.cc', +            'browser/ssl/ssl_add_certificate.cc',              # about:flags is unsupported.              'browser/about_flags.cc', diff --git a/content/browser/loader/buffered_resource_handler.cc b/content/browser/loader/buffered_resource_handler.cc index d588601..47d00df 100644 --- a/content/browser/loader/buffered_resource_handler.cc +++ b/content/browser/loader/buffered_resource_handler.cc @@ -12,9 +12,9 @@  #include "base/string_util.h"  #include "content/browser/download/download_resource_handler.h"  #include "content/browser/download/download_stats.h" +#include "content/browser/loader/certificate_resource_handler.h"  #include "content/browser/loader/resource_dispatcher_host_impl.h"  #include "content/browser/loader/resource_request_info_impl.h" -#include "content/browser/loader/x509_user_cert_resource_handler.h"  #include "content/browser/plugin_service_impl.h"  #include "content/public/browser/browser_thread.h"  #include "content/public/browser/content_browser_client.h" @@ -303,12 +303,12 @@ bool BufferedResourceHandler::SelectNextHandler(bool* defer) {    ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);    const std::string& mime_type = response_->head.mime_type; -  if (mime_type == "application/x-x509-user-cert") { -    // Install X509 handler. +  if (net::IsSupportedCertificateMimeType(mime_type)) { +    // Install certificate file.      scoped_ptr<ResourceHandler> handler( -        new X509UserCertResourceHandler(request_, -                                        info->GetChildID(), -                                        info->GetRouteID())); +        new CertificateResourceHandler(request_, +                                       info->GetChildID(), +                                       info->GetRouteID()));      return UseAlternateNextHandler(handler.Pass());    } diff --git a/content/browser/loader/x509_user_cert_resource_handler.cc b/content/browser/loader/certificate_resource_handler.cc index 0d37eba..70a38e2 100644 --- a/content/browser/loader/x509_user_cert_resource_handler.cc +++ b/content/browser/loader/certificate_resource_handler.cc @@ -2,7 +2,7 @@  // Use of this source code is governed by a BSD-style license that can be  // found in the LICENSE file. -#include "content/browser/loader/x509_user_cert_resource_handler.h" +#include "content/browser/loader/certificate_resource_handler.h"  #include "base/string_util.h"  #include "content/browser/loader/resource_request_info_impl.h" @@ -11,14 +11,13 @@  #include "net/base/io_buffer.h"  #include "net/base/mime_sniffer.h"  #include "net/base/mime_util.h" -#include "net/base/x509_certificate.h"  #include "net/http/http_response_headers.h"  #include "net/url_request/url_request.h"  #include "net/url_request/url_request_status.h"  namespace content { -X509UserCertResourceHandler::X509UserCertResourceHandler( +CertificateResourceHandler::CertificateResourceHandler(      net::URLRequest* request,      int render_process_host_id,      int render_view_id) @@ -27,42 +26,44 @@ X509UserCertResourceHandler::X509UserCertResourceHandler(        read_buffer_(NULL),        resource_buffer_(NULL),        render_process_host_id_(render_process_host_id), -      render_view_id_(render_view_id) { +      render_view_id_(render_view_id), +      cert_type_(net::CERTIFICATE_MIME_TYPE_UNKNOWN) {  } -X509UserCertResourceHandler::~X509UserCertResourceHandler() { +CertificateResourceHandler::~CertificateResourceHandler() {  } -bool X509UserCertResourceHandler::OnUploadProgress(int request_id, -                                                   uint64 position, -                                                   uint64 size) { +bool CertificateResourceHandler::OnUploadProgress(int request_id, +                                                 uint64 position, +                                                 uint64 size) {    return true;  } -bool X509UserCertResourceHandler::OnRequestRedirected(int request_id, -                                                      const GURL& url, -                                                      ResourceResponse* resp, -                                                      bool* defer) { +bool CertificateResourceHandler::OnRequestRedirected(int request_id, +                                                    const GURL& url, +                                                    ResourceResponse* resp, +                                                    bool* defer) {    url_ = url;    return true;  } -bool X509UserCertResourceHandler::OnResponseStarted(int request_id, -                                                    ResourceResponse* resp, -                                                    bool* defer) { -  return (resp->head.mime_type == "application/x-x509-user-cert"); +bool CertificateResourceHandler::OnResponseStarted(int request_id, +                                                  ResourceResponse* resp, +                                                  bool* defer) { +  cert_type_ = net::GetCertificateMimeTypeForMimeType(resp->head.mime_type); +  return cert_type_ != net::CERTIFICATE_MIME_TYPE_UNKNOWN;  } -bool X509UserCertResourceHandler::OnWillStart(int request_id, -                                              const GURL& url, -                                              bool* defer) { +bool CertificateResourceHandler::OnWillStart(int request_id, +                                            const GURL& url, +                                            bool* defer) {    return true;  } -bool X509UserCertResourceHandler::OnWillRead(int request_id, -                                             net::IOBuffer** buf, -                                             int* buf_size, -                                             int min_size) { +bool CertificateResourceHandler::OnWillRead(int request_id, +                                           net::IOBuffer** buf, +                                           int* buf_size, +                                           int min_size) {    static const int kReadBufSize = 32768;    // TODO(gauravsh): Should we use 'min_size' here? @@ -76,9 +77,9 @@ bool X509UserCertResourceHandler::OnWillRead(int request_id,    return true;  } -bool X509UserCertResourceHandler::OnReadCompleted(int request_id, -                                                  int bytes_read, -                                                  bool* defer) { +bool CertificateResourceHandler::OnReadCompleted(int request_id, +                                                int bytes_read, +                                                bool* defer) {    if (!bytes_read)      return true; @@ -96,7 +97,7 @@ bool X509UserCertResourceHandler::OnReadCompleted(int request_id,    return true;  } -bool X509UserCertResourceHandler::OnResponseCompleted( +bool CertificateResourceHandler::OnResponseCompleted(      int request_id,      const net::URLRequestStatus& urs,      const std::string& sec_info) { @@ -104,17 +105,21 @@ bool X509UserCertResourceHandler::OnResponseCompleted(      return false;    AssembleResource(); -  scoped_refptr<net::X509Certificate> cert; -  if (resource_buffer_) { -      cert = net::X509Certificate::CreateFromBytes(resource_buffer_->data(), -                                                   content_length_); -  } -  GetContentClient()->browser()->AddNewCertificate( -      request_, cert, render_process_host_id_, render_view_id_); + +  const void* content_bytes = NULL; +  if (resource_buffer_) +    content_bytes = resource_buffer_->data(); + +  // Note that it's up to the browser to verify that the certificate +  // data is well-formed. +  GetContentClient()->browser()->AddCertificate( +      request_, cert_type_, content_bytes, content_length_, +      render_process_host_id_, render_view_id_); +    return true;  } -void X509UserCertResourceHandler::AssembleResource() { +void CertificateResourceHandler::AssembleResource() {    // 0-length IOBuffers are not allowed.    if (content_length_ == 0) {      resource_buffer_ = NULL; diff --git a/content/browser/loader/x509_user_cert_resource_handler.h b/content/browser/loader/certificate_resource_handler.h index cdfc113..ba07bf5 100644 --- a/content/browser/loader/x509_user_cert_resource_handler.h +++ b/content/browser/loader/certificate_resource_handler.h @@ -2,18 +2,19 @@  // Use of this source code is governed by a BSD-style license that can be  // found in the LICENSE file. -#ifndef CONTENT_BROWSER_LOADER_X509_USER_CERT_RESOURCE_HANDLER_H_ -#define CONTENT_BROWSER_LOADER_X509_USER_CERT_RESOURCE_HANDLER_H_ +#ifndef CONTENT_BROWSER_LOADER_CERTIFICATE_RESOURCE_HANDLER_H_ +#define CONTENT_BROWSER_LOADER_CERTIFICATE_RESOURCE_HANDLER_H_  #include <string>  #include <utility>  #include <vector>  #include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h"  #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h"  #include "content/browser/loader/resource_handler.h"  #include "googleurl/src/gurl.h" +#include "net/base/mime_util.h"  namespace net {  class IOBuffer; @@ -23,16 +24,17 @@ class URLRequestStatus;  namespace content { -// This class handles the "application/x-x509-user-cert" mime-type -// which is a certificate generated by a CA, typically after a previous -// <keygen> form post. - -class X509UserCertResourceHandler : public ResourceHandler { +// This class handles certificate mime types such as: +// - "application/x-x509-user-cert" +// - "application/x-x509-ca-cert" +// - "application/x-pkcs12" +// +class CertificateResourceHandler : public ResourceHandler {   public: -  X509UserCertResourceHandler(net::URLRequest* request, -                              int render_process_host_id, -                              int render_view_id); -  virtual ~X509UserCertResourceHandler(); +  CertificateResourceHandler(net::URLRequest* request, +                             int render_process_host_id, +                             int render_view_id); +  virtual ~CertificateResourceHandler();    virtual bool OnUploadProgress(int request_id,                                  uint64 position, @@ -86,10 +88,10 @@ class X509UserCertResourceHandler : public ResourceHandler {    int render_process_host_id_;    // The id of the |RenderView| which started the download.    int render_view_id_; - -  DISALLOW_COPY_AND_ASSIGN(X509UserCertResourceHandler); +  net::CertificateMimeType cert_type_; +  DISALLOW_COPY_AND_ASSIGN(CertificateResourceHandler);  };  }  // namespace content -#endif  // CONTENT_BROWSER_LOADER_X509_USER_CERT_RESOURCE_HANDLER_H_ +#endif  // CONTENT_BROWSER_LOADER_CERTIFICATE_RESOURCE_HANDLER_H_ diff --git a/content/content_browser.gypi b/content/content_browser.gypi index ce16dcd..9ddefdd 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -504,6 +504,8 @@      'browser/loader/async_resource_handler.h',      'browser/loader/buffered_resource_handler.cc',      'browser/loader/buffered_resource_handler.h', +    'browser/loader/certificate_resource_handler.cc', +    'browser/loader/certificate_resource_handler.h',      'browser/loader/cross_site_resource_handler.cc',      'browser/loader/cross_site_resource_handler.h',      'browser/loader/doomed_resource_handler.cc', @@ -531,8 +533,6 @@      'browser/loader/throttling_resource_handler.h',      'browser/loader/transfer_navigation_resource_throttle.cc',      'browser/loader/transfer_navigation_resource_throttle.h', -    'browser/loader/x509_user_cert_resource_handler.cc', -    'browser/loader/x509_user_cert_resource_handler.h',      'browser/mach_broker_mac.cc',      'browser/mach_broker_mac.h',      'browser/media_devices_monitor.cc', diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 373ec58..867dad5 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -14,6 +14,7 @@  #include "content/public/common/socket_permission_request.h"  #include "content/public/common/content_client.h"  #include "content/public/common/window_container_type.h" +#include "net/base/mime_util.h"  #include "net/cookies/canonical_cookie.h"  #include "third_party/WebKit/Source/WebKit/chromium/public/WebNotificationPresenter.h" @@ -332,13 +333,15 @@ class CONTENT_EXPORT ContentBrowserClient {        net::SSLCertRequestInfo* cert_request_info,        const base::Callback<void(net::X509Certificate*)>& callback) {} -  // Adds a downloaded client cert. The embedder should ensure that there's -  // a private key for the cert, displays the cert to the user, and adds it upon -  // user approval. If the downloaded data could not be interpreted as a valid -  // certificate, |cert| will be NULL. -  virtual void AddNewCertificate( +  // Adds a new installable certificate or private key. +  // Typically used to install an X.509 user certificate. +  // Note that it's up to the embedder to verify that the data is +  // well-formed. |cert_data| will be NULL if file_size is 0. +  virtual void AddCertificate(        net::URLRequest* request, -      net::X509Certificate* cert, +      net::CertificateMimeType cert_type, +      const void* cert_data, +      size_t cert_size,        int render_process_id,        int render_view_id) {} 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<jbyteArray> data_array = +      ToJavaByteArray(env, reinterpret_cast<const uint8*>(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 <vector>  #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. diff --git a/net/base/cert_database_android.cc b/net/base/cert_database_android.cc new file mode 100644 index 0000000..c441089 --- /dev/null +++ b/net/base/cert_database_android.cc @@ -0,0 +1,39 @@ +// 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. + +#include "net/base/cert_database.h" + +#include "base/logging.h" +#include "base/observer_list_threadsafe.h" +#include "net/base/net_errors.h" + +namespace net { + +CertDatabase::CertDatabase() +    : observer_list_(new ObserverListThreadSafe<Observer>) { +} + +CertDatabase::~CertDatabase() {} + +int CertDatabase::CheckUserCert(X509Certificate* cert) { +  // NOTE: This method shall never be called on Android. +  // +  // On other platforms, it is only used by the SSLAddCertHandler class +  // to handle veritication and installation of downloaded certificates. +  // +  // On Android, the certificate data is passed directly to the system's +  // CertInstaller activity, which handles verification, naming, +  // installation and UI (for success/failure). +  NOTIMPLEMENTED(); +  return ERR_NOT_IMPLEMENTED; +} + +int CertDatabase::AddUserCert(X509Certificate* cert) { +  // This method is only used by the content SSLAddCertHandler which is +  // never used on Android. +  NOTIMPLEMENTED(); +  return ERR_NOT_IMPLEMENTED; +} + +}  // namespace net diff --git a/net/base/cert_database_openssl.cc b/net/base/cert_database_openssl.cc index 7459b07..47effe2 100644 --- a/net/base/cert_database_openssl.cc +++ b/net/base/cert_database_openssl.cc @@ -35,7 +35,6 @@ int CertDatabase::CheckUserCert(X509Certificate* cert) {  }  int CertDatabase::AddUserCert(X509Certificate* cert) { -  // TODO(bulach): implement me.    NOTIMPLEMENTED();    return ERR_NOT_IMPLEMENTED;  } diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc index 6ae918b..f7240f2 100644 --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc @@ -339,13 +339,27 @@ static const char* const supported_non_image_types[] = {    "application/rss+xml",    "application/xhtml+xml",    "application/json", -  "application/x-x509-user-cert",    "multipart/related",  // For MHTML support.    "multipart/x-mixed-replace"    // Note: ADDING a new type here will probably render it AS HTML. This can    // result in cross site scripting.  }; +// Dictionary of cryptographic file mime types. +struct CertificateMimeTypeInfo { +  const char* mime_type; +  CertificateMimeType cert_type; +}; + +static const CertificateMimeTypeInfo supported_certificate_types[] = { +  { "application/x-x509-user-cert", +      CERTIFICATE_MIME_TYPE_X509_USER_CERT }, +#if defined(OS_ANDROID) +  { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT }, +  { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE }, +#endif +}; +  // These types are excluded from the logic that allows all text/ types because  // while they are technically text, it's very unlikely that a user expects to  // see them rendered in text form. @@ -433,6 +447,8 @@ void MimeUtil::InitializeMimeTypeMaps() {    // Initialize the supported non-image types.    for (size_t i = 0; i < arraysize(supported_non_image_types); ++i)      non_image_map_.insert(supported_non_image_types[i]); +  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) +    non_image_map_.insert(supported_certificate_types[i].mime_type);    for (size_t i = 0; i < arraysize(unsupported_text_types); ++i)      unsupported_text_map_.insert(unsupported_text_types[i]);    for (size_t i = 0; i < arraysize(supported_javascript_types); ++i) @@ -968,4 +984,21 @@ const std::string GetIANAMediaType(const std::string& mime_type) {    return "";  } +CertificateMimeType GetCertificateMimeTypeForMimeType( +    const std::string& mime_type) { +  // Don't create a map, there is only one entry in the table, +  // except on Android. +  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) { +    if (mime_type == net::supported_certificate_types[i].mime_type) +      return net::supported_certificate_types[i].cert_type; +  } +  return CERTIFICATE_MIME_TYPE_UNKNOWN; +} + +bool IsSupportedCertificateMimeType(const std::string& mime_type) { +  CertificateMimeType file_type = +      GetCertificateMimeTypeForMimeType(mime_type); +  return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN; +} +  }  // namespace net diff --git a/net/base/mime_util.h b/net/base/mime_util.h index c8dfe86..82279f0 100644 --- a/net/base/mime_util.h +++ b/net/base/mime_util.h @@ -44,6 +44,7 @@ NET_EXPORT bool IsSupportedMediaMimeType(const std::string& mime_type);  NET_EXPORT bool IsSupportedNonImageMimeType(const std::string& mime_type);  NET_EXPORT bool IsUnsupportedTextMimeType(const std::string& mime_type);  NET_EXPORT bool IsSupportedJavascriptMimeType(const std::string& mime_type); +NET_EXPORT bool IsSupportedCertificateMimeType(const std::string& mime_type);  // Get whether this mime type should be displayed in view-source mode.  // (For example, XML.) @@ -111,6 +112,17 @@ NET_EXPORT void GetMediaCodecsBlacklistedForTests(  // Supported media types are defined at:  // http://www.iana.org/assignments/media-types/index.html  NET_EXPORT const std::string GetIANAMediaType(const std::string& mime_type); + +// A list of supported certificate-related mime types. +enum CertificateMimeType { +#define CERTIFICATE_MIME_TYPE(name, value) CERTIFICATE_MIME_TYPE_ ## name = value, +#include "net/base/mime_util_certificate_type_list.h" +#undef CERTIFICATE_MIME_TYPE +}; + +NET_EXPORT CertificateMimeType GetCertificateMimeTypeForMimeType( +    const std::string& mime_type); +  }  // namespace net  #endif  // NET_BASE_MIME_UTIL_H__ diff --git a/net/base/mime_util_certificate_type_list.h b/net/base/mime_util_certificate_type_list.h new file mode 100644 index 0000000..c3d2947 --- /dev/null +++ b/net/base/mime_util_certificate_type_list.h @@ -0,0 +1,13 @@ +// 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. + +// This file intentionally does not have header guards, it's included +// inside a macro to generate enum. + +// This file contains the list of certificate MIME types. + +CERTIFICATE_MIME_TYPE(UNKNOWN, 0) +CERTIFICATE_MIME_TYPE(X509_USER_CERT, 1) +CERTIFICATE_MIME_TYPE(X509_CA_CERT, 2) +CERTIFICATE_MIME_TYPE(PKCS12_ARCHIVE, 3) diff --git a/net/base/mime_util_unittest.cc b/net/base/mime_util_unittest.cc index f3d15d1..be4d7ca 100644 --- a/net/base/mime_util_unittest.cc +++ b/net/base/mime_util_unittest.cc @@ -70,6 +70,11 @@ TEST(MimeUtilTest, LookupTypes) {    EXPECT_TRUE(IsSupportedNonImageMimeType("text/banana"));    EXPECT_FALSE(IsSupportedNonImageMimeType("text/vcard"));    EXPECT_FALSE(IsSupportedNonImageMimeType("application/virus")); +  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-x509-user-cert")); +#if defined(OS_ANDROID) +  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-x509-ca-cert")); +  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-pkcs12")); +#endif    EXPECT_TRUE(IsSupportedMimeType("image/jpeg"));    EXPECT_FALSE(IsSupportedMimeType("image/lolcat")); @@ -272,4 +277,23 @@ TEST(MimeUtilTest, TestGetExtensionsForMimeType) {    }  } +TEST(MimeUtilTest, TestGetCertificateMimeTypeForMimeType) { +  EXPECT_EQ(CERTIFICATE_MIME_TYPE_X509_USER_CERT, +            GetCertificateMimeTypeForMimeType("application/x-x509-user-cert")); +#if defined(OS_ANDROID) +  // Only Android supports CA Certs and PKCS12 archives. +  EXPECT_EQ(CERTIFICATE_MIME_TYPE_X509_CA_CERT, +            GetCertificateMimeTypeForMimeType("application/x-x509-ca-cert")); +  EXPECT_EQ(CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE, +            GetCertificateMimeTypeForMimeType("application/x-pkcs12")); +#else +  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN, +            GetCertificateMimeTypeForMimeType("application/x-x509-ca-cert")); +  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN, +            GetCertificateMimeTypeForMimeType("application/x-pkcs12")); +#endif +  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN, +            GetCertificateMimeTypeForMimeType("text/plain")); +} +  }  // namespace net diff --git a/net/net.gyp b/net/net.gyp index 74eb3a8..9f2a11f 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -84,6 +84,7 @@          'base/cache_type.h',          'base/cert_database.cc',          'base/cert_database.h', +        'base/cert_database_android.cc',          'base/cert_database_ios.cc',          'base/cert_database_mac.cc',          'base/cert_database_nss.cc', @@ -1209,6 +1210,7 @@                'net_jni_headers',              ],              'sources!': [ +              'base/cert_database_openssl.cc',                'base/openssl_memory_private_key_store.cc',              ],            }, {  # else OS! = "android" @@ -2270,6 +2272,7 @@            'dependencies': [              '../base/base.gyp:base',              'net_errors_java', +            'certificate_mime_types_java',            ],            'includes': [ '../build/java.gypi' ],          }, @@ -2307,7 +2310,19 @@              'package_name': 'org.chromium.net',            },            'includes': [ '../build/android/java_cpp_template.gypi' ], -        } +        }, +        { +          'target_name': 'certificate_mime_types_java', +          'type': 'none', +          'sources': [ +            'base/mime_util_certificate_type_list.h', +            'android/java/CertificateMimeType.template', +          ], +          'variables': { +            'package_name': 'org.chromium.net', +          }, +          'includes': [ '../build/android/java_cpp_template.gypi' ], +        },        ],      }],      # Special target to wrap a gtest_target_type==shared_library | 
