Commit 05bfc260 authored by wtc@chromium.org's avatar wtc@chromium.org

Change the prototype of ChannelIDSource::GetChannelIDKey() to allow an

asynchronous implementation.

Current ChannelIDSource implementations work in synchronous mode. So
QuicCryptoClientStream still calls ChannelIDSource::GetChannelIDKey() as
a synchronous function. In a future CL, QuicCryptoClientStream will properly
call ChannelIDSource::GetChannelIDKey() as an asynchronous function.

Note that ChannelIDSourceForTesting() returns a ChannelIDSource that works
in synchronous mode.

Merge internal CL: 68399207

R=rch@chromium.org,rtenneti@chromium.org
BUG=none

Review URL: https://codereview.chromium.org/320663002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275634 0039d316-1c4b-4281-b951-d872f2087c98
parent eceaabf4
......@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
#include "net/quic/quic_types.h"
namespace net {
......@@ -22,10 +23,23 @@ class NET_EXPORT_PRIVATE ChannelIDKey {
// Sign signs |signed_data| using the ChannelID private key and puts the
// signature into |out_signature|. It returns true on success.
virtual bool Sign(base::StringPiece signed_data,
std::string* out_signature) = 0;
std::string* out_signature) const = 0;
// SerializeKey returns the serialized ChannelID public key.
virtual std::string SerializeKey() = 0;
virtual std::string SerializeKey() const = 0;
};
// ChannelIDSourceCallback provides a generic mechanism for a ChannelIDSource
// to call back after an asynchronous GetChannelIDKey operation.
class ChannelIDSourceCallback {
public:
virtual ~ChannelIDSourceCallback() {}
// Run is called on the original thread to mark the completion of an
// asynchonous GetChannelIDKey operation. If |*channel_id_key| is not NULL
// then the channel ID lookup is successful. |Run| may take ownership of
// |*channel_id_key| by calling |release| on it.
virtual void Run(scoped_ptr<ChannelIDKey>* channel_id_key) = 0;
};
// ChannelIDSource is an abstract interface by which a QUIC client can obtain
......@@ -35,9 +49,17 @@ class NET_EXPORT_PRIVATE ChannelIDSource {
virtual ~ChannelIDSource() {}
// GetChannelIDKey looks up the ChannelIDKey for |hostname|. On success it
// returns true and stores the ChannelIDKey in |*channel_id|.
virtual bool GetChannelIDKey(const std::string& hostname,
scoped_ptr<ChannelIDKey>* channel_id_key) = 0;
// returns QUIC_SUCCESS and stores the ChannelIDKey in |*channel_id_key|,
// which the caller takes ownership of. On failure, it returns QUIC_FAILURE.
//
// This function may also return QUIC_PENDING, in which case the
// ChannelIDSource will call back, on the original thread, via |callback|
// when complete. In this case, the ChannelIDSource will take ownership of
// |callback|.
virtual QuicAsyncStatus GetChannelIDKey(
const std::string& hostname,
scoped_ptr<ChannelIDKey>* channel_id_key,
ChannelIDSourceCallback* callback) = 0;
};
// ChannelIDVerifier verifies ChannelID signatures.
......
......@@ -226,7 +226,9 @@ TEST(ChannelIDTest, SignAndVerify) {
const string signed_data = "signed data";
const string hostname = "foo.example.com";
scoped_ptr<ChannelIDKey> channel_id_key;
ASSERT_TRUE(source->GetChannelIDKey(hostname, &channel_id_key));
QuicAsyncStatus status =
source->GetChannelIDKey(hostname, &channel_id_key, NULL);
ASSERT_EQ(QUIC_SUCCESS, status);
string signature;
ASSERT_TRUE(channel_id_key->Sign(signed_data, &signature));
......
......@@ -37,7 +37,7 @@ class NET_EXPORT_PRIVATE 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
// 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.
......@@ -55,7 +55,7 @@ class NET_EXPORT_PRIVATE 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
// QUIC_SUCCESS. On failure, it returns QUIC_ERROR and sets |*error_details|
// QUIC_SUCCESS. On failure, it returns QUIC_FAILURE and sets |*error_details|
// to a description of the problem. In either case it may set |*details|,
// which the caller takes ownership of.
//
......
......@@ -40,8 +40,8 @@ class ProofVerifierChromium::Job {
CertVerifier* cert_verifier,
const BoundNetLog& net_log);
// Starts the proof verification. If |PENDING| is returned, then |callback|
// will be invoked asynchronously when the verification completes.
// Starts the proof verification. If |QUIC_PENDING| is returned, then
// |callback| will be invoked asynchronously when the verification completes.
QuicAsyncStatus VerifyProof(const std::string& hostname,
const std::string& server_config,
const std::vector<std::string>& certs,
......
......@@ -350,6 +350,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
const CachedState* cached,
QuicWallTime now,
QuicRandom* rand,
const ChannelIDKey* channel_id_key,
QuicCryptoNegotiatedParameters* out_params,
CryptoHandshakeMessage* out,
string* error_details) const {
......@@ -447,22 +448,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
}
out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
bool do_channel_id = false;
if (channel_id_source_.get()) {
const QuicTag* their_proof_demands;
size_t num_their_proof_demands;
if (scfg->GetTaglist(kPDMD, &their_proof_demands,
&num_their_proof_demands) == QUIC_NO_ERROR) {
for (size_t i = 0; i < num_their_proof_demands; i++) {
if (their_proof_demands[i] == kCHID) {
do_channel_id = true;
break;
}
}
}
}
if (do_channel_id) {
if (channel_id_key) {
// In order to calculate the encryption key for the CETV block we need to
// serialise the client hello as it currently is (i.e. without the CETV
// block). For this, the client hello is serialized without padding.
......@@ -482,12 +468,6 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
client_hello_serialized.length());
hkdf_input.append(cached->server_config());
scoped_ptr<ChannelIDKey> channel_id_key;
if (!channel_id_source_->GetChannelIDKey(server_id.host(),
&channel_id_key)) {
*error_details = "Channel ID lookup failed";
return QUIC_INVALID_CHANNEL_ID_SIGNATURE;
}
string key = channel_id_key->SerializeKey();
string signature;
if (!channel_id_key->Sign(hkdf_input, &signature)) {
......@@ -523,6 +503,10 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
out->set_minimum_size(orig_min_size);
}
// Derive the symmetric keys and set up the encrypters and decrypters.
// Set the following members of out_params:
// out_params->hkdf_input_suffix
// out_params->initial_crypters
out_params->hkdf_input_suffix.clear();
out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&connection_id),
sizeof(connection_id));
......
......@@ -18,6 +18,7 @@
namespace net {
class ChannelIDKey;
class ChannelIDSource;
class CryptoHandshakeMessage;
class ProofVerifier;
......@@ -168,6 +169,10 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
// accept. |preferred_version| is the version of the QUIC protocol that this
// client chose to use initially. This allows the server to detect downgrade
// attacks.
//
// If |channel_id_key| is not null, it is used to sign a secret value derived
// from the client and server's keys, and the Channel ID public key and the
// signature are placed in the CETV value of the CHLO.
QuicErrorCode FillClientHello(const QuicServerId& server_id,
QuicConnectionId connection_id,
const QuicVersion preferred_version,
......@@ -175,6 +180,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
const CachedState* cached,
QuicWallTime now,
QuicRandom* rand,
const ChannelIDKey* channel_id_key,
QuicCryptoNegotiatedParameters* out_params,
CryptoHandshakeMessage* out,
std::string* error_details) const;
......
......@@ -122,6 +122,7 @@ TEST(QuicCryptoClientConfigTest, FillClientHello) {
&state,
QuicWallTime::Zero(),
&rand,
NULL, // channel_id_key
&params,
&chlo,
&error_details);
......
......@@ -4,6 +4,7 @@
#include "net/quic/quic_crypto_client_stream.h"
#include "net/quic/crypto/channel_id.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/null_encrypter.h"
......@@ -151,6 +152,35 @@ void QuicCryptoClientStream::DoHandshakeLoop(
return;
}
session()->config()->ToHandshakeMessage(&out);
scoped_ptr<ChannelIDKey> channel_id_key;
bool do_channel_id = false;
if (crypto_config_->channel_id_source()) {
const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
DCHECK(scfg);
const QuicTag* their_proof_demands;
size_t num_their_proof_demands;
if (scfg->GetTaglist(kPDMD, &their_proof_demands,
&num_their_proof_demands) == QUIC_NO_ERROR) {
for (size_t i = 0; i < num_their_proof_demands; i++) {
if (their_proof_demands[i] == kCHID) {
do_channel_id = true;
break;
}
}
}
}
if (do_channel_id) {
QuicAsyncStatus status =
crypto_config_->channel_id_source()->GetChannelIDKey(
server_id_.host(), &channel_id_key, NULL);
if (status != QUIC_SUCCESS) {
CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
"Channel ID lookup failed");
return;
}
}
error = crypto_config_->FillClientHello(
server_id_,
session()->connection()->connection_id(),
......@@ -159,6 +189,7 @@ void QuicCryptoClientStream::DoHandshakeLoop(
cached,
session()->connection()->clock()->WallNow(),
session()->connection()->random_generator(),
channel_id_key.get(),
&crypto_negotiated_params_,
&out,
&error_details);
......
......@@ -192,8 +192,11 @@ int CryptoTestUtils::HandshakeWithFakeClient(
if (options.channel_id_enabled) {
scoped_ptr<ChannelIDKey> channel_id_key;
EXPECT_TRUE(crypto_config.channel_id_source()->GetChannelIDKey(
kServerHostname, &channel_id_key));
QuicAsyncStatus status =
crypto_config.channel_id_source()->GetChannelIDKey(kServerHostname,
&channel_id_key,
NULL);
EXPECT_EQ(QUIC_SUCCESS, status);
EXPECT_EQ(channel_id_key->SerializeKey(),
server->crypto_negotiated_params().channel_id);
}
......
......@@ -133,7 +133,9 @@ class CryptoTestUtils {
va_list ap);
// ChannelIDSourceForTesting returns a ChannelIDSource that generates keys
// deterministically based on the hostname given in the GetChannelID call.
// deterministically based on the hostname given in the GetChannelIDKey call.
// This ChannelIDSource works in synchronous mode, i.e., its GetChannelIDKey
// method never returns QUIC_PENDING.
static ChannelIDSource* ChannelIDSourceForTesting();
private:
......
......@@ -31,7 +31,7 @@ class TestChannelIDKey : public ChannelIDKey {
// ChannelIDKey implementation.
virtual bool Sign(StringPiece signed_data,
string* out_signature) OVERRIDE {
string* out_signature) const OVERRIDE {
unsigned char hash_buf[SHA256_LENGTH];
SECItem hash_item = { siBuffer, hash_buf, sizeof(hash_buf) };
......@@ -71,13 +71,13 @@ class TestChannelIDKey : public ChannelIDKey {
return true;
}
virtual string SerializeKey() OVERRIDE {
static const unsigned int kExpectedKeyLength = 65;
virtual string SerializeKey() const OVERRIDE {
const SECKEYPublicKey* public_key = ecdsa_keypair_->public_key();
// public_key->u.ec.publicValue is an ANSI X9.62 public key which, for
// a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field
// elements as 32-byte, big-endian numbers.
static const unsigned int kExpectedKeyLength = 65;
const unsigned char* const data = public_key->u.ec.publicValue.data;
const unsigned int len = public_key->u.ec.publicValue.len;
......@@ -101,11 +101,12 @@ class TestChannelIDSource : public ChannelIDSource {
// ChannelIDSource implementation.
virtual bool GetChannelIDKey(
virtual QuicAsyncStatus GetChannelIDKey(
const string& hostname,
scoped_ptr<ChannelIDKey>* channel_id_key) OVERRIDE {
scoped_ptr<ChannelIDKey>* channel_id_key,
ChannelIDSourceCallback* /*callback*/) OVERRIDE {
channel_id_key->reset(new TestChannelIDKey(HostnameToKey(hostname)));
return true;
return QUIC_SUCCESS;
}
private:
......@@ -125,7 +126,6 @@ class TestChannelIDSource : public ChannelIDSource {
return keypair;
}
HostnameToKeyMap hostname_to_key_;
};
......
......@@ -38,7 +38,7 @@ class TestChannelIDKey : public ChannelIDKey {
// ChannelIDKey implementation.
virtual bool Sign(StringPiece signed_data,
string* out_signature) OVERRIDE {
string* out_signature) const OVERRIDE {
EVP_MD_CTX md_ctx;
EVP_MD_CTX_init(&md_ctx);
crypto::ScopedOpenSSL<EVP_MD_CTX, EvpMdCtxCleanUp>
......@@ -85,7 +85,7 @@ class TestChannelIDKey : public ChannelIDKey {
return true;
}
virtual string SerializeKey() OVERRIDE {
virtual string SerializeKey() const OVERRIDE {
// i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256
// key, is 0x04 (meaning uncompressed) followed by the x and y field
// elements as 32-byte, big-endian numbers.
......@@ -113,11 +113,12 @@ class TestChannelIDSource : public ChannelIDSource {
// ChannelIDSource implementation.
virtual bool GetChannelIDKey(
virtual QuicAsyncStatus GetChannelIDKey(
const string& hostname,
scoped_ptr<ChannelIDKey>* channel_id_key) OVERRIDE {
scoped_ptr<ChannelIDKey>* channel_id_key,
ChannelIDSourceCallback* /*callback*/) OVERRIDE {
channel_id_key->reset(new TestChannelIDKey(HostnameToKey(hostname)));
return true;
return QUIC_SUCCESS;
}
private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment