Chromium Code Reviews| 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 |