Commit 19886aaf authored by rtenneti@chromium.org's avatar rtenneti@chromium.org

QUIC Crypto - return the reasons for reject message. Reject reason

contains failures due to invalid source address token client nonce and
server nonce. Will add UMA histogram in chrome when this CL is merged.

Send reject reason to client for debugging purposes. Protected behind
new flags: FLAGS_use_early_return_when_verifying_chlo and
FLAGS_send_quic_crypto_reject_reason

Merge internal change: 69227401

R=jar@chromium.org, wtc@chromium.org, avd@google.com

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278523 0039d316-1c4b-4281-b951-d872f2087c98
parent 209a4cfc
...@@ -110,6 +110,9 @@ const QuicTag kRSEQ = TAG('R', 'S', 'E', 'Q'); // Rejected sequence number ...@@ -110,6 +110,9 @@ const QuicTag kRSEQ = TAG('R', 'S', 'E', 'Q'); // Rejected sequence number
// Universal tags // Universal tags
const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding
// Reasons for server sending rejection message tag.
const QuicTag kRREJ = TAG('R', 'R', 'E', 'J');
// These tags have a special form so that they appear either at the beginning // These tags have a special form so that they appear either at the beginning
// or the end of a handshake message. Since handshake messages are sorted by // or the end of a handshake message. Since handshake messages are sorted by
// tag value, the tags with 0 at the end will sort first and those with 255 at // tag value, the tags with 0 at the end will sort first and those with 255 at
......
This diff is collapsed.
...@@ -587,6 +587,17 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( ...@@ -587,6 +587,17 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
} }
} }
const QuicTag* reject_reasons;
size_t num_reject_reasons;
if (rej.GetTaglist(kRREJ, &reject_reasons,
&num_reject_reasons) == QUIC_NO_ERROR) {
#if defined(DEBUG)
for (size_t i = 0; i < num_reject_reasons; ++i) {
DVLOG(1) << "Reasons for rejection: " << reject_reasons[i];
}
#endif
}
return QUIC_NO_ERROR; return QUIC_NO_ERROR;
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "net/quic/crypto/strike_register.h" #include "net/quic/crypto/strike_register.h"
#include "net/quic/crypto/strike_register_client.h" #include "net/quic/crypto/strike_register_client.h"
#include "net/quic/quic_clock.h" #include "net/quic/quic_clock.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h" #include "net/quic/quic_protocol.h"
#include "net/quic/quic_socket_address_coder.h" #include "net/quic/quic_socket_address_coder.h"
#include "net/quic/quic_utils.h" #include "net/quic/quic_utils.h"
...@@ -81,6 +82,9 @@ struct ClientHelloInfo { ...@@ -81,6 +82,9 @@ struct ClientHelloInfo {
StringPiece client_nonce; StringPiece client_nonce;
StringPiece server_nonce; StringPiece server_nonce;
StringPiece user_agent_id; StringPiece user_agent_id;
// Errors from EvaluateClientHello.
vector<uint32> reject_reasons;
}; };
struct ValidateClientHelloResultCallback::Result { struct ValidateClientHelloResultCallback::Result {
...@@ -146,6 +150,12 @@ class VerifyNonceIsValidAndUniqueCallback ...@@ -146,6 +150,12 @@ class VerifyNonceIsValidAndUniqueCallback
virtual void RunImpl(bool nonce_is_valid_and_unique) OVERRIDE { virtual void RunImpl(bool nonce_is_valid_and_unique) OVERRIDE {
DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique; DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique;
result_->info.unique = nonce_is_valid_and_unique; 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));
}
done_cb_->Run(result_); done_cb_->Run(result_);
} }
...@@ -888,32 +898,65 @@ void QuicCryptoServerConfig::EvaluateClientHello( ...@@ -888,32 +898,65 @@ void QuicCryptoServerConfig::EvaluateClientHello(
client_hello.GetStringPiece(kUAID, &info->user_agent_id); client_hello.GetStringPiece(kUAID, &info->user_agent_id);
StringPiece srct; if (!requested_config.get()) {
if (requested_config.get() != NULL && StringPiece requested_scid;
client_hello.GetStringPiece(kSourceAddressTokenTag, &srct) && if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
ValidateSourceAddressToken(*requested_config, info->reject_reasons.push_back(
srct, static_cast<uint32>(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE));
info->client_ip, } else {
info->now)) { info->reject_reasons.push_back(
info->valid_source_address_token = true; static_cast<uint32>(SERVER_CONFIG_INCHOATE_HELLO_FAILURE));
} else { }
// No server config with the requested ID, or no valid source address token. // No server config with the requested ID.
helper.ValidationComplete(QUIC_NO_ERROR, ""); helper.ValidationComplete(QUIC_NO_ERROR, "");
return; return;
} }
HandshakeFailureReason source_address_token_error;
StringPiece srct;
if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
source_address_token_error =
ValidateSourceAddressToken(*requested_config,
srct,
info->client_ip,
info->now);
info->valid_source_address_token =
(source_address_token_error == HANDSHAKE_OK);
} else {
source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
}
bool found_error = false;
if (source_address_token_error != HANDSHAKE_OK) {
info->reject_reasons.push_back(
static_cast<uint32>(source_address_token_error));
// No valid source address token.
if (FLAGS_use_early_return_when_verifying_chlo) {
helper.ValidationComplete(QUIC_NO_ERROR, "");
return;
}
found_error = true;
}
if (client_hello.GetStringPiece(kNONC, &info->client_nonce) && if (client_hello.GetStringPiece(kNONC, &info->client_nonce) &&
info->client_nonce.size() == kNonceSize) { info->client_nonce.size() == kNonceSize) {
info->client_nonce_well_formed = true; info->client_nonce_well_formed = true;
} else { } else {
info->reject_reasons.push_back(
static_cast<uint32>(CLIENT_NONCE_INVALID_FAILURE));
// Invalid client nonce. // Invalid client nonce.
DVLOG(1) << "Invalid client nonce."; DVLOG(1) << "Invalid client nonce.";
helper.ValidationComplete(QUIC_NO_ERROR, ""); if (FLAGS_use_early_return_when_verifying_chlo) {
return; helper.ValidationComplete(QUIC_NO_ERROR, "");
return;
}
found_error = true;
} }
if (!replay_protection_) { if (!replay_protection_) {
info->unique = true; if (!found_error) {
info->unique = true;
}
DVLOG(1) << "No replay protection."; DVLOG(1) << "No replay protection.";
helper.ValidationComplete(QUIC_NO_ERROR, ""); helper.ValidationComplete(QUIC_NO_ERROR, "");
return; return;
...@@ -922,12 +965,26 @@ void QuicCryptoServerConfig::EvaluateClientHello( ...@@ -922,12 +965,26 @@ void QuicCryptoServerConfig::EvaluateClientHello(
client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce); client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
if (!info->server_nonce.empty()) { if (!info->server_nonce.empty()) {
// If the server nonce is present, use it to establish uniqueness. // If the server nonce is present, use it to establish uniqueness.
info->unique = ValidateServerNonce(info->server_nonce, info->now); HandshakeFailureReason server_nonce_error =
ValidateServerNonce(info->server_nonce, info->now);
if (server_nonce_error == HANDSHAKE_OK) {
info->unique = true;
} else {
info->reject_reasons.push_back(static_cast<uint32>(server_nonce_error));
info->unique = false;
}
DVLOG(1) << "Using server nonce, unique: " << info->unique; DVLOG(1) << "Using server nonce, unique: " << info->unique;
helper.ValidationComplete(QUIC_NO_ERROR, ""); helper.ValidationComplete(QUIC_NO_ERROR, "");
return; return;
} }
// We want to contact strike register if there are no errors because it is
// a RPC call and is expensive.
if (found_error) {
helper.ValidationComplete(QUIC_NO_ERROR, "");
return;
}
// Use the client nonce to establish uniqueness. // Use the client nonce to establish uniqueness.
StrikeRegisterClient* strike_register_client; StrikeRegisterClient* strike_register_client;
{ {
...@@ -971,6 +1028,12 @@ void QuicCryptoServerConfig::BuildRejection( ...@@ -971,6 +1028,12 @@ void QuicCryptoServerConfig::BuildRejection(
out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now)); out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now));
} }
if (FLAGS_send_quic_crypto_reject_reason) {
// Send client the reject reason for debugging purposes.
DCHECK_LT(0u, info.reject_reasons.size());
out->SetVector(kRREJ, info.reject_reasons);
}
// The client may have requested a certificate chain. // The client may have requested a certificate chain.
const QuicTag* their_proof_demands; const QuicTag* their_proof_demands;
size_t num_their_proof_demands; size_t num_their_proof_demands;
...@@ -1288,7 +1351,7 @@ string QuicCryptoServerConfig::NewSourceAddressToken(const Config& config, ...@@ -1288,7 +1351,7 @@ string QuicCryptoServerConfig::NewSourceAddressToken(const Config& config,
rand, source_address_token.SerializeAsString()); rand, source_address_token.SerializeAsString());
} }
bool QuicCryptoServerConfig::ValidateSourceAddressToken( HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressToken(
const Config& config, const Config& config,
StringPiece token, StringPiece token,
const IPEndPoint& ip, const IPEndPoint& ip,
...@@ -1296,13 +1359,13 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken( ...@@ -1296,13 +1359,13 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
string storage; string storage;
StringPiece plaintext; StringPiece plaintext;
if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) { if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
return false; return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
} }
SourceAddressToken source_address_token; SourceAddressToken source_address_token;
if (!source_address_token.ParseFromArray(plaintext.data(), if (!source_address_token.ParseFromArray(plaintext.data(),
plaintext.size())) { plaintext.size())) {
return false; return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
} }
IPAddressNumber ip_address = ip.address(); IPAddressNumber ip_address = ip.address();
...@@ -1311,7 +1374,7 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken( ...@@ -1311,7 +1374,7 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
} }
if (source_address_token.ip() != IPAddressToPackedString(ip_address)) { if (source_address_token.ip() != IPAddressToPackedString(ip_address)) {
// It's for a different IP address. // It's for a different IP address.
return false; return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
} }
const QuicWallTime timestamp( const QuicWallTime timestamp(
...@@ -1320,15 +1383,15 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken( ...@@ -1320,15 +1383,15 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
if (now.IsBefore(timestamp) && if (now.IsBefore(timestamp) &&
delta.ToSeconds() > source_address_token_future_secs_) { delta.ToSeconds() > source_address_token_future_secs_) {
return false; return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
} }
if (now.IsAfter(timestamp) && if (now.IsAfter(timestamp) &&
delta.ToSeconds() > source_address_token_lifetime_secs_) { delta.ToSeconds() > source_address_token_lifetime_secs_) {
return false; return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
} }
return true; return HANDSHAKE_OK;
} }
// kServerNoncePlaintextSize is the number of bytes in an unencrypted server // kServerNoncePlaintextSize is the number of bytes in an unencrypted server
...@@ -1354,12 +1417,13 @@ string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand, ...@@ -1354,12 +1417,13 @@ string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce))); StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce)));
} }
bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token, HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce(
QuicWallTime now) const { StringPiece token,
QuicWallTime now) const {
string storage; string storage;
StringPiece plaintext; StringPiece plaintext;
if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) { if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) {
return false; return SERVER_NONCE_DECRYPTION_FAILURE;
} }
// plaintext contains: // plaintext contains:
...@@ -1369,7 +1433,7 @@ bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token, ...@@ -1369,7 +1433,7 @@ bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token,
if (plaintext.size() != kServerNoncePlaintextSize) { if (plaintext.size() != kServerNoncePlaintextSize) {
// This should never happen because the value decrypted correctly. // This should never happen because the value decrypted correctly.
LOG(DFATAL) << "Seemingly valid server nonce had incorrect length."; LOG(DFATAL) << "Seemingly valid server nonce had incorrect length.";
return false; return SERVER_NONCE_INVALID_FAILURE;
} }
uint8 server_nonce[32]; uint8 server_nonce[32];
...@@ -1394,7 +1458,7 @@ bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token, ...@@ -1394,7 +1458,7 @@ bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token,
server_nonce, static_cast<uint32>(now.ToUNIXSeconds())); server_nonce, static_cast<uint32>(now.ToUNIXSeconds()));
} }
return is_unique; return is_unique ? HANDSHAKE_OK : SERVER_NONCE_NOT_UNIQUE_FAILURE;
} }
QuicCryptoServerConfig::Config::Config() QuicCryptoServerConfig::Config::Config()
......
...@@ -40,6 +40,32 @@ namespace test { ...@@ -40,6 +40,32 @@ namespace test {
class QuicCryptoServerConfigPeer; class QuicCryptoServerConfigPeer;
} // namespace test } // namespace test
enum HandshakeFailureReason {
HANDSHAKE_OK = 0,
// Failure reasons for an invalid client nonce.
// TODO(rtenneti): Implement capturing of error from strike register.
CLIENT_NONCE_UNKNOWN_FAILURE = 100,
CLIENT_NONCE_INVALID_FAILURE,
// Failure reasons for an invalid server nonce.
SERVER_NONCE_INVALID_FAILURE = 200,
SERVER_NONCE_DECRYPTION_FAILURE,
SERVER_NONCE_NOT_UNIQUE_FAILURE,
// Failure reasons for an invalid server config.
SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 300,
SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE,
// Failure reasons for an invalid source adddress token.
SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 400,
SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
SOURCE_ADDRESS_TOKEN_PARSE_FAILURE,
SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
};
// Hook that allows application code to subscribe to primary config changes. // Hook that allows application code to subscribe to primary config changes.
class PrimaryConfigChangedCallback { class PrimaryConfigChangedCallback {
public: public:
...@@ -385,13 +411,13 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { ...@@ -385,13 +411,13 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
QuicRandom* rand, QuicRandom* rand,
QuicWallTime now) const; QuicWallTime now) const;
// ValidateSourceAddressToken returns true if the source address token in // ValidateSourceAddressToken returns HANDSHAKE_OK if the source address token
// |token| is a valid and timely token for the IP address |ip| given that the // in |token| is a valid and timely token for the IP address |ip| given that
// current time is |now|. // the current time is |now|. Otherwise it returns the reason for failure.
bool ValidateSourceAddressToken(const Config& config, HandshakeFailureReason ValidateSourceAddressToken(const Config& config,
base::StringPiece token, base::StringPiece token,
const IPEndPoint& ip, const IPEndPoint& ip,
QuicWallTime now) const; QuicWallTime now) const;
// NewServerNonce generates and encrypts a random nonce. // NewServerNonce generates and encrypts a random nonce.
std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const; std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const;
...@@ -399,10 +425,11 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { ...@@ -399,10 +425,11 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// ValidateServerNonce decrypts |token| and verifies that it hasn't been // ValidateServerNonce decrypts |token| and verifies that it hasn't been
// previously used and is recent enough that it is plausible that it was part // previously used and is recent enough that it is plausible that it was part
// of a very recently provided rejection ("recent" will be on the order of // of a very recently provided rejection ("recent" will be on the order of
// 10-30 seconds). If so, it records that it has been used and returns true. // 10-30 seconds). If so, it records that it has been used and returns
// Otherwise it returns false. // HANDSHAKE_OK. Otherwise it returns the reason for failure.
bool ValidateServerNonce(base::StringPiece echoed_server_nonce, HandshakeFailureReason ValidateServerNonce(
QuicWallTime now) const; base::StringPiece echoed_server_nonce,
QuicWallTime now) const;
// replay_protection_ controls whether the server enforces that handshakes // replay_protection_ controls whether the server enforces that handshakes
// aren't replays. // aren't replays.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/crypto_handshake_message.h" #include "net/quic/crypto/crypto_handshake_message.h"
#include "net/quic/crypto/crypto_secret_boxer.h"
#include "net/quic/crypto/crypto_server_config_protobuf.h" #include "net/quic/crypto/crypto_server_config_protobuf.h"
#include "net/quic/crypto/quic_random.h" #include "net/quic/crypto/quic_random.h"
#include "net/quic/crypto/strike_register_client.h" #include "net/quic/crypto/strike_register_client.h"
...@@ -58,14 +59,23 @@ class QuicCryptoServerConfigPeer { ...@@ -58,14 +59,23 @@ class QuicCryptoServerConfigPeer {
*GetConfig(config_id), ip, rand, now); *GetConfig(config_id), ip, rand, now);
} }
bool ValidateSourceAddressToken(string config_id, HandshakeFailureReason ValidateSourceAddressToken(string config_id,
StringPiece srct, StringPiece srct,
IPEndPoint ip, IPEndPoint ip,
QuicWallTime now) { QuicWallTime now) {
return server_config_->ValidateSourceAddressToken( return server_config_->ValidateSourceAddressToken(
*GetConfig(config_id), srct, ip, now); *GetConfig(config_id), srct, ip, now);
} }
string NewServerNonce(QuicRandom* rand, QuicWallTime now) const {
return server_config_->NewServerNonce(rand, now);
}
HandshakeFailureReason ValidateServerNonce(StringPiece token,
QuicWallTime now) {
return server_config_->ValidateServerNonce(token, now);
}
base::Lock* GetStrikeRegisterClientLock() { base::Lock* GetStrikeRegisterClientLock() {
return &server_config_->strike_register_client_lock_; return &server_config_->strike_register_client_lock_;
} }
...@@ -270,41 +280,84 @@ TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { ...@@ -270,41 +280,84 @@ TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
const string token4 = peer.NewSourceAddressToken(kPrimary, ip4, rand, now); const string token4 = peer.NewSourceAddressToken(kPrimary, ip4, rand, now);
const string token4d = peer.NewSourceAddressToken(kPrimary, ip4d, rand, now); const string token4d = peer.NewSourceAddressToken(kPrimary, ip4d, rand, now);
const string token6 = peer.NewSourceAddressToken(kPrimary, ip6, rand, now); const string token6 = peer.NewSourceAddressToken(kPrimary, ip6, rand, now);
EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now)); EXPECT_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4d, now)); kPrimary, token4, ip4, now));
EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4, ip6, now)); DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip4, now)); kPrimary, token4, ip4d, now));
EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip4d, now)); DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip6, now)); peer.ValidateSourceAddressToken(kPrimary, token4, ip6, now));
EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token6, ip6, now)); DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
kPrimary, token4d, ip4, now));
DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
kPrimary, token4d, ip4d, now));
DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
peer.ValidateSourceAddressToken(kPrimary, token4d, ip6, now));
DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
kPrimary, token6, ip6, now));
// Override config generates configs that validate successfully. // Override config generates configs that validate successfully.
const string override_token4 = peer.NewSourceAddressToken( const string override_token4 = peer.NewSourceAddressToken(
kOverride, ip4, rand, now); kOverride, ip4, rand, now);
const string override_token6 = peer.NewSourceAddressToken( const string override_token6 = peer.NewSourceAddressToken(
kOverride, ip6, rand, now); kOverride, ip6, rand, now);
EXPECT_TRUE(peer.ValidateSourceAddressToken( DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
kOverride, override_token4, ip4, now)); kOverride, override_token4, ip4, now));
EXPECT_FALSE(peer.ValidateSourceAddressToken( DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
kOverride, override_token4, ip6, now)); peer.ValidateSourceAddressToken(kOverride, override_token4, ip6,
EXPECT_TRUE(peer.ValidateSourceAddressToken( now));
DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
kOverride, override_token6, ip6, now)); kOverride, override_token6, ip6, now));
// Tokens generated by the primary config do not validate // Tokens generated by the primary config do not validate
// successfully against the override config, and vice versa. // successfully against the override config, and vice versa.
EXPECT_FALSE(peer.ValidateSourceAddressToken(kOverride, token4, ip4, now)); DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
EXPECT_FALSE(peer.ValidateSourceAddressToken(kOverride, token6, ip6, now)); peer.ValidateSourceAddressToken(kOverride, token4, ip4, now));
EXPECT_FALSE(peer.ValidateSourceAddressToken( DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
kPrimary, override_token4, ip4, now)); peer.ValidateSourceAddressToken(kOverride, token6, ip6, now));
EXPECT_FALSE(peer.ValidateSourceAddressToken( DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
kPrimary, override_token6, ip6, now)); peer.ValidateSourceAddressToken(kPrimary, override_token4, ip4,
now));
DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
peer.ValidateSourceAddressToken(kPrimary, override_token6, ip6,
now));
// Validation fails after tokens expire. // Validation fails after tokens expire.
now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7)); now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7));
EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now)); DCHECK_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now));
now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2)); now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2));
EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now)); DCHECK_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now));
}
TEST(QuicCryptoServerConfigTest, ValidateServerNonce) {
QuicRandom* rand = QuicRandom::GetInstance();
QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
QuicCryptoServerConfigPeer peer(&server);
StringPiece message("hello world");
const size_t key_size = CryptoSecretBoxer::GetKeySize();
scoped_ptr<uint8[]> key(new uint8[key_size]);
memset(key.get(), 0x11, key_size);
CryptoSecretBoxer boxer;
boxer.SetKey(StringPiece(reinterpret_cast<char*>(key.get()), key_size));
const string box = boxer.Box(rand, message);
MockClock clock;
QuicWallTime now = clock.WallNow();
const QuicWallTime original_time = now;
EXPECT_EQ(SERVER_NONCE_DECRYPTION_FAILURE,
peer.ValidateServerNonce(box, now));
string server_nonce = peer.NewServerNonce(rand, now);
EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
EXPECT_EQ(SERVER_NONCE_NOT_UNIQUE_FAILURE,
peer.ValidateServerNonce(server_nonce, now));
now = original_time.Add(QuicTime::Delta::FromSeconds(1000 * 7));
server_nonce = peer.NewServerNonce(rand, now);
EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
} }
class CryptoServerConfigsTest : public ::testing::Test { class CryptoServerConfigsTest : public ::testing::Test {
......
...@@ -39,3 +39,10 @@ bool FLAGS_quic_use_time_loss_detection = false; ...@@ -39,3 +39,10 @@ bool FLAGS_quic_use_time_loss_detection = false;
// If true, allow peer port migration of established QUIC connections. // If true, allow peer port migration of established QUIC connections.
bool FLAGS_quic_allow_port_migration = true; bool FLAGS_quic_allow_port_migration = true;
// If true, it will return as soon as an error is detected while validating
// CHLO.
bool FLAGS_use_early_return_when_verifying_chlo = true;
// If true, QUIC crypto reject message will include the reasons for rejection.
bool FLAGS_send_quic_crypto_reject_reason = false;
...@@ -14,5 +14,7 @@ NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_connection_flow_control_2; ...@@ -14,5 +14,7 @@ NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_connection_flow_control_2;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_oversized_packets_for_test; NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_oversized_packets_for_test;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_time_loss_detection; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_time_loss_detection;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_port_migration; NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_port_migration;
NET_EXPORT_PRIVATE extern bool FLAGS_use_early_return_when_verifying_chlo;
NET_EXPORT_PRIVATE extern bool FLAGS_send_quic_crypto_reject_reason;
#endif // NET_QUIC_QUIC_FLAGS_H_ #endif // NET_QUIC_QUIC_FLAGS_H_
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