Do not assume OSCertHandle is OpenSSL's X509 structure.
Instead create a X509Certificate instance from the OpenSSL
chain via PeerCertificateChain, and compare with the existing
X509Certificate.
BUG=none
Review URL: https://codereview.chromium.org/203323004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@258337 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index d04670f..f97c4697c 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -332,16 +332,17 @@
// and the other elements are in the order given by the server.
class SSLClientSocketOpenSSL::PeerCertificateChain {
public:
- explicit PeerCertificateChain(SSL* ssl) { Reset(ssl); }
+ explicit PeerCertificateChain(STACK_OF(X509)* chain) { Reset(chain); }
PeerCertificateChain(const PeerCertificateChain& other) { *this = other; }
~PeerCertificateChain() {}
PeerCertificateChain& operator=(const PeerCertificateChain& other);
- // Resets the PeerCertificateChain to the set of certificates supplied by the
- // peer of |ssl|, which may be NULL, indicating to empty the store
- // certificates. Note: If an error occurs, such as being unable to parse the
- // certificates, this will behave as if Reset(NULL) was called.
- void Reset(SSL* ssl);
+ // Resets the PeerCertificateChain to the set of certificates in|chain|,
+ // which may be NULL, indicating to empty the store certificates.
+ // Note: If an error occurs, such as being unable to parse the certificates,
+ // this will behave as if Reset(NULL) was called.
+ void Reset(STACK_OF(X509)* chain);
+
// Note that when USE_OPENSSL is defined, OSCertHandle is X509*
const scoped_refptr<X509Certificate>& AsOSChain() const { return os_chain_; }
@@ -356,6 +357,8 @@
return sk_X509_value(openssl_chain_.get(), index);
}
+ bool IsValid() { return os_chain_.get() && openssl_chain_.get(); }
+
private:
static void FreeX509Stack(STACK_OF(X509)* cert_chain) {
sk_X509_pop_free(cert_chain, X509_free);
@@ -389,14 +392,11 @@
#if defined(USE_OPENSSL)
// When OSCertHandle is typedef'ed to X509, this implementation does a short cut
// to avoid converting back and forth between der and X509 struct.
-void SSLClientSocketOpenSSL::PeerCertificateChain::Reset(SSL* ssl) {
+void SSLClientSocketOpenSSL::PeerCertificateChain::Reset(
+ STACK_OF(X509)* chain) {
openssl_chain_.reset(NULL);
os_chain_ = NULL;
- if (ssl == NULL)
- return;
-
- STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
if (!chain)
return;
@@ -418,14 +418,11 @@
}
}
#else // !defined(USE_OPENSSL)
-void SSLClientSocketOpenSSL::PeerCertificateChain::Reset(SSL* ssl) {
+void SSLClientSocketOpenSSL::PeerCertificateChain::Reset(
+ STACK_OF(X509)* chain) {
openssl_chain_.reset(NULL);
os_chain_ = NULL;
- if (ssl == NULL)
- return;
-
- STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
if (!chain)
return;
@@ -1058,8 +1055,12 @@
}
X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() {
- server_cert_chain_->Reset(ssl_);
+ server_cert_chain_->Reset(SSL_get_peer_cert_chain(ssl_));
server_cert_ = server_cert_chain_->AsOSChain();
+
+ if (!server_cert_chain_->IsValid())
+ DVLOG(1) << "UpdateServerCert received invalid certificate chain from peer";
+
return server_cert_.get();
}
@@ -1502,12 +1503,16 @@
return 1;
}
- if (X509Certificate::IsSameOSCert(server_cert_->os_cert_handle(),
- sk_X509_value(store_ctx->untrusted, 0))) {
- return 1;
- }
+ CHECK(server_cert_.get());
- LOG(ERROR) << "Server certificate changed between handshakes";
+ PeerCertificateChain chain(store_ctx->chain);
+ if (chain.IsValid() && server_cert_->Equals(chain.AsOSChain()))
+ return 1;
+
+ if (!chain.IsValid())
+ LOG(ERROR) << "Received invalid certificate chain between handshakes";
+ else
+ LOG(ERROR) << "Server certificate changed between handshakes";
return 0;
}