| Index: net/socket/ssl_client_socket_openssl.cc
|
| diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
|
| index 500e54d3898b5ee9ffcfc45bf62bc58342a130a8..cc90fdd5f4daddf57e0d2fd10ab85a07dc093b79 100644
|
| --- a/net/socket/ssl_client_socket_openssl.cc
|
| +++ b/net/socket/ssl_client_socket_openssl.cc
|
| @@ -38,6 +38,7 @@
|
| #include "net/ssl/ssl_cert_request_info.h"
|
| #include "net/ssl/ssl_client_session_cache_openssl.h"
|
| #include "net/ssl/ssl_connection_status_flags.h"
|
| +#include "net/ssl/ssl_failure_state.h"
|
| #include "net/ssl/ssl_info.h"
|
|
|
| #if defined(OS_WIN)
|
| @@ -371,6 +372,7 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
|
| channel_id_sent_(false),
|
| handshake_completed_(false),
|
| certificate_verified_(false),
|
| + ssl_failure_state_(kSSLFailureNone),
|
| transport_security_state_(context.transport_security_state),
|
| policy_enforcer_(context.cert_policy_enforcer),
|
| net_log_(transport_->socket()->NetLog()),
|
| @@ -400,6 +402,10 @@ SSLClientSocketOpenSSL::GetChannelIDService() const {
|
| return channel_id_service_;
|
| }
|
|
|
| +SSLFailureState SSLClientSocketOpenSSL::GetSSLFailureState() const {
|
| + return ssl_failure_state_;
|
| +}
|
| +
|
| int SSLClientSocketOpenSSL::ExportKeyingMaterial(
|
| const base::StringPiece& label,
|
| bool has_context, const base::StringPiece& context,
|
| @@ -507,7 +513,10 @@ void SSLClientSocketOpenSSL::Disconnect() {
|
| npn_proto_.clear();
|
|
|
| channel_id_sent_ = false;
|
| + handshake_completed_ = false;
|
| + certificate_verified_ = false;
|
| channel_id_request_handle_.Cancel();
|
| + ssl_failure_state_ = kSSLFailureNone;
|
| }
|
|
|
| bool SSLClientSocketOpenSSL::IsConnected() const {
|
| @@ -940,6 +949,31 @@ int SSLClientSocketOpenSSL::DoHandshake() {
|
| net_log_.AddEvent(
|
| NetLog::TYPE_SSL_HANDSHAKE_ERROR,
|
| CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
|
| +
|
| + // Classify the handshake failure. This is used to determine causes of the
|
| + // TLS version fallback.
|
| +
|
| + // |cipher| is the current outgoing cipher suite, so it is non-null iff
|
| + // ChangeCipherSpec was sent.
|
| + const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_);
|
| + if (SSL_get_state(ssl_) == SSL3_ST_CR_SRVR_HELLO_A) {
|
| + ssl_failure_state_ = kSSLFailureClientHello;
|
| + } else if (cipher && (SSL_CIPHER_get_id(cipher) ==
|
| + TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 ||
|
| + SSL_CIPHER_get_id(cipher) ==
|
| + TLS1_CK_RSA_WITH_AES_128_GCM_SHA256)) {
|
| + ssl_failure_state_ = kSSLFailureBuggyGCM;
|
| + } else if (cipher && ssl_config_.send_client_cert) {
|
| + ssl_failure_state_ = kSSLFailureClientAuth;
|
| + } else if (ERR_GET_LIB(error_info.error_code) == ERR_LIB_SSL &&
|
| + ERR_GET_REASON(error_info.error_code) ==
|
| + SSL_R_OLD_SESSION_VERSION_NOT_RETURNED) {
|
| + ssl_failure_state_ = kSSLFailureSessionMismatch;
|
| + } else if (cipher && npn_status_ != kNextProtoUnsupported) {
|
| + ssl_failure_state_ = kSSLFailureNextProto;
|
| + } else {
|
| + ssl_failure_state_ = kSSLFailureUnknown;
|
| + }
|
| }
|
|
|
| GotoState(STATE_HANDSHAKE_COMPLETE);
|
|
|