OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |