| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/crypto/proof_verifier_chromium.h" | 5 #include "net/quic/crypto/proof_verifier_chromium.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/metrics/histogram.h" |
| 12 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 13 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
| 14 #include "crypto/signature_verifier.h" | 15 #include "crypto/signature_verifier.h" |
| 15 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
| 16 #include "net/base/net_log.h" | 17 #include "net/base/net_log.h" |
| 17 #include "net/cert/asn1_util.h" | 18 #include "net/cert/asn1_util.h" |
| 18 #include "net/cert/cert_status_flags.h" | 19 #include "net/cert/cert_status_flags.h" |
| 19 #include "net/cert/cert_verifier.h" | 20 #include "net/cert/cert_verifier.h" |
| 20 #include "net/cert/cert_verify_result.h" | 21 #include "net/cert/cert_verify_result.h" |
| 21 #include "net/cert/single_request_cert_verifier.h" | 22 #include "net/cert/single_request_cert_verifier.h" |
| 22 #include "net/cert/x509_certificate.h" | 23 #include "net/cert/x509_certificate.h" |
| 23 #include "net/cert/x509_util.h" | 24 #include "net/cert/x509_util.h" |
| 25 #include "net/http/transport_security_state.h" |
| 24 #include "net/quic/crypto/crypto_protocol.h" | 26 #include "net/quic/crypto/crypto_protocol.h" |
| 25 #include "net/ssl/ssl_config_service.h" | 27 #include "net/ssl/ssl_config_service.h" |
| 26 | 28 |
| 27 using base::StringPiece; | 29 using base::StringPiece; |
| 28 using base::StringPrintf; | 30 using base::StringPrintf; |
| 29 using std::string; | 31 using std::string; |
| 30 using std::vector; | 32 using std::vector; |
| 31 | 33 |
| 32 namespace net { | 34 namespace net { |
| 33 | 35 |
| 34 ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const { | 36 ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const { |
| 35 ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium; | 37 ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium; |
| 36 other->cert_verify_result = cert_verify_result; | 38 other->cert_verify_result = cert_verify_result; |
| 37 return other; | 39 return other; |
| 38 } | 40 } |
| 39 | 41 |
| 40 // A Job handles the verification of a single proof. It is owned by the | 42 // A Job handles the verification of a single proof. It is owned by the |
| 41 // ProofVerifier. If the verification can not complete synchronously, it | 43 // ProofVerifier. If the verification can not complete synchronously, it |
| 42 // will notify the ProofVerifier upon completion. | 44 // will notify the ProofVerifier upon completion. |
| 43 class ProofVerifierChromium::Job { | 45 class ProofVerifierChromium::Job { |
| 44 public: | 46 public: |
| 45 Job(ProofVerifierChromium* proof_verifier, | 47 Job(ProofVerifierChromium* proof_verifier, |
| 46 CertVerifier* cert_verifier, | 48 CertVerifier* cert_verifier, |
| 49 TransportSecurityState* transport_security_state, |
| 47 const BoundNetLog& net_log); | 50 const BoundNetLog& net_log); |
| 48 | 51 |
| 49 // Starts the proof verification. If |QUIC_PENDING| is returned, then | 52 // Starts the proof verification. If |QUIC_PENDING| is returned, then |
| 50 // |callback| will be invoked asynchronously when the verification completes. | 53 // |callback| will be invoked asynchronously when the verification completes. |
| 51 QuicAsyncStatus VerifyProof(const std::string& hostname, | 54 QuicAsyncStatus VerifyProof(const std::string& hostname, |
| 52 const std::string& server_config, | 55 const std::string& server_config, |
| 53 const std::vector<std::string>& certs, | 56 const std::vector<std::string>& certs, |
| 54 const std::string& signature, | 57 const std::string& signature, |
| 55 std::string* error_details, | 58 std::string* error_details, |
| 56 scoped_ptr<ProofVerifyDetails>* verify_details, | 59 scoped_ptr<ProofVerifyDetails>* verify_details, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 71 bool VerifySignature(const std::string& signed_data, | 74 bool VerifySignature(const std::string& signed_data, |
| 72 const std::string& signature, | 75 const std::string& signature, |
| 73 const std::string& cert); | 76 const std::string& cert); |
| 74 | 77 |
| 75 // Proof verifier to notify when this jobs completes. | 78 // Proof verifier to notify when this jobs completes. |
| 76 ProofVerifierChromium* proof_verifier_; | 79 ProofVerifierChromium* proof_verifier_; |
| 77 | 80 |
| 78 // The underlying verifier used for verifying certificates. | 81 // The underlying verifier used for verifying certificates. |
| 79 scoped_ptr<SingleRequestCertVerifier> verifier_; | 82 scoped_ptr<SingleRequestCertVerifier> verifier_; |
| 80 | 83 |
| 84 TransportSecurityState* transport_security_state_; |
| 85 |
| 81 // |hostname| specifies the hostname for which |certs| is a valid chain. | 86 // |hostname| specifies the hostname for which |certs| is a valid chain. |
| 82 std::string hostname_; | 87 std::string hostname_; |
| 83 | 88 |
| 84 scoped_ptr<ProofVerifierCallback> callback_; | 89 scoped_ptr<ProofVerifierCallback> callback_; |
| 85 scoped_ptr<ProofVerifyDetailsChromium> verify_details_; | 90 scoped_ptr<ProofVerifyDetailsChromium> verify_details_; |
| 86 std::string error_details_; | 91 std::string error_details_; |
| 87 | 92 |
| 88 // X509Certificate from a chain of DER encoded certificates. | 93 // X509Certificate from a chain of DER encoded certificates. |
| 89 scoped_refptr<X509Certificate> cert_; | 94 scoped_refptr<X509Certificate> cert_; |
| 90 | 95 |
| 91 State next_state_; | 96 State next_state_; |
| 92 | 97 |
| 93 BoundNetLog net_log_; | 98 BoundNetLog net_log_; |
| 94 | 99 |
| 95 DISALLOW_COPY_AND_ASSIGN(Job); | 100 DISALLOW_COPY_AND_ASSIGN(Job); |
| 96 }; | 101 }; |
| 97 | 102 |
| 98 ProofVerifierChromium::Job::Job(ProofVerifierChromium* proof_verifier, | 103 ProofVerifierChromium::Job::Job( |
| 99 CertVerifier* cert_verifier, | 104 ProofVerifierChromium* proof_verifier, |
| 100 const BoundNetLog& net_log) | 105 CertVerifier* cert_verifier, |
| 106 TransportSecurityState* transport_security_state, |
| 107 const BoundNetLog& net_log) |
| 101 : proof_verifier_(proof_verifier), | 108 : proof_verifier_(proof_verifier), |
| 102 verifier_(new SingleRequestCertVerifier(cert_verifier)), | 109 verifier_(new SingleRequestCertVerifier(cert_verifier)), |
| 110 transport_security_state_(transport_security_state), |
| 103 next_state_(STATE_NONE), | 111 next_state_(STATE_NONE), |
| 104 net_log_(net_log) { | 112 net_log_(net_log) { |
| 105 } | 113 } |
| 106 | 114 |
| 107 QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof( | 115 QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof( |
| 108 const string& hostname, | 116 const string& hostname, |
| 109 const string& server_config, | 117 const string& server_config, |
| 110 const vector<string>& certs, | 118 const vector<string>& certs, |
| 111 const string& signature, | 119 const string& signature, |
| 112 std::string* error_details, | 120 std::string* error_details, |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 SSLConfigService::GetCRLSet().get(), | 229 SSLConfigService::GetCRLSet().get(), |
| 222 &verify_details_->cert_verify_result, | 230 &verify_details_->cert_verify_result, |
| 223 base::Bind(&ProofVerifierChromium::Job::OnIOComplete, | 231 base::Bind(&ProofVerifierChromium::Job::OnIOComplete, |
| 224 base::Unretained(this)), | 232 base::Unretained(this)), |
| 225 net_log_); | 233 net_log_); |
| 226 } | 234 } |
| 227 | 235 |
| 228 int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) { | 236 int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) { |
| 229 verifier_.reset(); | 237 verifier_.reset(); |
| 230 | 238 |
| 239 #if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID) && !defined(OS_IOS) |
| 240 // TODO(wtc): The following code was copied from ssl_client_socket_nss.cc. |
| 241 // Convert it to a new function that can be called by both files. These |
| 242 // variables simulate the arguments to the new function. |
| 243 const CertVerifyResult& cert_verify_result = |
| 244 verify_details_->cert_verify_result; |
| 245 bool sni_available = true; |
| 246 const std::string& host = hostname_; |
| 247 TransportSecurityState* transport_security_state = transport_security_state_; |
| 248 std::string* pinning_failure_log = &verify_details_->pinning_failure_log; |
| 249 |
| 250 // Take care of any mandates for public key pinning. |
| 251 // |
| 252 // Pinning is only enabled for official builds to make sure that others don't |
| 253 // end up with pins that cannot be easily updated. |
| 254 // |
| 255 // TODO(agl): We might have an issue here where a request for foo.example.com |
| 256 // merges into a SPDY connection to www.example.com, and gets a different |
| 257 // certificate. |
| 258 |
| 259 // Perform pin validation if, and only if, all these conditions obtain: |
| 260 // |
| 261 // * a TransportSecurityState object is available; |
| 262 // * the server's certificate chain is valid (or suffers from only a minor |
| 263 // error); |
| 264 // * the server's certificate chain chains up to a known root (i.e. not a |
| 265 // user-installed trust anchor); and |
| 266 // * the build is recent (very old builds should fail open so that users |
| 267 // have some chance to recover). |
| 268 // |
| 269 const CertStatus cert_status = cert_verify_result.cert_status; |
| 270 if (transport_security_state && |
| 271 (result == OK || |
| 272 (IsCertificateError(result) && IsCertStatusMinorError(cert_status))) && |
| 273 cert_verify_result.is_issued_by_known_root && |
| 274 TransportSecurityState::IsBuildTimely()) { |
| 275 if (transport_security_state->HasPublicKeyPins(host, sni_available)) { |
| 276 if (!transport_security_state->CheckPublicKeyPins( |
| 277 host, |
| 278 sni_available, |
| 279 cert_verify_result.public_key_hashes, |
| 280 pinning_failure_log)) { |
| 281 LOG(ERROR) << *pinning_failure_log; |
| 282 result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN; |
| 283 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", false); |
| 284 TransportSecurityState::ReportUMAOnPinFailure(host); |
| 285 } else { |
| 286 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", true); |
| 287 } |
| 288 } |
| 289 } |
| 290 #endif |
| 291 |
| 231 if (result != OK) { | 292 if (result != OK) { |
| 232 error_details_ = StringPrintf("Failed to verify certificate chain: %s", | 293 error_details_ = StringPrintf("Failed to verify certificate chain: %s", |
| 233 ErrorToString(result)); | 294 ErrorToString(result)); |
| 234 DLOG(WARNING) << error_details_; | 295 DLOG(WARNING) << error_details_; |
| 235 } | 296 } |
| 236 | 297 |
| 237 // Exit DoLoop and return the result to the caller to VerifyProof. | 298 // Exit DoLoop and return the result to the caller to VerifyProof. |
| 238 DCHECK_EQ(STATE_NONE, next_state_); | 299 DCHECK_EQ(STATE_NONE, next_state_); |
| 239 return result; | 300 return result; |
| 240 } | 301 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 | 369 |
| 309 if (!verifier.VerifyFinal()) { | 370 if (!verifier.VerifyFinal()) { |
| 310 DLOG(WARNING) << "VerifyFinal failed"; | 371 DLOG(WARNING) << "VerifyFinal failed"; |
| 311 return false; | 372 return false; |
| 312 } | 373 } |
| 313 | 374 |
| 314 DVLOG(1) << "VerifyFinal success"; | 375 DVLOG(1) << "VerifyFinal success"; |
| 315 return true; | 376 return true; |
| 316 } | 377 } |
| 317 | 378 |
| 318 ProofVerifierChromium::ProofVerifierChromium(CertVerifier* cert_verifier) | 379 ProofVerifierChromium::ProofVerifierChromium( |
| 319 : cert_verifier_(cert_verifier) {} | 380 CertVerifier* cert_verifier, |
| 381 TransportSecurityState* transport_security_state) |
| 382 : cert_verifier_(cert_verifier), |
| 383 transport_security_state_(transport_security_state) { |
| 384 } |
| 320 | 385 |
| 321 ProofVerifierChromium::~ProofVerifierChromium() { | 386 ProofVerifierChromium::~ProofVerifierChromium() { |
| 322 STLDeleteElements(&active_jobs_); | 387 STLDeleteElements(&active_jobs_); |
| 323 } | 388 } |
| 324 | 389 |
| 325 QuicAsyncStatus ProofVerifierChromium::VerifyProof( | 390 QuicAsyncStatus ProofVerifierChromium::VerifyProof( |
| 326 const std::string& hostname, | 391 const std::string& hostname, |
| 327 const std::string& server_config, | 392 const std::string& server_config, |
| 328 const std::vector<std::string>& certs, | 393 const std::vector<std::string>& certs, |
| 329 const std::string& signature, | 394 const std::string& signature, |
| 330 const ProofVerifyContext* verify_context, | 395 const ProofVerifyContext* verify_context, |
| 331 std::string* error_details, | 396 std::string* error_details, |
| 332 scoped_ptr<ProofVerifyDetails>* verify_details, | 397 scoped_ptr<ProofVerifyDetails>* verify_details, |
| 333 ProofVerifierCallback* callback) { | 398 ProofVerifierCallback* callback) { |
| 334 if (!verify_context) { | 399 if (!verify_context) { |
| 335 *error_details = "Missing context"; | 400 *error_details = "Missing context"; |
| 336 return QUIC_FAILURE; | 401 return QUIC_FAILURE; |
| 337 } | 402 } |
| 338 const ProofVerifyContextChromium* chromium_context = | 403 const ProofVerifyContextChromium* chromium_context = |
| 339 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); | 404 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); |
| 340 scoped_ptr<Job> job(new Job(this, cert_verifier_, chromium_context->net_log)); | 405 scoped_ptr<Job> job(new Job(this, |
| 406 cert_verifier_, |
| 407 transport_security_state_, |
| 408 chromium_context->net_log)); |
| 341 QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs, | 409 QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs, |
| 342 signature, error_details, | 410 signature, error_details, |
| 343 verify_details, callback); | 411 verify_details, callback); |
| 344 if (status == QUIC_PENDING) { | 412 if (status == QUIC_PENDING) { |
| 345 active_jobs_.insert(job.release()); | 413 active_jobs_.insert(job.release()); |
| 346 } | 414 } |
| 347 return status; | 415 return status; |
| 348 } | 416 } |
| 349 | 417 |
| 350 void ProofVerifierChromium::OnJobComplete(Job* job) { | 418 void ProofVerifierChromium::OnJobComplete(Job* job) { |
| 351 active_jobs_.erase(job); | 419 active_jobs_.erase(job); |
| 352 delete job; | 420 delete job; |
| 353 } | 421 } |
| 354 | 422 |
| 355 } // namespace net | 423 } // namespace net |
| OLD | NEW |