summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-24 19:01:54 +0000
committersnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-24 19:01:54 +0000
commit699cab9ba3a0fcb9dd7f41a86cf008d34b96de1b (patch)
tree870ff656500a6cfc2a24faf6895b3fac67d21660
parent39b3349ed1694810b454f9af793c8c9bb0a3bd5d (diff)
downloadchromium_src-699cab9ba3a0fcb9dd7f41a86cf008d34b96de1b.zip
chromium_src-699cab9ba3a0fcb9dd7f41a86cf008d34b96de1b.tar.gz
chromium_src-699cab9ba3a0fcb9dd7f41a86cf008d34b96de1b.tar.bz2
Mac client-side SSL cert improvements.
Allow Netscape-style client certs. Remember which identity the user chooses for a domain, and put it at the top of the list next time. BUG=36316,36446 TEST=none Review URL: http://codereview.chromium.org/651090 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39904 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ssl/ssl_client_auth_handler_mac.mm4
-rw-r--r--net/base/x509_certificate.h9
-rw-r--r--net/base/x509_certificate_mac.cc73
-rw-r--r--net/socket/ssl_client_socket_mac.cc3
4 files changed, 62 insertions, 27 deletions
diff --git a/chrome/browser/ssl/ssl_client_auth_handler_mac.mm b/chrome/browser/ssl/ssl_client_auth_handler_mac.mm
index 6908074..cde8acc 100644
--- a/chrome/browser/ssl/ssl_client_auth_handler_mac.mm
+++ b/chrome/browser/ssl/ssl_client_auth_handler_mac.mm
@@ -10,6 +10,7 @@
#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"
@@ -38,6 +39,9 @@ void SSLClientAuthHandler::DoSelectCertificate() {
// Create and set up a system choose-identity panel.
scoped_nsobject<SFChooseIdentityPanel> 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;
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h
index b9a3995..f3f3fea 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -225,15 +225,22 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
#endif
#if defined(OS_MACOSX)
+ // Does this certificate's usage allow SSL client authentication?
+ bool SupportsSSLClientAuth() const;
+
// Creates a security policy for SSL client certificates.
static OSStatus CreateSSLClientPolicy(SecPolicyRef* outPolicy);
// Adds all available SSL client identity certs to the given vector.
+ // |server_domain| is a hint for which domain the cert is to be sent to
+ // (a cert previously specified as the default for that domain will be given
+ // precedence and returned first in the output vector.)
static bool GetSSLClientCertificates(
+ const std::string& server_domain,
std::vector<scoped_refptr<X509Certificate> >* certs);
// Creates the chain of certs to use for this client identity cert.
- CFArrayRef CreateClientCertificateChain();
+ CFArrayRef CreateClientCertificateChain() const;
#endif
// Verifies the certificate against the given hostname. Returns OK if
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index 9487410..36fc65a 100644
--- a/net/base/x509_certificate_mac.cc
+++ b/net/base/x509_certificate_mac.cc
@@ -10,6 +10,7 @@
#include "base/scoped_cftyperef.h"
#include "base/logging.h"
#include "base/pickle.h"
+#include "base/sys_string_conversions.h"
#include "net/base/cert_status_flags.h"
#include "net/base/cert_verify_result.h"
#include "net/base/net_errors.h"
@@ -356,27 +357,6 @@ void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle,
}
}
-// Returns true if this cert supports a given extended key usage.
-bool CertSupportsUsage(SecCertificateRef cert, const CSSM_OID& usage_oid) {
- CSSMFields fields;
- if (GetCertFields(cert, &fields) != noErr)
- return false;
- for (unsigned f = 0; f < fields.num_of_fields; ++f) {
- const CSSM_FIELD &field = fields.fields[f];
- if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_ExtendedKeyUsage)) {
- const CSSM_X509_EXTENSION* ext =
- reinterpret_cast<const CSSM_X509_EXTENSION*>(field.FieldValue.Data);
- const CE_ExtendedKeyUsage* usage =
- reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
- for (unsigned p = 0; p < usage->numPurposes; ++p) {
- if (CSSMOIDEqual(&usage->purposes[p], &usage_oid))
- return true;
- }
- }
- }
- return false;
-}
-
// Creates a SecPolicyRef for the given OID, with optional value.
OSStatus CreatePolicy(const CSSM_OID* policy_OID,
void* option_data,
@@ -732,6 +712,31 @@ X509Certificate::Fingerprint X509Certificate::CalculateFingerprint(
return sha1;
}
+bool X509Certificate::SupportsSSLClientAuth() const {
+ CSSMFields fields;
+ if (GetCertFields(cert_handle_, &fields) != noErr)
+ return false;
+ for (unsigned f = 0; f < fields.num_of_fields; ++f) {
+ const CSSM_FIELD& field = fields.fields[f];
+ const CSSM_X509_EXTENSION* ext =
+ reinterpret_cast<const CSSM_X509_EXTENSION*>(field.FieldValue.Data);
+ if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_ExtendedKeyUsage)) {
+ const CE_ExtendedKeyUsage* usage =
+ reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
+ for (unsigned p = 0; p < usage->numPurposes; ++p) {
+ if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ClientAuth))
+ return true;
+ }
+ } else if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_NetscapeCertType)) {
+ uint16_t flags =
+ *reinterpret_cast<const uint16_t*>(ext->value.parsedValue);
+ if (flags & CE_NCT_SSL_Client)
+ return true;
+ }
+ }
+ return false;
+}
+
// static
OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) {
CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = {
@@ -748,7 +753,21 @@ OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) {
// static
bool X509Certificate::GetSSLClientCertificates (
+ const std::string& server_domain,
std::vector<scoped_refptr<X509Certificate> >* certs) {
+ scoped_cftyperef<SecIdentityRef> preferred_identity;
+ if (!server_domain.empty()) {
+ // See if there's an identity preference for this domain:
+ scoped_cftyperef<CFStringRef> domain_str(
+ base::SysUTF8ToCFStringRef("https://" + server_domain));
+ SecIdentityRef identity = NULL;
+ if (SecIdentityCopyPreference(domain_str,
+ 0,
+ NULL,
+ &identity) == noErr)
+ preferred_identity.reset(identity);
+ }
+
SecIdentitySearchRef search = nil;
OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search);
fprintf(stderr,"====Created SecIdentitySearch %p\n",search);//TEMP
@@ -768,8 +787,7 @@ bool X509Certificate::GetSSLClientCertificates (
scoped_refptr<X509Certificate> cert(
CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT));
// cert_handle is adoped by cert, so I don't need to release it myself.
- if (cert->HasExpired() ||
- !CertSupportsUsage(cert_handle, CSSMOID_ClientAuth))
+ if (cert->HasExpired() || !cert->SupportsSSLClientAuth())
continue;
// Skip duplicates (a cert may be in multiple keychains).
@@ -783,7 +801,12 @@ bool X509Certificate::GetSSLClientCertificates (
continue;
// The cert passes, so add it to the vector.
- certs->push_back(cert);
+ // If it's the preferred identity, add it at the start (so it'll be
+ // selected by default in the UI.)
+ if (preferred_identity && CFEqual(preferred_identity, identity))
+ certs->insert(certs->begin(), cert);
+ else
+ certs->push_back(cert);
}
if (err != errSecItemNotFound) {
@@ -793,7 +816,7 @@ bool X509Certificate::GetSSLClientCertificates (
return true;
}
-CFArrayRef X509Certificate::CreateClientCertificateChain() {
+CFArrayRef X509Certificate::CreateClientCertificateChain() const {
// Initialize the result array with just the IdentityRef of the receiver:
OSStatus result;
SecIdentityRef identity;
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index af0a11a..b03ed7a 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -658,7 +658,8 @@ void SSLClientSocketMac::GetSSLCertRequestInfo(
// I'm being asked for available client certs (identities).
cert_request_info->host_and_port = hostname_;
cert_request_info->client_certs.clear();
- X509Certificate::GetSSLClientCertificates(&cert_request_info->client_certs);
+ X509Certificate::GetSSLClientCertificates(hostname_,
+ &cert_request_info->client_certs);
}
SSLClientSocket::NextProtoStatus