From 1f18184a07252103a8cd9652d64de749f41ef09f Mon Sep 17 00:00:00 2001 From: "davidben@chromium.org" Date: Wed, 21 Jul 2010 19:34:49 +0000 Subject: Refactor SSLClientAuthHandler and certificate selection This cleans up much of the code involved in displaying a certificate selection dialog to the user. - Adds a new inner class to RenderViewHostDelegate (later to be populated with more SSL things). - Adds a helper class for TabContents' implementation. - Moves the certificate dialogs themselves to have a common entry point. - Makes SSLClientAuthHandler call the RVHDelegate to query the user, with the TabContents implementation displaying the dialogs. - Picks the correct parent window for the dialog on all platforms, instead of relying on BrowserList::GetLastActive - Makes the OS X implementation use an asynchronous sheet, now that we know the parent. - Fixes an index-mismatch problem in the OS X implementation, should we fail to create an identity. R=agl,brettw,mark BUG=148 TEST=selecting client certificates still works Review URL: http://codereview.chromium.org/2823038 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53231 0039d316-1c4b-4281-b951-d872f2087c98 --- .../cocoa/ssl_client_certificate_selector.mm | 145 +++++++++ .../browser/gtk/ssl_client_certificate_selector.cc | 339 +++++++++++++++++++++ .../renderer_host/render_view_host_delegate.cc | 5 + .../renderer_host/render_view_host_delegate.h | 14 + .../render_view_host_notification_task.h | 54 ++++ chrome/browser/ssl/ssl_client_auth_handler.cc | 50 +-- chrome/browser/ssl/ssl_client_auth_handler.h | 14 +- chrome/browser/ssl/ssl_client_auth_handler_gtk.cc | 330 -------------------- chrome/browser/ssl/ssl_client_auth_handler_mac.mm | 63 ---- chrome/browser/ssl/ssl_client_auth_handler_win.cc | 58 ---- chrome/browser/ssl_client_certificate_selector.h | 30 ++ chrome/browser/tab_contents/tab_contents.cc | 11 + chrome/browser/tab_contents/tab_contents.h | 8 + .../tab_contents/tab_contents_ssl_helper.cc | 24 ++ .../browser/tab_contents/tab_contents_ssl_helper.h | 28 ++ .../views/ssl_client_certificate_selector_win.cc | 61 ++++ 16 files changed, 756 insertions(+), 478 deletions(-) create mode 100644 chrome/browser/cocoa/ssl_client_certificate_selector.mm create mode 100644 chrome/browser/gtk/ssl_client_certificate_selector.cc delete mode 100644 chrome/browser/ssl/ssl_client_auth_handler_gtk.cc delete mode 100644 chrome/browser/ssl/ssl_client_auth_handler_mac.mm delete mode 100644 chrome/browser/ssl/ssl_client_auth_handler_win.cc create mode 100644 chrome/browser/ssl_client_certificate_selector.h create mode 100644 chrome/browser/tab_contents/tab_contents_ssl_helper.cc create mode 100644 chrome/browser/tab_contents/tab_contents_ssl_helper.h create mode 100644 chrome/browser/views/ssl_client_certificate_selector_win.cc (limited to 'chrome/browser') diff --git a/chrome/browser/cocoa/ssl_client_certificate_selector.mm b/chrome/browser/cocoa/ssl_client_certificate_selector.mm new file mode 100644 index 0000000..3f057af --- /dev/null +++ b/chrome/browser/cocoa/ssl_client_certificate_selector.mm @@ -0,0 +1,145 @@ +// 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_client_certificate_selector.h" + +#import + +#include + +#import "app/l10n_util_mac.h" +#include "base/logging.h" +#include "base/ref_counted.h" +#include "base/scoped_cftyperef.h" +#import "base/scoped_nsobject.h" +#include "base/string_util.h" +#include "base/sys_string_conversions.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/ssl/ssl_client_auth_handler.h" +#include "grit/generated_resources.h" +#include "net/base/x509_certificate.h" + +@interface SSLClientCertificateSelectorCocoa : NSObject { + @private + // The handler to report back to. + scoped_refptr handler_; + // The certificate request we serve. + scoped_refptr certRequestInfo_; + // The list of identities offered to the user. + scoped_nsobject identities_; + // The corresponding list of certificates. + std::vector > certificates_; + // The panel we display. + scoped_nsobject panel_; +} + +- (id)initWithHandler:(SSLClientAuthHandler*)handler + certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo; +- (void)displayDialog:(gfx::NativeWindow)parent; +@end + +namespace browser { + +void ShowSSLClientCertificateSelector( + gfx::NativeWindow parent, + net::SSLCertRequestInfo* cert_request_info, + SSLClientAuthHandler* delegate) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + SSLClientCertificateSelectorCocoa* selector = + [[[SSLClientCertificateSelectorCocoa alloc] + initWithHandler:delegate + certRequestInfo:cert_request_info] autorelease]; + [selector displayDialog:parent]; +} + +} // namespace browser + +@implementation SSLClientCertificateSelectorCocoa + +- (id)initWithHandler:(SSLClientAuthHandler*)handler + certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo { + DCHECK(handler); + DCHECK(certRequestInfo); + if ((self = [super init])) { + handler_ = handler; + certRequestInfo_ = certRequestInfo; + } + return self; +} + +- (void)sheetDidEnd:(NSWindow*)parent + returnCode:(NSInteger)returnCode + context:(void*)context { + net::X509Certificate* cert = NULL; + + if (returnCode == NSFileHandlingPanelOKButton) { + NSUInteger index = [identities_ indexOfObject:(id)[panel_ identity]]; + DCHECK(index != NSNotFound); + cert = certificates_[index]; + } + + // Finally, tell the backend which identity (or none) the user selected. + handler_->CertificateSelected(cert); + // Clean up. The retain occurred just before the sheet opened. + [self release]; +} + +- (void)displayDialog:(gfx::NativeWindow)parent { + DCHECK(!panel_.get()); + // Create an array of CFIdentityRefs for the certificates: + size_t numCerts = certRequestInfo_->client_certs.size(); + identities_.reset([[NSMutableArray alloc] initWithCapacity:numCerts]); + for (size_t i = 0; i < numCerts; ++i) { + SecCertificateRef cert; + cert = certRequestInfo_->client_certs[i]->os_cert_handle(); + SecIdentityRef identity; + if (SecIdentityCreateWithCertificate(NULL, cert, &identity) == noErr) { + [identities_ addObject:(id)identity]; + CFRelease(identity); + certificates_.push_back(certRequestInfo_->client_certs[i]); + } + } + + // Get the message to display: + NSString* title = l10n_util::GetNSString(IDS_CLIENT_CERT_DIALOG_TITLE); + NSString* message = l10n_util::GetNSStringF( + IDS_CLIENT_CERT_DIALOG_TEXT, + ASCIIToUTF16(certRequestInfo_->host_and_port)); + + // Create and set up a system choose-identity panel. + panel_.reset([[SFChooseIdentityPanel alloc] init]); + NSString* domain = base::SysUTF8ToNSString( + "https://" + certRequestInfo_->host_and_port); + // Setting the domain causes the dialog to record the preferred + // identity in the system keychain. + [panel_ setDomain:domain]; + [panel_ setInformativeText:message]; + [panel_ setDefaultButtonTitle:l10n_util::GetNSString(IDS_OK)]; + [panel_ setAlternateButtonTitle:l10n_util::GetNSString(IDS_CANCEL)]; + SecPolicyRef sslPolicy; + if (net::X509Certificate::CreateSSLClientPolicy(&sslPolicy) == noErr) { + [panel_ setPolicies:(id)sslPolicy]; + CFRelease(sslPolicy); + } + + // Increase the retain count to keep |self| alive while the sheet + // runs. -sheetDidEnd:returnCode:context: will release the + // additional reference. + [self retain]; + if (parent) { + // Open the cert panel as a sheet on the browser window. + [panel_ beginSheetForWindow:parent + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:context:) + contextInfo:nil + identities:identities_ + message:title]; + } else { + // No available browser window, so run independently as a (blocking) dialog. + int returnCode = [panel_ runModalForIdentities:identities_ message:title]; + [self sheetDidEnd:panel_ returnCode:returnCode context:nil]; + } +} + +@end diff --git a/chrome/browser/gtk/ssl_client_certificate_selector.cc b/chrome/browser/gtk/ssl_client_certificate_selector.cc new file mode 100644 index 0000000..b7c3f5f --- /dev/null +++ b/chrome/browser/gtk/ssl_client_certificate_selector.cc @@ -0,0 +1,339 @@ +// 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_client_certificate_selector.h" + +#include +#include + +#include +#include + +#include "app/l10n_util.h" +#include "base/i18n/time_formatting.h" +#include "base/logging.h" +#include "base/nss_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/certificate_viewer.h" +#include "chrome/browser/gtk/gtk_util.h" +#include "chrome/browser/ssl/ssl_client_auth_handler.h" +#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h" +#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h" +#include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h" +#include "gfx/native_widget_types.h" +#include "grit/generated_resources.h" +#include "net/base/x509_certificate.h" + +// PSM = Mozilla's Personal Security Manager. +namespace psm = mozilla_security_manager; + +namespace { + +enum { + RESPONSE_SHOW_CERT_INFO = 1, +}; + + +/////////////////////////////////////////////////////////////////////////////// +// SSLClientCertificateSelector + +class SSLClientCertificateSelector { + public: + SSLClientCertificateSelector(gfx::NativeWindow parent, + net::SSLCertRequestInfo* cert_request_info, + SSLClientAuthHandler* delegate); + + void Show(); + + private: + void PopulateCerts(); + + static std::string FormatComboBoxText(CERTCertificate* cert, + const char* nickname); + static std::string FormatDetailsText(CERTCertificate* cert); + + static void OnComboBoxChanged(GtkComboBox* combo_box, + SSLClientCertificateSelector* cert_selector); + static void OnResponse(GtkDialog* dialog, gint response_id, + SSLClientCertificateSelector* cert_selector); + static void OnDestroy(GtkDialog* dialog, + SSLClientCertificateSelector* cert_selector); + + scoped_refptr delegate_; + scoped_refptr cert_request_info_; + + std::vector details_strings_; + + GtkWidget* dialog_; + GtkWidget* cert_combo_box_; + GtkTextBuffer* cert_details_buffer_; +}; + +SSLClientCertificateSelector::SSLClientCertificateSelector( + gfx::NativeWindow parent, + net::SSLCertRequestInfo* cert_request_info, + SSLClientAuthHandler* delegate) + : delegate_(delegate), + cert_request_info_(cert_request_info) { + dialog_ = gtk_dialog_new_with_buttons( + l10n_util::GetStringFUTF8( + IDS_CERT_SELECTOR_DIALOG_TITLE, + UTF8ToUTF16(cert_request_info->host_and_port)).c_str(), + parent, + // Non-modal. + GTK_DIALOG_NO_SEPARATOR, + l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str(), + RESPONSE_SHOW_CERT_INFO, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), + gtk_util::kContentAreaSpacing); + gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK); + + GtkWidget* site_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), site_vbox, + FALSE, FALSE, 0); + + GtkWidget* site_description_label = gtk_util::CreateBoldLabel( + l10n_util::GetStringUTF8(IDS_CERT_SELECTOR_SITE_DESCRIPTION_LABEL)); + gtk_box_pack_start(GTK_BOX(site_vbox), site_description_label, + FALSE, FALSE, 0); + + GtkWidget* site_label = gtk_label_new( + cert_request_info->host_and_port.c_str()); + gtk_util::LeftAlignMisc(site_label); + gtk_box_pack_start(GTK_BOX(site_vbox), site_label, FALSE, FALSE, 0); + + GtkWidget* selector_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), selector_vbox, + TRUE, TRUE, 0); + + GtkWidget* choose_description_label = gtk_util::CreateBoldLabel( + l10n_util::GetStringUTF8(IDS_CERT_SELECTOR_CHOOSE_DESCRIPTION_LABEL)); + gtk_box_pack_start(GTK_BOX(selector_vbox), choose_description_label, + FALSE, FALSE, 0); + + + cert_combo_box_ = gtk_combo_box_new_text(); + g_signal_connect(cert_combo_box_, "changed", G_CALLBACK(OnComboBoxChanged), + this); + gtk_box_pack_start(GTK_BOX(selector_vbox), cert_combo_box_, + FALSE, FALSE, 0); + + GtkWidget* details_label = gtk_label_new(l10n_util::GetStringUTF8( + IDS_CERT_SELECTOR_DETAILS_DESCRIPTION_LABEL).c_str()); + gtk_util::LeftAlignMisc(details_label); + gtk_box_pack_start(GTK_BOX(selector_vbox), details_label, FALSE, FALSE, 0); + + // TODO(mattm): fix text view coloring (should have grey background). + GtkWidget* cert_details_view = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(cert_details_view), FALSE); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(cert_details_view), GTK_WRAP_WORD); + cert_details_buffer_ = gtk_text_view_get_buffer( + GTK_TEXT_VIEW(cert_details_view)); + // We put the details in a frame instead of a scrolled window so that the + // entirety will be visible without requiring scrolling or expanding the + // dialog. This does however mean the dialog will grow itself if you switch + // to different cert that has longer details text. + GtkWidget* details_frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(details_frame), GTK_SHADOW_ETCHED_IN); + gtk_container_add(GTK_CONTAINER(details_frame), cert_details_view); + gtk_box_pack_start(GTK_BOX(selector_vbox), details_frame, TRUE, TRUE, 0); + + PopulateCerts(); + + g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); + g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); +} + +void SSLClientCertificateSelector::Show() { + gtk_widget_show_all(dialog_); +} + +void SSLClientCertificateSelector::PopulateCerts() { + CERTCertList* cert_list = CERT_NewCertList(); + for (size_t i = 0; i < cert_request_info_->client_certs.size(); ++i) { + CERT_AddCertToListTail( + cert_list, + CERT_DupCertificate( + cert_request_info_->client_certs[i]->os_cert_handle())); + } + // Would like to use CERT_GetCertNicknameWithValidity on each cert + // individually instead of having to build a CERTCertList for this, but that + // function is not exported. + CERTCertNicknames* nicknames = CERT_NicknameStringsFromCertList( + cert_list, + const_cast(l10n_util::GetStringUTF8( + IDS_CERT_SELECTOR_CERT_EXPIRED).c_str()), + const_cast(l10n_util::GetStringUTF8( + IDS_CERT_SELECTOR_CERT_NOT_YET_VALID).c_str())); + DCHECK_EQ(nicknames->numnicknames, + static_cast(cert_request_info_->client_certs.size())); + + for (size_t i = 0; i < cert_request_info_->client_certs.size(); ++i) { + CERTCertificate* cert = + cert_request_info_->client_certs[i]->os_cert_handle(); + + details_strings_.push_back(FormatDetailsText(cert)); + + gtk_combo_box_append_text( + GTK_COMBO_BOX(cert_combo_box_), + FormatComboBoxText(cert, nicknames->nicknames[i]).c_str()); + } + + CERT_FreeNicknames(nicknames); + CERT_DestroyCertList(cert_list); + + // Auto-select the first cert. + gtk_combo_box_set_active(GTK_COMBO_BOX(cert_combo_box_), 0); +} + +// static +std::string SSLClientCertificateSelector::FormatComboBoxText( + CERTCertificate* cert, const char* nickname) { + std::string rv(nickname); + char* serial_hex = CERT_Hexify(&cert->serialNumber, TRUE); + rv += " ["; + rv += serial_hex; + rv += ']'; + PORT_Free(serial_hex); + return rv; +} + +// static +std::string SSLClientCertificateSelector::FormatDetailsText( + CERTCertificate* cert) { + std::string rv; + + rv += l10n_util::GetStringFUTF8(IDS_CERT_SUBJECTNAME_FORMAT, + UTF8ToUTF16(cert->subjectName)); + + char* serial_hex = CERT_Hexify(&cert->serialNumber, TRUE); + rv += "\n "; + rv += l10n_util::GetStringFUTF8(IDS_CERT_SERIAL_NUMBER_FORMAT, + UTF8ToUTF16(serial_hex)); + PORT_Free(serial_hex); + + PRTime issued, expires; + if (CERT_GetCertTimes(cert, &issued, &expires) == SECSuccess) { + string16 issued_str = WideToUTF16( + base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(issued))); + string16 expires_str = WideToUTF16( + base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(expires))); + rv += "\n "; + rv += l10n_util::GetStringFUTF8(IDS_CERT_VALIDITY_RANGE_FORMAT, + issued_str, expires_str); + } + + std::vector usages; + psm::GetCertUsageStrings(cert, &usages); + if (usages.size()) { + rv += "\n "; + rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_EXTENDED_KEY_USAGE_FORMAT, + UTF8ToUTF16(JoinString(usages, ','))); + } + + SECItem key_usage; + key_usage.data = NULL; + if (CERT_FindKeyUsageExtension(cert, &key_usage) == SECSuccess) { + std::string key_usage_str = psm::ProcessKeyUsageBitString(&key_usage, ','); + PORT_Free(key_usage.data); + if (!key_usage_str.empty()) { + rv += "\n "; + rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_KEY_USAGE_FORMAT, + UTF8ToUTF16(key_usage_str)); + } + } + + std::vector email_addresses; + for (const char* addr = CERT_GetFirstEmailAddress(cert); + addr; addr = CERT_GetNextEmailAddress(cert, addr)) { + // The first email addr (from Subject) may be duplicated in Subject + // Alternative Name, so check subsequent addresses are not equal to the + // first one before adding to the list. + if (!email_addresses.size() || email_addresses[0] != addr) + email_addresses.push_back(addr); + } + if (email_addresses.size()) { + rv += "\n "; + rv += l10n_util::GetStringFUTF8( + IDS_CERT_EMAIL_ADDRESSES_FORMAT, + UTF8ToUTF16(JoinString(email_addresses, ','))); + } + + rv += '\n'; + rv += l10n_util::GetStringFUTF8(IDS_CERT_ISSUERNAME_FORMAT, + UTF8ToUTF16(cert->issuerName)); + + string16 token(UTF8ToUTF16(psm::GetCertTokenName(cert))); + if (!token.empty()) { + rv += '\n'; + rv += l10n_util::GetStringFUTF8(IDS_CERT_TOKEN_FORMAT, token); + } + + return rv; +} + +// static +void SSLClientCertificateSelector::OnComboBoxChanged( + GtkComboBox* combo_box, SSLClientCertificateSelector* cert_selector) { + int selected = gtk_combo_box_get_active( + GTK_COMBO_BOX(cert_selector->cert_combo_box_)); + if (selected < 0) + return; + gtk_text_buffer_set_text(cert_selector->cert_details_buffer_, + cert_selector->details_strings_[selected].c_str(), + cert_selector->details_strings_[selected].size()); +} + +// static +void SSLClientCertificateSelector::OnResponse( + GtkDialog* dialog, gint response_id, + SSLClientCertificateSelector* cert_selector) { + net::X509Certificate* cert = NULL; + if (response_id == GTK_RESPONSE_OK || + response_id == RESPONSE_SHOW_CERT_INFO) { + int selected = gtk_combo_box_get_active( + GTK_COMBO_BOX(cert_selector->cert_combo_box_)); + if (selected >= 0 && + selected < static_cast( + cert_selector->cert_request_info_->client_certs.size())) + cert = cert_selector->cert_request_info_->client_certs[selected]; + } + if (response_id == RESPONSE_SHOW_CERT_INFO) { + if (cert) + ShowCertificateViewer(GTK_WINDOW(cert_selector->dialog_), cert); + return; + } + cert_selector->delegate_->CertificateSelected(cert); + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +// static +void SSLClientCertificateSelector::OnDestroy( + GtkDialog* dialog, + SSLClientCertificateSelector* cert_selector) { + delete cert_selector; +} + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// SSLClientAuthHandler platform specific implementation: + +namespace browser { + +void ShowSSLClientCertificateSelector( + gfx::NativeWindow parent, + net::SSLCertRequestInfo* cert_request_info, + SSLClientAuthHandler* delegate) { + (new SSLClientCertificateSelector(parent, + cert_request_info, + delegate))->Show(); +} + +} // namespace browser diff --git a/chrome/browser/renderer_host/render_view_host_delegate.cc b/chrome/browser/renderer_host/render_view_host_delegate.cc index 11f6168fc..1396368 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.cc +++ b/chrome/browser/renderer_host/render_view_host_delegate.cc @@ -68,6 +68,11 @@ RenderViewHostDelegate::GetBookmarkDragDelegate() { return NULL; } +RenderViewHostDelegate::SSL* +RenderViewHostDelegate::GetSSLDelegate() { + return NULL; +} + AutomationResourceRoutingDelegate* RenderViewHostDelegate::GetAutomationResourceRoutingDelegate() { return NULL; diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index 36b7a93..5817176 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -9,6 +9,7 @@ #include #include "base/basictypes.h" +#include "base/ref_counted.h" #include "base/string16.h" #include "chrome/common/content_settings_types.h" #include "chrome/common/translate_errors.h" @@ -37,6 +38,7 @@ class RenderViewHost; class ResourceRedirectDetails; class ResourceRequestDetails; class SkBitmap; +class SSLClientAuthHandler; class TabContents; struct ThumbnailScore; struct ViewHostMsg_DidPrintPage_Params; @@ -493,6 +495,17 @@ class RenderViewHostDelegate { virtual void OnDrop(const BookmarkDragData& data) = 0; }; + // SSL ----------------------------------------------------------------------- + // Interface for UI and other RenderViewHost-specific interactions with SSL. + + class SSL { + public: + // Displays a dialog to select client certificates from |request_info|, + // returning them to |handler|. + virtual void ShowClientCertificateRequestDialog( + scoped_refptr handler) = 0; + }; + // --------------------------------------------------------------------------- // Returns the current delegate associated with a feature. May return NULL if @@ -508,6 +521,7 @@ class RenderViewHostDelegate { virtual Autocomplete* GetAutocompleteDelegate(); virtual AutoFill* GetAutoFillDelegate(); virtual BookmarkDrag* GetBookmarkDragDelegate(); + virtual SSL* GetSSLDelegate(); // Return the delegate for registering RenderViewHosts for automation resource // routing. diff --git a/chrome/browser/renderer_host/render_view_host_notification_task.h b/chrome/browser/renderer_host/render_view_host_notification_task.h index c1d732a..1266922 100644 --- a/chrome/browser/renderer_host/render_view_host_notification_task.h +++ b/chrome/browser/renderer_host/render_view_host_notification_task.h @@ -147,6 +147,32 @@ inline void CallRenderViewHostRendererManagementDelegateHelper( params)); } +// For proxying calls to RenderViewHostDelegate::SSL + +class RenderViewHostToSSLDelegate { + public: + typedef RenderViewHostDelegate::SSL MappedType; + static MappedType* Map(RenderViewHost* rvh) { + return rvh ? rvh->delegate()->GetSSLDelegate() : NULL; + } +}; + +template +inline void CallRenderViewHostSSLDelegateHelper( + int render_process_id, + int render_view_id, + Method method, + const Params& params) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + new RenderViewHostNotificationTask< + Method, Params, RenderViewHostToSSLDelegate>( + render_process_id, + render_view_id, + method, + params)); +} + } // namespace internal // ---------------------------------------------------------------------------- @@ -310,5 +336,33 @@ inline void CallRenderViewHostRendererManagementDelegate(int render_process_id, } // ---------------------------------------------------------------------------- +// Proxy calls to the specified RenderViewHost's SSL delegate. + +template +inline void CallRenderViewHostSSLDelegate(int render_process_id, + int render_view_id, + Method method, + const A& a) { + internal::CallRenderViewHostSSLDelegateHelper( + render_process_id, + render_view_id, + method, + MakeTuple(a)); +} + +template +inline void CallRenderViewHostSSLDelegate(int render_process_id, + int render_view_id, + Method method, + const A& a, + const B& b) { + internal::CallRenderViewHostSSLDelegateHelper( + render_process_id, + render_view_id, + method, + MakeTuple(a, b)); +} + +// ---------------------------------------------------------------------------- #endif // CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_NOTIFICATION_TASK_H_ diff --git a/chrome/browser/ssl/ssl_client_auth_handler.cc b/chrome/browser/ssl/ssl_client_auth_handler.cc index f46c6f3..74b25bf 100644 --- a/chrome/browser/ssl/ssl_client_auth_handler.cc +++ b/chrome/browser/ssl/ssl_client_auth_handler.cc @@ -4,13 +4,10 @@ #include "chrome/browser/ssl/ssl_client_auth_handler.h" -#include "app/l10n_util.h" -#include "base/string_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 "grit/generated_resources.h" +#include "chrome/browser/renderer_host/render_view_host_delegate.h" +#include "chrome/browser/renderer_host/render_view_host_notification_task.h" +#include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "net/url_request/url_request.h" SSLClientAuthHandler::SSLClientAuthHandler( @@ -18,11 +15,11 @@ SSLClientAuthHandler::SSLClientAuthHandler( net::SSLCertRequestInfo* cert_request_info) : request_(request), cert_request_info_(cert_request_info) { - // Keep us alive until a cert is selected. - AddRef(); } SSLClientAuthHandler::~SSLClientAuthHandler() { + // If we were simply dropped, then act as if we selected no certificate. + DoCertificateSelected(NULL); } void SSLClientAuthHandler::OnRequestCancelled() { @@ -30,14 +27,24 @@ void SSLClientAuthHandler::OnRequestCancelled() { } void SSLClientAuthHandler::SelectCertificate() { - // Let's move the request to the UI thread. - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - NewRunnableMethod(this, &SSLClientAuthHandler::DoSelectCertificate)); -} + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); -// Looking for DoSelectCertificate()? -// It's implemented in a separate source file for each platform. + int render_process_host_id; + int render_view_host_id; + if (!ResourceDispatcherHost::RenderViewForRequest(request_, + &render_process_host_id, + &render_view_host_id)) + NOTREACHED(); + + // If the RVH does not exist by the time this task gets run, then the task + // will be dropped and the scoped_refptr to SSLClientAuthHandler will go + // away, so we do not leak anything. The destructor takes care of ensuring + // the URLRequest always gets a response. + CallRenderViewHostSSLDelegate( + render_process_host_id, render_view_host_id, + &RenderViewHostDelegate::SSL::ShowClientCertificateRequestDialog, + scoped_refptr(this)); +} // Notify the IO thread that we have selected a cert. void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) { @@ -48,11 +55,12 @@ void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) { } void SSLClientAuthHandler::DoCertificateSelected(net::X509Certificate* cert) { - // request_ could have been NULLed if the request was cancelled while the user - // was choosing a cert. - if (request_) + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + // request_ could have been NULLed if the request was cancelled while the + // user was choosing a cert, or because we have already responded to the + // certificate. + if (request_) { request_->ContinueWithCertificate(cert); - - // We are done. - Release(); + request_ = NULL; + } } diff --git a/chrome/browser/ssl/ssl_client_auth_handler.h b/chrome/browser/ssl/ssl_client_auth_handler.h index f63d4c9..05148d5 100644 --- a/chrome/browser/ssl/ssl_client_auth_handler.h +++ b/chrome/browser/ssl/ssl_client_auth_handler.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "base/ref_counted.h" +#include "chrome/browser/chrome_thread.h" #include "net/base/ssl_cert_request_info.h" namespace net { @@ -19,7 +20,8 @@ class URLRequest; // It is self-owned and deletes itself when the UI reports the user selection or // when the URLRequest is cancelled. class SSLClientAuthHandler - : public base::RefCountedThreadSafe { + : public base::RefCountedThreadSafe { public: SSLClientAuthHandler(URLRequest* request, net::SSLCertRequestInfo* cert_request_info); @@ -38,15 +40,15 @@ class SSLClientAuthHandler // be long after DoSelectCertificate returns, if the UI is modeless/async.) void CertificateSelected(net::X509Certificate* cert); + // Returns the SSLCertRequestInfo for this handler. + net::SSLCertRequestInfo* cert_request_info() { return cert_request_info_; } + private: - friend class base::RefCountedThreadSafe; + friend class ChromeThread; + friend class DeleteTask; ~SSLClientAuthHandler(); - // Asks the user for a cert. - // Called on the UI thread. - void DoSelectCertificate(); - // Notifies that the user has selected a cert. // Called on the IO thread. void DoCertificateSelected(net::X509Certificate* cert); diff --git a/chrome/browser/ssl/ssl_client_auth_handler_gtk.cc b/chrome/browser/ssl/ssl_client_auth_handler_gtk.cc deleted file mode 100644 index 1045ef9..0000000 --- a/chrome/browser/ssl/ssl_client_auth_handler_gtk.cc +++ /dev/null @@ -1,330 +0,0 @@ -// 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_client_auth_handler.h" - -#include -#include - -#include -#include - -#include "app/l10n_util.h" -#include "base/i18n/time_formatting.h" -#include "base/logging.h" -#include "base/nss_util.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/certificate_viewer.h" -#include "chrome/browser/gtk/gtk_util.h" -#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h" -#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h" -#include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h" -#include "gfx/native_widget_types.h" -#include "grit/generated_resources.h" -#include "net/base/x509_certificate.h" - -// PSM = Mozilla's Personal Security Manager. -namespace psm = mozilla_security_manager; - -namespace { - -enum { - RESPONSE_SHOW_CERT_INFO = 1, -}; - - -/////////////////////////////////////////////////////////////////////////////// -// SSLClientCertificateSelector - -class SSLClientCertificateSelector { - public: - SSLClientCertificateSelector(gfx::NativeWindow parent, - net::SSLCertRequestInfo* cert_request_info, - SSLClientAuthHandler* delegate); - - void Show(); - - private: - void PopulateCerts(); - - static std::string FormatComboBoxText(CERTCertificate* cert, - const char* nickname); - static std::string FormatDetailsText(CERTCertificate* cert); - - static void OnComboBoxChanged(GtkComboBox* combo_box, - SSLClientCertificateSelector* cert_selector); - static void OnResponse(GtkDialog* dialog, gint response_id, - SSLClientCertificateSelector* cert_selector); - static void OnDestroy(GtkDialog* dialog, - SSLClientCertificateSelector* cert_selector); - - SSLClientAuthHandler* delegate_; - scoped_refptr cert_request_info_; - - std::vector details_strings_; - - GtkWidget* dialog_; - GtkWidget* cert_combo_box_; - GtkTextBuffer* cert_details_buffer_; -}; - -SSLClientCertificateSelector::SSLClientCertificateSelector( - gfx::NativeWindow parent, - net::SSLCertRequestInfo* cert_request_info, - SSLClientAuthHandler* delegate) - : delegate_(delegate), - cert_request_info_(cert_request_info) { - dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringFUTF8( - IDS_CERT_SELECTOR_DIALOG_TITLE, - UTF8ToUTF16(cert_request_info->host_and_port)).c_str(), - parent, - // Non-modal. - GTK_DIALOG_NO_SEPARATOR, - l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str(), - RESPONSE_SHOW_CERT_INFO, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - NULL); - gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), - gtk_util::kContentAreaSpacing); - gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK); - - GtkWidget* site_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), site_vbox, - FALSE, FALSE, 0); - - GtkWidget* site_description_label = gtk_util::CreateBoldLabel( - l10n_util::GetStringUTF8(IDS_CERT_SELECTOR_SITE_DESCRIPTION_LABEL)); - gtk_box_pack_start(GTK_BOX(site_vbox), site_description_label, - FALSE, FALSE, 0); - - GtkWidget* site_label = gtk_label_new( - cert_request_info->host_and_port.c_str()); - gtk_util::LeftAlignMisc(site_label); - gtk_box_pack_start(GTK_BOX(site_vbox), site_label, FALSE, FALSE, 0); - - GtkWidget* selector_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), selector_vbox, - TRUE, TRUE, 0); - - GtkWidget* choose_description_label = gtk_util::CreateBoldLabel( - l10n_util::GetStringUTF8(IDS_CERT_SELECTOR_CHOOSE_DESCRIPTION_LABEL)); - gtk_box_pack_start(GTK_BOX(selector_vbox), choose_description_label, - FALSE, FALSE, 0); - - - cert_combo_box_ = gtk_combo_box_new_text(); - g_signal_connect(cert_combo_box_, "changed", G_CALLBACK(OnComboBoxChanged), - this); - gtk_box_pack_start(GTK_BOX(selector_vbox), cert_combo_box_, - FALSE, FALSE, 0); - - GtkWidget* details_label = gtk_label_new(l10n_util::GetStringUTF8( - IDS_CERT_SELECTOR_DETAILS_DESCRIPTION_LABEL).c_str()); - gtk_util::LeftAlignMisc(details_label); - gtk_box_pack_start(GTK_BOX(selector_vbox), details_label, FALSE, FALSE, 0); - - // TODO(mattm): fix text view coloring (should have grey background). - GtkWidget* cert_details_view = gtk_text_view_new(); - gtk_text_view_set_editable(GTK_TEXT_VIEW(cert_details_view), FALSE); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(cert_details_view), GTK_WRAP_WORD); - cert_details_buffer_ = gtk_text_view_get_buffer( - GTK_TEXT_VIEW(cert_details_view)); - // We put the details in a frame instead of a scrolled window so that the - // entirety will be visible without requiring scrolling or expanding the - // dialog. This does however mean the dialog will grow itself if you switch - // to different cert that has longer details text. - GtkWidget* details_frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(details_frame), GTK_SHADOW_ETCHED_IN); - gtk_container_add(GTK_CONTAINER(details_frame), cert_details_view); - gtk_box_pack_start(GTK_BOX(selector_vbox), details_frame, TRUE, TRUE, 0); - - PopulateCerts(); - - g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); - g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); -} - -void SSLClientCertificateSelector::Show() { - gtk_widget_show_all(dialog_); -} - -void SSLClientCertificateSelector::PopulateCerts() { - CERTCertList* cert_list = CERT_NewCertList(); - for (size_t i = 0; i < cert_request_info_->client_certs.size(); ++i) { - CERT_AddCertToListTail( - cert_list, - CERT_DupCertificate( - cert_request_info_->client_certs[i]->os_cert_handle())); - } - // Would like to use CERT_GetCertNicknameWithValidity on each cert - // individually instead of having to build a CERTCertList for this, but that - // function is not exported. - CERTCertNicknames* nicknames = CERT_NicknameStringsFromCertList( - cert_list, - const_cast(l10n_util::GetStringUTF8( - IDS_CERT_SELECTOR_CERT_EXPIRED).c_str()), - const_cast(l10n_util::GetStringUTF8( - IDS_CERT_SELECTOR_CERT_NOT_YET_VALID).c_str())); - DCHECK_EQ(nicknames->numnicknames, - static_cast(cert_request_info_->client_certs.size())); - - for (size_t i = 0; i < cert_request_info_->client_certs.size(); ++i) { - CERTCertificate* cert = - cert_request_info_->client_certs[i]->os_cert_handle(); - - details_strings_.push_back(FormatDetailsText(cert)); - - gtk_combo_box_append_text( - GTK_COMBO_BOX(cert_combo_box_), - FormatComboBoxText(cert, nicknames->nicknames[i]).c_str()); - } - - CERT_FreeNicknames(nicknames); - CERT_DestroyCertList(cert_list); - - // Auto-select the first cert. - gtk_combo_box_set_active(GTK_COMBO_BOX(cert_combo_box_), 0); -} - -// static -std::string SSLClientCertificateSelector::FormatComboBoxText( - CERTCertificate* cert, const char* nickname) { - std::string rv(nickname); - char* serial_hex = CERT_Hexify(&cert->serialNumber, TRUE); - rv += " ["; - rv += serial_hex; - rv += ']'; - PORT_Free(serial_hex); - return rv; -} - -// static -std::string SSLClientCertificateSelector::FormatDetailsText( - CERTCertificate* cert) { - std::string rv; - - rv += l10n_util::GetStringFUTF8(IDS_CERT_SUBJECTNAME_FORMAT, - UTF8ToUTF16(cert->subjectName)); - - char* serial_hex = CERT_Hexify(&cert->serialNumber, TRUE); - rv += "\n "; - rv += l10n_util::GetStringFUTF8(IDS_CERT_SERIAL_NUMBER_FORMAT, - UTF8ToUTF16(serial_hex)); - PORT_Free(serial_hex); - - PRTime issued, expires; - if (CERT_GetCertTimes(cert, &issued, &expires) == SECSuccess) { - string16 issued_str = WideToUTF16( - base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(issued))); - string16 expires_str = WideToUTF16( - base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(expires))); - rv += "\n "; - rv += l10n_util::GetStringFUTF8(IDS_CERT_VALIDITY_RANGE_FORMAT, - issued_str, expires_str); - } - - std::vector usages; - psm::GetCertUsageStrings(cert, &usages); - if (usages.size()) { - rv += "\n "; - rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_EXTENDED_KEY_USAGE_FORMAT, - UTF8ToUTF16(JoinString(usages, ','))); - } - - SECItem key_usage; - key_usage.data = NULL; - if (CERT_FindKeyUsageExtension(cert, &key_usage) == SECSuccess) { - std::string key_usage_str = psm::ProcessKeyUsageBitString(&key_usage, ','); - PORT_Free(key_usage.data); - if (!key_usage_str.empty()) { - rv += "\n "; - rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_KEY_USAGE_FORMAT, - UTF8ToUTF16(key_usage_str)); - } - } - - std::vector email_addresses; - for (const char* addr = CERT_GetFirstEmailAddress(cert); - addr; addr = CERT_GetNextEmailAddress(cert, addr)) { - // The first email addr (from Subject) may be duplicated in Subject - // Alternative Name, so check subsequent addresses are not equal to the - // first one before adding to the list. - if (!email_addresses.size() || email_addresses[0] != addr) - email_addresses.push_back(addr); - } - if (email_addresses.size()) { - rv += "\n "; - rv += l10n_util::GetStringFUTF8( - IDS_CERT_EMAIL_ADDRESSES_FORMAT, - UTF8ToUTF16(JoinString(email_addresses, ','))); - } - - rv += '\n'; - rv += l10n_util::GetStringFUTF8(IDS_CERT_ISSUERNAME_FORMAT, - UTF8ToUTF16(cert->issuerName)); - - string16 token(UTF8ToUTF16(psm::GetCertTokenName(cert))); - if (!token.empty()) { - rv += '\n'; - rv += l10n_util::GetStringFUTF8(IDS_CERT_TOKEN_FORMAT, token); - } - - return rv; -} - -// static -void SSLClientCertificateSelector::OnComboBoxChanged( - GtkComboBox* combo_box, SSLClientCertificateSelector* cert_selector) { - int selected = gtk_combo_box_get_active( - GTK_COMBO_BOX(cert_selector->cert_combo_box_)); - if (selected < 0) - return; - gtk_text_buffer_set_text(cert_selector->cert_details_buffer_, - cert_selector->details_strings_[selected].c_str(), - cert_selector->details_strings_[selected].size()); -} - -// static -void SSLClientCertificateSelector::OnResponse( - GtkDialog* dialog, gint response_id, - SSLClientCertificateSelector* cert_selector) { - net::X509Certificate* cert = NULL; - if (response_id == GTK_RESPONSE_OK || - response_id == RESPONSE_SHOW_CERT_INFO) { - int selected = gtk_combo_box_get_active( - GTK_COMBO_BOX(cert_selector->cert_combo_box_)); - if (selected >= 0 && - selected < static_cast( - cert_selector->cert_request_info_->client_certs.size())) - cert = cert_selector->cert_request_info_->client_certs[selected]; - } - if (response_id == RESPONSE_SHOW_CERT_INFO) { - if (cert) - ShowCertificateViewer(GTK_WINDOW(cert_selector->dialog_), cert); - return; - } - cert_selector->delegate_->CertificateSelected(cert); - gtk_widget_destroy(GTK_WIDGET(dialog)); -} - -// static -void SSLClientCertificateSelector::OnDestroy( - GtkDialog* dialog, - SSLClientCertificateSelector* cert_selector) { - delete cert_selector; -} - -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// SSLClientAuthHandler platform specific implementation: - -void SSLClientAuthHandler::DoSelectCertificate() { - // TODO(mattm): Pipe parent gfx::NativeWindow param into here somehow. - (new SSLClientCertificateSelector(NULL, cert_request_info_, this))->Show(); -} diff --git a/chrome/browser/ssl/ssl_client_auth_handler_mac.mm b/chrome/browser/ssl/ssl_client_auth_handler_mac.mm deleted file mode 100644 index cde8acc..0000000 --- a/chrome/browser/ssl/ssl_client_auth_handler_mac.mm +++ /dev/null @@ -1,63 +0,0 @@ -// 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_client_auth_handler.h" - -#import - -#include "app/l10n_util_mac.h" -#include "base/scoped_cftyperef.h" -#include "base/scoped_nsobject.h" -#include "base/string_util.h" -#include "base/sys_string_conversions.h" -#include "chrome/browser/chrome_thread.h" -#include "grit/generated_resources.h" -#include "net/base/x509_certificate.h" - -void SSLClientAuthHandler::DoSelectCertificate() { - net::X509Certificate* cert = NULL; - // Create an array of CFIdentityRefs for the certificates: - size_t num_certs = cert_request_info_->client_certs.size(); - NSMutableArray* identities = [NSMutableArray arrayWithCapacity:num_certs]; - for (size_t i = 0; i < num_certs; ++i) { - SecCertificateRef cert; - cert = cert_request_info_->client_certs[i]->os_cert_handle(); - SecIdentityRef identity; - if (SecIdentityCreateWithCertificate(NULL, cert, &identity) == noErr) { - [identities addObject:(id)identity]; - CFRelease(identity); - } - } - - // Get the message to display: - NSString* title = l10n_util::GetNSString(IDS_CLIENT_CERT_DIALOG_TITLE); - NSString* message = l10n_util::GetNSStringF( - IDS_CLIENT_CERT_DIALOG_TEXT, - ASCIIToUTF16(cert_request_info_->host_and_port)); - - // Create and set up a system choose-identity panel. - scoped_nsobject panel ( - [[SFChooseIdentityPanel alloc] init]); - NSString* domain = base::SysUTF8ToNSString( - "https://" + cert_request_info_->host_and_port); - [panel setDomain:domain]; - [panel setInformativeText:message]; - [panel setAlternateButtonTitle:l10n_util::GetNSString(IDS_CANCEL)]; - SecPolicyRef sslPolicy; - if (net::X509Certificate::CreateSSLClientPolicy(&sslPolicy) == noErr) { - [panel setPolicies:(id)sslPolicy]; - CFRelease(sslPolicy); - } - - // Run the panel, modally. - // TODO(snej): Change this into a sheet so it doesn't block the runloop! - if ([panel runModalForIdentities:identities message:title] == NSOKButton) { - NSUInteger index = [identities indexOfObject:(id)[panel identity]]; - DCHECK(index != NSNotFound); - cert = cert_request_info_->client_certs[index]; - } - - // Finally, tell the back end which identity (or none) the user selected. - CertificateSelected(cert); -} diff --git a/chrome/browser/ssl/ssl_client_auth_handler_win.cc b/chrome/browser/ssl/ssl_client_auth_handler_win.cc deleted file mode 100644 index cbac1ae..0000000 --- a/chrome/browser/ssl/ssl_client_auth_handler_win.cc +++ /dev/null @@ -1,58 +0,0 @@ -// 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_client_auth_handler.h" - -#include -#pragma comment(lib, "cryptui.lib") - -#include "app/l10n_util.h" -#include "base/string_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 "grit/generated_resources.h" -#include "net/url_request/url_request.h" - -void SSLClientAuthHandler::DoSelectCertificate() { - net::X509Certificate* cert = NULL; - // TODO(jcampan): replace this with our own cert selection dialog. - // CryptUIDlgSelectCertificateFromStore is blocking (but still processes - // Windows messages), which is scary. - HCERTSTORE client_certs = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, - 0, NULL); - BOOL ok; - for (size_t i = 0; i < cert_request_info_->client_certs.size(); ++i) { - PCCERT_CONTEXT cc = cert_request_info_->client_certs[i]->os_cert_handle(); - ok = CertAddCertificateContextToStore(client_certs, cc, - CERT_STORE_ADD_ALWAYS, NULL); - DCHECK(ok); - } - - HWND browser_hwnd = NULL; - Browser* browser = BrowserList::GetLastActive(); - if (browser) - browser_hwnd = browser->window()->GetNativeHandle(); - - std::wstring title = l10n_util::GetString(IDS_CLIENT_CERT_DIALOG_TITLE); - std::wstring text = l10n_util::GetStringF( - IDS_CLIENT_CERT_DIALOG_TEXT, - ASCIIToWide(cert_request_info_->host_and_port)); - PCCERT_CONTEXT cert_context = CryptUIDlgSelectCertificateFromStore( - client_certs, browser_hwnd, title.c_str(), text.c_str(), 0, 0, NULL); - - if (cert_context) { - cert = net::X509Certificate::CreateFromHandle( - cert_context, - net::X509Certificate::SOURCE_LONE_CERT_IMPORT, - net::X509Certificate::OSCertHandles()); - net::X509Certificate::FreeOSCertHandle(cert_context); - } - - ok = CertCloseStore(client_certs, CERT_CLOSE_STORE_CHECK_FLAG); - DCHECK(ok); - - CertificateSelected(cert); -} diff --git a/chrome/browser/ssl_client_certificate_selector.h b/chrome/browser/ssl_client_certificate_selector.h new file mode 100644 index 0000000..8a12a70 --- /dev/null +++ b/chrome/browser/ssl_client_certificate_selector.h @@ -0,0 +1,30 @@ +// 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_CLIENT_CERTIFICATE_SELECTOR_H_ +#define CHROME_BROWSER_SSL_CLIENT_CERTIFICATE_SELECTOR_H_ + +#include "gfx/native_widget_types.h" + +class SSLClientAuthHandler; + +namespace net { +class SSLCertRequestInfo; +} + +namespace browser { + +// Opens an SSL client certificate selection dialog under |parent|, offering +// certificates from |cert_request_info|. When the user has made a selection, +// the dialog will report back to |delegate|. |delegate| is notified when the +// dialog closes in call cases; if the user cancels the dialog, we call with a +// NULL certificate. +void ShowSSLClientCertificateSelector( + gfx::NativeWindow parent, + net::SSLCertRequestInfo* cert_request_info, + SSLClientAuthHandler* delegate); + +} // namespace browser + +#endif // CHROME_BROWSER_SSL_CLIENT_CERTIFICATE_SELECTOR_H_ diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 73b1b9f..e25fc44 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -71,6 +71,7 @@ #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/provisional_load_details.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" +#include "chrome/browser/tab_contents/tab_contents_ssl_helper.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/tab_contents/thumbnail_generator.h" #include "chrome/browser/translate/page_translated_details.h" @@ -501,6 +502,12 @@ PluginInstaller* TabContents::GetPluginInstaller() { return plugin_installer_.get(); } +TabContentsSSLHelper* TabContents::GetSSLHelper() { + if (ssl_helper_.get() == NULL) + ssl_helper_.reset(new TabContentsSSLHelper(this)); + return ssl_helper_.get(); +} + RenderProcessHost* TabContents::GetRenderProcessHost() const { return render_manager_.current_host()->process(); } @@ -2177,6 +2184,10 @@ RenderViewHostDelegate::AutoFill* TabContents::GetAutoFillDelegate() { return GetAutoFillManager(); } +RenderViewHostDelegate::SSL* TabContents::GetSSLDelegate() { + return GetSSLHelper(); +} + AutomationResourceRoutingDelegate* TabContents::GetAutomationResourceRoutingDelegate() { return delegate(); diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 49016ae..8d14246 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -88,6 +88,7 @@ class SkBitmap; class TabContents; class TabContentsDelegate; class TabContentsFactory; +class TabContentsSSLHelper; class TabContentsView; class URLPattern; class URLRequestContextGetter; @@ -168,6 +169,9 @@ class TabContents : public PageNavigator, // Returns the PluginInstaller, creating it if necessary. PluginInstaller* GetPluginInstaller(); + // Returns the TabContentsSSLHelper, creating if it necessary. + TabContentsSSLHelper* GetSSLHelper(); + // Returns the SavePackage which manages the page saving job. May be NULL. SavePackage* save_package() const { return save_package_.get(); } @@ -893,6 +897,7 @@ class TabContents : public PageNavigator, virtual RenderViewHostDelegate::FavIcon* GetFavIconDelegate(); virtual RenderViewHostDelegate::Autocomplete* GetAutocompleteDelegate(); virtual RenderViewHostDelegate::AutoFill* GetAutoFillDelegate(); + virtual RenderViewHostDelegate::SSL* GetSSLDelegate(); virtual AutomationResourceRoutingDelegate* GetAutomationResourceRoutingDelegate(); virtual TabContents* GetAsTabContents(); @@ -1067,6 +1072,9 @@ class TabContents : public PageNavigator, // PluginInstaller, lazily created. scoped_ptr plugin_installer_; + // TabContentsSSLHelper, lazily created. + scoped_ptr ssl_helper_; + // Handles drag and drop event forwarding to extensions. BookmarkDrag* bookmark_drag_; diff --git a/chrome/browser/tab_contents/tab_contents_ssl_helper.cc b/chrome/browser/tab_contents/tab_contents_ssl_helper.cc new file mode 100644 index 0000000..0f00d1e --- /dev/null +++ b/chrome/browser/tab_contents/tab_contents_ssl_helper.cc @@ -0,0 +1,24 @@ +// 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/tab_contents/tab_contents_ssl_helper.h" + +#include "chrome/browser/ssl/ssl_client_auth_handler.h" +#include "chrome/browser/ssl_client_certificate_selector.h" +#include "chrome/browser/tab_contents/tab_contents.h" + +TabContentsSSLHelper::TabContentsSSLHelper(TabContents* tab_contents) + : tab_contents_(tab_contents) { +} + +TabContentsSSLHelper::~TabContentsSSLHelper() { +} + +void TabContentsSSLHelper::ShowClientCertificateRequestDialog( + scoped_refptr handler) { + // Display the native certificate request dialog for each platform. + browser::ShowSSLClientCertificateSelector( + tab_contents_->GetMessageBoxRootWindow(), + handler->cert_request_info(), handler); +} diff --git a/chrome/browser/tab_contents/tab_contents_ssl_helper.h b/chrome/browser/tab_contents/tab_contents_ssl_helper.h new file mode 100644 index 0000000..bddb379 --- /dev/null +++ b/chrome/browser/tab_contents/tab_contents_ssl_helper.h @@ -0,0 +1,28 @@ +// 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_TAB_CONTENTS_TAB_CONTENTS_SSL_HELPER_H_ +#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_SSL_HELPER_H_ + +#include "chrome/browser/renderer_host/render_view_host_delegate.h" + +class SSLClientAuthHandler; +class TabContents; + +class TabContentsSSLHelper : public RenderViewHostDelegate::SSL { + public: + explicit TabContentsSSLHelper(TabContents* tab_contents); + virtual ~TabContentsSSLHelper(); + + // RenderViewHostDelegate::SSL implementation: + virtual void ShowClientCertificateRequestDialog( + scoped_refptr handler); + + private: + TabContents* tab_contents_; + + DISALLOW_COPY_AND_ASSIGN(TabContentsSSLHelper); +}; + +#endif // CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_SSL_HELPER_H_ diff --git a/chrome/browser/views/ssl_client_certificate_selector_win.cc b/chrome/browser/views/ssl_client_certificate_selector_win.cc new file mode 100644 index 0000000..cf5ad4f3 --- /dev/null +++ b/chrome/browser/views/ssl_client_certificate_selector_win.cc @@ -0,0 +1,61 @@ +// 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_client_certificate_selector.h" + +#include +#pragma comment(lib, "cryptui.lib") + +#include "app/l10n_util.h" +#include "base/string_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/browser/ssl/ssl_client_auth_handler.h" +#include "grit/generated_resources.h" +#include "net/url_request/url_request.h" + +namespace browser { + +void ShowSSLClientCertificateSelector( + gfx::NativeWindow parent, + net::SSLCertRequestInfo* cert_request_info, + SSLClientAuthHandler* delegate) { + net::X509Certificate* cert = NULL; + // TODO(jcampan): replace this with our own cert selection dialog. + // CryptUIDlgSelectCertificateFromStore is blocking (but still processes + // Windows messages), which is scary. + HCERTSTORE client_certs = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, + 0, NULL); + BOOL ok; + for (size_t i = 0; i < cert_request_info->client_certs.size(); ++i) { + PCCERT_CONTEXT cc = cert_request_info->client_certs[i]->os_cert_handle(); + ok = CertAddCertificateContextToStore(client_certs, cc, + CERT_STORE_ADD_ALWAYS, NULL); + DCHECK(ok); + } + + std::wstring title = l10n_util::GetString(IDS_CLIENT_CERT_DIALOG_TITLE); + std::wstring text = l10n_util::GetStringF( + IDS_CLIENT_CERT_DIALOG_TEXT, + ASCIIToWide(cert_request_info->host_and_port)); + PCCERT_CONTEXT cert_context = CryptUIDlgSelectCertificateFromStore( + client_certs, parent, title.c_str(), text.c_str(), 0, 0, NULL); + + if (cert_context) { + cert = net::X509Certificate::CreateFromHandle( + cert_context, + net::X509Certificate::SOURCE_LONE_CERT_IMPORT, + net::X509Certificate::OSCertHandles()); + net::X509Certificate::FreeOSCertHandle(cert_context); + } + + ok = CertCloseStore(client_certs, CERT_CLOSE_STORE_CHECK_FLAG); + DCHECK(ok); + + delegate->CertificateSelected(cert); +} + +} // namespace browser -- cgit v1.1