Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
8010ce5
Add attestation producer service (api + producer crates)
gmandyam Jul 30, 2026
351b329
Add SPDX license headers to Cargo.toml files
gmandyam Jul 30, 2026
1df0f7f
Add SPDX license headers to README files
gmandyam Jul 30, 2026
af100ee
Fix license headers: add missing 'Licensed under' line to all Rust so…
gmandyam Jul 30, 2026
bd5a9c1
Fix rustfmt formatting in types.rs and signer.rs
gmandyam Jul 30, 2026
187cd98
Add ciborium to crate registry and fix rustfmt formatting
gmandyam Jul 30, 2026
a7dac26
Fix BUILD.bazel: add edition to integration test rule, sort test targets
gmandyam Jul 30, 2026
3f6f80d
Fix formatting: revert to default rustfmt (max_width=100) to match pi…
gmandyam Jul 30, 2026
8f9b3e4
third_party: pin cortex-m-rt to exactly =0.7.5
gmandyam Jul 31, 2026
69226e8
Address PR review comments from rusty1968
gmandyam Aug 31, 2026
048f554
Replace ciborium/alloc with minicbor/heapless for allocation-free ope…
gmandyam Aug 31, 2026
9be5b7c
Remove unused zeroize and thiserror dependencies from attest producer
gmandyam Sep 1, 2026
8d0d0ff
Merge branch 'main' into Attestation-libraries
gmandyam Sep 1, 2026
79429fe
build: upgrade rules_rust from 0.70.0 to 0.74.0
gmandyam Sep 1, 2026
e06f887
style: apply rustfmt to attestation service sources
gmandyam Sep 1, 2026
e336f77
deps: add minicbor 0.21.1 to crates_io Cargo.lock
gmandyam Sep 1, 2026
5206772
deps: rebuild crates_io Cargo.lock from upstream main baseline
gmandyam Sep 1, 2026
7289430
build: revert rules_rust to 0.70.0
gmandyam Sep 1, 2026
75747e2
fix: remove unused CertChain import from attest api traits.rs
gmandyam Sep 1, 2026
0646518
fix: resolve clippy warnings in attest producer
gmandyam Sep 1, 2026
4479469
fix: elide unnecessary explicit lifetimes in builder test helpers
gmandyam Sep 1, 2026
80db1c5
deps: add missing lockfile entries for mctp and syn 2.0.119
gmandyam Sep 1, 2026
f39a0db
fix: correct n_claims count and allow BlueOak-1.0.0 license
gmandyam Sep 1, 2026
c47cef1
fix: correct COSE_Sign1/CWT structure and wire Caliptra measurements
gmandyam Sep 2, 2026
11b5d45
style: apply rustfmt to builder.rs and signer.rs
gmandyam Sep 2, 2026
8ed50b6
attest: incorporate chrysh review suggestions
gmandyam Sep 3, 2026
c4aac80
style: fix rustfmt indentation on sig_input_len closure in builder.rs
gmandyam Sep 3, 2026
379eb44
attest: derive UEID from Caliptra TCG UEID certificate extension
gmandyam Sep 3, 2026
f6ca4b2
style: fix clippy too_many_arguments and rustfmt in cert_ueid.rs, sig…
gmandyam Sep 3, 2026
3b8a1f9
style: fix rustfmt in producer_integration.rs
gmandyam Sep 3, 2026
4da4aec
refactor: remove CertChain newtype wrapper
gmandyam Sep 3, 2026
747f70d
docs: update api and producer READMEs to match current code
gmandyam Sep 3, 2026
bbd015a
refactor: share STUB_CERT constant across all test modules
gmandyam Sep 5, 2026
784ab7a
refactor: remove Send+Sync, unused constants, and uncalled functions
gmandyam Sep 8, 2026
73f549d
refactor: remove hwversion claim — not in OCP-EAT profile
gmandyam Sep 8, 2026
2c75ea4
Remove .claude skills and review prompt from branch
gmandyam Sep 9, 2026
cf3362e
refactor: unify measurement collection and update READMEs
gmandyam Sep 9, 2026
8328683
refactor: move HwSigner to caliptra.rs, remove rim-locators claim
gmandyam Sep 14, 2026
cfb6054
ci: retrigger CI
gmandyam Sep 15, 2026
10cd8be
chore: merge upstream/main, add ciborium+minicbor lock entries
gmandyam Sep 15, 2026
baa4481
fix: resolve clippy and rustfmt presubmit failures
gmandyam Sep 15, 2026
530af43
refactor: remove Caliptra-specific naming from api and producer
gmandyam Sep 16, 2026
6be5319
fix: rustfmt hw_abstraction.rs, lib.rs, cert_ueid.rs
gmandyam Sep 16, 2026
62d10e8
feat: add SwSigner and SwAttestProducer for caller-supplied key path
gmandyam Sep 20, 2026
304c0d0
refactor: rename hw_abstraction.rs to signing_abstraction.rs; fix REA…
gmandyam Sep 21, 2026
4d85797
attest: address review comments from rusty1968 (2026-09-23)
gmandyam Sep 23, 2026
546f9f6
fix: apply rustfmt formatting (CI format-check fix)
gmandyam Sep 23, 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
23 changes: 23 additions & 0 deletions services/attest/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

package(default_visibility = ["//visibility:public"])

# All production crates (embedded-safe, no test stubs).
filegroup(
name = "attest_embedded_all",
srcs = [
"//services/attest/api:attest_api",
"//services/attest/producer:attest_producer",
],
)

# Host-side tests; run without embedded target config.
test_suite(
name = "attest_host_tests",
tests = [
"//services/attest/api:attest_api_test",
"//services/attest/producer:attest_producer_integration_test",
"//services/attest/producer:attest_producer_unit_test",
],
)
28 changes: 28 additions & 0 deletions services/attest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!-- SPDX-License-Identifier: Apache-2.0 -->

# attest service

OCP-EAT attestation token producer for OpenPRoT.

## Crates

| Crate | Path | Purpose |
|---|---|---|
| `openprot-attest-api` | `api/` | Platform-independent traits, types, and error definitions. Callers depend only on this crate. |
| `openprot-attest-producer` | `producer/` | Concrete `AttestProducer` implementations (`HwAttestProducer`, `SwAttestProducer`, `SoftwareAttestProducer`). |

## Dependency structure

```
application / verifier service
└── openprot-attest-api (traits + types only)
└── openprot-attest-producer (production implementations)
```

Platform code selects an implementation at construction time:

- **`HwAttestProducer`** — backed by the Caliptra mailbox driver; all signing inside the hardware boundary.
- **`SwAttestProducer`** — backed by a caller-supplied P-384 key (`SwSigner`); no Caliptra required.
- **`SoftwareAttestProducer`** — software stub for tests (feature = `test-support`).

See each crate's README for API details and usage examples.
24 changes: 24 additions & 0 deletions services/attest/api/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")

rust_library(
name = "attest_api",
srcs = glob(["src/**/*.rs"]),
crate_name = "openprot_attest_api",
edition = "2021",
visibility = ["//visibility:public"],
deps = [
"@rust_crates//:heapless",
"@rust_crates//:p384",
"@rust_crates//:sha2",
"@rust_crates//:thiserror",
"@rust_crates//:zeroize",
],
)

rust_test(
name = "attest_api_test",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attest_api_test Bazel target exists but the api crate (traits.rs, types.rs, signing_abstraction.rs, error.rs, consts.rs) contains no #[cfg(test)] modules, so the security-critical SwSigner::new validation (zero-scalar check, P-384 order check, DER SEQUENCE check) has zero test coverage despite a passing test target implying otherwise. A future regression in that validation would pass silently.

crate = ":attest_api",
)
16 changes: 16 additions & 0 deletions services/attest/api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

[package]
name = "openprot-attest-api"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
description = "Platform-independent API for the OpenPRoT attestation producer service"

[dependencies]
heapless = { version = "0.9", default-features = false }
thiserror = "2"
p384 = { version = "0.13", default-features = false, features = ["ecdsa", "arithmetic"] }
sha2 = { version = "0.10", default-features = false }
zeroize = { version = "1.8", default-features = false, features = ["derive"] }
140 changes: 140 additions & 0 deletions services/attest/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!-- SPDX-License-Identifier: Apache-2.0 -->

# openprot-attest-api

Platform-independent trait and type definitions for the OpenPRoT attestation
producer service.

Callers and other OpenPRoT services depend **only** on this crate. It has no
dependency on the producer implementation, the verifier module, or `spdm-lib`.

## Purpose

This crate defines the stable interface boundary for attestation token
generation. By depending on `openprot-attest-api` rather than
`openprot-attest-producer`, services can be tested with any `AttestProducer`
implementation — including the `SoftwareAttestProducer` stub — without pulling
in hardware dependencies.

## Source files

| File | Contents |
|---|---|
| `src/lib.rs` | Public re-exports. `#![no_std]` `#![forbid(unsafe_code)]`. |
| `src/traits.rs` | `AttestProducer` trait. |
| `src/signing_abstraction.rs` | `HwSigner` trait; `SwSigner` struct with P-384 key validation and ECDSA signing. |
| `src/types.rs` | `Measurement`, `DigestAlgorithm`, `MeasurementAuthority`, `AttestConfig`, `OemId`, `MeasurementProvider` trait, `SwSignerConfig` struct. |
| `src/consts.rs` | Fixed-capacity constants (`MAX_CERT_SIZE`, `MAX_CHAIN_LEN`, etc.). |
| `src/error.rs` | `AttestError` — shared error type for both service crates. |

## Key traits

### `AttestProducer`

The primary interface implemented by `HwAttestProducer`, `SwAttestProducer`,
and the `SoftwareAttestProducer` stub in the producer crate.

```rust
pub trait AttestProducer {
fn generate_token(
&self,
nonce: &[u8],
out: &mut Vec<u8, MAX_TOKEN_SIZE>,
) -> Result<(), AttestError>;

/// `buf` is cleared before being populated with the chain (leaf → root).
fn cert_chain(
&self,
buf: &mut Vec<Vec<u8, MAX_CERT_SIZE>, MAX_CHAIN_LEN>,
) -> Result<(), AttestError>;
}
```

### `HwSigner`

Abstracts signing and certificate operations backed by the Caliptra hardware
boundary.

```rust
pub trait HwSigner {
fn sign(&self, payload: &[u8]) -> Result<[u8; 96], AttestError>;
fn cert_chain_der(
&self,
buf: &mut Vec<Vec<u8, MAX_CERT_SIZE>, MAX_CHAIN_LEN>,
) -> Result<(), AttestError>;
fn measurements(
&self,
out: &mut Vec<Measurement, MAX_MEASUREMENTS>,
) -> Result<(), AttestError>;
}
```

The private Alias Key never leaves Caliptra. Production code implements this
trait via the Caliptra mailbox driver (`caliptra-sw`).

### `SwSigner`

Holds a caller-supplied P-384 private key and DER certificate chain for
software signing (no Caliptra hardware required). Constructed via
`SwSigner::new(SwSignerConfig { ... })`, which validates:

- Scalar is a valid P-384 private key (`1 ≤ d < n`), via `p384::ecdsa::SigningKey::from_bytes`.
- Cert chain contains at least one certificate.
- Every certificate begins with `0x30` (DER SEQUENCE tag).

Returns `Err(AttestError::InvalidKey)` on any violation. The key is stored as
a `SigningKey` which zeroizes on drop. `SwSignerConfig` also zeroizes the raw
scalar on drop.

`sign()` produces a real ECDSA P-384 signature (SHA-384 prehash, RFC 6979
deterministic nonce) over the COSE `Sig_Structure`.

### `MeasurementProvider`

Plug in platform-specific firmware measurement sources (UEFI, BMC, etc.)
beyond the Caliptra-internal measurements.

```rust
pub trait MeasurementProvider {
fn measurements(
&self,
out: &mut Vec<Measurement, MAX_MEASUREMENTS>,
) -> Result<(), AttestError>;
}
```

## Key types

| Type | Description |
|---|---|
| `Measurement` | Single firmware measurement: component name, version, digest algorithm, digest bytes, measurement authority. |
| `DigestAlgorithm` | `Sha384` or `Sha512`. |
| `MeasurementAuthority` | `Caliptra` (hardware-measured) or `Platform` (software-registered). |
| `AttestConfig` | Producer configuration: `oemid`, `hw_model`. |
| `OemId` | OEM identifier (IANA Private Enterprise Number or UUID form). |
| `SwSignerConfig` | Input to `SwSigner::new`: 48-byte P-384 scalar and DER cert chain. Zeroizes scalar on drop. |

## Error variants

| Variant | Meaning |
|---|---|
| `Mailbox` | Caliptra mailbox communication failure. |
| `Der` | DER parse error (malformed certificate structure). |
| `ChainValidation` | DICE chain structural or compliance failure. |
| `InvalidNonce` | Nonce length outside the 8–64 byte range. |
| `Cbor` | CBOR encoding error. |
| `BufferFull` | Fixed-size buffer capacity exceeded. |
| `Cose` | COSE signing error. |
| `Provider` | Measurement provider error. |
| `InvalidKey` | Invalid P-384 key material supplied to `SwSigner::new`. |

## Cargo

```toml
[dependencies]
openprot-attest-api = { path = "services/attest/api" }
```

The crate is `no_std` and depends on `heapless` for fixed-capacity
collections, `thiserror` for `AttestError`, `p384` + `sha2` for ECDSA
signing, and `zeroize` for key material cleanup.
18 changes: 18 additions & 0 deletions services/attest/api/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

// Caliptra chain: VendorCA → IDevID → LDevID → AliasFMC → AliasRT (leaf)
pub const MAX_CHAIN_LEN: usize = 5;
pub const MAX_CERT_SIZE: usize = 2048;

pub const MAX_MEASUREMENTS: usize = 16;
Comment thread
chrysh marked this conversation as resolved.
pub const MAX_PROVIDERS: usize = 8;
pub const MAX_COMPONENT_LEN: usize = 64;
pub const MAX_VERSION_LEN: usize = 32;
pub const MAX_DIGEST_LEN: usize = 64; // SHA-512

pub const MAX_OEMID_LEN: usize = 16;
pub const MAX_HW_MODEL_LEN: usize = 64;

// Upper bound for a fully-populated COSE_Sign1 token
pub const MAX_TOKEN_SIZE: usize = 8192;
24 changes: 24 additions & 0 deletions services/attest/api/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

#[derive(Debug, thiserror::Error)]
pub enum AttestError {
#[error("Mailbox error: {0}")]
Mailbox(&'static str),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mailbox(&'static str) reads as "Caliptra mailbox communication failure" but is reused as a generic string-bucket for unrelated failure domains: DER parsing (cert_ueid.rs:42, e.g. "cert: bad outer SEQUENCE"), DICE chain validation (dice_identity.rs, e.g. "cert: not X.509 v3"), and even nonce-length validation (builder.rs:80, "nonce must be 8–64 bytes...") — none of which touch a mailbox. Callers can't match on failure category, only inspect an opaque string. Worth splitting into a real taxonomy (e.g. Der, InvalidNonce, ChainValidation, Mailbox) before external callers start pattern-matching on this enum.

#[error("DER parse error: {0}")]
Der(&'static str),
#[error("DICE chain validation error: {0}")]
ChainValidation(&'static str),
#[error("Invalid nonce: {0}")]
InvalidNonce(&'static str),
#[error("CBOR encoding error")]
Cbor,
#[error("Fixed-size buffer capacity exceeded")]
BufferFull,
#[error("COSE signing error")]
Cose,
#[error("Measurement provider error: {0}")]
Provider(&'static str),
#[error("Invalid key material: {0}")]
InvalidKey(&'static str),
}
42 changes: 42 additions & 0 deletions services/attest/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

//! Platform-independent API for the OpenPRoT attestation producer service.
//!
//! # Usage
//!
//! Applications depend only on this crate. Platform code provides a concrete
//! [`AttestProducer`] implementation (hardware-backed via a platform signer, or the
//! `test-support`-gated software stub in the `openprot-attest-producer` crate).
//!
//! ```text
//! ┌───────────────────────────────────────────────┐
//! │ application / verifier service │
//! │ depends on: openprot-attest-api │
//! │ calls: AttestProducer::generate_token│
//! └──────────────────┬────────────────────────────┘
//! │ trait object / generic bound
//! ┌──────────────────▼────────────────────────────┐
//! │ openprot-attest-producer │
//! │ HwAttestProducer (production, HW key) │
//! │ SwAttestProducer (production, SW key) │
//! │ SoftwareAttestProducer (test-support) │
//! └───────────────────────────────────────────────┘
//! ```

#![no_std]
#![forbid(unsafe_code)]

pub mod consts;
mod error;
mod signing_abstraction;
mod traits;
mod types;

pub use error::AttestError;
pub use signing_abstraction::{HwSigner, SwSigner};
pub use traits::AttestProducer;
pub use types::{
AttestConfig, DigestAlgorithm, Measurement, MeasurementAuthority, MeasurementProvider, OemId,
SwSignerConfig,
};
Loading
Loading