OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_mac.h" | 5 #include "net/ssl/client_cert_store_mac.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> |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 cert_handle, intermediates)); | 114 cert_handle, intermediates)); |
115 CFRelease(cert_chain); // Also frees |intermediates|. | 115 CFRelease(cert_chain); // Also frees |intermediates|. |
116 | 116 |
117 if (!new_cert->IsIssuedByEncoded(valid_issuers)) | 117 if (!new_cert->IsIssuedByEncoded(valid_issuers)) |
118 return false; | 118 return false; |
119 | 119 |
120 cert->swap(new_cert); | 120 cert->swap(new_cert); |
121 return true; | 121 return true; |
122 } | 122 } |
123 | 123 |
| 124 // Returns true if |purpose| is listed as allowed in |usage|. This |
| 125 // function also considers the "Any" purpose. If the attribute is |
| 126 // present and empty, we return false. |
| 127 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage, |
| 128 const CSSM_OID* purpose) { |
| 129 for (unsigned p = 0; p < usage->numPurposes; ++p) { |
| 130 if (CSSMOIDEqual(&usage->purposes[p], purpose)) |
| 131 return true; |
| 132 if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny)) |
| 133 return true; |
| 134 } |
| 135 return false; |
| 136 } |
| 137 |
| 138 // Does |cert|'s usage allow SSL client authentication? |
| 139 bool SupportsSSLClientAuth(SecCertificateRef cert) { |
| 140 x509_util::CSSMCachedCertificate cached_cert; |
| 141 OSStatus status = cached_cert.Init(cert); |
| 142 if (status) |
| 143 return false; |
| 144 |
| 145 // RFC5280 says to take the intersection of the two extensions. |
| 146 // |
| 147 // Our underlying crypto libraries don't expose |
| 148 // ClientCertificateType, so for now we will not support fixed |
| 149 // Diffie-Hellman mechanisms. For rsa_sign, we need the |
| 150 // digitalSignature bit. |
| 151 // |
| 152 // In particular, if a key has the nonRepudiation bit and not the |
| 153 // digitalSignature one, we will not offer it to the user. |
| 154 x509_util::CSSMFieldValue key_usage; |
| 155 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage); |
| 156 if (status == CSSM_OK && key_usage.field()) { |
| 157 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); |
| 158 const CE_KeyUsage* key_usage_value = |
| 159 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); |
| 160 if (!((*key_usage_value) & CE_KU_DigitalSignature)) |
| 161 return false; |
| 162 } |
| 163 |
| 164 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage); |
| 165 if (status == CSSM_OK && key_usage.field()) { |
| 166 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); |
| 167 const CE_ExtendedKeyUsage* ext_key_usage = |
| 168 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); |
| 169 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) |
| 170 return false; |
| 171 } |
| 172 return true; |
| 173 } |
| 174 |
124 // Examines the certificates in |preferred_cert| and |regular_certs| to find | 175 // Examines the certificates in |preferred_cert| and |regular_certs| to find |
125 // all certificates that match the client certificate request in |request|, | 176 // all certificates that match the client certificate request in |request|, |
126 // storing the matching certificates in |selected_certs|. | 177 // storing the matching certificates in |selected_certs|. |
127 // If |query_keychain| is true, Keychain Services will be queried to construct | 178 // If |query_keychain| is true, Keychain Services will be queried to construct |
128 // full certificate chains. If it is false, only the the certificates and their | 179 // full certificate chains. If it is false, only the the certificates and their |
129 // intermediates (available via X509Certificate::GetIntermediateCertificates()) | 180 // intermediates (available via X509Certificate::GetIntermediateCertificates()) |
130 // will be considered. | 181 // will be considered. |
131 void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, | 182 void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, |
132 const CertificateList& regular_certs, | 183 const CertificateList& regular_certs, |
133 const SSLCertRequestInfo& request, | 184 const SSLCertRequestInfo& request, |
134 bool query_keychain, | 185 bool query_keychain, |
135 CertificateList* selected_certs) { | 186 CertificateList* selected_certs) { |
136 CertificateList preliminary_list; | 187 CertificateList preliminary_list; |
137 if (preferred_cert.get()) | 188 if (preferred_cert.get()) |
138 preliminary_list.push_back(preferred_cert); | 189 preliminary_list.push_back(preferred_cert); |
139 preliminary_list.insert(preliminary_list.end(), regular_certs.begin(), | 190 preliminary_list.insert(preliminary_list.end(), regular_certs.begin(), |
140 regular_certs.end()); | 191 regular_certs.end()); |
141 | 192 |
142 selected_certs->clear(); | 193 selected_certs->clear(); |
143 for (size_t i = 0; i < preliminary_list.size(); ++i) { | 194 for (size_t i = 0; i < preliminary_list.size(); ++i) { |
144 scoped_refptr<X509Certificate>& cert = preliminary_list[i]; | 195 scoped_refptr<X509Certificate>& cert = preliminary_list[i]; |
145 if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) | 196 if (cert->HasExpired() || !SupportsSSLClientAuth(cert->os_cert_handle())) |
146 continue; | 197 continue; |
147 | 198 |
148 // Skip duplicates (a cert may be in multiple keychains). | 199 // Skip duplicates (a cert may be in multiple keychains). |
149 auto cert_iter = std::find_if( | 200 auto cert_iter = std::find_if( |
150 selected_certs->begin(), selected_certs->end(), | 201 selected_certs->begin(), selected_certs->end(), |
151 [&cert](const scoped_refptr<X509Certificate>& other_cert) { | 202 [&cert](const scoped_refptr<X509Certificate>& other_cert) { |
152 return X509Certificate::IsSameOSCert(cert->os_cert_handle(), | 203 return X509Certificate::IsSameOSCert(cert->os_cert_handle(), |
153 other_cert->os_cert_handle()); | 204 other_cert->os_cert_handle()); |
154 }); | 205 }); |
155 if (cert_iter != selected_certs->end()) | 206 if (cert_iter != selected_certs->end()) |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 const SSLCertRequestInfo& request, | 326 const SSLCertRequestInfo& request, |
276 CertificateList* selected_certs) { | 327 CertificateList* selected_certs) { |
277 GetClientCertsImpl( | 328 GetClientCertsImpl( |
278 preferred_cert, regular_certs, request, false, selected_certs); | 329 preferred_cert, regular_certs, request, false, selected_certs); |
279 return true; | 330 return true; |
280 } | 331 } |
281 | 332 |
282 #pragma clang diagnostic pop // "-Wdeprecated-declarations" | 333 #pragma clang diagnostic pop // "-Wdeprecated-declarations" |
283 | 334 |
284 } // namespace net | 335 } // namespace net |
OLD | NEW |