• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "net/quic/crypto/crypto_handshake.h"
6 
7 #include <ctype.h>
8 
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "crypto/secure_hash.h"
14 #include "net/base/net_util.h"
15 #include "net/quic/crypto/common_cert_set.h"
16 #include "net/quic/crypto/crypto_framer.h"
17 #include "net/quic/crypto/key_exchange.h"
18 #include "net/quic/crypto/quic_decrypter.h"
19 #include "net/quic/crypto/quic_encrypter.h"
20 #include "net/quic/crypto/quic_random.h"
21 #include "net/quic/quic_protocol.h"
22 #include "net/quic/quic_utils.h"
23 
24 using base::StringPiece;
25 using base::StringPrintf;
26 using std::string;
27 using std::vector;
28 
29 namespace net {
30 
CryptoHandshakeMessage()31 CryptoHandshakeMessage::CryptoHandshakeMessage()
32     : tag_(0),
33       minimum_size_(0) {}
34 
CryptoHandshakeMessage(const CryptoHandshakeMessage & other)35 CryptoHandshakeMessage::CryptoHandshakeMessage(
36     const CryptoHandshakeMessage& other)
37     : tag_(other.tag_),
38       tag_value_map_(other.tag_value_map_),
39       minimum_size_(other.minimum_size_) {
40   // Don't copy serialized_. scoped_ptr doesn't have a copy constructor.
41   // The new object can lazily reconstruct serialized_.
42 }
43 
~CryptoHandshakeMessage()44 CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
45 
operator =(const CryptoHandshakeMessage & other)46 CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
47     const CryptoHandshakeMessage& other) {
48   tag_ = other.tag_;
49   tag_value_map_ = other.tag_value_map_;
50   // Don't copy serialized_. scoped_ptr doesn't have an assignment operator.
51   // However, invalidate serialized_.
52   serialized_.reset();
53   minimum_size_ = other.minimum_size_;
54   return *this;
55 }
56 
Clear()57 void CryptoHandshakeMessage::Clear() {
58   tag_ = 0;
59   tag_value_map_.clear();
60   minimum_size_ = 0;
61   serialized_.reset();
62 }
63 
GetSerialized() const64 const QuicData& CryptoHandshakeMessage::GetSerialized() const {
65   if (!serialized_.get()) {
66     serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
67   }
68   return *serialized_.get();
69 }
70 
MarkDirty()71 void CryptoHandshakeMessage::MarkDirty() {
72   serialized_.reset();
73 }
74 
SetTaglist(QuicTag tag,...)75 void CryptoHandshakeMessage::SetTaglist(QuicTag tag, ...) {
76   // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break
77   // because the terminating 0 will only be promoted to int.
78   COMPILE_ASSERT(sizeof(QuicTag) <= sizeof(int),
79                  crypto_tag_may_not_be_larger_than_int_or_varargs_will_break);
80 
81   vector<QuicTag> tags;
82   va_list ap;
83 
84   va_start(ap, tag);
85   for (;;) {
86     QuicTag list_item = va_arg(ap, QuicTag);
87     if (list_item == 0) {
88       break;
89     }
90     tags.push_back(list_item);
91   }
92 
93   // Because of the way that we keep tags in memory, we can copy the contents
94   // of the vector and get the correct bytes in wire format. See
95   // crypto_protocol.h. This assumes that the system is little-endian.
96   SetVector(tag, tags);
97 
98   va_end(ap);
99 }
100 
SetStringPiece(QuicTag tag,StringPiece value)101 void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) {
102   tag_value_map_[tag] = value.as_string();
103 }
104 
Erase(QuicTag tag)105 void CryptoHandshakeMessage::Erase(QuicTag tag) {
106   tag_value_map_.erase(tag);
107 }
108 
GetTaglist(QuicTag tag,const QuicTag ** out_tags,size_t * out_len) const109 QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
110                                                  const QuicTag** out_tags,
111                                                  size_t* out_len) const {
112   QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
113   QuicErrorCode ret = QUIC_NO_ERROR;
114 
115   if (it == tag_value_map_.end()) {
116     ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
117   } else if (it->second.size() % sizeof(QuicTag) != 0) {
118     ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
119   }
120 
121   if (ret != QUIC_NO_ERROR) {
122     *out_tags = NULL;
123     *out_len = 0;
124     return ret;
125   }
126 
127   *out_tags = reinterpret_cast<const QuicTag*>(it->second.data());
128   *out_len = it->second.size() / sizeof(QuicTag);
129   return ret;
130 }
131 
GetStringPiece(QuicTag tag,StringPiece * out) const132 bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
133                                             StringPiece* out) const {
134   QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
135   if (it == tag_value_map_.end()) {
136     return false;
137   }
138   *out = it->second;
139   return true;
140 }
141 
GetNthValue24(QuicTag tag,unsigned index,StringPiece * out) const142 QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag,
143                                                     unsigned index,
144                                                     StringPiece* out) const {
145   StringPiece value;
146   if (!GetStringPiece(tag, &value)) {
147     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
148   }
149 
150   for (unsigned i = 0;; i++) {
151     if (value.empty()) {
152       return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
153     }
154     if (value.size() < 3) {
155       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
156     }
157 
158     const unsigned char* data =
159         reinterpret_cast<const unsigned char*>(value.data());
160     size_t size = static_cast<size_t>(data[0]) |
161                   (static_cast<size_t>(data[1]) << 8) |
162                   (static_cast<size_t>(data[2]) << 16);
163     value.remove_prefix(3);
164 
165     if (value.size() < size) {
166       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
167     }
168 
169     if (i == index) {
170       *out = StringPiece(value.data(), size);
171       return QUIC_NO_ERROR;
172     }
173 
174     value.remove_prefix(size);
175   }
176 }
177 
GetUint16(QuicTag tag,uint16 * out) const178 QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag,
179                                                 uint16* out) const {
180   return GetPOD(tag, out, sizeof(uint16));
181 }
182 
GetUint32(QuicTag tag,uint32 * out) const183 QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
184                                                 uint32* out) const {
185   return GetPOD(tag, out, sizeof(uint32));
186 }
187 
GetUint64(QuicTag tag,uint64 * out) const188 QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
189                                                 uint64* out) const {
190   return GetPOD(tag, out, sizeof(uint64));
191 }
192 
size() const193 size_t CryptoHandshakeMessage::size() const {
194   size_t ret = sizeof(QuicTag) +
195                sizeof(uint16) /* number of entries */ +
196                sizeof(uint16) /* padding */;
197   ret += (sizeof(QuicTag) + sizeof(uint32) /* end offset */) *
198          tag_value_map_.size();
199   for (QuicTagValueMap::const_iterator i = tag_value_map_.begin();
200        i != tag_value_map_.end(); ++i) {
201     ret += i->second.size();
202   }
203 
204   return ret;
205 }
206 
set_minimum_size(size_t min_bytes)207 void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
208   if (min_bytes == minimum_size_) {
209     return;
210   }
211   serialized_.reset();
212   minimum_size_ = min_bytes;
213 }
214 
minimum_size() const215 size_t CryptoHandshakeMessage::minimum_size() const {
216   return minimum_size_;
217 }
218 
DebugString() const219 string CryptoHandshakeMessage::DebugString() const {
220   return DebugStringInternal(0);
221 }
222 
GetPOD(QuicTag tag,void * out,size_t len) const223 QuicErrorCode CryptoHandshakeMessage::GetPOD(
224     QuicTag tag, void* out, size_t len) const {
225   QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
226   QuicErrorCode ret = QUIC_NO_ERROR;
227 
228   if (it == tag_value_map_.end()) {
229     ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
230   } else if (it->second.size() != len) {
231     ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
232   }
233 
234   if (ret != QUIC_NO_ERROR) {
235     memset(out, 0, len);
236     return ret;
237   }
238 
239   memcpy(out, it->second.data(), len);
240   return ret;
241 }
242 
DebugStringInternal(size_t indent) const243 string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
244   string ret = string(2 * indent, ' ') + QuicUtils::TagToString(tag_) + "<\n";
245   ++indent;
246   for (QuicTagValueMap::const_iterator it = tag_value_map_.begin();
247        it != tag_value_map_.end(); ++it) {
248     ret += string(2 * indent, ' ') + QuicUtils::TagToString(it->first) + ": ";
249 
250     bool done = false;
251     switch (it->first) {
252       case kICSL:
253       case kIRTT:
254       case kKATO:
255       case kMSPC:
256       case kSWND:
257         // uint32 value
258         if (it->second.size() == 4) {
259           uint32 value;
260           memcpy(&value, it->second.data(), sizeof(value));
261           ret += base::UintToString(value);
262           done = true;
263         }
264         break;
265       case kVERS:
266         // uint16 value
267         if (it->second.size() == 2) {
268           uint16 value;
269           memcpy(&value, it->second.data(), sizeof(value));
270           ret += base::UintToString(value);
271           done = true;
272         }
273         break;
274       case kKEXS:
275       case kAEAD:
276       case kCGST:
277       case kPDMD:
278       case kVER:
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             }
287             ret += "'" + QuicUtils::TagToString(tag) + "'";
288           }
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;
305       case kPAD:
306         ret += StringPrintf("(%d bytes of padding)",
307                             static_cast<int>(it->second.size()));
308         done = true;
309         break;
310     }
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 += "0x" + 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 
QuicCryptoNegotiatedParameters()324 QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
325     : key_exchange(0),
326       aead(0) {
327 }
328 
~QuicCryptoNegotiatedParameters()329 QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {}
330 
CrypterPair()331 CrypterPair::CrypterPair() {}
332 
~CrypterPair()333 CrypterPair::~CrypterPair() {}
334 
335 // static
336 const char QuicCryptoConfig::kInitialLabel[] = "QUIC key expansion";
337 
338 // static
339 const char QuicCryptoConfig::kCETVLabel[] = "QUIC CETV block";
340 
341 // static
342 const char QuicCryptoConfig::kForwardSecureLabel[] =
343     "QUIC forward secure key expansion";
344 
QuicCryptoConfig()345 QuicCryptoConfig::QuicCryptoConfig()
346     : common_cert_sets(CommonCertSets::GetInstanceQUIC()) {
347 }
348 
~QuicCryptoConfig()349 QuicCryptoConfig::~QuicCryptoConfig() {}
350 
351 }  // namespace net
352