Index: net/socket/ssl_client_socket_nss.cc |
=================================================================== |
--- net/socket/ssl_client_socket_nss.cc (revision 89911) |
+++ net/socket/ssl_client_socket_nss.cc (working copy) |
@@ -585,7 +585,11 @@ |
} |
} |
- GotoState(STATE_HANDSHAKE); |
+ if (ssl_config_.cached_info_enabled && ssl_host_info_.get()) { |
+ GotoState(STATE_LOAD_SSL_HOST_INFO); |
+ } else { |
+ GotoState(STATE_HANDSHAKE); |
+ } |
rv = DoHandshakeLoop(OK); |
if (rv == ERR_IO_PENDING) { |
@@ -916,11 +920,20 @@ |
#ifdef SSL_ENABLE_OCSP_STAPLING |
if (IsOCSPStaplingSupported()) { |
rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_OCSP_STAPLING, PR_TRUE); |
- if (rv != SECSuccess) |
- LogFailedNSSFunction(net_log_, "SSL_OptionSet (OCSP stapling)", ""); |
+ if (rv != SECSuccess) { |
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", |
+ "SSL_ENABLE_OCSP_STAPLING"); |
+ } |
} |
#endif |
+#ifdef SSL_ENABLE_CACHED_INFO |
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_CACHED_INFO, |
+ ssl_config_.cached_info_enabled); |
+ if (rv != SECSuccess) |
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_CACHED_INFO"); |
+#endif |
+ |
rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); |
if (rv != SECSuccess) { |
LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_CLIENT"); |
@@ -1202,6 +1215,9 @@ |
case STATE_NONE: |
// we're just pumping data between the buffer and the network |
break; |
+ case STATE_LOAD_SSL_HOST_INFO: |
+ rv = DoLoadSSLHostInfo(); |
+ break; |
case STATE_HANDSHAKE: |
rv = DoHandshake(); |
break; |
@@ -1283,6 +1299,57 @@ |
return rv; |
} |
+bool SSLClientSocketNSS::LoadSSLHostInfo() { |
+ const SSLHostInfo::State& state(ssl_host_info_->state()); |
+ |
+ if (state.certs.empty()) |
+ return false; |
+ |
+ SECStatus rv; |
+ 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*>(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 */); |
+ if (!certs[i]) { |
+ DestroyCertificates(&certs[0], i); |
+ NOTREACHED(); |
+ return false; |
+ } |
+ } |
+ |
+ rv = SSL_SetPredictedPeerCertificates(nss_fd_, certs.get(), certs_in.size()); |
+ DestroyCertificates(&certs[0], certs_in.size()); |
+ DCHECK_EQ(SECSuccess, rv); |
+ |
+ return true; |
+} |
+ |
+int SSLClientSocketNSS::DoLoadSSLHostInfo() { |
+ int rv; |
+ |
+ EnterFunction(""); |
+ rv = ssl_host_info_->WaitForDataReady(&handshake_io_callback_); |
+ GotoState(STATE_HANDSHAKE); |
+ |
+ if (rv == OK) { |
+ if (!LoadSSLHostInfo()) |
+ LOG(WARNING) << "LoadSSLHostInfo failed: " << host_and_port_.ToString(); |
+ } else { |
+ DCHECK_EQ(ERR_IO_PENDING, rv); |
+ GotoState(STATE_LOAD_SSL_HOST_INFO); |
+ } |
+ |
+ LeaveFunction(""); |
+ return rv; |
+} |
+ |
int SSLClientSocketNSS::DoHandshake() { |
EnterFunction(""); |
int net_error = net::OK; |
@@ -1307,7 +1374,8 @@ |
} else { |
// We need to see if the predicted certificate chain (in |
// |ssl_host_info_->state().certs) matches the actual certificate chain |
- // before we try to save it before we update |ssl_host_info_|. |
+ // before we call SaveSSLHostInfo, as that will update |
+ // |ssl_host_info_|. |
if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty()) { |
PeerCertificateChain certs(nss_fd_); |
const SSLHostInfo::State& state = ssl_host_info_->state(); |