blob: bd5a4a55aa399a4284cee38dbec429d925b5e64a [file] [log] [blame]
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001// 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
3// found in the LICENSE file.
4
5#include "net/quic/crypto/crypto_handshake.h"
6
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01007#include <ctype.h>
8
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00009#include "base/memory/scoped_ptr.h"
10#include "base/stl_util.h"
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +010011#include "base/strings/stringprintf.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010012#include "base/strings/string_number_conversions.h"
13#include "base/strings/string_split.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000014#include "crypto/secure_hash.h"
15#include "net/base/net_util.h"
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010016#include "net/quic/crypto/cert_compressor.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010017#include "net/quic/crypto/channel_id.h"
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010018#include "net/quic/crypto/common_cert_set.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000019#include "net/quic/crypto/crypto_framer.h"
20#include "net/quic/crypto/crypto_utils.h"
21#include "net/quic/crypto/curve25519_key_exchange.h"
22#include "net/quic/crypto/key_exchange.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010023#include "net/quic/crypto/p256_key_exchange.h"
24#include "net/quic/crypto/proof_verifier.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000025#include "net/quic/crypto/quic_decrypter.h"
26#include "net/quic/crypto/quic_encrypter.h"
27#include "net/quic/crypto/quic_random.h"
28#include "net/quic/quic_protocol.h"
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010029#include "net/quic/quic_utils.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000030
31using base::StringPiece;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010032using base::StringPrintf;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010033using std::map;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000034using std::string;
35using std::vector;
36
37namespace net {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000038
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010039CryptoHandshakeMessage::CryptoHandshakeMessage()
40 : tag_(0),
41 minimum_size_(0) {}
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000042
43CryptoHandshakeMessage::CryptoHandshakeMessage(
44 const CryptoHandshakeMessage& other)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010045 : tag_(other.tag_),
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010046 tag_value_map_(other.tag_value_map_),
47 minimum_size_(other.minimum_size_) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000048 // Don't copy serialized_. scoped_ptr doesn't have a copy constructor.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010049 // The new object can lazily reconstruct serialized_.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000050}
51
52CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
53
54CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
55 const CryptoHandshakeMessage& other) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010056 tag_ = other.tag_;
57 tag_value_map_ = other.tag_value_map_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000058 // Don't copy serialized_. scoped_ptr doesn't have an assignment operator.
59 // However, invalidate serialized_.
60 serialized_.reset();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010061 minimum_size_ = other.minimum_size_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000062 return *this;
63}
64
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010065void CryptoHandshakeMessage::Clear() {
66 tag_ = 0;
67 tag_value_map_.clear();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010068 minimum_size_ = 0;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010069 serialized_.reset();
70}
71
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000072const QuicData& CryptoHandshakeMessage::GetSerialized() const {
73 if (!serialized_.get()) {
74 serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
75 }
76 return *serialized_.get();
77}
78
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010079void CryptoHandshakeMessage::MarkDirty() {
80 serialized_.reset();
81}
82
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010083void CryptoHandshakeMessage::Insert(QuicTagValueMap::const_iterator begin,
84 QuicTagValueMap::const_iterator end) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010085 tag_value_map_.insert(begin, end);
86}
87
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010088void CryptoHandshakeMessage::SetTaglist(QuicTag tag, ...) {
89 // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000090 // because the terminating 0 will only be promoted to int.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010091 COMPILE_ASSERT(sizeof(QuicTag) <= sizeof(int),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010092 crypto_tag_may_not_be_larger_than_int_or_varargs_will_break);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000093
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010094 vector<QuicTag> tags;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000095 va_list ap;
96
97 va_start(ap, tag);
98 for (;;) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010099 QuicTag list_item = va_arg(ap, QuicTag);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100100 if (list_item == 0) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000101 break;
102 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100103 tags.push_back(list_item);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000104 }
105
106 // Because of the way that we keep tags in memory, we can copy the contents
107 // of the vector and get the correct bytes in wire format. See
108 // crypto_protocol.h. This assumes that the system is little-endian.
109 SetVector(tag, tags);
110
111 va_end(ap);
112}
113
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100114void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100115 tag_value_map_[tag] = value.as_string();
116}
117
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100118void CryptoHandshakeMessage::Erase(QuicTag tag) {
119 tag_value_map_.erase(tag);
120}
121
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100122QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
123 const QuicTag** out_tags,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000124 size_t* out_len) const {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100125 QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000126 QuicErrorCode ret = QUIC_NO_ERROR;
127
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100128 if (it == tag_value_map_.end()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000129 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100130 } else if (it->second.size() % sizeof(QuicTag) != 0) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000131 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
132 }
133
134 if (ret != QUIC_NO_ERROR) {
135 *out_tags = NULL;
136 *out_len = 0;
137 return ret;
138 }
139
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100140 *out_tags = reinterpret_cast<const QuicTag*>(it->second.data());
141 *out_len = it->second.size() / sizeof(QuicTag);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000142 return ret;
143}
144
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100145bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000146 StringPiece* out) const {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100147 QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100148 if (it == tag_value_map_.end()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000149 return false;
150 }
151 *out = it->second;
152 return true;
153}
154
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100155QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100156 unsigned index,
157 StringPiece* out) const {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000158 StringPiece value;
159 if (!GetStringPiece(tag, &value)) {
160 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
161 }
162
163 for (unsigned i = 0;; i++) {
164 if (value.empty()) {
165 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
166 }
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100167 if (value.size() < 3) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000168 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
169 }
170
171 const unsigned char* data =
172 reinterpret_cast<const unsigned char*>(value.data());
173 size_t size = static_cast<size_t>(data[0]) |
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100174 (static_cast<size_t>(data[1]) << 8) |
175 (static_cast<size_t>(data[2]) << 16);
176 value.remove_prefix(3);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000177
178 if (value.size() < size) {
179 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
180 }
181
182 if (i == index) {
183 *out = StringPiece(value.data(), size);
184 return QUIC_NO_ERROR;
185 }
186
187 value.remove_prefix(size);
188 }
189}
190
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100191QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000192 uint16* out) const {
193 return GetPOD(tag, out, sizeof(uint16));
194}
195
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100196QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000197 uint32* out) const {
198 return GetPOD(tag, out, sizeof(uint32));
199}
200
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100201QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
202 uint64* out) const {
203 return GetPOD(tag, out, sizeof(uint64));
204}
205
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100206size_t CryptoHandshakeMessage::size() const {
207 size_t ret = sizeof(QuicTag) +
208 sizeof(uint16) /* number of entries */ +
209 sizeof(uint16) /* padding */;
210 ret += (sizeof(QuicTag) + sizeof(uint32) /* end offset */) *
211 tag_value_map_.size();
212 for (QuicTagValueMap::const_iterator i = tag_value_map_.begin();
213 i != tag_value_map_.end(); ++i) {
214 ret += i->second.size();
215 }
216
217 return ret;
218}
219
220void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100221 if (min_bytes == minimum_size_) {
222 return;
223 }
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100224 serialized_.reset();
225 minimum_size_ = min_bytes;
226}
227
228size_t CryptoHandshakeMessage::minimum_size() const {
229 return minimum_size_;
230}
231
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100232string CryptoHandshakeMessage::DebugString() const {
233 return DebugStringInternal(0);
234}
235
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000236QuicErrorCode CryptoHandshakeMessage::GetPOD(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100237 QuicTag tag, void* out, size_t len) const {
238 QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000239 QuicErrorCode ret = QUIC_NO_ERROR;
240
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100241 if (it == tag_value_map_.end()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000242 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
243 } else if (it->second.size() != len) {
244 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
245 }
246
247 if (ret != QUIC_NO_ERROR) {
248 memset(out, 0, len);
249 return ret;
250 }
251
252 memcpy(out, it->second.data(), len);
253 return ret;
254}
255
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100256string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100257 string ret = string(2 * indent, ' ') + QuicUtils::TagToString(tag_) + "<\n";
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100258 ++indent;
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100259 for (QuicTagValueMap::const_iterator it = tag_value_map_.begin();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100260 it != tag_value_map_.end(); ++it) {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100261 ret += string(2 * indent, ' ') + QuicUtils::TagToString(it->first) + ": ";
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100262
263 bool done = false;
264 switch (it->first) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100265 case kKATO:
266 case kVERS:
267 // uint32 value
268 if (it->second.size() == 4) {
269 uint32 value;
270 memcpy(&value, it->second.data(), sizeof(value));
271 ret += base::UintToString(value);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100272 done = true;
273 }
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100274 break;
275 case kKEXS:
276 case kAEAD:
277 case kCGST:
278 case kPDMD:
279 // tag lists
280 if (it->second.size() % sizeof(QuicTag) == 0) {
281 for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
282 QuicTag tag;
283 memcpy(&tag, it->second.data() + j, sizeof(tag));
284 if (j > 0) {
285 ret += ",";
286 }
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100287 ret += QuicUtils::TagToString(tag);
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100288 }
289 done = true;
290 }
291 break;
292 case kSCFG:
293 // nested messages.
294 if (!it->second.empty()) {
295 scoped_ptr<CryptoHandshakeMessage> msg(
296 CryptoFramer::ParseMessage(it->second));
297 if (msg.get()) {
298 ret += "\n";
299 ret += msg->DebugStringInternal(indent + 1);
300
301 done = true;
302 }
303 }
304 break;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100305 case kPAD:
306 ret += StringPrintf("(%d bytes of padding)",
307 static_cast<int>(it->second.size()));
308 done = true;
309 break;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100310 }
311
312 if (!done) {
313 // If there's no specific format for this tag, or the value is invalid,
314 // then just use hex.
315 ret += base::HexEncode(it->second.data(), it->second.size());
316 }
317 ret += "\n";
318 }
319 --indent;
320 ret += string(2 * indent, ' ') + ">";
321 return ret;
322}
323
324QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000325 : version(0),
326 key_exchange(0),
327 aead(0) {
328}
329
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100330QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {}
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000331
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100332CrypterPair::CrypterPair() {}
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100333
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100334CrypterPair::~CrypterPair() {}
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100335
336// static
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100337const char QuicCryptoConfig::kInitialLabel[] = "QUIC key expansion";
338
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100339// static
340const char QuicCryptoConfig::kCETVLabel[] = "QUIC CETV block";
341
342// static
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100343const char QuicCryptoConfig::kForwardSecureLabel[] =
344 "QUIC forward secure key expansion";
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100345
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000346QuicCryptoConfig::QuicCryptoConfig()
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100347 : version(0),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100348 common_cert_sets(CommonCertSets::GetInstanceQUIC()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000349}
350
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100351QuicCryptoConfig::~QuicCryptoConfig() {}
352
353QuicCryptoClientConfig::QuicCryptoClientConfig() {}
354
355QuicCryptoClientConfig::~QuicCryptoClientConfig() {
356 STLDeleteValues(&cached_states_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000357}
358
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100359QuicCryptoClientConfig::CachedState::CachedState()
360 : server_config_valid_(false) {}
361
362QuicCryptoClientConfig::CachedState::~CachedState() {}
363
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100364bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
365 if (server_config_.empty() || !server_config_valid_) {
366 return false;
367 }
368
369 const CryptoHandshakeMessage* scfg = GetServerConfig();
370 if (!scfg) {
371 // Should be impossible short of cache corruption.
372 DCHECK(false);
373 return false;
374 }
375
376 uint64 expiry_seconds;
377 if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR ||
378 now.ToUNIXSeconds() >= expiry_seconds) {
379 return false;
380 }
381
382 return true;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100383}
384
385const CryptoHandshakeMessage*
386QuicCryptoClientConfig::CachedState::GetServerConfig() const {
387 if (server_config_.empty()) {
388 return NULL;
389 }
390
391 if (!scfg_.get()) {
392 scfg_.reset(CryptoFramer::ParseMessage(server_config_));
393 DCHECK(scfg_.get());
394 }
395 return scfg_.get();
396}
397
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100398QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig(
399 StringPiece server_config, QuicWallTime now, string* error_details) {
400 const bool matches_existing = server_config == server_config_;
401
402 // Even if the new server config matches the existing one, we still wish to
403 // reject it if it has expired.
404 scoped_ptr<CryptoHandshakeMessage> new_scfg_storage;
405 const CryptoHandshakeMessage* new_scfg;
406
407 if (!matches_existing) {
408 new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config));
409 new_scfg = new_scfg_storage.get();
410 } else {
411 new_scfg = GetServerConfig();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100412 }
413
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100414 if (!new_scfg) {
415 *error_details = "SCFG invalid";
416 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000417 }
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100418
419 uint64 expiry_seconds;
420 if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
421 *error_details = "SCFG missing EXPY";
422 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
423 }
424
425 if (now.ToUNIXSeconds() >= expiry_seconds) {
426 *error_details = "SCFG has expired";
427 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
428 }
429
430 if (!matches_existing) {
431 server_config_ = server_config.as_string();
432 server_config_valid_ = false;
433 scfg_.reset(new_scfg_storage.release());
434 }
435 return QUIC_NO_ERROR;
436}
437
438void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
439 server_config_.clear();
440 scfg_.reset();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100441 server_config_valid_ = false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000442}
443
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100444void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
445 StringPiece signature) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100446 bool has_changed =
447 signature != server_config_sig_ || certs_.size() != certs.size();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100448
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100449 if (!has_changed) {
450 for (size_t i = 0; i < certs_.size(); i++) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100451 if (certs_[i] != certs[i]) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100452 has_changed = true;
453 break;
454 }
455 }
456 }
457
458 if (!has_changed) {
459 return;
460 }
461
462 // If the proof has changed then it needs to be revalidated.
463 server_config_valid_ = false;
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100464 certs_ = certs;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100465 server_config_sig_ = signature.as_string();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000466}
467
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100468void QuicCryptoClientConfig::CachedState::SetProofValid() {
469 server_config_valid_ = true;
470}
471
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100472const string& QuicCryptoClientConfig::CachedState::server_config() const {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100473 return server_config_;
474}
475
476const string&
477QuicCryptoClientConfig::CachedState::source_address_token() const {
478 return source_address_token_;
479}
480
481const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
482 return certs_;
483}
484
485const string& QuicCryptoClientConfig::CachedState::signature() const {
486 return server_config_sig_;
487}
488
489bool QuicCryptoClientConfig::CachedState::proof_valid() const {
490 return server_config_valid_;
491}
492
493void QuicCryptoClientConfig::CachedState::set_source_address_token(
494 StringPiece token) {
495 source_address_token_ = token.as_string();
496}
497
498void QuicCryptoClientConfig::SetDefaults() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000499 // Version must be 0.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100500 // TODO(agl): this version stuff is obsolete now.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100501 version = QuicCryptoConfig::CONFIG_VERSION;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000502
503 // Key exchange methods.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100504 kexs.resize(2);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000505 kexs[0] = kC255;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100506 kexs[1] = kP256;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000507
508 // Authenticated encryption algorithms.
509 aead.resize(1);
510 aead[0] = kAESG;
511}
512
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100513QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
514 const string& server_hostname) {
515 map<string, CachedState*>::const_iterator it =
516 cached_states_.find(server_hostname);
517 if (it != cached_states_.end()) {
518 return it->second;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000519 }
520
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100521 CachedState* cached = new CachedState;
522 cached_states_.insert(make_pair(server_hostname, cached));
523 return cached;
524}
525
526void QuicCryptoClientConfig::FillInchoateClientHello(
527 const string& server_hostname,
528 const CachedState* cached,
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100529 QuicCryptoNegotiatedParameters* out_params,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100530 CryptoHandshakeMessage* out) const {
531 out->set_tag(kCHLO);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100532 out->set_minimum_size(kClientHelloMinimumSize);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000533
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100534 // Server name indication. We only send SNI if it's a valid domain name, as
535 // per the spec.
536 if (CryptoUtils::IsValidSNI(server_hostname)) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100537 out->SetStringPiece(kSNI, server_hostname);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000538 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100539 out->SetValue(kVERS, version);
540
541 if (!cached->source_address_token().empty()) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100542 out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100543 }
544
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100545 if (proof_verifier_.get()) {
546 out->SetTaglist(kPDMD, kX509, 0);
547 }
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100548
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100549 if (common_cert_sets) {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100550 out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100551 }
552
553 const vector<string>& certs = cached->certs();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100554 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
555 // client config is being used for multiple connections, another connection
556 // doesn't update the cached certificates and cause us to be unable to
557 // process the server's compressed certificate chain.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100558 out_params->cached_certs = certs;
559 if (!certs.empty()) {
560 vector<uint64> hashes;
561 hashes.reserve(certs.size());
562 for (vector<string>::const_iterator i = certs.begin();
563 i != certs.end(); ++i) {
564 hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
565 }
566 out->SetVector(kCCRT, hashes);
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100567 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100568}
569
570QuicErrorCode QuicCryptoClientConfig::FillClientHello(
571 const string& server_hostname,
572 QuicGuid guid,
573 const CachedState* cached,
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100574 QuicWallTime now,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100575 QuicRandom* rand,
576 QuicCryptoNegotiatedParameters* out_params,
577 CryptoHandshakeMessage* out,
578 string* error_details) const {
579 DCHECK(error_details != NULL);
580
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100581 FillInchoateClientHello(server_hostname, cached, out_params, out);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100582
583 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
584 if (!scfg) {
585 // This should never happen as our caller should have checked
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100586 // cached->IsComplete() before calling this function.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100587 *error_details = "Handshake not ready";
588 return QUIC_CRYPTO_INTERNAL_ERROR;
589 }
590
591 StringPiece scid;
592 if (!scfg->GetStringPiece(kSCID, &scid)) {
593 *error_details = "SCFG missing SCID";
594 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
595 }
596 out->SetStringPiece(kSCID, scid);
597
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100598 const QuicTag* their_aeads;
599 const QuicTag* their_key_exchanges;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100600 size_t num_their_aeads, num_their_key_exchanges;
601 if (scfg->GetTaglist(kAEAD, &their_aeads,
602 &num_their_aeads) != QUIC_NO_ERROR ||
603 scfg->GetTaglist(kKEXS, &their_key_exchanges,
604 &num_their_key_exchanges) != QUIC_NO_ERROR) {
605 *error_details = "Missing AEAD or KEXS";
606 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
607 }
608
609 size_t key_exchange_index;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100610 if (!QuicUtils::FindMutualTag(
611 aead, their_aeads, num_their_aeads, QuicUtils::PEER_PRIORITY,
612 &out_params->aead, NULL) ||
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100613 !QuicUtils::FindMutualTag(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100614 kexs, their_key_exchanges, num_their_key_exchanges,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100615 QuicUtils::PEER_PRIORITY, &out_params->key_exchange,
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100616 &key_exchange_index)) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100617 *error_details = "Unsupported AEAD or KEXS";
618 return QUIC_CRYPTO_NO_SUPPORT;
619 }
620 out->SetTaglist(kAEAD, out_params->aead, 0);
621 out->SetTaglist(kKEXS, out_params->key_exchange, 0);
622
623 StringPiece public_value;
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100624 if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100625 QUIC_NO_ERROR) {
626 *error_details = "Missing public value";
627 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
628 }
629
630 StringPiece orbit;
631 if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
632 *error_details = "SCFG missing OBIT";
633 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
634 }
635
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100636 CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce);
637 out->SetStringPiece(kNONC, out_params->client_nonce);
638 if (!out_params->server_nonce.empty()) {
639 out->SetStringPiece(kServerNonceTag, out_params->server_nonce);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100640 }
641
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100642 switch (out_params->key_exchange) {
643 case kC255:
644 out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
645 Curve25519KeyExchange::NewPrivateKey(rand)));
646 break;
647 case kP256:
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100648 out_params->client_key_exchange.reset(P256KeyExchange::New(
649 P256KeyExchange::NewPrivateKey()));
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100650 break;
651 default:
652 DCHECK(false);
653 *error_details = "Configured to support an unknown key exchange";
654 return QUIC_CRYPTO_INTERNAL_ERROR;
655 }
656
657 if (!out_params->client_key_exchange->CalculateSharedKey(
658 public_value, &out_params->initial_premaster_secret)) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100659 *error_details = "Key exchange failure";
660 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
661 }
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100662 out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100663
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100664 bool do_channel_id = false;
665 if (channel_id_signer_.get()) {
666 const QuicTag* their_proof_demands;
667 size_t num_their_proof_demands;
668 if (scfg->GetTaglist(kPDMD, &their_proof_demands,
669 &num_their_proof_demands) == QUIC_NO_ERROR) {
670 for (size_t i = 0; i < num_their_proof_demands; i++) {
671 if (their_proof_demands[i] == kCHID) {
672 do_channel_id = true;
673 break;
674 }
675 }
676 }
677 }
678
679 if (do_channel_id) {
680 // In order to calculate the encryption key for the CETV block we need to
681 // serialise the client hello as it currently is (i.e. without the CETV
682 // block). For this, the client hello is serialized without padding.
683 const size_t orig_min_size = out->minimum_size();
684 out->set_minimum_size(0);
685
686 CryptoHandshakeMessage cetv;
687 cetv.set_tag(kCETV);
688
689 string hkdf_input;
690 const QuicData& client_hello_serialized = out->GetSerialized();
691 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
692 strlen(QuicCryptoConfig::kCETVLabel) + 1);
693 hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid));
694 hkdf_input.append(client_hello_serialized.data(),
695 client_hello_serialized.length());
696 hkdf_input.append(cached->server_config());
697
698 string key, signature;
699 if (!channel_id_signer_->Sign(server_hostname, hkdf_input,
700 &key, &signature)) {
701 *error_details = "Channel ID signature failed";
702 return QUIC_INTERNAL_ERROR;
703 }
704
705 cetv.SetStringPiece(kCIDK, key);
706 cetv.SetStringPiece(kCIDS, signature);
707
708 CrypterPair crypters;
709 CryptoUtils::DeriveKeys(out_params->initial_premaster_secret,
710 out_params->aead, out_params->client_nonce,
711 out_params->server_nonce, hkdf_input,
712 CryptoUtils::CLIENT, &crypters);
713
714 const QuicData& cetv_plaintext = cetv.GetSerialized();
715 scoped_ptr<QuicData> cetv_ciphertext(crypters.encrypter->EncryptPacket(
716 0 /* sequence number */,
717 StringPiece() /* associated data */,
718 cetv_plaintext.AsStringPiece()));
719
720 out->SetStringPiece(kCETV, cetv_ciphertext->AsStringPiece());
721 out->MarkDirty();
722
723 out->set_minimum_size(orig_min_size);
724 }
725
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100726 out_params->hkdf_input_suffix.clear();
727 out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&guid),
728 sizeof(guid));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100729 const QuicData& client_hello_serialized = out->GetSerialized();
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100730 out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
731 client_hello_serialized.length());
732 out_params->hkdf_input_suffix.append(cached->server_config());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100733
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100734 string hkdf_input;
735 const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
736 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
737 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
738 hkdf_input.append(out_params->hkdf_input_suffix);
739
740 CryptoUtils::DeriveKeys(out_params->initial_premaster_secret,
741 out_params->aead, out_params->client_nonce,
742 out_params->server_nonce, hkdf_input,
743 CryptoUtils::CLIENT, &out_params->initial_crypters);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100744
745 return QUIC_NO_ERROR;
746}
747
748QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
749 CachedState* cached,
750 const CryptoHandshakeMessage& rej,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100751 QuicWallTime now,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100752 QuicCryptoNegotiatedParameters* out_params,
753 string* error_details) {
754 DCHECK(error_details != NULL);
755
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100756 if (rej.tag() != kREJ) {
757 *error_details = "Message is not REJ";
758 return QUIC_CRYPTO_INTERNAL_ERROR;
759 }
760
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100761 StringPiece scfg;
762 if (!rej.GetStringPiece(kSCFG, &scfg)) {
763 *error_details = "Missing SCFG";
764 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
765 }
766
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100767 QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details);
768 if (error != QUIC_NO_ERROR) {
769 return error;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100770 }
771
772 StringPiece token;
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100773 if (rej.GetStringPiece(kSourceAddressTokenTag, &token)) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100774 cached->set_source_address_token(token);
775 }
776
777 StringPiece nonce;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100778 if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100779 out_params->server_nonce = nonce.as_string();
780 }
781
782 StringPiece proof, cert_bytes;
783 if (rej.GetStringPiece(kPROF, &proof) &&
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100784 rej.GetStringPiece(kCertificateTag, &cert_bytes)) {
785 vector<string> certs;
786 if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100787 common_cert_sets, &certs)) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100788 *error_details = "Certificate data invalid";
789 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100790 }
791
792 cached->SetProof(certs, proof);
793 }
794
795 return QUIC_NO_ERROR;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000796}
797
798QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
799 const CryptoHandshakeMessage& server_hello,
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100800 QuicGuid guid,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100801 QuicCryptoNegotiatedParameters* out_params,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000802 string* error_details) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100803 DCHECK(error_details != NULL);
804
805 if (server_hello.tag() != kSHLO) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000806 *error_details = "Bad tag";
807 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
808 }
809
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100810 // TODO(agl):
811 // learn about updated SCFGs.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100812
813 StringPiece public_value;
814 if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
815 *error_details = "server hello missing forward secure public value";
816 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
817 }
818
819 if (!out_params->client_key_exchange->CalculateSharedKey(
820 public_value, &out_params->forward_secure_premaster_secret)) {
821 *error_details = "Key exchange failure";
822 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
823 }
824
825 string hkdf_input;
826 const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
827 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
828 hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
829 hkdf_input.append(out_params->hkdf_input_suffix);
830
831 CryptoUtils::DeriveKeys(
832 out_params->forward_secure_premaster_secret, out_params->aead,
833 out_params->client_nonce, out_params->server_nonce, hkdf_input,
834 CryptoUtils::CLIENT, &out_params->forward_secure_crypters);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000835
836 return QUIC_NO_ERROR;
837}
838
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100839const ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
840 return proof_verifier_.get();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000841}
842
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100843void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) {
844 proof_verifier_.reset(verifier);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000845}
846
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100847void QuicCryptoClientConfig::SetChannelIDSigner(ChannelIDSigner* signer) {
848 channel_id_signer_.reset(signer);
849}
850
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000851} // namespace net