OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |