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

Side by Side Diff: net/socket/ssl_client_socket_nss.cc

Issue 7995009: net: fix crash when failing to import a client-side cert into NSS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... Created 9 years, 2 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 | « no previous file | net/socket/ssl_server_socket_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) 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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | net/socket/ssl_server_socket_nss.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698