Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(299)

Side by Side Diff: net/ssl/client_cert_store_impl_mac.cc

Issue 13866049: Fix client certificate authentication on Mac and Linux introduced in r178732 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Refresh key files for certs Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/socket/ssl_client_socket_openssl_unittest.cc ('k') | net/ssl/client_cert_store_impl_nss.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/ssl/client_cert_store_impl.h" 5 #include "net/ssl/client_cert_store_impl.h"
6 6
7 #include <CommonCrypto/CommonDigest.h> 7 #include <CommonCrypto/CommonDigest.h>
8 #include <CoreFoundation/CFArray.h> 8 #include <CoreFoundation/CFArray.h>
9 #include <CoreServices/CoreServices.h> 9 #include <CoreServices/CoreServices.h>
10 #include <Security/SecBase.h> 10 #include <Security/SecBase.h>
11 #include <Security/Security.h> 11 #include <Security/Security.h>
12 12
13 #include <algorithm> 13 #include <algorithm>
14 #include <string> 14 #include <string>
15 15
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/mac/mac_logging.h" 17 #include "base/mac/mac_logging.h"
18 #include "base/mac/scoped_cftyperef.h" 18 #include "base/mac/scoped_cftyperef.h"
19 #include "base/strings/sys_string_conversions.h" 19 #include "base/strings/sys_string_conversions.h"
20 #include "base/synchronization/lock.h" 20 #include "base/synchronization/lock.h"
21 #include "crypto/mac_security_services_lock.h" 21 #include "crypto/mac_security_services_lock.h"
22 #include "net/base/host_port_pair.h" 22 #include "net/base/host_port_pair.h"
23 #include "net/cert/x509_util.h" 23 #include "net/cert/x509_util.h"
24 #include "net/cert/x509_util_mac.h"
24 25
25 using base::mac::ScopedCFTypeRef; 26 using base::mac::ScopedCFTypeRef;
26 27
27 namespace net { 28 namespace net {
28 29
29 namespace { 30 namespace {
30 31
32 // Gets the issuer for a given cert, starting with the cert itself and
33 // including the intermediate and finally root certificates (if any).
34 // This function calls SecTrust but doesn't actually pay attention to the trust
35 // result: it shouldn't be used to determine trust, just to traverse the chain.
36 // Caller is responsible for releasing the value stored into *out_cert_chain.
37 OSStatus CopyCertChain(SecCertificateRef cert_handle,
38 CFArrayRef* out_cert_chain) {
39 DCHECK(cert_handle);
40 DCHECK(out_cert_chain);
41
42 // Create an SSL policy ref configured for client cert evaluation.
43 SecPolicyRef ssl_policy;
44 OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy);
45 if (result)
46 return result;
47 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy);
48
49 // Create a SecTrustRef.
50 ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate(
51 NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)),
52 1, &kCFTypeArrayCallBacks));
53 SecTrustRef trust_ref = NULL;
54 {
55 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
56 result = SecTrustCreateWithCertificates(input_certs, ssl_policy,
57 &trust_ref);
58 }
59 if (result)
60 return result;
61 ScopedCFTypeRef<SecTrustRef> trust(trust_ref);
62
63 // Evaluate trust, which creates the cert chain.
64 SecTrustResultType status;
65 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain;
66 {
67 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
68 result = SecTrustEvaluate(trust, &status);
69 }
70 if (result)
71 return result;
72 {
73 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
74 result = SecTrustGetResult(trust, &status, out_cert_chain, &status_chain);
75 }
76 return result;
77 }
78
79 // Returns true if |*cert| is issued by an authority in |valid_issuers|
80 // according to Keychain Services, rather than using |cert|'s intermediate
81 // certificates. If it is, |*cert| is updated to point to the completed
82 // certificate
83 bool IsIssuedByInKeychain(const std::vector<std::string>& valid_issuers,
84 scoped_refptr<X509Certificate>* cert) {
85 DCHECK(cert);
86 DCHECK(*cert);
87
88 X509Certificate::OSCertHandle cert_handle = (*cert)->os_cert_handle();
89 CFArrayRef cert_chain = NULL;
90 OSStatus result = CopyCertChain(cert_handle, &cert_chain);
91 if (result) {
92 OSSTATUS_LOG(ERROR, result) << "CopyCertChain error";
93 return false;
94 }
95
96 if (!cert_chain)
97 return false;
98
99 X509Certificate::OSCertHandles intermediates;
100 for (CFIndex i = 1, chain_count = CFArrayGetCount(cert_chain);
101 i < chain_count; ++i) {
102 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
103 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i)));
104 intermediates.push_back(cert);
105 }
106
107 scoped_refptr<X509Certificate> new_cert(X509Certificate::CreateFromHandle(
108 cert_handle, intermediates));
109 CFRelease(cert_chain); // Also frees |intermediates|.
110
111 if (!new_cert->IsIssuedByEncoded(valid_issuers))
112 return false;
113
114 cert->swap(new_cert);
115 return true;
116 }
117
118 // Examines the certificates in |preferred_cert| and |regular_certs| to find
119 // all certificates that match the client certificate request in |request|,
120 // storing the matching certificates in |selected_certs|.
121 // If |query_keychain| is true, Keychain Services will be queried to construct
122 // full certificate chains. If it is false, only the the certificates and their
123 // intermediates (available via X509Certificate::GetIntermediateCertificates())
124 // will be considered.
31 bool GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, 125 bool GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert,
32 const CertificateList& regular_certs, 126 const CertificateList& regular_certs,
33 const SSLCertRequestInfo& request, 127 const SSLCertRequestInfo& request,
128 bool query_keychain,
34 CertificateList* selected_certs) { 129 CertificateList* selected_certs) {
35 CertificateList preliminary_list; 130 CertificateList preliminary_list;
36 if (preferred_cert) 131 if (preferred_cert)
37 preliminary_list.push_back(preferred_cert); 132 preliminary_list.push_back(preferred_cert);
38 preliminary_list.insert(preliminary_list.end(), regular_certs.begin(), 133 preliminary_list.insert(preliminary_list.end(), regular_certs.begin(),
39 regular_certs.end()); 134 regular_certs.end());
40 135
41 selected_certs->clear(); 136 selected_certs->clear();
42 for (size_t i = 0; i < preliminary_list.size(); ++i) { 137 for (size_t i = 0; i < preliminary_list.size(); ++i) {
43 scoped_refptr<X509Certificate>& cert = preliminary_list[i]; 138 scoped_refptr<X509Certificate>& cert = preliminary_list[i];
44 if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) 139 if (cert->HasExpired() || !cert->SupportsSSLClientAuth())
45 continue; 140 continue;
46 141
47 // Skip duplicates (a cert may be in multiple keychains). 142 // Skip duplicates (a cert may be in multiple keychains).
48 const SHA1HashValue& fingerprint = cert->fingerprint(); 143 const SHA1HashValue& fingerprint = cert->fingerprint();
49 size_t pos; 144 size_t pos;
50 for (pos = 0; pos < selected_certs->size(); ++pos) { 145 for (pos = 0; pos < selected_certs->size(); ++pos) {
51 if ((*selected_certs)[pos]->fingerprint().Equals(fingerprint)) 146 if ((*selected_certs)[pos]->fingerprint().Equals(fingerprint))
52 break; 147 break;
53 } 148 }
54 if (pos < selected_certs->size()) 149 if (pos < selected_certs->size())
55 continue; 150 continue;
56 151
57 // Check if the certificate issuer is allowed by the server. 152 // Check if the certificate issuer is allowed by the server.
58 if (!request.cert_authorities.empty() && 153 if (request.cert_authorities.empty() ||
59 !cert->IsIssuedByEncoded(request.cert_authorities)) { 154 cert->IsIssuedByEncoded(request.cert_authorities) ||
60 continue; 155 (query_keychain &&
156 IsIssuedByInKeychain(request.cert_authorities, &cert))) {
157 selected_certs->push_back(cert);
61 } 158 }
62 selected_certs->push_back(cert);
63 } 159 }
64 160
65 // Preferred cert should appear first in the ui, so exclude it from the 161 // Preferred cert should appear first in the ui, so exclude it from the
66 // sorting. 162 // sorting.
67 CertificateList::iterator sort_begin = selected_certs->begin(); 163 CertificateList::iterator sort_begin = selected_certs->begin();
68 CertificateList::iterator sort_end = selected_certs->end(); 164 CertificateList::iterator sort_end = selected_certs->end();
69 if (preferred_cert && 165 if (preferred_cert &&
70 sort_begin != sort_end && 166 sort_begin != sort_end &&
71 *sort_begin == preferred_cert) { 167 *sort_begin == preferred_cert) {
72 ++sort_begin; 168 ++sort_begin;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 } else { 236 } else {
141 regular_certs.push_back(cert); 237 regular_certs.push_back(cert);
142 } 238 }
143 } 239 }
144 240
145 if (err != errSecItemNotFound) { 241 if (err != errSecItemNotFound) {
146 OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error"; 242 OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error";
147 return false; 243 return false;
148 } 244 }
149 245
150 return GetClientCertsImpl(preferred_cert, regular_certs, request, 246 return GetClientCertsImpl(preferred_cert, regular_certs, request, true,
151 selected_certs); 247 selected_certs);
152 } 248 }
153 249
154 bool ClientCertStoreImpl::SelectClientCerts(const CertificateList& input_certs, 250 bool ClientCertStoreImpl::SelectClientCerts(const CertificateList& input_certs,
155 const SSLCertRequestInfo& request, 251 const SSLCertRequestInfo& request,
156 CertificateList* selected_certs) { 252 CertificateList* selected_certs) {
157 return GetClientCertsImpl(NULL, input_certs, request, 253 return GetClientCertsImpl(NULL, input_certs, request, false,
158 selected_certs); 254 selected_certs);
159 } 255 }
160 256
161 #if defined(OS_MACOSX) && !defined(OS_IOS) 257 #if defined(OS_MACOSX) && !defined(OS_IOS)
162 bool ClientCertStoreImpl::SelectClientCertsGivenPreferred( 258 bool ClientCertStoreImpl::SelectClientCertsGivenPreferred(
163 const scoped_refptr<X509Certificate>& preferred_cert, 259 const scoped_refptr<X509Certificate>& preferred_cert,
164 const CertificateList& regular_certs, 260 const CertificateList& regular_certs,
165 const SSLCertRequestInfo& request, 261 const SSLCertRequestInfo& request,
166 CertificateList* selected_certs) { 262 CertificateList* selected_certs) {
167 return GetClientCertsImpl(preferred_cert, regular_certs, request, 263 return GetClientCertsImpl(preferred_cert, regular_certs, request, false,
168 selected_certs); 264 selected_certs);
169 } 265 }
170 #endif 266 #endif
171 267
172 } // namespace net 268 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/ssl_client_socket_openssl_unittest.cc ('k') | net/ssl/client_cert_store_impl_nss.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698