summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-04 01:46:57 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-04 01:46:57 +0000
commitb1f18494233f64c720729039222d9ad66c8ae95f (patch)
tree0f2848bdedba2a46c3d3b3fc8c7855d2786fd14d
parentb1995975f4e6b17df513a6d0dae44b37c46c5e00 (diff)
downloadchromium_src-b1f18494233f64c720729039222d9ad66c8ae95f.zip
chromium_src-b1f18494233f64c720729039222d9ad66c8ae95f.tar.gz
chromium_src-b1f18494233f64c720729039222d9ad66c8ae95f.tar.bz2
Linux: implement Client SSL Certificate selection UI
BUG=25241 TEST=Visit site for which you have a client certificate, verify that dialog comes up and you can select your cert (or cancel) Review URL: http://codereview.chromium.org/661241 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40587 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd46
-rw-r--r--chrome/browser/chromeos/login/login_manager_view.cc7
-rw-r--r--chrome/browser/gtk/certificate_viewer.cc40
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc9
-rw-r--r--chrome/browser/ssl/ssl_client_auth_handler.h10
-rw-r--r--chrome/browser/ssl/ssl_client_auth_handler_gtk.cc322
-rwxr-xr-xchrome/chrome_browser.gypi4
-rw-r--r--chrome/common/chrome_switches.cc10
-rw-r--r--chrome/common/chrome_switches.h4
-rw-r--r--chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp68
-rw-r--r--chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h1
-rw-r--r--chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp13
-rw-r--r--chrome/third_party/mozilla_security_manager/nsNSSCertificate.h3
-rw-r--r--chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.cpp73
-rw-r--r--chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h53
15 files changed, 573 insertions, 90 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 3d0f3ea..8db5e7e 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2497,6 +2497,49 @@ each locale. -->
Unknown server certificate error
</message>
+
+ <!-- Certificate selector dialog strings. These are only used on platforms that don't have a native certificate selection dialog, such as Linux. -->
+ <message name="IDS_CERT_SELECTOR_DIALOG_TITLE" desc="Title of dialog asking user to select a certificate for SSL client certificate authentication">
+ Client Certificate Request: <ph name="REQUESTING_HOST_AND_PORT">$1<ex>pip.verisignlabs.com:443</ex></ph>
+ </message>
+ <message name="IDS_CERT_SELECTOR_SITE_DESCRIPTION_LABEL" desc="Text in the certificate selection dialog before the site">
+ This site has requested that you identify yourself with a certificate:
+ </message>
+ <message name="IDS_CERT_SELECTOR_CHOOSE_DESCRIPTION_LABEL" desc="Text in the certificate selection dialog describing the certificate selector combobox and certificate details">
+ Choose a certificate to present as identification:
+ </message>
+ <message name="IDS_CERT_SELECTOR_DETAILS_DESCRIPTION_LABEL" desc="Text in the certificate selection dialog in the 'choose a certificate' section describing the certificate details">
+ Details of selected certificate:
+ </message>
+ <message name="IDS_CERT_SELECTOR_CERT_EXPIRED" desc="In the certificate selection dialog's combobox for choosing certificates, this text will be appended to any of the user's certs which are expired.">
+ (expired)
+ </message>
+ <message name="IDS_CERT_SELECTOR_CERT_NOT_YET_VALID" desc="In the certificate selection dialog's combobox for choosing certificates, this text will be appended to any of the user's certs which are not yet valid.">
+ (not yet valid)
+ </message>
+ <message name="IDS_CERT_SUBJECTNAME_FORMAT" desc="Format for detailed certificate subject in certificate details">
+ Issued to: <ph name="NAME">$1<ex>CN=VeriSign Browser Certificate,OU=Device Identifier - r1923847</ex></ph>
+ </message>
+ <message name="IDS_CERT_ISSUERNAME_FORMAT" desc="Format for detailed certificate issuer in certificate details">
+ Issued by: <ph name="NAME">$1<ex>CN=VeriSign Device CA,O="VeriSign, Inc.",C=US</ex></ph>
+ </message>
+ <message name="IDS_CERT_VALIDITY_RANGE_FORMAT" desc="Format for showing the range of dates a certificate is valid in the certificate details">
+ Valid from <ph name="START_DATE_TIME">$1<ex>7/2/09 7:18:34 PM</ex></ph> to <ph name="END_DATE_TIME">$2<ex>7/2/10 7:28:34 PM</ex></ph>
+ </message>
+ <message name="IDS_CERT_X509_EXTENDED_KEY_USAGE_FORMAT" desc="Format for showing the usages a certificate is valid for in the certificate details">
+ Purposes: <ph name="USAGES">$1<ex>SSL Client Certificate,Email Signer Certificate</ex></ph>
+ </message>
+ <message name="IDS_CERT_X509_KEY_USAGE_FORMAT" desc="Format for showing the key usages a certificate is valid for in the certificate details">
+ Certificate Key Usage: <ph name="USAGES">$1<ex>Signing,Key Encipherment</ex></ph>
+ </message>
+ <message name="IDS_CERT_EMAIL_ADDRESSES_FORMAT" desc="Format for showing the email address(es) a certificate is associated with in the certificate details">
+ Email: <ph name="EMAIL_ADDRESSES">$1<ex>foo@example.com</ex></ph>
+ </message>
+ <message name="IDS_CERT_TOKEN_FORMAT" desc="Format for showing the location a certificate is stored">
+ Stored in: <ph name="CERT_LOCATION">$1<ex>NSS Certificate Database</ex></ph>
+ </message>
+
+
<!-- Certificate viewer dialog strings. These are only used on platforms that don't have a native certificate info dialog, such as Linux. -->
<message name="IDS_CERT_INFO_DIALOG_TITLE" desc="Title of dialog displaying info about a certificate">
Certificate Viewer: <ph name="CERTIFICATE_NAME">$1<ex>www.google.com</ex></ph>
@@ -2800,6 +2843,9 @@ each locale. -->
<message name="IDS_CERT_X509_KEY_USAGE_CRL_SIGNER" desc="description of certificate usage CRL Signer">
CRL Signer
</message>
+ <message name="IDS_CERT_X509_KEY_USAGE_ENCIPHER_ONLY" desc="description of certificate usage Encipher Only">
+ Encipher Only
+ </message>
<message name="IDS_CERT_X509_BASIC_CONSTRAINT_IS_CA" desc="description of certificate constraint Is a Certificate Authority">
Is a Certificate Authority
</message>
diff --git a/chrome/browser/chromeos/login/login_manager_view.cc b/chrome/browser/chromeos/login/login_manager_view.cc
index 82c1816..63d1c66 100644
--- a/chrome/browser/chromeos/login/login_manager_view.cc
+++ b/chrome/browser/chromeos/login/login_manager_view.cc
@@ -321,13 +321,6 @@ void LoginManagerView::SetupSession(const std::string& username) {
if (observer_) {
observer_->OnExit(chromeos::ScreenObserver::LOGIN_SIGN_IN_SELECTED);
}
- if (username.find("@google.com") != std::string::npos) {
- // This isn't thread-safe. However, the login window is specifically
- // supposed to be run in a blocking fashion, before any other threads are
- // created by the initial browser process.
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kAutoSSLClientAuth);
- }
if (chromeos::LoginLibrary::EnsureLoaded())
chromeos::LoginLibrary::Get()->StartSession(username, "");
}
diff --git a/chrome/browser/gtk/certificate_viewer.cc b/chrome/browser/gtk/certificate_viewer.cc
index a4cc92b..75a9d4a 100644
--- a/chrome/browser/gtk/certificate_viewer.cc
+++ b/chrome/browser/gtk/certificate_viewer.cc
@@ -21,6 +21,7 @@
#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 "grit/generated_resources.h"
// PSM = Mozilla's Personal Security Manager.
@@ -255,37 +256,14 @@ void CertificateViewer::InitGeneralPage() {
l10n_util::GetStringUTF8(IDS_CERT_INFO_VERIFIED_USAGES_GROUP)),
FALSE, FALSE, 0);
- SECCertificateUsage usages = 0;
- // TODO(wtc): See if we should use X509Certificate::Verify instead.
- if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, PR_TRUE,
- certificateUsageCheckAllUsages,
- NULL, &usages) == SECSuccess) {
- // List of usages to display is borrowed from
- // mozilla/source/security/manager/ssl/src/nsUsageArrayHelper.cpp
- static const struct {
- SECCertificateUsage usage;
- int string_id;
- } usage_string_map[] = {
- {certificateUsageSSLClient, IDS_CERT_USAGE_SSL_CLIENT},
- {certificateUsageSSLServer, IDS_CERT_USAGE_SSL_SERVER},
- {certificateUsageSSLServerWithStepUp,
- IDS_CERT_USAGE_SSL_SERVER_WITH_STEPUP},
- {certificateUsageEmailSigner, IDS_CERT_USAGE_EMAIL_SIGNER},
- {certificateUsageEmailRecipient, IDS_CERT_USAGE_EMAIL_RECEIVER},
- {certificateUsageObjectSigner, IDS_CERT_USAGE_OBJECT_SIGNER},
- {certificateUsageSSLCA, IDS_CERT_USAGE_SSL_CA},
- {certificateUsageStatusResponder, IDS_CERT_USAGE_STATUS_RESPONDER},
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(usage_string_map); ++i) {
- if (usages & usage_string_map[i].usage)
- gtk_box_pack_start(
- GTK_BOX(uses_vbox),
- gtk_util::IndentWidget(gtk_util::LeftAlignMisc(gtk_label_new(
- l10n_util::GetStringUTF8(
- usage_string_map[i].string_id).c_str()))),
- FALSE, FALSE, 0);
- }
- }
+ std::vector<std::string> usages;
+ psm::GetCertUsageStrings(cert, &usages);
+ for (size_t i = 0; i < usages.size(); ++i)
+ gtk_box_pack_start(
+ GTK_BOX(uses_vbox),
+ gtk_util::IndentWidget(gtk_util::LeftAlignMisc(gtk_label_new(
+ usages[i].c_str()))),
+ FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(general_page_vbox_), gtk_hseparator_new(),
FALSE, FALSE, 0);
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index c7e6050..8837247 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -969,14 +969,6 @@ void ResourceDispatcherHost::OnCertificateRequested(
net::SSLCertRequestInfo* cert_request_info) {
DCHECK(request);
-#if defined(OS_LINUX)
- bool select_first_cert = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAutoSSLClientAuth);
- net::X509Certificate* cert =
- select_first_cert && !cert_request_info->client_certs.empty() ?
- cert_request_info->client_certs[0] : NULL;
- request->ContinueWithCertificate(cert);
-#else
if (cert_request_info->client_certs.empty()) {
// No need to query the user if there are no certs to choose from.
request->ContinueWithCertificate(NULL);
@@ -989,7 +981,6 @@ void ResourceDispatcherHost::OnCertificateRequested(
info->set_ssl_client_auth_handler(
new SSLClientAuthHandler(request, cert_request_info));
info->ssl_client_auth_handler()->SelectCertificate();
-#endif
}
void ResourceDispatcherHost::OnSSLCertificateError(
diff --git a/chrome/browser/ssl/ssl_client_auth_handler.h b/chrome/browser/ssl/ssl_client_auth_handler.h
index 537b0ea..f63d4c9 100644
--- a/chrome/browser/ssl/ssl_client_auth_handler.h
+++ b/chrome/browser/ssl/ssl_client_auth_handler.h
@@ -33,6 +33,11 @@ class SSLClientAuthHandler
// Should only be called on the IO thread.
void OnRequestCancelled();
+ // Calls DoCertificateSelected on the I/O thread.
+ // Called on the UI thread after the user has made a selection (which may
+ // be long after DoSelectCertificate returns, if the UI is modeless/async.)
+ void CertificateSelected(net::X509Certificate* cert);
+
private:
friend class base::RefCountedThreadSafe<SSLClientAuthHandler>;
@@ -42,11 +47,6 @@ class SSLClientAuthHandler
// Called on the UI thread.
void DoSelectCertificate();
- // Calls DoCertificateSelected on the I/O thread.
- // Called on the UI thread after the user has made a selection (which may
- // be long after DoSelectCertificate returns, if the UI is modeless/async.)
- void CertificateSelected(net::X509Certificate* cert);
-
// 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
index 7ea1aec..49fa4c5 100644
--- a/chrome/browser/ssl/ssl_client_auth_handler_gtk.cc
+++ b/chrome/browser/ssl/ssl_client_auth_handler_gtk.cc
@@ -3,10 +3,328 @@
// found in the LICENSE file.
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
+
+#include <cert.h>
+#include <gtk/gtk.h>
+
+#include <string>
+#include <vector>
+
+#include "app/gfx/native_widget_types.h"
+#include "app/l10n_util.h"
+#include "base/i18n/time_formatting.h"
#include "base/logging.h"
+#include "base/nss_util.h"
+#include "chrome/browser/gtk/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 "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<net::SSLCertRequestInfo> cert_request_info_;
+
+ std::vector<std::string> 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<char*>(l10n_util::GetStringUTF8(
+ IDS_CERT_SELECTOR_CERT_EXPIRED).c_str()),
+ const_cast<char*>(l10n_util::GetStringUTF8(
+ IDS_CERT_SELECTOR_CERT_NOT_YET_VALID).c_str()));
+ DCHECK_EQ(nicknames->numnicknames,
+ static_cast<int>(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<std::string> 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<std::string> 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<int>(
+ 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->os_cert_handle());
+ 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() {
- NOTIMPLEMENTED();
- CertificateSelected(NULL);
+ // TODO(mattm): Pipe parent gfx::NativeWindow param into here somehow.
+ (new SSLClientCertificateSelector(NULL, cert_request_info_, this))->Show();
}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 1435d94..8c54ce5 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2291,6 +2291,8 @@
'third_party/mozilla_security_manager/nsNSSCertHelper.h',
'third_party/mozilla_security_manager/nsNSSCertificate.cpp',
'third_party/mozilla_security_manager/nsNSSCertificate.h',
+ 'third_party/mozilla_security_manager/nsUsageArrayHelper.cpp',
+ 'third_party/mozilla_security_manager/nsUsageArrayHelper.h',
],
'conditions': [
['linux_breakpad==1', {
@@ -2733,6 +2735,8 @@
['include', '^browser/gtk/cairo_cached_surface.h'],
['include', '^browser/gtk/clear_browsing_data_dialog_gtk.cc'],
['include', '^browser/gtk/clear_browsing_data_dialog_gtk.h'],
+ ['include', '^browser/gtk/certificate_viewer.cc'],
+ ['include', '^browser/gtk/certificate_viewer.h'],
['include', '^browser/gtk/constrained_window_gtk.cc'],
['include', '^browser/gtk/constrained_window_gtk.h'],
['include', '^browser/gtk/download_started_animation_gtk.cc'],
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 3b538b33..ac8ee7b 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -795,16 +795,6 @@ const char kChromeosFrame[] = "chromeos-frame";
const char kUseNSSForSSL[] = "use-nss-for-ssl";
#endif
-#if defined(OS_LINUX)
-// A temporary switch before we implement the client certificate selection UI.
-// When an SSL server requests client authentication, select a client
-// certificate automatically.
-// WARNING: This switch has privacy issues because it reveals the user's
-// identity to any server that requests a client certificate without the
-// user's consent.
-const char kAutoSSLClientAuth[] = "auto-ssl-client-auth";
-#endif
-
#if defined(OS_POSIX)
// Bypass the error dialog when the profile lock couldn't be attained.
// A flag, generated internally by Chrome for renderer and other helper process
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index c40675d..5ceb5fb 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -233,10 +233,6 @@ extern const char kChromeosFrame[];
extern const char kUseNSSForSSL[];
#endif
-#if defined(OS_LINUX)
-extern const char kAutoSSLClientAuth[];
-#endif
-
#if defined(OS_POSIX)
extern const char kEnableCrashReporter[];
extern const char kNoProcessSingletonDialog[];
diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp
index 6f6d9f2..3c16cf0 100644
--- a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp
+++ b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp
@@ -688,13 +688,34 @@ std::string ProcessBMPString(SECItem* extension_data) {
}
struct MaskIdPair {
- unsigned char mask;
+ unsigned int mask;
int string_id;
};
+static std::string ProcessBitField(SECItem* bitfield,
+ const MaskIdPair* string_map,
+ size_t len,
+ char separator) {
+ unsigned int bits = 0;
+ std::string rv;
+ // NSS bit flags like KU_DIGITAL_SIGNATURE, etc. are defined with the
+ // assumption that the bitfields have at most 8 bits.
+ if (bitfield->len)
+ bits = bitfield->data[0];
+ for (size_t i = 0; i < len; ++i) {
+ if (bits & string_map[i].mask) {
+ if (!rv.empty())
+ rv += separator;
+ rv += l10n_util::GetStringUTF8(string_map[i].string_id);
+ }
+ }
+ return rv;
+}
+
static std::string ProcessBitStringExtension(SECItem* extension_data,
const MaskIdPair* string_map,
- size_t len) {
+ size_t len,
+ char separator) {
SECItem decoded;
decoded.type = siBuffer;
decoded.data = NULL;
@@ -702,19 +723,13 @@ static std::string ProcessBitStringExtension(SECItem* extension_data,
if (SEC_ASN1DecodeItem(NULL, &decoded, SEC_ASN1_GET(SEC_BitStringTemplate),
extension_data) != SECSuccess)
return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
-
- std::string rv;
- for (size_t i = 0; i < len; ++i) {
- if (decoded.data[0] & string_map[i].mask) {
- rv += l10n_util::GetStringUTF8(string_map[i].string_id) + '\n';
- }
- }
+ std::string rv = ProcessBitField(&decoded, string_map, len, separator);
PORT_Free(decoded.data);
return rv;
}
std::string ProcessNSCertTypeExtension(SECItem* extension_data) {
- MaskIdPair usage_string_map[] = {
+ static const MaskIdPair usage_string_map[] = {
{NS_CERT_TYPE_SSL_CLIENT, IDS_CERT_USAGE_SSL_CLIENT},
{NS_CERT_TYPE_SSL_SERVER, IDS_CERT_USAGE_SSL_SERVER},
{NS_CERT_TYPE_EMAIL, IDS_CERT_EXT_NS_CERT_TYPE_EMAIL},
@@ -724,21 +739,30 @@ std::string ProcessNSCertTypeExtension(SECItem* extension_data) {
{NS_CERT_TYPE_OBJECT_SIGNING_CA, IDS_CERT_USAGE_OBJECT_SIGNER},
};
return ProcessBitStringExtension(extension_data, usage_string_map,
- ARRAYSIZE_UNSAFE(usage_string_map));
+ ARRAYSIZE_UNSAFE(usage_string_map), '\n');
+}
+
+static const MaskIdPair key_usage_string_map[] = {
+ {KU_DIGITAL_SIGNATURE, IDS_CERT_X509_KEY_USAGE_SIGNING},
+ {KU_NON_REPUDIATION, IDS_CERT_X509_KEY_USAGE_NONREP},
+ {KU_KEY_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_ENCIPHERMENT},
+ {KU_DATA_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_DATA_ENCIPHERMENT},
+ {KU_KEY_AGREEMENT, IDS_CERT_X509_KEY_USAGE_KEY_AGREEMENT},
+ {KU_KEY_CERT_SIGN, IDS_CERT_X509_KEY_USAGE_CERT_SIGNER},
+ {KU_CRL_SIGN, IDS_CERT_X509_KEY_USAGE_CRL_SIGNER},
+ {KU_ENCIPHER_ONLY, IDS_CERT_X509_KEY_USAGE_ENCIPHER_ONLY},
+ // NSS is missing a flag for dechiperOnly, see:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=549952
+};
+
+std::string ProcessKeyUsageBitString(SECItem* bitstring, char sep) {
+ return ProcessBitField(bitstring, key_usage_string_map,
+ arraysize(key_usage_string_map), sep);
}
std::string ProcessKeyUsageExtension(SECItem* extension_data) {
- MaskIdPair usage_string_map[] = {
- {KU_DIGITAL_SIGNATURE, IDS_CERT_X509_KEY_USAGE_SIGNING},
- {KU_NON_REPUDIATION, IDS_CERT_X509_KEY_USAGE_NONREP},
- {KU_KEY_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_ENCIPHERMENT},
- {KU_DATA_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_DATA_ENCIPHERMENT},
- {KU_KEY_AGREEMENT, IDS_CERT_X509_KEY_USAGE_KEY_AGREEMENT},
- {KU_KEY_CERT_SIGN, IDS_CERT_X509_KEY_USAGE_CERT_SIGNER},
- {KU_CRL_SIGN, IDS_CERT_X509_KEY_USAGE_CRL_SIGNER},
- };
- return ProcessBitStringExtension(extension_data, usage_string_map,
- ARRAYSIZE_UNSAFE(usage_string_map));
+ return ProcessBitStringExtension(extension_data, key_usage_string_map,
+ arraysize(key_usage_string_map), '\n');
}
std::string ProcessExtKeyUsage(SECItem* extension_data) {
diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h
index ba0a445..5741c69 100644
--- a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h
+++ b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h
@@ -88,6 +88,7 @@ std::string ProcessAuthInfoAccess(SECItem* extension_data);
std::string ProcessIA5String(SECItem* extension_data);
std::string ProcessBMPString(SECItem* extension_data);
std::string ProcessNSCertTypeExtension(SECItem* extension_data);
+std::string ProcessKeyUsageBitString(SECItem* bitstring, char sep);
std::string ProcessKeyUsageExtension(SECItem* extension_data);
std::string ProcessExtKeyUsage(SECItem* extension_data);
std::string ProcessExtensionData(SECOidTag oid_tag, SECItem* extension_data);
diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp
index 9d1abe8..74624ab 100644
--- a/chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp
+++ b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp
@@ -40,6 +40,11 @@
#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
+#include <pk11func.h>
+
+#include "app/l10n_util.h"
+#include "grit/generated_resources.h"
+
namespace mozilla_security_manager {
std::string GetCertTitle(CERTCertificate* cert) {
@@ -62,4 +67,12 @@ std::string GetCertTitle(CERTCertificate* cert) {
return rv;
}
+std::string GetCertTokenName(CERTCertificate* cert) {
+ std::string token;
+ if (cert->slot) {
+ token = PK11_GetTokenName(cert->slot);
+ }
+ return token;
+}
+
} // namespace mozilla_security_manager
diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertificate.h b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.h
index 8ac10e6..b436601 100644
--- a/chrome/third_party/mozilla_security_manager/nsNSSCertificate.h
+++ b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.h
@@ -50,6 +50,9 @@ namespace mozilla_security_manager {
// Based on nsNSSCertificate::GetWindowTitle.
std::string GetCertTitle(CERTCertificate* cert);
+// Based on nsNSSCertificate::GetTokenName.
+std::string GetCertTokenName(CERTCertificate* cert);
+
} // namespace mozilla_security_manager
#endif // CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSNSSCERTIFICATE_H_
diff --git a/chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.cpp b/chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.cpp
new file mode 100644
index 0000000..234e4dd
--- /dev/null
+++ b/chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.cpp
@@ -0,0 +1,73 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gardiner Myers <jgmyers@speakeasy.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
+
+#include "app/l10n_util.h"
+#include "grit/generated_resources.h"
+
+namespace mozilla_security_manager {
+
+void GetCertUsageStrings(CERTCertificate* cert, std::vector<std::string>* out) {
+ SECCertificateUsage usages = 0;
+ // TODO(wtc): See if we should use X509Certificate::Verify instead.
+ if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, PR_TRUE,
+ certificateUsageCheckAllUsages,
+ NULL, &usages) == SECSuccess) {
+ static const struct {
+ SECCertificateUsage usage;
+ int string_id;
+ } usage_string_map[] = {
+ {certificateUsageSSLClient, IDS_CERT_USAGE_SSL_CLIENT},
+ {certificateUsageSSLServer, IDS_CERT_USAGE_SSL_SERVER},
+ {certificateUsageSSLServerWithStepUp,
+ IDS_CERT_USAGE_SSL_SERVER_WITH_STEPUP},
+ {certificateUsageEmailSigner, IDS_CERT_USAGE_EMAIL_SIGNER},
+ {certificateUsageEmailRecipient, IDS_CERT_USAGE_EMAIL_RECEIVER},
+ {certificateUsageObjectSigner, IDS_CERT_USAGE_OBJECT_SIGNER},
+ {certificateUsageSSLCA, IDS_CERT_USAGE_SSL_CA},
+ {certificateUsageStatusResponder, IDS_CERT_USAGE_STATUS_RESPONDER},
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(usage_string_map); ++i) {
+ if (usages & usage_string_map[i].usage)
+ out->push_back(l10n_util::GetStringUTF8(
+ usage_string_map[i].string_id));
+ }
+ }
+}
+
+} // namespace mozilla_security_manager
diff --git a/chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h b/chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h
new file mode 100644
index 0000000..31ba550
--- /dev/null
+++ b/chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h
@@ -0,0 +1,53 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gardiner Myers <jgmyers@speakeasy.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSUSAGEARRAYHELPER_H_
+#define CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSUSAGEARRAYHELPER_H_
+
+#include <cert.h>
+
+#include <string>
+#include <vector>
+
+namespace mozilla_security_manager {
+
+// Based on nsUsageArrayHelper::GetUsagesArray.
+void GetCertUsageStrings(CERTCertificate* cert, std::vector<std::string>* out);
+
+} // namespace mozilla_security_manager
+
+#endif // CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSUSAGEARRAYHELPER_H_