diff options
-rw-r--r-- | net/base/net_error_list.h | 7 | ||||
-rw-r--r-- | net/base/ssl_client_socket_win.cc | 36 | ||||
-rw-r--r-- | net/base/ssl_client_socket_win.h | 1 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 9 |
4 files changed, 45 insertions, 8 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index ae7d272..e22e11f 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -99,6 +99,13 @@ NET_ERROR(SSL_RENEGOTIATION_REQUESTED, -114) // The proxy requested authentication (for tunnel establishment). NET_ERROR(PROXY_AUTH_REQUESTED, -115) +// During SSL renegotiation (rehandshake), the server sent a certificate with +// an error. +// +// Note: this error is not in the -2xx range so that it won't be handled as a +// certificate error. +NET_ERROR(CERT_ERROR_IN_SSL_RENEGOTIATION, -116) + // Certificate error codes // // The values of certificate error codes must be consecutive. diff --git a/net/base/ssl_client_socket_win.cc b/net/base/ssl_client_socket_win.cc index 7c76b99..a839bb3 100644 --- a/net/base/ssl_client_socket_win.cc +++ b/net/base/ssl_client_socket_win.cc @@ -60,6 +60,12 @@ static int MapSecurityError(SECURITY_STATUS err) { } } +// Returns true if the two CERT_CONTEXTs contain the same certificate. +bool SameCert(PCCERT_CONTEXT a, PCCERT_CONTEXT b) { + return a->cbCertEncoded == b->cbCertEncoded && + memcmp(a->pbCertEncoded, b->pbCertEncoded, b->cbCertEncoded) == 0; +} + //----------------------------------------------------------------------------- // A bitmask consisting of these bit flags encodes which versions of the SSL @@ -727,11 +733,7 @@ int SSLClientSocketWin::DoVerifyCertComplete(int result) { LogConnectionTypeMetrics(); if (renegotiating_) { - // A rehandshake, started in the middle of a Read, has completed. - renegotiating_ = false; - // Pick up where we left off. Go back to reading data. - if (result == OK) - SetNextStateForRead(); + DidCompleteRenegotiation(result); } else { // The initial handshake, kicked off by a Connect, has completed. completed_handshake_ = true; @@ -998,13 +1000,31 @@ int SSLClientSocketWin::DidCompleteHandshake() { DLOG(ERROR) << "QueryContextAttributes failed: " << status; return MapSecurityError(status); } - server_cert_ = X509Certificate::CreateFromHandle( - server_cert_handle, X509Certificate::SOURCE_FROM_NETWORK); + if (renegotiating_ && + SameCert(server_cert_->os_cert_handle(), server_cert_handle)) { + // We already verified the server certificate. Either it is good or the + // user has accepted the certificate error. + CertFreeCertificateContext(server_cert_handle); + DidCompleteRenegotiation(OK); + } else { + server_cert_ = X509Certificate::CreateFromHandle( + server_cert_handle, X509Certificate::SOURCE_FROM_NETWORK); - next_state_ = STATE_VERIFY_CERT; + next_state_ = STATE_VERIFY_CERT; + } return OK; } +// Called when a renegotiation is completed. |result| is the verification +// result of the server certificate received during renegotiation. +void SSLClientSocketWin::DidCompleteRenegotiation(int result) { + // A rehandshake, started in the middle of a Read, has completed. + renegotiating_ = false; + // Pick up where we left off. Go back to reading data. + if (result == OK) + SetNextStateForRead(); +} + void SSLClientSocketWin::LogConnectionTypeMetrics() const { UpdateConnectionTypeHistograms(CONNECTION_SSL); if (server_cert_verify_result_.has_md5) diff --git a/net/base/ssl_client_socket_win.h b/net/base/ssl_client_socket_win.h index 9bdb5a1..35f1e9e 100644 --- a/net/base/ssl_client_socket_win.h +++ b/net/base/ssl_client_socket_win.h @@ -66,6 +66,7 @@ class SSLClientSocketWin : public SSLClientSocket { int DidCallInitializeSecurityContext(); int DidCompleteHandshake(); + void DidCompleteRenegotiation(int result); void LogConnectionTypeMetrics() const; void SetNextStateForRead(); void FreeSendBuffer(); diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 5795011..97f7715 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -745,6 +745,15 @@ int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() { } int HttpNetworkTransaction::DoReadHeadersComplete(int result) { + if (using_ssl_ && IsCertificateError(result)) { + // We don't handle a certificate error during SSL renegotiation, so we + // have to return an error that's not in the certificate error range + // (-2xx). + LOG(ERROR) << "Got a server certificate with error " << result + << " during SSL renegotiation"; + result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION; + } + if (result < 0) return HandleIOError(result); |