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 |