| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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/crypto_server_config.h" | 5 #include "net/quic/crypto/crypto_server_config.h" |
| 6 | 6 |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 8 | 8 |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "crypto/hkdf.h" | 10 #include "crypto/hkdf.h" |
| 11 #include "crypto/secure_hash.h" | 11 #include "crypto/secure_hash.h" |
| 12 #include "net/quic/crypto/aes_128_gcm_12_decrypter.h" | 12 #include "net/quic/crypto/aes_128_gcm_12_decrypter.h" |
| 13 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" | 13 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" |
| 14 #include "net/quic/crypto/cert_compressor.h" | 14 #include "net/quic/crypto/cert_compressor.h" |
| 15 #include "net/quic/crypto/channel_id.h" |
| 15 #include "net/quic/crypto/crypto_framer.h" | 16 #include "net/quic/crypto/crypto_framer.h" |
| 16 #include "net/quic/crypto/crypto_server_config_protobuf.h" | 17 #include "net/quic/crypto/crypto_server_config_protobuf.h" |
| 17 #include "net/quic/crypto/crypto_utils.h" | 18 #include "net/quic/crypto/crypto_utils.h" |
| 18 #include "net/quic/crypto/curve25519_key_exchange.h" | 19 #include "net/quic/crypto/curve25519_key_exchange.h" |
| 19 #include "net/quic/crypto/ephemeral_key_source.h" | 20 #include "net/quic/crypto/ephemeral_key_source.h" |
| 20 #include "net/quic/crypto/key_exchange.h" | 21 #include "net/quic/crypto/key_exchange.h" |
| 21 #include "net/quic/crypto/p256_key_exchange.h" | 22 #include "net/quic/crypto/p256_key_exchange.h" |
| 22 #include "net/quic/crypto/proof_source.h" | 23 #include "net/quic/crypto/proof_source.h" |
| 23 #include "net/quic/crypto/quic_decrypter.h" | 24 #include "net/quic/crypto/quic_decrypter.h" |
| 24 #include "net/quic/crypto/quic_encrypter.h" | 25 #include "net/quic/crypto/quic_encrypter.h" |
| 25 #include "net/quic/crypto/quic_random.h" | 26 #include "net/quic/crypto/quic_random.h" |
| 26 #include "net/quic/crypto/source_address_token.h" | 27 #include "net/quic/crypto/source_address_token.h" |
| 27 #include "net/quic/crypto/strike_register.h" | 28 #include "net/quic/crypto/strike_register.h" |
| 28 #include "net/quic/quic_clock.h" | 29 #include "net/quic/quic_clock.h" |
| 29 #include "net/quic/quic_protocol.h" | 30 #include "net/quic/quic_protocol.h" |
| 30 #include "net/quic/quic_utils.h" | 31 #include "net/quic/quic_utils.h" |
| 31 | 32 |
| 32 using base::StringPiece; | 33 using base::StringPiece; |
| 33 using crypto::SecureHash; | 34 using crypto::SecureHash; |
| 34 using std::map; | 35 using std::map; |
| 35 using std::string; | 36 using std::string; |
| 36 using std::vector; | 37 using std::vector; |
| 37 | 38 |
| 38 namespace net { | 39 namespace net { |
| 39 | 40 |
| 40 // static | 41 // static |
| 41 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; | 42 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; |
| 42 | 43 |
| 44 QuicCryptoServerConfig::ConfigOptions::ConfigOptions() |
| 45 : expiry_time(QuicWallTime::Zero()), |
| 46 channel_id_enabled(false) { } |
| 47 |
| 43 QuicCryptoServerConfig::QuicCryptoServerConfig( | 48 QuicCryptoServerConfig::QuicCryptoServerConfig( |
| 44 StringPiece source_address_token_secret) | 49 StringPiece source_address_token_secret, |
| 50 QuicRandom* rand) |
| 45 : strike_register_lock_(), | 51 : strike_register_lock_(), |
| 52 server_nonce_strike_register_lock_(), |
| 46 strike_register_max_entries_(1 << 10), | 53 strike_register_max_entries_(1 << 10), |
| 47 strike_register_window_secs_(600), | 54 strike_register_window_secs_(600), |
| 48 source_address_token_future_secs_(3600), | 55 source_address_token_future_secs_(3600), |
| 49 source_address_token_lifetime_secs_(86400) { | 56 source_address_token_lifetime_secs_(86400), |
| 57 server_nonce_strike_register_max_entries_(1 << 10), |
| 58 server_nonce_strike_register_window_secs_(120) { |
| 50 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, | 59 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, |
| 51 "QUIC source address token key", | 60 "QUIC source address token key", |
| 52 CryptoSecretBoxer::GetKeySize(), | 61 CryptoSecretBoxer::GetKeySize(), |
| 53 0 /* no fixed IV needed */); | 62 0 /* no fixed IV needed */); |
| 54 source_address_token_boxer_.SetKey(hkdf.server_write_key()); | 63 source_address_token_boxer_.SetKey(hkdf.server_write_key()); |
| 64 |
| 65 // Generate a random key and orbit for server nonces. |
| 66 rand->RandBytes(server_nonce_orbit_, sizeof(server_nonce_orbit_)); |
| 67 const size_t key_size = server_nonce_boxer_.GetKeySize(); |
| 68 scoped_ptr<uint8[]> key_bytes(new uint8[key_size]); |
| 69 rand->RandBytes(key_bytes.get(), key_size); |
| 70 |
| 71 server_nonce_boxer_.SetKey( |
| 72 StringPiece(reinterpret_cast<char*>(key_bytes.get()), key_size)); |
| 55 } | 73 } |
| 56 | 74 |
| 57 QuicCryptoServerConfig::~QuicCryptoServerConfig() { | 75 QuicCryptoServerConfig::~QuicCryptoServerConfig() { |
| 58 STLDeleteValues(&configs_); | 76 STLDeleteValues(&configs_); |
| 59 } | 77 } |
| 60 | 78 |
| 61 // static | 79 // static |
| 62 QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( | 80 QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( |
| 63 QuicRandom* rand, | 81 QuicRandom* rand, |
| 64 const QuicClock* clock, | 82 const QuicClock* clock, |
| 65 uint64 expiry_time) { | 83 const ConfigOptions& options) { |
| 66 CryptoHandshakeMessage msg; | 84 CryptoHandshakeMessage msg; |
| 67 | 85 |
| 68 const string curve25519_private_key = | 86 const string curve25519_private_key = |
| 69 Curve25519KeyExchange::NewPrivateKey(rand); | 87 Curve25519KeyExchange::NewPrivateKey(rand); |
| 70 scoped_ptr<Curve25519KeyExchange> curve25519( | 88 scoped_ptr<Curve25519KeyExchange> curve25519( |
| 71 Curve25519KeyExchange::New(curve25519_private_key)); | 89 Curve25519KeyExchange::New(curve25519_private_key)); |
| 72 StringPiece curve25519_public_value = curve25519->public_value(); | 90 StringPiece curve25519_public_value = curve25519->public_value(); |
| 73 | 91 |
| 74 const string p256_private_key = P256KeyExchange::NewPrivateKey(); | 92 const string p256_private_key = P256KeyExchange::NewPrivateKey(); |
| 75 scoped_ptr<P256KeyExchange> p256(P256KeyExchange::New(p256_private_key)); | 93 scoped_ptr<P256KeyExchange> p256(P256KeyExchange::New(p256_private_key)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 87 encoded_public_values.push_back(p256_public_value.size() >> 16); | 105 encoded_public_values.push_back(p256_public_value.size() >> 16); |
| 88 encoded_public_values.append(p256_public_value.data(), | 106 encoded_public_values.append(p256_public_value.data(), |
| 89 p256_public_value.size()); | 107 p256_public_value.size()); |
| 90 | 108 |
| 91 msg.set_tag(kSCFG); | 109 msg.set_tag(kSCFG); |
| 92 msg.SetTaglist(kKEXS, kC255, kP256, 0); | 110 msg.SetTaglist(kKEXS, kC255, kP256, 0); |
| 93 msg.SetTaglist(kAEAD, kAESG, 0); | 111 msg.SetTaglist(kAEAD, kAESG, 0); |
| 94 msg.SetValue(kVERS, static_cast<uint16>(0)); | 112 msg.SetValue(kVERS, static_cast<uint16>(0)); |
| 95 msg.SetStringPiece(kPUBS, encoded_public_values); | 113 msg.SetStringPiece(kPUBS, encoded_public_values); |
| 96 | 114 |
| 97 if (expiry_time == 0) { | 115 if (options.expiry_time.IsZero()) { |
| 98 const QuicWallTime now = clock->WallNow(); | 116 const QuicWallTime now = clock->WallNow(); |
| 99 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( | 117 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( |
| 100 60 * 60 * 24 * 180 /* 180 days, ~six months */)); | 118 60 * 60 * 24 * 180 /* 180 days, ~six months */)); |
| 101 const uint64 expiry_seconds = expiry.ToUNIXSeconds(); | 119 const uint64 expiry_seconds = expiry.ToUNIXSeconds(); |
| 102 msg.SetValue(kEXPY, expiry_seconds); | 120 msg.SetValue(kEXPY, expiry_seconds); |
| 103 } else { | 121 } else { |
| 104 msg.SetValue(kEXPY, expiry_time); | 122 msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds()); |
| 105 } | 123 } |
| 106 | 124 |
| 107 char scid_bytes[16]; | 125 char scid_bytes[16]; |
| 108 rand->RandBytes(scid_bytes, sizeof(scid_bytes)); | 126 rand->RandBytes(scid_bytes, sizeof(scid_bytes)); |
| 109 msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes))); | 127 msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes))); |
| 110 | 128 |
| 111 char orbit_bytes[kOrbitSize]; | 129 char orbit_bytes[kOrbitSize]; |
| 112 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes)); | 130 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes)); |
| 113 msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes))); | 131 msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes))); |
| 114 | 132 |
| 133 if (options.channel_id_enabled) { |
| 134 msg.SetTaglist(kPDMD, kCHID, 0); |
| 135 } |
| 136 |
| 115 scoped_ptr<QuicData> serialized(CryptoFramer::ConstructHandshakeMessage(msg)); | 137 scoped_ptr<QuicData> serialized(CryptoFramer::ConstructHandshakeMessage(msg)); |
| 116 | 138 |
| 117 scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf); | 139 scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf); |
| 118 config->set_config(serialized->AsStringPiece()); | 140 config->set_config(serialized->AsStringPiece()); |
| 119 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key(); | 141 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key(); |
| 120 curve25519_key->set_tag(kC255); | 142 curve25519_key->set_tag(kC255); |
| 121 curve25519_key->set_private_key(curve25519_private_key); | 143 curve25519_key->set_private_key(curve25519_private_key); |
| 122 QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key(); | 144 QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key(); |
| 123 p256_key->set_tag(kP256); | 145 p256_key->set_tag(kP256); |
| 124 p256_key->set_private_key(p256_private_key); | 146 p256_key->set_private_key(p256_private_key); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 COMPILE_ASSERT(sizeof(config->orbit) == kOrbitSize, orbit_incorrect_size); | 202 COMPILE_ASSERT(sizeof(config->orbit) == kOrbitSize, orbit_incorrect_size); |
| 181 memcpy(config->orbit, orbit.data(), sizeof(config->orbit)); | 203 memcpy(config->orbit, orbit.data(), sizeof(config->orbit)); |
| 182 | 204 |
| 183 if (kexs_len != protobuf->key_size()) { | 205 if (kexs_len != protobuf->key_size()) { |
| 184 LOG(WARNING) << "Server config has " << kexs_len | 206 LOG(WARNING) << "Server config has " << kexs_len |
| 185 << " key exchange methods configured, but " | 207 << " key exchange methods configured, but " |
| 186 << protobuf->key_size() << " private keys"; | 208 << protobuf->key_size() << " private keys"; |
| 187 return NULL; | 209 return NULL; |
| 188 } | 210 } |
| 189 | 211 |
| 212 const QuicTag* proof_demand_tags; |
| 213 size_t num_proof_demand_tags; |
| 214 if (msg->GetTaglist(kPDMD, &proof_demand_tags, &num_proof_demand_tags) == |
| 215 QUIC_NO_ERROR) { |
| 216 for (size_t i = 0; i < num_proof_demand_tags; i++) { |
| 217 if (proof_demand_tags[i] == kCHID) { |
| 218 config->channel_id_enabled = true; |
| 219 break; |
| 220 } |
| 221 } |
| 222 } |
| 223 |
| 190 for (size_t i = 0; i < kexs_len; i++) { | 224 for (size_t i = 0; i < kexs_len; i++) { |
| 191 const QuicTag tag = kexs_tags[i]; | 225 const QuicTag tag = kexs_tags[i]; |
| 192 string private_key; | 226 string private_key; |
| 193 | 227 |
| 194 config->kexs.push_back(tag); | 228 config->kexs.push_back(tag); |
| 195 | 229 |
| 196 for (size_t j = 0; j < protobuf->key_size(); j++) { | 230 for (size_t j = 0; j < protobuf->key_size(); j++) { |
| 197 const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i); | 231 const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i); |
| 198 if (key.tag() == tag) { | 232 if (key.tag() == tag) { |
| 199 private_key = key.private_key(); | 233 private_key = key.private_key(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 if (msg->GetUint16(kVERS, &config->version) != QUIC_NO_ERROR) { | 279 if (msg->GetUint16(kVERS, &config->version) != QUIC_NO_ERROR) { |
| 246 LOG(WARNING) << "Server config message is missing version"; | 280 LOG(WARNING) << "Server config message is missing version"; |
| 247 return NULL; | 281 return NULL; |
| 248 } | 282 } |
| 249 | 283 |
| 250 if (config->version != QuicCryptoConfig::CONFIG_VERSION) { | 284 if (config->version != QuicCryptoConfig::CONFIG_VERSION) { |
| 251 LOG(WARNING) << "Server config specifies an unsupported version"; | 285 LOG(WARNING) << "Server config specifies an unsupported version"; |
| 252 return NULL; | 286 return NULL; |
| 253 } | 287 } |
| 254 | 288 |
| 289 // FIXME(agl): this is mismatched with |DefaultConfig|, which generates a |
| 290 // random id. |
| 255 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256)); | 291 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256)); |
| 256 sha256->Update(protobuf->config().data(), protobuf->config().size()); | 292 sha256->Update(protobuf->config().data(), protobuf->config().size()); |
| 257 char id_bytes[16]; | 293 char id_bytes[16]; |
| 258 sha256->Finish(id_bytes, sizeof(id_bytes)); | 294 sha256->Finish(id_bytes, sizeof(id_bytes)); |
| 259 const string id(id_bytes, sizeof(id_bytes)); | 295 const string id(id_bytes, sizeof(id_bytes)); |
| 260 | 296 |
| 261 configs_[id] = config.release(); | 297 configs_[id] = config.release(); |
| 262 active_config_ = id; | 298 active_config_ = id; |
| 263 | 299 |
| 264 return msg.release(); | 300 return msg.release(); |
| 265 } | 301 } |
| 266 | 302 |
| 267 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( | 303 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( |
| 268 QuicRandom* rand, | 304 QuicRandom* rand, |
| 269 const QuicClock* clock, | 305 const QuicClock* clock, |
| 270 uint64 expiry_time) { | 306 const ConfigOptions& options) { |
| 271 scoped_ptr<QuicServerConfigProtobuf> config( | 307 scoped_ptr<QuicServerConfigProtobuf> config( |
| 272 DefaultConfig(rand, clock, expiry_time)); | 308 DefaultConfig(rand, clock, options)); |
| 273 return AddConfig(config.get()); | 309 return AddConfig(config.get()); |
| 274 } | 310 } |
| 275 | 311 |
| 276 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( | 312 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( |
| 277 const CryptoHandshakeMessage& client_hello, | 313 const CryptoHandshakeMessage& client_hello, |
| 278 QuicGuid guid, | 314 QuicGuid guid, |
| 279 const IPEndPoint& client_ip, | 315 const IPEndPoint& client_ip, |
| 280 const QuicClock* clock, | 316 const QuicClock* clock, |
| 281 QuicRandom* rand, | 317 QuicRandom* rand, |
| 282 QuicCryptoNegotiatedParameters *params, | 318 QuicCryptoNegotiatedParameters *params, |
| (...skipping 21 matching lines...) Expand all Loading... |
| 304 } | 340 } |
| 305 | 341 |
| 306 const QuicWallTime now = clock->WallNow(); | 342 const QuicWallTime now = clock->WallNow(); |
| 307 bool valid_source_address_token = false; | 343 bool valid_source_address_token = false; |
| 308 StringPiece srct; | 344 StringPiece srct; |
| 309 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct) && | 345 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct) && |
| 310 ValidateSourceAddressToken(srct, client_ip, now)) { | 346 ValidateSourceAddressToken(srct, client_ip, now)) { |
| 311 valid_source_address_token = true; | 347 valid_source_address_token = true; |
| 312 } | 348 } |
| 313 | 349 |
| 314 const string fresh_source_address_token = | 350 StringPiece sni; |
| 315 NewSourceAddressToken(client_ip, rand, now); | 351 if (client_hello.GetStringPiece(kSNI, &sni) && |
| 352 !CryptoUtils::IsValidSNI(sni)) { |
| 353 *error_details = "Invalid SNI name"; |
| 354 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 355 } |
| 316 | 356 |
| 317 // If we previously sent a REJ to this client then we may have stored a | 357 // The client nonce is used first to try and establish uniqueness. |
| 318 // server nonce in |params|. In which case, we know that the connection | |
| 319 // is unique because the server nonce will be mixed into the key generation. | |
| 320 bool unique_by_server_nonce = !params->server_nonce.empty(); | |
| 321 // If we can't ensure uniqueness by a server nonce, then we will try and use | |
| 322 // the strike register. | |
| 323 bool unique_by_strike_register = false; | 358 bool unique_by_strike_register = false; |
| 324 | 359 |
| 325 StringPiece client_nonce; | 360 StringPiece client_nonce; |
| 326 bool client_nonce_well_formed = false; | 361 bool client_nonce_well_formed = false; |
| 327 if (client_hello.GetStringPiece(kNONC, &client_nonce) && | 362 if (client_hello.GetStringPiece(kNONC, &client_nonce) && |
| 328 client_nonce.size() == kNonceSize) { | 363 client_nonce.size() == kNonceSize) { |
| 329 client_nonce_well_formed = true; | 364 client_nonce_well_formed = true; |
| 330 base::AutoLock auto_lock(strike_register_lock_); | 365 base::AutoLock auto_lock(strike_register_lock_); |
| 331 | 366 |
| 332 if (strike_register_.get() == NULL) { | 367 if (strike_register_.get() == NULL) { |
| 333 strike_register_.reset(new StrikeRegister( | 368 strike_register_.reset(new StrikeRegister( |
| 334 strike_register_max_entries_, | 369 strike_register_max_entries_, |
| 335 static_cast<uint32>(now.ToUNIXSeconds()), | 370 static_cast<uint32>(now.ToUNIXSeconds()), |
| 336 strike_register_window_secs_, | 371 strike_register_window_secs_, |
| 337 config->orbit)); | 372 config->orbit, |
| 373 StrikeRegister::DENY_REQUESTS_AT_STARTUP)); |
| 338 } | 374 } |
| 339 unique_by_strike_register = strike_register_->Insert( | 375 unique_by_strike_register = strike_register_->Insert( |
| 340 reinterpret_cast<const uint8*>(client_nonce.data()), | 376 reinterpret_cast<const uint8*>(client_nonce.data()), |
| 341 static_cast<uint32>(now.ToUNIXSeconds())); | 377 static_cast<uint32>(now.ToUNIXSeconds())); |
| 342 } | 378 } |
| 343 | 379 |
| 344 StringPiece server_nonce; | 380 StringPiece server_nonce; |
| 345 client_hello.GetStringPiece(kServerNonceTag, &server_nonce); | 381 client_hello.GetStringPiece(kServerNonceTag, &server_nonce); |
| 346 const bool server_nonce_matches = server_nonce == params->server_nonce; | 382 |
| 383 // If the client nonce didn't establish uniqueness then an echoed server |
| 384 // nonce may. |
| 385 bool unique_by_server_nonce = false; |
| 386 if (!unique_by_strike_register && !server_nonce.empty()) { |
| 387 unique_by_server_nonce = ValidateServerNonce(server_nonce, now); |
| 388 } |
| 347 | 389 |
| 348 out->Clear(); | 390 out->Clear(); |
| 349 | 391 |
| 350 StringPiece sni; | |
| 351 if (client_hello.GetStringPiece(kSNI, &sni) && | |
| 352 !CryptoUtils::IsValidSNI(sni)) { | |
| 353 *error_details = "Invalid SNI name"; | |
| 354 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
| 355 } | |
| 356 | |
| 357 StringPiece scid; | 392 StringPiece scid; |
| 358 if (!client_hello.GetStringPiece(kSCID, &scid) || | 393 if (!client_hello.GetStringPiece(kSCID, &scid) || |
| 359 scid.as_string() != config->id || | 394 scid.as_string() != config->id || |
| 360 !valid_source_address_token || | 395 !valid_source_address_token || |
| 361 !client_nonce_well_formed || | 396 !client_nonce_well_formed || |
| 362 !server_nonce_matches || | |
| 363 (!unique_by_strike_register && | 397 (!unique_by_strike_register && |
| 364 !unique_by_server_nonce)) { | 398 !unique_by_server_nonce)) { |
| 365 // If the client didn't provide a server config ID, or gave the wrong one, | 399 // If the client didn't provide a server config ID, or gave the wrong one, |
| 366 // then the handshake cannot possibly complete. We reject the handshake and | 400 // then the handshake cannot possibly complete. We reject the handshake and |
| 367 // give the client enough information to do better next time. | 401 // give the client enough information to do better next time. |
| 368 out->set_tag(kREJ); | 402 out->set_tag(kREJ); |
| 369 out->SetStringPiece(kSCFG, config->serialized); | 403 out->SetStringPiece(kSCFG, config->serialized); |
| 370 out->SetStringPiece(kSourceAddressTokenTag, fresh_source_address_token); | 404 out->SetStringPiece(kSourceAddressTokenTag, |
| 371 if (params->server_nonce.empty()) { | 405 NewSourceAddressToken(client_ip, rand, now)); |
| 372 CryptoUtils::GenerateNonce( | 406 out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, now)); |
| 373 now, rand, StringPiece(reinterpret_cast<const char*>(config->orbit), | |
| 374 sizeof(config->orbit)), | |
| 375 ¶ms->server_nonce); | |
| 376 } | |
| 377 out->SetStringPiece(kServerNonceTag, params->server_nonce); | |
| 378 | 407 |
| 379 // The client may have requested a certificate chain. | 408 // The client may have requested a certificate chain. |
| 380 const QuicTag* their_proof_demands; | 409 const QuicTag* their_proof_demands; |
| 381 size_t num_their_proof_demands; | 410 size_t num_their_proof_demands; |
| 382 | 411 |
| 383 if (proof_source_.get() != NULL && !sni.empty() && | 412 if (proof_source_.get() != NULL && !sni.empty() && |
| 384 client_hello.GetTaglist(kPDMD, &their_proof_demands, | 413 client_hello.GetTaglist(kPDMD, &their_proof_demands, |
| 385 &num_their_proof_demands) == QUIC_NO_ERROR) { | 414 &num_their_proof_demands) == QUIC_NO_ERROR) { |
| 386 for (size_t i = 0; i < num_their_proof_demands; i++) { | 415 for (size_t i = 0; i < num_their_proof_demands; i++) { |
| 387 if (their_proof_demands[i] != kX509) { | 416 if (their_proof_demands[i] != kX509) { |
| 388 continue; | 417 continue; |
| 389 } | 418 } |
| 390 | 419 |
| 391 const vector<string>* certs; | 420 const vector<string>* certs; |
| 392 string signature; | 421 string signature; |
| 393 if (!proof_source_->GetProof(sni.as_string(), config->serialized, | 422 if (!proof_source_->GetProof(sni.as_string(), config->serialized, |
| 394 &certs, &signature)) { | 423 &certs, &signature)) { |
| 395 break; | 424 break; |
| 396 } | 425 } |
| 397 | 426 |
| 398 StringPiece their_common_set_hashes; | 427 StringPiece their_common_set_hashes; |
| 399 StringPiece their_cached_cert_hashes; | 428 StringPiece their_cached_cert_hashes; |
| 400 client_hello.GetStringPiece(kCCS, &their_common_set_hashes); | 429 client_hello.GetStringPiece(kCCS, &their_common_set_hashes); |
| 401 client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes); | 430 client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes); |
| 402 | 431 |
| 403 const string compressed = CertCompressor::CompressChain( | 432 const string compressed = CertCompressor::CompressChain( |
| 404 *certs, their_common_set_hashes, their_cached_cert_hashes, | 433 *certs, their_common_set_hashes, their_cached_cert_hashes, |
| 405 config->common_cert_sets.get()); | 434 config->common_cert_sets); |
| 406 | 435 |
| 407 // kMaxUnverifiedSize is the number of bytes that the certificate chain | 436 // kMaxUnverifiedSize is the number of bytes that the certificate chain |
| 408 // and signature can consume before we will demand a valid | 437 // and signature can consume before we will demand a valid |
| 409 // source-address token. | 438 // source-address token. |
| 439 // TODO(agl): make this configurable. |
| 410 static const size_t kMaxUnverifiedSize = 400; | 440 static const size_t kMaxUnverifiedSize = 400; |
| 411 if (valid_source_address_token || | 441 if (valid_source_address_token || |
| 412 signature.size() + compressed.size() < kMaxUnverifiedSize) { | 442 signature.size() + compressed.size() < kMaxUnverifiedSize) { |
| 413 out->SetStringPiece(kCertificateTag, compressed); | 443 out->SetStringPiece(kCertificateTag, compressed); |
| 414 out->SetStringPiece(kPROF, signature); | 444 out->SetStringPiece(kPROF, signature); |
| 415 } | 445 } |
| 416 break; | 446 break; |
| 417 } | 447 } |
| 418 } | 448 } |
| 419 | 449 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 | 498 |
| 469 string hkdf_suffix; | 499 string hkdf_suffix; |
| 470 const QuicData& client_hello_serialized = client_hello.GetSerialized(); | 500 const QuicData& client_hello_serialized = client_hello.GetSerialized(); |
| 471 hkdf_suffix.reserve(sizeof(guid) + client_hello_serialized.length() + | 501 hkdf_suffix.reserve(sizeof(guid) + client_hello_serialized.length() + |
| 472 config->serialized.size()); | 502 config->serialized.size()); |
| 473 hkdf_suffix.append(reinterpret_cast<char*>(&guid), sizeof(guid)); | 503 hkdf_suffix.append(reinterpret_cast<char*>(&guid), sizeof(guid)); |
| 474 hkdf_suffix.append(client_hello_serialized.data(), | 504 hkdf_suffix.append(client_hello_serialized.data(), |
| 475 client_hello_serialized.length()); | 505 client_hello_serialized.length()); |
| 476 hkdf_suffix.append(config->serialized); | 506 hkdf_suffix.append(config->serialized); |
| 477 | 507 |
| 508 StringPiece cetv_ciphertext; |
| 509 if (config->channel_id_enabled && |
| 510 client_hello.GetStringPiece(kCETV, &cetv_ciphertext)) { |
| 511 CryptoHandshakeMessage client_hello_copy(client_hello); |
| 512 client_hello_copy.Erase(kCETV); |
| 513 client_hello_copy.Erase(kPAD); |
| 514 |
| 515 const QuicData& client_hello_serialized = client_hello_copy.GetSerialized(); |
| 516 string hkdf_input; |
| 517 hkdf_input.append(QuicCryptoConfig::kCETVLabel, |
| 518 strlen(QuicCryptoConfig::kCETVLabel) + 1); |
| 519 hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid)); |
| 520 hkdf_input.append(client_hello_serialized.data(), |
| 521 client_hello_serialized.length()); |
| 522 hkdf_input.append(config->serialized); |
| 523 |
| 524 CrypterPair crypters; |
| 525 CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, |
| 526 client_nonce, server_nonce, hkdf_input, |
| 527 CryptoUtils::SERVER, &crypters); |
| 528 |
| 529 scoped_ptr<QuicData> cetv_plaintext(crypters.decrypter->DecryptPacket( |
| 530 0 /* sequence number */, StringPiece() /* associated data */, |
| 531 cetv_ciphertext)); |
| 532 if (!cetv_plaintext.get()) { |
| 533 *error_details = "CETV decryption failure"; |
| 534 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 535 } |
| 536 |
| 537 scoped_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage( |
| 538 cetv_plaintext->AsStringPiece())); |
| 539 if (!cetv.get()) { |
| 540 *error_details = "CETV parse error"; |
| 541 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 542 } |
| 543 |
| 544 StringPiece key, signature; |
| 545 if (cetv->GetStringPiece(kCIDK, &key) && |
| 546 cetv->GetStringPiece(kCIDS, &signature)) { |
| 547 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) { |
| 548 *error_details = "ChannelID signature failure"; |
| 549 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 550 } |
| 551 |
| 552 params->channel_id = key.as_string(); |
| 553 } |
| 554 } |
| 555 |
| 478 string hkdf_input; | 556 string hkdf_input; |
| 479 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; | 557 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; |
| 480 hkdf_input.reserve(label_len + hkdf_suffix.size()); | 558 hkdf_input.reserve(label_len + hkdf_suffix.size()); |
| 481 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); | 559 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); |
| 482 hkdf_input.append(hkdf_suffix); | 560 hkdf_input.append(hkdf_suffix); |
| 483 | 561 |
| 484 CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, | 562 CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, |
| 485 client_nonce, params->server_nonce, hkdf_input, | 563 client_nonce, server_nonce, hkdf_input, |
| 486 CryptoUtils::SERVER, ¶ms->initial_crypters); | 564 CryptoUtils::SERVER, ¶ms->initial_crypters); |
| 487 | 565 |
| 488 string forward_secure_public_value; | 566 string forward_secure_public_value; |
| 489 if (ephemeral_key_source_.get()) { | 567 if (ephemeral_key_source_.get()) { |
| 490 params->forward_secure_premaster_secret = | 568 params->forward_secure_premaster_secret = |
| 491 ephemeral_key_source_->CalculateForwardSecureKey( | 569 ephemeral_key_source_->CalculateForwardSecureKey( |
| 492 key_exchange, rand, clock->ApproximateNow(), public_value, | 570 key_exchange, rand, clock->ApproximateNow(), public_value, |
| 493 &forward_secure_public_value); | 571 &forward_secure_public_value); |
| 494 } else { | 572 } else { |
| 495 scoped_ptr<KeyExchange> forward_secure_key_exchange( | 573 scoped_ptr<KeyExchange> forward_secure_key_exchange( |
| 496 key_exchange->NewKeyPair(rand)); | 574 key_exchange->NewKeyPair(rand)); |
| 497 forward_secure_public_value = | 575 forward_secure_public_value = |
| 498 forward_secure_key_exchange->public_value().as_string(); | 576 forward_secure_key_exchange->public_value().as_string(); |
| 499 if (!forward_secure_key_exchange->CalculateSharedKey( | 577 if (!forward_secure_key_exchange->CalculateSharedKey( |
| 500 public_value, ¶ms->forward_secure_premaster_secret)) { | 578 public_value, ¶ms->forward_secure_premaster_secret)) { |
| 501 *error_details = "Invalid public value"; | 579 *error_details = "Invalid public value"; |
| 502 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 580 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 503 } | 581 } |
| 504 } | 582 } |
| 505 | 583 |
| 506 string forward_secure_hkdf_input; | 584 string forward_secure_hkdf_input; |
| 507 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; | 585 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; |
| 508 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size()); | 586 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size()); |
| 509 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, | 587 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, |
| 510 label_len); | 588 label_len); |
| 511 forward_secure_hkdf_input.append(hkdf_suffix); | 589 forward_secure_hkdf_input.append(hkdf_suffix); |
| 512 | 590 |
| 513 CryptoUtils::DeriveKeys(params->forward_secure_premaster_secret, params->aead, | 591 CryptoUtils::DeriveKeys(params->forward_secure_premaster_secret, params->aead, |
| 514 client_nonce, params->server_nonce, | 592 client_nonce, server_nonce, forward_secure_hkdf_input, |
| 515 forward_secure_hkdf_input, CryptoUtils::SERVER, | 593 CryptoUtils::SERVER, |
| 516 ¶ms->forward_secure_crypters); | 594 ¶ms->forward_secure_crypters); |
| 517 | 595 |
| 518 out->set_tag(kSHLO); | 596 out->set_tag(kSHLO); |
| 519 out->SetStringPiece(kSourceAddressTokenTag, fresh_source_address_token); | 597 out->SetStringPiece(kSourceAddressTokenTag, |
| 598 NewSourceAddressToken(client_ip, rand, now)); |
| 520 out->SetStringPiece(kPUBS, forward_secure_public_value); | 599 out->SetStringPiece(kPUBS, forward_secure_public_value); |
| 521 return QUIC_NO_ERROR; | 600 return QUIC_NO_ERROR; |
| 522 } | 601 } |
| 523 | 602 |
| 524 void QuicCryptoServerConfig::SetProofSource(ProofSource* proof_source) { | 603 void QuicCryptoServerConfig::SetProofSource(ProofSource* proof_source) { |
| 525 proof_source_.reset(proof_source); | 604 proof_source_.reset(proof_source); |
| 526 } | 605 } |
| 527 | 606 |
| 528 void QuicCryptoServerConfig::SetEphemeralKeySource( | 607 void QuicCryptoServerConfig::SetEphemeralKeySource( |
| 529 EphemeralKeySource* ephemeral_key_source) { | 608 EphemeralKeySource* ephemeral_key_source) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 } | 674 } |
| 596 | 675 |
| 597 if (now.IsAfter(timestamp) && | 676 if (now.IsAfter(timestamp) && |
| 598 delta.ToSeconds() > source_address_token_lifetime_secs_) { | 677 delta.ToSeconds() > source_address_token_lifetime_secs_) { |
| 599 return false; | 678 return false; |
| 600 } | 679 } |
| 601 | 680 |
| 602 return true; | 681 return true; |
| 603 } | 682 } |
| 604 | 683 |
| 605 QuicCryptoServerConfig::Config::Config() {} | 684 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server |
| 685 // nonce. |
| 686 static const size_t kServerNoncePlaintextSize = |
| 687 4 /* timestamp */ + 20 /* random bytes */; |
| 688 |
| 689 string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand, |
| 690 QuicWallTime now) const { |
| 691 const uint32 timestamp = static_cast<uint32>(now.ToUNIXSeconds()); |
| 692 |
| 693 uint8 server_nonce[kServerNoncePlaintextSize]; |
| 694 COMPILE_ASSERT(sizeof(server_nonce) > sizeof(timestamp), nonce_too_small); |
| 695 server_nonce[0] = static_cast<uint8>(timestamp >> 24); |
| 696 server_nonce[1] = static_cast<uint8>(timestamp >> 16); |
| 697 server_nonce[2] = static_cast<uint8>(timestamp >> 8); |
| 698 server_nonce[3] = static_cast<uint8>(timestamp); |
| 699 rand->RandBytes(&server_nonce[sizeof(timestamp)], |
| 700 sizeof(server_nonce) - sizeof(timestamp)); |
| 701 |
| 702 return server_nonce_boxer_.Box( |
| 703 rand, |
| 704 StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce))); |
| 705 } |
| 706 |
| 707 bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token, |
| 708 QuicWallTime now) const { |
| 709 string storage; |
| 710 StringPiece plaintext; |
| 711 if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) { |
| 712 return false; |
| 713 } |
| 714 |
| 715 // plaintext contains: |
| 716 // uint32 timestamp |
| 717 // uint8[20] random bytes |
| 718 |
| 719 if (plaintext.size() != kServerNoncePlaintextSize) { |
| 720 // This should never happen because the value decrypted correctly. |
| 721 LOG(DFATAL) << "Seemingly valid server nonce had incorrect length."; |
| 722 return false; |
| 723 } |
| 724 |
| 725 uint8 server_nonce[32]; |
| 726 memcpy(server_nonce, plaintext.data(), 4); |
| 727 memcpy(server_nonce + 4, server_nonce_orbit_, sizeof(server_nonce_orbit_)); |
| 728 memcpy(server_nonce + 4 + sizeof(server_nonce_orbit_), plaintext.data() + 4, |
| 729 20); |
| 730 COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce), |
| 731 bad_nonce_buffer_length); |
| 732 |
| 733 bool is_unique; |
| 734 { |
| 735 base::AutoLock auto_lock(server_nonce_strike_register_lock_); |
| 736 if (server_nonce_strike_register_.get() == NULL) { |
| 737 server_nonce_strike_register_.reset(new StrikeRegister( |
| 738 server_nonce_strike_register_max_entries_, |
| 739 static_cast<uint32>(now.ToUNIXSeconds()), |
| 740 server_nonce_strike_register_window_secs_, server_nonce_orbit_, |
| 741 StrikeRegister::NO_STARTUP_PERIOD_NEEDED)); |
| 742 } |
| 743 is_unique = server_nonce_strike_register_->Insert( |
| 744 server_nonce, static_cast<uint32>(now.ToUNIXSeconds())); |
| 745 } |
| 746 |
| 747 return is_unique; |
| 748 } |
| 749 |
| 750 QuicCryptoServerConfig::Config::Config() : channel_id_enabled(false) { } |
| 606 | 751 |
| 607 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } | 752 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } |
| 608 | 753 |
| 609 } // namespace net | 754 } // namespace net |
| OLD | NEW |