OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/ct_serialization.h" | 5 #include "net/cert/ct_serialization.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <limits> | 9 #include <limits> |
10 | 10 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/numerics/safe_math.h" | |
12 | 13 |
13 namespace net { | 14 namespace net { |
14 | 15 |
15 namespace ct { | 16 namespace ct { |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 // Note: length is always specified in bytes. | 20 // Note: length is always specified in bytes. |
20 // Signed Certificate Timestamp (SCT) Version length | 21 // Signed Certificate Timestamp (SCT) Version length |
21 const size_t kVersionLength = 1; | 22 const size_t kVersionLength = 1; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
59 T result = 0; | 60 T result = 0; |
60 for (size_t i = 0; i < length; ++i) { | 61 for (size_t i = 0; i < length; ++i) { |
61 result = (result << 8) | static_cast<unsigned char>((*in)[i]); | 62 result = (result << 8) | static_cast<unsigned char>((*in)[i]); |
62 } | 63 } |
63 in->remove_prefix(length); | 64 in->remove_prefix(length); |
64 *out = result; | 65 *out = result; |
65 return true; | 66 return true; |
66 } | 67 } |
67 | 68 |
68 // Reads a TLS-encoded field length from |in|. | 69 // Reads a TLS-encoded field length from |in|. |
69 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 70 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed). |
70 // |prefix_length| indicates the bytes needed to represent the length (e.g. 3) | 71 // |prefix_length| indicates the bytes needed to represent the length (e.g. 3). |
72 // Max |prefix_length| is 8. | |
71 // success, returns true and stores the result in |*out|. | 73 // success, returns true and stores the result in |*out|. |
72 bool ReadLength(size_t prefix_length, base::StringPiece* in, size_t* out) { | 74 bool ReadLength(size_t prefix_length, base::StringPiece* in, size_t* out) { |
73 size_t length; | 75 uint64_t length = 0; |
74 if (!ReadUint(prefix_length, in, &length)) | 76 if (!ReadUint(prefix_length, in, &length)) |
75 return false; | 77 return false; |
76 *out = length; | 78 base::CheckedNumeric<size_t> checked_length = length; |
79 if (!checked_length.IsValid()) | |
80 return false; | |
81 *out = checked_length.ValueOrDie(); | |
77 return true; | 82 return true; |
78 } | 83 } |
79 | 84 |
80 // Reads |length| bytes from |*in|. If |*in| is too small, returns false. | 85 // Reads |length| bytes from |*in|. If |*in| is too small, returns false. |
81 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 86 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
82 bool ReadFixedBytes(size_t length, | 87 bool ReadFixedBytes(size_t length, |
83 base::StringPiece* in, | 88 base::StringPiece* in, |
84 base::StringPiece* out) { | 89 base::StringPiece* out) { |
85 if (in->length() < length) | 90 if (in->length() < length) |
86 return false; | 91 return false; |
87 out->set(in->data(), length); | 92 out->set(in->data(), length); |
88 in->remove_prefix(length); | 93 in->remove_prefix(length); |
89 return true; | 94 return true; |
90 } | 95 } |
91 | 96 |
92 // Reads a length-prefixed variable amount of bytes from |in|, updating |out| | 97 // Reads a length-prefixed variable amount of bytes from |in|, updating |out| |
93 // on success. |prefix_length| indicates the number of bytes needed to represent | 98 // on success. |prefix_length| indicates the number of bytes needed to represent |
94 // the length. | 99 // the length. |
95 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 100 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
96 bool ReadVariableBytes(size_t prefix_length, | 101 bool ReadVariableBytes(size_t prefix_length, |
97 base::StringPiece* in, | 102 base::StringPiece* in, |
98 base::StringPiece* out) { | 103 base::StringPiece* out) { |
99 size_t length; | 104 size_t length = 0; |
100 if (!ReadLength(prefix_length, in, &length)) | 105 if (!ReadLength(prefix_length, in, &length)) |
101 return false; | 106 return false; |
102 return ReadFixedBytes(length, in, out); | 107 return ReadFixedBytes(length, in, out); |
103 } | 108 } |
104 | 109 |
105 // Reads a variable-length list that has been TLS encoded. | 110 // Reads a variable-length list that has been TLS encoded. |
106 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 111 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
107 // |max_list_length| contains the overall length of the encoded list. | 112 // |max_list_length| contains the overall length of the encoded list. |
108 // |max_item_length| contains the maximum length of a single item. | 113 // |max_item_length| contains the maximum length of a single item. |
109 // On success, returns true and updates |*out| with the encoded list. | 114 // On success, returns true and updates |*out| with the encoded list. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 | 182 |
178 // Writes a TLS-encoded variable length unsigned integer to |output|. | 183 // Writes a TLS-encoded variable length unsigned integer to |output|. |
179 // |length| indicates the size (in bytes) of the integer. | 184 // |length| indicates the size (in bytes) of the integer. |
180 // |value| the value itself to be written. | 185 // |value| the value itself to be written. |
181 template <typename T> | 186 template <typename T> |
182 void WriteUint(size_t length, T value, std::string* output) { | 187 void WriteUint(size_t length, T value, std::string* output) { |
183 DCHECK_LE(length, sizeof(T)); | 188 DCHECK_LE(length, sizeof(T)); |
184 DCHECK(length == sizeof(T) || value >> (length * 8) == 0); | 189 DCHECK(length == sizeof(T) || value >> (length * 8) == 0); |
185 | 190 |
186 for (; length > 0; --length) { | 191 for (; length > 0; --length) { |
187 output->push_back((value >> ((length - 1)* 8)) & 0xFF); | 192 output->push_back((value >> ((length - 1) * 8)) & 0xFF); |
188 } | 193 } |
Ryan Sleevi
2016/01/13 02:44:32
What if we:
Delete both DCHECKs
DCHECK(length >=
| |
189 } | 194 } |
190 | 195 |
191 // Writes an array to |output| from |input|. | 196 // Writes an array to |output| from |input|. |
192 // Should be used in one of two cases: | 197 // Should be used in one of two cases: |
193 // * The length of |input| has already been encoded into the |output| stream. | 198 // * The length of |input| has already been encoded into the |output| stream. |
194 // * The length of |input| is fixed and the reader is expected to specify that | 199 // * The length of |input| is fixed and the reader is expected to specify that |
195 // length when reading. | 200 // length when reading. |
196 // If the length of |input| is dynamic and data is expected to follow it, | 201 // If the length of |input| is dynamic and data is expected to follow it, |
197 // WriteVariableBytes must be used. | 202 // WriteVariableBytes must be used. |
198 void WriteEncodedBytes(const base::StringPiece& input, std::string* output) { | 203 // Returns the number of bytes written (the length of |input|). |
204 size_t WriteEncodedBytes(const base::StringPiece& input, std::string* output) { | |
199 input.AppendToString(output); | 205 input.AppendToString(output); |
206 return input.size(); | |
200 } | 207 } |
201 | 208 |
202 // Writes a variable-length array to |output|. | 209 // Writes a variable-length array to |output|. |
203 // |prefix_length| indicates the number of bytes needed to represnt the length. | 210 // |prefix_length| indicates the number of bytes needed to represnt the length. |
Ryan Sleevi
2016/01/12 00:10:15
typo: represent
Rob Percival
2016/01/13 00:55:52
Done.
| |
204 // |input| is the array itself. | 211 // |input| is the array itself. |
205 // If the size of |input| is less than 2^|prefix_length| - 1, encode the | 212 // If 1 <= |prefix_length| <= 8 and the size of |input| is less than |
206 // length and data and return true. Otherwise, return false. | 213 // 2^|prefix_length| - 1, encode the length and data and return true. |
214 // Otherwise, return false. | |
207 bool WriteVariableBytes(size_t prefix_length, | 215 bool WriteVariableBytes(size_t prefix_length, |
208 const base::StringPiece& input, | 216 const base::StringPiece& input, |
209 std::string* output) { | 217 std::string* output) { |
210 size_t input_size = input.size(); | 218 // Use uint64_t instead of size_t to allow a |prefix_length| up to 8 bytes, |
211 size_t max_allowed_input_size = | 219 // even on 32-bit builds. |
212 static_cast<size_t>(((1 << (prefix_length * 8)) - 1)); | 220 uint64_t input_size = input.size(); |
221 if (prefix_length > sizeof(input_size)) | |
222 return false; | |
223 | |
224 uint64_t max_allowed_input_size = ((1 << (prefix_length * 8)) - 1); | |
213 if (input_size > max_allowed_input_size) | 225 if (input_size > max_allowed_input_size) |
214 return false; | 226 return false; |
Rob Percival
2016/01/20 20:20:33
It's not clear to me why WriteVariableBytes return
Ryan Sleevi
2016/01/20 20:56:37
I believe the logic was because WriteVariableBytes
| |
215 | 227 |
216 WriteUint(prefix_length, input.size(), output); | 228 WriteUint(prefix_length, input_size, output); |
217 WriteEncodedBytes(input, output); | 229 WriteEncodedBytes(input, output); |
218 | 230 |
219 return true; | 231 return true; |
220 } | 232 } |
221 | 233 |
222 // Writes a LogEntry of type X.509 cert to |output|. | 234 // Writes a LogEntry of type X.509 cert to |output|. |
223 // |input| is the LogEntry containing the certificate. | 235 // |input| is the LogEntry containing the certificate. |
224 // Returns true if the leaf_certificate in the LogEntry does not exceed | 236 // Returns true if the leaf_certificate in the LogEntry does not exceed |
225 // kMaxAsn1CertificateLength and so can be written to |output|. | 237 // kMaxAsn1CertificateLength and so can be written to |output|. |
226 bool EncodeAsn1CertLogEntry(const LogEntry& input, std::string* output) { | 238 bool EncodeAsn1CertLogEntry(const LogEntry& input, std::string* output) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
284 WriteUint(kLogEntryTypeLength, input.type, output); | 296 WriteUint(kLogEntryTypeLength, input.type, output); |
285 switch (input.type) { | 297 switch (input.type) { |
286 case LogEntry::LOG_ENTRY_TYPE_X509: | 298 case LogEntry::LOG_ENTRY_TYPE_X509: |
287 return EncodeAsn1CertLogEntry(input, output); | 299 return EncodeAsn1CertLogEntry(input, output); |
288 case LogEntry::LOG_ENTRY_TYPE_PRECERT: | 300 case LogEntry::LOG_ENTRY_TYPE_PRECERT: |
289 return EncodePrecertLogEntry(input, output); | 301 return EncodePrecertLogEntry(input, output); |
290 } | 302 } |
291 return false; | 303 return false; |
292 } | 304 } |
293 | 305 |
306 static bool ReadTimeSinceEpoch(base::StringPiece* input, base::Time* output) { | |
307 uint64_t time_since_epoch = 0; | |
308 if (!ReadUint(kTimestampLength, input, &time_since_epoch)) { | |
309 return false; | |
310 } | |
311 | |
312 base::CheckedNumeric<int64_t> time_since_epoch_signed = time_since_epoch; | |
313 | |
314 if (!time_since_epoch_signed.IsValid()) { | |
315 DVLOG(1) << "Timestamp value too big to cast to int64_t: " | |
316 << time_since_epoch; | |
317 return false; | |
318 } | |
319 | |
320 *output = | |
321 base::Time::UnixEpoch() + | |
322 base::TimeDelta::FromMilliseconds(time_since_epoch_signed.ValueOrDie()); | |
323 | |
324 return true; | |
325 } | |
326 | |
294 static void WriteTimeSinceEpoch(const base::Time& timestamp, | 327 static void WriteTimeSinceEpoch(const base::Time& timestamp, |
295 std::string* output) { | 328 std::string* output) { |
296 base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); | 329 base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); |
297 WriteUint(kTimestampLength, time_since_epoch.InMilliseconds(), output); | 330 WriteUint(kTimestampLength, time_since_epoch.InMilliseconds(), output); |
298 } | 331 } |
299 | 332 |
300 bool EncodeV1SCTSignedData(const base::Time& timestamp, | 333 bool EncodeV1SCTSignedData(const base::Time& timestamp, |
301 const std::string& serialized_log_entry, | 334 const std::string& serialized_log_entry, |
302 const std::string& extensions, | 335 const std::string& extensions, |
303 std::string* output) { | 336 std::string* output) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
344 new SignedCertificateTimestamp()); | 377 new SignedCertificateTimestamp()); |
345 unsigned version; | 378 unsigned version; |
346 if (!ReadUint(kVersionLength, input, &version)) | 379 if (!ReadUint(kVersionLength, input, &version)) |
347 return false; | 380 return false; |
348 if (version != SignedCertificateTimestamp::SCT_VERSION_1) { | 381 if (version != SignedCertificateTimestamp::SCT_VERSION_1) { |
349 DVLOG(1) << "Unsupported/invalid version " << version; | 382 DVLOG(1) << "Unsupported/invalid version " << version; |
350 return false; | 383 return false; |
351 } | 384 } |
352 | 385 |
353 result->version = SignedCertificateTimestamp::SCT_VERSION_1; | 386 result->version = SignedCertificateTimestamp::SCT_VERSION_1; |
354 uint64_t timestamp; | |
355 base::StringPiece log_id; | 387 base::StringPiece log_id; |
356 base::StringPiece extensions; | 388 base::StringPiece extensions; |
357 if (!ReadFixedBytes(kLogIdLength, input, &log_id) || | 389 if (!ReadFixedBytes(kLogIdLength, input, &log_id) || |
358 !ReadUint(kTimestampLength, input, ×tamp) || | 390 !ReadTimeSinceEpoch(input, &result->timestamp) || |
359 !ReadVariableBytes(kExtensionsLengthBytes, input, | 391 !ReadVariableBytes(kExtensionsLengthBytes, input, &extensions) || |
360 &extensions) || | |
361 !DecodeDigitallySigned(input, &result->signature)) { | 392 !DecodeDigitallySigned(input, &result->signature)) { |
362 return false; | 393 return false; |
363 } | 394 } |
364 | 395 |
365 if (timestamp > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) { | |
366 DVLOG(1) << "Timestamp value too big to cast to int64_t: " << timestamp; | |
367 return false; | |
368 } | |
369 | |
370 log_id.CopyToString(&result->log_id); | 396 log_id.CopyToString(&result->log_id); |
371 extensions.CopyToString(&result->extensions); | 397 extensions.CopyToString(&result->extensions); |
372 result->timestamp = | |
373 base::Time::UnixEpoch() + | |
374 base::TimeDelta::FromMilliseconds(static_cast<int64_t>(timestamp)); | |
375 | |
376 output->swap(result); | 398 output->swap(result); |
377 return true; | 399 return true; |
378 } | 400 } |
379 | 401 |
380 bool EncodeSCTListForTesting(const base::StringPiece& sct, | 402 bool EncodeSCTListForTesting(const base::StringPiece& sct, |
381 std::string* output) { | 403 std::string* output) { |
382 std::string encoded_sct; | 404 std::string encoded_sct; |
383 return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && | 405 return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && |
384 WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); | 406 WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); |
385 } | 407 } |
386 | 408 |
387 } // namespace ct | 409 } // namespace ct |
388 | 410 |
389 } // namespace net | 411 } // namespace net |
OLD | NEW |