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_
, &clock_
, cb
);
200 void ShouldFailMentioning(const char* error_substr
,
201 const CryptoHandshakeMessage
& message
) {
203 ShouldFailMentioning(error_substr
, message
, &called
);
207 void ShouldFailMentioning(const char* error_substr
,
208 const CryptoHandshakeMessage
& message
,
210 config_
.ValidateClientHello(
211 message
, client_address_
, &clock_
,
212 new ValidateCallback(this, false, error_substr
, called
));
215 void ProcessValidationResult(const CryptoHandshakeMessage
& message
,
216 const ValidateCallback::Result
& result
,
218 const char* error_substr
) {
219 IPEndPoint server_ip
;
220 string error_details
;
221 QuicErrorCode error
= config_
.ProcessClientHello(
222 result
, 1 /* ConnectionId */, server_ip
, client_address_
,
223 supported_versions_
.front(), supported_versions_
, &clock_
, rand_
,
224 ¶ms_
, &out_
, &error_details
);
226 if (should_succeed
) {
227 ASSERT_EQ(error
, QUIC_NO_ERROR
)
228 << "Message failed with error " << error_details
<< ": "
229 << message
.DebugString();
231 ASSERT_NE(error
, QUIC_NO_ERROR
)
232 << "Message didn't fail: " << message
.DebugString();
234 EXPECT_TRUE(error_details
.find(error_substr
) != string::npos
)
235 << error_substr
<< " not in " << error_details
;
239 CryptoHandshakeMessage
InchoateClientHello(const char* message_tag
, ...) {
241 va_start(ap
, message_tag
);
243 CryptoHandshakeMessage message
=
244 CryptoTestUtils::BuildMessage(message_tag
, ap
);
247 message
.SetStringPiece(kPAD
, string(kClientHelloMinimumSize
, '-'));
251 string
GenerateNonce() {
253 CryptoUtils::GenerateNonce(
254 clock_
.WallNow(), rand_
,
255 StringPiece(reinterpret_cast<const char*>(orbit_
), sizeof(orbit_
)),
260 void CheckRejectReasons(
261 const HandshakeFailureReason
* expected_handshake_failures
,
262 size_t expected_count
) {
263 const uint32
* reject_reasons
;
264 size_t num_reject_reasons
;
265 static_assert(sizeof(QuicTag
) == sizeof(uint32
), "header out of sync");
266 QuicErrorCode error_code
= out_
.GetTaglist(kRREJ
, &reject_reasons
,
267 &num_reject_reasons
);
268 ASSERT_EQ(QUIC_NO_ERROR
, error_code
);
270 if (FLAGS_use_early_return_when_verifying_chlo
) {
271 EXPECT_EQ(1u, num_reject_reasons
);
273 EXPECT_EQ(expected_count
, num_reject_reasons
);
275 for (size_t i
= 0; i
< num_reject_reasons
; ++i
) {
276 EXPECT_EQ(expected_handshake_failures
[i
], reject_reasons
[i
]);
281 QuicRandom
* const rand_
;
283 const IPEndPoint client_address_
;
284 QuicVersionVector supported_versions_
;
285 string client_version_
;
286 QuicCryptoServerConfig config_
;
287 QuicCryptoServerConfig::ConfigOptions config_options_
;
288 QuicCryptoNegotiatedParameters params_
;
289 CryptoHandshakeMessage out_
;
290 uint8 orbit_
[kOrbitSize
];
292 // These strings contain hex escaped values from the server suitable for
293 // passing to |InchoateClientHello| when constructing client hello messages.
294 string nonce_hex_
, pub_hex_
, srct_hex_
, scid_hex_
;
295 scoped_ptr
<CryptoHandshakeMessage
> server_config_
;
298 // Run all CryptoServerTest with both values of
299 // FLAGS_use_early_return_when_verifying_chlo
300 INSTANTIATE_TEST_CASE_P(CryptoServerTests
,
302 ::testing::ValuesIn(GetTestParams()));
304 TEST_P(CryptoServerTest
, BadSNI
) {
305 static const char* const kBadSNIs
[] = {
314 string client_version
= QuicUtils::TagToString(
315 QuicVersionToQuicTag(supported_versions_
.front()));
317 for (size_t i
= 0; i
< arraysize(kBadSNIs
); i
++) {
318 ShouldFailMentioning("SNI", InchoateClientHello(
321 "VER\0", client_version
.data(),
323 const HandshakeFailureReason kRejectReasons
[] = {
324 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
326 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
330 // TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
331 TEST_F(CryptoServerTest
, DISABLED_DefaultCert
) {
332 // Check that the server replies with a default certificate when no SNI is
334 ShouldSucceed(InchoateClientHello(
338 "SCID", scid_hex_
.c_str(),
339 "#004b5453", srct_hex_
.c_str(),
340 "PUBS", pub_hex_
.c_str(),
341 "NONC", nonce_hex_
.c_str(),
342 "$padding", static_cast<int>(kClientHelloMinimumSize
),
344 "VER\0", client_version_
.data(),
347 StringPiece cert
, proof
;
348 EXPECT_TRUE(out_
.GetStringPiece(kCertificateTag
, &cert
));
349 EXPECT_TRUE(out_
.GetStringPiece(kPROF
, &proof
));
350 EXPECT_NE(0u, cert
.size());
351 EXPECT_NE(0u, proof
.size());
352 const HandshakeFailureReason kRejectReasons
[] = {
353 CLIENT_NONCE_INVALID_TIME_FAILURE
355 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
358 TEST_P(CryptoServerTest
, TooSmall
) {
359 ShouldFailMentioning("too small", CryptoTestUtils::Message(
361 "VER\0", client_version_
.data(),
363 const HandshakeFailureReason kRejectReasons
[] = {
364 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
366 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
369 TEST_P(CryptoServerTest
, BadSourceAddressToken
) {
370 // Invalid source-address tokens should be ignored.
371 static const char* const kBadSourceAddressTokens
[] = {
375 "#0000000000000000000000000000000000000000",
378 for (size_t i
= 0; i
< arraysize(kBadSourceAddressTokens
); i
++) {
379 ShouldSucceed(InchoateClientHello(
381 "STK", kBadSourceAddressTokens
[i
],
382 "VER\0", client_version_
.data(),
384 const HandshakeFailureReason kRejectReasons
[] = {
385 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
387 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
391 TEST_P(CryptoServerTest
, BadClientNonce
) {
392 // Invalid nonces should be ignored.
393 static const char* const kBadNonces
[] = {
396 "#0000000000000000000000000000000000000000",
399 for (size_t i
= 0; i
< arraysize(kBadNonces
); i
++) {
400 ShouldSucceed(InchoateClientHello(
402 "NONC", kBadNonces
[i
],
403 "VER\0", client_version_
.data(),
405 const HandshakeFailureReason kRejectReasons
[] = {
406 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
408 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
412 TEST_P(CryptoServerTest
, DowngradeAttack
) {
413 if (supported_versions_
.size() == 1) {
414 // No downgrade attack is possible if the server only supports one version.
417 // Set the client's preferred version to a supported version that
418 // is not the "current" version (supported_versions_.front()).
419 string bad_version
= QuicUtils::TagToString(
420 QuicVersionToQuicTag(supported_versions_
.back()));
422 ShouldFailMentioning("Downgrade", InchoateClientHello(
424 "VER\0", bad_version
.data(),
426 const HandshakeFailureReason kRejectReasons
[] = {
427 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
429 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
432 TEST_P(CryptoServerTest
, CorruptServerConfig
) {
433 // This tests corrupted server config.
434 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
438 "SCID", (string(1, 'X') + scid_hex_
).c_str(),
439 "#004b5453", srct_hex_
.c_str(),
440 "PUBS", pub_hex_
.c_str(),
441 "NONC", nonce_hex_
.c_str(),
442 "VER\0", client_version_
.data(),
443 "$padding", static_cast<int>(kClientHelloMinimumSize
),
446 ASSERT_EQ(kREJ
, out_
.tag());
447 const HandshakeFailureReason kRejectReasons
[] = {
448 SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE
450 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
453 TEST_P(CryptoServerTest
, CorruptSourceAddressToken
) {
454 // This tests corrupted source address token.
455 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
459 "SCID", scid_hex_
.c_str(),
460 "#004b5453", (string(1, 'X') + srct_hex_
).c_str(),
461 "PUBS", pub_hex_
.c_str(),
462 "NONC", nonce_hex_
.c_str(),
463 "VER\0", client_version_
.data(),
464 "$padding", static_cast<int>(kClientHelloMinimumSize
),
467 ASSERT_EQ(kREJ
, out_
.tag());
468 const HandshakeFailureReason kRejectReasons
[] = {
469 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
471 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
474 TEST_P(CryptoServerTest
, CorruptClientNonceAndSourceAddressToken
) {
475 // This test corrupts client nonce and source address token.
476 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
480 "SCID", scid_hex_
.c_str(),
481 "#004b5453", (string(1, 'X') + srct_hex_
).c_str(),
482 "PUBS", pub_hex_
.c_str(),
483 "NONC", (string(1, 'X') + nonce_hex_
).c_str(),
484 "VER\0", client_version_
.data(),
485 "$padding", static_cast<int>(kClientHelloMinimumSize
),
488 ASSERT_EQ(kREJ
, out_
.tag());
489 const HandshakeFailureReason kRejectReasons
[] = {
490 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
,
491 CLIENT_NONCE_INVALID_FAILURE
493 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
496 TEST_P(CryptoServerTest
, CorruptMultipleTags
) {
497 // This test corrupts client nonce, server nonce and source address token.
498 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
502 "SCID", scid_hex_
.c_str(),
503 "#004b5453", (string(1, 'X') + srct_hex_
).c_str(),
504 "PUBS", pub_hex_
.c_str(),
505 "NONC", (string(1, 'X') + nonce_hex_
).c_str(),
506 "SNO\0", (string(1, 'X') + nonce_hex_
).c_str(),
507 "VER\0", client_version_
.data(),
508 "$padding", static_cast<int>(kClientHelloMinimumSize
),
511 ASSERT_EQ(kREJ
, out_
.tag());
512 const HandshakeFailureReason kRejectReasons
[] = {
513 SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
,
514 CLIENT_NONCE_INVALID_FAILURE
,
515 SERVER_NONCE_DECRYPTION_FAILURE
,
517 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
520 TEST_P(CryptoServerTest
, ReplayProtection
) {
521 // This tests that disabling replay protection works.
522 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
526 "SCID", scid_hex_
.c_str(),
527 "#004b5453", srct_hex_
.c_str(),
528 "PUBS", pub_hex_
.c_str(),
529 "NONC", nonce_hex_
.c_str(),
530 "VER\0", client_version_
.data(),
531 "$padding", static_cast<int>(kClientHelloMinimumSize
),
534 // The message should be rejected because the strike-register is still
536 ASSERT_EQ(kREJ
, out_
.tag());
538 const HandshakeFailureReason kRejectReasons
[] = {
539 CLIENT_NONCE_INVALID_TIME_FAILURE
541 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
543 config_
.set_replay_protection(false);
546 // The message should be accepted now.
547 ASSERT_EQ(kSHLO
, out_
.tag());
548 CheckServerHello(out_
);
551 // The message should accepted twice when replay protection is off.
552 ASSERT_EQ(kSHLO
, out_
.tag());
553 CheckServerHello(out_
);
556 TEST(CryptoServerConfigGenerationTest
, Determinism
) {
557 // Test that using a deterministic PRNG causes the server-config to be
560 MockRandom rand_a
, rand_b
;
561 const QuicCryptoServerConfig::ConfigOptions options
;
564 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
565 QuicCryptoServerConfig
b(QuicCryptoServerConfig::TESTING
, &rand_b
);
566 scoped_ptr
<CryptoHandshakeMessage
> scfg_a(
567 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
568 scoped_ptr
<CryptoHandshakeMessage
> scfg_b(
569 b
.AddDefaultConfig(&rand_b
, &clock
, options
));
571 ASSERT_EQ(scfg_a
->DebugString(), scfg_b
->DebugString());
574 TEST(CryptoServerConfigGenerationTest
, SCIDVaries
) {
575 // This test ensures that the server config ID varies for different server
578 MockRandom rand_a
, rand_b
;
579 const QuicCryptoServerConfig::ConfigOptions options
;
582 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
583 rand_b
.ChangeValue();
584 QuicCryptoServerConfig
b(QuicCryptoServerConfig::TESTING
, &rand_b
);
585 scoped_ptr
<CryptoHandshakeMessage
> scfg_a(
586 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
587 scoped_ptr
<CryptoHandshakeMessage
> scfg_b(
588 b
.AddDefaultConfig(&rand_b
, &clock
, options
));
590 StringPiece scid_a
, scid_b
;
591 EXPECT_TRUE(scfg_a
->GetStringPiece(kSCID
, &scid_a
));
592 EXPECT_TRUE(scfg_b
->GetStringPiece(kSCID
, &scid_b
));
594 EXPECT_NE(scid_a
, scid_b
);
598 TEST(CryptoServerConfigGenerationTest
, SCIDIsHashOfServerConfig
) {
600 const QuicCryptoServerConfig::ConfigOptions options
;
603 QuicCryptoServerConfig
a(QuicCryptoServerConfig::TESTING
, &rand_a
);
604 scoped_ptr
<CryptoHandshakeMessage
> scfg(
605 a
.AddDefaultConfig(&rand_a
, &clock
, options
));
608 EXPECT_TRUE(scfg
->GetStringPiece(kSCID
, &scid
));
609 // Need to take a copy of |scid| has we're about to call |Erase|.
610 const string
scid_str(scid
.as_string());
614 const QuicData
& serialized(scfg
->GetSerialized());
616 scoped_ptr
<crypto::SecureHash
> hash(
617 crypto::SecureHash::Create(crypto::SecureHash::SHA256
));
618 hash
->Update(serialized
.data(), serialized
.length());
620 hash
->Finish(digest
, sizeof(digest
));
622 ASSERT_EQ(scid
.size(), sizeof(digest
));
623 EXPECT_EQ(0, memcmp(digest
, scid_str
.data(), sizeof(digest
)));
626 class CryptoServerTestNoConfig
: public CryptoServerTest
{
628 void SetUp() override
{
629 // Deliberately don't add a config so that we can test this situation.
633 TEST_P(CryptoServerTestNoConfig
, DontCrash
) {
634 ShouldFailMentioning("No config", InchoateClientHello(
636 "VER\0", client_version_
.data(),
639 const HandshakeFailureReason kRejectReasons
[] = {
640 SERVER_CONFIG_INCHOATE_HELLO_FAILURE
642 CheckRejectReasons(kRejectReasons
, arraysize(kRejectReasons
));
645 class AsyncStrikeServerVerificationTest
: public CryptoServerTest
{
647 AsyncStrikeServerVerificationTest() {
650 void SetUp() override
{
651 const string kOrbit
= "12345678";
652 config_options_
.orbit
= kOrbit
;
653 strike_register_client_
= new DelayedVerifyStrikeRegisterClient(
654 10000, // strike_register_max_entries
655 static_cast<uint32
>(clock_
.WallNow().ToUNIXSeconds()),
656 60, // strike_register_window_secs
657 reinterpret_cast<const uint8
*>(kOrbit
.data()),
658 StrikeRegister::NO_STARTUP_PERIOD_NEEDED
);
659 config_
.SetStrikeRegisterClient(strike_register_client_
);
660 CryptoServerTest::SetUp();
661 strike_register_client_
->StartDelayingVerification();
664 DelayedVerifyStrikeRegisterClient
* strike_register_client_
;
667 TEST_P(AsyncStrikeServerVerificationTest
, AsyncReplayProtection
) {
668 // This tests async validation with a strike register works.
669 CryptoHandshakeMessage msg
= CryptoTestUtils::Message(
673 "SCID", scid_hex_
.c_str(),
674 "#004b5453", srct_hex_
.c_str(),
675 "PUBS", pub_hex_
.c_str(),
676 "NONC", nonce_hex_
.c_str(),
677 "VER\0", client_version_
.data(),
678 "$padding", static_cast<int>(kClientHelloMinimumSize
),
681 // Clear the message tag.
685 RunValidate(msg
, new ValidateCallback(this, true, "", &called
));
686 // The verification request was queued.
687 ASSERT_FALSE(called
);
688 EXPECT_EQ(0u, out_
.tag());
689 EXPECT_EQ(1, strike_register_client_
->PendingVerifications());
691 // Continue processing the verification request.
692 strike_register_client_
->RunPendingVerifications();
694 EXPECT_EQ(0, strike_register_client_
->PendingVerifications());
695 // The message should be accepted now.
696 EXPECT_EQ(kSHLO
, out_
.tag());
698 // Rejected if replayed.
699 RunValidate(msg
, new ValidateCallback(this, true, "", &called
));
700 // The verification request was queued.
701 ASSERT_FALSE(called
);
702 EXPECT_EQ(1, strike_register_client_
->PendingVerifications());
704 strike_register_client_
->RunPendingVerifications();
706 EXPECT_EQ(0, strike_register_client_
->PendingVerifications());
707 // The message should be rejected now.
708 EXPECT_EQ(kREJ
, out_
.tag());