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

Side by Side 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: Added test case for retrieving unverified server cert chain. Created 6 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // OpenSSL binding for SSLClientSocket. The class layout and general principle 5 // OpenSSL binding for SSLClientSocket. The class layout and general principle
6 // of operation is derived from SSLClientSocketNSS. 6 // of operation is derived from SSLClientSocketNSS.
7 7
8 #include "net/socket/ssl_client_socket_openssl.h" 8 #include "net/socket/ssl_client_socket_openssl.h"
9 9
10 #include <openssl/err.h> 10 #include <openssl/err.h>
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 312
313 // This is the index used with SSL_get_ex_data to retrieve the owner 313 // This is the index used with SSL_get_ex_data to retrieve the owner
314 // SSLClientSocketOpenSSL object from an SSL instance. 314 // SSLClientSocketOpenSSL object from an SSL instance.
315 int ssl_socket_data_index_; 315 int ssl_socket_data_index_;
316 316
317 crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; 317 crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_;
318 // |session_cache_| must be destroyed before |ssl_ctx_|. 318 // |session_cache_| must be destroyed before |ssl_ctx_|.
319 SSLSessionCacheOpenSSL session_cache_; 319 SSLSessionCacheOpenSSL session_cache_;
320 }; 320 };
321 321
322 // PeerCertificateChain is a helper object which extracts the certificate
323 // chain, as given by the server, from an OpenSSL socket and performs the needed
324 // resource management. The first element of the chain is the leaf certificate
325 // and the other elements are in the order given by the server.
326 class PeerCertificateChain {
327 public:
328 explicit PeerCertificateChain(SSL* ssl);
329 PeerCertificateChain(const PeerCertificateChain& other);
330 ~PeerCertificateChain();
331 PeerCertificateChain& operator=(const PeerCertificateChain& other);
332
333 void Reset(SSL* ssl);
334 const scoped_refptr<X509Certificate>& AsNativeChain() const {
335 return native_chain_;
wtc 2014/03/10 21:45:34 Nit: it's not clear what "native" means here. I w
haavardm 2014/03/11 18:43:21 For consistency and possible future use of this fu
336 }
337
338 size_t size() const {
339 if (!openssl_chain_.get())
340 return 0;
341 return sk_X509_num(openssl_chain_.get());
342 }
343
344 // Returns the certificate chain as presented by server.
wtc 2014/03/10 21:45:34 This comment seems wrong; it doesn't seem to descr
haavardm 2014/03/11 18:43:21 Done.
345 X509* operator[](size_t index) const {
346 DCHECK_LT(index, size());
347 return sk_X509_value(openssl_chain_.get(), index);
348 }
349
350 private:
351 static void FreeX509Stack(STACK_OF(X509) * chain) {
wtc 2014/03/10 21:45:34 Nit: delete the space before '*'.
haavardm 2014/03/11 18:43:21 Done.
352 sk_X509_pop_free(chain, X509_free);
353 }
354 crypto::ScopedOpenSSL<STACK_OF(X509), FreeX509Stack> openssl_chain_;
355
356 scoped_refptr<X509Certificate> native_chain_;
357 };
358
359 PeerCertificateChain::PeerCertificateChain(SSL* ssl) { Reset(ssl); }
360 PeerCertificateChain::~PeerCertificateChain() {};
361
362 PeerCertificateChain::PeerCertificateChain(const PeerCertificateChain& other) {
363 *this = other;
364 }
365
366 PeerCertificateChain& PeerCertificateChain::operator=(
367 const PeerCertificateChain& other) {
368 if (this == &other)
369 return *this;
370
371 // native_chain is reference counted by scoped_refptr;
372 native_chain_ = other.native_chain_;
373
374 // Must increase the reference count manually for sk_X509_dup
375 openssl_chain_.reset(sk_X509_dup(other.openssl_chain_.get()));
376 for (int i = 0; i < sk_X509_num(openssl_chain_.get()); ++i) {
377 X509* x = sk_X509_value(openssl_chain_.get(), i);
378 CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
379 }
380 return *this;
381 }
382
383 void PeerCertificateChain::Reset(SSL* ssl) {
384 openssl_chain_.reset(NULL);
385 native_chain_ = NULL;
386
387 if (ssl == NULL)
388 return;
389
390 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
391 if (!chain)
392 return;
393
394 // sk_X509_dup does not increase reference count on the certs in the stack.
395 openssl_chain_.reset(sk_X509_dup(chain));
396
397 std::vector<base::StringPiece> der_chain;
398 for (int i = 0; i < sk_X509_num(openssl_chain_.get()); ++i) {
399 X509* x = sk_X509_value(openssl_chain_.get(), i);
400
401 // We increase reference count for the certs in openssl_chain_.
402 CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
403
404 unsigned char* cert_data = NULL;
405 int cert_data_length = i2d_X509(x, &cert_data);
406 if (cert_data_length && cert_data)
407 der_chain.push_back(base::StringPiece(reinterpret_cast<char*>(cert_data),
408 cert_data_length));
409 }
410
411 native_chain_ = X509Certificate::CreateFromDERCertChain(der_chain);
412
413 for (size_t i = 0; i < der_chain.size(); ++i) {
414 OPENSSL_free(const_cast<char*>(der_chain[i].data()));
415 }
416
417 if (der_chain.size() !=
418 static_cast<size_t>(sk_X509_num(openssl_chain_.get()))) {
wtc 2014/03/10 21:45:34 Just to check my understanding: this can only happ
Ryan Sleevi 2014/03/11 00:15:15 Correct
419 openssl_chain_.reset(NULL);
420 native_chain_ = NULL;
421 }
422 }
423
322 // static 424 // static
323 SSLSessionCacheOpenSSL::Config 425 SSLSessionCacheOpenSSL::Config
324 SSLClientSocketOpenSSL::SSLContext::kDefaultSessionCacheConfig = { 426 SSLClientSocketOpenSSL::SSLContext::kDefaultSessionCacheConfig = {
325 &GetSessionCacheKey, // key_func 427 &GetSessionCacheKey, // key_func
326 1024, // max_entries 428 1024, // max_entries
327 256, // expiration_check_count 429 256, // expiration_check_count
328 60 * 60, // timeout_seconds 430 60 * 60, // timeout_seconds
329 }; 431 };
330 432
331 // static 433 // static
332 void SSLClientSocket::ClearSessionCache() { 434 void SSLClientSocket::ClearSessionCache() {
333 SSLClientSocketOpenSSL::SSLContext* context = 435 SSLClientSocketOpenSSL::SSLContext* context =
334 SSLClientSocketOpenSSL::SSLContext::GetInstance(); 436 SSLClientSocketOpenSSL::SSLContext::GetInstance();
335 context->session_cache()->Flush(); 437 context->session_cache()->Flush();
336 OpenSSLClientKeyStore::GetInstance()->Flush(); 438 OpenSSLClientKeyStore::GetInstance()->Flush();
337 } 439 }
338 440
339 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( 441 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
340 scoped_ptr<ClientSocketHandle> transport_socket, 442 scoped_ptr<ClientSocketHandle> transport_socket,
341 const HostPortPair& host_and_port, 443 const HostPortPair& host_and_port,
342 const SSLConfig& ssl_config, 444 const SSLConfig& ssl_config,
343 const SSLClientSocketContext& context) 445 const SSLClientSocketContext& context)
344 : transport_send_busy_(false), 446 : transport_send_busy_(false),
345 transport_recv_busy_(false), 447 transport_recv_busy_(false),
346 transport_recv_eof_(false), 448 transport_recv_eof_(false),
347 weak_factory_(this), 449 weak_factory_(this),
348 pending_read_error_(kNoPendingReadResult), 450 pending_read_error_(kNoPendingReadResult),
349 transport_write_error_(OK), 451 transport_write_error_(OK),
452 server_cert_chain_(new PeerCertificateChain(NULL)),
wtc 2014/03/10 21:45:34 Is it necessary to create an empty PeerCertificate
haavardm 2014/03/11 18:43:21 That was just to avoid having to check for NULL an
453 server_cert_(NULL),
wtc 2014/03/10 21:45:34 Nit: we usually don't initialize a scoped_refptr t
haavardm 2014/03/11 18:43:21 Done.
350 completed_handshake_(false), 454 completed_handshake_(false),
351 client_auth_cert_needed_(false), 455 client_auth_cert_needed_(false),
352 cert_verifier_(context.cert_verifier), 456 cert_verifier_(context.cert_verifier),
353 server_bound_cert_service_(context.server_bound_cert_service), 457 server_bound_cert_service_(context.server_bound_cert_service),
354 ssl_(NULL), 458 ssl_(NULL),
355 transport_bio_(NULL), 459 transport_bio_(NULL),
356 transport_(transport_socket.Pass()), 460 transport_(transport_socket.Pass()),
357 host_and_port_(host_and_port), 461 host_and_port_(host_and_port),
358 ssl_config_(ssl_config), 462 ssl_config_(ssl_config),
359 ssl_session_cache_shard_(context.ssl_session_cache_shard), 463 ssl_session_cache_shard_(context.ssl_session_cache_shard),
360 trying_cached_session_(false), 464 trying_cached_session_(false),
361 next_handshake_state_(STATE_NONE), 465 next_handshake_state_(STATE_NONE),
362 npn_status_(kNextProtoUnsupported), 466 npn_status_(kNextProtoUnsupported),
363 channel_id_request_return_value_(ERR_UNEXPECTED), 467 channel_id_request_return_value_(ERR_UNEXPECTED),
364 channel_id_xtn_negotiated_(false), 468 channel_id_xtn_negotiated_(false),
365 net_log_(transport_->socket()->NetLog()) { 469 net_log_(transport_->socket()->NetLog()) {}
366 }
367 470
368 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { 471 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() {
369 Disconnect(); 472 Disconnect();
370 } 473 }
371 474
372 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( 475 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo(
373 SSLCertRequestInfo* cert_request_info) { 476 SSLCertRequestInfo* cert_request_info) {
374 cert_request_info->host_and_port = host_and_port_; 477 cert_request_info->host_and_port = host_and_port_;
375 cert_request_info->cert_authorities = cert_authorities_; 478 cert_request_info->cert_authorities = cert_authorities_;
376 } 479 }
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 1013
911 void SSLClientSocketOpenSSL::DoConnectCallback(int rv) { 1014 void SSLClientSocketOpenSSL::DoConnectCallback(int rv) {
912 if (!user_connect_callback_.is_null()) { 1015 if (!user_connect_callback_.is_null()) {
913 CompletionCallback c = user_connect_callback_; 1016 CompletionCallback c = user_connect_callback_;
914 user_connect_callback_.Reset(); 1017 user_connect_callback_.Reset();
915 c.Run(rv > OK ? OK : rv); 1018 c.Run(rv > OK ? OK : rv);
916 } 1019 }
917 } 1020 }
918 1021
919 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { 1022 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() {
920 if (server_cert_.get()) 1023 #ifdef USE_OPENSSL
wtc 2014/03/10 21:45:34 NitL: the Chromium coding style recommends always
haavardm 2014/03/11 18:43:21 Done.
921 return server_cert_.get(); 1024 server_cert_ = NULL;
wtc 2014/03/10 21:45:34 Please confirm that this "one-time initialization"
922
923 crypto::ScopedOpenSSL<X509, X509_free> cert(SSL_get_peer_certificate(ssl_));
924 if (!cert.get()) {
925 LOG(WARNING) << "SSL_get_peer_certificate returned NULL";
926 return NULL;
927 }
928
929 // Unlike SSL_get_peer_certificate, SSL_get_peer_cert_chain does not 1025 // Unlike SSL_get_peer_certificate, SSL_get_peer_cert_chain does not
930 // increment the reference so sk_X509_free does not need to be called. 1026 // increment the reference so sk_X509_free does not need to be called.
wtc 2014/03/10 21:45:34 Nit: I think the "Unlike SSL_get_peer_certificate,
haavardm 2014/03/11 18:43:21 Done.
931 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_); 1027 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_);
932 X509Certificate::OSCertHandles intermediates; 1028 X509Certificate::OSCertHandles intermediates;
933 if (chain) { 1029 if (chain) {
934 for (int i = 0; i < sk_X509_num(chain); ++i) 1030 for (int i = 1; i < sk_X509_num(chain); ++i)
935 intermediates.push_back(sk_X509_value(chain, i)); 1031 intermediates.push_back(sk_X509_value(chain, i));
1032
1033 server_cert_ = X509Certificate::CreateFromHandle(sk_X509_value(chain, 0),
1034 intermediates);
936 } 1035 }
937 server_cert_ = X509Certificate::CreateFromHandle(cert.get(), intermediates); 1036 #else
938 DCHECK(server_cert_.get()); 1037 server_cert_chain_->Reset(ssl_);
1038 server_cert_ = server_cert_chain_->AsNativeChain();
wtc 2014/03/10 21:45:34 IMPORTANT: comparing the two implementations of th
haavardm 2014/03/11 18:43:21 The difference is that the first implementation do
1039 #endif
939 1040
940 return server_cert_.get(); 1041 return server_cert_.get();
941 } 1042 }
942 1043
943 void SSLClientSocketOpenSSL::OnHandshakeIOComplete(int result) { 1044 void SSLClientSocketOpenSSL::OnHandshakeIOComplete(int result) {
944 int rv = DoHandshakeLoop(result); 1045 int rv = DoHandshakeLoop(result);
945 if (rv != ERR_IO_PENDING) { 1046 if (rv != ERR_IO_PENDING) {
946 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); 1047 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv);
947 DoConnectCallback(rv); 1048 DoConnectCallback(rv);
948 } 1049 }
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after
1417 *outlen = ssl_config_.next_protos[0].size(); 1518 *outlen = ssl_config_.next_protos[0].size();
1418 } 1519 }
1419 1520
1420 npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen); 1521 npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen);
1421 server_protos_.assign(reinterpret_cast<const char*>(in), inlen); 1522 server_protos_.assign(reinterpret_cast<const char*>(in), inlen);
1422 DVLOG(2) << "next protocol: '" << npn_proto_ << "' status: " << npn_status_; 1523 DVLOG(2) << "next protocol: '" << npn_proto_ << "' status: " << npn_status_;
1423 #endif 1524 #endif
1424 return SSL_TLSEXT_ERR_OK; 1525 return SSL_TLSEXT_ERR_OK;
1425 } 1526 }
1426 1527
1528 const scoped_refptr<X509Certificate>
1529 SSLClientSocketOpenSSL::GetUnverifiedServerCertificate() const {
1530 return server_cert_;
1531 }
1532
1427 } // namespace net 1533 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698