summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/page_info_model.cc11
-rw-r--r--net/base/connection_type_histograms.h5
-rw-r--r--net/base/ssl_cipher_suite_names.cc26
-rw-r--r--net/base/ssl_cipher_suite_names.h6
-rw-r--r--net/base/ssl_connection_status_flags.h15
-rw-r--r--net/base/ssl_info.h5
-rw-r--r--net/http/http_response_info.cc1
-rw-r--r--net/socket/ssl_client_socket_nss.cc156
-rw-r--r--net/socket/ssl_client_socket_nss.h6
10 files changed, 175 insertions, 59 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 7a51308..a0a9d15 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6029,6 +6029,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK" desc="Linking 2 sentences in 1 paragraph.">
<ph name="SENTENCE1">$1<ex>Your connection is encrypted.</ex></ph> <ph name="SENTENCE2">$2<ex>However, this page includes resources from other pages whose identity cannot be verified.</ex></ph>
</message>
+ <message name="IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION" desc="This message gives the version of the SSL protocol used to protect the HTTPS connection.">
+ The connection uses <ph name="SSL_VERSION">$1<ex>TLS 1.0</ex></ph>.
+ </message>
<message name="IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS" desc="This message gives details of the cryptographic primitives used to protect the HTTPS connection.">
The connection is encrypted using <ph name="CIPHER">$1<ex>AES_128</ex></ph>, with <ph name="MAC">$2<ex>SHA1</ex></ph> for message authentication and <ph name="KX">$3<ex>RSA</ex></ph> as the key exchange mechanism.
</message>
diff --git a/chrome/browser/page_info_model.cc b/chrome/browser/page_info_model.cc
index 8b0d983..d0d7b74 100644
--- a/chrome/browser/page_info_model.cc
+++ b/chrome/browser/page_info_model.cc
@@ -195,6 +195,15 @@ PageInfoModel::PageInfoModel(Profile* profile,
uint16 cipher_suite =
net::SSLConnectionStatusToCipherSuite(ssl.connection_status());
if (ssl.security_bits() > 0 && cipher_suite) {
+ int ssl_version =
+ net::SSLConnectionStatusToVersion(ssl.connection_status());
+ const char* ssl_version_str;
+ net::SSLVersionToString(&ssl_version_str, ssl_version);
+ description += ASCIIToUTF16("\n\n");
+ description += l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION,
+ ASCIIToUTF16(ssl_version_str));
+
bool did_fallback = (ssl.connection_status() &
net::SSL_CONNECTION_SSL3_FALLBACK) != 0;
bool no_renegotiation =
@@ -212,7 +221,7 @@ PageInfoModel::PageInfoModel(Profile* profile,
uint8 compression_id =
net::SSLConnectionStatusToCompression(ssl.connection_status());
if (compression_id) {
- const char *compression;
+ const char* compression;
net::SSLCompressionToString(&compression, compression_id);
description += l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_COMPRESSION_DETAILS,
diff --git a/net/base/connection_type_histograms.h b/net/base/connection_type_histograms.h
index e6c2a59..e3e4a84 100644
--- a/net/base/connection_type_histograms.h
+++ b/net/base/connection_type_histograms.h
@@ -30,6 +30,11 @@ enum ConnectionType {
// in the certificate chain (excluding root)
CONNECTION_HTTP = 7, // An HTTP connection
CONNECTION_SPDY = 8, // A SPDY connection
+ CONNECTION_SSL_SSL2 = 9, // An SSL connection that uses SSL 2.0
+ CONNECTION_SSL_SSL3 = 10, // An SSL connection that uses SSL 3.0
+ CONNECTION_SSL_TLS1 = 11, // An SSL connection that uses TLS 1.0
+ CONNECTION_SSL_TLS1_1 = 12, // An SSL connection that uses TLS 1.1
+ CONNECTION_SSL_TLS1_2 = 13, // An SSL connection that uses TLS 1.2
NUM_OF_CONNECTION_TYPES
};
diff --git a/net/base/ssl_cipher_suite_names.cc b/net/base/ssl_cipher_suite_names.cc
index 2db9a4b..39efd1c 100644
--- a/net/base/ssl_cipher_suite_names.cc
+++ b/net/base/ssl_cipher_suite_names.cc
@@ -6,6 +6,8 @@
#include <stdlib.h>
+#include "base/logging.h"
+#include "net/base/ssl_connection_status_flags.h"
// Rather than storing the names of all the ciphersuites we eliminate the
// redundancy and break each cipher suite into a key exchange method, cipher
@@ -346,4 +348,28 @@ void SSLCompressionToString(const char** name, uint8 compresssion) {
}
}
+void SSLVersionToString(const char** name, int ssl_version) {
+ switch (ssl_version) {
+ case SSL_CONNECTION_VERSION_SSL2:
+ *name = "SSL 2.0";
+ break;
+ case SSL_CONNECTION_VERSION_SSL3:
+ *name = "SSL 3.0";
+ break;
+ case SSL_CONNECTION_VERSION_TLS1:
+ *name = "TLS 1.0";
+ break;
+ case SSL_CONNECTION_VERSION_TLS1_1:
+ *name = "TLS 1.1";
+ break;
+ case SSL_CONNECTION_VERSION_TLS1_2:
+ *name = "TLS 1.2";
+ break;
+ default:
+ NOTREACHED();
+ *name = "???";
+ break;
+ }
+}
+
} // namespace net
diff --git a/net/base/ssl_cipher_suite_names.h b/net/base/ssl_cipher_suite_names.h
index cd61471..9241c1b 100644
--- a/net/base/ssl_cipher_suite_names.h
+++ b/net/base/ssl_cipher_suite_names.h
@@ -25,6 +25,12 @@ void SSLCipherSuiteToStrings(const char** key_exchange_str,
// If the algorithm is unknown, |name| is set to "???".
void SSLCompressionToString(const char** name, uint8 compression_method);
+// SSLVersionToString returns the name of the SSL protocol version
+// specified by |ssl_version|, which is defined in
+// net/base/ssl_connection_status_flags.h.
+// If the version is unknown, |name| is set to "???".
+void SSLVersionToString(const char** name, int ssl_version);
+
} // namespace net
#endif // NET_BASE_SSL_CIPHER_SUITE_NAMES_H_
diff --git a/net/base/ssl_connection_status_flags.h b/net/base/ssl_connection_status_flags.h
index 1b7640c..51eb884 100644
--- a/net/base/ssl_connection_status_flags.h
+++ b/net/base/ssl_connection_status_flags.h
@@ -27,6 +27,16 @@ enum {
// library that doesn't report it, like SChannel.)
SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION = 1 << 19,
+ // The next three bits are reserved for the SSL version.
+ SSL_CONNECTION_VERSION_SHIFT = 20,
+ SSL_CONNECTION_VERSION_MASK = 7,
+ SSL_CONNECTION_VERSION_UNKNOWN = 0, // Unknown SSL version or SSL not used.
+ SSL_CONNECTION_VERSION_SSL2 = 1,
+ SSL_CONNECTION_VERSION_SSL3 = 2,
+ SSL_CONNECTION_VERSION_TLS1 = 3,
+ SSL_CONNECTION_VERSION_TLS1_1 = 4,
+ SSL_CONNECTION_VERSION_TLS1_2 = 5,
+
// 1 << 31 (the sign bit) is reserved so that the SSL connection status will
// never be negative.
};
@@ -41,6 +51,11 @@ inline int SSLConnectionStatusToCompression(int connection_status) {
SSL_CONNECTION_COMPRESSION_MASK;
}
+inline int SSLConnectionStatusToVersion(int connection_status) {
+ return (connection_status >> SSL_CONNECTION_VERSION_SHIFT) &
+ SSL_CONNECTION_VERSION_MASK;
+}
+
} // namespace net
#endif // NET_BASE_SSL_CONNECTION_STATUS_FLAGS_H_
diff --git a/net/base/ssl_info.h b/net/base/ssl_info.h
index 1786b58..4c68f06 100644
--- a/net/base/ssl_info.h
+++ b/net/base/ssl_info.h
@@ -42,9 +42,8 @@ class SSLInfo {
int security_bits;
// Information about the SSL connection itself. See
- // ssl_connection_status_flags.h for values. The ciphersuite and compression
- // in use are encoded within.
- // TODO(agl): also encode the protocol version used.
+ // ssl_connection_status_flags.h for values. The protocol version,
+ // ciphersuite, and compression in use are encoded within.
int connection_status;
};
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index dc90d1f..00bfb92 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -182,6 +182,7 @@ void HttpResponseInfo::Persist(Pickle* pickle,
}
if (ssl_info.security_bits != -1)
flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
+ // TODO(wtc): we should persist ssl_info.connection_status.
if (vary_data.is_valid())
flags |= RESPONSE_INFO_HAS_VARY_DATA;
if (response_truncated)
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 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
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 @@ void SSLClientSocketNSS::Disconnect() {
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 @@ bool SSLClientSocketNSS::SetSendBufferSize(int32 size) {
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 @@ X509Certificate *SSLClientSocketNSS::UpdateServerCert() {
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 @@ void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
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 @@ void SSLClientSocketNSS::HandshakeCallback(PRFileDesc* socket,
that->handshake_callback_called_ = true;
that->UpdateServerCert();
-
- that->CheckSecureRenegotiation();
+ that->UpdateConnectionStatus();
}
int SSLClientSocketNSS::DoSnapStartLoadInfo() {
@@ -2218,6 +2233,9 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
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 @@ int SSLClientSocketNSS::DoPayloadWrite() {
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
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index ce5fef8..a0c79fb 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -50,7 +50,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual void GetSSLInfo(SSLInfo* ssl_info);
virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
virtual NextProtoStatus GetNextProto(std::string* proto);
- virtual void UseDNSSEC(DNSSECProvider*);
+ virtual void UseDNSSEC(DNSSECProvider* provider);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -83,7 +83,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
static X509Certificate::OSCertHandle CreateOSCert(const SECItem& der_cert);
#endif
X509Certificate* UpdateServerCert();
- void CheckSecureRenegotiation() const;
+ void UpdateConnectionStatus();
void DoReadCallback(int result);
void DoWriteCallback(int result);
void DoConnectCallback(int result);
@@ -105,6 +105,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
int DoVerifyCertComplete(int result);
int DoPayloadRead();
int DoPayloadWrite();
+ void LogConnectionTypeMetrics() const;
int Init();
void SaveSnapStartInfo();
bool LoadSnapStartInfo();
@@ -166,6 +167,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
scoped_refptr<X509Certificate> server_cert_;
CERTCertificate* server_cert_nss_;
CertVerifyResult server_cert_verify_result_;
+ int ssl_connection_status_;
// Stores client authentication information between ClientAuthHandler and
// GetSSLCertRequestInfo calls.