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

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: Fixes after review comments 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..cceacebb67f7cf46d0a4a13be90e309c6973fb73 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -319,6 +319,88 @@ 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 SSLClientSocketOpenSSL::PeerCertificateChain {
+ public:
+ virtual ~PeerCertificateChain() {};
+
+ // Resets the current chain, freeing any resources, and updates the current
+ // chain to be a referenced copy of the chain stored in |ssl|.
+ // If |ssl| is NULL, then the current certificate chain will be freed.
+ void Reset(SSL* ssl) {
+ x509_certs_.clear();
+ der_certs_chain_.clear();
+ der_certs_mem_handler_.clear();
+
+ if (ssl == NULL)
+ return;
+
+ STACK_OF(X509)* intermediates = SSL_get_peer_cert_chain(ssl);
+ if (intermediates) {
+ for (int i = 0; i < sk_X509_num(intermediates); ++i) {
+ if (!AddCert(sk_X509_value(intermediates, i))) {
+ Reset(NULL);
+ return;
+ }
+ }
+ }
+ }
+
+ // Returns the current certificate chain as a vector of DER-encoded
+ // base::StringPieces. The returned vector remains valid until Reset is
+ // called.
+ std::vector<base::StringPiece> AsStringPieceVector() const {
+ return der_certs_chain_;
+ }
+
+ bool empty() const { return x509_certs_.empty(); }
+ size_t size() const { return x509_certs_.size(); }
+
+ X509* operator[](size_t index) const {
+ DCHECK_LT(index, x509_certs_.size());
+ return x509_certs_[index].get();
+ }
+
+ private:
+ struct OpenSSLFreeDeleter {
+ inline void operator()(void* ptr) const { OPENSSL_free(ptr); }
+ };
+
+ struct X509Deleter {
+ inline void operator()(X509* ptr) const { X509_free(ptr); }
+ };
+
+ typedef scoped_ptr<unsigned char, OpenSSLFreeDeleter> ScopedOpenSSLArray;
+ typedef scoped_ptr<X509, X509Deleter> ScopedX509;
+
+ bool AddCert(X509* cert) {
+ unsigned char* cert_data = NULL;
+ int cert_data_length = i2d_X509(cert, &cert_data);
+ if (cert_data_length <= 0 || !cert_data)
+ return false;
+
+ der_certs_mem_handler_.push_back(ScopedOpenSSLArray(cert_data));
+ der_certs_chain_.push_back(base::StringPiece(
+ reinterpret_cast<char*>(cert_data), cert_data_length));
+
+ x509_certs_.push_back(ScopedX509(cert));
+ // Increase reference count for cert
+ CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
+
+ return true;
+ }
+
+ std::vector<base::StringPiece> der_certs_chain_;
+
+ // Make sure the DER data strings are free'd with OPENSSL_free
+ std::vector<PeerCertificateChain::ScopedOpenSSLArray> der_certs_mem_handler_;
+
+ std::vector<ScopedX509> x509_certs_;
Ryan Sleevi 2014/02/25 20:27:09 Storing a vector of ScopedX509 doesn't work before
haavardm 2014/02/25 20:53:52 Seems good. I guess I got a little too focused on
haavardm 2014/03/11 18:43:20 Done.
+};
+
// static
SSLSessionCacheOpenSSL::Config
SSLClientSocketOpenSSL::SSLContext::kDefaultSessionCacheConfig = {
@@ -347,6 +429,8 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
weak_factory_(this),
pending_read_error_(kNoPendingReadResult),
transport_write_error_(OK),
+ server_cert_chain_(new PeerCertificateChain()),
+ server_cert_(NULL),
completed_handshake_(false),
client_auth_cert_needed_(false),
cert_verifier_(context.cert_verifier),
@@ -917,25 +1001,22 @@ 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_));
haavardm 2014/02/25 19:37:37 I removed this, as it seems that server certificat
- if (!cert.get()) {
- LOG(WARNING) << "SSL_get_peer_certificate returned NULL";
- return NULL;
- }
-
+#ifdef USE_OPENSSL
// 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(cert.get(), intermediates);
- DCHECK(server_cert_.get());
+ server_cert_ =
+ X509Certificate::CreateFromHandle(sk_X509_value(chain, 0), intermediates);
Ryan Sleevi 2014/02/25 20:27:09 if |chain| is false, or sk_X509_num(chain) is 0, t
haavardm 2014/03/11 18:43:20 Done.
+#else
+ server_cert_chain_->Reset(ssl_);
+ server_cert_ = X509Certificate::CreateFromDERCertChain(
+ server_cert_chain_->AsStringPieceVector());
+#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