Commit 0d25a428 authored by Kaustubha Govind's avatar Kaustubha Govind Committed by Commit Bot

Replace custom CT parsing code with BoringSSL CBS/CBB APIs.

Reuse ByteString/ByteBuilder APIs for CT parsing and serialization.

Added boolean return arguments to EncodeTreeHeadSignature and
EncodeSignedCertificateTimestamp, and updated a couple of clients to check
return value and handle failure cases as appropriate.

Bug: 634570
Change-Id: Id309470e18d0bc7316623c2f5dd7aaf3854527cf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1465984
Commit-Queue: Kaustubha Govind <kaustubhag@chromium.org>
Reviewed-by: default avatarEmily Stark <estark@chromium.org>
Reviewed-by: default avatarDavid Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/master@{#637879}
parent 03af9daa
...@@ -108,7 +108,9 @@ bool CTLogVerifier::VerifySignedTreeHead( ...@@ -108,7 +108,9 @@ bool CTLogVerifier::VerifySignedTreeHead(
return false; return false;
std::string serialized_data; std::string serialized_data;
ct::EncodeTreeHeadSignature(signed_tree_head, &serialized_data); if (!ct::EncodeTreeHeadSignature(signed_tree_head, &serialized_data))
return false;
if (VerifySignature(serialized_data, if (VerifySignature(serialized_data,
signed_tree_head.signature.signature_data)) { signed_tree_head.signature.signature_data)) {
if (signed_tree_head.tree_size == 0) { if (signed_tree_head.tree_size == 0) {
......
...@@ -4,17 +4,12 @@ ...@@ -4,17 +4,12 @@
#include "net/cert/ct_serialization.h" #include "net/cert/ct_serialization.h"
#include <stdint.h>
#include <algorithm>
#include <limits>
#include "base/logging.h" #include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "crypto/sha2.h" #include "crypto/sha2.h"
#include "net/cert/merkle_tree_leaf.h" #include "net/cert/merkle_tree_leaf.h"
#include "net/cert/signed_certificate_timestamp.h" #include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/signed_tree_head.h" #include "net/cert/signed_tree_head.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
namespace net { namespace net {
...@@ -22,132 +17,39 @@ namespace ct { ...@@ -22,132 +17,39 @@ namespace ct {
namespace { namespace {
// Note: length is always specified in bytes.
// CT protocol version length
const size_t kVersionLength = 1;
// Common V1 struct members
const size_t kTimestampLength = 8;
const size_t kSignedEntryTypeLength = 2;
const size_t kAsn1CertificateLengthBytes = 3;
const size_t kTbsCertificateLengthBytes = 3;
const size_t kExtensionsLengthBytes = 2;
// Members of a V1 SCT
const size_t kLogIdLength = crypto::kSHA256Length; const size_t kLogIdLength = crypto::kSHA256Length;
const size_t kHashAlgorithmLength = 1;
const size_t kSigAlgorithmLength = 1;
const size_t kSignatureLengthBytes = 2;
// Members of the digitally-signed struct of a V1 SCT
const size_t kSignatureTypeLength = 1;
const size_t kSCTListLengthBytes = 2;
const size_t kSerializedSCTLengthBytes = 2;
// Members of digitally-signed struct of a STH
const size_t kTreeSizeLength = 8;
// Members of a V1 MerkleTreeLeaf
const size_t kMerkleLeafTypeLength = 1;
const size_t kIssuerKeyHashLength = crypto::kSHA256Length;
enum SignatureType { enum SignatureType {
SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0, SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0,
TREE_HASH = 1, TREE_HASH = 1,
}; };
// Reads a TLS-encoded variable length unsigned integer from |in|. // Reads a variable-length SCT list that has been TLS encoded.
// The integer is expected to be in big-endian order, which is used by TLS.
// The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
// |length| indicates the size (in bytes) of the integer. On success, returns
// true and stores the result in |*out|.
template <typename T>
bool ReadUint(size_t length, base::StringPiece* in, T* out) {
if (in->size() < length)
return false;
DCHECK_NE(length, 0u);
DCHECK_LE(length, sizeof(T));
T result = static_cast<uint8_t>((*in)[0]);
// This loop only executes if sizeof(T) > 1, because the first operation is
// to shift left by 1 byte, which is undefined behaviour if T is a 1 byte
// integer.
for (size_t i = 1; i < length; ++i) {
result = (result << 8) | static_cast<uint8_t>((*in)[i]);
}
in->remove_prefix(length);
*out = result;
return true;
}
// Reads a TLS-encoded field length from |in|.
// The bytes read from |in| are discarded (i.e. |in|'s prefix removed).
// |prefix_length| indicates the bytes needed to represent the length (e.g. 3).
// Max |prefix_length| is 8.
// success, returns true and stores the result in |*out|.
bool ReadLength(size_t prefix_length, base::StringPiece* in, size_t* out) {
uint64_t length = 0;
if (!ReadUint(prefix_length, in, &length))
return false;
base::CheckedNumeric<size_t> checked_length = length;
if (!checked_length.IsValid())
return false;
*out = checked_length.ValueOrDie();
return true;
}
// Reads |length| bytes from |*in|. If |*in| is too small, returns false.
// The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
bool ReadFixedBytes(size_t length,
base::StringPiece* in,
base::StringPiece* out) {
if (in->length() < length)
return false;
out->set(in->data(), length);
in->remove_prefix(length);
return true;
}
// Reads a length-prefixed variable amount of bytes from |in|, updating |out|
// on success. |prefix_length| indicates the number of bytes needed to represent
// the length.
// The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
bool ReadVariableBytes(size_t prefix_length,
base::StringPiece* in,
base::StringPiece* out) {
size_t length = 0;
if (!ReadLength(prefix_length, in, &length))
return false;
return ReadFixedBytes(length, in, out);
}
// Reads a variable-length list that has been TLS encoded.
// The bytes read from |in| are discarded (i.e. |in|'s prefix removed) // The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
// |max_list_length| contains the overall length of the encoded list. // |max_list_length| contains the overall length of the encoded list.
// |max_item_length| contains the maximum length of a single item. // |max_item_length| contains the maximum length of a single item.
// On success, returns true and updates |*out| with the encoded list. // On success, returns true and updates |*out| with the encoded list.
bool ReadList(size_t max_list_length, bool ReadSCTList(CBS* in, std::vector<base::StringPiece>* out) {
size_t max_item_length,
base::StringPiece* in,
std::vector<base::StringPiece>* out) {
std::vector<base::StringPiece> result; std::vector<base::StringPiece> result;
base::StringPiece list_data; CBS sct_list_data;
if (!ReadVariableBytes(max_list_length, in, &list_data))
if (!CBS_get_u16_length_prefixed(in, &sct_list_data))
return false; return false;
while (!list_data.empty()) { while (CBS_len(&sct_list_data) != 0) {
base::StringPiece list_item; CBS sct_list_item;
if (!ReadVariableBytes(max_item_length, &list_data, &list_item)) { if (!CBS_get_u16_length_prefixed(&sct_list_data, &sct_list_item)) {
DVLOG(1) << "Failed to read item in list."; DVLOG(1) << "Failed to read item in list.";
return false; return false;
} }
if (list_item.empty()) { if (CBS_len(&sct_list_item) == 0) {
DVLOG(1) << "Empty item in list"; DVLOG(1) << "Empty item in list";
return false; return false;
} }
result.push_back(list_item);
result.emplace_back(reinterpret_cast<const char*>(CBS_data(&sct_list_item)),
CBS_len(&sct_list_item));
} }
result.swap(*out); result.swap(*out);
...@@ -195,103 +97,73 @@ bool ConvertSignatureAlgorithm( ...@@ -195,103 +97,73 @@ bool ConvertSignatureAlgorithm(
return true; return true;
} }
// Writes a TLS-encoded variable length unsigned integer to |output|. // Writes a SignedEntryData of type X.509 cert to |*output|.
// |length| indicates the size (in bytes) of the integer. This must be able to
// accomodate |value|.
// |value| the value itself to be written.
void WriteUint(size_t length, uint64_t value, std::string* output) {
// Check that |value| fits into |length| bytes.
DCHECK(length >= sizeof(value) || value >> (length * 8) == 0);
for (; length > 0; --length) {
output->push_back((value >> ((length - 1) * 8)) & 0xFF);
}
}
// Writes an array to |output| from |input|.
// Should be used in one of two cases:
// * The length of |input| has already been encoded into the |output| stream.
// * The length of |input| is fixed and the reader is expected to specify that
// length when reading.
// If the length of |input| is dynamic and data is expected to follow it,
// WriteVariableBytes must be used.
// Returns the number of bytes written (the length of |input|).
size_t WriteEncodedBytes(const base::StringPiece& input, std::string* output) {
input.AppendToString(output);
return input.size();
}
// Writes a variable-length array to |output|.
// |prefix_length| indicates the number of bytes needed to represent the length.
// |input| is the array itself.
// If 1 <= |prefix_length| <= 8 and the size of |input| is less than
// 2^|prefix_length| - 1, encode the length and data and return true.
// Otherwise, return false.
bool WriteVariableBytes(size_t prefix_length,
const base::StringPiece& input,
std::string* output) {
DCHECK_GE(prefix_length, 1u);
DCHECK_LE(prefix_length, 8u);
uint64_t input_size = input.size();
uint64_t max_input_size = (prefix_length == 8)
? UINT64_MAX
: ((UINT64_C(1) << (prefix_length * 8)) - 1);
if (input_size > max_input_size)
return false;
WriteUint(prefix_length, input_size, output);
WriteEncodedBytes(input, output);
return true;
}
// Writes a SignedEntryData of type X.509 cert to |output|.
// |input| is the SignedEntryData containing the certificate. // |input| is the SignedEntryData containing the certificate.
// Returns true if the leaf_certificate in the SignedEntryData does not exceed // Returns true if the leaf_certificate in the SignedEntryData does not exceed
// kMaxAsn1CertificateLength and so can be written to |output|. // kMaxAsn1CertificateLength and so can be written to |output|.
bool EncodeAsn1CertSignedEntry(const SignedEntryData& input, bool EncodeAsn1CertSignedEntry(const SignedEntryData& input, CBB* output) {
std::string* output) { CBB child;
return WriteVariableBytes(kAsn1CertificateLengthBytes, return CBB_add_u24_length_prefixed(output, &child) &&
input.leaf_certificate, output); CBB_add_bytes(
&child,
reinterpret_cast<const uint8_t*>(input.leaf_certificate.data()),
input.leaf_certificate.size()) &&
CBB_flush(output);
} }
// Writes a SignedEntryData of type PreCertificate to |output|. // Writes a SignedEntryData of type PreCertificate to |*output|.
// |input| is the SignedEntryData containing the TBSCertificate and issuer key // |input| is the SignedEntryData containing the TBSCertificate and issuer key
// hash. Returns true if the TBSCertificate component in the SignedEntryData // hash. Returns true if the TBSCertificate component in the SignedEntryData
// does not exceed kMaxTbsCertificateLength and so can be written to |output|. // does not exceed kMaxTbsCertificateLength and so can be written to |output|.
bool EncodePrecertSignedEntry(const SignedEntryData& input, bool EncodePrecertSignedEntry(const SignedEntryData& input, CBB* output) {
std::string* output) { CBB child;
WriteEncodedBytes( return CBB_add_bytes(
base::StringPiece( output,
reinterpret_cast<const char*>(input.issuer_key_hash.data), reinterpret_cast<const uint8_t*>(input.issuer_key_hash.data),
kIssuerKeyHashLength), kLogIdLength) &&
output); CBB_add_u24_length_prefixed(output, &child) &&
return WriteVariableBytes(kTbsCertificateLengthBytes, CBB_add_bytes(
input.tbs_certificate, output); &child,
reinterpret_cast<const uint8_t*>(input.tbs_certificate.data()),
input.tbs_certificate.size()) &&
CBB_flush(output);
} }
} // namespace } // namespace
bool EncodeDigitallySigned(const DigitallySigned& input, CBB* output_cbb) {
CBB child;
return CBB_add_u8(output_cbb, input.hash_algorithm) &&
CBB_add_u8(output_cbb, input.signature_algorithm) &&
CBB_add_u16_length_prefixed(output_cbb, &child) &&
CBB_add_bytes(
&child,
reinterpret_cast<const uint8_t*>(input.signature_data.data()),
input.signature_data.size()) &&
CBB_flush(output_cbb);
}
bool EncodeDigitallySigned(const DigitallySigned& input, bool EncodeDigitallySigned(const DigitallySigned& input,
std::string* output) { std::string* output) {
WriteUint(kHashAlgorithmLength, input.hash_algorithm, output); bssl::ScopedCBB output_cbb;
WriteUint(kSigAlgorithmLength, input.signature_algorithm, if (!CBB_init(output_cbb.get(), 64) ||
output); !EncodeDigitallySigned(input, output_cbb.get()) ||
return WriteVariableBytes(kSignatureLengthBytes, input.signature_data, !CBB_flush(output_cbb.get())) {
output); return false;
}
output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
CBB_len(output_cbb.get()));
return true;
} }
bool DecodeDigitallySigned(base::StringPiece* input, bool DecodeDigitallySigned(CBS* input, DigitallySigned* output) {
DigitallySigned* output) { uint8_t hash_algo;
unsigned hash_algo; uint8_t sig_algo;
unsigned sig_algo; CBS sig_data;
base::StringPiece sig_data;
if (!ReadUint(kHashAlgorithmLength, input, &hash_algo) || if (!CBS_get_u8(input, &hash_algo) || !CBS_get_u8(input, &sig_algo) ||
!ReadUint(kSigAlgorithmLength, input, &sig_algo) || !CBS_get_u16_length_prefixed(input, &sig_data)) {
!ReadVariableBytes(kSignatureLengthBytes, input, &sig_data)) {
return false; return false;
} }
...@@ -304,14 +176,26 @@ bool DecodeDigitallySigned(base::StringPiece* input, ...@@ -304,14 +176,26 @@ bool DecodeDigitallySigned(base::StringPiece* input,
DVLOG(1) << "Invalid signature algorithm " << sig_algo; DVLOG(1) << "Invalid signature algorithm " << sig_algo;
return false; return false;
} }
sig_data.CopyToString(&result.signature_data); result.signature_data.assign(
reinterpret_cast<const char*>(CBS_data(&sig_data)), CBS_len(&sig_data));
*output = result; *output = result;
return true; return true;
} }
bool EncodeSignedEntry(const SignedEntryData& input, std::string* output) { bool DecodeDigitallySigned(base::StringPiece* input, DigitallySigned* output) {
WriteUint(kSignedEntryTypeLength, input.type, output); CBS input_cbs;
CBS_init(&input_cbs, reinterpret_cast<const uint8_t*>(input->data()),
input->size());
bool result = DecodeDigitallySigned(&input_cbs, output);
input->remove_prefix(input->size() - CBS_len(&input_cbs));
return result;
}
static bool EncodeSignedEntry(const SignedEntryData& input, CBB* output) {
if (!CBB_add_u16(output, input.type)) {
return false;
}
switch (input.type) { switch (input.type) {
case SignedEntryData::LOG_ENTRY_TYPE_X509: case SignedEntryData::LOG_ENTRY_TYPE_X509:
return EncodeAsn1CertSignedEntry(input, output); return EncodeAsn1CertSignedEntry(input, output);
...@@ -321,9 +205,23 @@ bool EncodeSignedEntry(const SignedEntryData& input, std::string* output) { ...@@ -321,9 +205,23 @@ bool EncodeSignedEntry(const SignedEntryData& input, std::string* output) {
return false; return false;
} }
static bool ReadTimeSinceEpoch(base::StringPiece* input, base::Time* output) { bool EncodeSignedEntry(const SignedEntryData& input, std::string* output) {
bssl::ScopedCBB output_cbb;
if (!CBB_init(output_cbb.get(), 64) ||
!EncodeSignedEntry(input, output_cbb.get()) ||
!CBB_flush(output_cbb.get())) {
return false;
}
output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
CBB_len(output_cbb.get()));
return true;
}
static bool ReadTimeSinceEpoch(CBS* input, base::Time* output) {
uint64_t time_since_epoch = 0; uint64_t time_since_epoch = 0;
if (!ReadUint(kTimestampLength, input, &time_since_epoch)) if (!CBS_get_u64(input, &time_since_epoch))
return false; return false;
base::CheckedNumeric<int64_t> time_since_epoch_signed = time_since_epoch; base::CheckedNumeric<int64_t> time_since_epoch_signed = time_since_epoch;
...@@ -341,21 +239,28 @@ static bool ReadTimeSinceEpoch(base::StringPiece* input, base::Time* output) { ...@@ -341,21 +239,28 @@ static bool ReadTimeSinceEpoch(base::StringPiece* input, base::Time* output) {
return true; return true;
} }
static void WriteTimeSinceEpoch(const base::Time& timestamp, static bool WriteTimeSinceEpoch(const base::Time& timestamp, CBB* output) {
std::string* output) {
base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch();
WriteUint(kTimestampLength, time_since_epoch.InMilliseconds(), output); return CBB_add_u64(output, time_since_epoch.InMilliseconds());
} }
bool EncodeTreeLeaf(const MerkleTreeLeaf& leaf, std::string* output) { bool EncodeTreeLeaf(const MerkleTreeLeaf& leaf, std::string* output) {
WriteUint(kVersionLength, 0, output); // version: 1 bssl::ScopedCBB output_cbb;
WriteUint(kMerkleLeafTypeLength, 0, output); // type: timestamped entry CBB child;
WriteTimeSinceEpoch(leaf.timestamp, output); if (!CBB_init(output_cbb.get(), 64) ||
if (!EncodeSignedEntry(leaf.signed_entry, output)) !CBB_add_u8(output_cbb.get(), 0) || // version: 1
!CBB_add_u8(output_cbb.get(), 0) || // type: timestamped entry
!WriteTimeSinceEpoch(leaf.timestamp, output_cbb.get()) ||
!EncodeSignedEntry(leaf.signed_entry, output_cbb.get()) ||
!CBB_add_u16_length_prefixed(output_cbb.get(), &child) ||
!CBB_add_bytes(&child,
reinterpret_cast<const uint8_t*>(leaf.extensions.data()),
leaf.extensions.size()) ||
!CBB_flush(output_cbb.get())) {
return false; return false;
if (!WriteVariableBytes(kExtensionsLengthBytes, leaf.extensions, output)) }
return false; output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
CBB_len(output_cbb.get()));
return true; return true;
} }
...@@ -363,38 +268,60 @@ bool EncodeV1SCTSignedData(const base::Time& timestamp, ...@@ -363,38 +268,60 @@ bool EncodeV1SCTSignedData(const base::Time& timestamp,
const std::string& serialized_log_entry, const std::string& serialized_log_entry,
const std::string& extensions, const std::string& extensions,
std::string* output) { std::string* output) {
WriteUint(kVersionLength, SignedCertificateTimestamp::V1, bssl::ScopedCBB output_cbb;
output); CBB child;
WriteUint(kSignatureTypeLength, SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP, if (!CBB_init(output_cbb.get(), 64) ||
output); !CBB_add_u8(output_cbb.get(), SignedCertificateTimestamp::V1) ||
WriteTimeSinceEpoch(timestamp, output); !CBB_add_u8(output_cbb.get(), SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP) ||
!WriteTimeSinceEpoch(timestamp, output_cbb.get()) ||
// NOTE: serialized_log_entry must already be serialized and contain the // NOTE: serialized_log_entry must already be serialized and contain the
// length as the prefix. // length as the prefix.
WriteEncodedBytes(serialized_log_entry, output); !CBB_add_bytes(
return WriteVariableBytes(kExtensionsLengthBytes, extensions, output); output_cbb.get(),
reinterpret_cast<const uint8_t*>(serialized_log_entry.data()),
serialized_log_entry.size()) ||
!CBB_add_u16_length_prefixed(output_cbb.get(), &child) ||
!CBB_add_bytes(&child,
reinterpret_cast<const uint8_t*>(extensions.data()),
extensions.size()) ||
!CBB_flush(output_cbb.get())) {
return false;
}
output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
CBB_len(output_cbb.get()));
return true;
} }
void EncodeTreeHeadSignature(const SignedTreeHead& signed_tree_head, bool EncodeTreeHeadSignature(const SignedTreeHead& signed_tree_head,
std::string* output) { std::string* output) {
WriteUint(kVersionLength, signed_tree_head.version, output); bssl::ScopedCBB output_cbb;
WriteUint(kSignatureTypeLength, TREE_HASH, output); if (!CBB_init(output_cbb.get(), 64) ||
WriteTimeSinceEpoch(signed_tree_head.timestamp, output); !CBB_add_u8(output_cbb.get(), signed_tree_head.version) ||
WriteUint(kTreeSizeLength, signed_tree_head.tree_size, output); !CBB_add_u8(output_cbb.get(), TREE_HASH) ||
WriteEncodedBytes( !WriteTimeSinceEpoch(signed_tree_head.timestamp, output_cbb.get()) ||
base::StringPiece(signed_tree_head.sha256_root_hash, kSthRootHashLength), !CBB_add_u64(output_cbb.get(), signed_tree_head.tree_size) ||
output); !CBB_add_bytes(
output_cbb.get(),
reinterpret_cast<const uint8_t*>(signed_tree_head.sha256_root_hash),
kSthRootHashLength)) {
return false;
}
output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
CBB_len(output_cbb.get()));
return true;
} }
bool DecodeSCTList(base::StringPiece input, bool DecodeSCTList(base::StringPiece input,
std::vector<base::StringPiece>* output) { std::vector<base::StringPiece>* output) {
std::vector<base::StringPiece> result; std::vector<base::StringPiece> result;
if (!ReadList(kSCTListLengthBytes, kSerializedSCTLengthBytes, &input, CBS input_cbs;
&result)) { CBS_init(&input_cbs, reinterpret_cast<const uint8_t*>(input.data()),
input.size());
if (!ReadSCTList(&input_cbs, &result) || CBS_len(&input_cbs) != 0 ||
result.empty()) {
return false; return false;
} }
if (!input.empty() || result.empty())
return false;
output->swap(result); output->swap(result);
return true; return true;
} }
...@@ -404,8 +331,11 @@ bool DecodeSignedCertificateTimestamp( ...@@ -404,8 +331,11 @@ bool DecodeSignedCertificateTimestamp(
scoped_refptr<SignedCertificateTimestamp>* output) { scoped_refptr<SignedCertificateTimestamp>* output) {
scoped_refptr<SignedCertificateTimestamp> result( scoped_refptr<SignedCertificateTimestamp> result(
new SignedCertificateTimestamp()); new SignedCertificateTimestamp());
unsigned version; uint8_t version;
if (!ReadUint(kVersionLength, input, &version)) CBS input_cbs;
CBS_init(&input_cbs, reinterpret_cast<const uint8_t*>(input->data()),
input->size());
if (!CBS_get_u8(&input_cbs, &version))
return false; return false;
if (version != SignedCertificateTimestamp::V1) { if (version != SignedCertificateTimestamp::V1) {
DVLOG(1) << "Unsupported/invalid version " << version; DVLOG(1) << "Unsupported/invalid version " << version;
...@@ -413,42 +343,73 @@ bool DecodeSignedCertificateTimestamp( ...@@ -413,42 +343,73 @@ bool DecodeSignedCertificateTimestamp(
} }
result->version = SignedCertificateTimestamp::V1; result->version = SignedCertificateTimestamp::V1;
base::StringPiece log_id; CBS log_id;
base::StringPiece extensions; CBS extensions;
if (!ReadFixedBytes(kLogIdLength, input, &log_id) || if (!CBS_get_bytes(&input_cbs, &log_id, kLogIdLength) ||
!ReadTimeSinceEpoch(input, &result->timestamp) || !ReadTimeSinceEpoch(&input_cbs, &result->timestamp) ||
!ReadVariableBytes(kExtensionsLengthBytes, input, &extensions) || !CBS_get_u16_length_prefixed(&input_cbs, &extensions) ||
!DecodeDigitallySigned(input, &result->signature)) { !DecodeDigitallySigned(&input_cbs, &result->signature)) {
return false; return false;
} }
log_id.CopyToString(&result->log_id); result->log_id.assign(reinterpret_cast<const char*>(CBS_data(&log_id)),
extensions.CopyToString(&result->extensions); CBS_len(&log_id));
result->extensions.assign(
reinterpret_cast<const char*>(CBS_data(&extensions)),
CBS_len(&extensions));
output->swap(result); output->swap(result);
input->remove_prefix(input->size() - CBS_len(&input_cbs));
return true; return true;
} }
void EncodeSignedCertificateTimestamp( bool EncodeSignedCertificateTimestamp(
const scoped_refptr<ct::SignedCertificateTimestamp>& input, const scoped_refptr<ct::SignedCertificateTimestamp>& input,
std::string* output) { std::string* output) {
// This function only supports serialization of V1 SCTs. // This function only supports serialization of V1 SCTs.
DCHECK_EQ(SignedCertificateTimestamp::V1, input->version); DCHECK_EQ(SignedCertificateTimestamp::V1, input->version);
WriteUint(kVersionLength, input->version, output);
DCHECK_EQ(kLogIdLength, input->log_id.size()); DCHECK_EQ(kLogIdLength, input->log_id.size());
WriteEncodedBytes(
base::StringPiece(reinterpret_cast<const char*>(input->log_id.data()), bssl::ScopedCBB output_cbb;
kLogIdLength), CBB child;
output); if (!CBB_init(output_cbb.get(), 64) ||
WriteTimeSinceEpoch(input->timestamp, output); !CBB_add_u8(output_cbb.get(), input->version) ||
WriteVariableBytes(kExtensionsLengthBytes, input->extensions, output); !CBB_add_bytes(output_cbb.get(),
EncodeDigitallySigned(input->signature, output); reinterpret_cast<const uint8_t*>(input->log_id.data()),
kLogIdLength) ||
!WriteTimeSinceEpoch(input->timestamp, output_cbb.get()) ||
!CBB_add_u16_length_prefixed(output_cbb.get(), &child) ||
!CBB_add_bytes(&child,
reinterpret_cast<const uint8_t*>(input->extensions.data()),
input->extensions.size()) ||
!EncodeDigitallySigned(input->signature, output_cbb.get()) ||
!CBB_flush(output_cbb.get())) {
return false;
}
output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
CBB_len(output_cbb.get()));
return true;
} }
bool EncodeSCTListForTesting(const base::StringPiece& sct, bool EncodeSCTListForTesting(const base::StringPiece& sct,
std::string* output) { std::string* output) {
std::string encoded_sct; bssl::ScopedCBB encoded_sct, output_cbb;
return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && CBB encoded_sct_child, output_child;
WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); if (!CBB_init(encoded_sct.get(), 64) || !CBB_init(output_cbb.get(), 64) ||
!CBB_add_u16_length_prefixed(encoded_sct.get(), &encoded_sct_child) ||
!CBB_add_bytes(&encoded_sct_child,
reinterpret_cast<const uint8_t*>(sct.data()),
sct.size()) ||
!CBB_flush(encoded_sct.get()) ||
!CBB_add_u16_length_prefixed(output_cbb.get(), &output_child) ||
!CBB_add_bytes(&output_child, CBB_data(encoded_sct.get()),
CBB_len(encoded_sct.get())) ||
!CBB_flush(output_cbb.get())) {
return false;
}
output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
CBB_len(output_cbb.get()));
return true;
} }
} // namespace ct } // namespace ct
......
...@@ -64,7 +64,9 @@ NET_EXPORT_PRIVATE bool EncodeV1SCTSignedData( ...@@ -64,7 +64,9 @@ NET_EXPORT_PRIVATE bool EncodeV1SCTSignedData(
// Encodes the data signed by a Signed Tree Head (STH) |signed_tree_head| into // Encodes the data signed by a Signed Tree Head (STH) |signed_tree_head| into
// |output|. The signature included in the |signed_tree_head| can then be // |output|. The signature included in the |signed_tree_head| can then be
// verified over these bytes. // verified over these bytes.
NET_EXPORT_PRIVATE void EncodeTreeHeadSignature( // Returns true if the data could be encoded successfully, false
// otherwise.
NET_EXPORT_PRIVATE bool EncodeTreeHeadSignature(
const SignedTreeHead& signed_tree_head, const SignedTreeHead& signed_tree_head,
std::string* output); std::string* output);
...@@ -86,7 +88,9 @@ NET_EXPORT_PRIVATE bool DecodeSignedCertificateTimestamp( ...@@ -86,7 +88,9 @@ NET_EXPORT_PRIVATE bool DecodeSignedCertificateTimestamp(
scoped_refptr<ct::SignedCertificateTimestamp>* output); scoped_refptr<ct::SignedCertificateTimestamp>* output);
// Serializes a Signed Certificate Timestamp (SCT) into |output|. // Serializes a Signed Certificate Timestamp (SCT) into |output|.
NET_EXPORT void EncodeSignedCertificateTimestamp( // Returns true if the SCT could be encoded successfully, false
// otherwise.
NET_EXPORT bool EncodeSignedCertificateTimestamp(
const scoped_refptr<ct::SignedCertificateTimestamp>& input, const scoped_refptr<ct::SignedCertificateTimestamp>& input,
std::string* output); std::string* output);
......
...@@ -161,7 +161,7 @@ TEST_F(CtSerializationTest, EncodeSignedCertificateTimestamp) { ...@@ -161,7 +161,7 @@ TEST_F(CtSerializationTest, EncodeSignedCertificateTimestamp) {
ASSERT_TRUE(ct::DecodeSignedCertificateTimestamp(&encoded_sct, &sct)); ASSERT_TRUE(ct::DecodeSignedCertificateTimestamp(&encoded_sct, &sct));
std::string serialized; std::string serialized;
ct::EncodeSignedCertificateTimestamp(sct, &serialized); ASSERT_TRUE(ct::EncodeSignedCertificateTimestamp(sct, &serialized));
EXPECT_EQ(serialized, encoded_test_sct); EXPECT_EQ(serialized, encoded_test_sct);
} }
...@@ -256,7 +256,7 @@ TEST_F(CtSerializationTest, EncodesValidSignedTreeHead) { ...@@ -256,7 +256,7 @@ TEST_F(CtSerializationTest, EncodesValidSignedTreeHead) {
ASSERT_TRUE(GetSampleSignedTreeHead(&signed_tree_head)); ASSERT_TRUE(GetSampleSignedTreeHead(&signed_tree_head));
std::string encoded; std::string encoded;
ct::EncodeTreeHeadSignature(signed_tree_head, &encoded); ASSERT_TRUE(ct::EncodeTreeHeadSignature(signed_tree_head, &encoded));
// Expected size is 50 bytes: // Expected size is 50 bytes:
// Byte 0 is version, byte 1 is signature type // Byte 0 is version, byte 1 is signature type
// Bytes 2-9 are timestamp // Bytes 2-9 are timestamp
......
...@@ -79,7 +79,7 @@ std::string SCTOriginToString( ...@@ -79,7 +79,7 @@ std::string SCTOriginToString(
return ""; return "";
} }
void AddSCT(const net::SignedCertificateTimestampAndStatus& sct, bool AddSCT(const net::SignedCertificateTimestampAndStatus& sct,
base::ListValue* list) { base::ListValue* list) {
std::unique_ptr<base::DictionaryValue> list_item(new base::DictionaryValue()); std::unique_ptr<base::DictionaryValue> list_item(new base::DictionaryValue());
// Chrome implements RFC6962, not 6962-bis, so the reports contain v1 SCTs. // Chrome implements RFC6962, not 6962-bis, so the reports contain v1 SCTs.
...@@ -102,11 +102,13 @@ void AddSCT(const net::SignedCertificateTimestampAndStatus& sct, ...@@ -102,11 +102,13 @@ void AddSCT(const net::SignedCertificateTimestampAndStatus& sct,
list_item->SetString("status", status); list_item->SetString("status", status);
list_item->SetString("source", SCTOriginToString(sct.sct->origin)); list_item->SetString("source", SCTOriginToString(sct.sct->origin));
std::string serialized_sct; std::string serialized_sct;
net::ct::EncodeSignedCertificateTimestamp(sct.sct, &serialized_sct); if (!net::ct::EncodeSignedCertificateTimestamp(sct.sct, &serialized_sct))
return false;
std::string encoded_serialized_sct; std::string encoded_serialized_sct;
base::Base64Encode(serialized_sct, &encoded_serialized_sct); base::Base64Encode(serialized_sct, &encoded_serialized_sct);
list_item->SetString("serialized_sct", encoded_serialized_sct); list_item->SetString("serialized_sct", encoded_serialized_sct);
list->Append(std::move(list_item)); list->Append(std::move(list_item));
return true;
} }
constexpr net::NetworkTrafficAnnotationTag kExpectCTReporterTrafficAnnotation = constexpr net::NetworkTrafficAnnotationTag kExpectCTReporterTrafficAnnotation =
...@@ -176,7 +178,8 @@ void ExpectCTReporter::OnExpectCTFailed( ...@@ -176,7 +178,8 @@ void ExpectCTReporter::OnExpectCTFailed(
std::unique_ptr<base::ListValue> scts(new base::ListValue()); std::unique_ptr<base::ListValue> scts(new base::ListValue());
for (const auto& sct_and_status : signed_certificate_timestamps) { for (const auto& sct_and_status : signed_certificate_timestamps) {
AddSCT(sct_and_status, scts.get()); if (!AddSCT(sct_and_status, scts.get()))
LOG(ERROR) << "Failed to add signed certificate timestamp to list";
} }
report->Set("scts", std::move(scts)); report->Set("scts", std::move(scts));
......
...@@ -150,8 +150,10 @@ net::ct::SignedCertificateTimestamp::Origin SCTOriginStringToOrigin( ...@@ -150,8 +150,10 @@ net::ct::SignedCertificateTimestamp::Origin SCTOriginStringToOrigin(
net::ct::SCTVerifyStatus expected_status, net::ct::SCTVerifyStatus expected_status,
const base::ListValue& report_list) { const base::ListValue& report_list) {
std::string expected_serialized_sct; std::string expected_serialized_sct;
net::ct::EncodeSignedCertificateTimestamp(expected_sct, if (!net::ct::EncodeSignedCertificateTimestamp(expected_sct,
&expected_serialized_sct); &expected_serialized_sct)) {
return ::testing::AssertionFailure() << "Failed to serialize SCT";
}
for (size_t i = 0; i < report_list.GetSize(); i++) { for (size_t i = 0; i < report_list.GetSize(); i++) {
const base::DictionaryValue* report_sct; const base::DictionaryValue* report_sct;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment