Skip to content

Commit

Permalink
Merge branch 'main' into mku-abs
Browse files Browse the repository at this point in the history
  • Loading branch information
heidihoward authored Sep 20, 2024
2 parents b84a6e0 + 187d469 commit 185a4b4
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 8 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

- SGX Platform support.

### Added

- Provided API for getting COSE signatures and Merkle proofs (#6477).
- Exposed COSE signature in historical API via `TxReceiptImpl`.
- Introduced `ccf::describe_merkle_proof_v1(receipt)` for Merkle proof construction in CBOR format.
- Added COSE signatures over the Merkle root to the KV (#6449).
- Signing is done with service key (different from raw signatures, which remain unchanged and are still signed by the node key).
- New signature reside in `public:ccf.internal.cose_signatures`.

## [5.0.4]

[5.0.4]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.4
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,7 @@ if(BUILD_TESTS)
)
target_link_libraries(
historical_queries_test PRIVATE http_parser.host sss.host ccf_kv.host
ccf_endpoints.host
)
# Temporarily disabled flaky test
# https://github.com/microsoft/CCF/issues/4403 add_unit_test( indexing_test
Expand Down
10 changes: 10 additions & 0 deletions include/ccf/receipt.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ namespace ccf
nlohmann::json describe_receipt_v1(const TxReceiptImpl& receipt);
ReceiptPtr describe_receipt_v2(const TxReceiptImpl& receipt);

enum MerkleProofLabel : int64_t
{
// Values TBD:
// https://github.com/ietf-scitt/draft-birkholz-cose-cometre-ccf-profile
MERKLE_PROOF_LEAF_LABEL = 404,
MERKLE_PROOF_PATH_LABEL = 405
};
std::optional<std::vector<uint8_t>> describe_merkle_proof_v1(
const TxReceiptImpl& in);

// Manual JSON serializers are specified for these types as they are not
// trivial POD structs

Expand Down
19 changes: 12 additions & 7 deletions src/crypto/openssl/cose_sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ namespace
QCBOREncodeContext* cbor_encode,
const std::vector<ccf::crypto::COSEParametersFactory>& protected_headers)
{
QCBOREncode_AddTag(cbor_encode, CBOR_TAG_COSE_SIGN1);
QCBOREncode_OpenArray(cbor_encode);

encode_protected_headers(me, cbor_encode, protected_headers);

QCBOREncode_OpenMap(cbor_encode);
Expand Down Expand Up @@ -164,7 +161,8 @@ namespace ccf::crypto
std::span<const uint8_t> payload)
{
const auto buf_size = estimate_buffer_size(protected_headers, payload);
Q_USEFUL_BUF_MAKE_STACK_UB(signed_cose_buffer, buf_size);
std::vector<uint8_t> underlying_buffer(buf_size);
q_useful_buf signed_cose_buffer{underlying_buffer.data(), buf_size};

QCBOREncodeContext cbor_encode;
QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
Expand All @@ -185,6 +183,9 @@ namespace ccf::crypto

t_cose_sign1_set_signing_key(&sign_ctx, signing_key, NULL_Q_USEFUL_BUF_C);

QCBOREncode_AddTag(&cbor_encode, CBOR_TAG_COSE_SIGN1);
QCBOREncode_OpenArray(&cbor_encode);

encode_parameters_custom(&sign_ctx, &cbor_encode, protected_headers);

// Mark empty payload manually.
Expand Down Expand Up @@ -216,8 +217,12 @@ namespace ccf::crypto
fmt::format("Can't finish QCBOR encoding with error code {}", err));
}

return {
static_cast<const uint8_t*>(signed_cose.ptr),
static_cast<const uint8_t*>(signed_cose.ptr) + signed_cose.len};
// Memory address is said to match:
// github.com/laurencelundblade/QCBOR/blob/v1.4.1/inc/qcbor/qcbor_encode.h#L2190-L2191
assert(signed_cose.ptr == underlying_buffer.data());

underlying_buffer.resize(signed_cose.len);
underlying_buffer.shrink_to_fit();
return underlying_buffer;
}
}
13 changes: 12 additions & 1 deletion src/node/historical_queries.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ namespace ccf::historical
return signatures->get();
}

static std::optional<ccf::CoseSignature> get_cose_signature(
const ccf::kv::StorePtr& sig_store)
{
auto tx = sig_store->create_read_only_tx();
auto signatures = tx.ro<ccf::CoseSignatures>(ccf::Tables::COSE_SIGNATURES);
return signatures->get();
}

static std::optional<std::vector<uint8_t>> get_tree(
const ccf::kv::StorePtr& sig_store)
{
Expand Down Expand Up @@ -430,6 +438,7 @@ namespace ccf::historical
// Iterate through earlier indices. If this signature covers them
// then create a receipt for them
const auto sig = get_signature(sig_details->store);
const auto cose_sig = get_cose_signature(sig_details->store);
ccf::MerkleTreeHistory tree(get_tree(sig_details->store).value());

// This is either pointing at the sig itself, or the closest larger
Expand All @@ -453,6 +462,7 @@ namespace ccf::historical
details->transaction_id = {sig->view, seqno};
details->receipt = std::make_shared<TxReceiptImpl>(
sig->sig,
cose_sig,
proof.get_root(),
proof.get_path(),
sig->node,
Expand Down Expand Up @@ -735,10 +745,11 @@ namespace ccf::historical
// the receipt _later_ for an already-fetched signature
// transaction.
const auto sig = get_signature(details->store);
const auto cose_sig = get_cose_signature(details->store);
assert(sig.has_value());
details->transaction_id = {sig->view, sig->seqno};
details->receipt = std::make_shared<TxReceiptImpl>(
sig->sig, sig->root.h, nullptr, sig->node, sig->cert);
sig->sig, cose_sig, sig->root.h, nullptr, sig->node, sig->cert);
}

auto request_it = requests.begin();
Expand Down
97 changes: 97 additions & 0 deletions src/node/historical_queries_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,51 @@
#include "node/rpc/network_identity_subsystem.h"
#include "node/tx_receipt_impl.h"

#include <t_cose/t_cose_sign1_sign.h>

namespace
{
void encode_leaf_cbor(
QCBOREncodeContext& ctx, const ccf::TxReceiptImpl& receipt)
{
QCBOREncode_OpenArrayInMapN(
&ctx, ccf::MerkleProofLabel::MERKLE_PROOF_LEAF_LABEL);

// 1 WSD
const auto& wsd = receipt.write_set_digest->h;
QCBOREncode_AddBytes(&ctx, {wsd.data(), wsd.size()});

// 2. CE
const auto& ce = receipt.commit_evidence.value();
QCBOREncode_AddSZString(&ctx, ce.data());

// 3. CD
const auto& cd = receipt.claims_digest.value().h;
QCBOREncode_AddBytes(&ctx, {cd.data(), cd.size()});

QCBOREncode_CloseArray(&ctx);
}

void encode_path_cbor(
QCBOREncodeContext& ctx, const ccf::HistoryTree::Path& path)
{
QCBOREncode_OpenArrayInMapN(
&ctx, ccf::MerkleProofLabel::MERKLE_PROOF_PATH_LABEL);
for (const auto& node : path)
{
const int64_t dir =
(node.direction == ccf::HistoryTree::Path::Direction::PATH_LEFT);
std::vector<uint8_t> hash{node.hash};

QCBOREncode_OpenArray(&ctx);
QCBOREncode_AddInt64(&ctx, dir);
QCBOREncode_AddBytes(&ctx, {hash.data(), hash.size()});
QCBOREncode_CloseArray(&ctx);
}
QCBOREncode_CloseArray(&ctx);
}
}

namespace ccf
{
nlohmann::json describe_receipt_v1(const TxReceiptImpl& receipt)
Expand Down Expand Up @@ -153,6 +198,58 @@ namespace ccf

return receipt;
}

std::optional<std::vector<uint8_t>> describe_merkle_proof_v1(
const TxReceiptImpl& receipt)
{
constexpr size_t buf_size = 2048;
std::vector<uint8_t> underlying_buffer(buf_size);
q_useful_buf buffer{underlying_buffer.data(), buf_size};

QCBOREncodeContext ctx;
QCBOREncode_Init(&ctx, buffer);

QCBOREncode_BstrWrap(&ctx);
QCBOREncode_OpenMap(&ctx);

if (!receipt.commit_evidence)
{
LOG_DEBUG_FMT("Merkle proof is missing commit evidence");
return std::nullopt;
}
if (!receipt.write_set_digest)
{
LOG_DEBUG_FMT("Merkle proof is missing write set digest");
return std::nullopt;
}
encode_leaf_cbor(ctx, receipt);

if (!receipt.path)
{
LOG_DEBUG_FMT("Merkle proof is missing path");
return std::nullopt;
}
encode_path_cbor(ctx, *receipt.path);

QCBOREncode_CloseMap(&ctx);
QCBOREncode_CloseBstrWrap2(&ctx, false, nullptr);

struct q_useful_buf_c result;
auto qerr = QCBOREncode_Finish(&ctx, &result);
if (qerr)
{
LOG_DEBUG_FMT("Failed to encode merkle proof: {}", qerr);
return std::nullopt;
}

// Memory address is said to match:
// github.com/laurencelundblade/QCBOR/blob/v1.4.1/inc/qcbor/qcbor_encode.h#L2190-L2191
assert(result.ptr == underlying_buffer.data());

underlying_buffer.resize(result.len);
underlying_buffer.shrink_to_fit();
return underlying_buffer;
}
}

namespace ccf::historical
Expand Down
1 change: 1 addition & 0 deletions src/node/snapshot_serdes.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ namespace ccf
cd.set(std::move(claims_digest));
ccf::TxReceiptImpl tx_receipt(
sig,
std::nullopt, // cose
proof.get_root(),
proof.get_path(),
node_id,
Expand Down
Loading

0 comments on commit 185a4b4

Please sign in to comment.