diff options
author | Ben Murdoch <benm@google.com> | 2013-07-31 10:55:33 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2013-07-31 10:55:33 +0100 |
commit | d3868032626d59662ff73b372b5d584c1d144c53 (patch) | |
tree | b53968078879cdade155a2e869a58b2ec568a06d /net | |
parent | e5b4422c968a7a35d5d4fbae38f8786f61e98bc8 (diff) | |
download | chromium_org-d3868032626d59662ff73b372b5d584c1d144c53.tar.gz |
Merge from Chromium at DEPS revision r214391
This commit was generated by merge_to_master.py.
Change-Id: Iad15fada300ebc6cf9cbcebfc484b1a5f5f372e5
Diffstat (limited to 'net')
-rw-r--r-- | net/http/transport_security_state_static.h | 1 | ||||
-rw-r--r-- | net/http/transport_security_state_static.json | 1 | ||||
-rw-r--r-- | net/net.gyp | 1 | ||||
-rw-r--r-- | net/net.target.darwin-arm.mk | 1 | ||||
-rw-r--r-- | net/net.target.darwin-mips.mk | 1 | ||||
-rw-r--r-- | net/net.target.darwin-x86.mk | 1 | ||||
-rw-r--r-- | net/net.target.linux-arm.mk | 1 | ||||
-rw-r--r-- | net/net.target.linux-mips.mk | 1 | ||||
-rw-r--r-- | net/net.target.linux-x86.mk | 1 | ||||
-rw-r--r-- | net/quic/crypto/crypto_handshake.cc | 12 | ||||
-rw-r--r-- | net/quic/crypto/crypto_handshake.h | 12 | ||||
-rw-r--r-- | net/quic/crypto/proof_test.cc | 167 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier.cc | 15 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier.h | 68 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier_chromium.cc | 67 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier_chromium.h | 29 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream.cc | 93 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream.h | 51 | ||||
-rw-r--r-- | net/tools/quic/test_tools/quic_test_client.cc | 23 |
19 files changed, 352 insertions, 194 deletions
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h index 830974392f..cf43609ce8 100644 --- a/net/http/transport_security_state_static.h +++ b/net/http/transport_security_state_static.h @@ -831,6 +831,7 @@ static const struct HSTSPreload kPreloadedSTS[] = { {18, true, "\015rapidresearch\002me", true, kNoPins, DOMAIN_NOT_PINNED }, {14, true, "\010surkatty\003org", true, kNoPins, DOMAIN_NOT_PINNED }, {21, true, "\017securityheaders\003com", true, kNoPins, DOMAIN_NOT_PINNED }, + {10, true, "\005haste\002ch", true, kNoPins, DOMAIN_NOT_PINNED }, }; static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS); diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 4ca4aca448..e0528c499a 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json @@ -621,6 +621,7 @@ { "name": "rapidresearch.me", "include_subdomains": true, "mode": "force-https" }, { "name": "surkatty.org", "include_subdomains": true, "mode": "force-https" }, { "name": "securityheaders.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "haste.ch", "include_subdomains": true, "mode": "force-https" }, // Entries that are only valid if the client supports SNI. { "name": "gmail.com", "mode": "force-https", "pins": "google", "snionly": true }, diff --git a/net/net.gyp b/net/net.gyp index 657a772083..2a9d78aa66 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -762,6 +762,7 @@ 'quic/crypto/proof_source.h', 'quic/crypto/proof_source_chromium.cc', 'quic/crypto/proof_source_chromium.h', + 'quic/crypto/proof_verifier.cc', 'quic/crypto/proof_verifier_chromium.cc', 'quic/crypto/proof_verifier_chromium.h', 'quic/crypto/quic_decrypter.cc', diff --git a/net/net.target.darwin-arm.mk b/net/net.target.darwin-arm.mk index 0b2fee4157..0b23ed3479 100644 --- a/net/net.target.darwin-arm.mk +++ b/net/net.target.darwin-arm.mk @@ -298,6 +298,7 @@ LOCAL_SRC_FILES := \ net/quic/crypto/null_encrypter.cc \ net/quic/crypto/p256_key_exchange_openssl.cc \ net/quic/crypto/proof_source_chromium.cc \ + net/quic/crypto/proof_verifier.cc \ net/quic/crypto/proof_verifier_chromium.cc \ net/quic/crypto/quic_decrypter.cc \ net/quic/crypto/quic_encrypter.cc \ diff --git a/net/net.target.darwin-mips.mk b/net/net.target.darwin-mips.mk index d239f35241..85e56d53ed 100644 --- a/net/net.target.darwin-mips.mk +++ b/net/net.target.darwin-mips.mk @@ -298,6 +298,7 @@ LOCAL_SRC_FILES := \ net/quic/crypto/null_encrypter.cc \ net/quic/crypto/p256_key_exchange_openssl.cc \ net/quic/crypto/proof_source_chromium.cc \ + net/quic/crypto/proof_verifier.cc \ net/quic/crypto/proof_verifier_chromium.cc \ net/quic/crypto/quic_decrypter.cc \ net/quic/crypto/quic_encrypter.cc \ diff --git a/net/net.target.darwin-x86.mk b/net/net.target.darwin-x86.mk index 4deda275aa..b351009261 100644 --- a/net/net.target.darwin-x86.mk +++ b/net/net.target.darwin-x86.mk @@ -298,6 +298,7 @@ LOCAL_SRC_FILES := \ net/quic/crypto/null_encrypter.cc \ net/quic/crypto/p256_key_exchange_openssl.cc \ net/quic/crypto/proof_source_chromium.cc \ + net/quic/crypto/proof_verifier.cc \ net/quic/crypto/proof_verifier_chromium.cc \ net/quic/crypto/quic_decrypter.cc \ net/quic/crypto/quic_encrypter.cc \ diff --git a/net/net.target.linux-arm.mk b/net/net.target.linux-arm.mk index 0b2fee4157..0b23ed3479 100644 --- a/net/net.target.linux-arm.mk +++ b/net/net.target.linux-arm.mk @@ -298,6 +298,7 @@ LOCAL_SRC_FILES := \ net/quic/crypto/null_encrypter.cc \ net/quic/crypto/p256_key_exchange_openssl.cc \ net/quic/crypto/proof_source_chromium.cc \ + net/quic/crypto/proof_verifier.cc \ net/quic/crypto/proof_verifier_chromium.cc \ net/quic/crypto/quic_decrypter.cc \ net/quic/crypto/quic_encrypter.cc \ diff --git a/net/net.target.linux-mips.mk b/net/net.target.linux-mips.mk index d239f35241..85e56d53ed 100644 --- a/net/net.target.linux-mips.mk +++ b/net/net.target.linux-mips.mk @@ -298,6 +298,7 @@ LOCAL_SRC_FILES := \ net/quic/crypto/null_encrypter.cc \ net/quic/crypto/p256_key_exchange_openssl.cc \ net/quic/crypto/proof_source_chromium.cc \ + net/quic/crypto/proof_verifier.cc \ net/quic/crypto/proof_verifier_chromium.cc \ net/quic/crypto/quic_decrypter.cc \ net/quic/crypto/quic_encrypter.cc \ diff --git a/net/net.target.linux-x86.mk b/net/net.target.linux-x86.mk index 4deda275aa..b351009261 100644 --- a/net/net.target.linux-x86.mk +++ b/net/net.target.linux-x86.mk @@ -298,6 +298,7 @@ LOCAL_SRC_FILES := \ net/quic/crypto/null_encrypter.cc \ net/quic/crypto/p256_key_exchange_openssl.cc \ net/quic/crypto/proof_source_chromium.cc \ + net/quic/crypto/proof_verifier.cc \ net/quic/crypto/proof_verifier_chromium.cc \ net/quic/crypto/quic_decrypter.cc \ net/quic/crypto/quic_encrypter.cc \ diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc index 00cc342060..ad4366dcf6 100644 --- a/net/quic/crypto/crypto_handshake.cc +++ b/net/quic/crypto/crypto_handshake.cc @@ -500,9 +500,9 @@ uint64 QuicCryptoClientConfig::CachedState::generation_counter() const { return generation_counter_; } -const CertVerifyResult* -QuicCryptoClientConfig::CachedState::cert_verify_result() const { - return &cert_verify_result_; +const ProofVerifyDetails* +QuicCryptoClientConfig::CachedState::proof_verify_details() const { + return proof_verify_details_.get(); } void QuicCryptoClientConfig::CachedState::set_source_address_token( @@ -510,9 +510,9 @@ void QuicCryptoClientConfig::CachedState::set_source_address_token( source_address_token_ = token.as_string(); } -void QuicCryptoClientConfig::CachedState::SetCertVerifyResult( - const CertVerifyResult& cert_verify_result) { - cert_verify_result_.CopyFrom(cert_verify_result); +void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails( + ProofVerifyDetails* details) { + proof_verify_details_.reset(details); } void QuicCryptoClientConfig::SetDefaults() { diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h index d2f11f8c17..fdc92a0fc3 100644 --- a/net/quic/crypto/crypto_handshake.h +++ b/net/quic/crypto/crypto_handshake.h @@ -15,6 +15,7 @@ #include "net/cert/cert_verify_result.h" #include "net/cert/x509_certificate.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/crypto/proof_verifier.h" #include "net/quic/quic_protocol.h" namespace net { @@ -281,10 +282,12 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { const std::string& signature() const; bool proof_valid() const; uint64 generation_counter() const; - const CertVerifyResult* cert_verify_result() const; + const ProofVerifyDetails* proof_verify_details() const; void set_source_address_token(base::StringPiece token); - void SetCertVerifyResult(const CertVerifyResult& cert_verify_result); + + // SetProofVerifyDetails takes ownership of |details|. + void SetProofVerifyDetails(ProofVerifyDetails* details); private: std::string server_config_id_; // An opaque id from the server. @@ -301,10 +304,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // server_config_valid_ to false. uint64 generation_counter_; - // The result of certificate verification. - // TODO(rtenneti): should we change CertVerifyResult to be - // RefCountedThreadSafe object to avoid copying. - CertVerifyResult cert_verify_result_; + scoped_ptr<ProofVerifyDetails> proof_verify_details_; // scfg contains the cached, parsed value of |server_config|. mutable scoped_ptr<CryptoHandshakeMessage> scfg_; diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc index 3258c12a8f..8facb82374 100644 --- a/net/quic/crypto/proof_test.cc +++ b/net/quic/crypto/proof_test.cc @@ -89,6 +89,68 @@ TEST(Proof, Verify) { #endif // 0 } +// TestProofVerifierCallback is a simple callback for a ProofVerifier that +// signals a TestCompletionCallback when called and stores the results from the +// ProofVerifier in pointers passed to the constructor. +class TestProofVerifierCallback : public ProofVerifierCallback { + public: + TestProofVerifierCallback(TestCompletionCallback* comp_callback, + bool* ok, + std::string* error_details) + : comp_callback_(comp_callback), + ok_(ok), + error_details_(error_details) {} + + virtual void Run(bool ok, + const std::string& error_details, + scoped_ptr<ProofVerifyDetails>* details) OVERRIDE { + *ok_ = ok; + *error_details_ = error_details; + + comp_callback_->callback().Run(0); + } + + private: + TestCompletionCallback* const comp_callback_; + bool* const ok_; + std::string* const error_details_; +}; + +// RunVerification runs |verifier->VerifyProof| and asserts that the result +// matches |expected_ok|. +static void RunVerification(ProofVerifier* verifier, + const std::string& hostname, + const std::string& server_config, + const vector<std::string>& certs, + const std::string& proof, + bool expected_ok) { + scoped_ptr<ProofVerifyDetails> details; + TestCompletionCallback comp_callback; + bool ok; + std::string error_details; + TestProofVerifierCallback* callback = + new TestProofVerifierCallback(&comp_callback, &ok, &error_details); + + ProofVerifier::Status status = verifier->VerifyProof( + hostname, server_config, certs, proof, &error_details, &details, + callback); + + switch (status) { + case ProofVerifier::FAILURE: + ASSERT_FALSE(expected_ok); + ASSERT_NE("", error_details); + return; + case ProofVerifier::SUCCESS: + ASSERT_TRUE(expected_ok); + ASSERT_EQ("", error_details); + return; + case ProofVerifier::PENDING: + comp_callback.WaitForResult(); + ASSERT_EQ(expected_ok, ok); + break; + } +} + static string PEMCertFileToDER(const string& file_name) { base::FilePath certs_dir = GetTestCertsDirectory(); scoped_refptr<X509Certificate> cert = @@ -227,48 +289,26 @@ TEST(Proof, VerifyRSAKnownAnswerTest) { for (size_t i = 0; i < signatures.size(); i++) { const string& signature = signatures[i]; - int rv; - TestCompletionCallback callback; - rv = verifier->VerifyProof(hostname, server_config, certs, signature, - &error_details, &cert_verify_result, - callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(OK, rv); - ASSERT_EQ("", error_details); - ASSERT_FALSE(IsCertStatusError(cert_verify_result.cert_status)); - - rv = verifier->VerifyProof("foo.com", server_config, certs, signature, - &error_details, &cert_verify_result, - callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); - - rv = verifier->VerifyProof(hostname, server_config.substr(1, string::npos), - certs, signature, &error_details, - &cert_verify_result, callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); + + RunVerification( + verifier.get(), hostname, server_config, certs, signature, true); + RunVerification( + verifier.get(), "foo.com", server_config, certs, signature, false); + RunVerification( + verifier.get(), hostname, server_config.substr(1, string::npos), + certs, signature, false); const string corrupt_signature = "1" + signature; - rv = verifier->VerifyProof(hostname, server_config, certs, - corrupt_signature, &error_details, - &cert_verify_result, callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); + RunVerification( + verifier.get(), hostname, server_config, certs, corrupt_signature, + false); vector<string> wrong_certs; for (size_t i = 1; i < certs.size(); i++) { wrong_certs.push_back(certs[i]); } - rv = verifier->VerifyProof("foo.com", server_config, wrong_certs, signature, - &error_details, &cert_verify_result, - callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); + RunVerification(verifier.get(), hostname, server_config, wrong_certs, + signature, false); } } @@ -340,60 +380,35 @@ TEST(Proof, MAYBE_VerifyECDSAKnownAnswerTest) { for (size_t i = 0; i < signatures.size(); i++) { const string& signature = signatures[i]; - int rv; - TestCompletionCallback callback; - rv = verifier->VerifyProof(hostname, server_config, certs, signature, - &error_details, &cert_verify_result, - callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(OK, rv); - ASSERT_EQ("", error_details); - ASSERT_FALSE(IsCertStatusError(cert_verify_result.cert_status)); - - rv = verifier->VerifyProof("foo.com", server_config, certs, signature, - &error_details, &cert_verify_result, - callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); - - rv = verifier->VerifyProof(hostname, server_config.substr(1, string::npos), - certs, signature, &error_details, - &cert_verify_result, callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); + + RunVerification( + verifier.get(), hostname, server_config, certs, signature, true); + RunVerification( + verifier.get(), "foo.com", server_config, certs, signature, false); + RunVerification( + verifier.get(), hostname, server_config.substr(1, string::npos), + certs, signature, false); // An ECDSA signature is DER-encoded. Corrupt the last byte so that the // signature can still be DER-decoded correctly. string corrupt_signature = signature; corrupt_signature[corrupt_signature.size() - 1] += 1; - rv = verifier->VerifyProof(hostname, server_config, certs, - corrupt_signature, &error_details, - &cert_verify_result, callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); + RunVerification( + verifier.get(), hostname, server_config, certs, corrupt_signature, + false); // Prepending a "1" makes the DER invalid. const string bad_der_signature1 = "1" + signature; - rv = verifier->VerifyProof(hostname, server_config, certs, - bad_der_signature1, &error_details, - &cert_verify_result, callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); + RunVerification( + verifier.get(), hostname, server_config, certs, bad_der_signature1, + false); vector<string> wrong_certs; for (size_t i = 1; i < certs.size(); i++) { wrong_certs.push_back(certs[i]); } - rv = verifier->VerifyProof("foo.com", server_config, wrong_certs, signature, - &error_details, &cert_verify_result, - callback.callback()); - rv = callback.GetResult(rv); - ASSERT_EQ(ERR_FAILED, rv); - ASSERT_NE("", error_details); + RunVerification( + verifier.get(), hostname, server_config, wrong_certs, signature, false); } } diff --git a/net/quic/crypto/proof_verifier.cc b/net/quic/crypto/proof_verifier.cc new file mode 100644 index 0000000000..7bccba2bdb --- /dev/null +++ b/net/quic/crypto/proof_verifier.cc @@ -0,0 +1,15 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/crypto/proof_verifier.h" + +namespace net { + +ProofVerifyDetails::~ProofVerifyDetails() {} + +ProofVerifierCallback::~ProofVerifierCallback() {} + +ProofVerifier::~ProofVerifier() {} + +} // namespace net diff --git a/net/quic/crypto/proof_verifier.h b/net/quic/crypto/proof_verifier.h index eb96898950..f469c55295 100644 --- a/net/quic/crypto/proof_verifier.h +++ b/net/quic/crypto/proof_verifier.h @@ -15,32 +15,68 @@ namespace net { class CertVerifyResult; +// ProofVerifyDetails is an abstract class that acts as a container for any +// implementation specific details that a ProofVerifier wishes to return. These +// details are saved in the CachedInfo for the origin in question. +class ProofVerifyDetails { + public: + virtual ~ProofVerifyDetails(); +}; + +// ProofVerifierCallback provides a generic mechanism for a ProofVerifier to +// call back after an asynchronous verification. +class NET_EXPORT_PRIVATE ProofVerifierCallback { + public: + virtual ~ProofVerifierCallback(); + + // Run is called on the original thread to mark the completion of an + // asynchonous verification. If |ok| is true then the certificate is valid + // and |*error_details| is unused. Otherwise, |*error_details| contains a + // description of the error. |details| contains implementation-specific + // details of the verification. |Run| may take ownership of |details| by + // calling |release| on it. + virtual void Run(bool ok, + const std::string& error_details, + scoped_ptr<ProofVerifyDetails>* details) = 0; +}; + // A ProofVerifier checks the signature on a server config, and the certificate // chain that backs the public key. class NET_EXPORT_PRIVATE ProofVerifier { public: - virtual ~ProofVerifier() {} + // Status enumerates the possible results of verifying a proof. + enum Status { + SUCCESS = 0, + FAILURE = 1, + // PENDING results from a verification which will occur asynchonously. When + // the verification is complete, |callback|'s |Run| method will be called. + PENDING = 2, + }; + + virtual ~ProofVerifier(); // VerifyProof checks that |signature| is a valid signature of // |server_config| by the public key in the leaf certificate of |certs|, and - // that |certs| is a valid chain for |hostname|. On success, it returns OK. - // On failure, it returns ERR_FAILED and sets |*error_details| to a - // description of the problem. This function may also return ERR_IO_PENDING, - // in which case the |callback| will be run on the calling thread with the - // final OK/ERR_FAILED result when the proof is verified. + // that |certs| is a valid chain for |hostname|. On success, it returns + // SUCCESS. On failure, it returns ERROR and sets |*error_details| to a + // description of the problem. In either case it may set |*details|, which the + // caller takes ownership of. + // + // This function may also return PENDING, in which case the ProofVerifier + // will call back, on the original thread, via |callback| when complete. + // + // This function takes ownership of |callback|. It will be deleted even if + // the call returns immediately. // // The signature uses SHA-256 as the hash function and PSS padding in the // case of RSA. - // - // Note: this is just for testing. The CN of the certificate is ignored and - // wildcards in the SANs are not supported. - virtual int VerifyProof(const std::string& hostname, - const std::string& server_config, - const std::vector<std::string>& certs, - const std::string& signature, - std::string* error_details, - CertVerifyResult* cert_verify_result, - const CompletionCallback& callback) = 0; + virtual Status VerifyProof(const std::string& hostname, + const std::string& server_config, + const std::vector<std::string>& certs, + const std::string& signature, + std::string* error_details, + scoped_ptr<ProofVerifyDetails>* details, + ProofVerifierCallback* callback) = 0; }; } // namespace net diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc index 6f547882eb..c8b197b3d0 100644 --- a/net/quic/crypto/proof_verifier_chromium.cc +++ b/net/quic/crypto/proof_verifier_chromium.cc @@ -33,8 +33,6 @@ namespace net { ProofVerifierChromium::ProofVerifierChromium(CertVerifier* cert_verifier, const BoundNetLog& net_log) : cert_verifier_(cert_verifier), - cert_verify_result_(NULL), - error_details_(NULL), next_state_(STATE_NONE), net_log_(net_log) { } @@ -43,29 +41,36 @@ ProofVerifierChromium::~ProofVerifierChromium() { verifier_.reset(); } -int ProofVerifierChromium::VerifyProof(const string& hostname, - const string& server_config, - const vector<string>& certs, - const string& signature, - std::string* error_details, - CertVerifyResult* cert_verify_result, - const CompletionCallback& callback) { +ProofVerifierChromium::Status ProofVerifierChromium::VerifyProof( + const string& hostname, + const string& server_config, + const vector<string>& certs, + const string& signature, + std::string* error_details, + scoped_ptr<ProofVerifyDetails>* details, + ProofVerifierCallback* callback) { DCHECK(error_details); - DCHECK(cert_verify_result); + DCHECK(details); + DCHECK(callback); + + callback_.reset(callback); error_details->clear(); - cert_verify_result->Reset(); DCHECK_EQ(STATE_NONE, next_state_); if (STATE_NONE != next_state_) { *error_details = "Certificate is already set and VerifyProof has begun"; DLOG(WARNING) << *error_details; - return ERR_FAILED; + return FAILURE; } + verify_details_.reset(new ProofVerifyDetailsChromium); + if (certs.empty()) { *error_details = "Failed to create certificate chain. Certs are empty."; DLOG(WARNING) << *error_details; - return ERR_FAILED; + verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; + details->reset(verify_details_.release()); + return FAILURE; } // Convert certs to X509Certificate. @@ -77,8 +82,9 @@ int ProofVerifierChromium::VerifyProof(const string& hostname, if (!cert_.get()) { *error_details = "Failed to create certificate chain"; DLOG(WARNING) << *error_details; - cert_verify_result->cert_status = CERT_STATUS_INVALID; - return ERR_FAILED; + verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; + details->reset(verify_details_.release()); + return FAILURE; } // We call VerifySignature first to avoid copying of server_config and @@ -86,16 +92,25 @@ int ProofVerifierChromium::VerifyProof(const string& hostname, if (!VerifySignature(server_config, signature, certs[0])) { *error_details = "Failed to verify signature of server config"; DLOG(WARNING) << *error_details; - return ERR_FAILED; + verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; + details->reset(verify_details_.release()); + return FAILURE; } hostname_ = hostname; - callback_ = callback; - error_details_ = error_details; - cert_verify_result_ = cert_verify_result; next_state_ = STATE_VERIFY_CERT; - return DoLoop(OK); + switch (DoLoop(OK)) { + case OK: + details->reset(verify_details_.release()); + return SUCCESS; + case ERR_IO_PENDING: + return PENDING; + default: + *error_details = error_details_; + details->reset(verify_details_.release()); + return FAILURE; + } } int ProofVerifierChromium::DoLoop(int last_result) { @@ -124,7 +139,9 @@ int ProofVerifierChromium::DoLoop(int last_result) { void ProofVerifierChromium::OnIOComplete(int result) { int rv = DoLoop(result); if (rv != ERR_IO_PENDING) { - base::ResetAndReturn(&callback_).Run(rv); + scoped_ptr<ProofVerifyDetails> scoped_details(verify_details_.release()); + callback_->Run(rv == OK, error_details_, &scoped_details); + callback_.reset(); } } @@ -138,7 +155,7 @@ int ProofVerifierChromium::DoVerifyCert(int result) { hostname_, flags, SSLConfigService::GetCRLSet().get(), - cert_verify_result_, + &verify_details_->cert_verify_result, base::Bind(&ProofVerifierChromium::OnIOComplete, base::Unretained(this)), net_log_); @@ -148,9 +165,9 @@ int ProofVerifierChromium::DoVerifyCertComplete(int result) { verifier_.reset(); if (result <= ERR_FAILED) { - *error_details_ = StringPrintf("Failed to verify certificate chain: %s", - ErrorToString(result)); - DLOG(WARNING) << *error_details_; + error_details_ = StringPrintf("Failed to verify certificate chain: %s", + ErrorToString(result)); + DLOG(WARNING) << error_details_; result = ERR_FAILED; } diff --git a/net/quic/crypto/proof_verifier_chromium.h b/net/quic/crypto/proof_verifier_chromium.h index 134f62baa1..4969cc8aa5 100644 --- a/net/quic/crypto/proof_verifier_chromium.h +++ b/net/quic/crypto/proof_verifier_chromium.h @@ -23,6 +23,13 @@ namespace net { class CertVerifier; class SingleRequestCertVerifier; +// ProofVerifyDetailsChromium is the implementation-specific information that a +// ProofVerifierChromium returns about a certificate verification. +struct ProofVerifyDetailsChromium : public ProofVerifyDetails { + public: + CertVerifyResult cert_verify_result; +}; + // ProofVerifierChromium implements the QUIC ProofVerifier interface. // TODO(rtenneti): Add support for multiple requests for one ProofVerifier. class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier { @@ -32,13 +39,13 @@ class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier { virtual ~ProofVerifierChromium(); // ProofVerifier interface - virtual int VerifyProof(const std::string& hostname, - const std::string& server_config, - const std::vector<std::string>& certs, - const std::string& signature, - std::string* error_details, - CertVerifyResult* cert_verify_result, - const CompletionCallback& callback) OVERRIDE; + virtual Status VerifyProof(const std::string& hostname, + const std::string& server_config, + const std::vector<std::string>& certs, + const std::string& signature, + std::string* error_details, + scoped_ptr<ProofVerifyDetails>* details, + ProofVerifierCallback* callback) OVERRIDE; private: enum State { @@ -63,11 +70,9 @@ class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier { // |hostname| specifies the hostname for which |certs| is a valid chain. std::string hostname_; - CompletionCallback callback_; - - // The result of certificate verification. - CertVerifyResult* cert_verify_result_; - std::string* error_details_; + scoped_ptr<ProofVerifierCallback> callback_; + scoped_ptr<ProofVerifyDetailsChromium> verify_details_; + std::string error_details_; // X509Certificate from a chain of DER encoded certificates. scoped_refptr<X509Certificate> cert_; diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index 78b39e759e..69c63a5664 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -10,6 +10,7 @@ #include "net/quic/crypto/crypto_utils.h" #include "net/quic/crypto/null_encrypter.h" #include "net/quic/crypto/proof_verifier.h" +#include "net/quic/crypto/proof_verifier_chromium.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_session.h" #include "net/ssl/ssl_connection_status_flags.h" @@ -17,30 +18,63 @@ namespace net { +QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl( + QuicCryptoClientStream* stream) + : stream_(stream) {} + +QuicCryptoClientStream::ProofVerifierCallbackImpl:: + ~ProofVerifierCallbackImpl() {} + +void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run( + bool ok, + const string& error_details, + scoped_ptr<ProofVerifyDetails>* details) { + if (stream_ == NULL) { + return; + } + + stream_->verify_ok_ = ok; + stream_->verify_error_details_ = error_details; + stream_->verify_details_.reset(details->release()); + stream_->proof_verify_callback_ = NULL; + stream_->DoHandshakeLoop(NULL); + + // The ProofVerifier owns this object and will delete it when this method + // returns. +} + +void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() { + stream_ = NULL; +} + + QuicCryptoClientStream::QuicCryptoClientStream( const string& server_hostname, QuicSession* session, QuicCryptoClientConfig* crypto_config) : QuicCryptoStream(session), - weak_factory_(this), next_state_(STATE_IDLE), num_client_hellos_(0), crypto_config_(crypto_config), server_hostname_(server_hostname), - generation_counter_(0) { + generation_counter_(0), + proof_verify_callback_(NULL) { } QuicCryptoClientStream::~QuicCryptoClientStream() { + if (proof_verify_callback_) { + proof_verify_callback_->Cancel(); + } } void QuicCryptoClientStream::OnHandshakeMessage( const CryptoHandshakeMessage& message) { - DoHandshakeLoop(&message, OK); + DoHandshakeLoop(&message); } bool QuicCryptoClientStream::CryptoConnect() { next_state_ = STATE_SEND_CHLO; - DoHandshakeLoop(NULL, OK); + DoHandshakeLoop(NULL); return true; } @@ -57,7 +91,8 @@ bool QuicCryptoClientStream::GetSSLInfo(SSLInfo* ssl_info) { return false; } const CertVerifyResult* cert_verify_result = - cached->cert_verify_result(); + &(reinterpret_cast<const ProofVerifyDetailsChromium*>( + cached->proof_verify_details()))->cert_verify_result; ssl_info->cert_status = cert_verify_result->cert_status; ssl_info->cert = cert_verify_result->verified_cert; @@ -95,8 +130,7 @@ bool QuicCryptoClientStream::GetSSLInfo(SSLInfo* ssl_info) { static const int kMaxClientHellos = 3; void QuicCryptoClientStream::DoHandshakeLoop( - const CryptoHandshakeMessage* in, - int result) { + const CryptoHandshakeMessage* in) { CryptoHandshakeMessage out; QuicErrorCode error; string error_details; @@ -112,7 +146,6 @@ void QuicCryptoClientStream::DoHandshakeLoop( next_state_ = STATE_IDLE; switch (state) { case STATE_SEND_CHLO: { - DCHECK_EQ(OK, result); // Send the client hello in plaintext. session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); if (num_client_hellos_ > kMaxClientHellos) { @@ -171,7 +204,6 @@ void QuicCryptoClientStream::DoHandshakeLoop( return; } case STATE_RECV_REJ: - DCHECK_EQ(OK, result); // We sent a dummy CHLO because we didn't have enough information to // perform a handshake, or we sent a full hello that the server // rejected. Here we hope to have a REJ that contains the information @@ -205,25 +237,40 @@ void QuicCryptoClientStream::DoHandshakeLoop( DCHECK(verifier); next_state_ = STATE_VERIFY_PROOF_COMPLETE; generation_counter_ = cached->generation_counter(); - result = verifier->VerifyProof( + + ProofVerifierCallbackImpl* proof_verify_callback = + new ProofVerifierCallbackImpl(this); + + verify_ok_ = false; + + ProofVerifier::Status status = verifier->VerifyProof( server_hostname_, cached->server_config(), cached->certs(), cached->signature(), - &error_details_, - &cert_verify_result_, - base::Bind(&QuicCryptoClientStream::OnVerifyProofComplete, - weak_factory_.GetWeakPtr())); - if (result == ERR_IO_PENDING) { - DVLOG(1) << "Doing VerifyProof"; - return; + &error_details, + &verify_details_, + proof_verify_callback); + + switch (status) { + case ProofVerifier::PENDING: + proof_verify_callback_ = proof_verify_callback; + DVLOG(1) << "Doing VerifyProof"; + return; + case ProofVerifier::FAILURE: + CloseConnectionWithDetails( + QUIC_PROOF_INVALID, "Proof invalid: " + error_details); + return; + case ProofVerifier::SUCCESS: + verify_ok_ = true; + break; } break; } case STATE_VERIFY_PROOF_COMPLETE: - if (result != OK) { + if (!verify_ok_) { CloseConnectionWithDetails( - QUIC_PROOF_INVALID, "Proof invalid: " + error_details_); + QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); return; } // Check if generation_counter has changed between STATE_VERIFY_PROOF @@ -232,7 +279,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( next_state_ = STATE_VERIFY_PROOF; } else { cached->SetProofValid(); - cached->SetCertVerifyResult(cert_verify_result_); + cached->SetProofVerifyDetails(verify_details_.release()); next_state_ = STATE_SEND_CHLO; } break; @@ -305,10 +352,4 @@ void QuicCryptoClientStream::DoHandshakeLoop( } } -void QuicCryptoClientStream::OnVerifyProofComplete(int result) { - DCHECK_EQ(STATE_VERIFY_PROOF_COMPLETE, next_state_); - DVLOG(1) << "VerifyProof completed: " << result; - DoHandshakeLoop(NULL, result); -} - } // namespace net diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h index 4686fedf1a..50cfbb8679 100644 --- a/net/quic/quic_crypto_client_stream.h +++ b/net/quic/quic_crypto_client_stream.h @@ -10,11 +10,13 @@ #include "net/cert/cert_verify_result.h" #include "net/cert/x509_certificate.h" #include "net/quic/crypto/crypto_handshake.h" +#include "net/quic/crypto/proof_verifier.h" #include "net/quic/quic_config.h" #include "net/quic/quic_crypto_stream.h" namespace net { +class ProofVerifyDetails; class QuicSession; class SSLInfo; @@ -47,7 +49,29 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { bool GetSSLInfo(SSLInfo* ssl_info); private: + // ProofVerifierCallbackImpl is passed as the callback method to VerifyProof. + // The ProofVerifier calls this class with the result of proof verification + // when verification is performed asynchronously. + class ProofVerifierCallbackImpl : public ProofVerifierCallback { + public: + explicit ProofVerifierCallbackImpl(QuicCryptoClientStream* stream); + virtual ~ProofVerifierCallbackImpl(); + + // ProofVerifierCallback interface. + virtual void Run(bool ok, + const string& error_details, + scoped_ptr<ProofVerifyDetails>* details) OVERRIDE; + + // Cancel causes any future callbacks to be ignored. It must be called on + // the same thread as the callback will be made on. + void Cancel(); + + private: + QuicCryptoClientStream* stream_; + }; + friend class test::CryptoTestUtils; + friend class ProofVerifierCallbackImpl; enum State { STATE_IDLE, @@ -59,17 +83,8 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { }; // DoHandshakeLoop performs a step of the handshake state machine. Note that - // |in| is NULL for the first call. OnVerifyProofComplete passes the |result| - // it has received from VerifyProof call (from all other places |result| is - // set to OK). - void DoHandshakeLoop(const CryptoHandshakeMessage* in, int result); - - // OnVerifyProofComplete is passed as the callback method to VerifyProof. - // ProofVerifier calls this method with the result of proof verification when - // verification is performed asynchronously. - void OnVerifyProofComplete(int result); - - base::WeakPtrFactory<QuicCryptoClientStream> weak_factory_; + // |in| may be NULL if the call did not result from a received message + void DoHandshakeLoop(const CryptoHandshakeMessage* in); State next_state_; // num_client_hellos_ contains the number of client hello messages that this @@ -86,13 +101,15 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { // Generation counter from QuicCryptoClientConfig's CachedState. uint64 generation_counter_; - // The result of certificate verification. - // TODO(rtenneti): should we change CertVerifyResult to be - // RefCountedThreadSafe object to avoid copying. - CertVerifyResult cert_verify_result_; + // proof_verify_callback_ contains the callback object that we passed to an + // asynchronous proof verification. The ProofVerifier owns this object. + ProofVerifierCallbackImpl* proof_verify_callback_; - // Error details for ProofVerifier's VerifyProof call. - std::string error_details_; + // These members are used to store the result of an asynchronous proof + // verification. + bool verify_ok_; + string verify_error_details_; + scoped_ptr<ProofVerifyDetails> verify_details_; DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream); }; diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index ef9a164053..eb260781a0 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -24,16 +24,19 @@ namespace { class RecordingProofVerifier : public net::ProofVerifier { public: // ProofVerifier interface. - virtual int VerifyProof(const string& hostname, - const string& server_config, - const vector<string>& certs, - const string& signature, - string* error_details, - net::CertVerifyResult* cert_verify_result, - const net::CompletionCallback& callback) OVERRIDE { + virtual net::ProofVerifier::Status VerifyProof( + const string& hostname, + const string& server_config, + const vector<string>& certs, + const string& signature, + string* error_details, + scoped_ptr<net::ProofVerifyDetails>* details, + net::ProofVerifierCallback* callback) OVERRIDE { + delete callback; + common_name_.clear(); if (certs.empty()) { - return net::ERR_FAILED; + return FAILURE; } // Convert certs to X509Certificate. @@ -44,11 +47,11 @@ class RecordingProofVerifier : public net::ProofVerifier { scoped_refptr<net::X509Certificate> cert = net::X509Certificate::CreateFromDERCertChain(cert_pieces); if (!cert.get()) { - return net::ERR_FAILED; + return FAILURE; } common_name_ = cert->subject().GetDisplayName(); - return net::OK; + return SUCCESS; } const string& common_name() const { return common_name_; } |