diff options
-rw-r--r-- | chrome/browser/ssl/ssl_client_auth_handler_mac.mm | 4 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 9 | ||||
-rw-r--r-- | net/base/x509_certificate_mac.cc | 73 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_mac.cc | 3 |
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 |