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 |