Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(462)

Unified Diff: net/quic/crypto/crypto_server_config.cc

Issue 14816006: Land Recent QUIC changes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added missing NET_PRIVATE_EXPORT to QuicWallTime Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/quic/crypto/crypto_server_config.h ('k') | net/quic/crypto/crypto_server_config_protobuf.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/quic/crypto/crypto_server_config.cc
diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc
index 953f57cbb77e1ffab1e009514e54506351ea07ae..e4ee4009f1023a7b65ab43a391a9a104077ecc3f 100644
--- a/net/quic/crypto/crypto_server_config.cc
+++ b/net/quic/crypto/crypto_server_config.cc
@@ -14,6 +14,7 @@
#include "net/quic/crypto/crypto_server_config_protobuf.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/curve25519_key_exchange.h"
+#include "net/quic/crypto/ephemeral_key_source.h"
#include "net/quic/crypto/key_exchange.h"
#include "net/quic/crypto/p256_key_exchange.h"
#include "net/quic/crypto/proof_source.h"
@@ -52,7 +53,7 @@ QuicCryptoServerConfig::QuicCryptoServerConfig(
: strike_register_lock_(),
source_address_token_encrypter_(new Aes128GcmEncrypter),
source_address_token_decrypter_(new Aes128GcmDecrypter) {
- crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
+ crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
"QUIC source address token key",
source_address_token_encrypter_->GetKeySize(),
0 /* no fixed IV needed */);
@@ -68,7 +69,8 @@ QuicCryptoServerConfig::~QuicCryptoServerConfig() {
QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
- const CryptoHandshakeMessage& extra_tags) {
+ const CryptoHandshakeMessage& extra_tags,
+ uint64 expiry_time) {
CryptoHandshakeMessage msg;
const string curve25519_private_key =
@@ -77,20 +79,20 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
Curve25519KeyExchange::New(curve25519_private_key));
StringPiece curve25519_public_value = curve25519->public_value();
- const string p256_private_key =
- P256KeyExchange::NewPrivateKey();
- scoped_ptr<P256KeyExchange> p256(
- P256KeyExchange::New(p256_private_key));
+ const string p256_private_key = P256KeyExchange::NewPrivateKey();
+ scoped_ptr<P256KeyExchange> p256(P256KeyExchange::New(p256_private_key));
StringPiece p256_public_value = p256->public_value();
string encoded_public_values;
- // First two bytes encode the length of the public value.
+ // First three bytes encode the length of the public value.
encoded_public_values.push_back(curve25519_public_value.size());
encoded_public_values.push_back(curve25519_public_value.size() >> 8);
+ encoded_public_values.push_back(curve25519_public_value.size() >> 16);
encoded_public_values.append(curve25519_public_value.data(),
curve25519_public_value.size());
encoded_public_values.push_back(p256_public_value.size());
encoded_public_values.push_back(p256_public_value.size() >> 8);
+ encoded_public_values.push_back(p256_public_value.size() >> 16);
encoded_public_values.append(p256_public_value.data(),
p256_public_value.size());
@@ -102,6 +104,16 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
msg.Insert(extra_tags.tag_value_map().begin(),
extra_tags.tag_value_map().end());
+ if (expiry_time == 0) {
+ const QuicWallTime now = clock->WallNow();
+ const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds(
+ 60 * 60 * 24 * 180 /* 180 days, ~six months */));
+ const uint64 expiry_seconds = expiry.ToUNIXSeconds();
+ msg.SetValue(kEXPY, expiry_seconds);
+ } else {
+ msg.SetValue(kEXPY, expiry_time);
+ }
+
char scid_bytes[16];
rand->RandBytes(scid_bytes, sizeof(scid_bytes));
msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
@@ -110,8 +122,7 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes)));
- scoped_ptr<QuicData> serialized(
- CryptoFramer::ConstructHandshakeMessage(msg));
+ scoped_ptr<QuicData> serialized(CryptoFramer::ConstructHandshakeMessage(msg));
scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf);
config->set_config(serialized->AsStringPiece());
@@ -135,9 +146,8 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
return NULL;
}
if (msg->tag() != kSCFG) {
- LOG(WARNING) << "Server config message has tag "
- << msg->tag() << " expected "
- << kSCFG;
+ LOG(WARNING) << "Server config message has tag " << msg->tag()
+ << " expected " << kSCFG;
return NULL;
}
@@ -151,15 +161,15 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
}
config->id = scid.as_string();
- const CryptoTag* aead_tags;
+ const QuicTag* aead_tags;
size_t aead_len;
if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) {
LOG(WARNING) << "Server config message is missing AEAD";
return NULL;
}
- config->aead = vector<CryptoTag>(aead_tags, aead_tags + aead_len);
+ config->aead = vector<QuicTag>(aead_tags, aead_tags + aead_len);
- const CryptoTag* kexs_tags;
+ const QuicTag* kexs_tags;
size_t kexs_len;
if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) {
LOG(WARNING) << "Server config message is missing KEXS";
@@ -181,16 +191,14 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
if (kexs_len != protobuf->key_size()) {
- LOG(WARNING) << "Server config has "
- << kexs_len
+ LOG(WARNING) << "Server config has " << kexs_len
<< " key exchange methods configured, but "
- << protobuf->key_size()
- << " private keys";
+ << protobuf->key_size() << " private keys";
return NULL;
}
for (size_t i = 0; i < kexs_len; i++) {
- const CryptoTag tag = kexs_tags[i];
+ const QuicTag tag = kexs_tags[i];
string private_key;
config->kexs.push_back(tag);
@@ -205,34 +213,32 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
if (private_key.empty()) {
LOG(WARNING) << "Server config contains key exchange method without "
- "corresponding private key: "
- << tag;
+ "corresponding private key: " << tag;
return NULL;
}
scoped_ptr<KeyExchange> ka;
switch (tag) {
- case kC255:
- ka.reset(Curve25519KeyExchange::New(private_key));
- if (!ka.get()) {
- LOG(WARNING) << "Server config contained an invalid curve25519"
- " private key.";
- return NULL;
- }
- break;
- case kP256:
- ka.reset(P256KeyExchange::New(private_key));
- if (!ka.get()) {
- LOG(WARNING) << "Server config contained an invalid P-256"
- " private key.";
+ case kC255:
+ ka.reset(Curve25519KeyExchange::New(private_key));
+ if (!ka.get()) {
+ LOG(WARNING) << "Server config contained an invalid curve25519"
+ " private key.";
+ return NULL;
+ }
+ break;
+ case kP256:
+ ka.reset(P256KeyExchange::New(private_key));
+ if (!ka.get()) {
+ LOG(WARNING) << "Server config contained an invalid P-256"
+ " private key.";
+ return NULL;
+ }
+ break;
+ default:
+ LOG(WARNING) << "Server config message contains unknown key exchange "
+ "method: " << tag;
return NULL;
- }
- break;
- default:
- LOG(WARNING) << "Server config message contains unknown key exchange "
- "method: "
- << tag;
- return NULL;
}
for (vector<KeyExchange*>::const_iterator i = config->key_exchanges.begin();
@@ -271,9 +277,10 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
- const CryptoHandshakeMessage& extra_tags) {
+ const CryptoHandshakeMessage& extra_tags,
+ uint64 expiry_time) {
scoped_ptr<QuicServerConfigProtobuf> config(DefaultConfig(
- rand, clock, extra_tags));
+ rand, clock, extra_tags, expiry_time));
return AddConfig(config.get());
}
@@ -281,7 +288,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
const CryptoHandshakeMessage& client_hello,
QuicGuid guid,
const IPEndPoint& client_ip,
- QuicTime::Delta now_since_unix_epoch,
+ const QuicClock* clock,
QuicRandom* rand,
QuicCryptoNegotiatedParameters *params,
CryptoHandshakeMessage* out,
@@ -299,15 +306,16 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
}
const Config* const config(it->second);
+ const QuicWallTime now = clock->WallNow();
bool valid_source_address_token = false;
StringPiece srct;
- if (client_hello.GetStringPiece(kSRCT, &srct) &&
- ValidateSourceAddressToken(srct, client_ip, now_since_unix_epoch)) {
+ if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct) &&
+ ValidateSourceAddressToken(srct, client_ip, now)) {
valid_source_address_token = true;
}
const string fresh_source_address_token =
- NewSourceAddressToken(client_ip, rand, now_since_unix_epoch);
+ NewSourceAddressToken(client_ip, rand, now);
// If we previously sent a REJ to this client then we may have stored a
// server nonce in |params|. In which case, we know that the connection
@@ -328,14 +336,18 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
strike_register_.reset(new StrikeRegister(
// TODO(agl): these magic numbers should come from config.
1024 /* max entries */,
- static_cast<uint32>(now_since_unix_epoch.ToSeconds()),
+ static_cast<uint32>(now.ToUNIXSeconds()),
600 /* window secs */, config->orbit));
}
unique_by_strike_register = strike_register_->Insert(
reinterpret_cast<const uint8*>(client_nonce.data()),
- static_cast<uint32>(now_since_unix_epoch.ToSeconds()));
+ static_cast<uint32>(now.ToUNIXSeconds()));
}
+ StringPiece server_nonce;
+ client_hello.GetStringPiece(kServerNonceTag, &server_nonce);
+ const bool server_nonce_matches = server_nonce == params->server_nonce;
+
out->Clear();
StringPiece sni;
@@ -346,6 +358,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
scid.as_string() != config->id ||
!valid_source_address_token ||
!client_nonce_well_formed ||
+ !server_nonce_matches ||
(!unique_by_strike_register &&
!unique_by_server_nonce)) {
// If the client didn't provide a server config ID, or gave the wrong one,
@@ -353,22 +366,20 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
// give the client enough information to do better next time.
out->set_tag(kREJ);
out->SetStringPiece(kSCFG, config->serialized);
- out->SetStringPiece(kSRCT, fresh_source_address_token);
+ out->SetStringPiece(kSourceAddressTokenTag, fresh_source_address_token);
if (params->server_nonce.empty()) {
CryptoUtils::GenerateNonce(
- now_since_unix_epoch, rand,
- StringPiece(reinterpret_cast<const char*>(config->orbit),
- sizeof(config->orbit)),
+ now, rand, StringPiece(reinterpret_cast<const char*>(config->orbit),
+ sizeof(config->orbit)),
&params->server_nonce);
}
- out->SetStringPiece(kNONC, params->server_nonce);
+ out->SetStringPiece(kServerNonceTag, params->server_nonce);
// The client may have requested a certificate chain.
- const CryptoTag* their_proof_demands;
+ const QuicTag* their_proof_demands;
size_t num_their_proof_demands;
- if (proof_source_.get() != NULL &&
- !sni.empty() &&
+ if (proof_source_.get() != NULL && !sni.empty() &&
client_hello.GetTaglist(kPDMD, &their_proof_demands,
&num_their_proof_demands) == QUIC_NO_ERROR) {
for (size_t i = 0; i < num_their_proof_demands; i++) {
@@ -398,7 +409,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
static const size_t kMaxUnverifiedSize = 400;
if (valid_source_address_token ||
signature.size() + compressed.size() < kMaxUnverifiedSize) {
- out->SetStringPiece(kCERT, compressed);
+ out->SetStringPiece(kCertificateTag, compressed);
out->SetStringPiece(kPROF, signature);
}
break;
@@ -408,8 +419,8 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
return QUIC_NO_ERROR;
}
- const CryptoTag* their_aeads;
- const CryptoTag* their_key_exchanges;
+ const QuicTag* their_aeads;
+ const QuicTag* their_key_exchanges;
size_t num_their_aeads, num_their_key_exchanges;
if (client_hello.GetTaglist(kAEAD, &their_aeads,
&num_their_aeads) != QUIC_NO_ERROR ||
@@ -422,16 +433,13 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
}
size_t key_exchange_index;
- if (!CryptoUtils::FindMutualTag(config->aead,
- their_aeads, num_their_aeads,
- CryptoUtils::LOCAL_PRIORITY,
- &params->aead,
+ if (!CryptoUtils::FindMutualTag(config->aead, their_aeads, num_their_aeads,
+ CryptoUtils::LOCAL_PRIORITY, &params->aead,
NULL) ||
- !CryptoUtils::FindMutualTag(config->kexs,
- their_key_exchanges, num_their_key_exchanges,
- CryptoUtils::LOCAL_PRIORITY,
- &params->key_exchange,
- &key_exchange_index)) {
+ !CryptoUtils::FindMutualTag(
+ config->kexs, their_key_exchanges, num_their_key_exchanges,
+ CryptoUtils::LOCAL_PRIORITY, &params->key_exchange,
+ &key_exchange_index)) {
*error_details = "Unsupported AEAD or KEXS";
return QUIC_CRYPTO_NO_SUPPORT;
}
@@ -442,28 +450,67 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
- if (!config->key_exchanges[key_exchange_index]->CalculateSharedKey(
- public_value, &params->premaster_secret)) {
+ const KeyExchange* key_exchange = config->key_exchanges[key_exchange_index];
+ if (!key_exchange->CalculateSharedKey(public_value,
+ &params->initial_premaster_secret)) {
*error_details = "Invalid public value";
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
params->server_config_id = scid.as_string();
- string hkdf_input(QuicCryptoConfig::kLabel,
- strlen(QuicCryptoConfig::kLabel) + 1);
- hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid));
-
+ string hkdf_suffix;
const QuicData& client_hello_serialized = client_hello.GetSerialized();
- hkdf_input.append(client_hello_serialized.data(),
- client_hello_serialized.length());
- hkdf_input.append(config->serialized);
+ hkdf_suffix.reserve(sizeof(guid) + client_hello_serialized.length() +
+ config->serialized.size());
+ hkdf_suffix.append(reinterpret_cast<char*>(&guid), sizeof(guid));
+ hkdf_suffix.append(client_hello_serialized.data(),
+ client_hello_serialized.length());
+ hkdf_suffix.append(config->serialized);
+
+ string hkdf_input;
+ size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
+ hkdf_input.reserve(label_len + hkdf_suffix.size());
+ hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
+ hkdf_input.append(hkdf_suffix);
+
+ CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
+ client_nonce, params->server_nonce, hkdf_input,
+ CryptoUtils::SERVER, &params->initial_crypters);
+
+ string forward_secure_public_value;
+ if (ephemeral_key_source_.get()) {
+ params->forward_secure_premaster_secret =
+ ephemeral_key_source_->CalculateForwardSecureKey(
+ key_exchange, rand, clock->ApproximateNow(), public_value,
+ &forward_secure_public_value);
+ } else {
+ scoped_ptr<KeyExchange> forward_secure_key_exchange(
+ key_exchange->NewKeyPair(rand));
+ forward_secure_public_value =
+ forward_secure_key_exchange->public_value().as_string();
+ if (!forward_secure_key_exchange->CalculateSharedKey(
+ public_value, &params->forward_secure_premaster_secret)) {
+ *error_details = "Invalid public value";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ }
- CryptoUtils::DeriveKeys(params, client_nonce, hkdf_input,
- CryptoUtils::SERVER);
+ string forward_secure_hkdf_input;
+ label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
+ forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
+ forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
+ label_len);
+ forward_secure_hkdf_input.append(hkdf_suffix);
+
+ CryptoUtils::DeriveKeys(params->forward_secure_premaster_secret, params->aead,
+ client_nonce, params->server_nonce,
+ forward_secure_hkdf_input, CryptoUtils::SERVER,
+ &params->forward_secure_crypters);
out->set_tag(kSHLO);
- out->SetStringPiece(kSRCT, fresh_source_address_token);
+ out->SetStringPiece(kSourceAddressTokenTag, fresh_source_address_token);
+ out->SetStringPiece(kPUBS, forward_secure_public_value);
return QUIC_NO_ERROR;
}
@@ -471,19 +518,24 @@ void QuicCryptoServerConfig::SetProofSource(ProofSource* proof_source) {
proof_source_.reset(proof_source);
}
+void QuicCryptoServerConfig::SetEphemeralKeySource(
+ EphemeralKeySource* ephemeral_key_source) {
+ ephemeral_key_source_.reset(ephemeral_key_source);
+}
+
string QuicCryptoServerConfig::NewSourceAddressToken(
const IPEndPoint& ip,
QuicRandom* rand,
- QuicTime::Delta now_since_epoch) const {
+ QuicWallTime now) const {
SourceAddressToken source_address_token;
source_address_token.set_ip(ip.ToString());
- source_address_token.set_timestamp(now_since_epoch.ToSeconds());
+ source_address_token.set_timestamp(now.ToUNIXSeconds());
string plaintext = source_address_token.SerializeAsString();
char nonce[12];
DCHECK_EQ(sizeof(nonce),
- source_address_token_encrypter_->GetNoncePrefixSize() +
- sizeof(QuicPacketSequenceNumber));
+ source_address_token_encrypter_->GetNoncePrefixSize() +
+ sizeof(QuicPacketSequenceNumber));
rand->RandBytes(nonce, sizeof(nonce));
size_t ciphertext_size =
@@ -493,8 +545,8 @@ string QuicCryptoServerConfig::NewSourceAddressToken(
memcpy(&result[0], &nonce, sizeof(nonce));
if (!source_address_token_encrypter_->Encrypt(
- StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext,
- reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) {
+ StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext,
+ reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) {
DCHECK(false);
return string();
}
@@ -505,11 +557,11 @@ string QuicCryptoServerConfig::NewSourceAddressToken(
bool QuicCryptoServerConfig::ValidateSourceAddressToken(
StringPiece token,
const IPEndPoint& ip,
- QuicTime::Delta now_since_epoch) const {
+ QuicWallTime now) const {
char nonce[12];
DCHECK_EQ(sizeof(nonce),
- source_address_token_encrypter_->GetNoncePrefixSize() +
- sizeof(QuicPacketSequenceNumber));
+ source_address_token_encrypter_->GetNoncePrefixSize() +
+ sizeof(QuicPacketSequenceNumber));
if (token.size() <= sizeof(nonce)) {
return false;
@@ -529,8 +581,8 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
size_t plaintext_length;
if (!source_address_token_decrypter_->Decrypt(
- StringPiece(nonce, sizeof(nonce)), StringPiece(), token,
- plaintext, &plaintext_length)) {
+ StringPiece(nonce, sizeof(nonce)), StringPiece(), token, plaintext,
+ &plaintext_length)) {
return false;
}
@@ -544,18 +596,18 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
return false;
}
- const QuicTime::Delta delta(now_since_epoch.Subtract(
- QuicTime::Delta::FromSeconds(source_address_token.timestamp())));
- const int64 delta_secs = delta.ToSeconds();
+ const QuicWallTime timestamp(
+ QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
+ const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
// TODO(agl): consider whether and how these magic values should be moved to
// a config.
- if (delta_secs < -3600) {
+ if (now.IsBefore(timestamp) && delta.ToSeconds() > 3600) {
// We only allow timestamps to be from an hour in the future.
return false;
}
- if (delta_secs > 86400) {
+ if (now.IsAfter(timestamp) && delta.ToSeconds() > 86400) {
// We allow one day into the past.
return false;
}
@@ -563,11 +615,8 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
return true;
}
-QuicCryptoServerConfig::Config::Config() {
-}
+QuicCryptoServerConfig::Config::Config() {}
-QuicCryptoServerConfig::Config::~Config() {
- STLDeleteElements(&key_exchanges);
-}
+QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); }
} // namespace net
« no previous file with comments | « net/quic/crypto/crypto_server_config.h ('k') | net/quic/crypto/crypto_server_config_protobuf.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698