| Index: net/socket/ssl_client_socket_nss.cc
|
| diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
|
| index 384fa9d3bf2e6ae14d608e61ec71d680e01ea027..f4718aff4b02c1262f58120c354986ea374c5844 100644
|
| --- a/net/socket/ssl_client_socket_nss.cc
|
| +++ b/net/socket/ssl_client_socket_nss.cc
|
| @@ -75,6 +75,7 @@
|
| #include "base/string_util.h"
|
| #include "base/stringprintf.h"
|
| #include "base/threading/thread_restrictions.h"
|
| +#include "base/utf_string_conversions.h"
|
| #include "base/values.h"
|
| #include "net/base/address_list.h"
|
| #include "net/base/cert_status_flags.h"
|
| @@ -469,6 +470,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
|
| completed_handshake_(false),
|
| pseudo_connected_(false),
|
| eset_mitm_detected_(false),
|
| + server_cert_needed_(true),
|
| predicted_cert_chain_correct_(false),
|
| peername_initialized_(false),
|
| dnssec_provider_(NULL),
|
| @@ -498,15 +500,21 @@ void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
|
| EnterFunction("");
|
| ssl_info->Reset();
|
|
|
| - if (!server_cert_) {
|
| - LOG(DFATAL) << "!server_cert_";
|
| + if (!server_cert_ && server_cert_needed_) {
|
| + LOG(DFATAL) << "!server_cert_ && server_cert_needed_";
|
| return;
|
| }
|
|
|
| - ssl_info->cert_status = server_cert_verify_result_->cert_status;
|
| - DCHECK(server_cert_ != NULL);
|
| - ssl_info->cert = server_cert_;
|
| ssl_info->connection_status = ssl_connection_status_;
|
| + if (server_cert_verify_result_) {
|
| + ssl_info->cert_status = server_cert_verify_result_->cert_status;
|
| + }
|
| + if (server_cert_ != NULL) {
|
| + ssl_info->cert = server_cert_;
|
| + }
|
| + if (ssl_config_.use_tls_auth && !authenticated_tls_username_.empty()) {
|
| + ssl_info->tls_username = UTF8ToUTF16(authenticated_tls_username_);
|
| + }
|
|
|
| PRUint16 cipher_suite =
|
| SSLConnectionStatusToCipherSuite(ssl_connection_status_);
|
| @@ -911,14 +919,6 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
|
| return ERR_UNEXPECTED;
|
| }
|
|
|
| - for (std::vector<uint16>::const_iterator it =
|
| - ssl_config_.disabled_cipher_suites.begin();
|
| - it != ssl_config_.disabled_cipher_suites.end(); ++it) {
|
| - // This will fail if the specified cipher is not implemented by NSS, but
|
| - // the failure is harmless.
|
| - SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE);
|
| - }
|
| -
|
| #ifdef SSL_ENABLE_SESSION_TICKETS
|
| // Support RFC 5077
|
| rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
|
| @@ -1029,6 +1029,43 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
|
| return ERR_UNEXPECTED;
|
| }
|
|
|
| + if (ssl_config_.use_tls_auth) {
|
| + // Enable SRP ciphers, and disable non-SRP ciphers if we *require* TLS auth.
|
| + rv = SetCiphersForTLSAuth(true, ssl_config_.require_tls_auth);
|
| + if (rv != OK)
|
| + return rv;
|
| +
|
| + if (!ssl_config_.tls_username.empty() &&
|
| + !ssl_config_.tls_password.empty()) {
|
| + LOG(WARNING) << "Using TLS-SRP as " <<
|
| + ssl_config_.tls_username << " / " << ssl_config_.tls_password;
|
| +
|
| + rv = SSL_SetUserLogin(nss_fd_,
|
| + ssl_config_.tls_username.c_str(),
|
| + ssl_config_.tls_password.c_str());
|
| + if (rv != SECSuccess) {
|
| + LogFailedNSSFunction(net_log_, "SSL_SetUserLogin", "");
|
| + return ERR_UNEXPECTED;
|
| + }
|
| + } else
|
| + LOG(INFO) << "Using TLS-SRP with no username/password";
|
| + } else {
|
| + // Disable SRP ciphers.
|
| + // TODO(sqs): this disable step should only be called if the SRP cipher
|
| + // suites are on by default.
|
| + rv = SetCiphersForTLSAuth(false, false);
|
| + if (rv != OK)
|
| + return rv;
|
| + }
|
| +
|
| + for (std::vector<uint16>::const_iterator it =
|
| + ssl_config_.disabled_cipher_suites.begin();
|
| + it != ssl_config_.disabled_cipher_suites.end(); ++it) {
|
| + // This will fail if the specified cipher is not implemented by NSS, but
|
| + // the failure is harmless.
|
| + SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE);
|
| + }
|
| +
|
| rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this);
|
| if (rv != SECSuccess) {
|
| LogFailedNSSFunction(net_log_, "SSL_HandshakeCallback", "");
|
| @@ -1044,6 +1081,35 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
|
| return OK;
|
| }
|
|
|
| +// Enables SRP ciphers if |set_srp_ciphers| is true; otherwise, disables SRP
|
| +// ciphers. If |disable_non_srp_ciphers| is true, then disable non-SRP ciphers;
|
| +// otherwise, leave them alone.
|
| +int SSLClientSocketNSS::SetCiphersForTLSAuth(bool set_srp_ciphers,
|
| + bool disable_non_srp_ciphers) {
|
| + int rv;
|
| + const PRUint16 *cipherSuites = SSL_GetImplementedCiphers();
|
| + int numCiphers = SSL_GetNumImplementedCiphers();
|
| + SSLCipherSuiteInfo info;
|
| + for (int i = 0; i < numCiphers; i++) {
|
| + PRUint16 suite = cipherSuites[i];
|
| + rv = SSL_GetCipherSuiteInfo(suite, &info, sizeof(info));
|
| + if (rv != SECSuccess) {
|
| + LogFailedNSSFunction(net_log_, "SSL_GetCipherSuiteInfo", "");
|
| + return ERR_UNEXPECTED;
|
| + }
|
| + if (IsNSSCipherKEATypeSRP(info.keaType)) {
|
| + rv = SSL_CipherPrefSet(nss_fd_, suite, set_srp_ciphers);
|
| + } else if (disable_non_srp_ciphers) {
|
| + rv = SSL_CipherPrefSet(nss_fd_, suite, PR_FALSE);
|
| + }
|
| + if (rv != SECSuccess) {
|
| + LogFailedNSSFunction(net_log_, "SSL_CipherPrefSet", "");
|
| + return ERR_UNEXPECTED;
|
| + }
|
| + }
|
| + return OK;
|
| +}
|
| +
|
| int SSLClientSocketNSS::InitializeSSLPeerName() {
|
| // Tell NSS who we're connected to
|
| AddressList peer_address;
|
| @@ -1096,6 +1162,43 @@ X509Certificate *SSLClientSocketNSS::UpdateServerCert() {
|
| return server_cert_;
|
| }
|
|
|
| +// Sets tls_username_ and server_cert_needed_.
|
| +void SSLClientSocketNSS::UpdateAuth() {
|
| + if (ssl_config_.use_tls_auth) {
|
| + // Get the username that we actually authenticated with.
|
| + SECItem user;
|
| + SECStatus rv = SSL_GetChannelUsername(nss_fd_, &user);
|
| + if (rv != SECSuccess) {
|
| + LogFailedNSSFunction(net_log_, "SSL_GetChannelUsername", "");
|
| + } else {
|
| + authenticated_tls_username_.assign(const_cast<char *>((char *)user.data),
|
| + (size_t)user.len);
|
| + SECITEM_FreeItem(&user, PR_FALSE);
|
| + }
|
| + DCHECK(authenticated_tls_username_ == ssl_config_.tls_username);
|
| +
|
| + // See whether this SRP cipher suite uses certs.
|
| + SSLChannelInfo channel_info;
|
| + SSLCipherSuiteInfo info;
|
| + rv = SSL_GetChannelInfo(nss_fd_, &channel_info, sizeof(channel_info));
|
| + if (rv != SECSuccess) {
|
| + LogFailedNSSFunction(net_log_, "SSL_GetChannelInfo", "");
|
| + return;
|
| + }
|
| + if (!channel_info.cipherSuite) {
|
| + LOG(WARNING) << "Couldn't get SSL channel cipher suite";
|
| + return;
|
| + }
|
| + rv = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, &info, sizeof(info));
|
| + if (rv != SECSuccess) {
|
| + LogFailedNSSFunction(net_log_, "SSL_GetCipherSuiteInfo", "");
|
| + return;
|
| + }
|
| + bool cipher_is_srp_no_certs = (info.keaType == ssl_kea_srp);
|
| + server_cert_needed_ = !cipher_is_srp_no_certs;
|
| + }
|
| +}
|
| +
|
| // Sets ssl_connection_status_.
|
| void SSLClientSocketNSS::UpdateConnectionStatus() {
|
| SSLChannelInfo channel_info;
|
| @@ -1449,6 +1552,8 @@ int SSLClientSocketNSS::DoSnapStartWaitForWrite() {
|
| return OK;
|
| }
|
|
|
| +// TODO(sqs): this hangs if the server returns an unknown_psk_identity alert
|
| +// that is not fatal (that is a warning)
|
| int SSLClientSocketNSS::DoHandshake() {
|
| EnterFunction("");
|
| int net_error = net::OK;
|
| @@ -1640,6 +1745,13 @@ int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) {
|
| }
|
|
|
| int SSLClientSocketNSS::DoVerifyCert(int result) {
|
| + if (!server_cert_needed_) {
|
| + DCHECK(ssl_config_.use_tls_auth);
|
| + DCHECK(!ssl_config_.tls_username.empty());
|
| + GotoState(STATE_VERIFY_CERT_COMPLETE);
|
| + return OK;
|
| + }
|
| +
|
| DCHECK(server_cert_);
|
|
|
| GotoState(STATE_VERIFY_CERT_COMPLETE);
|
| @@ -1809,16 +1921,20 @@ int SSLClientSocketNSS::DoPayloadWrite() {
|
|
|
| void SSLClientSocketNSS::LogConnectionTypeMetrics() const {
|
| UpdateConnectionTypeHistograms(CONNECTION_SSL);
|
| - if (server_cert_verify_result_->has_md5)
|
| - UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5);
|
| - if (server_cert_verify_result_->has_md2)
|
| - UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2);
|
| - if (server_cert_verify_result_->has_md4)
|
| - UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4);
|
| - if (server_cert_verify_result_->has_md5_ca)
|
| - UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA);
|
| - if (server_cert_verify_result_->has_md2_ca)
|
| - UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA);
|
| +
|
| + if (server_cert_verify_result_) {
|
| + if (server_cert_verify_result_->has_md5)
|
| + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5);
|
| + if (server_cert_verify_result_->has_md2)
|
| + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2);
|
| + if (server_cert_verify_result_->has_md4)
|
| + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4);
|
| + if (server_cert_verify_result_->has_md5_ca)
|
| + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA);
|
| + if (server_cert_verify_result_->has_md2_ca)
|
| + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA);
|
| + }
|
| +
|
| int ssl_version = SSLConnectionStatusToVersion(ssl_connection_status_);
|
| switch (ssl_version) {
|
| case SSL_CONNECTION_VERSION_SSL2:
|
| @@ -1837,6 +1953,9 @@ void SSLClientSocketNSS::LogConnectionTypeMetrics() const {
|
| UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2);
|
| break;
|
| };
|
| +
|
| + if (!authenticated_tls_username_.empty())
|
| + UpdateConnectionTypeHistograms(CONNECTION_TLS_PASSWORD_AUTH);
|
| }
|
|
|
| // SaveSnapStartInfo extracts the information needed to perform a Snap Start
|
| @@ -2495,6 +2614,7 @@ void SSLClientSocketNSS::HandshakeCallback(PRFileDesc* socket,
|
| that->handshake_callback_called_ = true;
|
|
|
| that->UpdateServerCert();
|
| + that->UpdateAuth();
|
| that->UpdateConnectionStatus();
|
| }
|
|
|
|
|