diff options
Diffstat (limited to 'net/socket/ssl_client_socket_nss.cc')
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 193 |
1 files changed, 39 insertions, 154 deletions
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_) |