| 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" |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 delete result; | 201 delete result; |
| 202 delete this; | 202 delete this; |
| 203 } | 203 } |
| 204 | 204 |
| 205 QuicCryptoServerConfig::ConfigOptions::ConfigOptions() | 205 QuicCryptoServerConfig::ConfigOptions::ConfigOptions() |
| 206 : expiry_time(QuicWallTime::Zero()), | 206 : expiry_time(QuicWallTime::Zero()), |
| 207 channel_id_enabled(false), | 207 channel_id_enabled(false), |
| 208 p256(false) {} | 208 p256(false) {} |
| 209 | 209 |
| 210 QuicCryptoServerConfig::QuicCryptoServerConfig( | 210 QuicCryptoServerConfig::QuicCryptoServerConfig( |
| 211 StringPiece source_address_token_secret, | 211 StringPiece source_address_token_secret, QuicRandom* server_nonce_entropy, |
| 212 QuicRandom* server_nonce_entropy, | |
| 213 ProofSource* proof_source) | 212 ProofSource* proof_source) |
| 214 : replay_protection_(true), | 213 : replay_protection_(true), |
| 215 configs_lock_(), | 214 configs_lock_(), |
| 216 primary_config_(nullptr), | 215 primary_config_(nullptr), |
| 217 next_config_promotion_time_(QuicWallTime::Zero()), | 216 next_config_promotion_time_(QuicWallTime::Zero()), |
| 218 server_nonce_strike_register_lock_(), | 217 server_nonce_strike_register_lock_(), |
| 219 proof_source_(proof_source), | 218 proof_source_(proof_source), |
| 220 strike_register_no_startup_period_(false), | 219 strike_register_no_startup_period_(false), |
| 221 strike_register_max_entries_(1 << 10), | 220 strike_register_max_entries_(1 << 10), |
| 222 strike_register_window_secs_(600), | 221 strike_register_window_secs_(600), |
| 223 source_address_token_future_secs_(3600), | 222 source_address_token_future_secs_(3600), |
| 224 source_address_token_lifetime_secs_(86400), | 223 source_address_token_lifetime_secs_(86400), |
| 225 server_nonce_strike_register_max_entries_(1 << 10), | 224 server_nonce_strike_register_max_entries_(1 << 10), |
| 226 server_nonce_strike_register_window_secs_(120) { | 225 server_nonce_strike_register_window_secs_(120), |
| 226 enable_serving_sct_(false) { |
| 227 DCHECK(proof_source_.get()); | 227 DCHECK(proof_source_.get()); |
| 228 default_source_address_token_boxer_.SetKey( | 228 default_source_address_token_boxer_.SetKey( |
| 229 DeriveSourceAddressTokenKey(source_address_token_secret)); | 229 DeriveSourceAddressTokenKey(source_address_token_secret)); |
| 230 | 230 |
| 231 // Generate a random key and orbit for server nonces. | 231 // Generate a random key and orbit for server nonces. |
| 232 server_nonce_entropy->RandBytes(server_nonce_orbit_, | 232 server_nonce_entropy->RandBytes(server_nonce_orbit_, |
| 233 sizeof(server_nonce_orbit_)); | 233 sizeof(server_nonce_orbit_)); |
| 234 const size_t key_size = server_nonce_boxer_.GetKeySize(); | 234 const size_t key_size = server_nonce_boxer_.GetKeySize(); |
| 235 scoped_ptr<uint8[]> key_bytes(new uint8[key_size]); | 235 scoped_ptr<uint8[]> key_bytes(new uint8[key_size]); |
| 236 server_nonce_entropy->RandBytes(key_bytes.get(), key_size); | 236 server_nonce_entropy->RandBytes(key_bytes.get(), key_size); |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 | 604 |
| 605 out->Clear(); | 605 out->Clear(); |
| 606 | 606 |
| 607 bool x509_supported = false; | 607 bool x509_supported = false; |
| 608 bool x509_ecdsa_supported = false; | 608 bool x509_ecdsa_supported = false; |
| 609 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); | 609 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); |
| 610 DCHECK(proof_source_.get()); | 610 DCHECK(proof_source_.get()); |
| 611 if (!crypto_proof->certs && | 611 if (!crypto_proof->certs && |
| 612 !proof_source_->GetProof(server_ip, info.sni.as_string(), | 612 !proof_source_->GetProof(server_ip, info.sni.as_string(), |
| 613 primary_config->serialized, x509_ecdsa_supported, | 613 primary_config->serialized, x509_ecdsa_supported, |
| 614 &crypto_proof->certs, | 614 &crypto_proof->certs, &crypto_proof->signature, |
| 615 &crypto_proof->signature)) { | 615 &crypto_proof->cert_sct)) { |
| 616 return QUIC_HANDSHAKE_FAILED; | 616 return QUIC_HANDSHAKE_FAILED; |
| 617 } | 617 } |
| 618 | 618 |
| 619 if (version > QUIC_VERSION_29) { |
| 620 StringPiece cert_sct; |
| 621 if (client_hello.GetStringPiece(kCertificateSCTTag, &cert_sct) && |
| 622 cert_sct.empty()) { |
| 623 params->sct_supported_by_client = true; |
| 624 } |
| 625 } |
| 626 |
| 619 if (!info.reject_reasons.empty() || !requested_config.get()) { | 627 if (!info.reject_reasons.empty() || !requested_config.get()) { |
| 620 BuildRejection(*primary_config, client_hello, info, | 628 BuildRejection(version, *primary_config, client_hello, info, |
| 621 validate_chlo_result.cached_network_params, | 629 validate_chlo_result.cached_network_params, |
| 622 use_stateless_rejects, server_designated_connection_id, rand, | 630 use_stateless_rejects, server_designated_connection_id, rand, |
| 623 params, *crypto_proof, out); | 631 params, *crypto_proof, out); |
| 624 return QUIC_NO_ERROR; | 632 return QUIC_NO_ERROR; |
| 625 } | 633 } |
| 626 | 634 |
| 627 const QuicTag* their_aeads; | 635 const QuicTag* their_aeads; |
| 628 const QuicTag* their_key_exchanges; | 636 const QuicTag* their_key_exchanges; |
| 629 size_t num_their_aeads, num_their_key_exchanges; | 637 size_t num_their_aeads, num_their_key_exchanges; |
| 630 if (client_hello.GetTaglist(kAEAD, &their_aeads, | 638 if (client_hello.GetTaglist(kAEAD, &their_aeads, |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1007 helper.ValidationComplete(QUIC_NO_ERROR, ""); | 1015 helper.ValidationComplete(QUIC_NO_ERROR, ""); |
| 1008 return; | 1016 return; |
| 1009 } | 1017 } |
| 1010 found_error = true; | 1018 found_error = true; |
| 1011 } | 1019 } |
| 1012 | 1020 |
| 1013 if (version > QUIC_VERSION_25) { | 1021 if (version > QUIC_VERSION_25) { |
| 1014 bool x509_supported = false; | 1022 bool x509_supported = false; |
| 1015 bool x509_ecdsa_supported = false; | 1023 bool x509_ecdsa_supported = false; |
| 1016 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); | 1024 ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported); |
| 1017 if (!proof_source_->GetProof(server_ip, info->sni.as_string(), | 1025 if (!proof_source_->GetProof( |
| 1018 requested_config->serialized, | 1026 server_ip, info->sni.as_string(), requested_config->serialized, |
| 1019 x509_ecdsa_supported, &crypto_proof->certs, | 1027 x509_ecdsa_supported, &crypto_proof->certs, |
| 1020 &crypto_proof->signature)) { | 1028 &crypto_proof->signature, &crypto_proof->cert_sct)) { |
| 1021 found_error = true; | 1029 found_error = true; |
| 1022 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); | 1030 info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); |
| 1023 } | 1031 } |
| 1024 | 1032 |
| 1025 if (!ValidateExpectedLeafCertificate(client_hello, *crypto_proof)) { | 1033 if (!ValidateExpectedLeafCertificate(client_hello, *crypto_proof)) { |
| 1026 found_error = true; | 1034 found_error = true; |
| 1027 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE); | 1035 info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE); |
| 1028 } | 1036 } |
| 1029 } | 1037 } |
| 1030 | 1038 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1108 } | 1116 } |
| 1109 | 1117 |
| 1110 strike_register_client->VerifyNonceIsValidAndUnique( | 1118 strike_register_client->VerifyNonceIsValidAndUnique( |
| 1111 info->client_nonce, | 1119 info->client_nonce, |
| 1112 info->now, | 1120 info->now, |
| 1113 new VerifyNonceIsValidAndUniqueCallback(client_hello_state, done_cb)); | 1121 new VerifyNonceIsValidAndUniqueCallback(client_hello_state, done_cb)); |
| 1114 helper.StartedAsyncCallback(); | 1122 helper.StartedAsyncCallback(); |
| 1115 } | 1123 } |
| 1116 | 1124 |
| 1117 bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage( | 1125 bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage( |
| 1126 QuicVersion version, |
| 1118 const SourceAddressTokens& previous_source_address_tokens, | 1127 const SourceAddressTokens& previous_source_address_tokens, |
| 1119 const IPAddressNumber& server_ip, | 1128 const IPAddressNumber& server_ip, |
| 1120 const IPAddressNumber& client_ip, | 1129 const IPAddressNumber& client_ip, |
| 1121 const QuicClock* clock, | 1130 const QuicClock* clock, |
| 1122 QuicRandom* rand, | 1131 QuicRandom* rand, |
| 1123 const QuicCryptoNegotiatedParameters& params, | 1132 const QuicCryptoNegotiatedParameters& params, |
| 1124 const CachedNetworkParameters* cached_network_params, | 1133 const CachedNetworkParameters* cached_network_params, |
| 1125 CryptoHandshakeMessage* out) const { | 1134 CryptoHandshakeMessage* out) const { |
| 1126 base::AutoLock locked(configs_lock_); | 1135 base::AutoLock locked(configs_lock_); |
| 1127 out->set_tag(kSCUP); | 1136 out->set_tag(kSCUP); |
| 1128 out->SetStringPiece(kSCFG, primary_config_->serialized); | 1137 out->SetStringPiece(kSCFG, primary_config_->serialized); |
| 1129 out->SetStringPiece( | 1138 out->SetStringPiece( |
| 1130 kSourceAddressTokenTag, | 1139 kSourceAddressTokenTag, |
| 1131 NewSourceAddressToken(*primary_config_.get(), | 1140 NewSourceAddressToken(*primary_config_.get(), |
| 1132 previous_source_address_tokens, client_ip, rand, | 1141 previous_source_address_tokens, client_ip, rand, |
| 1133 clock->WallNow(), cached_network_params)); | 1142 clock->WallNow(), cached_network_params)); |
| 1134 | 1143 |
| 1135 const vector<string>* certs; | 1144 const vector<string>* certs; |
| 1136 string signature; | 1145 string signature; |
| 1146 string cert_sct; |
| 1137 if (!proof_source_->GetProof( | 1147 if (!proof_source_->GetProof( |
| 1138 server_ip, params.sni, primary_config_->serialized, | 1148 server_ip, params.sni, primary_config_->serialized, |
| 1139 params.x509_ecdsa_supported, &certs, &signature)) { | 1149 params.x509_ecdsa_supported, &certs, &signature, &cert_sct)) { |
| 1140 DVLOG(1) << "Server: failed to get proof."; | 1150 DVLOG(1) << "Server: failed to get proof."; |
| 1141 return false; | 1151 return false; |
| 1142 } | 1152 } |
| 1143 | 1153 |
| 1144 const string compressed = CertCompressor::CompressChain( | 1154 const string compressed = CertCompressor::CompressChain( |
| 1145 *certs, params.client_common_set_hashes, params.client_cached_cert_hashes, | 1155 *certs, params.client_common_set_hashes, params.client_cached_cert_hashes, |
| 1146 primary_config_->common_cert_sets); | 1156 primary_config_->common_cert_sets); |
| 1147 | 1157 |
| 1148 out->SetStringPiece(kCertificateTag, compressed); | 1158 out->SetStringPiece(kCertificateTag, compressed); |
| 1149 out->SetStringPiece(kPROF, signature); | 1159 out->SetStringPiece(kPROF, signature); |
| 1160 if (params.sct_supported_by_client && version > QUIC_VERSION_29 && |
| 1161 enable_serving_sct_) { |
| 1162 if (cert_sct.empty()) { |
| 1163 DLOG(WARNING) << "SCT is expected but it is empty."; |
| 1164 } else { |
| 1165 out->SetStringPiece(kCertificateSCTTag, cert_sct); |
| 1166 } |
| 1167 } |
| 1150 return true; | 1168 return true; |
| 1151 } | 1169 } |
| 1152 | 1170 |
| 1153 void QuicCryptoServerConfig::BuildRejection( | 1171 void QuicCryptoServerConfig::BuildRejection( |
| 1154 const Config& config, | 1172 QuicVersion version, const Config& config, |
| 1155 const CryptoHandshakeMessage& client_hello, | 1173 const CryptoHandshakeMessage& client_hello, const ClientHelloInfo& info, |
| 1156 const ClientHelloInfo& info, | |
| 1157 const CachedNetworkParameters& cached_network_params, | 1174 const CachedNetworkParameters& cached_network_params, |
| 1158 bool use_stateless_rejects, | 1175 bool use_stateless_rejects, |
| 1159 QuicConnectionId server_designated_connection_id, | 1176 QuicConnectionId server_designated_connection_id, QuicRandom* rand, |
| 1160 QuicRandom* rand, | 1177 QuicCryptoNegotiatedParameters* params, const QuicCryptoProof& crypto_proof, |
| 1161 QuicCryptoNegotiatedParameters* params, | |
| 1162 const QuicCryptoProof& crypto_proof, | |
| 1163 CryptoHandshakeMessage* out) const { | 1178 CryptoHandshakeMessage* out) const { |
| 1164 if (FLAGS_enable_quic_stateless_reject_support && use_stateless_rejects) { | 1179 if (FLAGS_enable_quic_stateless_reject_support && use_stateless_rejects) { |
| 1165 DVLOG(1) << "QUIC Crypto server config returning stateless reject " | 1180 DVLOG(1) << "QUIC Crypto server config returning stateless reject " |
| 1166 << "with server-designated connection ID " | 1181 << "with server-designated connection ID " |
| 1167 << server_designated_connection_id; | 1182 << server_designated_connection_id; |
| 1168 out->set_tag(kSREJ); | 1183 out->set_tag(kSREJ); |
| 1169 out->SetValue(kRCID, server_designated_connection_id); | 1184 out->SetValue(kRCID, server_designated_connection_id); |
| 1170 } else { | 1185 } else { |
| 1171 out->set_tag(kREJ); | 1186 out->set_tag(kREJ); |
| 1172 } | 1187 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1208 // kREJOverheadBytes is a very rough estimate of how much of a REJ | 1223 // kREJOverheadBytes is a very rough estimate of how much of a REJ |
| 1209 // message is taken up by things other than the certificates. | 1224 // message is taken up by things other than the certificates. |
| 1210 // STK: 56 bytes | 1225 // STK: 56 bytes |
| 1211 // SNO: 56 bytes | 1226 // SNO: 56 bytes |
| 1212 // SCFG | 1227 // SCFG |
| 1213 // SCID: 16 bytes | 1228 // SCID: 16 bytes |
| 1214 // PUBS: 38 bytes | 1229 // PUBS: 38 bytes |
| 1215 const size_t kREJOverheadBytes = 166; | 1230 const size_t kREJOverheadBytes = 166; |
| 1216 // kMultiplier is the multiple of the CHLO message size that a REJ message | 1231 // kMultiplier is the multiple of the CHLO message size that a REJ message |
| 1217 // must stay under when the client doesn't present a valid source-address | 1232 // must stay under when the client doesn't present a valid source-address |
| 1218 // token. | 1233 // token. This is used to protect QUIC from amplification attacks. |
| 1219 const size_t kMultiplier = 2; | 1234 const size_t kMultiplier = 2; |
| 1220 // max_unverified_size is the number of bytes that the certificate chain | 1235 // max_unverified_size is the number of bytes that the certificate chain, |
| 1221 // and signature can consume before we will demand a valid source-address | 1236 // signature, and (optionally) signed certificate timestamp can consume before |
| 1222 // token. | 1237 // we will demand a valid source-address token. |
| 1223 const size_t max_unverified_size = | 1238 const size_t max_unverified_size = |
| 1224 client_hello.size() * kMultiplier - kREJOverheadBytes; | 1239 client_hello.size() * kMultiplier - kREJOverheadBytes; |
| 1225 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes, | 1240 static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes, |
| 1226 "overhead calculation may overflow"); | 1241 "overhead calculation may underflow"); |
| 1242 bool should_return_sct = params->sct_supported_by_client && |
| 1243 version > QUIC_VERSION_29 && enable_serving_sct_; |
| 1244 const size_t sct_size = should_return_sct ? crypto_proof.cert_sct.size() : 0; |
| 1227 if (info.valid_source_address_token || | 1245 if (info.valid_source_address_token || |
| 1228 crypto_proof.signature.size() + compressed.size() < max_unverified_size) { | 1246 crypto_proof.signature.size() + compressed.size() + sct_size < |
| 1247 max_unverified_size) { |
| 1229 out->SetStringPiece(kCertificateTag, compressed); | 1248 out->SetStringPiece(kCertificateTag, compressed); |
| 1230 out->SetStringPiece(kPROF, crypto_proof.signature); | 1249 out->SetStringPiece(kPROF, crypto_proof.signature); |
| 1250 if (should_return_sct) { |
| 1251 if (crypto_proof.cert_sct.empty()) { |
| 1252 DLOG(WARNING) << "SCT is expected but it is empty."; |
| 1253 } else { |
| 1254 out->SetStringPiece(kCertificateSCTTag, crypto_proof.cert_sct); |
| 1255 } |
| 1256 } |
| 1231 } | 1257 } |
| 1232 } | 1258 } |
| 1233 | 1259 |
| 1234 scoped_refptr<QuicCryptoServerConfig::Config> | 1260 scoped_refptr<QuicCryptoServerConfig::Config> |
| 1235 QuicCryptoServerConfig::ParseConfigProtobuf( | 1261 QuicCryptoServerConfig::ParseConfigProtobuf( |
| 1236 QuicServerConfigProtobuf* protobuf) { | 1262 QuicServerConfigProtobuf* protobuf) { |
| 1237 scoped_ptr<CryptoHandshakeMessage> msg( | 1263 scoped_ptr<CryptoHandshakeMessage> msg( |
| 1238 CryptoFramer::ParseMessage(protobuf->config())); | 1264 CryptoFramer::ParseMessage(protobuf->config())); |
| 1239 | 1265 |
| 1240 if (msg->tag() != kSCFG) { | 1266 if (msg->tag() != kSCFG) { |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1445 DCHECK(!server_nonce_strike_register_.get()); | 1471 DCHECK(!server_nonce_strike_register_.get()); |
| 1446 server_nonce_strike_register_max_entries_ = max_entries; | 1472 server_nonce_strike_register_max_entries_ = max_entries; |
| 1447 } | 1473 } |
| 1448 | 1474 |
| 1449 void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs( | 1475 void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs( |
| 1450 uint32 window_secs) { | 1476 uint32 window_secs) { |
| 1451 DCHECK(!server_nonce_strike_register_.get()); | 1477 DCHECK(!server_nonce_strike_register_.get()); |
| 1452 server_nonce_strike_register_window_secs_ = window_secs; | 1478 server_nonce_strike_register_window_secs_ = window_secs; |
| 1453 } | 1479 } |
| 1454 | 1480 |
| 1481 void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) { |
| 1482 enable_serving_sct_ = enable_serving_sct; |
| 1483 } |
| 1484 |
| 1455 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb( | 1485 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb( |
| 1456 PrimaryConfigChangedCallback* cb) { | 1486 PrimaryConfigChangedCallback* cb) { |
| 1457 base::AutoLock locked(configs_lock_); | 1487 base::AutoLock locked(configs_lock_); |
| 1458 primary_config_changed_cb_.reset(cb); | 1488 primary_config_changed_cb_.reset(cb); |
| 1459 } | 1489 } |
| 1460 | 1490 |
| 1461 string QuicCryptoServerConfig::NewSourceAddressToken( | 1491 string QuicCryptoServerConfig::NewSourceAddressToken( |
| 1462 const Config& config, | 1492 const Config& config, |
| 1463 const SourceAddressTokens& previous_tokens, | 1493 const SourceAddressTokens& previous_tokens, |
| 1464 const IPAddressNumber& ip, | 1494 const IPAddressNumber& ip, |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1706 QuicCryptoServerConfig::Config::Config() | 1736 QuicCryptoServerConfig::Config::Config() |
| 1707 : channel_id_enabled(false), | 1737 : channel_id_enabled(false), |
| 1708 is_primary(false), | 1738 is_primary(false), |
| 1709 primary_time(QuicWallTime::Zero()), | 1739 primary_time(QuicWallTime::Zero()), |
| 1710 priority(0), | 1740 priority(0), |
| 1711 source_address_token_boxer(nullptr) {} | 1741 source_address_token_boxer(nullptr) {} |
| 1712 | 1742 |
| 1713 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } | 1743 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } |
| 1714 | 1744 |
| 1715 } // namespace net | 1745 } // namespace net |
| OLD | NEW |