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

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: 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
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/foundation_util.h"
17 #include "base/mac/mac_logging.h" 18 #include "base/mac/mac_logging.h"
18 #include "base/mac/scoped_cftyperef.h" 19 #include "base/mac/scoped_cftyperef.h"
19 #include "base/strings/sys_string_conversions.h" 20 #include "base/strings/sys_string_conversions.h"
20 #include "base/synchronization/lock.h" 21 #include "base/synchronization/lock.h"
21 #include "crypto/mac_security_services_lock.h" 22 #include "crypto/mac_security_services_lock.h"
22 #include "net/base/host_port_pair.h" 23 #include "net/base/host_port_pair.h"
23 #include "net/cert/x509_util.h" 24 #include "net/cert/x509_util.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 = base::mac::CFCastStrict<SecCertificateRef>(
103 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))
Ryan Sleevi 2013/04/16 02:32:50 The downside to this approach is that |new_cert->o
112 return false;
113
114 cert->swap(new_cert);
115 return true;
116 }
117
31 bool GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, 118 bool GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert,
32 const CertificateList& regular_certs, 119 const CertificateList& regular_certs,
33 const SSLCertRequestInfo& request, 120 const SSLCertRequestInfo& request,
121 bool query_keychain,
wtc 2013/04/16 18:50:32 query_keychain probably should be documented. It'
Ryan Sleevi 2013/04/16 19:00:26 Good point. Will add comments to these functions.
34 CertificateList* selected_certs) { 122 CertificateList* selected_certs) {
35 CertificateList preliminary_list; 123 CertificateList preliminary_list;
36 if (preferred_cert) 124 if (preferred_cert)
37 preliminary_list.push_back(preferred_cert); 125 preliminary_list.push_back(preferred_cert);
38 preliminary_list.insert(preliminary_list.end(), regular_certs.begin(), 126 preliminary_list.insert(preliminary_list.end(), regular_certs.begin(),
39 regular_certs.end()); 127 regular_certs.end());
40 128
41 selected_certs->clear(); 129 selected_certs->clear();
42 for (size_t i = 0; i < preliminary_list.size(); ++i) { 130 for (size_t i = 0; i < preliminary_list.size(); ++i) {
43 scoped_refptr<X509Certificate>& cert = preliminary_list[i]; 131 scoped_refptr<X509Certificate>& cert = preliminary_list[i];
44 if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) 132 if (cert->HasExpired() || !cert->SupportsSSLClientAuth())
45 continue; 133 continue;
46 134
47 // Skip duplicates (a cert may be in multiple keychains). 135 // Skip duplicates (a cert may be in multiple keychains).
48 const SHA1HashValue& fingerprint = cert->fingerprint(); 136 const SHA1HashValue& fingerprint = cert->fingerprint();
49 size_t pos; 137 size_t pos;
50 for (pos = 0; pos < selected_certs->size(); ++pos) { 138 for (pos = 0; pos < selected_certs->size(); ++pos) {
51 if ((*selected_certs)[pos]->fingerprint().Equals(fingerprint)) 139 if ((*selected_certs)[pos]->fingerprint().Equals(fingerprint))
52 break; 140 break;
53 } 141 }
54 if (pos < selected_certs->size()) 142 if (pos < selected_certs->size())
55 continue; 143 continue;
56 144
57 // Check if the certificate issuer is allowed by the server. 145 // Check if the certificate issuer is allowed by the server.
58 if (!request.cert_authorities.empty() && 146 if (request.cert_authorities.empty() ||
59 !cert->IsIssuedByEncoded(request.cert_authorities)) { 147 cert->IsIssuedByEncoded(request.cert_authorities) ||
60 continue; 148 (query_keychain &&
149 IsIssuedByInKeychain(request.cert_authorities, &cert))) {
150 selected_certs->push_back(cert);
61 } 151 }
62 selected_certs->push_back(cert);
63 } 152 }
64 153
65 // Preferred cert should appear first in the ui, so exclude it from the 154 // Preferred cert should appear first in the ui, so exclude it from the
66 // sorting. 155 // sorting.
67 CertificateList::iterator sort_begin = selected_certs->begin(); 156 CertificateList::iterator sort_begin = selected_certs->begin();
68 CertificateList::iterator sort_end = selected_certs->end(); 157 CertificateList::iterator sort_end = selected_certs->end();
69 if (preferred_cert && 158 if (preferred_cert &&
70 sort_begin != sort_end && 159 sort_begin != sort_end &&
71 *sort_begin == preferred_cert) { 160 *sort_begin == preferred_cert) {
72 ++sort_begin; 161 ++sort_begin;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 } else { 229 } else {
141 regular_certs.push_back(cert); 230 regular_certs.push_back(cert);
142 } 231 }
143 } 232 }
144 233
145 if (err != errSecItemNotFound) { 234 if (err != errSecItemNotFound) {
146 OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error"; 235 OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error";
147 return false; 236 return false;
148 } 237 }
149 238
150 return GetClientCertsImpl(preferred_cert, regular_certs, request, 239 return GetClientCertsImpl(preferred_cert, regular_certs, request, true,
151 selected_certs); 240 selected_certs);
152 } 241 }
153 242
154 bool ClientCertStoreImpl::SelectClientCerts(const CertificateList& input_certs, 243 bool ClientCertStoreImpl::SelectClientCerts(const CertificateList& input_certs,
155 const SSLCertRequestInfo& request, 244 const SSLCertRequestInfo& request,
156 CertificateList* selected_certs) { 245 CertificateList* selected_certs) {
157 return GetClientCertsImpl(NULL, input_certs, request, 246 return GetClientCertsImpl(NULL, input_certs, request, false,
158 selected_certs); 247 selected_certs);
159 } 248 }
160 249
161 #if defined(OS_MACOSX) && !defined(OS_IOS) 250 #if defined(OS_MACOSX) && !defined(OS_IOS)
162 bool ClientCertStoreImpl::SelectClientCertsGivenPreferred( 251 bool ClientCertStoreImpl::SelectClientCertsGivenPreferred(
163 const scoped_refptr<X509Certificate>& preferred_cert, 252 const scoped_refptr<X509Certificate>& preferred_cert,
164 const CertificateList& regular_certs, 253 const CertificateList& regular_certs,
165 const SSLCertRequestInfo& request, 254 const SSLCertRequestInfo& request,
166 CertificateList* selected_certs) { 255 CertificateList* selected_certs) {
167 return GetClientCertsImpl(preferred_cert, regular_certs, request, 256 return GetClientCertsImpl(preferred_cert, regular_certs, request, false,
168 selected_certs); 257 selected_certs);
169 } 258 }
170 #endif 259 #endif
171 260
172 } // namespace net 261 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698