Commit 44594085 authored by rtenneti@chromium.org's avatar rtenneti@chromium.org

Reject reasons from strike register when nonce validation fails.

Send reject reason to client for debugging purposes.

Merge internal change: 70366491

R=wtc@chromium.org

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@283692 0039d316-1c4b-4281-b951-d872f2087c98
parent d4b87557
...@@ -26,49 +26,54 @@ enum HandshakeFailureReason { ...@@ -26,49 +26,54 @@ enum HandshakeFailureReason {
// Failure reasons for an invalid client nonce in CHLO. // Failure reasons for an invalid client nonce in CHLO.
// //
// The default error value for nonce verification failures from strike
// register (covers old strike registers and unknown failures).
CLIENT_NONCE_UNKNOWN_FAILURE = 1,
// Client nonce had incorrect length. // Client nonce had incorrect length.
CLIENT_NONCE_INVALID_FAILURE = 1, CLIENT_NONCE_INVALID_FAILURE = 2,
// Client nonce is not unique. // Client nonce is not unique.
CLIENT_NONCE_NOT_UNIQUE_FAILURE = 2, CLIENT_NONCE_NOT_UNIQUE_FAILURE = 3,
// Client orbit is invalid or incorrect. // Client orbit is invalid or incorrect.
CLIENT_NONCE_INVALID_ORBIT_FAILURE = 3, CLIENT_NONCE_INVALID_ORBIT_FAILURE = 4,
// Client nonce's timestamp is not in the strike register's valid time range. // Client nonce's timestamp is not in the strike register's valid time range.
CLIENT_NONCE_INVALID_TIME_FAILURE = 4, CLIENT_NONCE_INVALID_TIME_FAILURE = 5,
// Client nonce verification has failed because strike register is down. // Strike register's RPC call timed out, client nonce couldn't be verified.
CLIENT_NONCE_NO_STRIKE_REGISTER_FAILURE = 5, CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT = 6,
// Strike register is down, client nonce couldn't be verified.
CLIENT_NONCE_STRIKE_REGISTER_FAILURE = 7,
// Failure reasons for an invalid server nonce in CHLO. // Failure reasons for an invalid server nonce in CHLO.
// //
// Unbox of server nonce failed. // Unbox of server nonce failed.
SERVER_NONCE_DECRYPTION_FAILURE = 6, SERVER_NONCE_DECRYPTION_FAILURE = 8,
// Decrypted server nonce had incorrect length. // Decrypted server nonce had incorrect length.
SERVER_NONCE_INVALID_FAILURE = 7, SERVER_NONCE_INVALID_FAILURE = 9,
// Server nonce is not unique. // Server nonce is not unique.
SERVER_NONCE_NOT_UNIQUE_FAILURE = 8, SERVER_NONCE_NOT_UNIQUE_FAILURE = 10,
// Server nonce's timestamp is not in the strike register's valid time range. // Server nonce's timestamp is not in the strike register's valid time range.
SERVER_NONCE_INVALID_TIME_FAILURE = 9, SERVER_NONCE_INVALID_TIME_FAILURE = 11,
// Failure reasons for an invalid server config in CHLO. // Failure reasons for an invalid server config in CHLO.
// //
// Missing Server config id (kSCID) tag. // Missing Server config id (kSCID) tag.
SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 10, SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 12,
// Couldn't find the Server config id (kSCID). // Couldn't find the Server config id (kSCID).
SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE = 11, SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE = 13,
// Failure reasons for an invalid source-address token. // Failure reasons for an invalid source-address token.
// //
// Missing Source-address token (kSourceAddressTokenTag) tag. // Missing Source-address token (kSourceAddressTokenTag) tag.
SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 12, SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 14,
// Unbox of Source-address token failed. // Unbox of Source-address token failed.
SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE = 13, SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE = 15,
// Couldn't parse the unbox'ed Source-address token. // Couldn't parse the unbox'ed Source-address token.
SOURCE_ADDRESS_TOKEN_PARSE_FAILURE = 14, SOURCE_ADDRESS_TOKEN_PARSE_FAILURE = 16,
// Source-address token is for a different IP address. // Source-address token is for a different IP address.
SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE = 15, SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE = 17,
// The source-address token has a timestamp in the future. // The source-address token has a timestamp in the future.
SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE = 16, SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE = 18,
// The source-address token has expired. // The source-address token has expired.
SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE = 17, SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE = 19,
MAX_FAILURE_REASON, MAX_FAILURE_REASON,
}; };
......
...@@ -365,7 +365,7 @@ TEST_F(CryptoServerTest, DISABLED_DefaultCert) { ...@@ -365,7 +365,7 @@ TEST_F(CryptoServerTest, DISABLED_DefaultCert) {
EXPECT_NE(0u, cert.size()); EXPECT_NE(0u, cert.size());
EXPECT_NE(0u, proof.size()); EXPECT_NE(0u, proof.size());
const HandshakeFailureReason kRejectReasons[] = { const HandshakeFailureReason kRejectReasons[] = {
CLIENT_NONCE_INVALID_FAILURE CLIENT_NONCE_INVALID_TIME_FAILURE
}; };
CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
} }
...@@ -551,7 +551,7 @@ TEST_P(CryptoServerTest, ReplayProtection) { ...@@ -551,7 +551,7 @@ TEST_P(CryptoServerTest, ReplayProtection) {
ASSERT_EQ(kREJ, out_.tag()); ASSERT_EQ(kREJ, out_.tag());
const HandshakeFailureReason kRejectReasons[] = { const HandshakeFailureReason kRejectReasons[] = {
CLIENT_NONCE_INVALID_FAILURE CLIENT_NONCE_INVALID_TIME_FAILURE
}; };
CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
...@@ -652,7 +652,7 @@ TEST_P(CryptoServerTestNoConfig, DontCrash) { ...@@ -652,7 +652,7 @@ TEST_P(CryptoServerTestNoConfig, DontCrash) {
NULL)); NULL));
const HandshakeFailureReason kRejectReasons[] = { const HandshakeFailureReason kRejectReasons[] = {
CLIENT_NONCE_INVALID_FAILURE SERVER_CONFIG_INCHOATE_HELLO_FAILURE
}; };
CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
} }
......
...@@ -30,19 +30,21 @@ bool LocalStrikeRegisterClient::IsKnownOrbit(StringPiece orbit) const { ...@@ -30,19 +30,21 @@ bool LocalStrikeRegisterClient::IsKnownOrbit(StringPiece orbit) const {
} }
void LocalStrikeRegisterClient::VerifyNonceIsValidAndUnique( void LocalStrikeRegisterClient::VerifyNonceIsValidAndUnique(
StringPiece nonce, QuicWallTime now, ResultCallback* cb) { StringPiece nonce,
bool nonce_is_valid_and_unique; QuicWallTime now,
ResultCallback* cb) {
InsertStatus nonce_error;
if (nonce.length() != kNonceSize) { if (nonce.length() != kNonceSize) {
nonce_is_valid_and_unique = false; nonce_error = NONCE_INVALID_FAILURE;
} else { } else {
base::AutoLock lock(m_); base::AutoLock lock(m_);
nonce_is_valid_and_unique = strike_register_.Insert( nonce_error = strike_register_.Insert(
reinterpret_cast<const uint8*>(nonce.data()), reinterpret_cast<const uint8*>(nonce.data()),
static_cast<uint32>(now.ToUNIXSeconds())); static_cast<uint32>(now.ToUNIXSeconds()));
} }
// m_ must not be held when the ResultCallback runs. // m_ must not be held when the ResultCallback runs.
cb->Run(nonce_is_valid_and_unique); cb->Run((nonce_error == NONCE_OK), nonce_error);
} }
} // namespace net } // namespace net
...@@ -25,21 +25,27 @@ class RecordResultCallback : public StrikeRegisterClient::ResultCallback { ...@@ -25,21 +25,27 @@ class RecordResultCallback : public StrikeRegisterClient::ResultCallback {
// RecordResultCallback stores the argument to RunImpl in // RecordResultCallback stores the argument to RunImpl in
// |*saved_value| and sets |*called| to true. The callback is self // |*saved_value| and sets |*called| to true. The callback is self
// deleting. // deleting.
RecordResultCallback(bool* called, bool* saved_value) RecordResultCallback(bool* called,
bool* saved_value,
InsertStatus* saved_nonce_error)
: called_(called), : called_(called),
saved_value_(saved_value) { saved_value_(saved_value),
saved_nonce_error_(saved_nonce_error) {
*called_ = false; *called_ = false;
} }
protected: protected:
virtual void RunImpl(bool nonce_is_valid_and_unique) OVERRIDE { virtual void RunImpl(bool nonce_is_valid_and_unique,
InsertStatus nonce_error) OVERRIDE {
*called_ = true; *called_ = true;
*saved_value_ = nonce_is_valid_and_unique; *saved_value_ = nonce_is_valid_and_unique;
*saved_nonce_error_ = nonce_error;
} }
private: private:
bool* called_; bool* called_;
bool* saved_value_; bool* saved_value_;
InsertStatus* saved_nonce_error_;
DISALLOW_COPY_AND_ASSIGN(RecordResultCallback); DISALLOW_COPY_AND_ASSIGN(RecordResultCallback);
}; };
...@@ -85,39 +91,45 @@ TEST_F(LocalStrikeRegisterClientTest, IncorrectNonceLength) { ...@@ -85,39 +91,45 @@ TEST_F(LocalStrikeRegisterClientTest, IncorrectNonceLength) {
// Validation fails if you remove a byte from the nonce. // Validation fails if you remove a byte from the nonce.
bool called = false; bool called = false;
bool is_valid = false; bool is_valid = false;
InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
string short_nonce = valid_nonce.substr(0, valid_nonce.length() - 1); string short_nonce = valid_nonce.substr(0, valid_nonce.length() - 1);
strike_register_->VerifyNonceIsValidAndUnique( strike_register_->VerifyNonceIsValidAndUnique(
short_nonce, short_nonce,
QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs), QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
new RecordResultCallback(&called, &is_valid)); new RecordResultCallback(&called, &is_valid, &nonce_error));
EXPECT_TRUE(called); EXPECT_TRUE(called);
EXPECT_FALSE(is_valid); EXPECT_FALSE(is_valid);
EXPECT_EQ(NONCE_INVALID_FAILURE, nonce_error);
} }
{ {
// Validation fails if you add a byte to the nonce. // Validation fails if you add a byte to the nonce.
bool called = false; bool called = false;
bool is_valid = false; bool is_valid = false;
InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
string long_nonce(valid_nonce); string long_nonce(valid_nonce);
long_nonce.append("a"); long_nonce.append("a");
strike_register_->VerifyNonceIsValidAndUnique( strike_register_->VerifyNonceIsValidAndUnique(
long_nonce, long_nonce,
QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs), QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
new RecordResultCallback(&called, &is_valid)); new RecordResultCallback(&called, &is_valid, &nonce_error));
EXPECT_TRUE(called); EXPECT_TRUE(called);
EXPECT_FALSE(is_valid); EXPECT_FALSE(is_valid);
EXPECT_EQ(NONCE_INVALID_FAILURE, nonce_error);
} }
{ {
// Verify that the base nonce validates was valid. // Verify that the base nonce validates was valid.
bool called = false; bool called = false;
bool is_valid = false; bool is_valid = false;
InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
strike_register_->VerifyNonceIsValidAndUnique( strike_register_->VerifyNonceIsValidAndUnique(
valid_nonce, valid_nonce,
QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs), QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
new RecordResultCallback(&called, &is_valid)); new RecordResultCallback(&called, &is_valid, &nonce_error));
EXPECT_TRUE(called); EXPECT_TRUE(called);
EXPECT_TRUE(is_valid); EXPECT_TRUE(is_valid);
EXPECT_EQ(NONCE_OK, nonce_error);
} }
} }
......
...@@ -148,13 +148,40 @@ class VerifyNonceIsValidAndUniqueCallback ...@@ -148,13 +148,40 @@ class VerifyNonceIsValidAndUniqueCallback
} }
protected: protected:
virtual void RunImpl(bool nonce_is_valid_and_unique) OVERRIDE { virtual void RunImpl(bool nonce_is_valid_and_unique,
DVLOG(1) << "Using client nonce, unique: " << 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; result_->info.unique = nonce_is_valid_and_unique;
// TODO(rtenneti): Implement capturing of error from strike register.
// Temporarily treat them as CLIENT_NONCE_INVALID_FAILURE.
if (!nonce_is_valid_and_unique) { if (!nonce_is_valid_and_unique) {
result_->info.reject_reasons.push_back(CLIENT_NONCE_INVALID_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_OK:
case NONCE_UNKNOWN_FAILURE:
default:
LOG(WARNING) << "Unexpected 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_); done_cb_->Run(result_);
} }
...@@ -1440,7 +1467,7 @@ HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce( ...@@ -1440,7 +1467,7 @@ HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce(
COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce), COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce),
bad_nonce_buffer_length); bad_nonce_buffer_length);
bool is_unique; InsertStatus nonce_error;
{ {
base::AutoLock auto_lock(server_nonce_strike_register_lock_); base::AutoLock auto_lock(server_nonce_strike_register_lock_);
if (server_nonce_strike_register_.get() == NULL) { if (server_nonce_strike_register_.get() == NULL) {
...@@ -1450,11 +1477,27 @@ HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce( ...@@ -1450,11 +1477,27 @@ HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce(
server_nonce_strike_register_window_secs_, server_nonce_orbit_, server_nonce_strike_register_window_secs_, server_nonce_orbit_,
StrikeRegister::NO_STARTUP_PERIOD_NEEDED)); 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())); 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:
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 NONCE_INVALID_ORBIT_FAILURE:
case STRIKE_REGISTER_TIMEOUT:
case STRIKE_REGISTER_FAILURE:
default:
LOG(WARNING) << "Unexpected nonce error: " << nonce_error;
return SERVER_NONCE_NOT_UNIQUE_FAILURE;
}
} }
QuicCryptoServerConfig::Config::Config() QuicCryptoServerConfig::Config::Config()
......
...@@ -130,8 +130,8 @@ void StrikeRegister::Reset() { ...@@ -130,8 +130,8 @@ void StrikeRegister::Reset() {
internal_node_head_ = kNil; internal_node_head_ = kNil;
} }
bool StrikeRegister::Insert(const uint8 nonce[32], InsertStatus StrikeRegister::Insert(const uint8 nonce[32],
uint32 current_time_external) { uint32 current_time_external) {
// Make space for the insertion if the strike register is full. // Make space for the insertion if the strike register is full.
while (external_node_free_head_ == kNil || while (external_node_free_head_ == kNil ||
internal_node_free_head_ == kNil) { internal_node_free_head_ == kNil) {
...@@ -142,7 +142,7 @@ bool StrikeRegister::Insert(const uint8 nonce[32], ...@@ -142,7 +142,7 @@ bool StrikeRegister::Insert(const uint8 nonce[32],
// Check to see if the orbit is correct. // Check to see if the orbit is correct.
if (memcmp(nonce + sizeof(current_time), orbit_, sizeof(orbit_))) { if (memcmp(nonce + sizeof(current_time), orbit_, sizeof(orbit_))) {
return false; return NONCE_INVALID_ORBIT_FAILURE;
} }
const uint32 nonce_time = ExternalTimeToInternal(TimeFromBytes(nonce)); const uint32 nonce_time = ExternalTimeToInternal(TimeFromBytes(nonce));
...@@ -151,7 +151,7 @@ bool StrikeRegister::Insert(const uint8 nonce[32], ...@@ -151,7 +151,7 @@ bool StrikeRegister::Insert(const uint8 nonce[32],
pair<uint32, uint32> valid_range = pair<uint32, uint32> valid_range =
StrikeRegister::GetValidRange(current_time); StrikeRegister::GetValidRange(current_time);
if (nonce_time < valid_range.first || nonce_time > valid_range.second) { if (nonce_time < valid_range.first || nonce_time > valid_range.second) {
return false; return NONCE_INVALID_TIME_FAILURE;
} }
// We strip the orbit out of the nonce. // We strip the orbit out of the nonce.
...@@ -171,13 +171,13 @@ bool StrikeRegister::Insert(const uint8 nonce[32], ...@@ -171,13 +171,13 @@ bool StrikeRegister::Insert(const uint8 nonce[32],
memcpy(external_node(index), value, sizeof(value)); memcpy(external_node(index), value, sizeof(value));
internal_node_head_ = (index | kExternalFlag) << 8; internal_node_head_ = (index | kExternalFlag) << 8;
DCHECK_LE(horizon_, nonce_time); DCHECK_LE(horizon_, nonce_time);
return true; return NONCE_OK;
} }
const uint8* best_match = external_node(best_match_index); const uint8* best_match = external_node(best_match_index);
if (memcmp(best_match, value, sizeof(value)) == 0) { if (memcmp(best_match, value, sizeof(value)) == 0) {
// We found the value in the tree. // We found the value in the tree.
return false; return NONCE_NOT_UNIQUE_FAILURE;
} }
// We are going to insert a new entry into the tree, so get the nodes now. // We are going to insert a new entry into the tree, so get the nodes now.
...@@ -263,7 +263,7 @@ bool StrikeRegister::Insert(const uint8 nonce[32], ...@@ -263,7 +263,7 @@ bool StrikeRegister::Insert(const uint8 nonce[32],
*where_index = (*where_index & 0xff) | (internal_node_index << 8); *where_index = (*where_index & 0xff) | (internal_node_index << 8);
DCHECK_LE(horizon_, nonce_time); DCHECK_LE(horizon_, nonce_time);
return true; return NONCE_OK;
} }
const uint8* StrikeRegister::orbit() const { const uint8* StrikeRegister::orbit() const {
......
...@@ -15,6 +15,26 @@ ...@@ -15,6 +15,26 @@
namespace net { namespace net {
// InsertStatus enum values cannot be changed, they need to be stable.
enum InsertStatus {
NONCE_OK = 0,
// The default error value for nonce verification failures from strike
// register (covers old strike registers and unknown failures).
NONCE_UNKNOWN_FAILURE = 1,
// Decrypted nonce had incorrect length.
NONCE_INVALID_FAILURE = 2,
// Nonce is not unique.
NONCE_NOT_UNIQUE_FAILURE = 3,
// Nonce's orbit is invalid or incorrect.
NONCE_INVALID_ORBIT_FAILURE = 4,
// Nonce's timestamp is not in the strike register's valid time range.
NONCE_INVALID_TIME_FAILURE = 5,
// Strike register's RPC call timed out, nonce couldn't be verified.
STRIKE_REGISTER_TIMEOUT = 6,
// Strike register is down, nonce couldn't be verified.
STRIKE_REGISTER_FAILURE = 7,
};
// A StrikeRegister is critbit tree which stores a set of observed nonces. // A StrikeRegister is critbit tree which stores a set of observed nonces.
// We use a critbit tree because: // We use a critbit tree because:
// 1) It's immune to algorithmic complexity attacks. If we had used a hash // 1) It's immune to algorithmic complexity attacks. If we had used a hash
...@@ -107,16 +127,17 @@ class NET_EXPORT_PRIVATE StrikeRegister { ...@@ -107,16 +127,17 @@ class NET_EXPORT_PRIVATE StrikeRegister {
// b) before the current horizon // b) before the current horizon
// c) outside of the valid time window // c) outside of the valid time window
// d) already in the set of observed nonces // d) already in the set of observed nonces
// and returns false if any of these are true. It is also free to return // and returns the failure reason if any of these are true. It is also free to
// false for other reasons as it's always safe to reject an nonce. // return failure reason for other reasons as it's always safe to reject an
// nonce.
// //
// nonces are: // nonces are:
// 4 bytes of timestamp (UNIX epoch seconds) // 4 bytes of timestamp (UNIX epoch seconds)
// 8 bytes of orbit value (a cluster id) // 8 bytes of orbit value (a cluster id)
// 20 bytes of random data // 20 bytes of random data
// //
// Otherwise, it inserts |nonce| into the observed set and returns true. // Otherwise, it inserts |nonce| into the observed set and returns NONCE_OK.
bool Insert(const uint8 nonce[32], uint32 current_time); InsertStatus Insert(const uint8 nonce[32], uint32 current_time);
// orbit returns a pointer to the 8-byte orbit value for this // orbit returns a pointer to the 8-byte orbit value for this
// strike-register. // strike-register.
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "net/base/net_export.h" #include "net/base/net_export.h"
#include "net/quic/crypto/strike_register.h"
#include "net/quic/quic_time.h" #include "net/quic/quic_time.h"
namespace net { namespace net {
...@@ -24,13 +25,14 @@ class NET_EXPORT_PRIVATE StrikeRegisterClient { ...@@ -24,13 +25,14 @@ class NET_EXPORT_PRIVATE StrikeRegisterClient {
public: public:
ResultCallback() {} ResultCallback() {}
virtual ~ResultCallback() {} virtual ~ResultCallback() {}
void Run(bool nonce_is_valid_and_unique) { void Run(bool nonce_is_valid_and_unique, InsertStatus nonce_error) {
RunImpl(nonce_is_valid_and_unique); RunImpl(nonce_is_valid_and_unique, nonce_error);
delete this; delete this;
} }
protected: protected:
virtual void RunImpl(bool nonce_is_valid_and_unique) = 0; virtual void RunImpl(bool nonce_is_valid_and_unique,
InsertStatus nonce_error) = 0;
private: private:
DISALLOW_COPY_AND_ASSIGN(ResultCallback); DISALLOW_COPY_AND_ASSIGN(ResultCallback);
...@@ -42,7 +44,8 @@ class NET_EXPORT_PRIVATE StrikeRegisterClient { ...@@ -42,7 +44,8 @@ class NET_EXPORT_PRIVATE StrikeRegisterClient {
// Returns true iff the strike register knows about the given orbit. // Returns true iff the strike register knows about the given orbit.
virtual bool IsKnownOrbit(base::StringPiece orbit) const = 0; virtual bool IsKnownOrbit(base::StringPiece orbit) const = 0;
// Validate a nonce for freshness and uniqueness. // Validate a nonce for freshness and uniqueness.
// Will invoke cb->Run(ValidateResponse::nonce_is_valid_and_unique()) // Will invoke cb->Run(ValidateResponse::nonce_is_valid_and_unique(),
// ValidateResponse::nonce_error())
// once the asynchronous operation is complete. // once the asynchronous operation is complete.
virtual void VerifyNonceIsValidAndUnique( virtual void VerifyNonceIsValidAndUnique(
base::StringPiece nonce, base::StringPiece nonce,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
namespace { namespace {
using net::InsertStatus;
using net::StrikeRegister; using net::StrikeRegister;
using std::make_pair; using std::make_pair;
using std::min; using std::min;
...@@ -40,9 +41,9 @@ TEST(StrikeRegisterTest, SimpleHorizon) { ...@@ -40,9 +41,9 @@ TEST(StrikeRegisterTest, SimpleHorizon) {
StrikeRegister::DENY_REQUESTS_AT_STARTUP); StrikeRegister::DENY_REQUESTS_AT_STARTUP);
uint8 nonce[32]; uint8 nonce[32];
SetNonce(nonce, 999, kOrbit); SetNonce(nonce, 999, kOrbit);
ASSERT_FALSE(set.Insert(nonce, 1000)); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
SetNonce(nonce, 1000, kOrbit); SetNonce(nonce, 1000, kOrbit);
ASSERT_FALSE(set.Insert(nonce, 1000)); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1000 /* current time */)); EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1000 /* current time */));
EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1100 /* current time */)); EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1100 /* current time */));
...@@ -60,8 +61,8 @@ TEST(StrikeRegisterTest, NoStartupMode) { ...@@ -60,8 +61,8 @@ TEST(StrikeRegisterTest, NoStartupMode) {
StrikeRegister::NO_STARTUP_PERIOD_NEEDED); StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
uint8 nonce[32]; uint8 nonce[32];
SetNonce(nonce, 1000, kOrbit); SetNonce(nonce, 1000, kOrbit);
ASSERT_TRUE(set.Insert(nonce, 1000)); EXPECT_EQ(net::NONCE_OK, set.Insert(nonce, 1000));
ASSERT_FALSE(set.Insert(nonce, 1000)); EXPECT_EQ(net::NONCE_NOT_UNIQUE_FAILURE, set.Insert(nonce, 1000));
EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1000 /* current time */)); EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1000 /* current time */));
EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1050 /* current time */)); EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1050 /* current time */));
...@@ -77,9 +78,9 @@ TEST(StrikeRegisterTest, WindowFuture) { ...@@ -77,9 +78,9 @@ TEST(StrikeRegisterTest, WindowFuture) {
StrikeRegister::DENY_REQUESTS_AT_STARTUP); StrikeRegister::DENY_REQUESTS_AT_STARTUP);
uint8 nonce[32]; uint8 nonce[32];
SetNonce(nonce, 1101, kOrbit); SetNonce(nonce, 1101, kOrbit);
ASSERT_FALSE(set.Insert(nonce, 1000)); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
SetNonce(nonce, 999, kOrbit); SetNonce(nonce, 999, kOrbit);
ASSERT_FALSE(set.Insert(nonce, 1100)); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1100));
} }
TEST(StrikeRegisterTest, BadOrbit) { TEST(StrikeRegisterTest, BadOrbit) {
...@@ -90,7 +91,7 @@ TEST(StrikeRegisterTest, BadOrbit) { ...@@ -90,7 +91,7 @@ TEST(StrikeRegisterTest, BadOrbit) {
uint8 nonce[32]; uint8 nonce[32];
static const uint8 kBadOrbit[8] = { 0, 0, 0, 0, 1, 1, 1, 1 }; static const uint8 kBadOrbit[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
SetNonce(nonce, 1101, kBadOrbit); SetNonce(nonce, 1101, kBadOrbit);
ASSERT_FALSE(set.Insert(nonce, 1100)); EXPECT_EQ(net::NONCE_INVALID_ORBIT_FAILURE, set.Insert(nonce, 1100));
} }
TEST(StrikeRegisterTest, OneValue) { TEST(StrikeRegisterTest, OneValue) {
...@@ -99,7 +100,7 @@ TEST(StrikeRegisterTest, OneValue) { ...@@ -99,7 +100,7 @@ TEST(StrikeRegisterTest, OneValue) {
StrikeRegister::DENY_REQUESTS_AT_STARTUP); StrikeRegister::DENY_REQUESTS_AT_STARTUP);
uint8 nonce[32]; uint8 nonce[32];
SetNonce(nonce, 1101, kOrbit); SetNonce(nonce, 1101, kOrbit);
ASSERT_TRUE(set.Insert(nonce, 1101)); EXPECT_EQ(net::NONCE_OK, set.Insert(nonce, 1101));
} }
TEST(StrikeRegisterTest, RejectDuplicate) { TEST(StrikeRegisterTest, RejectDuplicate) {
...@@ -109,8 +110,8 @@ TEST(StrikeRegisterTest, RejectDuplicate) { ...@@ -109,8 +110,8 @@ TEST(StrikeRegisterTest, RejectDuplicate) {
StrikeRegister::DENY_REQUESTS_AT_STARTUP); StrikeRegister::DENY_REQUESTS_AT_STARTUP);
uint8 nonce[32]; uint8 nonce[32];
SetNonce(nonce, 1101, kOrbit); SetNonce(nonce, 1101, kOrbit);
ASSERT_TRUE(set.Insert(nonce, 1101)); EXPECT_EQ(net::NONCE_OK, set.Insert(nonce, 1101));
ASSERT_FALSE(set.Insert(nonce, 1101)); EXPECT_EQ(net::NONCE_NOT_UNIQUE_FAILURE, set.Insert(nonce, 1101));
} }
TEST(StrikeRegisterTest, HorizonUpdating) { TEST(StrikeRegisterTest, HorizonUpdating) {
...@@ -127,7 +128,7 @@ TEST(StrikeRegisterTest, HorizonUpdating) { ...@@ -127,7 +128,7 @@ TEST(StrikeRegisterTest, HorizonUpdating) {
for (unsigned i = 0; i < 5; i++) { for (unsigned i = 0; i < 5; i++) {
SetNonce(nonce[i], 1101 + i, kOrbit); SetNonce(nonce[i], 1101 + i, kOrbit);
nonce[i][31] = i; nonce[i][31] = i;
ASSERT_TRUE(set.Insert(nonce[i], 1100)); EXPECT_EQ(net::NONCE_OK, set.Insert(nonce[i], 1100));
} }
// Valid window is still equal to |window_secs + 1|. // Valid window is still equal to |window_secs + 1|.
...@@ -136,34 +137,34 @@ TEST(StrikeRegisterTest, HorizonUpdating) { ...@@ -136,34 +137,34 @@ TEST(StrikeRegisterTest, HorizonUpdating) {
// This should push the oldest value out and force the horizon to // This should push the oldest value out and force the horizon to
// be updated. // be updated.
SetNonce(nonce[5], 1110, kOrbit); SetNonce(nonce[5], 1110, kOrbit);
ASSERT_TRUE(set.Insert(nonce[5], 1110)); EXPECT_EQ(net::NONCE_OK, set.Insert(nonce[5], 1110));
// Effective horizon is computed based on the timestamp of the // Effective horizon is computed based on the timestamp of the
// value that was pushed out. // value that was pushed out.
EXPECT_EQ(9u, set.GetCurrentValidWindowSecs(1110)); EXPECT_EQ(9u, set.GetCurrentValidWindowSecs(1110));
SetNonce(nonce[5], 1111, kOrbit); SetNonce(nonce[5], 1111, kOrbit);
EXPECT_TRUE(set.Insert(nonce[5], 1110)); EXPECT_EQ(net::NONCE_OK, set.Insert(nonce[5], 1110));
EXPECT_EQ(8u, set.GetCurrentValidWindowSecs(1110)); EXPECT_EQ(8u, set.GetCurrentValidWindowSecs(1110));
// This should be behind the horizon now: // This should be behind the horizon now:
SetNonce(nonce[5], 1101, kOrbit); SetNonce(nonce[5], 1101, kOrbit);
nonce[5][31] = 10; nonce[5][31] = 10;
EXPECT_FALSE(set.Insert(nonce[5], 1110)); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
// Insert beyond the valid range. // Insert beyond the valid range.
SetNonce(nonce[5], 1117, kOrbit); SetNonce(nonce[5], 1117, kOrbit);
nonce[5][31] = 2; nonce[5][31] = 2;
EXPECT_FALSE(set.Insert(nonce[5], 1110)); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
// Insert at the upper valid range. // Insert at the upper valid range.
SetNonce(nonce[5], 1116, kOrbit); SetNonce(nonce[5], 1116, kOrbit);
nonce[5][31] = 1; nonce[5][31] = 1;
EXPECT_TRUE(set.Insert(nonce[5], 1110)); EXPECT_EQ(net::NONCE_OK, set.Insert(nonce[5], 1110));
// This should be beyond the upper valid range now: // This should be beyond the upper valid range now:
SetNonce(nonce[5], 1116, kOrbit); SetNonce(nonce[5], 1116, kOrbit);
nonce[5][31] = 2; nonce[5][31] = 2;
EXPECT_FALSE(set.Insert(nonce[5], 1110)); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
} }
} }
...@@ -177,7 +178,7 @@ TEST(StrikeRegisterTest, InsertMany) { ...@@ -177,7 +178,7 @@ TEST(StrikeRegisterTest, InsertMany) {
for (unsigned i = 0; i < 100000; i++) { for (unsigned i = 0; i < 100000; i++) {
SetNonce(nonce, 1101 + i/500, kOrbit); SetNonce(nonce, 1101 + i/500, kOrbit);
memcpy(nonce + 12, &i, sizeof(i)); memcpy(nonce + 12, &i, sizeof(i));
set.Insert(nonce, 1100); EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1100));
} }
} }
...@@ -201,9 +202,9 @@ class SlowStrikeRegister { ...@@ -201,9 +202,9 @@ class SlowStrikeRegister {
memcpy(orbit_, orbit, sizeof(orbit_)); memcpy(orbit_, orbit, sizeof(orbit_));
} }
bool Insert(const uint8 nonce_bytes[32], InsertStatus Insert(const uint8 nonce_bytes[32],
const uint32 nonce_time_external, const uint32 nonce_time_external,
const uint32 current_time_external) { const uint32 current_time_external) {
if (nonces_.size() == max_entries_) { if (nonces_.size() == max_entries_) {
DropOldestEntry(); DropOldestEntry();
} }
...@@ -212,7 +213,7 @@ class SlowStrikeRegister { ...@@ -212,7 +213,7 @@ class SlowStrikeRegister {
// Check to see if the orbit is correct. // Check to see if the orbit is correct.
if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) { if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) {
return false; return net::NONCE_INVALID_ORBIT_FAILURE;
} }
const uint32 nonce_time = const uint32 nonce_time =
ExternalTimeToInternal(TimeFromBytes(nonce_bytes)); ExternalTimeToInternal(TimeFromBytes(nonce_bytes));
...@@ -221,14 +222,14 @@ class SlowStrikeRegister { ...@@ -221,14 +222,14 @@ class SlowStrikeRegister {
// so we have to reject anything with a timestamp less than or // so we have to reject anything with a timestamp less than or
// equal to that. // equal to that.
if (nonce_time < horizon_) { if (nonce_time < horizon_) {
return false; return net::NONCE_INVALID_TIME_FAILURE;
} }
// Check that the timestamp is in the current window. // Check that the timestamp is in the current window.
if ((current_time > window_secs_ && if ((current_time > window_secs_ &&
nonce_time < (current_time - window_secs_)) || nonce_time < (current_time - window_secs_)) ||
nonce_time > (current_time + window_secs_)) { nonce_time > (current_time + window_secs_)) {
return false; return net::NONCE_INVALID_TIME_FAILURE;
} }
pair<uint32, string> nonce = make_pair( pair<uint32, string> nonce = make_pair(
...@@ -237,11 +238,11 @@ class SlowStrikeRegister { ...@@ -237,11 +238,11 @@ class SlowStrikeRegister {
set<pair<uint32, string> >::const_iterator it = nonces_.find(nonce); set<pair<uint32, string> >::const_iterator it = nonces_.find(nonce);
if (it != nonces_.end()) { if (it != nonces_.end()) {
return false; return net::NONCE_NOT_UNIQUE_FAILURE;
} }
nonces_.insert(nonce); nonces_.insert(nonce);
return true; return net::NONCE_OK;
} }
uint32 GetCurrentValidWindowSecs(const uint32 current_time_external) const { uint32 GetCurrentValidWindowSecs(const uint32 current_time_external) const {
...@@ -314,11 +315,16 @@ TEST_F(StrikeRegisterStressTest, InOrderInsertion) { ...@@ -314,11 +315,16 @@ TEST_F(StrikeRegisterStressTest, InOrderInsertion) {
nonce[30] = v >> 8; nonce[30] = v >> 8;
nonce[31] = v; nonce[31] = v;
const bool r2 = s2->Insert(nonce, time, time); const InsertStatus nonce_error2 = s2->Insert(nonce, time, time);
const bool r1 = s1->Insert(nonce, time); const InsertStatus nonce_error1 = s1->Insert(nonce, time);
EXPECT_EQ(r1, r2); EXPECT_EQ(nonce_error1, nonce_error2);
// Inserts succeed after the startup period. // Inserts succeed after the startup period.
EXPECT_EQ(time > current_time + window, r1); if (time > current_time + window) {
EXPECT_EQ(net::NONCE_OK, nonce_error1);
} else {
EXPECT_EQ(net::NONCE_INVALID_TIME_FAILURE, nonce_error1);
}
EXPECT_EQ(s1->GetCurrentValidWindowSecs(time), EXPECT_EQ(s1->GetCurrentValidWindowSecs(time),
s2->GetCurrentValidWindowSecs(time)); s2->GetCurrentValidWindowSecs(time));
...@@ -379,9 +385,9 @@ TEST_F(StrikeRegisterStressTest, Stress) { ...@@ -379,9 +385,9 @@ TEST_F(StrikeRegisterStressTest, Stress) {
nonce[30] = v >> 8; nonce[30] = v >> 8;
nonce[31] = v; nonce[31] = v;
const bool r2 = s2->Insert(nonce, time, time); const InsertStatus nonce_error2 = s2->Insert(nonce, time, time);
const bool r1 = s1->Insert(nonce, time); const InsertStatus nonce_error1 = s1->Insert(nonce, time);
EXPECT_EQ(r1, r2); EXPECT_EQ(nonce_error1, nonce_error2);
EXPECT_EQ(s1->GetCurrentValidWindowSecs(time), EXPECT_EQ(s1->GetCurrentValidWindowSecs(time),
s2->GetCurrentValidWindowSecs(time)); s2->GetCurrentValidWindowSecs(time));
......
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