OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/crypto/quic_crypto_server_config.h" | 5 #include "net/quic/crypto/quic_crypto_server_config.h" |
6 | 6 |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 | 9 |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "crypto/hkdf.h" | 12 #include "crypto/hkdf.h" |
13 #include "crypto/secure_hash.h" | 13 #include "crypto/secure_hash.h" |
14 #include "net/base/net_util.h" | 14 #include "net/base/net_util.h" |
15 #include "net/quic/crypto/aes_128_gcm_12_decrypter.h" | 15 #include "net/quic/crypto/aes_128_gcm_12_decrypter.h" |
16 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" | 16 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" |
17 #include "net/quic/crypto/cert_compressor.h" | 17 #include "net/quic/crypto/cert_compressor.h" |
18 #include "net/quic/crypto/chacha20_poly1305_encrypter.h" | 18 #include "net/quic/crypto/chacha20_poly1305_encrypter.h" |
19 #include "net/quic/crypto/channel_id.h" | 19 #include "net/quic/crypto/channel_id.h" |
20 #include "net/quic/crypto/crypto_framer.h" | 20 #include "net/quic/crypto/crypto_framer.h" |
| 21 #include "net/quic/crypto/crypto_handshake_message.h" |
21 #include "net/quic/crypto/crypto_server_config_protobuf.h" | 22 #include "net/quic/crypto/crypto_server_config_protobuf.h" |
22 #include "net/quic/crypto/crypto_utils.h" | 23 #include "net/quic/crypto/crypto_utils.h" |
23 #include "net/quic/crypto/curve25519_key_exchange.h" | 24 #include "net/quic/crypto/curve25519_key_exchange.h" |
24 #include "net/quic/crypto/ephemeral_key_source.h" | 25 #include "net/quic/crypto/ephemeral_key_source.h" |
25 #include "net/quic/crypto/key_exchange.h" | 26 #include "net/quic/crypto/key_exchange.h" |
26 #include "net/quic/crypto/local_strike_register_client.h" | 27 #include "net/quic/crypto/local_strike_register_client.h" |
27 #include "net/quic/crypto/p256_key_exchange.h" | 28 #include "net/quic/crypto/p256_key_exchange.h" |
28 #include "net/quic/crypto/proof_source.h" | 29 #include "net/quic/crypto/proof_source.h" |
29 #include "net/quic/crypto/quic_decrypter.h" | 30 #include "net/quic/crypto/quic_decrypter.h" |
30 #include "net/quic/crypto/quic_encrypter.h" | 31 #include "net/quic/crypto/quic_encrypter.h" |
(...skipping 23 matching lines...) Expand all Loading... |
54 StringPiece() /* no salt */, | 55 StringPiece() /* no salt */, |
55 "QUIC source address token key", | 56 "QUIC source address token key", |
56 CryptoSecretBoxer::GetKeySize(), | 57 CryptoSecretBoxer::GetKeySize(), |
57 0 /* no fixed IV needed */, | 58 0 /* no fixed IV needed */, |
58 0 /* no subkey secret */); | 59 0 /* no subkey secret */); |
59 return hkdf.server_write_key().as_string(); | 60 return hkdf.server_write_key().as_string(); |
60 } | 61 } |
61 | 62 |
62 } // namespace | 63 } // namespace |
63 | 64 |
64 // ClientHelloInfo contains information about a client hello message that is | |
65 // only kept for as long as it's being processed. | |
66 struct ClientHelloInfo { | |
67 ClientHelloInfo(const IPEndPoint& in_client_ip, QuicWallTime in_now) | |
68 : client_ip(in_client_ip), | |
69 now(in_now), | |
70 valid_source_address_token(false), | |
71 client_nonce_well_formed(false), | |
72 unique(false) {} | |
73 | |
74 // Inputs to EvaluateClientHello. | |
75 const IPEndPoint client_ip; | |
76 const QuicWallTime now; | |
77 | |
78 // Outputs from EvaluateClientHello. | |
79 bool valid_source_address_token; | |
80 bool client_nonce_well_formed; | |
81 bool unique; | |
82 StringPiece sni; | |
83 StringPiece client_nonce; | |
84 StringPiece server_nonce; | |
85 StringPiece user_agent_id; | |
86 | |
87 // Errors from EvaluateClientHello. | |
88 vector<uint32> reject_reasons; | |
89 COMPILE_ASSERT(sizeof(QuicTag) == sizeof(uint32), header_out_of_sync); | |
90 }; | |
91 | |
92 struct ValidateClientHelloResultCallback::Result { | |
93 Result(const CryptoHandshakeMessage& in_client_hello, | |
94 IPEndPoint in_client_ip, | |
95 QuicWallTime in_now) | |
96 : client_hello(in_client_hello), | |
97 info(in_client_ip, in_now), | |
98 error_code(QUIC_NO_ERROR) { | |
99 } | |
100 | |
101 CryptoHandshakeMessage client_hello; | |
102 ClientHelloInfo info; | |
103 QuicErrorCode error_code; | |
104 string error_details; | |
105 }; | |
106 | |
107 class ValidateClientHelloHelper { | 65 class ValidateClientHelloHelper { |
108 public: | 66 public: |
109 ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result* result, | 67 ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result* result, |
110 ValidateClientHelloResultCallback* done_cb) | 68 ValidateClientHelloResultCallback* done_cb) |
111 : result_(result), done_cb_(done_cb) { | 69 : result_(result), done_cb_(done_cb) { |
112 } | 70 } |
113 | 71 |
114 ~ValidateClientHelloHelper() { | 72 ~ValidateClientHelloHelper() { |
115 LOG_IF(DFATAL, done_cb_ != nullptr) | 73 LOG_IF(DFATAL, done_cb_ != nullptr) |
116 << "Deleting ValidateClientHelloHelper with a pending callback."; | 74 << "Deleting ValidateClientHelloHelper with a pending callback."; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 private: | 150 private: |
193 ValidateClientHelloResultCallback::Result* result_; | 151 ValidateClientHelloResultCallback::Result* result_; |
194 ValidateClientHelloResultCallback* done_cb_; | 152 ValidateClientHelloResultCallback* done_cb_; |
195 | 153 |
196 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback); | 154 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback); |
197 }; | 155 }; |
198 | 156 |
199 // static | 157 // static |
200 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; | 158 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; |
201 | 159 |
| 160 ClientHelloInfo::ClientHelloInfo(const IPEndPoint& in_client_ip, |
| 161 QuicWallTime in_now) |
| 162 : client_ip(in_client_ip), |
| 163 now(in_now), |
| 164 valid_source_address_token(false), |
| 165 client_nonce_well_formed(false), |
| 166 unique(false) { |
| 167 } |
| 168 |
| 169 ClientHelloInfo::~ClientHelloInfo() { |
| 170 } |
| 171 |
202 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() { | 172 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() { |
203 } | 173 } |
204 | 174 |
205 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() { | 175 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() { |
206 } | 176 } |
207 | 177 |
| 178 ValidateClientHelloResultCallback::Result::Result( |
| 179 const CryptoHandshakeMessage& in_client_hello, |
| 180 IPEndPoint in_client_ip, |
| 181 QuicWallTime in_now) |
| 182 : client_hello(in_client_hello), |
| 183 info(in_client_ip, in_now), |
| 184 error_code(QUIC_NO_ERROR) { |
| 185 } |
| 186 |
| 187 ValidateClientHelloResultCallback::Result::~Result() { |
| 188 } |
| 189 |
208 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() { | 190 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() { |
209 } | 191 } |
210 | 192 |
211 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() { | 193 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() { |
212 } | 194 } |
213 | 195 |
214 void ValidateClientHelloResultCallback::Run(const Result* result) { | 196 void ValidateClientHelloResultCallback::Run(const Result* result) { |
215 RunImpl(result->client_hello, *result); | 197 RunImpl(result->client_hello, *result); |
216 delete result; | 198 delete result; |
217 delete this; | 199 delete this; |
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 *error_details = validate_chlo_result.error_details; | 578 *error_details = validate_chlo_result.error_details; |
597 return validate_chlo_result.error_code; | 579 return validate_chlo_result.error_code; |
598 } | 580 } |
599 | 581 |
600 out->Clear(); | 582 out->Clear(); |
601 | 583 |
602 if (!info.valid_source_address_token || | 584 if (!info.valid_source_address_token || |
603 !info.client_nonce_well_formed || | 585 !info.client_nonce_well_formed || |
604 !info.unique || | 586 !info.unique || |
605 !requested_config.get()) { | 587 !requested_config.get()) { |
606 BuildRejection( | 588 BuildRejection(*primary_config.get(), client_hello, info, |
607 *primary_config.get(), client_hello, info, rand, params, out); | 589 validate_chlo_result.cached_network_params, rand, params, |
| 590 out); |
608 return QUIC_NO_ERROR; | 591 return QUIC_NO_ERROR; |
609 } | 592 } |
610 | 593 |
611 const QuicTag* their_aeads; | 594 const QuicTag* their_aeads; |
612 const QuicTag* their_key_exchanges; | 595 const QuicTag* their_key_exchanges; |
613 size_t num_their_aeads, num_their_key_exchanges; | 596 size_t num_their_aeads, num_their_key_exchanges; |
614 if (client_hello.GetTaglist(kAEAD, &their_aeads, | 597 if (client_hello.GetTaglist(kAEAD, &their_aeads, |
615 &num_their_aeads) != QUIC_NO_ERROR || | 598 &num_their_aeads) != QUIC_NO_ERROR || |
616 client_hello.GetTaglist(kKEXS, &their_key_exchanges, | 599 client_hello.GetTaglist(kKEXS, &their_key_exchanges, |
617 &num_their_key_exchanges) != QUIC_NO_ERROR || | 600 &num_their_key_exchanges) != QUIC_NO_ERROR || |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
942 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); | 925 info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); |
943 } | 926 } |
944 // No server config with the requested ID. | 927 // No server config with the requested ID. |
945 helper.ValidationComplete(QUIC_NO_ERROR, ""); | 928 helper.ValidationComplete(QUIC_NO_ERROR, ""); |
946 return; | 929 return; |
947 } | 930 } |
948 | 931 |
949 HandshakeFailureReason source_address_token_error; | 932 HandshakeFailureReason source_address_token_error; |
950 StringPiece srct; | 933 StringPiece srct; |
951 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { | 934 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { |
952 source_address_token_error = ValidateSourceAddressToken( | 935 source_address_token_error = |
953 *requested_config.get(), srct, info->client_ip, info->now); | 936 ValidateSourceAddressToken(*requested_config.get(), |
| 937 srct, |
| 938 info->client_ip, |
| 939 info->now, |
| 940 &client_hello_state->cached_network_params); |
954 info->valid_source_address_token = | 941 info->valid_source_address_token = |
955 (source_address_token_error == HANDSHAKE_OK); | 942 (source_address_token_error == HANDSHAKE_OK); |
956 } else { | 943 } else { |
957 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; | 944 source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; |
958 } | 945 } |
959 | 946 |
960 bool found_error = false; | 947 bool found_error = false; |
961 if (source_address_token_error != HANDSHAKE_OK) { | 948 if (source_address_token_error != HANDSHAKE_OK) { |
962 info->reject_reasons.push_back(source_address_token_error); | 949 info->reject_reasons.push_back(source_address_token_error); |
963 // No valid source address token. | 950 // No valid source address token. |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1076 | 1063 |
1077 out->SetStringPiece(kCertificateTag, compressed); | 1064 out->SetStringPiece(kCertificateTag, compressed); |
1078 out->SetStringPiece(kPROF, signature); | 1065 out->SetStringPiece(kPROF, signature); |
1079 return true; | 1066 return true; |
1080 } | 1067 } |
1081 | 1068 |
1082 void QuicCryptoServerConfig::BuildRejection( | 1069 void QuicCryptoServerConfig::BuildRejection( |
1083 const Config& config, | 1070 const Config& config, |
1084 const CryptoHandshakeMessage& client_hello, | 1071 const CryptoHandshakeMessage& client_hello, |
1085 const ClientHelloInfo& info, | 1072 const ClientHelloInfo& info, |
| 1073 const CachedNetworkParameters& cached_network_params, |
1086 QuicRandom* rand, | 1074 QuicRandom* rand, |
1087 QuicCryptoNegotiatedParameters *params, | 1075 QuicCryptoNegotiatedParameters *params, |
1088 CryptoHandshakeMessage* out) const { | 1076 CryptoHandshakeMessage* out) const { |
1089 out->set_tag(kREJ); | 1077 out->set_tag(kREJ); |
1090 out->SetStringPiece(kSCFG, config.serialized); | 1078 out->SetStringPiece(kSCFG, config.serialized); |
1091 out->SetStringPiece(kSourceAddressTokenTag, | 1079 out->SetStringPiece(kSourceAddressTokenTag, |
1092 NewSourceAddressToken( | 1080 NewSourceAddressToken( |
1093 config, | 1081 config, |
1094 info.client_ip, | 1082 info.client_ip, |
1095 rand, | 1083 rand, |
1096 info.now, | 1084 info.now, |
1097 nullptr)); | 1085 &cached_network_params)); |
1098 if (replay_protection_) { | 1086 if (replay_protection_) { |
1099 out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now)); | 1087 out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now)); |
1100 } | 1088 } |
1101 | 1089 |
1102 if (FLAGS_send_quic_crypto_reject_reason) { | 1090 if (FLAGS_send_quic_crypto_reject_reason) { |
1103 // Send client the reject reason for debugging purposes. | 1091 // Send client the reject reason for debugging purposes. |
1104 DCHECK_LT(0u, info.reject_reasons.size()); | 1092 DCHECK_LT(0u, info.reject_reasons.size()); |
1105 out->SetVector(kRREJ, info.reject_reasons); | 1093 out->SetVector(kRREJ, info.reject_reasons); |
1106 } | 1094 } |
1107 | 1095 |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1430 } | 1418 } |
1431 | 1419 |
1432 return config.source_address_token_boxer->Box( | 1420 return config.source_address_token_boxer->Box( |
1433 rand, source_address_token.SerializeAsString()); | 1421 rand, source_address_token.SerializeAsString()); |
1434 } | 1422 } |
1435 | 1423 |
1436 HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressToken( | 1424 HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressToken( |
1437 const Config& config, | 1425 const Config& config, |
1438 StringPiece token, | 1426 StringPiece token, |
1439 const IPEndPoint& ip, | 1427 const IPEndPoint& ip, |
1440 QuicWallTime now) const { | 1428 QuicWallTime now, |
| 1429 CachedNetworkParameters* cached_network_params) const { |
1441 string storage; | 1430 string storage; |
1442 StringPiece plaintext; | 1431 StringPiece plaintext; |
1443 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) { | 1432 if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) { |
1444 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE; | 1433 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE; |
1445 } | 1434 } |
1446 | 1435 |
1447 SourceAddressToken source_address_token; | 1436 SourceAddressToken source_address_token; |
1448 if (!source_address_token.ParseFromArray(plaintext.data(), | 1437 if (!source_address_token.ParseFromArray(plaintext.data(), |
1449 plaintext.size())) { | 1438 plaintext.size())) { |
1450 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE; | 1439 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE; |
(...skipping 15 matching lines...) Expand all Loading... |
1466 if (now.IsBefore(timestamp) && | 1455 if (now.IsBefore(timestamp) && |
1467 delta.ToSeconds() > source_address_token_future_secs_) { | 1456 delta.ToSeconds() > source_address_token_future_secs_) { |
1468 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE; | 1457 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE; |
1469 } | 1458 } |
1470 | 1459 |
1471 if (now.IsAfter(timestamp) && | 1460 if (now.IsAfter(timestamp) && |
1472 delta.ToSeconds() > source_address_token_lifetime_secs_) { | 1461 delta.ToSeconds() > source_address_token_lifetime_secs_) { |
1473 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE; | 1462 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE; |
1474 } | 1463 } |
1475 | 1464 |
| 1465 if (FLAGS_quic_store_cached_network_params_from_chlo && |
| 1466 source_address_token.has_cached_network_parameters()) { |
| 1467 *cached_network_params = source_address_token.cached_network_parameters(); |
| 1468 } |
| 1469 |
1476 return HANDSHAKE_OK; | 1470 return HANDSHAKE_OK; |
1477 } | 1471 } |
1478 | 1472 |
1479 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server | 1473 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server |
1480 // nonce. | 1474 // nonce. |
1481 static const size_t kServerNoncePlaintextSize = | 1475 static const size_t kServerNoncePlaintextSize = |
1482 4 /* timestamp */ + 20 /* random bytes */; | 1476 4 /* timestamp */ + 20 /* random bytes */; |
1483 | 1477 |
1484 string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand, | 1478 string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand, |
1485 QuicWallTime now) const { | 1479 QuicWallTime now) const { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1562 QuicCryptoServerConfig::Config::Config() | 1556 QuicCryptoServerConfig::Config::Config() |
1563 : channel_id_enabled(false), | 1557 : channel_id_enabled(false), |
1564 is_primary(false), | 1558 is_primary(false), |
1565 primary_time(QuicWallTime::Zero()), | 1559 primary_time(QuicWallTime::Zero()), |
1566 priority(0), | 1560 priority(0), |
1567 source_address_token_boxer(nullptr) {} | 1561 source_address_token_boxer(nullptr) {} |
1568 | 1562 |
1569 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } | 1563 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } |
1570 | 1564 |
1571 } // namespace net | 1565 } // namespace net |
OLD | NEW |