Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions crates/attestation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ tee-verifier-interface = { workspace = true, features = ["serde"] }
thiserror = { workspace = true }

[dev-dependencies]
assert_matches = { workspace = true }
attestation = { path = ".", features = [
"local-verify",
"test-utils",
Expand All @@ -41,9 +40,5 @@ test-utils = { workspace = true }
name = "app_compose"
required-features = ["dstack-conversions"]

[[test]]
name = "collateral"
required-features = ["test-utils"]

[lints]
workspace = true
67 changes: 0 additions & 67 deletions crates/attestation/src/collateral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,4 @@
//!
//! [`Collateral`] is re-exported from `tee-verifier-interface`, not redefined,
//! so it has a single canonical definition.
//!
//! The `test-utils` JSON parser below lives here, not in the wire crate:
//! `tee-verifier-interface` is Borsh-only on the cross-contract call, so
//! adding `serde_json` + `hex` there would bloat every consumer's WASM. The
//! only place collateral exists as JSON is off-chain test fixtures.
pub use tee_verifier_interface::Collateral;

#[cfg(feature = "test-utils")]
pub use parse::{CollateralError, collateral_from_json, collateral_from_str};

#[cfg(feature = "test-utils")]
mod parse {
use super::Collateral;
use alloc::{string::String, vec::Vec};
use hex::FromHexError;
use serde_json::Value;
use thiserror::Error;

pub fn collateral_from_json(v: Value) -> Result<Collateral, CollateralError> {
fn get_str(v: &Value, key: &str) -> Result<String, CollateralError> {
v.get(key)
.and_then(Value::as_str)
.map(String::from)
.ok_or_else(|| CollateralError::MissingField(String::from(key)))
}

fn get_hex(v: &Value, key: &str) -> Result<Vec<u8>, CollateralError> {
let hex_str = get_str(v, key)?;
hex::decode(hex_str).map_err(|source| CollateralError::HexDecode {
field: String::from(key),
source,
})
}

Ok(Collateral {
pck_crl_issuer_chain: get_str(&v, "pck_crl_issuer_chain")?,
root_ca_crl: get_hex(&v, "root_ca_crl")?,
pck_crl: get_hex(&v, "pck_crl")?,
tcb_info_issuer_chain: get_str(&v, "tcb_info_issuer_chain")?,
tcb_info: get_str(&v, "tcb_info")?,
tcb_info_signature: get_hex(&v, "tcb_info_signature")?,
qe_identity_issuer_chain: get_str(&v, "qe_identity_issuer_chain")?,
qe_identity: get_str(&v, "qe_identity")?,
qe_identity_signature: get_hex(&v, "qe_identity_signature")?,
pck_certificate_chain: get_str(&v, "pck_certificate_chain").ok(),
})
}

pub fn collateral_from_str(s: &str) -> Result<Collateral, CollateralError> {
let json_value: Value =
serde_json::from_str(s).map_err(|_| CollateralError::InvalidJson)?;
collateral_from_json(json_value)
}

#[derive(Debug, Error)]
pub enum CollateralError {
#[error("Missing or invalid field: {0}")]
MissingField(String),
#[error("Failed to decode hex field '{field}': {source}")]
HexDecode {
field: String,
#[source]
source: FromHexError,
},
#[error("Invalid JSON format")]
InvalidJson,
}
}
91 changes: 0 additions & 91 deletions crates/attestation/tests/collateral.rs

This file was deleted.

7 changes: 1 addition & 6 deletions crates/tee-authority/src/tee_authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1117,12 +1117,7 @@ mod tests {
/// fresh for the JSON-field tests; the dedicated CRL-staleness tests
/// drive their own `now` past the window.
fn fixture_pck_crl() -> Vec<u8> {
let collateral_json = test_utils::attestation::collateral();
let hex_str = collateral_json
.get("pck_crl")
.and_then(|v| v.as_str())
.expect("test fixture has pck_crl");
hex::decode(hex_str).expect("test fixture pck_crl is valid hex")
test_utils::attestation::collateral().pck_crl
}

/// Build a [`Collateral`] with synthetic `tcb_info` / `qe_identity` JSON
Expand Down
37 changes: 7 additions & 30 deletions crates/tee-verifier/tests/verify_quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,10 @@ use near_sdk::{test_utils::VMContextBuilder, testing_env};
use std::time::Duration;
use tee_verifier::TeeVerifier;
use tee_verifier_interface::{
Collateral, QuoteBytes, Report, TDReport10, TcbStatus, TcbStatusWithAdvisory,
VerificationResult, VerifiedReport, VerifierError,
QuoteBytes, Report, TDReport10, TcbStatus, TcbStatusWithAdvisory, VerificationResult,
VerifiedReport, VerifierError,
};
use test_utils::attestation::{VALID_ATTESTATION_TIMESTAMP, collateral as collateral_json, quote};

fn make_collateral() -> Collateral {
// `test_utils::attestation::collateral()` returns a `serde_json::Value`
// matching `attestation::Collateral`'s JSON shape. We re-parse it
// into the interface crate's mirror type by extracting the same
// field names that `dcap_qvl::QuoteCollateralV3` uses.
let v = collateral_json();
Collateral {
pck_crl_issuer_chain: v["pck_crl_issuer_chain"].as_str().unwrap().to_string(),
root_ca_crl: hex::decode(v["root_ca_crl"].as_str().unwrap()).unwrap(),
pck_crl: hex::decode(v["pck_crl"].as_str().unwrap()).unwrap(),
tcb_info_issuer_chain: v["tcb_info_issuer_chain"].as_str().unwrap().to_string(),
tcb_info: v["tcb_info"].as_str().unwrap().to_string(),
tcb_info_signature: hex::decode(v["tcb_info_signature"].as_str().unwrap()).unwrap(),
qe_identity_issuer_chain: v["qe_identity_issuer_chain"].as_str().unwrap().to_string(),
qe_identity: v["qe_identity"].as_str().unwrap().to_string(),
qe_identity_signature: hex::decode(v["qe_identity_signature"].as_str().unwrap()).unwrap(),
pck_certificate_chain: v
.get("pck_certificate_chain")
.and_then(|s| s.as_str())
.map(str::to_string),
}
}
use test_utils::attestation::{VALID_ATTESTATION_TIMESTAMP, collateral, quote};

fn make_quote_bytes() -> QuoteBytes {
QuoteBytes(Vec::from(quote()))
Expand All @@ -66,7 +43,7 @@ fn verify_quote__should_return_verified_td10_report_for_valid_fixture() {
set_valid_timestamp_context();
let contract = TeeVerifier::default();
let quote = make_quote_bytes();
let collateral = make_collateral();
let collateral = collateral();

// When
let result = contract.verify_quote(quote, collateral);
Expand Down Expand Up @@ -133,7 +110,7 @@ fn verify_quote__should_reject_without_panicking_for_invalid_quote() {
set_valid_timestamp_context();
let contract = TeeVerifier::default();
let invalid_quote = QuoteBytes(vec![0u8; 16]);
let collateral = make_collateral();
let collateral = collateral();

// When
let result = contract.verify_quote(invalid_quote, collateral);
Expand All @@ -155,7 +132,7 @@ fn verify_quote__should_reject_valid_quote_with_mismatched_collateral() {
set_valid_timestamp_context();
let contract = TeeVerifier::default();
let quote = make_quote_bytes();
let mut collateral = make_collateral();
let mut collateral = collateral();
collateral.tcb_info = String::from("{}");

// When
Expand Down Expand Up @@ -191,7 +168,7 @@ fn hex_arr<const N: usize>(s: &str) -> [u8; N] {
#[test]
fn verify_quote_args_fixture__should_match_committed_file() {
let mut expected = borsh::to_vec(&make_quote_bytes()).unwrap();
expected.extend(borsh::to_vec(&make_collateral()).unwrap());
expected.extend(borsh::to_vec(&collateral()).unwrap());
let path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/verify_quote_args.borsh"
Expand Down
2 changes: 1 addition & 1 deletion crates/test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ near-sdk = { workspace = true, features = ["non-contract-usage"] }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
sha2 = { workspace = true }
tee-verifier-interface = { workspace = true }
tee-verifier-interface = { workspace = true, features = ["serde"] }

[dev-dependencies]
bs58 = { workspace = true }
Expand Down
12 changes: 6 additions & 6 deletions crates/test-utils/assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ This will regenerate the following files:
- `near_p2p_public_key.pub`
- `near_account_public_key.pub`
- `app_compose.json`
- `collateral.json`
- `quote.json`
- `tcb_info.json`
- `launcher_image_compose.yaml`
Expand All @@ -48,7 +47,7 @@ This will regenerate the following files:
All files will be written into the specified output directory.

`public_data.json` is the endpoint response verbatim, so its collateral byte fields are arrays, while
`collateral.json` holds the same bytes hex-encoded for the parser.
`collateral.json` holds the same bytes hex-encoded for the contract DTO.

4. Update `VALID_ATTESTATION_TIMESTAMP` in `crates/test-utils/src/attestation.rs` to a Unix timestamp after the date when the measurements were taken. This ensures that the tests will consider the measurements valid.

Expand Down Expand Up @@ -87,16 +86,17 @@ All files will be written into the specified output directory.
> will be managed entirely through on-chain voting (`vote_add_os_measurement`), and these
> files will no longer need to be kept in sync with the deployed OS image.

8. Regenerate the verifier's borsh argument fixture and refresh the report values
the verifier test hardcodes (`mr_config_id`, `rt_mr3`, `report_data` change with
every new node):
8. Regenerate the derived fixtures — `collateral.json` (the captured collateral, hex-encoded for the
contract DTO) and the verifier's borsh arguments — then refresh the report values the verifier test
hardcodes (`mr_config_id`, `rt_mr3`, `report_data` change with every new node):

```shell
UPDATE_FIXTURES=1 cargo test -p test-utils collateral_fixture
UPDATE_FIXTURES=1 cargo test -p tee-verifier --test verify_quote verify_quote_args_fixture
cargo test -p tee-verifier --test verify_quote
```

The second run fails on `verify_quote__should_return_verified_td10_report_for_valid_fixture`
The last run fails on `verify_quote__should_return_verified_td10_report_for_valid_fixture`
and prints the values actually produced; copy them into
`crates/tee-verifier/tests/verify_quote.rs`.

Expand Down
13 changes: 0 additions & 13 deletions crates/test-utils/assets/create-assets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,6 @@ jq -j '.near_signer_public_key' "$INPUT_FILE" > "$OUTPUT_DIR/near_account_public
# Extract app_compose.json. We set 4 width indentation, and remove trailing newline, so it matches the original string in tests.
printf '%s' "$(jq -r --indent 4 '.tee_participant_info.Dstack.tcb_info.app_compose' "$INPUT_FILE")" > "$OUTPUT_DIR/app_compose.json"

# The endpoint emits the DER/signature fields as byte arrays (serde_bytes) while the fixture parser
# reads them as hex, and the PEM chains keep the NUL terminator from the quote's C strings. Fields
# already in the target form pass through unchanged.
jq -r 'def tohex:
if type == "array" then "0123456789abcdef" as $h
| map($h[(. / 16 | floor):(. / 16 | floor) + 1] + $h[(. % 16):(. % 16) + 1]) | join("")
else . end;
def strip_nul: if type == "string" then split("\u0000")[0] else . end;
.tee_participant_info.Dstack.collateral
| (.root_ca_crl, .pck_crl, .tcb_info_signature, .qe_identity_signature) |= tohex
| (.pck_crl_issuer_chain, .tcb_info_issuer_chain, .qe_identity_issuer_chain,
.pck_certificate_chain) |= strip_nul' "$INPUT_FILE" > "$OUTPUT_DIR/collateral.json"

# Extract quote
jq -c '.tee_participant_info.Dstack.quote' "$INPUT_FILE" > "$OUTPUT_DIR/quote.json"

Expand Down
Loading