Index: net/socket/ssl_client_socket_nss.cc |
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc |
index 60f03240ab9e07f0496a1ffd71a6ec0c5cab599a..554d8d7119bfa733fde7d3031f66217d4359919c 100644 |
--- a/net/socket/ssl_client_socket_nss.cc |
+++ b/net/socket/ssl_client_socket_nss.cc |
@@ -93,6 +93,7 @@ |
#include "net/cert/asn1_util.h" |
#include "net/cert/cert_status_flags.h" |
#include "net/cert/cert_verifier.h" |
+#include "net/cert/ct_verifier.h" |
#include "net/cert/single_request_cert_verifier.h" |
#include "net/cert/x509_certificate_net_log_param.h" |
#include "net/cert/x509_util.h" |
@@ -2751,6 +2752,7 @@ SSLClientSocketNSS::SSLClientSocketNSS( |
nss_fd_(NULL), |
net_log_(transport_->socket()->NetLog()), |
transport_security_state_(context.transport_security_state), |
+ cert_transparency_verifier_(context.cert_transparency_verifier), |
valid_thread_id_(base::kInvalidThreadId) { |
EnterFunction(""); |
InitCore(); |
@@ -3271,6 +3273,12 @@ int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) { |
case STATE_VERIFY_CERT_COMPLETE: |
rv = DoVerifyCertComplete(rv); |
break; |
+ case STATE_VERIFY_CT: |
+ rv = DoVerifyCT(rv); |
+ break; |
+ case STATE_VERIFY_CT_COMPLETE: |
+ rv = DoVerifyCTComplete(rv); |
+ break; |
case STATE_NONE: |
default: |
rv = ERR_UNEXPECTED; |
@@ -3307,7 +3315,6 @@ int SSLClientSocketNSS::DoHandshakeComplete(int result) { |
return result; |
} |
- |
int SSLClientSocketNSS::DoVerifyCert(int result) { |
DCHECK(!core_->state().server_cert_chain.empty()); |
DCHECK(core_->state().server_cert_chain[0]); |
@@ -3391,8 +3398,6 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) { |
if (result == OK) |
LogConnectionTypeMetrics(); |
- completed_handshake_ = true; |
- |
#if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID) && !defined(OS_IOS) |
// Take care of any mandates for public key pinning. |
// |
@@ -3440,11 +3445,72 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) { |
} |
#endif |
+ if (result == OK) { |
+ // Only check Certificate Transparency if there were no other errors with |
+ // the connection. |
+ GotoState(STATE_VERIFY_CT); |
+ return OK; |
+ } |
+ |
+ completed_handshake_ = true; |
+ |
// Exit DoHandshakeLoop and return the result to the caller to Connect. |
DCHECK_EQ(STATE_NONE, next_handshake_state_); |
return result; |
} |
+int SSLClientSocketNSS::DoVerifyCT(int result) { |
+ GotoState(STATE_VERIFY_CT_COMPLETE); |
+ |
+ if (!cert_transparency_verifier_) |
+ return OK; |
+ |
+ // XXX(rsleevi): Not actually async-safe (using base::Unretained and giving |
+ // the raw pointer up). Need to use WeakPtr<> so that this can be cancelled, |
+ // but without requiring the opaque request handles of CertVerifier. |
+ return cert_transparency_verifier_->Verify( |
+ core_->state().server_cert, |
+ server_cert_verify_result_.verified_cert, |
+ &ct_verify_result_, |
+ base::Bind(&SSLClientSocketNSS::OnHandshakeIOComplete, |
+ base::Unretained(this)), |
+ net_log_); |
+} |
+ |
+int SSLClientSocketNSS::DoVerifyCTComplete(int result) { |
+ VLOG(1) << "CT Verification complete: result " << result << |
+ " Unverified scts: " << ct_verify_result_.unverified_scts.size() << |
+ " Verified scts: " << ct_verify_result_.verified_scts.size() << |
+ " scts from unknown logs: " << |
+ ct_verify_result_.unknown_logs_scts.size(); |
+ if (ct_verify_result_.unverified_scts.empty() && |
+ ct_verify_result_.unknown_logs_scts.empty() && |
+ ct_verify_result_.verified_scts.empty()) { |
+ return OK; |
+ } |
+ |
+ // XXX(eranm): Saving CT state in cert_status bits is a temporary solution, |
+ // until the SCTs themselves are threaded into the SSLInfo (as well as into |
+ // the HTTP cache). Using a status flag is a cheap way to persist the |
+ // SCT status. |
+ server_cert_verify_result_.cert_status |= CERT_STATUS_HAS_ANY_SCT; |
+ |
+ if (!ct_verify_result_.verified_scts.empty() && result == OK) { |
+ // Found some valid SCTs - good |
+ server_cert_verify_result_.cert_status |= |
+ CERT_STATUS_HAS_VALID_SCT | CERT_STATUS_HAS_SCT_FROM_KNOWN_LOG; |
+ } else if (!ct_verify_result_.unverified_scts.empty()) { |
+ server_cert_verify_result_.cert_status |= |
+ CERT_STATUS_HAS_SCT_FROM_KNOWN_LOG; |
+ } |
+ |
+ completed_handshake_ = true; |
+ |
+ DCHECK_EQ(STATE_NONE, next_handshake_state_); |
+ |
+ return OK; |
+} |
+ |
void SSLClientSocketNSS::LogConnectionTypeMetrics() const { |
UpdateConnectionTypeHistograms(CONNECTION_SSL); |
int ssl_version = SSLConnectionStatusToVersion( |