diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/base/ssl_config_service.h | 1 | ||||
-rw-r--r-- | net/base/ssl_host_info.cc | 13 | ||||
-rw-r--r-- | net/http/disk_cache_based_ssl_host_info.cc | 12 | ||||
-rw-r--r-- | net/http/disk_cache_based_ssl_host_info.h | 5 | ||||
-rw-r--r-- | net/http/http_cache.cc | 2 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 1 | ||||
-rw-r--r-- | net/net.gyp | 42 | ||||
-rw-r--r-- | net/socket/client_socket_factory.cc | 2 | ||||
-rw-r--r-- | net/socket/client_socket_pool_base_unittest.cc | 1 | ||||
-rw-r--r-- | net/socket/socket_test_util.cc | 1 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_mac_factory.cc | 1 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 193 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.h | 2 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss_factory.cc | 1 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_pool.cc | 2 | ||||
-rw-r--r-- | net/socket/ssl_host_info.cc | 100 | ||||
-rw-r--r-- | net/socket/ssl_host_info.h (renamed from net/base/ssl_host_info.h) | 51 | ||||
-rw-r--r-- | net/socket/ssl_host_info.proto | 34 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_pool_unittest.cc | 1 |
19 files changed, 268 insertions, 197 deletions
diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h index dc48a36..0ab88b2 100644 --- a/net/base/ssl_config_service.h +++ b/net/base/ssl_config_service.h @@ -10,7 +10,6 @@ #include "base/observer_list.h" #include "base/ref_counted.h" -#include "net/base/ssl_host_info.h" #include "net/base/x509_certificate.h" namespace net { diff --git a/net/base/ssl_host_info.cc b/net/base/ssl_host_info.cc deleted file mode 100644 index 4b6c0e2..0000000 --- a/net/base/ssl_host_info.cc +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/base/ssl_host_info.h" - -namespace net { - -SSLHostInfo::~SSLHostInfo() {} - -SSLHostInfoFactory::~SSLHostInfoFactory() {} - -} // namespace net diff --git a/net/http/disk_cache_based_ssl_host_info.cc b/net/http/disk_cache_based_ssl_host_info.cc index f2de223..10b2e15 100644 --- a/net/http/disk_cache_based_ssl_host_info.cc +++ b/net/http/disk_cache_based_ssl_host_info.cc @@ -147,11 +147,12 @@ int DiskCacheBasedSSLHostInfo::WaitForDataReadyDone() { ready_ = true; callback = user_callback_; user_callback_ = NULL; - // We close the entry because, if we shutdown before ::Set is called, then we - // might leak a cache reference, which causes a DCHECK on shutdown. + // We close the entry because, if we shutdown before ::Persist is called, + // then we might leak a cache reference, which causes a DCHECK on shutdown. if (entry_) entry_->Close(); entry_ = NULL; + Parse(data_); if (callback) callback->Run(OK); @@ -172,17 +173,14 @@ int DiskCacheBasedSSLHostInfo::WaitForDataReady(CompletionCallback* callback) { return ERR_IO_PENDING; } -void DiskCacheBasedSSLHostInfo::Set(const std::string& new_data) { +void DiskCacheBasedSSLHostInfo::Persist() { DCHECK(CalledOnValidThread()); DCHECK(state_ != GET_BACKEND); - if (new_data.empty()) - return; - DCHECK(new_data_.empty()); CHECK(ready_); DCHECK(user_callback_ == NULL); - new_data_ = new_data; + new_data_ = Serialize(); if (!backend_) return; diff --git a/net/http/disk_cache_based_ssl_host_info.h b/net/http/disk_cache_based_ssl_host_info.h index 5cab8ff..51a4a91 100644 --- a/net/http/disk_cache_based_ssl_host_info.h +++ b/net/http/disk_cache_based_ssl_host_info.h @@ -11,8 +11,8 @@ #include "base/non_thread_safe.h" #include "base/scoped_ptr.h" #include "net/base/completion_callback.h" -#include "net/base/ssl_host_info.h" #include "net/disk_cache/disk_cache.h" +#include "net/socket/ssl_host_info.h" namespace net { @@ -30,8 +30,7 @@ class DiskCacheBasedSSLHostInfo : public SSLHostInfo, // Implementation of SSLHostInfo virtual void Start(); virtual int WaitForDataReady(CompletionCallback* callback); - virtual const std::string& data() const { return data_; } - virtual void Set(const std::string& new_data); + virtual void Persist(); private: ~DiskCacheBasedSSLHostInfo(); diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 153b5d5..eca95ef 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -24,7 +24,6 @@ #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" -#include "net/base/ssl_host_info.h" #include "net/disk_cache/disk_cache.h" #include "net/http/disk_cache_based_ssl_host_info.h" #include "net/http/http_cache_transaction.h" @@ -34,6 +33,7 @@ #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" #include "net/http/http_util.h" +#include "net/socket/ssl_host_info.h" #include "net/spdy/spdy_session_pool.h" namespace net { diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 0d9f340..e0b9c39 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -26,7 +26,6 @@ #include "net/base/net_util.h" #include "net/base/ssl_cert_request_info.h" #include "net/base/ssl_connection_status_flags.h" -#include "net/base/ssl_host_info.h" #include "net/base/upload_data_stream.h" #include "net/http/http_auth.h" #include "net/http/http_auth_handler.h" diff --git a/net/net.gyp b/net/net.gyp index e8a32c9..f0306b1 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -173,8 +173,6 @@ 'base/ssl_config_service_win.cc', 'base/ssl_config_service_win.h', 'base/ssl_false_start_blacklist.cc', - 'base/ssl_host_info.cc', - 'base/ssl_host_info.h', 'base/ssl_info.cc', 'base/ssl_info.h', 'base/static_cookie_policy.cc', @@ -324,6 +322,7 @@ '../third_party/zlib/zlib.gyp:zlib', 'net_base', 'net_resources', + 'ssl_host_info', ], 'sources': [ 'disk_cache/addr.cc', @@ -995,6 +994,45 @@ ], }, { + # This is a separate target in order to limit the scope of the protobuf + # includes. + 'target_name': 'ssl_host_info', + 'type': '<(library)', + 'dependencies': [ + '../base/base.gyp:base', + '../third_party/protobuf/protobuf.gyp:protobuf_lite', + ], + 'sources': [ + 'socket/ssl_host_info.proto', + 'socket/ssl_host_info.cc', + 'socket/ssl_host_info.h', + ], + 'rules': [ + { + 'rule_name': 'genproto', + 'extension': 'proto', + 'inputs': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/protoc_out/net/socket/<(RULE_INPUT_ROOT).pb.h', + '<(SHARED_INTERMEDIATE_DIR)/protoc_out/net/socket/<(RULE_INPUT_ROOT).pb.cc', + ], + 'action': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + 'socket/<(RULE_INPUT_ROOT)<(RULE_INPUT_EXT)', + '--cpp_out=<(SHARED_INTERMEDIATE_DIR)/protoc_out/net', + ], + 'message': 'Generating C++ code from <(RULE_INPUT_PATH)', + 'process_outputs_as_sources': 1, + }, + ], + 'include_dirs': [ + '<(SHARED_INTERMEDIATE_DIR)/protoc_out/net', + '<(SHARED_INTERMEDIATE_DIR)/protoc_out', + ], + }, + { 'target_name': 'net_perftests', 'type': 'executable', 'dependencies': [ diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc index a31af007..90bcdc5 100644 --- a/net/socket/client_socket_factory.cc +++ b/net/socket/client_socket_factory.cc @@ -6,7 +6,6 @@ #include "base/singleton.h" #include "build/build_config.h" -#include "net/base/ssl_host_info.h" #include "net/socket/client_socket_handle.h" #if defined(OS_WIN) #include "net/socket/ssl_client_socket_win.h" @@ -18,6 +17,7 @@ #include "net/socket/ssl_client_socket_mac.h" #include "net/socket/ssl_client_socket_nss.h" #endif +#include "net/socket/ssl_host_info.h" #include "net/socket/tcp_client_socket.h" namespace net { diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc index 1f99b3d..820b030 100644 --- a/net/socket/client_socket_pool_base_unittest.cc +++ b/net/socket/client_socket_pool_base_unittest.cc @@ -23,6 +23,7 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket_test_util.h" +#include "net/socket/ssl_host_info.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 9854cc5..53bcf89 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -21,6 +21,7 @@ #include "net/http/http_response_headers.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket.h" +#include "net/socket/ssl_host_info.h" #include "testing/gtest/include/gtest/gtest.h" #define NET_TRACE(level, s) DLOG(level) << s << __FUNCTION__ << "() " diff --git a/net/socket/ssl_client_socket_mac_factory.cc b/net/socket/ssl_client_socket_mac_factory.cc index bc26261..7f0c5ce 100644 --- a/net/socket/ssl_client_socket_mac_factory.cc +++ b/net/socket/ssl_client_socket_mac_factory.cc @@ -5,6 +5,7 @@ #include "net/socket/client_socket_factory.h" #include "net/socket/ssl_client_socket_mac.h" +#include "net/socket/ssl_host_info.h" namespace net { diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 95458fa..136f138 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -83,11 +83,11 @@ #include "net/base/net_log.h" #include "net/base/ssl_cert_request_info.h" #include "net/base/ssl_connection_status_flags.h" -#include "net/base/ssl_host_info.h" #include "net/base/ssl_info.h" #include "net/base/sys_addrinfo.h" #include "net/ocsp/nss_ocsp.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/ssl_host_info.h" static const int kRecvBufferSize = 4096; @@ -461,15 +461,9 @@ int SSLClientSocketNSS::Init() { return OK; } -// This is a version number of the Snap Start information saved by -// |SaveSnapStartInfo| and loaded by |LoadSnapStartInfo|. Since the information -// can be saved on disk we might have version skew in the future. Any data with -// a different version is ignored by |LoadSnapStartInfo|. -static const uint8 kSnapStartInfoVersion = 0; - -// SaveSnapStartInfo serialises the information needed to perform a Snap Start -// with this server in the future (if any) and tells -// |ssl_host_info_| to preserve it. +// SaveSnapStartInfo extracts the information needed to perform a Snap Start +// with this server in the future (if any) and tells |ssl_host_info_| to +// preserve it. void SSLClientSocketNSS::SaveSnapStartInfo() { if (!ssl_host_info_.get()) return; @@ -501,32 +495,12 @@ void SSLClientSocketNSS::SaveSnapStartInfo() { return; if (hello_data_len > std::numeric_limits<uint16>::max()) return; + SSLHostInfo::State* state = ssl_host_info_->mutable_state(); + state->server_hello = + std::string(reinterpret_cast<const char *>(hello_data), hello_data_len); - // The format of the saved info looks like: - // struct Cert { - // uint16 length - // opaque certificate[length]; - // } - // - // uint8 version (kSnapStartInfoVersion) - // uint8 npn_status - // uint8 npn_proto_len - // uint8 npn_proto[npn_proto_len] - // uint16 hello_data_len - // opaque hello_data[hello_data_len] - // uint8 num_certs; - // Cert[num_certs]; - - std::string npn_proto; - NextProtoStatus npn_status = GetNextProto(&npn_proto); - - unsigned num_certs = 0; - unsigned len = 3; - DCHECK_LT(npn_proto.size(), 256u); - len += npn_proto.size(); - len += 2; // for hello_data_len - len += hello_data_len; - len++; // for |num_certs| + state->npn_valid = true; + state->npn_status = GetNextProto(&state->npn_protocol); // TODO(wtc): CERT_GetCertChainFromCert might not return the same cert chain // that the Certificate message actually contained. http://crbug.com/48854 @@ -535,67 +509,22 @@ void SSLClientSocketNSS::SaveSnapStartInfo() { if (!cert_list) return; - unsigned last_cert_len = 0; - bool last_cert_is_root = false; for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) { - num_certs++; if (node->cert->derCert.len > std::numeric_limits<uint16>::max()) { CERT_DestroyCertList(cert_list); return; } - last_cert_len = node->cert->derCert.len; - len += 2 + last_cert_len; - last_cert_is_root = node->cert->isRoot == PR_TRUE; - } - - if (num_certs == 0 || num_certs > std::numeric_limits<uint8>::max()) { - CERT_DestroyCertList(cert_list); - return; - } - - if (num_certs > 1 && last_cert_is_root) { - // The cert list included the root certificate, which we don't want to - // save. (Since we need to predict the server's certificates we don't want - // to predict the root cert because the server won't send it to us. We - // could implement this logic either here, or in the code which loads the - // certificates. But, by doing it here, we save a little disk space). - // - // Note that, when the TODO above (http://crbug.com/48854) is handled, this - // point will be moot. - len -= 2 + last_cert_len; - num_certs--; - } - - std::vector<uint8> data(len); - unsigned j = 0; - data[j++] = kSnapStartInfoVersion; - data[j++] = static_cast<uint8>(npn_status); - data[j++] = static_cast<uint8>(npn_proto.size()); - memcpy(&data[j], npn_proto.data(), npn_proto.size()); - j += npn_proto.size(); - data[j++] = hello_data_len >> 8; - data[j++] = hello_data_len; - memcpy(&data[j], hello_data, hello_data_len); - j += hello_data_len; - data[j++] = num_certs; - - unsigned i = 0; - for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); - i < num_certs; - node = CERT_LIST_NEXT(node), i++) { - data[j++] = node->cert->derCert.len >> 8; - data[j++] = node->cert->derCert.len; - memcpy(&data[j], node->cert->derCert.data, node->cert->derCert.len); - j += node->cert->derCert.len; + if (node->cert->isRoot == PR_TRUE) + continue; + state->certs.push_back(std::string( + reinterpret_cast<char*>(node->cert->derCert.data), + node->cert->derCert.len)); } - DCHECK_EQ(j, len); - - LOG(ERROR) << "Setting Snap Start info " << hostname_ << " " << len; - ssl_host_info_->Set(std::string( - reinterpret_cast<const char *>(&data[0]), len)); + LOG(ERROR) << "Setting Snap Start info " << hostname_; + ssl_host_info_->Persist(); CERT_DestroyCertList(cert_list); } @@ -609,69 +538,29 @@ static void DestroyCertificates(CERTCertificate** certs, unsigned len) { // by |SaveSnapStartInfo|, and sets the predicted certificates and ServerHello // data on the NSS socket. Returns true on success. If this function returns // false, the caller should try a normal TLS handshake. -bool SSLClientSocketNSS::LoadSnapStartInfo(const std::string& info) { - const unsigned char* data = - reinterpret_cast<const unsigned char*>(info.data()); - SECStatus rv; - - // See the comment in |SaveSnapStartInfo| for the format of the data. - if (info.size() < 3 || - data[0] != kSnapStartInfoVersion) { - return false; - } +bool SSLClientSocketNSS::LoadSnapStartInfo() { + const SSLHostInfo::State& state(ssl_host_info_->state()); - unsigned j = 1; - const uint8 npn_status = data[j++]; - const uint8 npn_proto_len = data[j++]; - if (static_cast<unsigned>(npn_proto_len) + j > info.size()) { - NOTREACHED(); + if (state.server_hello.empty() || + state.certs.empty() || + !state.npn_valid) { return false; } - const std::string npn_proto(info.substr(j, npn_proto_len)); - j += npn_proto_len; - if (j + 2 > info.size()) { - NOTREACHED(); - return false; - } - uint16 hello_data_len = static_cast<uint16>(data[j]) << 8 | - static_cast<uint16>(data[j+1]); - j += 2; - if (static_cast<unsigned>(hello_data_len) + j > info.size()) { - NOTREACHED(); - return false; - } - - rv = SSL_SetPredictedServerHelloData(nss_fd_, &data[j], hello_data_len); + SECStatus rv; + rv = SSL_SetPredictedServerHelloData( + nss_fd_, + reinterpret_cast<const uint8*>(state.server_hello.data()), + state.server_hello.size()); DCHECK_EQ(SECSuccess, rv); - j += hello_data_len; - - if (j + 1 > info.size()) { - NOTREACHED(); - return false; - } - unsigned num_certs = data[j++]; - scoped_array<CERTCertificate*> certs(new CERTCertificate*[num_certs]); - for (unsigned i = 0; i < num_certs; i++) { - if (j + 2 > info.size()) { - DestroyCertificates(&certs[0], i); - NOTREACHED(); - // It's harmless to call only SSL_SetPredictedServerHelloData. - return false; - } - uint16 cert_len = static_cast<uint16>(data[j]) << 8 | - static_cast<uint16>(data[j+1]); - j += 2; - if (static_cast<unsigned>(cert_len) + j > info.size()) { - DestroyCertificates(&certs[0], i); - NOTREACHED(); - return false; - } + const std::vector<std::string>& certs_in = state.certs; + scoped_array<CERTCertificate*> certs(new CERTCertificate*[certs_in.size()]); + for (size_t i = 0; i < certs_in.size(); i++) { SECItem derCert; - derCert.data = const_cast<uint8*>(data + j); - derCert.len = cert_len; - j += cert_len; + derCert.data = + const_cast<uint8*>(reinterpret_cast<const uint8*>(certs_in[i].data())); + derCert.len = certs_in[i].size(); certs[i] = CERT_NewTempCertificate( CERT_GetDefaultCertDB(), &derCert, NULL /* no nickname given */, PR_FALSE /* not permanent */, PR_TRUE /* copy DER data */); @@ -682,16 +571,14 @@ bool SSLClientSocketNSS::LoadSnapStartInfo(const std::string& info) { } } - rv = SSL_SetPredictedPeerCertificates(nss_fd_, certs.get(), num_certs); - DestroyCertificates(&certs[0], num_certs); + rv = SSL_SetPredictedPeerCertificates(nss_fd_, certs.get(), certs_in.size()); + DestroyCertificates(&certs[0], certs_in.size()); DCHECK_EQ(SECSuccess, rv); - predicted_npn_status_ = static_cast<NextProtoStatus>(npn_status); - predicted_npn_proto_ = npn_proto; - - // We ignore any trailing data that might be in |info|. - if (j != info.size()) - LOG(WARNING) << "Trailing data found in SSLHostInfo"; + if (state.npn_valid) { + predicted_npn_status_ = state.npn_status; + predicted_npn_proto_ = state.npn_protocol; + } return true; } @@ -1974,9 +1861,7 @@ int SSLClientSocketNSS::DoSnapStartLoadInfo() { int rv = ssl_host_info_->WaitForDataReady(&handshake_io_callback_); if (rv == OK) { - LOG(ERROR) << "SSL host info size " << hostname_ << " " - << ssl_host_info_->data().size(); - if (LoadSnapStartInfo(ssl_host_info_->data())) { + if (LoadSnapStartInfo()) { pseudo_connected_ = true; GotoState(STATE_SNAP_START_WAIT_FOR_WRITE); if (user_connect_callback_) diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index 8518084..56d16b2 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -103,7 +103,7 @@ class SSLClientSocketNSS : public SSLClientSocket { int DoPayloadWrite(); int Init(); void SaveSnapStartInfo(); - bool LoadSnapStartInfo(const std::string& info); + bool LoadSnapStartInfo(); bool IsNPNProtocolMispredicted(); void UncorkAfterTimeout(); diff --git a/net/socket/ssl_client_socket_nss_factory.cc b/net/socket/ssl_client_socket_nss_factory.cc index b5488d9..efa6e23 100644 --- a/net/socket/ssl_client_socket_nss_factory.cc +++ b/net/socket/ssl_client_socket_nss_factory.cc @@ -6,6 +6,7 @@ #include "build/build_config.h" #include "net/socket/ssl_client_socket_nss.h" +#include "net/socket/ssl_host_info.h" #if defined(OS_WIN) #include "net/socket/ssl_client_socket_win.h" #endif diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index 048ff4b..98e3b09 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc @@ -8,13 +8,13 @@ #include "base/values.h" #include "net/base/net_errors.h" #include "net/base/ssl_cert_request_info.h" -#include "net/base/ssl_host_info.h" #include "net/http/http_proxy_client_socket.h" #include "net/http/http_proxy_client_socket_pool.h" #include "net/socket/client_socket_factory.h" #include "net/socket/client_socket_handle.h" #include "net/socket/socks_client_socket_pool.h" #include "net/socket/ssl_client_socket.h" +#include "net/socket/ssl_host_info.h" #include "net/socket/tcp_client_socket_pool.h" namespace net { diff --git a/net/socket/ssl_host_info.cc b/net/socket/ssl_host_info.cc new file mode 100644 index 0000000..4b5bb02 --- /dev/null +++ b/net/socket/ssl_host_info.cc @@ -0,0 +1,100 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/socket/ssl_host_info.h" + +#include "net/socket/ssl_client_socket.h" +#include "net/socket/ssl_host_info.pb.h" + +namespace net { + +SSLHostInfo::SSLHostInfo() { + state_.npn_valid = false; +} + +SSLHostInfo::~SSLHostInfo() {} + +// This array and the next two functions serve to map between the internal NPN +// status enum (which might change across versions) and the protocol buffer +// based enum (which will not). +static const struct { + SSLClientSocket::NextProtoStatus npn_status; + SSLHostInfoProto::NextProtoStatus proto_status; +} kNPNStatusMapping[] = { + { SSLClientSocket::kNextProtoUnsupported, SSLHostInfoProto::UNSUPPORTED }, + { SSLClientSocket::kNextProtoNegotiated, SSLHostInfoProto::NEGOTIATED }, + { SSLClientSocket::kNextProtoNoOverlap, SSLHostInfoProto::NO_OVERLAP }, +}; + +static SSLClientSocket::NextProtoStatus NPNStatusFromProtoStatus( + SSLHostInfoProto::NextProtoStatus proto_status) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNPNStatusMapping) - 1; i++) { + if (kNPNStatusMapping[i].proto_status == proto_status) + return kNPNStatusMapping[i].npn_status; + } + return kNPNStatusMapping[ARRAYSIZE_UNSAFE(kNPNStatusMapping) - 1].npn_status; +} + +static SSLHostInfoProto::NextProtoStatus ProtoStatusFromNPNStatus( + SSLClientSocket::NextProtoStatus npn_status) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNPNStatusMapping) - 1; i++) { + if (kNPNStatusMapping[i].npn_status == npn_status) + return kNPNStatusMapping[i].proto_status; + } + return kNPNStatusMapping[ARRAYSIZE_UNSAFE(kNPNStatusMapping)-1].proto_status; +} + +const SSLHostInfo::State& SSLHostInfo::state() const { + return state_; +} + +SSLHostInfo::State* SSLHostInfo::mutable_state() { + return &state_; +} + +bool SSLHostInfo::Parse(const std::string& data) { + SSLHostInfoProto proto; + State* state = mutable_state(); + + state->certs.clear(); + state->server_hello.clear(); + state->npn_valid = false; + + if (!proto.ParseFromString(data)) + return false; + + for (int i = 0; i < proto.certificate_der_size(); i++) + state->certs.push_back(proto.certificate_der(i)); + if (proto.has_server_hello()) + state->server_hello = proto.server_hello(); + if (proto.has_npn_status() && proto.has_npn_protocol()) { + state->npn_valid = true; + state->npn_status = NPNStatusFromProtoStatus(proto.npn_status()); + state->npn_protocol = proto.npn_protocol(); + } + + return true; +} + +std::string SSLHostInfo::Serialize() const { + SSLHostInfoProto proto; + + for (std::vector<std::string>::const_iterator + i = state_.certs.begin(); i != state_.certs.end(); i++) { + proto.add_certificate_der(*i); + } + if (!state_.server_hello.empty()) + proto.set_server_hello(state_.server_hello); + + if (state_.npn_valid) { + proto.set_npn_status(ProtoStatusFromNPNStatus(state_.npn_status)); + proto.set_npn_protocol(state_.npn_protocol); + } + + return proto.SerializeAsString(); +} + +SSLHostInfoFactory::~SSLHostInfoFactory() {} + +} // namespace net diff --git a/net/base/ssl_host_info.h b/net/socket/ssl_host_info.h index ae9ac6a..8065b47 100644 --- a/net/base/ssl_host_info.h +++ b/net/socket/ssl_host_info.h @@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_BASE_SSL_HOST_INFO_H -#define NET_BASE_SSL_HOST_INFO_H +#ifndef NET_SOCKET_SSL_HOST_INFO_H +#define NET_SOCKET_SSL_HOST_INFO_H #include <string> +#include <vector> + #include "base/ref_counted.h" #include "net/base/completion_callback.h" +#include "net/socket/ssl_client_socket.h" namespace net { @@ -17,6 +20,7 @@ namespace net { // certificates. class SSLHostInfo { public: + SSLHostInfo(); virtual ~SSLHostInfo(); // Start will commence the lookup. This must be called before any other @@ -36,16 +40,39 @@ class SSLHostInfo { // but, obviously, a callback will never be made. virtual int WaitForDataReady(CompletionCallback* callback) = 0; - // data returns any host information once WaitForDataReady has indicated that - // the fetch has completed. In the event of an error, |data| returns an empty - // string. - virtual const std::string& data() const = 0; + // Persist allows for the host information to be updated for future users. + // This is a fire and forget operation: the caller may drop its reference + // from this object and the store operation will still complete. This can + // only be called once WaitForDataReady has returned OK or called its + // callback. + virtual void Persist() = 0; + + struct State { + // certs is a vector of DER encoded X.509 certificates, as the server + // returned them and in the same order. + std::vector<std::string> certs; + // server_hello contains the bytes of the ServerHello message (or may be + // empty if the server doesn't support Snap Start.) + std::string server_hello; + // npn_valid is true iff |npn_status| and |npn_protocol| is successful. + bool npn_valid; + // these members contain the NPN result of a connection to the server. + SSLClientSocket::NextProtoStatus npn_status; + std::string npn_protocol; + }; + + // Once the data is ready, it can be read using the following members. These + // members can then be updated before calling |Persist|. + const State& state() const; + State* mutable_state(); - // Set allows for the host information to be updated for future users. This - // is a fire and forget operation: the caller may drop its reference from - // this object and the store operation will still complete. This can only be - // called once WaitForDataReady has returned OK or called its callback. - virtual void Set(const std::string& new_data) = 0; + protected: + // Parse parses an opaque blob of data and fills out the public member fields + // of this object. It returns true iff the parse was successful. The public + // member fields will be set to something sane in any case. + bool Parse(const std::string& data); + std::string Serialize() const; + State state_; }; class SSLHostInfoFactory { @@ -59,4 +86,4 @@ class SSLHostInfoFactory { } // namespace net -#endif // NET_BASE_SSL_HOST_INFO_H +#endif // NET_SOCKET_SSL_HOST_INFO_H diff --git a/net/socket/ssl_host_info.proto b/net/socket/ssl_host_info.proto new file mode 100644 index 0000000..d74a872 --- /dev/null +++ b/net/socket/ssl_host_info.proto @@ -0,0 +1,34 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package net; + +// SSLHostInfoProto contains information which we store about a given HTTPS +// server. +message SSLHostInfoProto { + // The certificate chain, as returned by the server, as a series of DER + // encoded X.509 certificates. + repeated bytes certificate_der = 1; + // The contents of the server's ServerHello message. Needed in order to + // predict its response in the case of Snap Start. + optional bytes server_hello = 2; + + // This is a mirror of SSLClientSocket::NextProtoStatus. We use this in order + // to be robust against changes to that enum, which isn't required to be + // stable across versions. See the comments there for details. + enum NextProtoStatus { + UNSUPPORTED = 0; + NEGOTIATED = 1; + NO_OVERLAP = 2; + } + + // When doing Snap Start, we also need to know what protocol we expect the + // server to negotiate. + optional NextProtoStatus npn_status = 3; + optional bytes npn_protocol = 4; +}; diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc index 32ac9f8..80de0aa 100644 --- a/net/socket/tcp_client_socket_pool_unittest.cc +++ b/net/socket/tcp_client_socket_pool_unittest.cc @@ -15,6 +15,7 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket_test_util.h" +#include "net/socket/ssl_host_info.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { |