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 |