Report the SSL protocol version in ssl_info.connection_status.
Refactor SSLClientSocketNSS::GetSSLInfo -- the code that sets
ssl_info->connection_status is moved to a new
UpdateConnectionStatus method, and CheckSecureRenegotiation
is subsumed by UpdateConnectionStatus.
R=agl,finnur
BUG=53659
TEST=none
Review URL: http://codereview.chromium.org/4198003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64178 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 6d3f54f..f62c7b1 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -60,6 +60,7 @@
#include <sechash.h>
#include <ssl.h>
#include <sslerr.h>
+#include <sslproto.h>
#include <limits>
@@ -76,6 +77,7 @@
#include "net/base/address_list.h"
#include "net/base/cert_status_flags.h"
#include "net/base/cert_verifier.h"
+#include "net/base/connection_type_histograms.h"
#include "net/base/dns_util.h"
#include "net/base/dnsrr_resolver.h"
#include "net/base/dnssec_chain_verifier.h"
@@ -381,6 +383,7 @@
user_read_buf_len_(0),
user_write_buf_len_(0),
server_cert_nss_(NULL),
+ ssl_connection_status_(0),
client_auth_cert_needed_(false),
handshake_callback_called_(false),
completed_handshake_(false),
@@ -867,6 +870,7 @@
server_cert_nss_ = NULL;
}
server_cert_verify_result_.Reset();
+ ssl_connection_status_ = 0;
completed_handshake_ = false;
pseudo_connected_ = false;
eset_mitm_detected_ = false;
@@ -1034,11 +1038,10 @@
return transport_->socket()->SetSendBufferSize(size);
}
-
+// Sets server_cert_ and server_cert_nss_ if not yet set.
+// Returns server_cert_.
X509Certificate *SSLClientSocketNSS::UpdateServerCert() {
- // We set the server_cert_ from HandshakeCallback(), but this handler
- // does not necessarily get called if we are continuing a cached SSL
- // session.
+ // We set the server_cert_ from HandshakeCallback().
if (server_cert_ == NULL) {
server_cert_nss_ = SSL_PeerCertificate(nss_fd_);
if (server_cert_nss_) {
@@ -1069,21 +1072,61 @@
return server_cert_;
}
-// Log an informational message if the server does not support secure
-// renegotiation (RFC 5746).
-void SSLClientSocketNSS::CheckSecureRenegotiation() const {
+// Sets ssl_connection_status_.
+void SSLClientSocketNSS::UpdateConnectionStatus() {
+ SSLChannelInfo channel_info;
+ SECStatus ok = SSL_GetChannelInfo(nss_fd_,
+ &channel_info, sizeof(channel_info));
+ if (ok == SECSuccess &&
+ channel_info.length == sizeof(channel_info) &&
+ channel_info.cipherSuite) {
+ ssl_connection_status_ |=
+ (static_cast<int>(channel_info.cipherSuite) &
+ SSL_CONNECTION_CIPHERSUITE_MASK) <<
+ SSL_CONNECTION_CIPHERSUITE_SHIFT;
+
+ ssl_connection_status_ |=
+ (static_cast<int>(channel_info.compressionMethod) &
+ SSL_CONNECTION_COMPRESSION_MASK) <<
+ SSL_CONNECTION_COMPRESSION_SHIFT;
+
+ int version = SSL_CONNECTION_VERSION_UNKNOWN;
+ if (channel_info.protocolVersion < SSL_LIBRARY_VERSION_3_0) {
+ // All versions less than SSL_LIBRARY_VERSION_3_0 are treated as SSL
+ // version 2.
+ version = SSL_CONNECTION_VERSION_SSL2;
+ } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_3_0) {
+ version = SSL_CONNECTION_VERSION_SSL3;
+ } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_3_1_TLS) {
+ version = SSL_CONNECTION_VERSION_TLS1;
+ }
+ ssl_connection_status_ |=
+ (version & SSL_CONNECTION_VERSION_MASK) <<
+ SSL_CONNECTION_VERSION_SHIFT;
+ }
+
// SSL_HandshakeNegotiatedExtension was added in NSS 3.12.6.
// Since SSL_MAX_EXTENSIONS was added at the same time, we can test
// SSL_MAX_EXTENSIONS for the presence of SSL_HandshakeNegotiatedExtension.
#if defined(SSL_MAX_EXTENSIONS)
- PRBool received_renego_info;
- if (SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn,
- &received_renego_info) == SECSuccess &&
- !received_renego_info) {
- VLOG(1) << "The server " << hostname_
- << " does not support the TLS renegotiation_info extension.";
+ PRBool peer_supports_renego_ext;
+ ok = SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn,
+ &peer_supports_renego_ext);
+ if (ok == SECSuccess) {
+ if (!peer_supports_renego_ext) {
+ ssl_connection_status_ |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION;
+ // Log an informational message if the server does not support secure
+ // renegotiation (RFC 5746).
+ VLOG(1) << "The server " << hostname_
+ << " does not support the TLS renegotiation_info extension.";
+ }
+ UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported",
+ peer_supports_renego_ext, 2);
}
#endif
+
+ if (ssl_config_.ssl3_fallback)
+ ssl_connection_status_ |= SSL_CONNECTION_SSL3_FALLBACK;
}
void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
@@ -1095,50 +1138,23 @@
return;
}
- SSLChannelInfo channel_info;
- SECStatus ok = SSL_GetChannelInfo(nss_fd_,
- &channel_info, sizeof(channel_info));
- if (ok == SECSuccess &&
- channel_info.length == sizeof(channel_info) &&
- channel_info.cipherSuite) {
- SSLCipherSuiteInfo cipher_info;
- ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
- &cipher_info, sizeof(cipher_info));
- if (ok == SECSuccess) {
- ssl_info->security_bits = cipher_info.effectiveKeyBits;
- } else {
- ssl_info->security_bits = -1;
- LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError()
- << " for cipherSuite " << channel_info.cipherSuite;
- }
- ssl_info->connection_status |=
- (((int)channel_info.cipherSuite) & SSL_CONNECTION_CIPHERSUITE_MASK) <<
- SSL_CONNECTION_CIPHERSUITE_SHIFT;
-
- ssl_info->connection_status |=
- (((int)channel_info.compressionMethod) &
- SSL_CONNECTION_COMPRESSION_MASK) <<
- SSL_CONNECTION_COMPRESSION_SHIFT;
-
- UpdateServerCert();
- }
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_;
- PRBool peer_supports_renego_ext;
- ok = SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn,
- &peer_supports_renego_ext);
+ PRUint16 cipher_suite =
+ SSLConnectionStatusToCipherSuite(ssl_connection_status_);
+ SSLCipherSuiteInfo cipher_info;
+ SECStatus ok = SSL_GetCipherSuiteInfo(cipher_suite,
+ &cipher_info, sizeof(cipher_info));
if (ok == SECSuccess) {
- if (!peer_supports_renego_ext)
- ssl_info->connection_status |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION;
- UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported",
- (int)peer_supports_renego_ext, 2);
+ ssl_info->security_bits = cipher_info.effectiveKeyBits;
+ } else {
+ ssl_info->security_bits = -1;
+ LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError()
+ << " for cipherSuite " << cipher_suite;
}
-
- if (ssl_config_.ssl3_fallback)
- ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK;
-
LeaveFunction("");
}
@@ -1798,8 +1814,7 @@
that->handshake_callback_called_ = true;
that->UpdateServerCert();
-
- that->CheckSecureRenegotiation();
+ that->UpdateConnectionStatus();
}
int SSLClientSocketNSS::DoSnapStartLoadInfo() {
@@ -2218,6 +2233,9 @@
result = OK;
}
+ if (result == OK)
+ LogConnectionTypeMetrics();
+
completed_handshake_ = true;
// TODO(ukai): we may not need this call because it is now harmless to have a
// session with a bad cert.
@@ -2286,4 +2304,36 @@
return rv;
}
+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);
+ int ssl_version = SSLConnectionStatusToVersion(ssl_connection_status_);
+ switch (ssl_version) {
+ case SSL_CONNECTION_VERSION_SSL2:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL2);
+ break;
+ case SSL_CONNECTION_VERSION_SSL3:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL3);
+ break;
+ case SSL_CONNECTION_VERSION_TLS1:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1);
+ break;
+ case SSL_CONNECTION_VERSION_TLS1_1:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_1);
+ break;
+ case SSL_CONNECTION_VERSION_TLS1_2:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2);
+ break;
+ };
+}
+
} // namespace net