OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // This file includes code SSLClientSocketNSS::DoVerifyCertComplete() derived | 5 // This file includes code SSLClientSocketNSS::DoVerifyCertComplete() derived |
6 // from AuthCertificateCallback() in | 6 // from AuthCertificateCallback() in |
7 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. | 7 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. |
8 | 8 |
9 /* ***** BEGIN LICENSE BLOCK ***** | 9 /* ***** BEGIN LICENSE BLOCK ***** |
10 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 10 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
(...skipping 2119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2130 CERTCertList** result_certs, | 2130 CERTCertList** result_certs, |
2131 void** result_private_key) { | 2131 void** result_private_key) { |
2132 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); | 2132 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); |
2133 | 2133 |
2134 that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert; | 2134 that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert; |
2135 #if defined(OS_WIN) | 2135 #if defined(OS_WIN) |
2136 if (that->ssl_config_.send_client_cert) { | 2136 if (that->ssl_config_.send_client_cert) { |
2137 if (that->ssl_config_.client_cert) { | 2137 if (that->ssl_config_.client_cert) { |
2138 PCCERT_CONTEXT cert_context = | 2138 PCCERT_CONTEXT cert_context = |
2139 that->ssl_config_.client_cert->os_cert_handle(); | 2139 that->ssl_config_.client_cert->os_cert_handle(); |
2140 PCERT_KEY_CONTEXT key_context = reinterpret_cast<PCERT_KEY_CONTEXT>( | |
2141 PORT_ZAlloc(sizeof(CERT_KEY_CONTEXT))); | |
2142 if (!key_context) | |
2143 return SECFailure; | |
2144 key_context->cbSize = sizeof(*key_context); | |
2145 | 2140 |
2141 HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv = INVALID_HANDLE; | |
2142 DWORD dwKeySpec = 0; | |
wtc
2011/09/23 19:53:34
I haven't seen the INVALID_HANDLE macro before. S
| |
2146 BOOL must_free = FALSE; | 2143 BOOL must_free = FALSE; |
2147 BOOL acquired_key = CryptAcquireCertificatePrivateKey( | 2144 BOOL acquired_key = CryptAcquireCertificatePrivateKey( |
2148 cert_context, CRYPT_ACQUIRE_CACHE_FLAG, NULL, | 2145 cert_context, CRYPT_ACQUIRE_CACHE_FLAG, NULL, |
2149 &key_context->hCryptProv, &key_context->dwKeySpec, &must_free); | 2146 &hCryptProv, &dwKeySpec, &must_free); |
2150 if (acquired_key && key_context->hCryptProv) { | 2147 // Since we passed CRYPT_ACQUIRE_CACHE_FLAG, |must_free| must be false |
2151 DCHECK_NE(key_context->dwKeySpec, CERT_NCRYPT_KEY_SPEC); | 2148 // according to the MSDN documentation. |
2149 DCHECK(must_free == FALSE); | |
wtc
2011/09/23 19:53:34
You can use DCHECK_EQ here. cpplint probably will
Ryan Sleevi
2011/09/23 22:33:50
Double checked my notes from disassembling this fu
| |
2152 | 2150 |
2153 // The certificate cache may have been updated/used, in which case, | 2151 if (acquired_key && hCryptProv != INVALID_HANDLE) { |
2154 // duplicate the existing handle, since NSS will free it when no | 2152 DCHECK_NE(dwKeySpec, CERT_NCRYPT_KEY_SPEC); |
2155 // longer in use. | |
2156 if (!must_free) | |
2157 CryptContextAddRef(key_context->hCryptProv, NULL, 0); | |
2158 | 2153 |
2159 SECItem der_cert; | 2154 SECItem der_cert; |
2160 der_cert.type = siDERCertBuffer; | 2155 der_cert.type = siDERCertBuffer; |
2161 der_cert.data = cert_context->pbCertEncoded; | 2156 der_cert.data = cert_context->pbCertEncoded; |
2162 der_cert.len = cert_context->cbCertEncoded; | 2157 der_cert.len = cert_context->cbCertEncoded; |
2163 | 2158 |
2164 // TODO(rsleevi): Error checking for NSS allocation errors. | 2159 // TODO(rsleevi): Error checking for NSS allocation errors. |
2165 *result_certs = CERT_NewCertList(); | |
2166 CERTCertDBHandle* db_handle = CERT_GetDefaultCertDB(); | 2160 CERTCertDBHandle* db_handle = CERT_GetDefaultCertDB(); |
2167 CERTCertificate* user_cert = CERT_NewTempCertificate( | 2161 CERTCertificate* user_cert = CERT_NewTempCertificate( |
2168 db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); | 2162 db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); |
2169 CERT_AddCertToListTail(*result_certs, user_cert); | 2163 if (!user_cert) { |
2164 // Importing the certificate can fail for reasons including a serial | |
2165 // number collision. See crbug.com/97355. | |
2166 return SECFailure; | |
2167 } | |
2168 CERTCertList* cert_chain = CERT_NewCertList(); | |
2169 CERT_AddCertToListTail(cert_chain, user_cert); | |
2170 | 2170 |
2171 // Add the intermediates. | 2171 // Add the intermediates. |
2172 X509Certificate::OSCertHandles intermediates = | 2172 X509Certificate::OSCertHandles intermediates = |
2173 that->ssl_config_.client_cert->GetIntermediateCertificates(); | 2173 that->ssl_config_.client_cert->GetIntermediateCertificates(); |
2174 for (X509Certificate::OSCertHandles::const_iterator it = | 2174 for (X509Certificate::OSCertHandles::const_iterator it = |
2175 intermediates.begin(); it != intermediates.end(); ++it) { | 2175 intermediates.begin(); it != intermediates.end(); ++it) { |
2176 der_cert.data = (*it)->pbCertEncoded; | 2176 der_cert.data = (*it)->pbCertEncoded; |
2177 der_cert.len = (*it)->cbCertEncoded; | 2177 der_cert.len = (*it)->cbCertEncoded; |
2178 | 2178 |
2179 CERTCertificate* intermediate = CERT_NewTempCertificate( | 2179 CERTCertificate* intermediate = CERT_NewTempCertificate( |
2180 db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); | 2180 db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); |
2181 CERT_AddCertToListTail(*result_certs, intermediate); | 2181 if (!intermediate) { |
2182 CERT_DestroyCertList(cert_chain); | |
2183 return SECFailure; | |
2184 } | |
2185 CERT_AddCertToListTail(cert_chain, intermediate); | |
2182 } | 2186 } |
2187 PCERT_KEY_CONTEXT key_context = reinterpret_cast<PCERT_KEY_CONTEXT>( | |
2188 PORT_ZAlloc(sizeof(CERT_KEY_CONTEXT)); | |
2189 key_context->cbSize = sizeof(*key_context); | |
2190 // NSS will free this context when no longer in use, but the | |
2191 // |must_free| result from CryptAcquireCertificatePrivateKey was false | |
2192 // so we increment the refcount to negate NSS's future decrement. | |
2193 CryptContextAddRef(hCryptProv, NULL, 0); | |
2194 key_context->hCryptProv = hCryptProv; | |
2195 key_context->dwKeySpec = dwKeySpec; | |
2183 *result_private_key = key_context; | 2196 *result_private_key = key_context; |
2197 *result_certs = cert_chain; | |
2198 | |
2184 return SECSuccess; | 2199 return SECSuccess; |
2185 } | 2200 } |
2186 PORT_Free(key_context); | |
2187 LOG(WARNING) << "Client cert found without private key"; | 2201 LOG(WARNING) << "Client cert found without private key"; |
2188 } | 2202 } |
2189 // Send no client certificate. | 2203 // Send no client certificate. |
2190 return SECFailure; | 2204 return SECFailure; |
2191 } | 2205 } |
2192 | 2206 |
2193 that->client_certs_.clear(); | 2207 that->client_certs_.clear(); |
2194 | 2208 |
2195 std::vector<CERT_NAME_BLOB> issuer_list(ca_names->nnames); | 2209 std::vector<CERT_NAME_BLOB> issuer_list(ca_names->nnames); |
2196 for (int i = 0; i < ca_names->nnames; ++i) { | 2210 for (int i = 0; i < ca_names->nnames; ++i) { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2291 that->ssl_config_.client_cert->CreateClientCertificateChain(); | 2305 that->ssl_config_.client_cert->CreateClientCertificateChain(); |
2292 if (chain) { | 2306 if (chain) { |
2293 identity = reinterpret_cast<SecIdentityRef>( | 2307 identity = reinterpret_cast<SecIdentityRef>( |
2294 const_cast<void*>(CFArrayGetValueAtIndex(chain, 0))); | 2308 const_cast<void*>(CFArrayGetValueAtIndex(chain, 0))); |
2295 } | 2309 } |
2296 if (identity) | 2310 if (identity) |
2297 os_error = SecIdentityCopyPrivateKey(identity, &private_key); | 2311 os_error = SecIdentityCopyPrivateKey(identity, &private_key); |
2298 | 2312 |
2299 if (chain && identity && os_error == noErr) { | 2313 if (chain && identity && os_error == noErr) { |
2300 // TODO(rsleevi): Error checking for NSS allocation errors. | 2314 // TODO(rsleevi): Error checking for NSS allocation errors. |
2301 *result_certs = CERT_NewCertList(); | 2315 *result_certs = CERT_NewCertList(); |
Ryan Sleevi
2011/09/23 22:33:50
Should the same restructuring added in the Windows
wtc
2011/09/26 18:26:07
rsleevi: ("lines 296-297" is a typo). The Mac cod
| |
2302 *result_private_key = private_key; | 2316 *result_private_key = private_key; |
2303 | 2317 |
2304 for (CFIndex i = 0; i < CFArrayGetCount(chain); ++i) { | 2318 for (CFIndex i = 0; i < CFArrayGetCount(chain); ++i) { |
2305 CSSM_DATA cert_data; | 2319 CSSM_DATA cert_data; |
2306 SecCertificateRef cert_ref; | 2320 SecCertificateRef cert_ref; |
2307 if (i == 0) { | 2321 if (i == 0) { |
2308 cert_ref = that->ssl_config_.client_cert->os_cert_handle(); | 2322 cert_ref = that->ssl_config_.client_cert->os_cert_handle(); |
2309 } else { | 2323 } else { |
2310 cert_ref = reinterpret_cast<SecCertificateRef>( | 2324 cert_ref = reinterpret_cast<SecCertificateRef>( |
2311 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); | 2325 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); |
2312 } | 2326 } |
2313 os_error = SecCertificateGetData(cert_ref, &cert_data); | 2327 os_error = SecCertificateGetData(cert_ref, &cert_data); |
2314 if (os_error != noErr) | 2328 if (os_error != noErr) |
2315 break; | 2329 break; |
2316 | 2330 |
2317 SECItem der_cert; | 2331 SECItem der_cert; |
2318 der_cert.type = siDERCertBuffer; | 2332 der_cert.type = siDERCertBuffer; |
2319 der_cert.data = cert_data.Data; | 2333 der_cert.data = cert_data.Data; |
2320 der_cert.len = cert_data.Length; | 2334 der_cert.len = cert_data.Length; |
2321 CERTCertificate* nss_cert = CERT_NewTempCertificate( | 2335 CERTCertificate* nss_cert = CERT_NewTempCertificate( |
2322 CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE); | 2336 CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE); |
2337 if (!nss_cert) { | |
2338 // In the event of an NSS error we make up an OS error and reuse | |
2339 // the error handling, below. | |
2340 os_error = errKCCreateChainFailed; | |
2341 break; | |
2342 } | |
2323 CERT_AddCertToListTail(*result_certs, nss_cert); | 2343 CERT_AddCertToListTail(*result_certs, nss_cert); |
2324 } | 2344 } |
2325 } | 2345 } |
2326 if (os_error == noErr) { | 2346 if (os_error == noErr) { |
2327 CFRelease(chain); | 2347 CFRelease(chain); |
2328 return SECSuccess; | 2348 return SECSuccess; |
2329 } | 2349 } |
2330 LOG(WARNING) << "Client cert found, but could not be used: " | 2350 LOG(WARNING) << "Client cert found, but could not be used: " |
2331 << os_error; | 2351 << os_error; |
2332 if (*result_certs) { | 2352 if (*result_certs) { |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2498 valid_thread_id_ = base::PlatformThread::CurrentId(); | 2518 valid_thread_id_ = base::PlatformThread::CurrentId(); |
2499 } | 2519 } |
2500 | 2520 |
2501 bool SSLClientSocketNSS::CalledOnValidThread() const { | 2521 bool SSLClientSocketNSS::CalledOnValidThread() const { |
2502 EnsureThreadIdAssigned(); | 2522 EnsureThreadIdAssigned(); |
2503 base::AutoLock auto_lock(lock_); | 2523 base::AutoLock auto_lock(lock_); |
2504 return valid_thread_id_ == base::PlatformThread::CurrentId(); | 2524 return valid_thread_id_ == base::PlatformThread::CurrentId(); |
2505 } | 2525 } |
2506 | 2526 |
2507 } // namespace net | 2527 } // namespace net |
OLD | NEW |