Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7de3dd0
COSE signatures now service map
maxtropets Sep 9, 2026
b7d6a5b
Fixup build
maxtropets Sep 10, 2026
6771a0d
Clang tidy
maxtropets Sep 10, 2026
ec2d308
Merge branch 'main' into f/multisign-part-3
maxtropets Sep 10, 2026
ad3d58c
Clang tidy!
maxtropets Sep 10, 2026
6a7a6a0
Merge branch 'f/multisign-part-3' of https://github.com/maxtropets/CC…
maxtropets Sep 10, 2026
22cabb9
Merge branch 'main' into f/multisign-part-3
maxtropets Sep 10, 2026
06f0b71
Merge branch 'main' into f/multisign-part-3
achamayou Sep 11, 2026
708e3c8
Validate the Lean disaster recovery model against Stateright (#8279)
achamayou Sep 11, 2026
6a33609
Remove the superseded Stateright disaster recovery model (#8280)
achamayou Sep 11, 2026
34c54c9
Fix HTTP/1.1 request-target size handling and add configuration (#8333)
eddyashton Sep 11, 2026
1d4aedf
Apply batched suggestions from code review
achamayou Sep 11, 2026
5bcca65
Fix delayed task clock ordering (#8337)
achamayou Sep 11, 2026
c0b8a3b
Fix race condition in HistoricalExtension with request-scoped instanc…
eddyashton Sep 11, 2026
47213ec
Always release the value passed to JSWrappedValue::set on failure (#8…
achamayou Sep 11, 2026
b8f3cf9
Use TAV for SNP attestation verification (#8083)
cjen1-msft Sep 11, 2026
b9c429b
Avoid races when copying ledger chunks in cleanup tests (#8343)
achamayou Sep 11, 2026
f286a3f
Fix changelog issues for version 7.0.15 and update version to 7.0.16 …
eddyashton Sep 12, 2026
969f475
Scrub native private-key copies in JS crypto bindings (#8354)
achamayou Sep 12, 2026
dd43ae8
Resolve conflicts between PR #8334 and main
achamayou Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ File: `codeql-analysis.yml`

# Continuous Verification

Runs the standard model checking, simulation, trace validation, counterexample, and disaster recovery jobs each week.
Runs the standard model checking, simulation, trace validation, and counterexample jobs each week.

File: `ci-verification.yml`
3rd party dependencies: None
Expand Down
22 changes: 0 additions & 22 deletions .github/workflows/ci-verification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -242,25 +242,3 @@ jobs:
name: tlc-trace-validation-consensus
path: |
tla/traces/*

model-checking-self-healing-open:
name: Model Checking - Self-Healing Open
runs-on: [self-hosted, 1ES.Pool=gha-vmss-d16av6-ci]
container:
image: mcr.microsoft.com/azurelinux/base/core:3.0
options: --user root --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_PTRACE

steps:
- name: "Checkout dependencies"
shell: bash
run: |
gpg --import /etc/pki/rpm-gpg/MICROSOFT-RPM-GPG-KEY
tdnf -y update
tdnf -y install ca-certificates git

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Stateright dependencies
run: |
tdnf install -y cargo

- run: cd tla/disaster-recovery && cargo run check
27 changes: 22 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [7.0.16]

[7.0.16]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.16

### Changed

- HTTP/1.x request targets, including query strings, are now bounded before accumulation by a new `max_request_target_size` setting (16 KB by default), independent of `max_header_size`. Oversized targets return HTTP 414 `RequestTargetTooLong`, increment the per-interface `request_target_too_long` error metric, and close the session. HTTP/2 limits are unchanged (#8333).

### Fixed

- Temporary native PEM buffers, string copies, private JWK fields and JSON values owned by the `ccf.crypto.generateRsaKeyPair`, `ccf.crypto.generateEcdsaKeyPair`, `ccf.crypto.generateEddsaKeyPair`, `ccf.crypto.pemToJwk` (and its RSA/EdDSA variants), `ccf.crypto.jwkToPem` (and its RSA/EdDSA variants), and `ccf.crypto.sign` bindings are now scrubbed on scope exit. Previously these copies were scrubbed only on success or not at all. JavaScript-owned strings and internal library temporaries are not covered by this change (#8354).
- Fixed a double free when setting a property on a JavaScript object fails, which application script could trigger while the request object was being built. Such failures are now reported as a failed request (#8356).
- Historical states retrieved by JavaScript endpoints, through `ccf.historicalState` or `ccf.historical.getStateRange`, remain available through response conversion and are released when the request completes, rather than being retained for the lifetime of the node (#8355).
- JavaScript `verifySnpAttestation()` and the deprecated C++ `ccf::pal::snp::Attestation` returned swapped `current_minor` and `current_build` values. Both now match the AMD SEV-SNP report layout, with `current_build` at offset `0x1E8` and `current_minor` at `0x1E9` (#8083).

### Changed

- SNP attestation reports are now parsed and verified through TAV. Decode a report with `ccf::pal::snp::parse_attestation_report_unverified()`, which returns `ccf::pal::snp::AttestationReport`, an owning smart pointer, and verify it against TAV and CCF's policy with `ccf::pal::verify_snp_attestation_report_and_get()`. Field accessors borrow the report's storage, so destroying or replacing the owner invalidates them. The packed `ccf::pal::snp::Attestation` wire-layout type and its accessors still work, but are deprecated (#8083).
- `ccf::pal::snp::get_attestation()` in `ccf/pal/snp_ioctl.h` is unchanged, but its `get()` accessor is deprecated. Call `get_raw()` instead for the unverified report bytes, then decode them with `parse_attestation_report_unverified()` (#8083).

## [7.0.15]

[7.0.15]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.15
Expand All @@ -23,6 +43,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Reaching the soft session cap on an unsecured RPC interface no longer terminates the node by attempting a TLS handshake without a certificate. (#8331)
- Transactions from an earlier view are now rejected before entering the replication queue even after the node has stepped down. This prevents rolled-back writes from being replicated after a later election and blocking subsequent replication (#8293, #8295).
- Nodes now retain a peer's reconnect address even when an incoming node-to-node channel was established before its Raft configuration was applied. Previously, losing that connection could prevent outbound consensus messages from reaching the peer and stall elections (#8336).
- Transactions with pending writes now correctly validate `foreach`, `size`, and `clear` observations of an existing empty KV table made at revision zero. Previously, these observations could be mistaken for no whole-map read dependency (#8320).
- The OpenAPI schema for `GET /node/consensus` and `GET /node/network` now correctly marks `details.primary_id` and `primary_id` as nullable, matching their `null` value while no primary is known (e.g. between elections). Previously the schema required a non-null string, causing spurious response validation failures (#8344).

### Changed

Expand All @@ -33,11 +55,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

- Removed the exported `evercbor` CMake target and installed `libevercbor.a` library. Applications using CCF's public APIs that explicitly depend on this target or link this library directly must remove that dependency. No further build changes are necessary: the replacement CBOR implementation is linked transitively by CCF (#8297).

### Fixed

- Transactions with pending writes now correctly validate `foreach`, `size`, and `clear` observations of an existing empty KV table made at revision zero. Previously, these observations could be mistaken for no whole-map read dependency (#8320).
- The OpenAPI schema for `GET /node/consensus` and `GET /node/network` now correctly marks `details.primary_id` and `primary_id` as nullable, matching their `null` value while no primary is known (e.g. between elections). Previously the schema required a non-null string, causing spurious response validation failures (#8344).

## [7.0.14]

[7.0.14]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.14
Expand Down
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ add_ccf_static_library(
SRCS ${CCF_DIR}/src/pal/attestation.cpp
LINK_LIBS ccfcrypto
)
target_include_directories(
ccf_pal
PRIVATE ${CCF_DIR}/3rdparty/internal/tee-attestation-verification/ffi/include
)

# CCF js lib
add_ccf_static_library(
Expand Down Expand Up @@ -510,6 +514,11 @@ install(
PATTERN "*.inc"
)

install(
FILES ${TAV_INCLUDE_DIR}/tav/snp.h ${TAV_INCLUDE_DIR}/tav/utils.h
DESTINATION include/3rdparty/tav
)

# Install all private CCF headers, which may still be needed
install(
DIRECTORY src/
Expand Down Expand Up @@ -598,6 +607,7 @@ if(BUILD_TESTS)
snp_ioctl_test
${CMAKE_CURRENT_SOURCE_DIR}/src/pal/test/snp_ioctl_test.cpp
)
target_link_libraries(snp_ioctl_test PRIVATE ccf_pal)
set_property(TEST snp_ioctl_test APPEND PROPERTY LABELS snp)
set_property(TEST snp_ioctl_test APPEND PROPERTY CONFIGURATIONS snp)

Expand Down
19 changes: 19 additions & 0 deletions cmake/ccf_rs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,29 @@ add_custom_target(
"${CCF_RS_DIR}/rust-toolchain.toml"
"${CCF_DIR}/src/cose/cose_rs/Cargo.toml"
"${CCF_DIR}/3rdparty/internal/cose-openssl/Cargo.toml"
"${CCF_DIR}/3rdparty/internal/tee-attestation-verification/ffi/Cargo.toml"
COMMENT
"Building ${CCF_RS_PACKAGE} Rust static library (Cargo profile: ${CCF_RS_CARGO_PROFILE_NAME})"
USES_TERMINAL
VERBATIM
)

add_library(ccf_rs INTERFACE)
target_link_libraries(
ccf_rs
INTERFACE
$<BUILD_INTERFACE:${CCF_RS_LIB_BUILD_PATH}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/lib/${CCF_RS_LIB}>
ssl
crypto
)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(
ccf_rs
INTERFACE ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} m
)
endif()
add_dependencies(ccf_rs cargo-build_ccf_rs)

install(FILES "${CCF_RS_LIB_BUILD_PATH}" DESTINATION lib)
install(TARGETS ccf_rs EXPORT ccf)
8 changes: 1 addition & 7 deletions cmake/crypto.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,7 @@ add_hardening(ccfcrypto)
add_tidy(ccfcrypto)

target_link_libraries(ccfcrypto PUBLIC crypto ssl ccf_threading)
target_link_libraries(
ccfcrypto
PUBLIC
$<BUILD_INTERFACE:${CCF_RS_LIB_BUILD_PATH}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/lib/${CCF_RS_LIB}>
)
add_dependencies(ccfcrypto cargo-build_ccf_rs)
target_link_libraries(ccfcrypto PUBLIC ccf_rs)
set_property(TARGET ccfcrypto PROPERTY POSITION_INDEPENDENT_CODE ON)

install(TARGETS ccfcrypto EXPORT ccf DESTINATION lib)
6 changes: 3 additions & 3 deletions doc/audit/builtin_maps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -494,11 +494,11 @@ Signatures emitted by the primary node at regular interval, over the root of the
``cose_signatures``
~~~~~~~~~~~~~~~~~~~

COSE signatures emitted by the primary node over the root of the Merkle Tree at that sequence number.
COSE signatures over the Merkle root, keyed by service signing identity type.

**Key** Sentinel value 0, represented as a little-endian 64-bit unsigned integer.
**Key** Identity type as a little-endian 64-bit unsigned integer. Only ``CLASSICAL`` (0) is currently populated; ``PQ`` (1) is reserved for future support.

**Value** Raw COSE Sign1 message as byte string (DER-encoded). Implements the following :ccf_repo:`CDDL schema </cddl/ccf-merkle-tree-cose-signature.cddl>`.
**Value** A CBOR-encoded COSE Sign1 message, stored as a base64-encoded JSON string. Implements the following :ccf_repo:`CDDL schema </cddl/ccf-merkle-tree-cose-signature.cddl>`.

``recovery_shares``
~~~~~~~~~~~~~~~~~~~
Expand Down
5 changes: 5 additions & 0 deletions doc/host_config_schema/host_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
"default": "16KB",
"description": "Maximum size (size string) of a single HTTP request header (key or value). Submitting a request with a header larger than this value will result in the client session being automatically closed"
},
"max_request_target_size": {
"type": "string",
"default": "16KB",
"description": "HTTP/1.x only. Maximum size (size string) of a single HTTP request target, including the query string. Submitting a request with a target larger than this value will result in the client session being automatically closed"
},
"max_headers_count": {
"type": "integer",
"default": 256,
Expand Down
11 changes: 9 additions & 2 deletions doc/schemas/node_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,9 @@
},
"max_headers_count": {
"$ref": "#/components/schemas/uint32"
},
"max_request_target_size": {
"$ref": "#/components/schemas/SizeString"
}
},
"type": "object"
Expand Down Expand Up @@ -828,12 +831,16 @@
},
"request_payload_too_large": {
"$ref": "#/components/schemas/uint64"
},
"request_target_too_long": {
"$ref": "#/components/schemas/uint64"
}
},
"required": [
"parsing",
"request_payload_too_large",
"request_header_too_large"
"request_header_too_large",
"request_target_too_long"
],
"type": "object"
},
Expand Down Expand Up @@ -963,7 +970,7 @@
"info": {
"description": "This API provides public, uncredentialed access to service and node state.",
"title": "CCF Public Node API",
"version": "5.0.7"
"version": "5.0.8"
},
"openapi": "3.0.0",
"paths": {
Expand Down
6 changes: 6 additions & 0 deletions include/ccf/http_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace ccf::http
// requests that are too large.
static const ccf::ds::SizeString default_max_body_size = {"1MB"};
static const ccf::ds::SizeString default_max_header_size = {"16KB"};
static const ccf::ds::SizeString default_max_request_target_size = {"16KB"};
static const uint32_t default_max_headers_count = 256;

// HTTP/2 only, as per nghttp2 defaults
Expand All @@ -26,6 +27,9 @@ namespace ccf::http
std::optional<ccf::ds::SizeString> max_header_size = std::nullopt;
std::optional<uint32_t> max_headers_count = std::nullopt;

// HTTP/1.x only, including the query string.
std::optional<ccf::ds::SizeString> max_request_target_size = std::nullopt;

// HTTP/2 only
std::optional<size_t> max_concurrent_streams_count = std::nullopt;
std::optional<ccf::ds::SizeString> initial_window_size = std::nullopt;
Expand All @@ -42,6 +46,7 @@ namespace ccf::http
max_body_size,
max_header_size,
max_headers_count,
max_request_target_size,
max_concurrent_streams_count,
initial_window_size,
max_frame_size);
Expand All @@ -53,6 +58,7 @@ namespace ccf::http
ParserConfiguration config;
config.max_body_size = "1GB";
config.max_header_size = "100MB";
config.max_request_target_size = "100MB";
config.max_headers_count = 1024;
config.max_concurrent_streams_count = 1;
config.initial_window_size = "64KB";
Expand Down
7 changes: 7 additions & 0 deletions include/ccf/node/quote.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ namespace ccf

static std::optional<HostData> get_host_data(const QuoteInfo& quote_info);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
[[deprecated("Use get_snp_attestation_report")]]
static std::optional<pal::snp::Attestation> get_snp_attestation(
const QuoteInfo& quote_info);
#pragma GCC diagnostic pop

static std::optional<pal::snp::AttestationReport>
get_snp_attestation_report(const QuoteInfo& quote_info);

static QuoteVerificationResult verify_quote_against_store(
ccf::kv::ReadOnlyTx& tx,
Expand Down
1 change: 1 addition & 0 deletions include/ccf/odata_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ namespace ccf
ERROR(UnsupportedHttpVerb)
ERROR(UnsupportedContentType)
ERROR(RequestBodyTooLarge)
ERROR(RequestTargetTooLong)
ERROR(RequestHeaderTooLarge)
ERROR(PreconditionFailed)

Expand Down
7 changes: 7 additions & 0 deletions include/ccf/pal/attestation.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include "ccf/ds/quote_info.h"
#include "ccf/pal/attestation_sev_snp.h"
#include "ccf/pal/attestation_sev_snp_endorsements.h"
#include "ccf/pal/measurement.h"
#include "ccf/pal/report_data.h"
Expand All @@ -28,6 +29,12 @@ namespace ccf::pal
PlatformAttestationMeasurement& measurement,
PlatformAttestationReportData& report_data);

/// Verify with TAV, then enforce CCF's SNP attestation policy.
snp::AttestationReport verify_snp_attestation_report_and_get(
const QuoteInfo& quote_info,
PlatformAttestationMeasurement& measurement,
PlatformAttestationReportData& report_data);

void verify_quote(
const QuoteInfo& quote_info,
PlatformAttestationMeasurement& measurement,
Expand Down
Loading