StringPiece() /* no salt */,
"QUIC source address token key",
CryptoSecretBoxer::GetKeySize(),
- 0 /* no fixed IV needed */);
+ 0 /* no fixed IV needed */,
+ 0 /* no subkey secret */);
return hkdf.server_write_key().as_string();
}
// Errors from EvaluateClientHello.
vector<uint32> reject_reasons;
+ COMPILE_ASSERT(sizeof(QuicTag) == sizeof(uint32), header_out_of_sync);
};
struct ValidateClientHelloResultCallback::Result {
}
protected:
- virtual void RunImpl(bool nonce_is_valid_and_unique) OVERRIDE {
- DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique;
+ virtual void RunImpl(bool nonce_is_valid_and_unique,
+ InsertStatus nonce_error) OVERRIDE {
+ DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique
+ << " nonce_error: " << nonce_error;
result_->info.unique = nonce_is_valid_and_unique;
- // TODO(rtenneti): Implement capturing of error from strike register.
- // Temporarily treat them as CLIENT_NONCE_UNKNOWN_FAILURE.
if (!nonce_is_valid_and_unique) {
- result_->info.reject_reasons.push_back(
- static_cast<uint32>(CLIENT_NONCE_UNKNOWN_FAILURE));
+ HandshakeFailureReason client_nonce_error;
+ switch (nonce_error) {
+ case NONCE_INVALID_FAILURE:
+ client_nonce_error = CLIENT_NONCE_INVALID_FAILURE;
+ break;
+ case NONCE_NOT_UNIQUE_FAILURE:
+ client_nonce_error = CLIENT_NONCE_NOT_UNIQUE_FAILURE;
+ break;
+ case NONCE_INVALID_ORBIT_FAILURE:
+ client_nonce_error = CLIENT_NONCE_INVALID_ORBIT_FAILURE;
+ break;
+ case NONCE_INVALID_TIME_FAILURE:
+ client_nonce_error = CLIENT_NONCE_INVALID_TIME_FAILURE;
+ break;
+ case STRIKE_REGISTER_TIMEOUT:
+ client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT;
+ break;
+ case STRIKE_REGISTER_FAILURE:
+ client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_FAILURE;
+ break;
+ case NONCE_UNKNOWN_FAILURE:
+ client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
+ break;
+ case NONCE_OK:
+ default:
+ LOG(DFATAL) << "Unexpected client nonce error: " << nonce_error;
+ client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
+ break;
+ }
+ result_->info.reject_reasons.push_back(client_nonce_error);
}
done_cb_->Run(result_);
}
configs_.swap(new_configs);
SelectNewPrimaryConfig(now);
- DCHECK(primary_config_);
+ DCHECK(primary_config_.get());
DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
}
if (!next_config_promotion_time_.IsZero() &&
next_config_promotion_time_.IsAfter(now)) {
SelectNewPrimaryConfig(now);
- DCHECK(primary_config_);
- DCHECK(configs_.find(primary_config_->id)->second == primary_config_);
+ DCHECK(primary_config_.get());
+ DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
}
memcpy(primary_orbit, primary_config_->orbit, sizeof(primary_orbit));
if (!next_config_promotion_time_.IsZero() &&
next_config_promotion_time_.IsAfter(now)) {
SelectNewPrimaryConfig(now);
- DCHECK(primary_config_);
- DCHECK(configs_.find(primary_config_->id)->second == primary_config_);
+ DCHECK(primary_config_.get());
+ DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
}
// We'll use the config that the client requested in order to do
!info.client_nonce_well_formed ||
!info.unique ||
!requested_config.get()) {
- BuildRejection(*primary_config, client_hello, info, rand, out);
+ BuildRejection(*primary_config, client_hello, info, rand, params, out);
return QUIC_NO_ERROR;
}
CrypterPair crypters;
if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
info.client_nonce, info.server_nonce,
- hkdf_input, CryptoUtils::SERVER, &crypters)) {
+ hkdf_input, CryptoUtils::SERVER, &crypters,
+ NULL /* subkey secret */)) {
*error_details = "Symmetric key setup failed";
return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
}
if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
info.client_nonce, info.server_nonce, hkdf_input,
CryptoUtils::SERVER,
- ¶ms->initial_crypters)) {
+ ¶ms->initial_crypters,
+ NULL /* subkey secret */)) {
*error_details = "Symmetric key setup failed";
return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
}
if (!CryptoUtils::DeriveKeys(
params->forward_secure_premaster_secret, params->aead,
info.client_nonce, info.server_nonce, forward_secure_hkdf_input,
- CryptoUtils::SERVER, ¶ms->forward_secure_crypters)) {
+ CryptoUtils::SERVER, ¶ms->forward_secure_crypters,
+ ¶ms->subkey_secret)) {
*error_details = "Symmetric key setup failed";
return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
}
if (!requested_config.get()) {
StringPiece requested_scid;
if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
- info->reject_reasons.push_back(
- static_cast<uint32>(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE));
+ info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
} else {
- info->reject_reasons.push_back(
- static_cast<uint32>(SERVER_CONFIG_INCHOATE_HELLO_FAILURE));
+ info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
}
// No server config with the requested ID.
helper.ValidationComplete(QUIC_NO_ERROR, "");
bool found_error = false;
if (source_address_token_error != HANDSHAKE_OK) {
- info->reject_reasons.push_back(
- static_cast<uint32>(source_address_token_error));
+ info->reject_reasons.push_back(source_address_token_error);
// No valid source address token.
if (FLAGS_use_early_return_when_verifying_chlo) {
helper.ValidationComplete(QUIC_NO_ERROR, "");
info->client_nonce.size() == kNonceSize) {
info->client_nonce_well_formed = true;
} else {
- info->reject_reasons.push_back(
- static_cast<uint32>(CLIENT_NONCE_INVALID_FAILURE));
+ info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
// Invalid client nonce.
DVLOG(1) << "Invalid client nonce.";
if (FLAGS_use_early_return_when_verifying_chlo) {
if (server_nonce_error == HANDSHAKE_OK) {
info->unique = true;
} else {
- info->reject_reasons.push_back(static_cast<uint32>(server_nonce_error));
+ info->reject_reasons.push_back(server_nonce_error);
info->unique = false;
}
DVLOG(1) << "Using server nonce, unique: " << info->unique;
return;
}
- // We want to contact strike register if there are no errors because it is
- // a RPC call and is expensive.
+ // We want to contact strike register only if there are no errors because it
+ // is a RPC call and is expensive.
if (found_error) {
helper.ValidationComplete(QUIC_NO_ERROR, "");
return;
helper.StartedAsyncCallback();
}
+bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
+ const IPEndPoint& client_ip,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ const QuicCryptoNegotiatedParameters& params,
+ CryptoHandshakeMessage* out) const {
+ base::AutoLock locked(configs_lock_);
+ out->set_tag(kSCUP);
+ out->SetStringPiece(kSCFG, primary_config_->serialized);
+ out->SetStringPiece(kSourceAddressTokenTag,
+ NewSourceAddressToken(*primary_config_,
+ client_ip,
+ rand,
+ clock->WallNow()));
+
+ if (proof_source_ == NULL) {
+ // Insecure QUIC, can send SCFG without proof.
+ return true;
+ }
+
+ const vector<string>* certs;
+ string signature;
+ if (!proof_source_->GetProof(params.sni, primary_config_->serialized,
+ params.x509_ecdsa_supported, &certs,
+ &signature)) {
+ DVLOG(1) << "Server: failed to get proof.";
+ return false;
+ }
+
+ const string compressed = CertCompressor::CompressChain(
+ *certs, params.client_common_set_hashes, params.client_cached_cert_hashes,
+ primary_config_->common_cert_sets);
+
+ out->SetStringPiece(kCertificateTag, compressed);
+ out->SetStringPiece(kPROF, signature);
+ return true;
+}
+
void QuicCryptoServerConfig::BuildRejection(
const Config& config,
const CryptoHandshakeMessage& client_hello,
const ClientHelloInfo& info,
QuicRandom* rand,
+ QuicCryptoNegotiatedParameters *params,
CryptoHandshakeMessage* out) const {
out->set_tag(kREJ);
out->SetStringPiece(kSCFG, config.serialized);
return;
}
- bool x509_supported = false, x509_ecdsa_supported = false;
+ bool x509_supported = false;
for (size_t i = 0; i < num_their_proof_demands; i++) {
switch (their_proof_demands[i]) {
case kX509:
x509_supported = true;
- x509_ecdsa_supported = true;
+ params->x509_ecdsa_supported = true;
break;
case kX59R:
x509_supported = true;
const vector<string>* certs;
string signature;
if (!proof_source_->GetProof(info.sni.as_string(), config.serialized,
- x509_ecdsa_supported, &certs, &signature)) {
+ params->x509_ecdsa_supported, &certs,
+ &signature)) {
return;
}
- StringPiece their_common_set_hashes;
- StringPiece their_cached_cert_hashes;
- client_hello.GetStringPiece(kCCS, &their_common_set_hashes);
- client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes);
+ StringPiece client_common_set_hashes;
+ if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) {
+ params->client_common_set_hashes = client_common_set_hashes.as_string();
+ }
+
+ StringPiece client_cached_cert_hashes;
+ if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) {
+ params->client_cached_cert_hashes = client_cached_cert_hashes.as_string();
+ }
const string compressed = CertCompressor::CompressChain(
- *certs, their_common_set_hashes, their_cached_cert_hashes,
- config.common_cert_sets);
+ *certs, params->client_common_set_hashes,
+ params->client_cached_cert_hashes, config.common_cert_sets);
// kREJOverheadBytes is a very rough estimate of how much of a REJ
// message is taken up by things other than the certificates.
COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce),
bad_nonce_buffer_length);
- bool is_unique;
+ InsertStatus nonce_error;
{
base::AutoLock auto_lock(server_nonce_strike_register_lock_);
if (server_nonce_strike_register_.get() == NULL) {
server_nonce_strike_register_window_secs_, server_nonce_orbit_,
StrikeRegister::NO_STARTUP_PERIOD_NEEDED));
}
- is_unique = server_nonce_strike_register_->Insert(
+ nonce_error = server_nonce_strike_register_->Insert(
server_nonce, static_cast<uint32>(now.ToUNIXSeconds()));
}
- return is_unique ? HANDSHAKE_OK : SERVER_NONCE_NOT_UNIQUE_FAILURE;
+ switch (nonce_error) {
+ case NONCE_OK:
+ return HANDSHAKE_OK;
+ case NONCE_INVALID_FAILURE:
+ case NONCE_INVALID_ORBIT_FAILURE:
+ return SERVER_NONCE_INVALID_FAILURE;
+ case NONCE_NOT_UNIQUE_FAILURE:
+ return SERVER_NONCE_NOT_UNIQUE_FAILURE;
+ case NONCE_INVALID_TIME_FAILURE:
+ return SERVER_NONCE_INVALID_TIME_FAILURE;
+ case NONCE_UNKNOWN_FAILURE:
+ case STRIKE_REGISTER_TIMEOUT:
+ case STRIKE_REGISTER_FAILURE:
+ default:
+ LOG(DFATAL) << "Unexpected server nonce error: " << nonce_error;
+ return SERVER_NONCE_NOT_UNIQUE_FAILURE;
+ }
}
QuicCryptoServerConfig::Config::Config()