| 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 |