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 SSLClientSocketOpenSSL::PeerCertificateChain { | |
327 public: | |
328 virtual ~PeerCertificateChain() {}; | |
329 | |
330 // Resets the current chain, freeing any resources, and updates the current | |
331 // chain to be a referenced copy of the chain stored in |ssl|. | |
332 // If |ssl| is NULL, then the current certificate chain will be freed. | |
333 void Reset(SSL* ssl) { | |
334 x509_certs_.clear(); | |
335 der_certs_chain_.clear(); | |
336 der_certs_mem_handler_.clear(); | |
337 | |
338 if (ssl == NULL) | |
339 return; | |
340 | |
341 STACK_OF(X509)* intermediates = SSL_get_peer_cert_chain(ssl); | |
342 if (intermediates) { | |
343 for (int i = 0; i < sk_X509_num(intermediates); ++i) { | |
344 if (!AddCert(sk_X509_value(intermediates, i))) { | |
345 Reset(NULL); | |
346 return; | |
347 } | |
348 } | |
349 } | |
350 } | |
351 | |
352 // Returns the current certificate chain as a vector of DER-encoded | |
353 // base::StringPieces. The returned vector remains valid until Reset is | |
354 // called. | |
355 std::vector<base::StringPiece> AsStringPieceVector() const { | |
356 return der_certs_chain_; | |
357 } | |
358 | |
359 bool empty() const { return x509_certs_.empty(); } | |
360 size_t size() const { return x509_certs_.size(); } | |
361 | |
362 X509* operator[](size_t index) const { | |
363 DCHECK_LT(index, x509_certs_.size()); | |
364 return x509_certs_[index].get(); | |
365 } | |
366 | |
367 private: | |
368 struct OpenSSLFreeDeleter { | |
369 inline void operator()(void* ptr) const { OPENSSL_free(ptr); } | |
370 }; | |
371 | |
372 struct X509Deleter { | |
373 inline void operator()(X509* ptr) const { X509_free(ptr); } | |
374 }; | |
375 | |
376 typedef scoped_ptr<unsigned char, OpenSSLFreeDeleter> ScopedOpenSSLArray; | |
377 typedef scoped_ptr<X509, X509Deleter> ScopedX509; | |
378 | |
379 bool AddCert(X509* cert) { | |
380 unsigned char* cert_data = NULL; | |
381 int cert_data_length = i2d_X509(cert, &cert_data); | |
382 if (cert_data_length <= 0 || !cert_data) | |
383 return false; | |
384 | |
385 der_certs_mem_handler_.push_back(ScopedOpenSSLArray(cert_data)); | |
386 der_certs_chain_.push_back(base::StringPiece( | |
387 reinterpret_cast<char*>(cert_data), cert_data_length)); | |
388 | |
389 x509_certs_.push_back(ScopedX509(cert)); | |
390 // Increase reference count for cert | |
391 CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); | |
392 | |
393 return true; | |
394 } | |
395 | |
396 std::vector<base::StringPiece> der_certs_chain_; | |
397 | |
398 // Make sure the DER data strings are free'd with OPENSSL_free | |
399 std::vector<PeerCertificateChain::ScopedOpenSSLArray> der_certs_mem_handler_; | |
400 | |
401 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.
| |
402 }; | |
403 | |
322 // static | 404 // static |
323 SSLSessionCacheOpenSSL::Config | 405 SSLSessionCacheOpenSSL::Config |
324 SSLClientSocketOpenSSL::SSLContext::kDefaultSessionCacheConfig = { | 406 SSLClientSocketOpenSSL::SSLContext::kDefaultSessionCacheConfig = { |
325 &GetSessionCacheKey, // key_func | 407 &GetSessionCacheKey, // key_func |
326 1024, // max_entries | 408 1024, // max_entries |
327 256, // expiration_check_count | 409 256, // expiration_check_count |
328 60 * 60, // timeout_seconds | 410 60 * 60, // timeout_seconds |
329 }; | 411 }; |
330 | 412 |
331 // static | 413 // static |
332 void SSLClientSocket::ClearSessionCache() { | 414 void SSLClientSocket::ClearSessionCache() { |
333 SSLClientSocketOpenSSL::SSLContext* context = | 415 SSLClientSocketOpenSSL::SSLContext* context = |
334 SSLClientSocketOpenSSL::SSLContext::GetInstance(); | 416 SSLClientSocketOpenSSL::SSLContext::GetInstance(); |
335 context->session_cache()->Flush(); | 417 context->session_cache()->Flush(); |
336 OpenSSLClientKeyStore::GetInstance()->Flush(); | 418 OpenSSLClientKeyStore::GetInstance()->Flush(); |
337 } | 419 } |
338 | 420 |
339 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( | 421 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( |
340 scoped_ptr<ClientSocketHandle> transport_socket, | 422 scoped_ptr<ClientSocketHandle> transport_socket, |
341 const HostPortPair& host_and_port, | 423 const HostPortPair& host_and_port, |
342 const SSLConfig& ssl_config, | 424 const SSLConfig& ssl_config, |
343 const SSLClientSocketContext& context) | 425 const SSLClientSocketContext& context) |
344 : transport_send_busy_(false), | 426 : transport_send_busy_(false), |
345 transport_recv_busy_(false), | 427 transport_recv_busy_(false), |
346 transport_recv_eof_(false), | 428 transport_recv_eof_(false), |
347 weak_factory_(this), | 429 weak_factory_(this), |
348 pending_read_error_(kNoPendingReadResult), | 430 pending_read_error_(kNoPendingReadResult), |
349 transport_write_error_(OK), | 431 transport_write_error_(OK), |
432 server_cert_chain_(new PeerCertificateChain()), | |
433 server_cert_(NULL), | |
350 completed_handshake_(false), | 434 completed_handshake_(false), |
351 client_auth_cert_needed_(false), | 435 client_auth_cert_needed_(false), |
352 cert_verifier_(context.cert_verifier), | 436 cert_verifier_(context.cert_verifier), |
353 server_bound_cert_service_(context.server_bound_cert_service), | 437 server_bound_cert_service_(context.server_bound_cert_service), |
354 ssl_(NULL), | 438 ssl_(NULL), |
355 transport_bio_(NULL), | 439 transport_bio_(NULL), |
356 transport_(transport_socket.Pass()), | 440 transport_(transport_socket.Pass()), |
357 host_and_port_(host_and_port), | 441 host_and_port_(host_and_port), |
358 ssl_config_(ssl_config), | 442 ssl_config_(ssl_config), |
359 ssl_session_cache_shard_(context.ssl_session_cache_shard), | 443 ssl_session_cache_shard_(context.ssl_session_cache_shard), |
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
910 | 994 |
911 void SSLClientSocketOpenSSL::DoConnectCallback(int rv) { | 995 void SSLClientSocketOpenSSL::DoConnectCallback(int rv) { |
912 if (!user_connect_callback_.is_null()) { | 996 if (!user_connect_callback_.is_null()) { |
913 CompletionCallback c = user_connect_callback_; | 997 CompletionCallback c = user_connect_callback_; |
914 user_connect_callback_.Reset(); | 998 user_connect_callback_.Reset(); |
915 c.Run(rv > OK ? OK : rv); | 999 c.Run(rv > OK ? OK : rv); |
916 } | 1000 } |
917 } | 1001 } |
918 | 1002 |
919 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { | 1003 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { |
920 if (server_cert_.get()) | 1004 #ifdef USE_OPENSSL |
921 return server_cert_.get(); | |
922 | |
923 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
| |
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 | 1005 // 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. | 1006 // increment the reference so sk_X509_free does not need to be called. |
931 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_); | 1007 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_); |
932 X509Certificate::OSCertHandles intermediates; | 1008 X509Certificate::OSCertHandles intermediates; |
933 if (chain) { | 1009 if (chain) { |
934 for (int i = 0; i < sk_X509_num(chain); ++i) | 1010 for (int i = 1; i < sk_X509_num(chain); ++i) |
935 intermediates.push_back(sk_X509_value(chain, i)); | 1011 intermediates.push_back(sk_X509_value(chain, i)); |
936 } | 1012 } |
937 server_cert_ = X509Certificate::CreateFromHandle(cert.get(), intermediates); | 1013 server_cert_ = |
938 DCHECK(server_cert_.get()); | 1014 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.
| |
1015 #else | |
1016 server_cert_chain_->Reset(ssl_); | |
1017 server_cert_ = X509Certificate::CreateFromDERCertChain( | |
1018 server_cert_chain_->AsStringPieceVector()); | |
1019 #endif | |
939 | 1020 |
940 return server_cert_.get(); | 1021 return server_cert_.get(); |
941 } | 1022 } |
942 | 1023 |
943 void SSLClientSocketOpenSSL::OnHandshakeIOComplete(int result) { | 1024 void SSLClientSocketOpenSSL::OnHandshakeIOComplete(int result) { |
944 int rv = DoHandshakeLoop(result); | 1025 int rv = DoHandshakeLoop(result); |
945 if (rv != ERR_IO_PENDING) { | 1026 if (rv != ERR_IO_PENDING) { |
946 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); | 1027 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); |
947 DoConnectCallback(rv); | 1028 DoConnectCallback(rv); |
948 } | 1029 } |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1418 } | 1499 } |
1419 | 1500 |
1420 npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen); | 1501 npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen); |
1421 server_protos_.assign(reinterpret_cast<const char*>(in), inlen); | 1502 server_protos_.assign(reinterpret_cast<const char*>(in), inlen); |
1422 DVLOG(2) << "next protocol: '" << npn_proto_ << "' status: " << npn_status_; | 1503 DVLOG(2) << "next protocol: '" << npn_proto_ << "' status: " << npn_status_; |
1423 #endif | 1504 #endif |
1424 return SSL_TLSEXT_ERR_OK; | 1505 return SSL_TLSEXT_ERR_OK; |
1425 } | 1506 } |
1426 | 1507 |
1427 } // namespace net | 1508 } // namespace net |
OLD | NEW |