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_handshake.h" | 5 #include "net/quic/crypto/crypto_handshake.h" |
6 | 6 |
7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
| 9 #include "crypto/hkdf.h" |
9 #include "crypto/secure_hash.h" | 10 #include "crypto/secure_hash.h" |
10 #include "net/base/net_util.h" | 11 #include "net/base/net_util.h" |
11 #include "net/quic/crypto/crypto_framer.h" | 12 #include "net/quic/crypto/crypto_framer.h" |
12 #include "net/quic/crypto/crypto_utils.h" | 13 #include "net/quic/crypto/crypto_utils.h" |
13 #include "net/quic/crypto/curve25519_key_exchange.h" | 14 #include "net/quic/crypto/curve25519_key_exchange.h" |
14 #include "net/quic/crypto/key_exchange.h" | 15 #include "net/quic/crypto/key_exchange.h" |
| 16 #include "net/quic/crypto/quic_decrypter.h" |
| 17 #include "net/quic/crypto/quic_encrypter.h" |
15 #include "net/quic/crypto/quic_random.h" | 18 #include "net/quic/crypto/quic_random.h" |
16 #include "net/quic/quic_protocol.h" | 19 #include "net/quic/quic_protocol.h" |
17 | 20 |
18 using base::StringPiece; | 21 using base::StringPiece; |
19 using crypto::SecureHash; | 22 using crypto::SecureHash; |
20 using std::string; | 23 using std::string; |
21 using std::vector; | 24 using std::vector; |
22 | 25 |
23 namespace net { | 26 namespace net { |
24 // kVersion contains the one (and, for the moment, only) version number that we | 27 // kVersion contains the one (and, for the moment, only) version number that we |
25 // implement. | 28 // implement. |
26 static const uint16 kVersion = 0; | 29 static const uint16 kVersion = 0; |
27 | 30 |
| 31 static const char kLabel[] = "QUIC key expansion"; |
| 32 |
28 using crypto::SecureHash; | 33 using crypto::SecureHash; |
29 | 34 |
30 QuicServerConfigProtobuf::QuicServerConfigProtobuf() { | 35 QuicServerConfigProtobuf::QuicServerConfigProtobuf() { |
31 } | 36 } |
32 | 37 |
33 QuicServerConfigProtobuf::~QuicServerConfigProtobuf() { | 38 QuicServerConfigProtobuf::~QuicServerConfigProtobuf() { |
34 STLDeleteElements(&keys_); | 39 STLDeleteElements(&keys_); |
35 } | 40 } |
36 | 41 |
| 42 CryptoHandshakeMessage::CryptoHandshakeMessage() {} |
| 43 |
| 44 CryptoHandshakeMessage::CryptoHandshakeMessage( |
| 45 const CryptoHandshakeMessage& other) |
| 46 : tag(other.tag), |
| 47 tag_value_map(other.tag_value_map) { |
| 48 // Don't copy serialized_. scoped_ptr doesn't have a copy constructor. |
| 49 // The new object can reconstruct serialized_ lazily. |
| 50 } |
| 51 |
| 52 CryptoHandshakeMessage::~CryptoHandshakeMessage() {} |
| 53 |
| 54 CryptoHandshakeMessage& CryptoHandshakeMessage::operator=( |
| 55 const CryptoHandshakeMessage& other) { |
| 56 tag = other.tag; |
| 57 tag_value_map = other.tag_value_map; |
| 58 // Don't copy serialized_. scoped_ptr doesn't have an assignment operator. |
| 59 // However, invalidate serialized_. |
| 60 serialized_.reset(); |
| 61 return *this; |
| 62 } |
| 63 |
| 64 const QuicData& CryptoHandshakeMessage::GetSerialized() const { |
| 65 if (!serialized_.get()) { |
| 66 serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this)); |
| 67 } |
| 68 return *serialized_.get(); |
| 69 } |
| 70 |
| 71 void CryptoHandshakeMessage::SetTaglist(CryptoTag tag, ...) { |
| 72 // Warning, if sizeof(CryptoTag) > sizeof(int) then this function will break |
| 73 // because the terminating 0 will only be promoted to int. |
| 74 COMPILE_ASSERT(sizeof(CryptoTag) <= sizeof(int), |
| 75 crypto_tag_not_be_larger_than_int_or_varargs_will_break); |
| 76 |
| 77 vector<CryptoTag> tags; |
| 78 va_list ap; |
| 79 |
| 80 va_start(ap, tag); |
| 81 for (;;) { |
| 82 CryptoTag tag = va_arg(ap, CryptoTag); |
| 83 if (tag == 0) { |
| 84 break; |
| 85 } |
| 86 tags.push_back(tag); |
| 87 } |
| 88 |
| 89 // Because of the way that we keep tags in memory, we can copy the contents |
| 90 // of the vector and get the correct bytes in wire format. See |
| 91 // crypto_protocol.h. This assumes that the system is little-endian. |
| 92 SetVector(tag, tags); |
| 93 |
| 94 va_end(ap); |
| 95 } |
| 96 |
| 97 QuicErrorCode CryptoHandshakeMessage::GetTaglist(CryptoTag tag, |
| 98 const CryptoTag** out_tags, |
| 99 size_t* out_len) const { |
| 100 CryptoTagValueMap::const_iterator it = tag_value_map.find(tag); |
| 101 QuicErrorCode ret = QUIC_NO_ERROR; |
| 102 |
| 103 if (it == tag_value_map.end()) { |
| 104 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
| 105 } else if (it->second.size() % sizeof(CryptoTag) != 0) { |
| 106 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 107 } |
| 108 |
| 109 if (ret != QUIC_NO_ERROR) { |
| 110 *out_tags = NULL; |
| 111 *out_len = 0; |
| 112 return ret; |
| 113 } |
| 114 |
| 115 *out_tags = reinterpret_cast<const CryptoTag*>(it->second.data()); |
| 116 *out_len = it->second.size() / sizeof(CryptoTag); |
| 117 return ret; |
| 118 } |
| 119 |
| 120 bool CryptoHandshakeMessage::GetStringPiece(CryptoTag tag, |
| 121 StringPiece* out) const { |
| 122 CryptoTagValueMap::const_iterator it = tag_value_map.find(tag); |
| 123 if (it == tag_value_map.end()) { |
| 124 return false; |
| 125 } |
| 126 *out = it->second; |
| 127 return true; |
| 128 } |
| 129 |
| 130 QuicErrorCode CryptoHandshakeMessage::GetNthValue16( |
| 131 CryptoTag tag, |
| 132 unsigned index, |
| 133 StringPiece* out) const { |
| 134 StringPiece value; |
| 135 if (!GetStringPiece(tag, &value)) { |
| 136 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
| 137 } |
| 138 |
| 139 for (unsigned i = 0;; i++) { |
| 140 if (value.empty()) { |
| 141 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND; |
| 142 } |
| 143 if (value.size() < 2) { |
| 144 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 145 } |
| 146 |
| 147 const unsigned char* data = |
| 148 reinterpret_cast<const unsigned char*>(value.data()); |
| 149 size_t size = static_cast<size_t>(data[0]) | |
| 150 (static_cast<size_t>(data[1]) << 8); |
| 151 value.remove_prefix(2); |
| 152 |
| 153 if (value.size() < size) { |
| 154 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 155 } |
| 156 |
| 157 if (i == index) { |
| 158 *out = StringPiece(value.data(), size); |
| 159 return QUIC_NO_ERROR; |
| 160 } |
| 161 |
| 162 value.remove_prefix(size); |
| 163 } |
| 164 } |
| 165 |
| 166 bool CryptoHandshakeMessage::GetString(CryptoTag tag, string* out) const { |
| 167 CryptoTagValueMap::const_iterator it = tag_value_map.find(tag); |
| 168 if (it == tag_value_map.end()) { |
| 169 return false; |
| 170 } |
| 171 *out = it->second; |
| 172 return true; |
| 173 } |
| 174 |
| 175 QuicErrorCode CryptoHandshakeMessage::GetUint16(CryptoTag tag, |
| 176 uint16* out) const { |
| 177 return GetPOD(tag, out, sizeof(uint16)); |
| 178 } |
| 179 |
| 180 QuicErrorCode CryptoHandshakeMessage::GetUint32(CryptoTag tag, |
| 181 uint32* out) const { |
| 182 return GetPOD(tag, out, sizeof(uint32)); |
| 183 } |
| 184 |
| 185 QuicErrorCode CryptoHandshakeMessage::GetPOD( |
| 186 CryptoTag tag, void* out, size_t len) const { |
| 187 CryptoTagValueMap::const_iterator it = tag_value_map.find(tag); |
| 188 QuicErrorCode ret = QUIC_NO_ERROR; |
| 189 |
| 190 if (it == tag_value_map.end()) { |
| 191 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
| 192 } else if (it->second.size() != len) { |
| 193 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 194 } |
| 195 |
| 196 if (ret != QUIC_NO_ERROR) { |
| 197 memset(out, 0, len); |
| 198 return ret; |
| 199 } |
| 200 |
| 201 memcpy(out, it->second.data(), len); |
| 202 return ret; |
| 203 } |
| 204 |
37 QuicCryptoNegotiatedParams::QuicCryptoNegotiatedParams() | 205 QuicCryptoNegotiatedParams::QuicCryptoNegotiatedParams() |
38 : version(0), | 206 : version(0), |
39 key_exchange(0), | 207 key_exchange(0), |
40 aead(0) { | 208 aead(0) { |
41 } | 209 } |
42 | 210 |
43 QuicCryptoNegotiatedParams::~QuicCryptoNegotiatedParams() { | 211 QuicCryptoNegotiatedParams::~QuicCryptoNegotiatedParams() { |
44 } | 212 } |
45 | 213 |
46 | |
47 QuicCryptoConfig::QuicCryptoConfig() | 214 QuicCryptoConfig::QuicCryptoConfig() |
48 : version(0) { | 215 : version(0) { |
49 } | 216 } |
50 | 217 |
51 QuicCryptoConfig::~QuicCryptoConfig() { | 218 QuicCryptoConfig::~QuicCryptoConfig() { |
52 STLDeleteElements(&key_exchanges); | 219 STLDeleteElements(&key_exchanges); |
53 } | 220 } |
54 | 221 |
55 bool QuicCryptoConfig::ProcessPeerHandshake( | 222 bool QuicCryptoConfig::ProcessPeerHandshake( |
56 const CryptoHandshakeMessage& peer_msg, | 223 const CryptoHandshakeMessage& peer_msg, |
57 CryptoUtils::Priority priority, | 224 CryptoUtils::Priority priority, |
58 QuicCryptoNegotiatedParams* out_params, | 225 QuicCryptoNegotiatedParams* out_params, |
59 string *error_details) const { | 226 string* error_details) const { |
60 if (peer_msg.GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR || | 227 if (peer_msg.GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR || |
61 out_params->version != kVersion) { | 228 out_params->version != kVersion) { |
62 if (error_details) { | 229 if (error_details) { |
63 *error_details = "Bad version"; | 230 *error_details = "Bad version"; |
64 } | 231 } |
65 return false; | 232 return false; |
66 } | 233 } |
67 | 234 |
68 const CryptoTag* their_aeads; | 235 const CryptoTag* their_aeads; |
69 const CryptoTag* their_key_exchanges; | 236 const CryptoTag* their_key_exchanges; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 &out_params->premaster_secret)) { | 285 &out_params->premaster_secret)) { |
119 if (error_details) { | 286 if (error_details) { |
120 *error_details = "Key exchange failure"; | 287 *error_details = "Key exchange failure"; |
121 } | 288 } |
122 return false; | 289 return false; |
123 } | 290 } |
124 | 291 |
125 return true; | 292 return true; |
126 } | 293 } |
127 | 294 |
| 295 QuicCryptoClientConfig::QuicCryptoClientConfig() |
| 296 : hkdf_info(kLabel, arraysize(kLabel)) { |
| 297 } |
| 298 |
128 void QuicCryptoClientConfig::SetDefaults(QuicRandom* rand) { | 299 void QuicCryptoClientConfig::SetDefaults(QuicRandom* rand) { |
129 // Version must be 0. | 300 // Version must be 0. |
130 version = kVersion; | 301 version = kVersion; |
131 | 302 |
132 // Key exchange methods. | 303 // Key exchange methods. |
133 const string private_key = Curve25519KeyExchange::NewPrivateKey(rand); | 304 const string private_key = Curve25519KeyExchange::NewPrivateKey(rand); |
134 key_exchanges.clear(); | 305 key_exchanges.clear(); |
135 key_exchanges.push_back(Curve25519KeyExchange::New(private_key)); | 306 key_exchanges.push_back(Curve25519KeyExchange::New(private_key)); |
136 kexs.resize(1); | 307 kexs.resize(1); |
137 kexs[0] = kC255; | 308 kexs[0] = kC255; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 // If server_hostname is not an IP address literal, it is a DNS hostname. | 347 // If server_hostname is not an IP address literal, it is a DNS hostname. |
177 IPAddressNumber ip; | 348 IPAddressNumber ip; |
178 if (!server_hostname.empty() && | 349 if (!server_hostname.empty() && |
179 !ParseIPLiteralToNumber(server_hostname, &ip)) { | 350 !ParseIPLiteralToNumber(server_hostname, &ip)) { |
180 out->tag_value_map[kSNI] = server_hostname; | 351 out->tag_value_map[kSNI] = server_hostname; |
181 } | 352 } |
182 } | 353 } |
183 | 354 |
184 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( | 355 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( |
185 const CryptoHandshakeMessage& server_hello, | 356 const CryptoHandshakeMessage& server_hello, |
| 357 const string& nonce, |
186 QuicCryptoNegotiatedParams* out_params, | 358 QuicCryptoNegotiatedParams* out_params, |
187 string* error_details) { | 359 string* error_details) { |
188 if (server_hello.tag != kSHLO) { | 360 if (server_hello.tag != kSHLO) { |
189 *error_details = "Bad tag"; | 361 *error_details = "Bad tag"; |
190 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; | 362 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; |
191 } | 363 } |
192 | 364 |
193 StringPiece scfg_bytes; | 365 StringPiece scfg_bytes; |
194 if (!server_hello.GetStringPiece(kSCFG, &scfg_bytes)) { | 366 if (!server_hello.GetStringPiece(kSCFG, &scfg_bytes)) { |
195 *error_details = "Missing SCFG"; | 367 *error_details = "Missing SCFG"; |
196 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 368 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
197 } | 369 } |
198 | 370 |
199 scoped_ptr<CryptoHandshakeMessage> scfg( | 371 scoped_ptr<CryptoHandshakeMessage> scfg( |
200 CryptoFramer::ParseMessage(scfg_bytes)); | 372 CryptoFramer::ParseMessage(scfg_bytes)); |
201 if (!scfg.get() || | 373 if (!scfg.get() || scfg->tag != kSCFG) { |
202 scfg->tag != kSCFG) { | |
203 *error_details = "Invalid SCFG"; | 374 *error_details = "Invalid SCFG"; |
204 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 375 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
205 } | 376 } |
206 | 377 |
207 if (!ProcessPeerHandshake(*scfg, CryptoUtils::PEER_PRIORITY, out_params, | 378 if (!ProcessPeerHandshake(*scfg, CryptoUtils::PEER_PRIORITY, out_params, |
208 error_details)) { | 379 error_details)) { |
209 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 380 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
210 } | 381 } |
211 | 382 |
| 383 hkdf_info.append(scfg_bytes.data(), scfg_bytes.size()); |
| 384 |
| 385 out_params->encrypter.reset(QuicEncrypter::Create(out_params->aead)); |
| 386 out_params->decrypter.reset(QuicDecrypter::Create(out_params->aead)); |
| 387 size_t key_bytes = out_params->encrypter->GetKeySize(); |
| 388 size_t nonce_prefix_bytes = out_params->encrypter->GetNoncePrefixSize(); |
| 389 uint32 key_length_in_bits = 8 * 2 * (key_bytes + nonce_prefix_bytes); |
| 390 hkdf_info.append(reinterpret_cast<char*>(&key_length_in_bits), |
| 391 sizeof(key_length_in_bits)); |
| 392 |
| 393 crypto::HKDF hkdf(out_params->premaster_secret, nonce, |
| 394 hkdf_info, key_bytes, nonce_prefix_bytes); |
| 395 out_params->encrypter->SetKey(hkdf.client_write_key()); |
| 396 out_params->encrypter->SetNoncePrefix(hkdf.client_write_iv()); |
| 397 out_params->decrypter->SetKey(hkdf.server_write_key()); |
| 398 out_params->decrypter->SetNoncePrefix(hkdf.server_write_iv()); |
| 399 |
212 return QUIC_NO_ERROR; | 400 return QUIC_NO_ERROR; |
213 } | 401 } |
214 | 402 |
215 | 403 |
216 QuicCryptoServerConfig::QuicCryptoServerConfig() { | 404 QuicCryptoServerConfig::QuicCryptoServerConfig() |
| 405 : hkdf_info(kLabel, arraysize(kLabel)) { |
217 } | 406 } |
218 | 407 |
219 QuicCryptoServerConfig::~QuicCryptoServerConfig() { | 408 QuicCryptoServerConfig::~QuicCryptoServerConfig() { |
220 STLDeleteValues(&configs_); | 409 STLDeleteValues(&configs_); |
221 } | 410 } |
222 | 411 |
223 // static | 412 // static |
224 QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting( | 413 QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting( |
225 QuicRandom* rand, | 414 QuicRandom* rand, |
226 const QuicClock* clock, | 415 const QuicClock* clock, |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 out->tag = kREJ; | 582 out->tag = kREJ; |
394 out->tag_value_map.clear(); | 583 out->tag_value_map.clear(); |
395 | 584 |
396 if (!config->ProcessPeerHandshake(client_hello, | 585 if (!config->ProcessPeerHandshake(client_hello, |
397 CryptoUtils::LOCAL_PRIORITY, | 586 CryptoUtils::LOCAL_PRIORITY, |
398 out_params, | 587 out_params, |
399 error_details)) { | 588 error_details)) { |
400 return false; | 589 return false; |
401 } | 590 } |
402 | 591 |
| 592 StringPiece client_nonce; |
| 593 if (!client_hello.GetStringPiece(kNONC, &client_nonce)) { |
| 594 return false; |
| 595 } |
| 596 |
| 597 const QuicData& client_hello_serialized = client_hello.GetSerialized(); |
| 598 hkdf_info.append(client_hello_serialized.data(), |
| 599 client_hello_serialized.length()); |
| 600 hkdf_info.append(config->serialized); |
| 601 |
| 602 out_params->encrypter.reset(QuicEncrypter::Create(out_params->aead)); |
| 603 out_params->decrypter.reset(QuicDecrypter::Create(out_params->aead)); |
| 604 size_t key_bytes = out_params->encrypter->GetKeySize(); |
| 605 size_t nonce_prefix_bytes = out_params->encrypter->GetNoncePrefixSize(); |
| 606 uint32 key_length_in_bits = 8 * 2 * (key_bytes + nonce_prefix_bytes); |
| 607 hkdf_info.append(reinterpret_cast<char*>(&key_length_in_bits), |
| 608 sizeof(key_length_in_bits)); |
| 609 |
| 610 crypto::HKDF hkdf(out_params->premaster_secret, client_nonce, |
| 611 hkdf_info, key_bytes, nonce_prefix_bytes); |
| 612 out_params->encrypter->SetKey(hkdf.server_write_key()); |
| 613 out_params->encrypter->SetNoncePrefix(hkdf.server_write_iv()); |
| 614 out_params->decrypter->SetKey(hkdf.client_write_key()); |
| 615 out_params->decrypter->SetNoncePrefix(hkdf.client_write_iv()); |
| 616 |
403 // TODO(agl): This is obviously missing most of the handshake. | 617 // TODO(agl): This is obviously missing most of the handshake. |
404 out->tag = kSHLO; | 618 out->tag = kSHLO; |
405 out->tag_value_map[kNONC] = nonce; | 619 out->tag_value_map[kNONC] = nonce; |
406 out->tag_value_map[kSCFG] = config->serialized; | 620 out->tag_value_map[kSCFG] = config->serialized; |
407 return true; | 621 return true; |
408 } | 622 } |
409 | 623 |
410 QuicCryptoServerConfig::Config::Config() { | 624 QuicCryptoServerConfig::Config::Config() { |
411 } | 625 } |
412 | 626 |
413 QuicCryptoServerConfig::Config::~Config() { | 627 QuicCryptoServerConfig::Config::~Config() { |
414 } | 628 } |
415 | 629 |
416 } // namespace net | 630 } // namespace net |
OLD | NEW |