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

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

Issue 12035105: Move client certificates retrieval logic out of the SSL sockets. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add missing license header Created 7 years, 10 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
« no previous file with comments | « net/http/http_network_transaction.cc ('k') | net/socket/ssl_client_socket_openssl.h » ('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 // 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 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 // that the network task runner can safely make a copy, which avoids the need 404 // that the network task runner can safely make a copy, which avoids the need
405 // for locking. 405 // for locking.
406 struct HandshakeState { 406 struct HandshakeState {
407 HandshakeState() { Reset(); } 407 HandshakeState() { Reset(); }
408 408
409 void Reset() { 409 void Reset() {
410 next_proto_status = SSLClientSocket::kNextProtoUnsupported; 410 next_proto_status = SSLClientSocket::kNextProtoUnsupported;
411 next_proto.clear(); 411 next_proto.clear();
412 server_protos.clear(); 412 server_protos.clear();
413 channel_id_sent = false; 413 channel_id_sent = false;
414 client_certs.clear();
415 server_cert_chain.Reset(NULL); 414 server_cert_chain.Reset(NULL);
416 server_cert = NULL; 415 server_cert = NULL;
417 resumed_handshake = false; 416 resumed_handshake = false;
418 ssl_connection_status = 0; 417 ssl_connection_status = 0;
419 } 418 }
420 419
421 // Set to kNextProtoNegotiated if NPN was successfully negotiated, with the 420 // Set to kNextProtoNegotiated if NPN was successfully negotiated, with the
422 // negotiated protocol stored in |next_proto|. 421 // negotiated protocol stored in |next_proto|.
423 SSLClientSocket::NextProtoStatus next_proto_status; 422 SSLClientSocket::NextProtoStatus next_proto_status;
424 std::string next_proto; 423 std::string next_proto;
425 // If the server supports NPN, the protocols supported by the server. 424 // If the server supports NPN, the protocols supported by the server.
426 std::string server_protos; 425 std::string server_protos;
427 426
428 // True if a channel ID was sent. 427 // True if a channel ID was sent.
429 bool channel_id_sent; 428 bool channel_id_sent;
430 429
431 // If the peer requests client certificate authentication, the set of
432 // certificates that matched the peer's criteria. This should be soon removed
433 // as being tracked in http://crbug.com/166642.
434 CertificateList client_certs;
435
436 // List of DER-encoded X.509 DistinguishedName of certificate authorities 430 // List of DER-encoded X.509 DistinguishedName of certificate authorities
437 // allowed by the server. 431 // allowed by the server.
438 std::vector<std::string> cert_authorities; 432 std::vector<std::string> cert_authorities;
439 433
440 // Set when the handshake fully completes. 434 // Set when the handshake fully completes.
441 // 435 //
442 // The server certificate is first received from NSS as an NSS certificate 436 // The server certificate is first received from NSS as an NSS certificate
443 // chain (|server_cert_chain|) and then converted into a platform-specific 437 // chain (|server_cert_chain|) and then converted into a platform-specific
444 // X509Certificate object (|server_cert|). It's possible for some 438 // X509Certificate object (|server_cert|). It's possible for some
445 // certificates to be successfully parsed by NSS, and not by the platform 439 // certificates to be successfully parsed by NSS, and not by the platform
(...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after
1351 return SECSuccess; 1345 return SECSuccess;
1352 } 1346 }
1353 LOG(WARNING) << "Client cert found without private key"; 1347 LOG(WARNING) << "Client cert found without private key";
1354 } 1348 }
1355 1349
1356 // Send no client certificate. 1350 // Send no client certificate.
1357 core->AddCertProvidedEvent(0); 1351 core->AddCertProvidedEvent(0);
1358 return SECFailure; 1352 return SECFailure;
1359 } 1353 }
1360 1354
1361 core->nss_handshake_state_.client_certs.clear();
1362 core->nss_handshake_state_.cert_authorities.clear(); 1355 core->nss_handshake_state_.cert_authorities.clear();
1363 1356
1364 std::vector<CERT_NAME_BLOB> issuer_list(ca_names->nnames); 1357 std::vector<CERT_NAME_BLOB> issuer_list(ca_names->nnames);
1365 for (int i = 0; i < ca_names->nnames; ++i) { 1358 for (int i = 0; i < ca_names->nnames; ++i) {
1366 issuer_list[i].cbData = ca_names->names[i].len; 1359 issuer_list[i].cbData = ca_names->names[i].len;
1367 issuer_list[i].pbData = ca_names->names[i].data; 1360 issuer_list[i].pbData = ca_names->names[i].data;
1368 core->nss_handshake_state_.cert_authorities.push_back(std::string( 1361 core->nss_handshake_state_.cert_authorities.push_back(std::string(
1369 reinterpret_cast<const char*>(ca_names->names[i].data), 1362 reinterpret_cast<const char*>(ca_names->names[i].data),
1370 static_cast<size_t>(ca_names->names[i].len))); 1363 static_cast<size_t>(ca_names->names[i].len)));
1371 } 1364 }
1372 1365
1373 // Retrieve the list of matching client certificates. This is to be moved out
1374 // of here as a part of refactoring effort being tracked in
1375 // http://crbug.com/166642.
1376
1377 // Client certificates of the user are in the "MY" system certificate store.
1378 HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY");
1379 if (!my_cert_store) {
1380 PLOG(ERROR) << "Could not open the \"MY\" system certificate store";
1381
1382 core->AddCertProvidedEvent(0);
1383 return SECFailure;
1384 }
1385
1386 // Enumerate the client certificates.
1387 CERT_CHAIN_FIND_BY_ISSUER_PARA find_by_issuer_para;
1388 memset(&find_by_issuer_para, 0, sizeof(find_by_issuer_para));
1389 find_by_issuer_para.cbSize = sizeof(find_by_issuer_para);
1390 find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
1391 find_by_issuer_para.cIssuer = ca_names->nnames;
1392 find_by_issuer_para.rgIssuer = ca_names->nnames ? &issuer_list[0] : NULL;
1393 find_by_issuer_para.pfnFindCallback = ClientCertFindCallback;
1394
1395 PCCERT_CHAIN_CONTEXT chain_context = NULL;
1396 DWORD find_flags = CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG |
1397 CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG;
1398
1399 for (;;) {
1400 // Find a certificate chain.
1401 chain_context = CertFindChainInStore(my_cert_store,
1402 X509_ASN_ENCODING,
1403 find_flags,
1404 CERT_CHAIN_FIND_BY_ISSUER,
1405 &find_by_issuer_para,
1406 chain_context);
1407 if (!chain_context) {
1408 DWORD err = GetLastError();
1409 if (err != CRYPT_E_NOT_FOUND)
1410 DLOG(ERROR) << "CertFindChainInStore failed: " << err;
1411 break;
1412 }
1413
1414 // Get the leaf certificate.
1415 PCCERT_CONTEXT cert_context =
1416 chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
1417 // Create a copy the handle, so that we can close the "MY" certificate store
1418 // before returning from this function.
1419 PCCERT_CONTEXT cert_context2;
1420 BOOL ok = CertAddCertificateContextToStore(NULL, cert_context,
1421 CERT_STORE_ADD_USE_EXISTING,
1422 &cert_context2);
1423 if (!ok) {
1424 NOTREACHED();
1425 continue;
1426 }
1427
1428 // Copy the rest of the chain. Copying the chain stops gracefully if an
1429 // error is encountered, with the partial chain being used as the
1430 // intermediates, as opposed to failing to consider the client certificate
1431 // at all.
1432 net::X509Certificate::OSCertHandles intermediates;
1433 for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; i++) {
1434 PCCERT_CONTEXT intermediate_copy;
1435 ok = CertAddCertificateContextToStore(
1436 NULL, chain_context->rgpChain[0]->rgpElement[i]->pCertContext,
1437 CERT_STORE_ADD_USE_EXISTING, &intermediate_copy);
1438 if (!ok) {
1439 NOTREACHED();
1440 break;
1441 }
1442 intermediates.push_back(intermediate_copy);
1443 }
1444
1445 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
1446 cert_context2, intermediates);
1447 core->nss_handshake_state_.client_certs.push_back(cert);
1448
1449 X509Certificate::FreeOSCertHandle(cert_context2);
1450 for (net::X509Certificate::OSCertHandles::iterator it =
1451 intermediates.begin(); it != intermediates.end(); ++it) {
1452 net::X509Certificate::FreeOSCertHandle(*it);
1453 }
1454 }
1455
1456 std::sort(core->nss_handshake_state_.client_certs.begin(),
1457 core->nss_handshake_state_.client_certs.end(),
1458 x509_util::ClientCertSorter());
1459
1460 BOOL ok = CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG);
1461 DCHECK(ok);
1462
1463 // Update the network task runner's view of the handshake state now that 1366 // Update the network task runner's view of the handshake state now that
1464 // client certs have been detected. 1367 // server certificate request has been recorded.
1465 core->PostOrRunCallback( 1368 core->PostOrRunCallback(
1466 FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, core, 1369 FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, core,
1467 core->nss_handshake_state_)); 1370 core->nss_handshake_state_));
1468 1371
1469 // Tell NSS to suspend the client authentication. We will then abort the 1372 // Tell NSS to suspend the client authentication. We will then abort the
1470 // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED. 1373 // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
1471 return SECWouldBlock; 1374 return SECWouldBlock;
1472 #elif defined(OS_MACOSX) 1375 #elif defined(OS_MACOSX)
1473 if (core->ssl_config_.send_client_cert) { 1376 if (core->ssl_config_.send_client_cert) {
1474 if (core->ssl_config_.client_cert) { 1377 if (core->ssl_config_.client_cert) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1538 CFRelease(private_key); 1441 CFRelease(private_key);
1539 if (chain) 1442 if (chain)
1540 CFRelease(chain); 1443 CFRelease(chain);
1541 } 1444 }
1542 1445
1543 // Send no client certificate. 1446 // Send no client certificate.
1544 core->AddCertProvidedEvent(0); 1447 core->AddCertProvidedEvent(0);
1545 return SECFailure; 1448 return SECFailure;
1546 } 1449 }
1547 1450
1548 core->nss_handshake_state_.client_certs.clear();
1549 core->nss_handshake_state_.cert_authorities.clear(); 1451 core->nss_handshake_state_.cert_authorities.clear();
1550 1452
1551 // Retrieve the cert issuers accepted by the server. This information is 1453 // Retrieve the cert issuers accepted by the server.
1552 // currently (temporarily) being saved both in |valid_issuers| and
1553 // |cert_authorities|, the latter being the target solution. The refactoring
1554 // effort is being tracked in http://crbug.com/166642.
1555 std::vector<CertPrincipal> valid_issuers; 1454 std::vector<CertPrincipal> valid_issuers;
1556 int n = ca_names->nnames; 1455 int n = ca_names->nnames;
1557 for (int i = 0; i < n; i++) { 1456 for (int i = 0; i < n; i++) {
1558 // Add the DER-encoded issuer DistinguishedName to |cert_authorities|.
1559 core->nss_handshake_state_.cert_authorities.push_back(std::string( 1457 core->nss_handshake_state_.cert_authorities.push_back(std::string(
1560 reinterpret_cast<const char*>(ca_names->names[i].data), 1458 reinterpret_cast<const char*>(ca_names->names[i].data),
1561 static_cast<size_t>(ca_names->names[i].len))); 1459 static_cast<size_t>(ca_names->names[i].len)));
1562 // Add the CertPrincipal object representing the issuer to
1563 // |valid_issuers|.
1564 CertPrincipal p;
1565 if (p.ParseDistinguishedName(ca_names->names[i].data,
1566 ca_names->names[i].len)) {
1567 valid_issuers.push_back(p);
1568 }
1569 } 1460 }
1570 1461
1571 // Now get the available client certs whose issuers are allowed by the server.
1572 X509Certificate::GetSSLClientCertificates(
1573 core->host_and_port_.host(), valid_issuers,
1574 &core->nss_handshake_state_.client_certs);
1575
1576 std::sort(core->nss_handshake_state_.client_certs.begin(),
1577 core->nss_handshake_state_.client_certs.end(),
1578 x509_util::ClientCertSorter());
1579
1580 // Update the network task runner's view of the handshake state now that 1462 // Update the network task runner's view of the handshake state now that
1581 // client certs have been detected. 1463 // server certificate request has been recorded.
1582 core->PostOrRunCallback( 1464 core->PostOrRunCallback(
1583 FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, core, 1465 FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, core,
1584 core->nss_handshake_state_)); 1466 core->nss_handshake_state_));
1585 1467
1586 // Tell NSS to suspend the client authentication. We will then abort the 1468 // Tell NSS to suspend the client authentication. We will then abort the
1587 // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED. 1469 // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
1588 return SECWouldBlock; 1470 return SECWouldBlock;
1589 #else 1471 #else
1590 return SECFailure; 1472 return SECFailure;
1591 #endif 1473 #endif
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1656 return SECSuccess; 1538 return SECSuccess;
1657 } 1539 }
1658 LOG(WARNING) << "Client cert found without private key"; 1540 LOG(WARNING) << "Client cert found without private key";
1659 } 1541 }
1660 // Send no client certificate. 1542 // Send no client certificate.
1661 core->AddCertProvidedEvent(0); 1543 core->AddCertProvidedEvent(0);
1662 return SECFailure; 1544 return SECFailure;
1663 } 1545 }
1664 1546
1665 // First pass: client certificate is needed. 1547 // First pass: client certificate is needed.
1666 core->nss_handshake_state_.client_certs.clear();
1667 core->nss_handshake_state_.cert_authorities.clear(); 1548 core->nss_handshake_state_.cert_authorities.clear();
1668 1549
1669 // Retrieve the DER-encoded DistinguishedName of the cert issuers accepted by 1550 // Retrieve the DER-encoded DistinguishedName of the cert issuers accepted by
1670 // the server and save them in |cert_authorities|. 1551 // the server and save them in |cert_authorities|.
1671 for (int i = 0; i < ca_names->nnames; i++) { 1552 for (int i = 0; i < ca_names->nnames; i++) {
1672 core->nss_handshake_state_.cert_authorities.push_back(std::string( 1553 core->nss_handshake_state_.cert_authorities.push_back(std::string(
1673 reinterpret_cast<const char*>(ca_names->names[i].data), 1554 reinterpret_cast<const char*>(ca_names->names[i].data),
1674 static_cast<size_t>(ca_names->names[i].len))); 1555 static_cast<size_t>(ca_names->names[i].len)));
1675 } 1556 }
1676 1557
1677 // Iterate over all client certificates and put the ones matching the server
1678 // criteria in |nss_handshake_state_.client_certs|. This is to be moved out of
1679 // here as a part of refactoring effort being tracked in
1680 // http://crbug.com/166642.
1681 CERTCertList* client_certs = CERT_FindUserCertsByUsage(
1682 CERT_GetDefaultCertDB(), certUsageSSLClient,
1683 PR_FALSE, PR_FALSE, wincx);
1684 if (client_certs) {
1685 for (CERTCertListNode* node = CERT_LIST_HEAD(client_certs);
1686 !CERT_LIST_END(node, client_certs);
1687 node = CERT_LIST_NEXT(node)) {
1688 // Only offer unexpired certificates.
1689 if (CERT_CheckCertValidTimes(node->cert, PR_Now(), PR_TRUE) !=
1690 secCertTimeValid) {
1691 continue;
1692 }
1693 // Filter by issuer.
1694 //
1695 // TODO(davidben): This does a binary comparison of the DER-encoded
1696 // issuers. We should match according to RFC 5280 sec. 7.1. We should find
1697 // an appropriate NSS function or add one if needbe.
1698 if (ca_names->nnames &&
1699 NSS_CmpCertChainWCANames(node->cert, ca_names) != SECSuccess) {
1700 continue;
1701 }
1702
1703 X509Certificate* x509_cert = X509Certificate::CreateFromHandle(
1704 node->cert, net::X509Certificate::OSCertHandles());
1705 core->nss_handshake_state_.client_certs.push_back(x509_cert);
1706 }
1707 CERT_DestroyCertList(client_certs);
1708 }
1709
1710 std::sort(core->nss_handshake_state_.client_certs.begin(),
1711 core->nss_handshake_state_.client_certs.end(),
1712 x509_util::ClientCertSorter());
1713
1714 // Update the network task runner's view of the handshake state now that 1558 // Update the network task runner's view of the handshake state now that
1715 // client certs have been detected. 1559 // server certificate request has been recorded.
1716 core->PostOrRunCallback( 1560 core->PostOrRunCallback(
1717 FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, core, 1561 FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, core,
1718 core->nss_handshake_state_)); 1562 core->nss_handshake_state_));
1719 1563
1720 // Tell NSS to suspend the client authentication. We will then abort the 1564 // Tell NSS to suspend the client authentication. We will then abort the
1721 // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED. 1565 // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
1722 return SECWouldBlock; 1566 return SECWouldBlock;
1723 } 1567 }
1724 #endif // NSS_PLATFORM_CLIENT_AUTH 1568 #endif // NSS_PLATFORM_CLIENT_AUTH
1725 1569
(...skipping 1191 matching lines...) Expand 10 before | Expand all | Expand 10 after
2917 LeaveFunction(""); 2761 LeaveFunction("");
2918 return true; 2762 return true;
2919 } 2763 }
2920 2764
2921 void SSLClientSocketNSS::GetSSLCertRequestInfo( 2765 void SSLClientSocketNSS::GetSSLCertRequestInfo(
2922 SSLCertRequestInfo* cert_request_info) { 2766 SSLCertRequestInfo* cert_request_info) {
2923 EnterFunction(""); 2767 EnterFunction("");
2924 // TODO(rch): switch SSLCertRequestInfo.host_and_port to a HostPortPair 2768 // TODO(rch): switch SSLCertRequestInfo.host_and_port to a HostPortPair
2925 cert_request_info->host_and_port = host_and_port_.ToString(); 2769 cert_request_info->host_and_port = host_and_port_.ToString();
2926 cert_request_info->cert_authorities = core_->state().cert_authorities; 2770 cert_request_info->cert_authorities = core_->state().cert_authorities;
2927 // This should be removed as being tracked in http://crbug.com/166642. 2771 LeaveFunction("");
2928 cert_request_info->client_certs = core_->state().client_certs;
2929 LeaveFunction(cert_request_info->client_certs.size());
2930 } 2772 }
2931 2773
2932 int SSLClientSocketNSS::ExportKeyingMaterial(const base::StringPiece& label, 2774 int SSLClientSocketNSS::ExportKeyingMaterial(const base::StringPiece& label,
2933 bool has_context, 2775 bool has_context,
2934 const base::StringPiece& context, 2776 const base::StringPiece& context,
2935 unsigned char* out, 2777 unsigned char* out,
2936 unsigned int outlen) { 2778 unsigned int outlen) {
2937 if (!IsConnected()) 2779 if (!IsConnected())
2938 return ERR_SOCKET_NOT_CONNECTED; 2780 return ERR_SOCKET_NOT_CONNECTED;
2939 2781
(...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after
3597 EnsureThreadIdAssigned(); 3439 EnsureThreadIdAssigned();
3598 base::AutoLock auto_lock(lock_); 3440 base::AutoLock auto_lock(lock_);
3599 return valid_thread_id_ == base::PlatformThread::CurrentId(); 3441 return valid_thread_id_ == base::PlatformThread::CurrentId();
3600 } 3442 }
3601 3443
3602 ServerBoundCertService* SSLClientSocketNSS::GetServerBoundCertService() const { 3444 ServerBoundCertService* SSLClientSocketNSS::GetServerBoundCertService() const {
3603 return server_bound_cert_service_; 3445 return server_bound_cert_service_;
3604 } 3446 }
3605 3447
3606 } // namespace net 3448 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_network_transaction.cc ('k') | net/socket/ssl_client_socket_openssl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698