summaryrefslogtreecommitdiffstats
path: root/net/socket/ssl_client_socket_nss.cc
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 16:30:19 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 16:30:19 +0000
commitd0672be51d1a4c25f3dd7d91f9d9c1293b33adc6 (patch)
tree93a2a7f1b8d3426a4e65692b56e12e4011b60241 /net/socket/ssl_client_socket_nss.cc
parenta5e842bf6fda331cdacf3a8d56da19a3ea8d3d0b (diff)
downloadchromium_src-d0672be51d1a4c25f3dd7d91f9d9c1293b33adc6.zip
chromium_src-d0672be51d1a4c25f3dd7d91f9d9c1293b33adc6.tar.gz
chromium_src-d0672be51d1a4c25f3dd7d91f9d9c1293b33adc6.tar.bz2
net: move SSL host info serialisation into SSLHostInfo
This is a prelude to SSLHostInfo being able to kick off certificate validation based on predicted certificates. In order for that to happen, SSLHostInfo has to be able to parse the contents of the saved data, therefore the serialisation/deserialisation is moved into SSLHostInfo and we use a protocol buffer to clean things up. TEST=net_unittests BUG=none Review URL: http://codereview.chromium.org/3915001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63221 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket/ssl_client_socket_nss.cc')
-rw-r--r--net/socket/ssl_client_socket_nss.cc193
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_)