| Index: net/ssl/client_cert_store_mac.cc
|
| diff --git a/net/ssl/client_cert_store_mac.cc b/net/ssl/client_cert_store_mac.cc
|
| index 7fadb337f1e7735ae8ffd340c81c93c95588d7c4..e1b65f773d698a900593a86298f560ea015f5e02 100644
|
| --- a/net/ssl/client_cert_store_mac.cc
|
| +++ b/net/ssl/client_cert_store_mac.cc
|
| @@ -17,6 +17,7 @@
|
| #include "base/logging.h"
|
| #include "base/mac/mac_logging.h"
|
| #include "base/mac/scoped_cftyperef.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "base/synchronization/lock.h"
|
| #include "crypto/mac_security_services_lock.h"
|
| @@ -24,6 +25,7 @@
|
| #include "net/cert/x509_util.h"
|
| #include "net/cert/x509_util_ios_and_mac.h"
|
| #include "net/cert/x509_util_mac.h"
|
| +#include "net/ssl/client_cert_identity_mac.h"
|
|
|
| using base::ScopedCFTypeRef;
|
|
|
| @@ -83,18 +85,18 @@ OSStatus CopyCertChain(SecCertificateRef cert_handle,
|
| return result;
|
| }
|
|
|
| -// Returns true if |*cert| is issued by an authority in |valid_issuers|
|
| -// according to Keychain Services, rather than using |cert|'s intermediate
|
| -// certificates. If it is, |*cert| is updated to point to the completed
|
| -// certificate
|
| +// Returns true if |*identity| is issued by an authority in |valid_issuers|
|
| +// according to Keychain Services, rather than using |identity|'s intermediate
|
| +// certificates. If it is, |*identity| is updated to include the intermediates.
|
| bool IsIssuedByInKeychain(const std::vector<std::string>& valid_issuers,
|
| - scoped_refptr<X509Certificate>* cert) {
|
| - DCHECK(cert);
|
| - DCHECK(cert->get());
|
| -
|
| - base::ScopedCFTypeRef<SecCertificateRef> os_cert(
|
| - x509_util::CreateSecCertificateFromX509Certificate(cert->get()));
|
| - if (!os_cert)
|
| + ClientCertIdentity* identity) {
|
| + DCHECK(identity);
|
| + DCHECK(identity->sec_identity_ref());
|
| +
|
| + ScopedCFTypeRef<SecCertificateRef> os_cert;
|
| + int err = SecIdentityCopyCertificate(identity->sec_identity_ref(),
|
| + os_cert.InitializeInto());
|
| + if (err != noErr)
|
| return false;
|
| CFArrayRef cert_chain = NULL;
|
| OSStatus result = CopyCertChain(os_cert.get(), &cert_chain);
|
| @@ -109,9 +111,9 @@ bool IsIssuedByInKeychain(const std::vector<std::string>& valid_issuers,
|
| std::vector<SecCertificateRef> intermediates;
|
| for (CFIndex i = 1, chain_count = CFArrayGetCount(cert_chain);
|
| i < chain_count; ++i) {
|
| - SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
|
| + SecCertificateRef sec_cert = reinterpret_cast<SecCertificateRef>(
|
| const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i)));
|
| - intermediates.push_back(cert);
|
| + intermediates.push_back(sec_cert);
|
| }
|
|
|
| scoped_refptr<X509Certificate> new_cert(
|
| @@ -122,7 +124,7 @@ bool IsIssuedByInKeychain(const std::vector<std::string>& valid_issuers,
|
| if (!new_cert || !new_cert->IsIssuedByEncoded(valid_issuers))
|
| return false;
|
|
|
| - cert->swap(new_cert);
|
| + identity->SetIntermediates(new_cert->GetIntermediateCertificates());
|
| return true;
|
| }
|
|
|
| @@ -177,58 +179,65 @@ bool SupportsSSLClientAuth(SecCertificateRef cert) {
|
| return true;
|
| }
|
|
|
| -// Examines the certificates in |preferred_cert| and |regular_certs| to find
|
| -// all certificates that match the client certificate request in |request|,
|
| -// storing the matching certificates in |selected_certs|.
|
| +// Examines the certificates in |preferred_identity| and |regular_identities| to
|
| +// find all certificates that match the client certificate request in |request|,
|
| +// storing the matching certificates in |selected_identities|.
|
| // If |query_keychain| is true, Keychain Services will be queried to construct
|
| // full certificate chains. If it is false, only the the certificates and their
|
| // intermediates (available via X509Certificate::GetIntermediateCertificates())
|
| // will be considered.
|
| -void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert,
|
| - const CertificateList& regular_certs,
|
| +void GetClientCertsImpl(std::unique_ptr<ClientCertIdentity> preferred_identity,
|
| + ClientCertIdentityList regular_identities,
|
| const SSLCertRequestInfo& request,
|
| bool query_keychain,
|
| - CertificateList* selected_certs) {
|
| - CertificateList preliminary_list;
|
| - if (preferred_cert.get())
|
| - preliminary_list.push_back(preferred_cert);
|
| - preliminary_list.insert(preliminary_list.end(), regular_certs.begin(),
|
| - regular_certs.end());
|
| -
|
| - selected_certs->clear();
|
| + ClientCertIdentityList* selected_identities) {
|
| + scoped_refptr<X509Certificate> preferred_cert_orig;
|
| + ClientCertIdentityList preliminary_list(std::move(regular_identities));
|
| + if (preferred_identity) {
|
| + preferred_cert_orig = preferred_identity->certificate();
|
| + preliminary_list.insert(preliminary_list.begin(),
|
| + std::move(preferred_identity));
|
| + }
|
| +
|
| + selected_identities->clear();
|
| for (size_t i = 0; i < preliminary_list.size(); ++i) {
|
| - scoped_refptr<X509Certificate>& cert = preliminary_list[i];
|
| - if (cert->HasExpired())
|
| + std::unique_ptr<ClientCertIdentity>& cert = preliminary_list[i];
|
| + if (cert->certificate()->HasExpired())
|
| continue;
|
|
|
| // Skip duplicates (a cert may be in multiple keychains).
|
| auto cert_iter = std::find_if(
|
| - selected_certs->begin(), selected_certs->end(),
|
| - [&cert](const scoped_refptr<X509Certificate>& other_cert) {
|
| - return X509Certificate::IsSameOSCert(cert->os_cert_handle(),
|
| - other_cert->os_cert_handle());
|
| + selected_identities->begin(), selected_identities->end(),
|
| + [&cert](
|
| + const std::unique_ptr<ClientCertIdentity>& other_cert_identity) {
|
| + return X509Certificate::IsSameOSCert(
|
| + cert->certificate()->os_cert_handle(),
|
| + other_cert_identity->certificate()->os_cert_handle());
|
| });
|
| - if (cert_iter != selected_certs->end())
|
| + if (cert_iter != selected_identities->end())
|
| continue;
|
|
|
| // Check if the certificate issuer is allowed by the server.
|
| if (request.cert_authorities.empty() ||
|
| - cert->IsIssuedByEncoded(request.cert_authorities) ||
|
| + cert->certificate()->IsIssuedByEncoded(request.cert_authorities) ||
|
| (query_keychain &&
|
| - IsIssuedByInKeychain(request.cert_authorities, &cert))) {
|
| - selected_certs->push_back(cert);
|
| + IsIssuedByInKeychain(request.cert_authorities, cert.get()))) {
|
| + selected_identities->push_back(std::move(cert));
|
| }
|
| }
|
|
|
| // Preferred cert should appear first in the ui, so exclude it from the
|
| - // sorting.
|
| - CertificateList::iterator sort_begin = selected_certs->begin();
|
| - CertificateList::iterator sort_end = selected_certs->end();
|
| - if (preferred_cert.get() && sort_begin != sort_end &&
|
| - sort_begin->get() == preferred_cert.get()) {
|
| + // sorting. Compare the os_cert_handle since the X509Certificate object may
|
| + // have changed if intermediates were added.
|
| + ClientCertIdentityList::iterator sort_begin = selected_identities->begin();
|
| + ClientCertIdentityList::iterator sort_end = selected_identities->end();
|
| + if (preferred_cert_orig && sort_begin != sort_end &&
|
| + X509Certificate::IsSameOSCert(
|
| + sort_begin->get()->certificate()->os_cert_handle(),
|
| + preferred_cert_orig->os_cert_handle())) {
|
| ++sort_begin;
|
| }
|
| - sort(sort_begin, sort_end, x509_util::ClientCertSorter());
|
| + sort(sort_begin, sort_end, ClientCertIdentitySorter());
|
| }
|
|
|
| } // namespace
|
| @@ -242,12 +251,12 @@ void ClientCertStoreMac::GetClientCerts(
|
| const ClientCertListCallback& callback) {
|
| std::string server_domain = request.host_and_port.host();
|
|
|
| - ScopedCFTypeRef<SecIdentityRef> preferred_identity;
|
| + ScopedCFTypeRef<SecIdentityRef> preferred_sec_identity;
|
| if (!server_domain.empty()) {
|
| // See if there's an identity preference for this domain:
|
| ScopedCFTypeRef<CFStringRef> domain_str(
|
| base::SysUTF8ToCFStringRef("https://" + server_domain));
|
| - SecIdentityRef identity = NULL;
|
| + SecIdentityRef sec_identity = NULL;
|
| // While SecIdentityCopyPreferences appears to take a list of CA issuers
|
| // to restrict the identity search to, within Security.framework the
|
| // argument is ignored and filtering unimplemented. See
|
| @@ -255,14 +264,15 @@ void ClientCertStoreMac::GetClientCerts(
|
| // _SecIdentityCopyPreferenceMatchingName().
|
| {
|
| base::AutoLock lock(crypto::GetMacSecurityServicesLock());
|
| - if (SecIdentityCopyPreference(domain_str, 0, NULL, &identity) == noErr)
|
| - preferred_identity.reset(identity);
|
| + if (SecIdentityCopyPreference(domain_str, 0, NULL, &sec_identity) ==
|
| + noErr)
|
| + preferred_sec_identity.reset(sec_identity);
|
| }
|
| }
|
|
|
| // Now enumerate the identities in the available keychains.
|
| - scoped_refptr<X509Certificate> preferred_cert = NULL;
|
| - CertificateList regular_certs;
|
| + std::unique_ptr<ClientCertIdentity> preferred_identity;
|
| + ClientCertIdentityList regular_identities;
|
|
|
| SecIdentitySearchRef search = NULL;
|
| OSStatus err;
|
| @@ -271,71 +281,76 @@ void ClientCertStoreMac::GetClientCerts(
|
| err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search);
|
| }
|
| if (err) {
|
| - callback.Run(CertificateList());
|
| + callback.Run(ClientCertIdentityList());
|
| return;
|
| }
|
| ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search);
|
| while (!err) {
|
| - SecIdentityRef identity = NULL;
|
| + ScopedCFTypeRef<SecIdentityRef> sec_identity;
|
| {
|
| base::AutoLock lock(crypto::GetMacSecurityServicesLock());
|
| - err = SecIdentitySearchCopyNext(search, &identity);
|
| + err = SecIdentitySearchCopyNext(search, sec_identity.InitializeInto());
|
| }
|
| if (err)
|
| break;
|
| - ScopedCFTypeRef<SecIdentityRef> scoped_identity(identity);
|
|
|
| - SecCertificateRef cert_handle;
|
| - err = SecIdentityCopyCertificate(identity, &cert_handle);
|
| + ScopedCFTypeRef<SecCertificateRef> cert_handle;
|
| + err = SecIdentityCopyCertificate(sec_identity.get(),
|
| + cert_handle.InitializeInto());
|
| if (err != noErr)
|
| continue;
|
| - ScopedCFTypeRef<SecCertificateRef> scoped_cert_handle(cert_handle);
|
|
|
| - if (!SupportsSSLClientAuth(cert_handle))
|
| + if (!SupportsSSLClientAuth(cert_handle.get()))
|
| continue;
|
|
|
| scoped_refptr<X509Certificate> cert(
|
| x509_util::CreateX509CertificateFromSecCertificate(
|
| - cert_handle, std::vector<SecCertificateRef>()));
|
| + cert_handle.get(), std::vector<SecCertificateRef>()));
|
| if (!cert)
|
| continue;
|
|
|
| - if (preferred_identity && CFEqual(preferred_identity, identity)) {
|
| + if (preferred_sec_identity &&
|
| + CFEqual(preferred_sec_identity, sec_identity.get())) {
|
| // Only one certificate should match.
|
| - DCHECK(!preferred_cert.get());
|
| - preferred_cert = cert;
|
| + DCHECK(!preferred_identity.get());
|
| + preferred_identity = base::MakeUnique<ClientCertIdentityMac>(
|
| + std::move(cert), std::move(sec_identity));
|
| } else {
|
| - regular_certs.push_back(cert);
|
| + regular_identities.push_back(base::MakeUnique<ClientCertIdentityMac>(
|
| + std::move(cert), std::move(sec_identity)));
|
| }
|
| }
|
|
|
| if (err != errSecItemNotFound) {
|
| OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error";
|
| - callback.Run(CertificateList());
|
| + callback.Run(ClientCertIdentityList());
|
| return;
|
| }
|
|
|
| - CertificateList selected_certs;
|
| - GetClientCertsImpl(preferred_cert, regular_certs, request, true,
|
| - &selected_certs);
|
| - callback.Run(std::move(selected_certs));
|
| + ClientCertIdentityList selected_identities;
|
| + GetClientCertsImpl(std::move(preferred_identity),
|
| + std::move(regular_identities), request, true,
|
| + &selected_identities);
|
| + callback.Run(std::move(selected_identities));
|
| }
|
|
|
| bool ClientCertStoreMac::SelectClientCertsForTesting(
|
| - const CertificateList& input_certs,
|
| + ClientCertIdentityList input_identities,
|
| const SSLCertRequestInfo& request,
|
| - CertificateList* selected_certs) {
|
| - GetClientCertsImpl(NULL, input_certs, request, false, selected_certs);
|
| + ClientCertIdentityList* selected_identities) {
|
| + GetClientCertsImpl(NULL, std::move(input_identities), request, false,
|
| + selected_identities);
|
| return true;
|
| }
|
|
|
| bool ClientCertStoreMac::SelectClientCertsGivenPreferredForTesting(
|
| - const scoped_refptr<X509Certificate>& preferred_cert,
|
| - const CertificateList& regular_certs,
|
| + std::unique_ptr<ClientCertIdentity> preferred_identity,
|
| + ClientCertIdentityList regular_identities,
|
| const SSLCertRequestInfo& request,
|
| - CertificateList* selected_certs) {
|
| - GetClientCertsImpl(
|
| - preferred_cert, regular_certs, request, false, selected_certs);
|
| + ClientCertIdentityList* selected_identities) {
|
| + GetClientCertsImpl(std::move(preferred_identity),
|
| + std::move(regular_identities), request, false,
|
| + selected_identities);
|
| return true;
|
| }
|
|
|
|
|