1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/basictypes.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "crypto/secure_hash.h"
11 #include "net/quic/crypto/crypto_utils.h"
12 #include "net/quic/crypto/quic_crypto_server_config.h"
13 #include "net/quic/crypto/quic_random.h"
14 #include "net/quic/quic_flags.h"
15 #include "net/quic/quic_socket_address_coder.h"
16 #include "net/quic/quic_utils.h"
17 #include "net/quic/test_tools/crypto_test_utils.h"
18 #include "net/quic/test_tools/delayed_verify_strike_register_client.h"
19 #include "net/quic/test_tools/mock_clock.h"
20 #include "net/quic/test_tools/mock_random.h"
21 #include "net/quic/test_tools/quic_test_utils.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using base::StringPiece
;
32 class QuicCryptoServerConfigPeer
{
34 explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig
* server_config
)
35 : server_config_(server_config
) {}
37 base::Lock
* GetStrikeRegisterClientLock() {
38 return &server_config_
->strike_register_client_lock_
;
42 QuicCryptoServerConfig
* server_config_
;
45 // Run tests with both parities of
46 // FLAGS_use_early_return_when_verifying_chlo.
48 explicit TestParams(bool use_early_return_when_verifying_chlo
)
49 : use_early_return_when_verifying_chlo(
50 use_early_return_when_verifying_chlo
) {}
52 friend ostream
& operator<<(ostream
& os
, const TestParams
& p
) {
53 os
<< "{ use_early_return_when_verifying_chlo: "
54 << p
.use_early_return_when_verifying_chlo
<< " }";
58 bool use_early_return_when_verifying_chlo
;
61 // Constructs various test permutations.
62 vector
<TestParams
> GetTestParams() {
63 vector
<TestParams
> params
;
64 params
.push_back(TestParams(false));
65 params
.push_back(TestParams(true));
69 class CryptoServerTest
: public ::testing::TestWithParam
<TestParams
> {
72 : rand_(QuicRandom::GetInstance()),
73 client_address_(Loopback4(), 1234),
74 config_(QuicCryptoServerConfig::TESTING
, rand_
) {
75 config_
.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
76 supported_versions_
= QuicSupportedVersions();
77 client_version_
= QuicUtils::TagToString(
78 QuicVersionToQuicTag(supported_versions_
.front()));
80 FLAGS_use_early_return_when_verifying_chlo
=
81 GetParam().use_early_return_when_verifying_chlo
;
84 void SetUp() override
{
85 scoped_ptr
<CryptoHandshakeMessage
> msg(
86 config_
.AddDefaultConfig(rand_
, &clock_
,
90 CHECK(msg
->GetStringPiece(kORBT
, &orbit
));
91 CHECK_EQ(sizeof(orbit_
), orbit
.size());
92 memcpy(orbit_
, orbit
.data(), orbit
.size());
94 char public_value
[32];
95 memset(public_value
, 42, sizeof(public_value
));
97 const string nonce_str
= GenerateNonce();
98 nonce_hex_
= "#" + base::HexEncode(nonce_str
.data(), nonce_str
.size());
99 pub_hex_
= "#" + base::HexEncode(public_value
, sizeof(public_value
));
101 CryptoHandshakeMessage client_hello
= CryptoTestUtils::Message(
105 "PUBS", pub_hex_
.c_str(),
106 "NONC", nonce_hex_
.c_str(),
107 "VER\0", client_version_
.data(),
108 "$padding", static_cast<int>(kClientHelloMinimumSize
),
110 ShouldSucceed(client_hello
);
111 // The message should be rejected because the source-address token is
113 ASSERT_EQ(kREJ
, out_
.tag());
114 const HandshakeFailureReason kRejectReasons
[] = {
115 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
117 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
120 ASSERT_TRUE(out_
.GetStringPiece(kSourceAddressTokenTag
, &srct
));
121 srct_hex_
= "#" + base::HexEncode(srct
.data(), srct
.size());
124 ASSERT_TRUE(out_
.GetStringPiece(kSCFG
, &scfg
));
125 server_config_
.reset(CryptoFramer::ParseMessage(scfg
));
128 ASSERT_TRUE(server_config_
->GetStringPiece(kSCID
, &scid
));
129 scid_hex_
= "#" + base::HexEncode(scid
.data(), scid
.size());
132 // Helper used to accept the result of ValidateClientHello and pass
133 // it on to ProcessClientHello.
134 class ValidateCallback
: public ValidateClientHelloResultCallback
{
136 ValidateCallback(CryptoServerTest
* test
,
138 const char* error_substr
,
141 should_succeed_(should_succeed
),
142 error_substr_(error_substr
),
147 void RunImpl(const CryptoHandshakeMessage
& client_hello
,
148 const Result
& result
) override
{
150 // Ensure that the strike register client lock is not held.
151 QuicCryptoServerConfigPeer
peer(&test_
->config_
);
152 base::Lock
* m
= peer
.GetStrikeRegisterClientLock();
153 // In Chromium, we will dead lock if the lock is held by the current
154 // thread. Chromium doesn't have AssertNotHeld API call.
155 // m->AssertNotHeld();
156 base::AutoLock
lock(*m
);
158 ASSERT_FALSE(*called_
);
159 test_
->ProcessValidationResult(
160 client_hello
, result
, should_succeed_
, error_substr_
);
165 CryptoServerTest
* test_
;
166 bool should_succeed_
;
167 const char* error_substr_
;
171 void CheckServerHello(const CryptoHandshakeMessage
& server_hello
) {
172 const QuicTag
* versions
;
174 server_hello
.GetTaglist(kVER
, &versions
, &num_versions
);
175 ASSERT_EQ(QuicSupportedVersions().size(), num_versions
);
176 for (size_t i
= 0; i
< num_versions
; ++i
) {
177 EXPECT_EQ(QuicVersionToQuicTag(QuicSupportedVersions()[i
]), versions
[i
]);
181 ASSERT_TRUE(server_hello
.GetStringPiece(kCADR
, &address
));
182 QuicSocketAddressCoder decoder
;
183 ASSERT_TRUE(decoder
.Decode(address
.data(), address
.size()));
184 EXPECT_EQ(client_address_
.address(), decoder
.ip());
185 EXPECT_EQ(client_address_
.port(), decoder
.port());
188 void ShouldSucceed(const CryptoHandshakeMessage
& message
) {
190 RunValidate(message
, new ValidateCallback(this, true, "", &called
));
195 const CryptoHandshakeMessage
& message
,
196 ValidateClientHelloResultCallback
* cb
) {
197 config_
.ValidateClientHello(message
, client_address_
.address(), &clock_
,
201 void ShouldFailMentioning(const char* error_substr
,
202 const CryptoHandshakeMessage
& message
) {
204 ShouldFailMentioning(error_substr
, message
, &called
);
208 void ShouldFailMentioning(const char* error_substr
,
209 const CryptoHandshakeMessage
& message
,
211 config_
.ValidateClientHello(
212 message
, client_address_
.address(), &clock_
,
213 new ValidateCallback(this, false, error_substr
, called
));
216 void ProcessValidationResult(const CryptoHandshakeMessage
& message
,
217 const ValidateCallback::Result
& result
,
219 const char* error_substr
) {
220 IPAddressNumber server_ip
;
221 string error_details
;
222 QuicErrorCode error
= config_
.ProcessClientHello(
223 result
, 1 /* ConnectionId */, server_ip
, client_address_
,
224 supported_versions_
.front(), supported_versions_
, &clock_
, rand_
,
225 ¶ms_
, &out_
, &error_details
);
227 if (should_succeed
) {
228 ASSERT_EQ(error
, QUIC_NO_ERROR
)
229 << "Message failed with error " << error_details
<< ": "
230 << message
.DebugString();
232 ASSERT_NE(error
, QUIC_NO_ERROR
)
233 << "Message didn't fail: " << message
.DebugString();
235 EXPECT_TRUE(error_details
.find(error_substr
) != string::npos
)
236 << error_substr
<< " not in " << error_details
;
240 CryptoHandshakeMessage
InchoateClientHello(const char* message_tag
, ...) {
242 va_start(ap
, message_tag
);
244 CryptoHandshakeMessage message
=
245 CryptoTestUtils::BuildMessage(message_tag
, ap
);
248 message
.SetStringPiece(kPAD
, string(kClientHelloMinimumSize
, '-'));
252 string
GenerateNonce() {
254 CryptoUtils::GenerateNonce(
255 clock_
.WallNow(), rand_
,
256 StringPiece(reinterpret_cast<const char*>(orbit_
), sizeof(orbit_
)),
261 void CheckRejectReasons(
262 const HandshakeFailureReason
* expected_handshake_failures
,
263 size_t expected_count
) {
264 const uint32
* reject_reasons
;
265 size_t num_reject_reasons
;
266 COMPILE_ASSERT(sizeof(QuicTag
) == sizeof(uint32
), header_out_of_sync
);
267 QuicErrorCode error_code
= out_
.GetTaglist(kRREJ
, &reject_reasons
,
268 &num_reject_reasons
);
269 ASSERT_EQ(QUIC_NO_ERROR
, error_code
);
271 if (FLAGS_use_early_return_when_verifying_chlo
) {
272 EXPECT_EQ(1u, num_reject_reasons
);
274 EXPECT_EQ(expected_count
, num_reject_reasons
);
276 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
277 EXPECT_EQ(expected_handshake_failures
[i
], reject_reasons
[i
]);
282 QuicRandom
* const rand_
;
284 const IPEndPoint client_address_
;
285 QuicVersionVector supported_versions_
;
286 string client_version_
;
287 QuicCryptoServerConfig config_
;
288 QuicCryptoServerConfig::ConfigOptions config_options_
;
289 QuicCryptoNegotiatedParameters params_
;
290 CryptoHandshakeMessage out_
;
291 uint8 orbit_
[kOrbitSize
];
293 // These strings contain hex escaped values from the server suitable for
294 // passing to |InchoateClientHello| when constructing client hello messages.
295 string nonce_hex_
, pub_hex_
, srct_hex_
, scid_hex_
;
296 scoped_ptr
<CryptoHandshakeMessage
> server_config_
;
299 // Run all CryptoServerTest with both values of
300 // FLAGS_use_early_return_when_verifying_chlo
301 INSTANTIATE_TEST_CASE_P(CryptoServerTests
,
303 ::testing::ValuesIn(GetTestParams()));
305 TEST_P(CryptoServerTest
, BadSNI
) {
306 static const char* const kBadSNIs
[] = {
315 string client_version
= QuicUtils::TagToString(
316 QuicVersionToQuicTag(supported_versions_
.front()));
318 for (size_t i
= 0; i
< arraysize(kBadSNIs
); i
++) {
319 ShouldFailMentioning("SNI", InchoateClientHello(
322 "VER\0", client_version
.data(),
324 const HandshakeFailureReason kRejectReasons
[] = {
325 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
327 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
331 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
332 TEST_F(CryptoServerTest
, DISABLED_DefaultCert
) {
333 // Check that the server replies with a default certificate when no SNI is
335 ShouldSucceed(InchoateClientHello(
339 "SCID", scid_hex_
.c_str(),
340 "#004b5453", srct_hex_
.c_str(),
341 "PUBS", pub_hex_
.c_str(),
342 "NONC", nonce_hex_
.c_str(),
343 "$padding", static_cast<int>(kClientHelloMinimumSize
),
345 "VER\0", client_version_
.data(),
348 StringPiece cert
, proof
;
349 EXPECT_TRUE(out_
.GetStringPiece(kCertificateTag
, &cert
));
350 EXPECT_TRUE(out_
.GetStringPiece(kPROF
, &proof
));
351 EXPECT_NE(0u, cert
.size());
352 EXPECT_NE(0u, proof
.size());
353 const HandshakeFailureReason kRejectReasons
[] = {
354 CLIENT_NONCE_INVALID_TIME_FAILURE
356 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
359 TEST_P(CryptoServerTest
, TooSmall
) {
360 ShouldFailMentioning("too small", CryptoTestUtils::Message(
362 "VER\0", client_version_
.data(),
364 const HandshakeFailureReason kRejectReasons
[] = {
365 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
367 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
370 TEST_P(CryptoServerTest
, BadSourceAddressToken
) {
371 // Invalid source-address tokens should be ignored.
372 static const char* const kBadSourceAddressTokens
[] = {
376 "#0000000000000000000000000000000000000000",
379 for (size_t i
= 0; i
< arraysize(kBadSourceAddressTokens
); i
++) {
380 ShouldSucceed(InchoateClientHello(
382 "STK", kBadSourceAddressTokens
[i
],
383 "VER\0", client_version_
.data(),
385 const HandshakeFailureReason kRejectReasons
[] = {
386 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
388 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
392 TEST_P(CryptoServerTest
, BadClientNonce
) {
393 // Invalid nonces should be ignored.
394 static const char* const kBadNonces
[] = {
397 "#0000000000000000000000000000000000000000",
400 for (size_t i
= 0; i
< arraysize(kBadNonces
); i
++) {
401 ShouldSucceed(InchoateClientHello(
403 "NONC", kBadNonces
[i
],
404 "VER\0", client_version_
.data(),
406 const HandshakeFailureReason kRejectReasons
[] = {
407 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
409 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
413 TEST_P(CryptoServerTest
, DowngradeAttack
) {
414 if (supported_versions_
.size() == 1) {
415 // No downgrade attack is possible if the server only supports one version.
418 // Set the client's preferred version to a supported version that
419 // is not the "current" version (supported_versions_.front()).
420 string bad_version
= QuicUtils::TagToString(
421 QuicVersionToQuicTag(supported_versions_
.back()));
423 ShouldFailMentioning("Downgrade", InchoateClientHello(
425 "VER\0", bad_version
.data(),
427 const HandshakeFailureReason kRejectReasons
[] = {
428 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
430 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
433 TEST_P(CryptoServerTest
, CorruptServerConfig
) {
434 // This tests corrupted server config.
435 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
439 "SCID", (string(1, 'X') + scid_hex_
).c_str(),
440 "#004b5453", srct_hex_
.c_str(),
441 "PUBS", pub_hex_
.c_str(),
442 "NONC", nonce_hex_
.c_str(),
443 "VER\0", client_version_
.data(),
444 "$padding", static_cast<int>(kClientHelloMinimumSize
),
447 ASSERT_EQ(kREJ
, out_
.tag());
448 const HandshakeFailureReason kRejectReasons
[] = {
449 SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE
451 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
454 TEST_P(CryptoServerTest
, CorruptSourceAddressToken
) {
455 // This tests corrupted source address token.
456 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
460 "SCID", scid_hex_
.c_str(),
461 "#004b5453", (string(1, 'X') + srct_hex_
).c_str(),
462 "PUBS", pub_hex_
.c_str(),
463 "NONC", nonce_hex_
.c_str(),
464 "VER\0", client_version_
.data(),
465 "$padding", static_cast<int>(kClientHelloMinimumSize
),
468 ASSERT_EQ(kREJ
, out_
.tag());
469 const HandshakeFailureReason kRejectReasons
[] = {
470 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
472 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
475 TEST_P(CryptoServerTest
, CorruptClientNonceAndSourceAddressToken
) {
476 // This test corrupts client nonce and source address token.
477 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
481 "SCID", scid_hex_
.c_str(),
482 "#004b5453", (string(1, 'X') + srct_hex_
).c_str(),
483 "PUBS", pub_hex_
.c_str(),
484 "NONC", (string(1, 'X') + nonce_hex_
).c_str(),
485 "VER\0", client_version_
.data(),
486 "$padding", static_cast<int>(kClientHelloMinimumSize
),
489 ASSERT_EQ(kREJ
, out_
.tag());
490 const HandshakeFailureReason kRejectReasons
[] = {
491 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
,
492 CLIENT_NONCE_INVALID_FAILURE
494 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
497 TEST_P(CryptoServerTest
, CorruptMultipleTags
) {
498 // This test corrupts client nonce, server nonce and source address token.
499 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
503 "SCID", scid_hex_
.c_str(),
504 "#004b5453", (string(1, 'X') + srct_hex_
).c_str(),
505 "PUBS", pub_hex_
.c_str(),
506 "NONC", (string(1, 'X') + nonce_hex_
).c_str(),
507 "SNO\0", (string(1, 'X') + nonce_hex_
).c_str(),
508 "VER\0", client_version_
.data(),
509 "$padding", static_cast<int>(kClientHelloMinimumSize
),
512 ASSERT_EQ(kREJ
, out_
.tag());
513 const HandshakeFailureReason kRejectReasons
[] = {
514 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
,
515 CLIENT_NONCE_INVALID_FAILURE
,
516 SERVER_NONCE_DECRYPTION_FAILURE
,
518 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
521 TEST_P(CryptoServerTest
, ReplayProtection
) {
522 // This tests that disabling replay protection works.
523 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
527 "SCID", scid_hex_
.c_str(),
528 "#004b5453", srct_hex_
.c_str(),
529 "PUBS", pub_hex_
.c_str(),
530 "NONC", nonce_hex_
.c_str(),
531 "VER\0", client_version_
.data(),
532 "$padding", static_cast<int>(kClientHelloMinimumSize
),
535 // The message should be rejected because the strike-register is still
537 ASSERT_EQ(kREJ
, out_
.tag());
539 const HandshakeFailureReason kRejectReasons
[] = {
540 CLIENT_NONCE_INVALID_TIME_FAILURE
542 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
544 config_
.set_replay_protection(false);
547 // The message should be accepted now.
548 ASSERT_EQ(kSHLO
, out_
.tag());
549 CheckServerHello(out_
);
552 // The message should accepted twice when replay protection is off.
553 ASSERT_EQ(kSHLO
, out_
.tag());
554 CheckServerHello(out_
);
557 TEST(CryptoServerConfigGenerationTest
, Determinism
) {
558 // Test that using a deterministic PRNG causes the server-config to be
561 MockRandom rand_a
, rand_b
;
562 const QuicCryptoServerConfig::ConfigOptions options
;
565 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
566 QuicCryptoServerConfig
b(QuicCryptoServerConfig::TESTING
, &rand_b
);
567 scoped_ptr
<CryptoHandshakeMessage
> scfg_a(
568 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
569 scoped_ptr
<CryptoHandshakeMessage
> scfg_b(
570 b
.AddDefaultConfig(&rand_b
, &clock
, options
));
572 ASSERT_EQ(scfg_a
->DebugString(), scfg_b
->DebugString());
575 TEST(CryptoServerConfigGenerationTest
, SCIDVaries
) {
576 // This test ensures that the server config ID varies for different server
579 MockRandom rand_a
, rand_b
;
580 const QuicCryptoServerConfig::ConfigOptions options
;
583 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
584 rand_b
.ChangeValue();
585 QuicCryptoServerConfig
b(QuicCryptoServerConfig::TESTING
, &rand_b
);
586 scoped_ptr
<CryptoHandshakeMessage
> scfg_a(
587 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
588 scoped_ptr
<CryptoHandshakeMessage
> scfg_b(
589 b
.AddDefaultConfig(&rand_b
, &clock
, options
));
591 StringPiece scid_a
, scid_b
;
592 EXPECT_TRUE(scfg_a
->GetStringPiece(kSCID
, &scid_a
));
593 EXPECT_TRUE(scfg_b
->GetStringPiece(kSCID
, &scid_b
));
595 EXPECT_NE(scid_a
, scid_b
);
599 TEST(CryptoServerConfigGenerationTest
, SCIDIsHashOfServerConfig
) {
601 const QuicCryptoServerConfig::ConfigOptions options
;
604 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
605 scoped_ptr
<CryptoHandshakeMessage
> scfg(
606 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
609 EXPECT_TRUE(scfg
->GetStringPiece(kSCID
, &scid
));
610 // Need to take a copy of |scid| has we're about to call |Erase|.
611 const string
scid_str(scid
.as_string());
615 const QuicData
& serialized(scfg
->GetSerialized());
617 scoped_ptr
<crypto::SecureHash
> hash(
618 crypto::SecureHash::Create(crypto::SecureHash::SHA256
));
619 hash
->Update(serialized
.data(), serialized
.length());
621 hash
->Finish(digest
, sizeof(digest
));
623 ASSERT_EQ(scid
.size(), sizeof(digest
));
624 EXPECT_EQ(0, memcmp(digest
, scid_str
.data(), sizeof(digest
)));
627 class CryptoServerTestNoConfig
: public CryptoServerTest
{
629 void SetUp() override
{
630 // Deliberately don't add a config so that we can test this situation.
634 TEST_P(CryptoServerTestNoConfig
, DontCrash
) {
635 ShouldFailMentioning("No config", InchoateClientHello(
637 "VER\0", client_version_
.data(),
640 const HandshakeFailureReason kRejectReasons
[] = {
641 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
643 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
646 class AsyncStrikeServerVerificationTest
: public CryptoServerTest
{
648 AsyncStrikeServerVerificationTest() {
651 void SetUp() override
{
652 const string kOrbit
= "12345678";
653 config_options_
.orbit
= kOrbit
;
654 strike_register_client_
= new DelayedVerifyStrikeRegisterClient(
655 10000, // strike_register_max_entries
656 static_cast<uint32
>(clock_
.WallNow().ToUNIXSeconds()),
657 60, // strike_register_window_secs
658 reinterpret_cast<const uint8
*>(kOrbit
.data()),
659 StrikeRegister::NO_STARTUP_PERIOD_NEEDED
);
660 config_
.SetStrikeRegisterClient(strike_register_client_
);
661 CryptoServerTest::SetUp();
662 strike_register_client_
->StartDelayingVerification();
665 DelayedVerifyStrikeRegisterClient
* strike_register_client_
;
668 TEST_P(AsyncStrikeServerVerificationTest
, AsyncReplayProtection
) {
669 // This tests async validation with a strike register works.
670 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
674 "SCID", scid_hex_
.c_str(),
675 "#004b5453", srct_hex_
.c_str(),
676 "PUBS", pub_hex_
.c_str(),
677 "NONC", nonce_hex_
.c_str(),
678 "VER\0", client_version_
.data(),
679 "$padding", static_cast<int>(kClientHelloMinimumSize
),
682 // Clear the message tag.
686 RunValidate(msg
, new ValidateCallback(this, true, "", &called
));
687 // The verification request was queued.
688 ASSERT_FALSE(called
);
689 EXPECT_EQ(0u, out_
.tag());
690 EXPECT_EQ(1, strike_register_client_
->PendingVerifications());
692 // Continue processing the verification request.
693 strike_register_client_
->RunPendingVerifications();
695 EXPECT_EQ(0, strike_register_client_
->PendingVerifications());
696 // The message should be accepted now.
697 EXPECT_EQ(kSHLO
, out_
.tag());
699 // Rejected if replayed.
700 RunValidate(msg
, new ValidateCallback(this, true, "", &called
));
701 // The verification request was queued.
702 ASSERT_FALSE(called
);
703 EXPECT_EQ(1, strike_register_client_
->PendingVerifications());
705 strike_register_client_
->RunPendingVerifications();
707 EXPECT_EQ(0, strike_register_client_
->PendingVerifications());
708 // The message should be rejected now.
709 EXPECT_EQ(kREJ
, out_
.tag());