diff options
author | snej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-02 17:47:02 +0000 |
---|---|---|
committer | snej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-02 17:47:02 +0000 |
commit | cdafbff7b3e83702c20b0f754a6d27159b78c06c (patch) | |
tree | 5b66619f7822e7189e8cc3287365ed49808d3c72 /chrome | |
parent | 078a10a1c64458e5f5c4fdf57edbbc935dd145ca (diff) | |
download | chromium_src-cdafbff7b3e83702c20b0f754a6d27159b78c06c.zip chromium_src-cdafbff7b3e83702c20b0f754a6d27159b78c06c.tar.gz chromium_src-cdafbff7b3e83702c20b0f754a6d27159b78c06c.tar.bz2 |
Mac: implement <keygen> support, including adding generated cert to the Keychain.
BUG=34607
TEST=KeygenHandlerTest.SmokeTest
Review URL: http://codereview.chromium.org/652137
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40387 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/app/generated_resources.grd | 14 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 21 | ||||
-rw-r--r-- | chrome/browser/renderer_host/x509_user_cert_resource_handler.cc | 14 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_add_cert_handler.cc | 69 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_add_cert_handler.h | 50 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_add_cert_handler_mac.mm | 88 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 3 |
7 files changed, 251 insertions, 8 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 6ba6970..bc8b8c1 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -2941,6 +2941,20 @@ each locale. --> &View </message> + <!-- Add Client Certificate Dialog --> + <message name="IDS_ADD_CERT_DIALOG_ADD" desc="Title of the button that adds the certificate in the Add Client Certificate dialog"> + Add Certificate + </message> + <message name="IDS_ADD_CERT_FAILURE_TITLE" desc="Title of add-certificate error dialog"> + Client Certificate Error + </message> + <message name="IDS_ADD_CERT_ERR_INVALID_CERT" desc="Error message when the server returns an invalid client certificate after key generation"> + The server returned an invalid client certificate. + </message> + <message name="IDS_ADD_CERT_ERR_FAILED" desc="Generic error message for a failure to add the generated certificate to the cert store/keychain"> + There was an error while trying to store the client certificate. + </message> + <!-- Basic Auth Dialog --> <message name="IDS_LOGIN_DIALOG_TITLE" desc="String to be displayed in the title bar of the login prompt dialog"> Authentication Required diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index b7c75e4..94f60a8 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -1332,10 +1332,23 @@ 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(); + // Map displayed strings indicating level of keysecurity in the <keygen> + // menu to the key size in bits. (See SSLKeyGeneratorChromium.cpp in WebCore.) + int key_size_in_bits; + switch (key_size_index) { + case 0: + key_size_in_bits = 2048; + break; + case 1: + key_size_in_bits = 1024; + break; + default: + DCHECK(false) << "Illegal key_size_index " << key_size_index; + *signed_public_key = std::string(); + return; + } + net::KeygenHandler keygen_handler(key_size_in_bits, challenge_string); + *signed_public_key = keygen_handler.GenKeyAndSignChallenge(); } void ResourceMessageFilter::OnTranslateText( diff --git a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc index 0c200a9..3dcc8ee 100644 --- a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc +++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc @@ -10,9 +10,9 @@ #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/browser/ssl/ssl_add_cert_handler.h" #include "chrome/common/resource_response.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" @@ -91,12 +91,18 @@ bool X509UserCertResourceHandler::OnResponseCompleted( int request_id, const URLRequestStatus& urs, const std::string& sec_info) { + if (urs.status() != URLRequestStatus::SUCCESS) + return false; + // 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_); + scoped_refptr<net::X509Certificate> cert = + net::X509Certificate::CreateFromBytes(resource_buffer_->data(), + content_length_); + // The handler will run the UI and delete itself when it's finished. + new SSLAddCertHandler(request_, cert); + return true; } void X509UserCertResourceHandler::OnRequestClosed() { diff --git a/chrome/browser/ssl/ssl_add_cert_handler.cc b/chrome/browser/ssl/ssl_add_cert_handler.cc new file mode 100644 index 0000000..8c75d7d --- /dev/null +++ b/chrome/browser/ssl/ssl_add_cert_handler.cc @@ -0,0 +1,69 @@ +// 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 "chrome/browser/ssl/ssl_add_cert_handler.h" + +#include "app/l10n_util.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/platform_util.h" +#include "grit/generated_resources.h" +#include "net/base/cert_database.h" +#include "net/base/net_errors.h" +#include "net/base/x509_certificate.h" +#include "net/url_request/url_request.h" + +SSLAddCertHandler::SSLAddCertHandler(URLRequest* request, + net::X509Certificate* cert) + : cert_(cert) { + // Stay alive until the UI completes and Finished() is called. + AddRef(); + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &SSLAddCertHandler::RunUI)); +} + +void SSLAddCertHandler::RunUI() { + int cert_error; + { + net::CertDatabase db; + cert_error = db.CheckUserCert(cert_); + } + if (cert_error != net::OK) { + // TODO(snej): Map cert_error to a more specific error message. + ShowError(l10n_util::GetStringUTF16(IDS_ADD_CERT_ERR_INVALID_CERT)); + Finished(false); + return; + } + AskToAddCert(); +} + +#if !defined(OS_MACOSX) +void SSLAddCertHandler::AskToAddCert() { + // TODO(snej): Someone should add Windows and GTK implementations with UI. + Finished(true); +} +#endif + +void SSLAddCertHandler::Finished(bool add_cert) { + if (add_cert) { + net::CertDatabase db; + int cert_error = db.AddUserCert(cert_); + if (cert_error != net::OK) { + // TODO(snej): Map cert_error to a more specific error message. + ShowError(l10n_util::GetStringUTF16(IDS_ADD_CERT_ERR_FAILED)); + } + } + Release(); +} + +void SSLAddCertHandler::ShowError(const string16& error) { + Browser* browser = BrowserList::GetLastActive(); + platform_util::SimpleErrorBox( + browser ? browser->window()->GetNativeHandle() : NULL, + l10n_util::GetStringUTF16(IDS_ADD_CERT_FAILURE_TITLE), + error); +} diff --git a/chrome/browser/ssl/ssl_add_cert_handler.h b/chrome/browser/ssl/ssl_add_cert_handler.h new file mode 100644 index 0000000..0680128 --- /dev/null +++ b/chrome/browser/ssl/ssl_add_cert_handler.h @@ -0,0 +1,50 @@ +// 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 CHROME_BROWSER_SSL_SSL_ADD_CERT_HANDLER_H_ +#define CHROME_BROWSER_SSL_SSL_ADD_CERT_HANDLER_H_ + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/string16.h" + +namespace net { +class X509Certificate; +} +class URLRequest; + +// This class handles adding a newly-generated client cert. It ensures there's a +// private key for the cert, displays the cert to the user, and adds it upon +// user approval. +// It is self-owned and deletes itself when finished. +class SSLAddCertHandler : public base::RefCountedThreadSafe<SSLAddCertHandler> { + public: + SSLAddCertHandler(URLRequest* request, net::X509Certificate* cert); + + net::X509Certificate* cert() { return cert_; } + + // The platform-specific code calls this when it's done, to clean up. + // If |addCert| is true, the cert will be added to the CertDatabase. + void Finished(bool add_cert); + + private: + friend class base::RefCountedThreadSafe<SSLAddCertHandler>; + + // Runs the user interface. Called on the UI thread. Calls AskToAddCert. + void RunUI(); + + // Platform-specific code that asks the user whether to add the cert. + // Called on the UI thread. + void AskToAddCert(); + + // Utility to display an error message in a dialog box. + void ShowError(const string16& error); + + // The cert to add. + scoped_refptr<net::X509Certificate> cert_; + + DISALLOW_COPY_AND_ASSIGN(SSLAddCertHandler); +}; + +#endif // CHROME_BROWSER_SSL_SSL_ADD_CERT_HANDLER_H_ diff --git a/chrome/browser/ssl/ssl_add_cert_handler_mac.mm b/chrome/browser/ssl/ssl_add_cert_handler_mac.mm new file mode 100644 index 0000000..75b8142 --- /dev/null +++ b/chrome/browser/ssl/ssl_add_cert_handler_mac.mm @@ -0,0 +1,88 @@ +// 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 "ssl_add_cert_handler.h" + +#include <SecurityInterface/SFCertificatePanel.h> +#include <SecurityInterface/SFCertificateView.h> + +#include "app/l10n_util_mac.h" +#include "base/scoped_nsobject.h" +#include "chrome/common/logging_chrome.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" +#include "grit/generated_resources.h" +#include "net/base/x509_certificate.h" + +@interface SSLAddCertHandlerCocoa : NSObject +{ + scoped_refptr<SSLAddCertHandler> handler_; +} + +- (id)initWithHandler:(SSLAddCertHandler*)handler; +- (void)askToAddCert; +@end + + +void SSLAddCertHandler::AskToAddCert() { + [[[SSLAddCertHandlerCocoa alloc] initWithHandler: this] askToAddCert]; + // The new object will release itself when the sheet ends. +} + + +// The actual implementation of the add-client-cert handler is an Obj-C class. +@implementation SSLAddCertHandlerCocoa + +- (id)initWithHandler:(SSLAddCertHandler*)handler { + DCHECK(handler && handler->cert()); + self = [super init]; + if (self) { + handler_ = handler; + } + return self; +} + +- (void)sheetDidEnd:(SFCertificatePanel*)panel + returnCode:(NSInteger)returnCode + context:(void*)context { + [panel orderOut:self]; + [panel autorelease]; + handler_->Finished(returnCode == NSOKButton); + [self release]; +} + +- (void)askToAddCert { + NSWindow* parentWindow = NULL; + Browser* browser = BrowserList::GetLastActive(); + // TODO(snej): Can I get the Browser that issued the request? + if (browser) { + parentWindow = browser->window()->GetNativeHandle(); + if ([parentWindow attachedSheet]) + parentWindow = nil; + } + + // Create the cert panel, which will be released in my -sheetDidEnd: method. + SFCertificatePanel* panel = [[SFCertificatePanel alloc] init]; + [panel setDefaultButtonTitle:l10n_util::GetNSString(IDS_ADD_CERT_DIALOG_ADD)]; + [panel setAlternateButtonTitle:l10n_util::GetNSString(IDS_CANCEL)]; + SecCertificateRef cert = handler_->cert()->os_cert_handle(); + NSArray* certs = [NSArray arrayWithObject: (id)cert]; + + if (parentWindow) { + // Open the cert panel as a sheet on the browser window. + [panel beginSheetForWindow:parentWindow + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:context:) + contextInfo:NULL + certificates:certs + showGroup:NO]; + } else { + // No available browser window, so run independently as a (blocking) dialog. + int returnCode = [panel runModalForCertificates:certs showGroup:NO]; + [self sheetDidEnd:panel returnCode:returnCode context:NULL]; + } +} + +@end diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index fe76e2e..001b67a 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1746,6 +1746,9 @@ 'browser/spellchecker_mac.mm', 'browser/spellchecker_platform_engine.h', 'browser/spellchecker_win.cc', + 'browser/ssl/ssl_add_cert_handler.cc', + 'browser/ssl/ssl_add_cert_handler.h', + 'browser/ssl/ssl_add_cert_handler_mac.mm', 'browser/ssl/ssl_blocking_page.cc', 'browser/ssl/ssl_blocking_page.h', 'browser/ssl/ssl_cert_error_handler.cc', |