Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1182)

Unified Diff: net/socket/ssl_client_socket_openssl.cc

Issue 173853014: Make OpenSSL UpdateServerCert() OS independent. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Free Openssl strings Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/socket/ssl_client_socket_openssl.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 b253dfeae50884859e2dceb3657363d2a6834b29..71465b8165783d71fb847ea32a51a64b1366e62a 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -319,6 +319,110 @@ class SSLClientSocketOpenSSL::SSLContext {
SSLSessionCacheOpenSSL session_cache_;
};
+// PeerCertificateChain is a helper object which extracts the certificate
+// chain, as given by the server, from an OpenSSL socket and performs the needed
+// resource management. The first element of the chain is the leaf certificate
+// and the other elements are in the order given by the server.
+class PeerCertificateChain {
+ public:
+ explicit PeerCertificateChain(SSL* ssl);
+ PeerCertificateChain(const PeerCertificateChain& other);
+ ~PeerCertificateChain();
+ PeerCertificateChain& operator=(const PeerCertificateChain& other);
+
+ void Reset(SSL* ssl);
+ const scoped_refptr<X509Certificate>& AsNativeChain() const {
+ return native_chain_;
+ }
+
+ size_t size() const {
+ if (!openssl_chain_.get())
+ return 0;
+ return sk_X509_num(openssl_chain_.get());
+ }
+
+ // Returns the certificate chain as presented by server.
+ X509* operator[](size_t index) const {
+ DCHECK_LT(index, size());
+ return sk_X509_value(openssl_chain_.get(), index);
+ }
+
+ private:
+ static void FreeX509Stack(STACK_OF(X509) * chain) {
+ sk_X509_pop_free(chain, X509_free);
+ }
+ crypto::ScopedOpenSSL<STACK_OF(X509), FreeX509Stack> openssl_chain_;
+
+ scoped_refptr<X509Certificate> native_chain_;
+};
+
+PeerCertificateChain::PeerCertificateChain(SSL* ssl) { Reset(ssl); }
+PeerCertificateChain::~PeerCertificateChain() {};
+
+PeerCertificateChain::PeerCertificateChain(const PeerCertificateChain& other) {
+ *this = other;
+}
+
+PeerCertificateChain& PeerCertificateChain::operator=(
+ const PeerCertificateChain& other) {
+ if (this == &other)
+ return *this;
+
+ // native_chain is reference counted by scoped_refptr;
+ native_chain_ = other.native_chain_;
+
+ // Must increase the reference count manually for sk_X509_dup
+ openssl_chain_.reset(sk_X509_dup(other.openssl_chain_.get()));
+ for (int i = 0; i < sk_X509_num(openssl_chain_.get()); ++i) {
+ X509* x = sk_X509_value(openssl_chain_.get(), i);
+ CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+ }
+ return *this;
+}
+
+void PeerCertificateChain::Reset(SSL* ssl) {
+ openssl_chain_.reset(NULL);
+ native_chain_ = NULL;
+
+ if (ssl == NULL)
+ return;
+
+ STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
+ if (!chain)
+ return;
+
+ // sk_X509_dup does not increase reference count on the certs in the stack.
+ openssl_chain_.reset(sk_X509_dup(chain));
+
+ std::vector<base::StringPiece> der_chain;
+ for (int i = 0; i < sk_X509_num(openssl_chain_.get()); ++i) {
+ X509* x = sk_X509_value(openssl_chain_.get(), i);
+
+ // We increase reference count for the certs in openssl_chain_.
+ CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+
+ unsigned char* cert_data = NULL;
+ int cert_data_length = i2d_X509(x, &cert_data);
+ if (cert_data_length && cert_data)
+ der_chain.push_back(base::StringPiece(reinterpret_cast<char*>(cert_data),
+ cert_data_length));
+ }
+
+ native_chain_ = X509Certificate::CreateFromDERCertChain(der_chain);
+
+ for (size_t i = 0; i < der_chain.size(); ++i) {
+ OPENSSL_free((void*)der_chain[i].data());
Ryan Sleevi 2014/02/27 03:07:29 You shouldn't need to cast to void* here. If you d
haavardm 2014/02/27 10:46:28 chain[i].data() is 'const char*' while OPENSSL_Fre
wtc 2014/02/27 17:54:56 Yes, this requires a cast, and const_cast<char*> i
haavardm 2014/03/11 18:43:21 Done.
+ }
+
+ if (!native_chain_->os_cert_handle() ||
+ native_chain_->GetIntermediateCertificates().size() + 1 !=
+ static_cast<size_t>(sk_X509_num(openssl_chain_.get()))) {
Ryan Sleevi 2014/02/27 03:07:29 Pathological case: What happens when .size() == nu
haavardm 2014/02/27 10:46:28 I think we would have a crash or freeze long befor
haavardm 2014/03/11 18:43:21 Done.
+ openssl_chain_.reset(NULL);
+ native_chain_ = NULL;
+ }
+}
+;
+
// static
SSLSessionCacheOpenSSL::Config
SSLClientSocketOpenSSL::SSLContext::kDefaultSessionCacheConfig = {
@@ -347,6 +451,8 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
weak_factory_(this),
pending_read_error_(kNoPendingReadResult),
transport_write_error_(OK),
+ server_cert_chain_(new PeerCertificateChain(NULL)),
+ server_cert_(NULL),
completed_handshake_(false),
client_auth_cert_needed_(false),
cert_verifier_(context.cert_verifier),
@@ -362,8 +468,7 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
npn_status_(kNextProtoUnsupported),
channel_id_request_return_value_(ERR_UNEXPECTED),
channel_id_xtn_negotiated_(false),
- net_log_(transport_->socket()->NetLog()) {
-}
+ net_log_(transport_->socket()->NetLog()) {}
SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() {
Disconnect();
@@ -917,25 +1022,23 @@ void SSLClientSocketOpenSSL::DoConnectCallback(int rv) {
}
X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() {
- if (server_cert_.get())
- return server_cert_.get();
-
- crypto::ScopedOpenSSL<X509, X509_free> cert(SSL_get_peer_certificate(ssl_));
- if (!cert.get()) {
- LOG(WARNING) << "SSL_get_peer_certificate returned NULL";
- return NULL;
- }
-
+#ifdef USE_OPENSSL
+ server_cert_ = NULL;
// Unlike SSL_get_peer_certificate, SSL_get_peer_cert_chain does not
// increment the reference so sk_X509_free does not need to be called.
STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_);
X509Certificate::OSCertHandles intermediates;
if (chain) {
- for (int i = 0; i < sk_X509_num(chain); ++i)
+ for (int i = 1; i < sk_X509_num(chain); ++i)
intermediates.push_back(sk_X509_value(chain, i));
+
+ server_cert_ = X509Certificate::CreateFromHandle(sk_X509_value(chain, 0),
+ intermediates);
}
- server_cert_ = X509Certificate::CreateFromHandle(cert.get(), intermediates);
- DCHECK(server_cert_.get());
+#else
+ server_cert_chain_->Reset(ssl_);
+ server_cert_ = server_cert_chain_->AsNativeChain();
+#endif
return server_cert_.get();
}
« no previous file with comments | « net/socket/ssl_client_socket_openssl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698