summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/renderer_host/buffered_resource_handler.cc59
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc12
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h3
-rw-r--r--chrome/browser/renderer_host/x509_user_cert_resource_handler.cc100
-rw-r--r--chrome/browser/renderer_host/x509_user_cert_resource_handler.h58
-rwxr-xr-xchrome/chrome.gyp2
-rw-r--r--chrome/common/render_messages_internal.h13
-rw-r--r--chrome/renderer/renderer_webkitclient_impl.cc16
-rw-r--r--chrome/renderer/renderer_webkitclient_impl.h4
-rw-r--r--net/base/cert_database.h34
-rw-r--r--net/base/cert_database_mac.cc24
-rw-r--r--net/base/cert_database_nss.cc102
-rw-r--r--net/base/cert_database_win.cc24
-rw-r--r--net/base/keygen_handler.h27
-rw-r--r--net/base/keygen_handler_mac.cc23
-rw-r--r--net/base/keygen_handler_nss.cc255
-rw-r--r--net/base/keygen_handler_win.cc23
-rw-r--r--net/base/mime_util.cc1
-rw-r--r--net/net.gyp10
-rw-r--r--webkit/api/public/WebKitClient.h9
-rw-r--r--webkit/api/src/ChromiumBridge.cpp5
-rw-r--r--webkit/glue/webkitclient_impl.cc8
-rw-r--r--webkit/glue/webkitclient_impl.h4
23 files changed, 806 insertions, 10 deletions
diff --git a/chrome/browser/renderer_host/buffered_resource_handler.cc b/chrome/browser/renderer_host/buffered_resource_handler.cc
index 347bf69..68514ad 100644
--- a/chrome/browser/renderer_host/buffered_resource_handler.cc
+++ b/chrome/browser/renderer_host/buffered_resource_handler.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
+#include "chrome/browser/renderer_host/x509_user_cert_resource_handler.h"
#include "chrome/common/url_constants.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
@@ -293,6 +294,50 @@ bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
// TODO(paulg): Only download if the context from the renderer allows it.
ResourceDispatcherHostRequestInfo* info =
ResourceDispatcherHost::InfoForRequest(request_);
+ std::string mime_type;
+ request_->GetMimeType(&mime_type);
+
+ // Check if this is an X.509 certificate, if yes, let it be handled
+ // by X509UserCertResourceHandler.
+ if (mime_type == "application/x-x509-user-cert") {
+
+ // This is entirely similar to how DownloadThrottlingResourceHandler
+ // works except we are doing it for an X.509 client certificates.
+
+ if (response_->response_head.headers && // Can be NULL if FTP.
+ response_->response_head.headers->response_code() / 100 != 2) {
+ // The response code indicates that this is an error page, but we are
+ // expecting an X.509 user certificate. We follow Firefox here and show
+ // our own error page instead of handling the error page as a
+ // certificate.
+ // TODO(abarth): We should abstract the response_code test, but this kind
+ // of check is scattered throughout our codebase.
+ request_->SimulateError(net::ERR_FILE_NOT_FOUND);
+ return false;
+ }
+
+ scoped_refptr<X509UserCertResourceHandler> x509_cert_handler =
+ new X509UserCertResourceHandler(host_, request_);
+
+ if (bytes_read_) {
+ // A Read has already occured and we need to copy the data into the
+ // EventHandler.
+ net::IOBuffer* buf = NULL;
+ int buf_len = 0;
+ x509_cert_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
+ CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
+ memcpy(buf->data(), read_buffer_->data(), bytes_read_);
+ }
+
+ // Inform the renderer that this will be handled entirely by the browser.
+ real_handler_->OnResponseStarted(info->request_id(), response_);
+ URLRequestStatus status(URLRequestStatus::HANDLED_EXTERNALLY, 0);
+ real_handler_->OnResponseCompleted(info->request_id(), status,
+ std::string());
+
+ // This is handled entirely within the browser, so just reset the handler.
+ real_handler_ = x509_cert_handler;
+ }
if (info->allow_download() && ShouldDownload(NULL)) {
if (response_->response_head.headers && // Can be NULL if FTP.
@@ -310,14 +355,14 @@ bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
scoped_refptr<DownloadThrottlingResourceHandler> download_handler =
new DownloadThrottlingResourceHandler(host_,
- request_,
- request_->url(),
- info->child_id(),
- info->route_id(),
- request_id,
- in_complete);
+ request_,
+ request_->url(),
+ info->child_id(),
+ info->route_id(),
+ request_id,
+ in_complete);
if (bytes_read_) {
- // a Read has already occurred and we need to copy the data into the
+ // A Read has already occurred and we need to copy the data into the
// EventHandler.
net::IOBuffer* buf = NULL;
int buf_len = 0;
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index 0650fa7..dc49500 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -46,6 +46,7 @@
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/worker_messages.h"
+#include "net/base/keygen_handler.h"
#include "net/base/mime_util.h"
#include "net/base/load_flags.h"
#include "net/http/http_cache.h"
@@ -381,6 +382,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
OnCloseIdleConnections)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetCacheMode, OnSetCacheMode)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize, OnGetFileSize)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Keygen, OnKeygen)
#if defined(USE_TCMALLOC)
IPC_MESSAGE_HANDLER(ViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
#endif
@@ -1110,6 +1112,16 @@ void ResourceMessageFilter::ReplyGetFileSize(int64 result, void* param) {
Release();
}
+void ResourceMessageFilter::OnKeygen(uint32 key_size_index,
+ const std::string& challenge_string,
+ const GURL& url,
+ std::string* signed_public_key) {
+ scoped_ptr<net::KeygenHandler> keygen_handler(
+ new net::KeygenHandler(key_size_index,
+ challenge_string));
+ *signed_public_key = keygen_handler->GenKeyAndSignChallenge();
+}
+
#if defined(USE_TCMALLOC)
void ResourceMessageFilter::OnRendererTcmalloc(base::ProcessId pid,
const std::string& output) {
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index 029fb20..f0029a5 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -277,7 +277,8 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnGetFileSize(const FilePath& path, IPC::Message* reply_msg);
void ReplyGetFileSize(int64 result, void* param);
-
+ void OnKeygen(uint32 key_size_index, const std::string& challenge_string,
+ const GURL& url, std::string* signed_public_key);
#if defined(OS_LINUX)
void SendDelayedReply(IPC::Message* reply_msg);
void DoOnGetScreenInfo(gfx::NativeViewId view, IPC::Message* reply_msg);
diff --git a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc
new file mode 100644
index 0000000..76dcedd
--- /dev/null
+++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 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/renderer_host/x509_user_cert_resource_handler.h"
+
+#include "base/string_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/download/download_file.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
+#include "chrome/common/url_constants.h"
+#include "net/base/cert_database.h"
+#include "net/base/io_buffer.h"
+#include "net/base/mime_sniffer.h"
+#include "net/base/mime_util.h"
+#include "net/http/http_response_headers.h"
+
+X509UserCertResourceHandler::X509UserCertResourceHandler(
+ ResourceDispatcherHost* host, URLRequest* request)
+ : host_(host),
+ request_(request),
+ content_length_(0),
+ buffer_(new DownloadBuffer),
+ read_buffer_(NULL),
+ resource_buffer_(NULL) {
+}
+
+bool X509UserCertResourceHandler::OnRequestRedirected(int request_id,
+ const GURL& url,
+ ResourceResponse* resp,
+ bool* defer) {
+ url_ = url;
+ return true;
+}
+
+bool X509UserCertResourceHandler::OnResponseStarted(int request_id,
+ ResourceResponse* resp) {
+ return (resp->response_head.mime_type == "application/x-x509-user-cert");
+}
+
+bool X509UserCertResourceHandler::OnWillRead(int request_id,
+ net::IOBuffer** buf,
+ int* buf_size,
+ int min_size) {
+ // TODO(gauravsh): Should we use 'min_size' here?
+ DCHECK(buf && buf_size);
+ if (!read_buffer_) {
+ read_buffer_ = new net::IOBuffer(kReadBufSize);
+ }
+ *buf = read_buffer_.get();
+ *buf_size = kReadBufSize;
+
+ return true;
+}
+
+bool X509UserCertResourceHandler::OnReadCompleted(int request_id,
+ int* bytes_read) {
+ if (!*bytes_read)
+ return true;
+
+ // We have more data to read.
+ DCHECK(read_buffer_);
+ content_length_ += *bytes_read;
+
+ // Release the ownership of the buffer, and store a reference
+ // to it. A new one will be allocated in OnWillRead().
+ net::IOBuffer* buffer = NULL;
+ read_buffer_.swap(&buffer);
+ // TODO(gauravsh): Should this be handled by a separate thread?
+ buffer_->contents.push_back(std::make_pair(buffer, *bytes_read));
+
+ return true;
+}
+
+bool X509UserCertResourceHandler::OnResponseCompleted(
+ int request_id,
+ const URLRequestStatus& urs,
+ const std::string& sec_info) {
+ // TODO(gauravsh): Verify that 'request_id' was actually a keygen form post
+ // and only then import the certificate.
+ scoped_ptr<net::CertDatabase> cert_db(new net::CertDatabase());
+ AssembleResource();
+
+ return cert_db->AddUserCert(resource_buffer_->data(), content_length_);
+}
+
+void X509UserCertResourceHandler::AssembleResource() {
+ size_t bytes_copied = 0;
+ resource_buffer_ = new net::IOBuffer(content_length_);
+
+ for (size_t i = 0; i < buffer_->contents.size(); ++i) {
+ net::IOBuffer* data = buffer_->contents[i].first;
+ const int data_len = buffer_->contents[i].second;
+ DCHECK(bytes_copied + data_len <= content_length_);
+ memcpy(resource_buffer_->data() + bytes_copied, data->data(), data_len);
+ bytes_copied += data_len;
+ }
+}
diff --git a/chrome/browser/renderer_host/x509_user_cert_resource_handler.h b/chrome/browser/renderer_host/x509_user_cert_resource_handler.h
new file mode 100644
index 0000000..78dffad
--- /dev/null
+++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2009 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_RENDERER_HOST_X509_USER_CERT_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_X509_USER_CERT_RESOURCE_HANDLER_H_
+
+#include <string>
+
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_handler.h"
+#include "chrome/browser/download/download_file.h"
+
+// This class handles the "application/x-x509-user-cert" mime-type
+// which is a certificate generated by a CA after a previous
+// <keygen> form post.
+
+class X509UserCertResourceHandler : public ResourceHandler {
+ public:
+ X509UserCertResourceHandler(ResourceDispatcherHost* host,
+ URLRequest* request);
+
+ // Not needed, as this event handler ought to be the final resource.
+ bool OnRequestRedirected(int request_id, const GURL& url,
+ ResourceResponse* resp, bool* defer);
+
+ // Check if this indeed an X509 cert.
+ bool OnResponseStarted(int request_id, ResourceResponse* resp);
+
+ // Create a new buffer to store received data.
+ bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
+ int min_size);
+
+ // A read was completed, maybe allocate a new buffer for further data.
+ bool OnReadCompleted(int request_id, int* bytes_read);
+
+ // Done downloading the certificate.
+ bool OnResponseCompleted(int request_id,
+ const URLRequestStatus& urs,
+ const std::string& sec_info);
+
+
+ private:
+ void AssembleResource();
+
+ GURL url_;
+ ResourceDispatcherHost* host_;
+ URLRequest* request_;
+ size_t content_length_;
+ scoped_ptr<DownloadBuffer> buffer_;
+ scoped_refptr<net::IOBuffer> read_buffer_;
+ scoped_refptr<net::IOBuffer> resource_buffer_; // Downloaded certificate.
+ static const int kReadBufSize = 32768;
+
+ DISALLOW_COPY_AND_ASSIGN(X509UserCertResourceHandler);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_X509_USER_CERT__RESOURCE_HANDLER_H_
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index add4723..43ea689 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1965,6 +1965,8 @@
'browser/renderer_host/sync_resource_handler.h',
'browser/renderer_host/web_cache_manager.cc',
'browser/renderer_host/web_cache_manager.h',
+ 'browser/renderer_host/x509_user_cert_resource_handler.cc',
+ 'browser/renderer_host/x509_user_cert_resource_handler.h',
'browser/rlz/rlz.cc',
'browser/rlz/rlz.h',
'browser/safe_browsing/bloom_filter.cc',
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 1b39dae..ab4397c 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -1923,4 +1923,17 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_CONTROL1(ViewHostMsg_SocketStream_Close,
int /* socket_id */)
+ //---------------------------------------------------------------------------
+ // Request for cryptographic operation messages:
+ // These are messages from the renderer to the browser to perform a
+ // cryptographic operation.
+
+ // Asks the browser process to generate a keypair for grabbing a client
+ // certificate from a CA (<keygen> tag), and returns the signed public
+ // key and challenge string.
+ IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_Keygen,
+ uint32 /* key size index */,
+ std::string /* challenge string */,
+ GURL /* URL of requestor */,
+ std::string /* signed public key and challenge */)
IPC_END_MESSAGES(ViewHost)
diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc
index 69db1df..1f95c1ff 100644
--- a/chrome/renderer/renderer_webkitclient_impl.cc
+++ b/chrome/renderer/renderer_webkitclient_impl.cc
@@ -23,6 +23,7 @@
#include "chrome/renderer/render_thread.h"
#include "chrome/renderer/renderer_webstoragenamespace_impl.h"
#include "chrome/renderer/visitedlink_slave.h"
+#include "googleurl/src/gurl.h"
#include "webkit/api/public/WebString.h"
#include "webkit/api/public/WebURL.h"
#include "webkit/appcache/web_application_cache_host_impl.h"
@@ -314,3 +315,18 @@ long long RendererWebKitClientImpl::databaseGetFileSize(
message_id),
message_id, 0LL);
}
+
+//------------------------------------------------------------------------------
+
+WebKit::WebString RendererWebKitClientImpl::signedPublicKeyAndChallengeString(
+ unsigned key_size_index,
+ const WebKit::WebString& challenge,
+ const WebKit::WebURL& url) {
+ std::string signed_public_key;
+ RenderThread::current()->Send(new ViewHostMsg_Keygen(
+ static_cast<uint32>(key_size_index),
+ webkit_glue::WebStringToStdString(challenge),
+ GURL(url) ,
+ &signed_public_key));
+ return webkit_glue::StdStringToWebString(signed_public_key);
+}
diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h
index d9b7fc3..c5ac687 100644
--- a/chrome/renderer/renderer_webkitclient_impl.h
+++ b/chrome/renderer/renderer_webkitclient_impl.h
@@ -52,6 +52,10 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl {
bool sync_dir);
virtual long databaseGetFileAttributes(const WebKit::WebString& file_name);
virtual long long databaseGetFileSize(const WebKit::WebString& file_name);
+ virtual WebKit::WebString signedPublicKeyAndChallengeString(
+ unsigned key_size_index,
+ const WebKit::WebString& challenge,
+ const WebKit::WebURL& url);
virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(
WebKit::WebApplicationCacheHostClient*);
diff --git a/net/base/cert_database.h b/net/base/cert_database.h
new file mode 100644
index 0000000..e78c22e
--- /dev/null
+++ b/net/base/cert_database.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009 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_BASE_CERT_DATABASE_H_
+#define NET_BASE_CERT_DATABASE_H_
+
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+// This class provides functions to manipulate the local
+// certificate store.
+
+// TODO(gauravsh): This class could be augmented with methods
+// for all operations that manipulate the underlying system
+// certificate store.
+
+class CertDatabase {
+ public:
+ CertDatabase();
+
+ // Extract and Store User (Client) Certificate from a data blob.
+ // Return true if successful.
+ bool AddUserCert(const char* data, int len);
+
+ private:
+ void Init();
+ DISALLOW_COPY_AND_ASSIGN(CertDatabase);
+};
+
+} // namespace net
+
+#endif // NET_BASE_CERT_DATABASE_H_
diff --git a/net/base/cert_database_mac.cc b/net/base/cert_database_mac.cc
new file mode 100644
index 0000000..5caf9db
--- /dev/null
+++ b/net/base/cert_database_mac.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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"
+
+namespace net {
+
+CertDatabase::CertDatabase() {
+ NOTIMPLEMENTED();
+}
+
+bool CertDatabase::AddUserCert(const char* data, int len) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void CertDatabase::Init() {
+ NOTIMPLEMENTED();
+}
+
+} // namespace net
diff --git a/net/base/cert_database_nss.cc b/net/base/cert_database_nss.cc
new file mode 100644
index 0000000..5f43fef
--- /dev/null
+++ b/net/base/cert_database_nss.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2009 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"
+
+// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
+// until NSS 3.12.2 comes out and we update to it.
+#define Lock FOO_NSS_Lock
+#include <pk11pub.h>
+#include <secmod.h>
+#include <ssl.h>
+#include <nssb64.h> // NSSBase64_EncodeItem()
+#include <secder.h> // DER_Encode()
+#include <cryptohi.h> // SEC_DerSignData()
+#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
+#undef Lock
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/nss_init.h"
+
+namespace net {
+
+CertDatabase::CertDatabase() {
+ Init();
+}
+
+bool CertDatabase::AddUserCert(const char* data, int len) {
+ CERTCertificate* cert = NULL;
+ PK11SlotInfo* slot = NULL;
+ std::string nickname;
+ bool is_success = true;
+
+ // Make a copy of "data" since CERT_DecodeCertPackage
+ // might modify it.
+ char* data_copy = new char[len];
+ memcpy(data_copy, data, len);
+
+ // Parse into a certificate structure.
+ cert = CERT_DecodeCertFromPackage(data_copy, len);
+ delete [] data_copy;
+ if (!cert) {
+ LOG(ERROR) << "Couldn't create a temporary certificate";
+ return false;
+ }
+
+ // Check if the private key corresponding to the certificate exist
+ // We shouldn't accept any random client certificate sent by a CA.
+
+ // Note: The NSS source documentation wrongly suggests that this
+ // also imports the certificate if the private key exists. This
+ // doesn't seem to be the case.
+
+ slot = PK11_KeyForCertExists(cert, NULL, NULL);
+ if (!slot) {
+ LOG(ERROR) << "No corresponding private key in store";
+ CERT_DestroyCertificate(cert);
+ return false;
+ }
+ PK11_FreeSlot(slot);
+ slot = NULL;
+
+ // TODO(gauravsh): We also need to make sure another certificate
+ // doesn't already exist for the same private key.
+
+ // Create a nickname for this certificate.
+ // We use the scheme used by Firefox:
+ // --> <subject's common name>'s <issuer's common name> ID.
+ //
+
+ std::string username, ca_name;
+ char* temp_username = CERT_GetCommonName(&cert->subject);
+ char* temp_ca_name = CERT_GetCommonName(&cert->issuer);
+ if (temp_username) {
+ username = temp_username;
+ PORT_Free(temp_username);
+ }
+ if (temp_ca_name) {
+ ca_name = temp_ca_name;
+ PORT_Free(temp_ca_name);
+ }
+ nickname = username + "'s " + ca_name + " ID";
+
+ slot = PK11_ImportCertForKey(cert,
+ const_cast<char*>(nickname.c_str()),
+ NULL);
+ if (slot) {
+ PK11_FreeSlot(slot);
+ } else {
+ LOG(ERROR) << "Couldn't import user certificate.";
+ is_success = false;
+ }
+ CERT_DestroyCertificate(cert);
+ return is_success;
+}
+
+void CertDatabase::Init() {
+ base::EnsureNSSInit();
+}
+
+} // namespace net
diff --git a/net/base/cert_database_win.cc b/net/base/cert_database_win.cc
new file mode 100644
index 0000000..5caf9db
--- /dev/null
+++ b/net/base/cert_database_win.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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"
+
+namespace net {
+
+CertDatabase::CertDatabase() {
+ NOTIMPLEMENTED();
+}
+
+bool CertDatabase::AddUserCert(const char* data, int len) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void CertDatabase::Init() {
+ NOTIMPLEMENTED();
+}
+
+} // namespace net
diff --git a/net/base/keygen_handler.h b/net/base/keygen_handler.h
new file mode 100644
index 0000000..346b577
--- /dev/null
+++ b/net/base/keygen_handler.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2009 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_BASE_KEYGEN_HANDLER_H_
+#define NET_BASE_KEYGEN_HANDLER_H_
+
+#include <string>
+
+namespace net {
+
+// This class handles keypair generation for generating client
+// certificates via the Netscape <keygen> tag.
+
+class KeygenHandler {
+ public:
+ KeygenHandler(int key_size_index, const std::string& challenge);
+ std::string GenKeyAndSignChallenge();
+
+ private:
+ int key_size_index_;
+ std::string challenge_;
+};
+
+} // namespace net
+
+#endif // NET_BASE_KEYGEN_HANDLER_H_
diff --git a/net/base/keygen_handler_mac.cc b/net/base/keygen_handler_mac.cc
new file mode 100644
index 0000000..f6b4551
--- /dev/null
+++ b/net/base/keygen_handler_mac.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2009 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/keygen_handler.h"
+
+#include "base/logging.h"
+
+namespace net {
+
+KeygenHandler::KeygenHandler(int key_size_index,
+ const std::string& challenge)
+ : key_size_index_(key_size_index),
+ challenge_(challenge) {
+ NOTIMPLEMENTED();
+}
+
+std::string KeygenHandler::GenKeyAndSignChallenge() {
+ NOTIMPLEMENTED();
+ return std::string();
+}
+
+} // namespace net
diff --git a/net/base/keygen_handler_nss.cc b/net/base/keygen_handler_nss.cc
new file mode 100644
index 0000000..9707dfc
--- /dev/null
+++ b/net/base/keygen_handler_nss.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2009 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/keygen_handler.h"
+
+// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
+// until NSS 3.12.2 comes out and we update to it.
+#define Lock FOO_NSS_Lock
+#include <pk11pub.h>
+#include <secmod.h>
+#include <ssl.h>
+#include <nssb64.h> // NSSBase64_EncodeItem()
+#include <secder.h> // DER_Encode()
+#include <cryptohi.h> // SEC_DerSignData()
+#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
+#undef Lock
+
+#include "base/nss_init.h"
+#include "base/logging.h"
+
+namespace net {
+
+const int64 DEFAULT_RSA_PUBLIC_EXPONENT = 0x10001;
+
+// Template for creating the signed public key structure to be sent to the CA.
+DERTemplate SECAlgorithmIDTemplate[] = {
+ { DER_SEQUENCE,
+ 0, NULL, sizeof(SECAlgorithmID) },
+ { DER_OBJECT_ID,
+ offsetof(SECAlgorithmID, algorithm), },
+ { DER_OPTIONAL | DER_ANY,
+ offsetof(SECAlgorithmID, parameters), },
+ { 0, }
+};
+
+DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
+ { DER_SEQUENCE,
+ 0, NULL, sizeof(CERTSubjectPublicKeyInfo) },
+ { DER_INLINE,
+ offsetof(CERTSubjectPublicKeyInfo, algorithm),
+ SECAlgorithmIDTemplate, },
+ { DER_BIT_STRING,
+ offsetof(CERTSubjectPublicKeyInfo, subjectPublicKey), },
+ { 0, }
+};
+
+DERTemplate CERTPublicKeyAndChallengeTemplate[] = {
+ { DER_SEQUENCE,
+ 0, NULL, sizeof(CERTPublicKeyAndChallenge) },
+ { DER_ANY,
+ offsetof(CERTPublicKeyAndChallenge, spki), },
+ { DER_IA5_STRING,
+ offsetof(CERTPublicKeyAndChallenge, challenge), },
+ { 0, }
+};
+
+// This maps displayed strings indicating level of keysecurity in the <keygen>
+// menu to the key size in bits.
+// TODO(gauravsh): Should this mapping be moved else where?
+int RSAkeySizeMap[] = {2048, 1024};
+
+KeygenHandler::KeygenHandler(int key_size_index,
+ const std::string& challenge)
+ : key_size_index_(key_size_index),
+ challenge_(challenge) {
+}
+
+// This function is largely copied from the Firefox's
+// <keygen> implementation in security/manager/ssl/src/nsKeygenHandler.cpp
+// FIXME(gauravsh): Do we need a copy of the Mozilla license here?
+
+std::string KeygenHandler::GenKeyAndSignChallenge() {
+ // Key pair generation mechanism - only RSA is supported at present.
+ PRUint32 keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // from nss/pkcs11t.h
+ char *keystring = NULL; // Temporary store for result/
+
+ // Temporary structures used for generating the result
+ // in the right format.
+ PK11SlotInfo *slot = NULL;
+ PK11RSAGenParams rsaKeyGenParams; // Keygen parameters.
+ SECOidTag algTag; // used by SEC_DerSignData().
+ SECKEYPrivateKey *privateKey = NULL;
+ SECKEYPublicKey *publicKey = NULL;
+ CERTSubjectPublicKeyInfo *spkInfo = NULL;
+ PRArenaPool *arena = NULL;
+ SECStatus sec_rv =SECFailure;
+ SECItem spkiItem;
+ SECItem pkacItem;
+ SECItem signedItem;
+ CERTPublicKeyAndChallenge pkac;
+ void *keyGenParams;
+ pkac.challenge.data = NULL;
+ bool isSuccess = true; // Set to false as soon as a step fails.
+
+ std::string result_blob; // the result.
+
+ // Ensure NSS is initialized.
+ base::EnsureNSSInit();
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) {
+ LOG(ERROR) << "Couldn't get Internal key slot!";
+ isSuccess = false;
+ goto failure;
+ }
+
+ switch (keyGenMechanism) {
+ case CKM_RSA_PKCS_KEY_PAIR_GEN:
+ rsaKeyGenParams.keySizeInBits = RSAkeySizeMap[key_size_index_];
+ rsaKeyGenParams.pe = DEFAULT_RSA_PUBLIC_EXPONENT;
+ keyGenParams = &rsaKeyGenParams;
+
+ algTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; // from <nss/secoidt.h>.
+ break;
+ default:
+ // TODO(gauravsh): If we ever support other mechanisms,
+ // this can be changed.
+ LOG(ERROR) << "Only RSA keygen mechanism is supported";
+ isSuccess = false;
+ goto failure;
+ break;
+ }
+
+ // Need to make sure that the token was initialized.
+ // Assume a null password.
+ sec_rv = PK11_Authenticate(slot, PR_TRUE, NULL);
+ if (SECSuccess != sec_rv) {
+ LOG(ERROR) << "Couldn't initialze PK11 token!";
+ isSuccess = false;
+ goto failure;
+ }
+
+ LOG(INFO) << "Creating key pair...";
+ privateKey = PK11_GenerateKeyPair(slot,
+ keyGenMechanism,
+ keyGenParams,
+ &publicKey,
+ PR_TRUE, // isPermanent?
+ PR_TRUE, // isSensitive?
+ NULL);
+ LOG(INFO) << "done.";
+
+ if (!privateKey) {
+ LOG(INFO) << "Generation of Keypair failed!";
+ isSuccess = false;
+ goto failure;
+ }
+
+ // The CA expects the signed public key in a specific format
+ // Let's create that now.
+
+ // Create a subject public key info from the public key.
+ spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
+ if (!spkInfo) {
+ LOG(ERROR) << "Couldn't create SubjectPublicKeyInfo from public key";
+ isSuccess = false;
+ goto failure;
+ }
+
+ // Temporary work store used by NSS.
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ LOG(ERROR) << "PORT_NewArena: Couldn't allocate memory";
+ isSuccess = false;
+ goto failure;
+ }
+
+ // DER encode the whole subjectPublicKeyInfo.
+ sec_rv = DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate,
+ spkInfo);
+ if (SECSuccess != sec_rv) {
+ LOG(ERROR) << "Couldn't DER Encode subjectPublicKeyInfo";
+ isSuccess = false;
+ goto failure;
+ }
+
+ // Set up the PublicKeyAndChallenge data structure, then DER encode it.
+ pkac.spki = spkiItem;
+ pkac.challenge.len = challenge_.length();
+ pkac.challenge.data = (unsigned char *)strdup(challenge_.c_str());
+ if (!pkac.challenge.data) {
+ LOG(ERROR) << "Out of memory while making a copy of challenge data";
+ isSuccess = false;
+ goto failure;
+ }
+ sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate,
+ &pkac);
+ if (SECSuccess != sec_rv) {
+ LOG(ERROR) << "Couldn't DER Encode PublicKeyAndChallenge";
+ isSuccess = false;
+ goto failure;
+ }
+
+ // Sign the DER encoded PublicKeyAndChallenge.
+ sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
+ privateKey, algTag);
+ if (SECSuccess != sec_rv) {
+ LOG(ERROR) << "Couldn't sign the DER encoded PublicKeyandChallenge";
+ isSuccess = false;
+ goto failure;
+ }
+
+ // Convert the signed public key and challenge into base64/ascii.
+ keystring = NSSBase64_EncodeItem(arena,
+ NULL, // NSS will allocate a buffer for us.
+ 0,
+ &signedItem);
+ if (!keystring) {
+ LOG(ERROR) << "Couldn't convert signed public key into base64";
+ isSuccess = false;
+ goto failure;
+ }
+
+ result_blob = keystring;
+
+ failure:
+ if (!isSuccess) {
+ LOG(ERROR) << "SSL Keygen failed!";
+ } else {
+ LOG(INFO) << "SSl Keygen succeeded!";
+ }
+
+ // Do cleanups
+ if (privateKey) {
+ // TODO(gauravsh): We still need to maintain the private key because it's
+ // used for certificate enrollment checks.
+
+ // PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
+ // SECKEY_DestroyPrivateKey(privateKey);
+ }
+
+ if (publicKey) {
+ PK11_DestroyTokenObject(publicKey->pkcs11Slot, publicKey->pkcs11ID);
+ }
+ if (spkInfo) {
+ SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
+ }
+ if (publicKey) {
+ SECKEY_DestroyPublicKey(publicKey);
+ }
+ if (arena) {
+ PORT_FreeArena(arena, PR_TRUE);
+ }
+ if (slot != NULL) {
+ PK11_FreeSlot(slot);
+ }
+ if (pkac.challenge.data) {
+ free(pkac.challenge.data);
+ }
+
+ return (isSuccess ? result_blob : std::string());
+}
+
+} // namespace net
diff --git a/net/base/keygen_handler_win.cc b/net/base/keygen_handler_win.cc
new file mode 100644
index 0000000..f6b4551
--- /dev/null
+++ b/net/base/keygen_handler_win.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2009 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/keygen_handler.h"
+
+#include "base/logging.h"
+
+namespace net {
+
+KeygenHandler::KeygenHandler(int key_size_index,
+ const std::string& challenge)
+ : key_size_index_(key_size_index),
+ challenge_(challenge) {
+ NOTIMPLEMENTED();
+}
+
+std::string KeygenHandler::GenKeyAndSignChallenge() {
+ NOTIMPLEMENTED();
+ return std::string();
+}
+
+} // namespace net
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index 0fbb8c3..83e41a9 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -233,6 +233,7 @@ static const char* const supported_non_image_types[] = {
"application/xhtml+xml",
"application/rss+xml",
"application/atom+xml",
+ "application/x-x509-user-cert",
"multipart/x-mixed-replace"
};
diff --git a/net/net.gyp b/net/net.gyp
index aa6e94a..5e630cd 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -29,6 +29,10 @@
'base/bzip2_filter.cc',
'base/bzip2_filter.h',
'base/cache_type.h',
+ 'base/cert_database.h',
+ 'base/cert_database_mac.cc',
+ 'base/cert_database_nss.cc',
+ 'base/cert_database_win.cc',
'base/cert_status_flags.cc',
'base/cert_status_flags.h',
'base/cert_verifier.cc',
@@ -74,6 +78,10 @@
'base/host_resolver_proc.h',
'base/io_buffer.cc',
'base/io_buffer.h',
+ 'base/keygen_handler.h',
+ 'base/keygen_handler_mac.cc',
+ 'base/keygen_handler_nss.cc',
+ 'base/keygen_handler_win.cc',
'base/listen_socket.cc',
'base/listen_socket.h',
'base/load_flags.h',
@@ -172,6 +180,8 @@
},
{ # else: OS != "linux"
'sources!': [
+ 'base/cert_database_nss.cc',
+ 'base/keygen_handler_nss.cc',
'base/nss_memio.c',
'base/nss_memio.h',
'base/x509_certificate_nss.cc',
diff --git a/webkit/api/public/WebKitClient.h b/webkit/api/public/WebKitClient.h
index 905355f..9d742a3 100644
--- a/webkit/api/public/WebKitClient.h
+++ b/webkit/api/public/WebKitClient.h
@@ -147,6 +147,15 @@ namespace WebKit {
// Returns the size of the given database file
virtual long long databaseGetFileSize(const WebString& fileName) = 0;
+ // Keygen --------------------------------------------------------------
+
+ // Handle the <keygen> tag for generating client certificates
+ // Returns a base64 encoded signed copy of a public key from a newly
+ // generated key pair and the supplied challenge string. keySizeindex
+ // specifies the strength of the key.
+ virtual WebString signedPublicKeyAndChallengeString(unsigned keySizeIndex,
+ const WebKit::WebString& challenge,
+ const WebKit::WebURL& url) = 0;
// Message Ports -------------------------------------------------------
diff --git a/webkit/api/src/ChromiumBridge.cpp b/webkit/api/src/ChromiumBridge.cpp
index e227683..ab8393c 100644
--- a/webkit/api/src/ChromiumBridge.cpp
+++ b/webkit/api/src/ChromiumBridge.cpp
@@ -269,8 +269,9 @@ long long ChromiumBridge::databaseGetFileSize(const String& fileName)
String ChromiumBridge::signedPublicKeyAndChallengeString(
unsigned keySizeIndex, const String& challenge, const KURL& url)
{
- notImplemented();
- return String();
+ return webKitClient()->signedPublicKeyAndChallengeString(keySizeIndex,
+ WebString(challenge),
+ WebURL(url));
}
// Language -------------------------------------------------------------------
diff --git a/webkit/glue/webkitclient_impl.cc b/webkit/glue/webkitclient_impl.cc
index c549dab..b45c37a 100644
--- a/webkit/glue/webkitclient_impl.cc
+++ b/webkit/glue/webkitclient_impl.cc
@@ -332,6 +332,14 @@ long long WebKitClientImpl::databaseGetFileSize(
return 0;
}
+WebKit::WebString WebKitClientImpl::signedPublicKeyAndChallengeString(
+ unsigned key_size_index,
+ const WebKit::WebString& challenge,
+ const WebKit::WebURL& url) {
+ NOTREACHED();
+ return WebKit::WebString();
+}
+
bool WebKitClientImpl::fileExists(const WebKit::WebString& path) {
FilePath::StringType file_path = webkit_glue::WebStringToFilePathString(path);
return file_util::PathExists(FilePath(file_path));
diff --git a/webkit/glue/webkitclient_impl.h b/webkit/glue/webkitclient_impl.h
index 9686730..e6f5c42 100644
--- a/webkit/glue/webkitclient_impl.h
+++ b/webkit/glue/webkitclient_impl.h
@@ -52,6 +52,10 @@ class WebKitClientImpl : public WebKit::WebKitClient {
virtual long databaseGetFileAttributes(const WebKit::WebString& file_name);
virtual long long databaseGetFileSize(const WebKit::WebString& file_name);
+ virtual WebKit::WebString signedPublicKeyAndChallengeString(
+ unsigned key_size_index, const WebKit::WebString& challenge,
+ const WebKit::WebURL& url);
+
virtual bool fileExists(const WebKit::WebString& path);
virtual bool deleteFile(const WebKit::WebString& path);
virtual bool deleteEmptyDirectory(const WebKit::WebString& path);