#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "crypto/rsa_private_key.h"
#include "crypto/scoped_nss_types.h"
#include "net/base/address_list.h"
-#include "net/base/connection_type_histograms.h"
#include "net/base/dns_util.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/cert/asn1_util.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_objects_extractor.h"
+#include "net/cert/ct_ev_whitelist.h"
#include "net/cert/ct_verifier.h"
#include "net/cert/ct_verify_result.h"
#include "net/cert/scoped_nss_types.h"
void Reset() {
next_proto_status = SSLClientSocket::kNextProtoUnsupported;
next_proto.clear();
+ negotiation_extension_ = SSLClientSocket::kExtensionUnknown;
channel_id_sent = false;
server_cert_chain.Reset(NULL);
server_cert = NULL;
SSLClientSocket::NextProtoStatus next_proto_status;
std::string next_proto;
+ // TLS extension used for protocol negotiation.
+ SSLClientSocket::SSLNegotiationExtension negotiation_extension_;
+
// True if a channel ID was sent.
bool channel_id_sent;
// UpdateNextProto gets any application-layer protocol that may have been
// negotiated by the TLS connection.
void UpdateNextProto();
+ // Record TLS extension used for protocol negotiation (NPN or ALPN).
+ void UpdateExtensionUsed();
////////////////////////////////////////////////////////////////////////////
// Methods that are ONLY called on the network task runner:
}
void SSLClientSocketNSS::Core::HandshakeSucceeded() {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::HandshakeSucceeded"));
+
DCHECK(OnNSSTaskRunner());
PRBool last_handshake_resumed;
UpdateStapledOCSPResponse();
UpdateConnectionStatus();
UpdateNextProto();
+ UpdateExtensionUsed();
// Update the network task runners view of the handshake state whenever
// a handshake has completed.
}
int SSLClientSocketNSS::Core::HandleNSSError(PRErrorCode nss_error) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::HandleNSSError"));
+
DCHECK(OnNSSTaskRunner());
int net_error = MapNSSClientError(nss_error);
}
int SSLClientSocketNSS::Core::DoHandshakeLoop(int last_io_result) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoHandshakeLoop"));
+
DCHECK(OnNSSTaskRunner());
int rv = last_io_result;
}
int SSLClientSocketNSS::Core::DoReadLoop(int result) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoReadLoop"));
+
DCHECK(OnNSSTaskRunner());
DCHECK(false_started_ || handshake_callback_called_);
DCHECK_EQ(STATE_NONE, next_handshake_state_);
}
int SSLClientSocketNSS::Core::DoHandshake() {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoHandshake"));
+
DCHECK(OnNSSTaskRunner());
int net_error = OK;
SECStatus rv = SSL_ForceHandshake(nss_fd_);
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoHandshake 1"));
+
// Note: this function may be called multiple times during the handshake, so
// even though channel id and client auth are separate else cases, they can
// both be used during a single SSL handshake.
}
int SSLClientSocketNSS::Core::DoGetDBCertComplete(int result) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoGetDBCertComplete"));
+
SECStatus rv;
PostOrRunCallback(
FROM_HERE,
// transport socket. Return true if some I/O performed, false
// otherwise (error or ERR_IO_PENDING).
bool SSLClientSocketNSS::Core::DoTransportIO() {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoTransportIO"));
+
DCHECK(OnNSSTaskRunner());
bool network_moved = false;
// callback. For Read() and Write(), that's what we want. But for Connect(),
// the caller expects OK (i.e. 0) for success.
void SSLClientSocketNSS::Core::DoConnectCallback(int rv) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoConnectCallback"));
+
DCHECK(OnNSSTaskRunner());
DCHECK_NE(rv, ERR_IO_PENDING);
DCHECK(!user_connect_callback_.is_null());
}
void SSLClientSocketNSS::Core::DoReadCallback(int rv) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424386 SSLClientSocketNSS::Core::DoReadCallback"));
+
DCHECK(OnNSSTaskRunner());
DCHECK_NE(ERR_IO_PENDING, rv);
DCHECK(!user_read_callback_.is_null());
PostOrRunCallback(
FROM_HERE,
base::Bind(&Core::DidNSSRead, this, rv));
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "SSLClientSocketNSS::Core::DoReadCallback"));
PostOrRunCallback(
FROM_HERE,
base::Bind(base::ResetAndReturn(&user_read_callback_), rv));
}
void SSLClientSocketNSS::Core::UpdateConnectionStatus() {
+ // Note: This function may be called multiple times for a single connection
+ // if renegotiations occur.
+ nss_handshake_state_.ssl_connection_status = 0;
+
SSLChannelInfo channel_info;
SECStatus ok = SSL_GetChannelInfo(nss_fd_,
&channel_info, sizeof(channel_info));
SSL_CONNECTION_COMPRESSION_MASK) <<
SSL_CONNECTION_COMPRESSION_SHIFT;
- // NSS 3.14.x doesn't have a version macro for TLS 1.2 (because NSS didn't
- // support it yet), so use 0x0303 directly.
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 = 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) {
+ } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_TLS_1_0) {
version = SSL_CONNECTION_VERSION_TLS1;
} else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_TLS_1_1) {
version = SSL_CONNECTION_VERSION_TLS1_1;
- } else if (channel_info.protocolVersion == 0x0303) {
+ } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_TLS_1_2) {
version = SSL_CONNECTION_VERSION_TLS1_2;
}
nss_handshake_state_.ssl_connection_status |=
}
}
+void SSLClientSocketNSS::Core::UpdateExtensionUsed() {
+ PRBool negotiated_extension;
+ SECStatus rv = SSL_HandshakeNegotiatedExtension(nss_fd_,
+ ssl_app_layer_protocol_xtn,
+ &negotiated_extension);
+ if (rv == SECSuccess && negotiated_extension) {
+ nss_handshake_state_.negotiation_extension_ = kExtensionALPN;
+ } else {
+ rv = SSL_HandshakeNegotiatedExtension(nss_fd_,
+ ssl_next_proto_nego_xtn,
+ &negotiated_extension);
+ if (rv == SECSuccess && negotiated_extension) {
+ nss_handshake_state_.negotiation_extension_ = kExtensionNPN;
+ }
+ }
+}
+
void SSLClientSocketNSS::Core::RecordChannelIDSupportOnNSSTaskRunner() {
DCHECK(OnNSSTaskRunner());
if (nss_handshake_state_.resumed_handshake)
}
void SSLClientSocketNSS::Core::BufferSendComplete(int result) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "418183 DidCompleteReadWrite => Core::BufferSendComplete"));
+
if (!OnNSSTaskRunner()) {
if (detached_)
return;
void SSLClientSocketNSS::Core::BufferRecvComplete(
IOBuffer* read_buffer,
int result) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "418183 DidCompleteReadWrite => SSLClientSocketNSS::Core::..."));
+
DCHECK(read_buffer);
if (!OnNSSTaskRunner()) {
!core_->state().sct_list_from_tls_extension.empty());
set_stapled_ocsp_response_received(
!core_->state().stapled_ocsp_response.empty());
+ set_negotiation_extension(core_->state().negotiation_extension_);
LeaveFunction(result);
return result;
// TODO(hclam): Skip logging if server cert was expected to be bad because
// |server_cert_verify_result_| doesn't contain all the information about
// the cert.
- if (result == OK)
- LogConnectionTypeMetrics();
+ if (result == OK) {
+ int ssl_version =
+ SSLConnectionStatusToVersion(core_->state().ssl_connection_status);
+ RecordConnectionTypeMetrics(ssl_version);
+ }
const CertStatus cert_status = server_cert_verify_result_.cert_status;
if (transport_security_state_ &&
result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
}
+ scoped_refptr<ct::EVCertsWhitelist> ev_whitelist =
+ SSLConfigService::GetEVCertsWhitelist();
+ if (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV) {
+ if (ev_whitelist.get() && ev_whitelist->IsValid()) {
+ const SHA256HashValue fingerprint(
+ X509Certificate::CalculateFingerprint256(
+ server_cert_verify_result_.verified_cert->os_cert_handle()));
+
+ UMA_HISTOGRAM_BOOLEAN(
+ "Net.SSL_EVCertificateInWhitelist",
+ ev_whitelist->ContainsCertificateHash(
+ std::string(reinterpret_cast<const char*>(fingerprint.data), 8)));
+ }
+ }
+
if (result == OK) {
// Only check Certificate Transparency if there were no other errors with
// the connection.
<< ct_verify_result_.unknown_logs_scts.size();
}
-void SSLClientSocketNSS::LogConnectionTypeMetrics() const {
- UpdateConnectionTypeHistograms(CONNECTION_SSL);
- int ssl_version = SSLConnectionStatusToVersion(
- core_->state().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;
- };
-}
-
void SSLClientSocketNSS::EnsureThreadIdAssigned() const {
base::AutoLock auto_lock(lock_);
if (valid_thread_id_ != base::kInvalidThreadId)