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/memory/scoped_ptr.h" | |
13 #include "base/strings/string_util.h" | |
14 #include "net/cert/merkle_consistency_proof.h" | |
12 | 15 |
13 namespace net { | 16 namespace net { |
14 | 17 |
15 namespace ct { | 18 namespace ct { |
16 | 19 |
17 namespace { | 20 namespace { |
18 | 21 |
19 // Note: length is always specified in bytes. | 22 // Note: length is always specified in bytes. |
20 // Signed Certificate Timestamp (SCT) Version length | 23 // Signed Certificate Timestamp (SCT) Version length |
21 const size_t kVersionLength = 1; | 24 const size_t kVersionLength = 1; |
(...skipping 11 matching lines...) Expand all Loading... | |
33 const size_t kLogEntryTypeLength = 2; | 36 const size_t kLogEntryTypeLength = 2; |
34 const size_t kAsn1CertificateLengthBytes = 3; | 37 const size_t kAsn1CertificateLengthBytes = 3; |
35 const size_t kTbsCertificateLengthBytes = 3; | 38 const size_t kTbsCertificateLengthBytes = 3; |
36 | 39 |
37 const size_t kSCTListLengthBytes = 2; | 40 const size_t kSCTListLengthBytes = 2; |
38 const size_t kSerializedSCTLengthBytes = 2; | 41 const size_t kSerializedSCTLengthBytes = 2; |
39 | 42 |
40 // Members of digitally-signed struct of a STH | 43 // Members of digitally-signed struct of a STH |
41 const size_t kTreeSizeLength = 8; | 44 const size_t kTreeSizeLength = 8; |
42 | 45 |
46 // Members of a V1 Consistency Proof | |
47 const size_t kSha256HashLength = 32; | |
48 const size_t kConsistencyPathLengthBytes = 8; | |
49 | |
50 // Length of the version field in a TransItem struct | |
51 const size_t kTransItemVersionLength = 1; | |
52 | |
53 // Length of the type field in a TransItem{V1,V2} struct | |
54 const size_t kTransTypeLength = 1; | |
55 | |
43 enum SignatureType { | 56 enum SignatureType { |
44 SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0, | 57 SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0, |
45 TREE_HASH = 1, | 58 TREE_HASH = 1, |
46 }; | 59 }; |
47 | 60 |
48 // Reads a TLS-encoded variable length unsigned integer from |in|. | 61 // Reads a TLS-encoded variable length unsigned integer from |in|. |
49 // The integer is expected to be in big-endian order, which is used by TLS. | 62 // The integer is expected to be in big-endian order, which is used by TLS. |
50 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 63 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
51 // |length| indicates the size (in bytes) of the integer. On success, returns | 64 // |length| indicates the size (in bytes) of the integer. On success, returns |
52 // true and stores the result in |*out|. | 65 // true and stores the result in |*out|. |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 output); | 318 output); |
306 WriteUint(kSignatureTypeLength, SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP, | 319 WriteUint(kSignatureTypeLength, SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP, |
307 output); | 320 output); |
308 WriteTimeSinceEpoch(timestamp, output); | 321 WriteTimeSinceEpoch(timestamp, output); |
309 // NOTE: serialized_log_entry must already be serialized and contain the | 322 // NOTE: serialized_log_entry must already be serialized and contain the |
310 // length as the prefix. | 323 // length as the prefix. |
311 WriteEncodedBytes(serialized_log_entry, output); | 324 WriteEncodedBytes(serialized_log_entry, output); |
312 return WriteVariableBytes(kExtensionsLengthBytes, extensions, output); | 325 return WriteVariableBytes(kExtensionsLengthBytes, extensions, output); |
313 } | 326 } |
314 | 327 |
328 // TODO(robpercival): This could probably be named better, since the one thing | |
329 // this doesn't encode is the signature. Perhaps just EncodeTreeHead, or | |
330 // EncodeTreeHeadForSignature? | |
315 void EncodeTreeHeadSignature(const SignedTreeHead& signed_tree_head, | 331 void EncodeTreeHeadSignature(const SignedTreeHead& signed_tree_head, |
316 std::string* output) { | 332 std::string* output) { |
317 WriteUint(kVersionLength, signed_tree_head.version, output); | 333 WriteUint(kVersionLength, signed_tree_head.version, output); |
318 WriteUint(kSignatureTypeLength, TREE_HASH, output); | 334 WriteUint(kSignatureTypeLength, TREE_HASH, output); |
319 WriteTimeSinceEpoch(signed_tree_head.timestamp, output); | 335 WriteTimeSinceEpoch(signed_tree_head.timestamp, output); |
320 WriteUint(kTreeSizeLength, signed_tree_head.tree_size, output); | 336 WriteUint(kTreeSizeLength, signed_tree_head.tree_size, output); |
321 WriteEncodedBytes( | 337 WriteEncodedBytes( |
322 base::StringPiece(signed_tree_head.sha256_root_hash, kSthRootHashLength), | 338 base::StringPiece(signed_tree_head.sha256_root_hash, kSthRootHashLength), |
323 output); | 339 output); |
324 } | 340 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
370 log_id.CopyToString(&result->log_id); | 386 log_id.CopyToString(&result->log_id); |
371 extensions.CopyToString(&result->extensions); | 387 extensions.CopyToString(&result->extensions); |
372 result->timestamp = | 388 result->timestamp = |
373 base::Time::UnixEpoch() + | 389 base::Time::UnixEpoch() + |
374 base::TimeDelta::FromMilliseconds(static_cast<int64_t>(timestamp)); | 390 base::TimeDelta::FromMilliseconds(static_cast<int64_t>(timestamp)); |
375 | 391 |
376 output->swap(result); | 392 output->swap(result); |
377 return true; | 393 return true; |
378 } | 394 } |
379 | 395 |
396 bool EncodeSignedCertificateTimestamp(const SignedCertificateTimestamp& input, | |
397 std::string* output) { | |
398 WriteUint(kVersionLength, input.version, output); | |
399 DCHECK_EQ(kLogIdLength, WriteEncodedBytes(input.log_id, output)); | |
400 WriteTimeSinceEpoch(input.timestamp, output); | |
401 | |
402 if (!WriteVariableBytes(kExtensionsLengthBytes, input.extensions, output) || | |
403 !EncodeDigitallySigned(input.signature, output)) { | |
404 return false; | |
405 } | |
406 | |
407 return true; | |
408 } | |
409 | |
380 bool EncodeSCTListForTesting(const base::StringPiece& sct, | 410 bool EncodeSCTListForTesting(const base::StringPiece& sct, |
381 std::string* output) { | 411 std::string* output) { |
382 std::string encoded_sct; | 412 std::string encoded_sct; |
383 return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && | 413 return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && |
384 WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); | 414 WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); |
385 } | 415 } |
386 | 416 |
417 bool DecodeSignedTreeHead(base::StringPiece* input, SignedTreeHead* output) { | |
418 base::StringPiece log_id; | |
419 base::StringPiece sha256_root_hash; | |
420 if (!ReadFixedBytes(kLogIdLength, input, &log_id) || | |
421 !ReadTimeSinceEpoch(input, &output->timestamp) || | |
422 !ReadUint(kTreeSizeLength, input, &output->tree_size) || | |
423 !ReadFixedBytes(kSthRootHashLength, input, &sha256_root_hash)) { | |
424 return false; | |
425 } | |
426 | |
427 log_id.CopyToString(&output->log_id); | |
Eran Messeri
2016/01/14 12:46:45
A common pattern in this file is to decode to a te
| |
428 log_id.copy(output->sha256_root_hash, kSthRootHashLength); | |
429 return true; | |
430 } | |
431 | |
432 bool EncodeSignedTreeHead(const SignedTreeHead& input, std::string* output) { | |
433 DCHECK_EQ(kLogIdLength, WriteEncodedBytes(input.log_id, output)); | |
434 WriteTimeSinceEpoch(input.timestamp, output); | |
435 WriteUint(kTreeSizeLength, input.tree_size, output); | |
436 | |
437 base::StringPiece root_hash(input.sha256_root_hash, kSthRootHashLength); | |
438 WriteEncodedBytes(root_hash, output); | |
439 | |
440 if (!EncodeDigitallySigned(input.signature, output)) { | |
441 return false; | |
442 } | |
443 | |
444 return true; | |
445 } | |
446 | |
447 bool DecodeConsistencyProof(base::StringPiece* input, | |
448 MerkleConsistencyProof* output) { | |
449 base::StringPiece log_id; | |
450 if (!ReadFixedBytes(kLogIdLength, input, &log_id)) { | |
451 return false; | |
452 } | |
453 log_id.CopyToString(&output->log_id); | |
454 | |
455 if (!ReadUint(kTreeSizeLength, input, &output->first_tree_size)) { | |
456 return false; | |
457 } | |
458 | |
459 if (!ReadUint(kTreeSizeLength, input, &output->second_tree_size)) { | |
460 return false; | |
461 } | |
462 | |
463 base::StringPiece consistency_path; | |
464 if (!ReadVariableBytes(kConsistencyPathLengthBytes, input, | |
465 &consistency_path)) { | |
466 return false; | |
467 } | |
468 | |
469 for (size_t i = 0; i < consistency_path.size() / kSha256HashLength; ++i) { | |
470 base::StringPiece node_hash = | |
471 consistency_path.substr(kSha256HashLength * i, kSha256HashLength); | |
472 | |
473 output->nodes.push_back(node_hash.as_string()); | |
474 } | |
475 | |
476 return true; | |
477 } | |
478 | |
479 bool EncodeConsistencyProof(const MerkleConsistencyProof& input, | |
480 std::string* output) { | |
481 WriteEncodedBytes(input.log_id, output); | |
482 WriteUint(kTreeSizeLength, input.first_tree_size, output); | |
483 WriteUint(kTreeSizeLength, input.second_tree_size, output); | |
484 | |
485 std::string consistency_path = base::JoinString(input.nodes, ""); | |
486 if (!WriteVariableBytes(kConsistencyPathLengthBytes, consistency_path, | |
487 output)) { | |
488 return false; | |
489 } | |
490 | |
491 return true; | |
492 } | |
493 | |
494 bool DecodeTransItem(base::StringPiece* input, TransItem* output) { | |
495 unsigned version; | |
496 if (!ReadUint(kTransItemVersionLength, input, &version)) { | |
497 return false; | |
498 } | |
499 | |
500 switch (static_cast<TransItem::Version>(version)) { | |
501 case TransItem::Version::V1: { | |
502 scoped_ptr<TransItemV1> item(new TransItemV1()); | |
503 if (!DecodeTransItem(input, item.get())) { | |
504 return false; | |
505 } | |
506 output->Set(std::move(item)); | |
507 return true; | |
508 } | |
509 } | |
510 | |
511 return false; | |
512 } | |
513 | |
514 bool DecodeTransItem(base::StringPiece* input, TransItemV1* output) { | |
515 unsigned type; | |
516 if (!ReadUint(kTransTypeLength, input, &type)) { | |
517 return false; | |
518 } | |
519 | |
520 switch (static_cast<TransType>(type)) { | |
521 case TransType::X509_SCT: { | |
522 scoped_refptr<SignedCertificateTimestamp> sct; | |
523 if (!DecodeSignedCertificateTimestamp(input, &sct)) { | |
524 return false; | |
525 } | |
526 output->SetX509Sct(sct); | |
527 return true; | |
528 } | |
529 case TransType::SIGNED_TREE_HEAD: { | |
530 SignedTreeHead sth; | |
531 if (!DecodeSignedTreeHead(input, &sth)) { | |
532 return false; | |
533 } | |
534 output->SetSignedTreeHead(sth); | |
535 return true; | |
536 } | |
537 case TransType::CONSISTENCY_PROOF: { | |
538 net::ct::MerkleConsistencyProof proof; | |
539 if (!DecodeConsistencyProof(input, &proof)) { | |
540 return false; | |
541 } | |
542 output->SetConsistencyProof(proof); | |
543 return true; | |
544 } | |
545 } | |
546 | |
547 return false; | |
548 } | |
549 | |
550 bool EncodeTransItem(const TransItem& input, std::string* output) { | |
551 WriteUint(kTransItemVersionLength, static_cast<uint8_t>(input.version()), | |
552 output); | |
553 | |
554 switch (input.version()) { | |
555 case TransItem::Version::V1: | |
556 return EncodeTransItem(input.v1(), output); | |
557 } | |
558 | |
559 return false; | |
560 } | |
561 | |
562 bool EncodeTransItem(const TransItemV1& input, std::string* output) { | |
563 WriteUint(kTransTypeLength, static_cast<uint8_t>(input.type()), output); | |
564 | |
565 switch (input.type()) { | |
566 case TransType::X509_SCT: | |
567 return EncodeSignedCertificateTimestamp(*input.x509_sct(), output); | |
568 case TransType::SIGNED_TREE_HEAD: | |
569 return EncodeSignedTreeHead(input.signed_tree_head(), output); | |
570 case TransType::CONSISTENCY_PROOF: | |
571 return EncodeConsistencyProof(input.consistency_proof(), output); | |
572 } | |
573 | |
574 return false; | |
575 } | |
576 | |
387 } // namespace ct | 577 } // namespace ct |
388 | 578 |
389 } // namespace net | 579 } // namespace net |
OLD | NEW |