Chromium Code Reviews| Index: net/cert/ct_serialization.cc |
| diff --git a/net/cert/ct_serialization.cc b/net/cert/ct_serialization.cc |
| index 235d37e65ad1fc8106a05d602c3c9f04b4e61a48..2beacc681f4ecc5442fb94e2790c163341533dff 100644 |
| --- a/net/cert/ct_serialization.cc |
| +++ b/net/cert/ct_serialization.cc |
| @@ -9,6 +9,9 @@ |
| #include <limits> |
| #include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/strings/string_util.h" |
| +#include "net/cert/merkle_consistency_proof.h" |
| namespace net { |
| @@ -40,6 +43,16 @@ const size_t kSerializedSCTLengthBytes = 2; |
| // Members of digitally-signed struct of a STH |
| const size_t kTreeSizeLength = 8; |
| +// Members of a V1 Consistency Proof |
| +const size_t kSha256HashLength = 32; |
| +const size_t kConsistencyPathLengthBytes = 8; |
| + |
| +// Length of the version field in a TransItem struct |
| +const size_t kTransItemVersionLength = 1; |
| + |
| +// Length of the type field in a TransItem{V1,V2} struct |
| +const size_t kTransTypeLength = 1; |
| + |
| enum SignatureType { |
| SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0, |
| TREE_HASH = 1, |
| @@ -312,6 +325,9 @@ bool EncodeV1SCTSignedData(const base::Time& timestamp, |
| return WriteVariableBytes(kExtensionsLengthBytes, extensions, output); |
| } |
| +// TODO(robpercival): This could probably be named better, since the one thing |
| +// this doesn't encode is the signature. Perhaps just EncodeTreeHead, or |
| +// EncodeTreeHeadForSignature? |
| void EncodeTreeHeadSignature(const SignedTreeHead& signed_tree_head, |
| std::string* output) { |
| WriteUint(kVersionLength, signed_tree_head.version, output); |
| @@ -377,6 +393,20 @@ bool DecodeSignedCertificateTimestamp( |
| return true; |
| } |
| +bool EncodeSignedCertificateTimestamp(const SignedCertificateTimestamp& input, |
| + std::string* output) { |
| + WriteUint(kVersionLength, input.version, output); |
| + DCHECK_EQ(kLogIdLength, WriteEncodedBytes(input.log_id, output)); |
| + WriteTimeSinceEpoch(input.timestamp, output); |
| + |
| + if (!WriteVariableBytes(kExtensionsLengthBytes, input.extensions, output) || |
| + !EncodeDigitallySigned(input.signature, output)) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| bool EncodeSCTListForTesting(const base::StringPiece& sct, |
| std::string* output) { |
| std::string encoded_sct; |
| @@ -384,6 +414,166 @@ bool EncodeSCTListForTesting(const base::StringPiece& sct, |
| WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); |
| } |
| +bool DecodeSignedTreeHead(base::StringPiece* input, SignedTreeHead* output) { |
| + base::StringPiece log_id; |
| + base::StringPiece sha256_root_hash; |
| + if (!ReadFixedBytes(kLogIdLength, input, &log_id) || |
| + !ReadTimeSinceEpoch(input, &output->timestamp) || |
| + !ReadUint(kTreeSizeLength, input, &output->tree_size) || |
| + !ReadFixedBytes(kSthRootHashLength, input, &sha256_root_hash)) { |
| + return false; |
| + } |
| + |
| + 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
|
| + log_id.copy(output->sha256_root_hash, kSthRootHashLength); |
| + return true; |
| +} |
| + |
| +bool EncodeSignedTreeHead(const SignedTreeHead& input, std::string* output) { |
| + DCHECK_EQ(kLogIdLength, WriteEncodedBytes(input.log_id, output)); |
| + WriteTimeSinceEpoch(input.timestamp, output); |
| + WriteUint(kTreeSizeLength, input.tree_size, output); |
| + |
| + base::StringPiece root_hash(input.sha256_root_hash, kSthRootHashLength); |
| + WriteEncodedBytes(root_hash, output); |
| + |
| + if (!EncodeDigitallySigned(input.signature, output)) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool DecodeConsistencyProof(base::StringPiece* input, |
| + MerkleConsistencyProof* output) { |
| + base::StringPiece log_id; |
| + if (!ReadFixedBytes(kLogIdLength, input, &log_id)) { |
| + return false; |
| + } |
| + log_id.CopyToString(&output->log_id); |
| + |
| + if (!ReadUint(kTreeSizeLength, input, &output->first_tree_size)) { |
| + return false; |
| + } |
| + |
| + if (!ReadUint(kTreeSizeLength, input, &output->second_tree_size)) { |
| + return false; |
| + } |
| + |
| + base::StringPiece consistency_path; |
| + if (!ReadVariableBytes(kConsistencyPathLengthBytes, input, |
| + &consistency_path)) { |
| + return false; |
| + } |
| + |
| + for (size_t i = 0; i < consistency_path.size() / kSha256HashLength; ++i) { |
| + base::StringPiece node_hash = |
| + consistency_path.substr(kSha256HashLength * i, kSha256HashLength); |
| + |
| + output->nodes.push_back(node_hash.as_string()); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool EncodeConsistencyProof(const MerkleConsistencyProof& input, |
| + std::string* output) { |
| + WriteEncodedBytes(input.log_id, output); |
| + WriteUint(kTreeSizeLength, input.first_tree_size, output); |
| + WriteUint(kTreeSizeLength, input.second_tree_size, output); |
| + |
| + std::string consistency_path = base::JoinString(input.nodes, ""); |
| + if (!WriteVariableBytes(kConsistencyPathLengthBytes, consistency_path, |
| + output)) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool DecodeTransItem(base::StringPiece* input, TransItem* output) { |
| + unsigned version; |
| + if (!ReadUint(kTransItemVersionLength, input, &version)) { |
| + return false; |
| + } |
| + |
| + switch (static_cast<TransItem::Version>(version)) { |
| + case TransItem::Version::V1: { |
| + scoped_ptr<TransItemV1> item(new TransItemV1()); |
| + if (!DecodeTransItem(input, item.get())) { |
| + return false; |
| + } |
| + output->Set(std::move(item)); |
| + return true; |
| + } |
| + } |
| + |
| + return false; |
| +} |
| + |
| +bool DecodeTransItem(base::StringPiece* input, TransItemV1* output) { |
| + unsigned type; |
| + if (!ReadUint(kTransTypeLength, input, &type)) { |
| + return false; |
| + } |
| + |
| + switch (static_cast<TransType>(type)) { |
| + case TransType::X509_SCT: { |
| + scoped_refptr<SignedCertificateTimestamp> sct; |
| + if (!DecodeSignedCertificateTimestamp(input, &sct)) { |
| + return false; |
| + } |
| + output->SetX509Sct(sct); |
| + return true; |
| + } |
| + case TransType::SIGNED_TREE_HEAD: { |
| + SignedTreeHead sth; |
| + if (!DecodeSignedTreeHead(input, &sth)) { |
| + return false; |
| + } |
| + output->SetSignedTreeHead(sth); |
| + return true; |
| + } |
| + case TransType::CONSISTENCY_PROOF: { |
| + net::ct::MerkleConsistencyProof proof; |
| + if (!DecodeConsistencyProof(input, &proof)) { |
| + return false; |
| + } |
| + output->SetConsistencyProof(proof); |
| + return true; |
| + } |
| + } |
| + |
| + return false; |
| +} |
| + |
| +bool EncodeTransItem(const TransItem& input, std::string* output) { |
| + WriteUint(kTransItemVersionLength, static_cast<uint8_t>(input.version()), |
| + output); |
| + |
| + switch (input.version()) { |
| + case TransItem::Version::V1: |
| + return EncodeTransItem(input.v1(), output); |
| + } |
| + |
| + return false; |
| +} |
| + |
| +bool EncodeTransItem(const TransItemV1& input, std::string* output) { |
| + WriteUint(kTransTypeLength, static_cast<uint8_t>(input.type()), output); |
| + |
| + switch (input.type()) { |
| + case TransType::X509_SCT: |
| + return EncodeSignedCertificateTimestamp(*input.x509_sct(), output); |
| + case TransType::SIGNED_TREE_HEAD: |
| + return EncodeSignedTreeHead(input.signed_tree_head(), output); |
| + case TransType::CONSISTENCY_PROOF: |
| + return EncodeConsistencyProof(input.consistency_proof(), output); |
| + } |
| + |
| + return false; |
| +} |
| + |
| } // namespace ct |
| } // namespace net |