Skip to content

Commit ec8d937

Browse files
JstatiaCopilot
andcommitted
docs: add missing README.md files for 4 native Rust crates
Create README.md for crates that were missing documentation: - primitives/cose/ (cose_primitives): RFC 9052 COSE building blocks - signing/headers/ (cose_sign1_headers): CWT claims and header management - validation/test_utils/ (cose_sign1_validation_test_utils): test helpers - extension_packs/mst/client/ (code_transparency_client): Azure CT REST client Each README follows the established project style with: - Copyright header, crate name, overview, architecture diagram - Modules table, key types with code examples - Memory design notes, dependencies, and cross-references Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 32d8811 commit ec8d937

File tree

4 files changed

+662
-0
lines changed

4 files changed

+662
-0
lines changed
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
<!-- Copyright (c) Microsoft Corporation. Licensed under the MIT License. -->
2+
3+
# code_transparency_client
4+
5+
Rust REST client for the Azure Code Transparency Service.
6+
7+
## Overview
8+
9+
This crate provides a high-level HTTP client for interacting with the
10+
[Azure Code Transparency](https://learn.microsoft.com/en-us/azure/confidential-ledger/code-transparency-overview)
11+
service (formerly Microsoft Supply-chain Transparency, MST). It follows
12+
canonical Azure SDK patterns — pipeline policies, long-running operation
13+
polling, and structured error handling — to submit COSE_Sign1 messages for
14+
transparent registration and retrieve receipts.
15+
16+
Key capabilities:
17+
18+
- **Entry submission**`create_entry()` submits COSE_Sign1 messages and
19+
returns a `Poller<OperationStatus>` for async tracking
20+
- **Convenience signing**`make_transparent()` submits and polls to
21+
completion in a single call
22+
- **Entry retrieval**`get_entry()` / `get_entry_statement()` fetch
23+
registered entries and their original statements
24+
- **Key management**`get_public_keys()` / `resolve_signing_key()` fetch
25+
and resolve JWKS for receipt verification
26+
- **Pipeline policies**`ApiKeyAuthPolicy` for Bearer-token injection,
27+
`TransactionNotCachedPolicy` for fast 503 retries
28+
- **CBOR error handling** — Parses RFC 9290 CBOR Problem Details from
29+
service error responses
30+
31+
## Architecture
32+
33+
```
34+
┌──────────────────────────────────────────────────────┐
35+
│ code_transparency_client │
36+
├─────────────────────────┬────────────────────────────┤
37+
│ client │ models │
38+
│ ┌────────────────────┐ │ ┌────────────────────────┐ │
39+
│ │CodeTransparency │ │ │JsonWebKey │ │
40+
│ │ Client │ │ │JwksDocument │ │
41+
│ │ │ │ └────────────────────────┘ │
42+
│ │ • create_entry() │ │ │
43+
│ │ • make_transparent │ │ operation_status │
44+
│ │ • get_entry() │ │ ┌────────────────────────┐ │
45+
│ │ • get_public_keys()│ │ │OperationStatus │ │
46+
│ │ • resolve_signing │ │ │ (StatusMonitor) │ │
47+
│ │ _key() │ │ └────────────────────────┘ │
48+
│ └────────────────────┘ │ │
49+
├─────────────────────────┼────────────────────────────┤
50+
│ Pipeline Policies │ Error Handling │
51+
│ ┌────────────────────┐ │ ┌────────────────────────┐ │
52+
│ │ApiKeyAuthPolicy │ │ │CodeTransparencyError │ │
53+
│ │TransactionNot │ │ │CborProblemDetails │ │
54+
│ │ CachedPolicy │ │ └────────────────────────┘ │
55+
│ └────────────────────┘ │ │
56+
├─────────────────────────┴────────────────────────────┤
57+
│ polling (DelayStrategy, MstPollingOptions) │
58+
│ mock_transport (SequentialMockTransport) [test-utils] │
59+
└──────────────────────────────────────────────────────┘
60+
│ │
61+
▼ ▼
62+
azure_core cbor_primitives
63+
(Pipeline, Poller, cose_sign1_primitives
64+
StatusMonitor)
65+
```
66+
67+
## Modules
68+
69+
| Module | Description |
70+
|--------|-------------|
71+
| `client` | `CodeTransparencyClient` — main HTTP client with entry submission, retrieval, and key management |
72+
| `models` | `JsonWebKey`, `JwksDocument` — JWKS types for receipt verification key resolution |
73+
| `operation_status` | `OperationStatus``StatusMonitor` implementation for long-running operation polling |
74+
| `polling` | `DelayStrategy` (fixed / exponential), `MstPollingOptions` — configurable polling behavior |
75+
| `api_key_auth_policy` | `ApiKeyAuthPolicy` — pipeline policy injecting `Authorization: Bearer {key}` headers |
76+
| `transaction_not_cached_policy` | `TransactionNotCachedPolicy` — fast-retry policy (250 ms × 8) for `TransactionNotCached` 503 errors |
77+
| `cbor_problem_details` | `CborProblemDetails` — RFC 9290 CBOR Problem Details parser for structured error responses |
78+
| `error` | `CodeTransparencyError` — structured errors with HTTP status codes and service messages |
79+
| `mock_transport` | `SequentialMockTransport` — mock HTTP transport for unit tests (behind `test-utils` feature) |
80+
81+
## Key Types
82+
83+
### CodeTransparencyClient
84+
85+
```rust
86+
use code_transparency_client::{CodeTransparencyClient, MstPollingOptions};
87+
88+
// Create a client with API key authentication
89+
let client = CodeTransparencyClient::new(
90+
"https://my-instance.confidential-ledger.azure.com",
91+
Some("my-api-key".into()),
92+
None, // default options
93+
)?;
94+
95+
// Submit a COSE_Sign1 message and wait for receipt
96+
let transparent_bytes = client
97+
.make_transparent(&cose_sign1_bytes, None)
98+
.await?;
99+
```
100+
101+
### Entry Submission with Polling
102+
103+
```rust
104+
use code_transparency_client::CodeTransparencyClient;
105+
106+
let client = CodeTransparencyClient::new(endpoint, api_key, None)?;
107+
108+
// Start the long-running operation
109+
let poller = client.create_entry(&cose_sign1_bytes).await?;
110+
111+
// Poll until complete (uses default delay strategy)
112+
let status = poller.wait().await?;
113+
let entry_id = status.entry_id.expect("entry registered");
114+
115+
// Retrieve the transparent entry
116+
let entry_bytes = client.get_entry(&entry_id).await?;
117+
```
118+
119+
### Receipt Key Resolution
120+
121+
```rust
122+
use code_transparency_client::CodeTransparencyClient;
123+
124+
// Resolve a signing key by key ID (checks cache first, then fetches JWKS)
125+
let jwk = client.resolve_signing_key("key-id-123", &jwks_cache).await?;
126+
```
127+
128+
### Custom Polling Options
129+
130+
```rust
131+
use code_transparency_client::{MstPollingOptions, DelayStrategy};
132+
use std::time::Duration;
133+
134+
let options = MstPollingOptions {
135+
delay_strategy: DelayStrategy::Exponential {
136+
initial: Duration::from_secs(1),
137+
max: Duration::from_secs(30),
138+
},
139+
max_retries: Some(20),
140+
};
141+
142+
let transparent = client
143+
.make_transparent(&cose_bytes, Some(options))
144+
.await?;
145+
```
146+
147+
## Error Handling
148+
149+
All operations return `CodeTransparencyError`:
150+
151+
```rust
152+
pub enum CodeTransparencyError {
153+
/// HTTP or network error from the Azure pipeline.
154+
HttpError(azure_core::Error),
155+
/// Service returned a structured CBOR Problem Details response.
156+
ServiceError {
157+
status: u16,
158+
details: Option<CborProblemDetails>,
159+
message: String,
160+
},
161+
/// Operation timed out or exceeded max retries.
162+
PollingTimeout,
163+
/// CBOR/COSE deserialization failure.
164+
DeserializationError(String),
165+
}
166+
```
167+
168+
The `TransactionNotCachedPolicy` automatically retries 503 responses with
169+
a `TransactionNotCached` error code up to 8 times at 250 ms intervals before
170+
surfacing the error to the caller.
171+
172+
## Memory Design
173+
174+
- **Pipeline-based I/O**: HTTP requests flow through an `azure_core::http::Pipeline`
175+
with configurable policies. Response bodies are read once and owned by the caller.
176+
- **COSE bytes are borrowed**: `create_entry()` and `make_transparent()` accept
177+
`&[u8]`, avoiding copies of potentially large COSE_Sign1 messages.
178+
- **JWKS caching**: `resolve_signing_key()` checks an in-memory cache before
179+
making network requests, avoiding redundant fetches.
180+
181+
## Dependencies
182+
183+
- `azure_core` — HTTP pipeline, `Poller`, `StatusMonitor`, retry policies
184+
- `cbor_primitives` — CBOR decoding for problem details and configuration
185+
- `cose_sign1_primitives` — COSE types shared with the signing/validation stack
186+
- `serde` / `serde_json` — JSON deserialization for JWKS responses
187+
- `tokio` — Async runtime for HTTP operations
188+
189+
## Testing
190+
191+
Enable the `test-utils` feature to access `SequentialMockTransport` for
192+
unit tests without network access:
193+
194+
```toml
195+
[dev-dependencies]
196+
code_transparency_client = { path = ".", features = ["test-utils"] }
197+
```
198+
199+
```rust
200+
use code_transparency_client::mock_transport::SequentialMockTransport;
201+
202+
let transport = SequentialMockTransport::new(vec![
203+
mock_response(200, cose_bytes),
204+
mock_response(200, receipt_bytes),
205+
]);
206+
```
207+
208+
## See Also
209+
210+
- [extension_packs/mst/](../) — MST trust pack using this client for receipt validation
211+
- [extension_packs/certificates/](../../certificates/) — Certificate trust pack
212+
- [Azure Code Transparency docs](https://learn.microsoft.com/en-us/azure/confidential-ledger/code-transparency-overview)
213+
214+
## License
215+
216+
Licensed under the [MIT License](../../../../../LICENSE).
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<!-- Copyright (c) Microsoft Corporation. Licensed under the MIT License. -->
2+
3+
# cose_primitives
4+
5+
RFC 9052 COSE generic building blocks for Rust.
6+
7+
## Overview
8+
9+
This crate provides the foundational types for working with CBOR Object Signing
10+
and Encryption (COSE) messages as defined in [RFC 9052](https://www.rfc-editor.org/rfc/rfc9052).
11+
It is designed as a **zero-copy**, **streaming-capable** layer that all
12+
higher-level COSE message types (Sign1, Encrypt, MAC, etc.) build upon.
13+
14+
Key capabilities:
15+
16+
- **Header management**`CoseHeaderMap`, `CoseHeaderLabel`, `CoseHeaderValue`,
17+
`ProtectedHeader` for encoding and decoding COSE headers
18+
- **Lazy header parsing**`LazyHeaderMap` defers CBOR decoding until first access
19+
- **Zero-copy data model**`ArcSlice` and `ArcStr` reference a shared `Arc<[u8]>`
20+
backing buffer without copying
21+
- **Streaming support**`CoseData` enum supports both fully-buffered and
22+
stream-backed message payloads
23+
- **IANA algorithm constants** — Re-exports from `crypto_primitives` (ES256, ES384,
24+
RS256, EdDSA, etc.)
25+
- **CBOR provider abstraction** — Compile-time selection of the CBOR backend
26+
(currently EverParse)
27+
28+
## Architecture
29+
30+
```
31+
┌───────────────────────────────────────────────────┐
32+
│ cose_primitives │
33+
├───────────┬───────────┬───────────┬───────────────┤
34+
│ headers │ data │ arc_types │ lazy_headers │
35+
│ ┌────────┐│ ┌────────┐│ ┌───────┐│ ┌────────────┐│
36+
│ │HeaderMap││ │CoseData││ │ArcSlice│ │LazyHeaderMap││
37+
│ │Label ││ │Buffered││ │ArcStr ││ │ OnceLock ││
38+
│ │Value ││ │Streamed││ └───────┘│ └────────────┘│
39+
│ │Protected│ └────────┘│ │ │
40+
│ └────────┘│ │ │ │
41+
├───────────┴───────────┴──────────┴────────────────┤
42+
│ algorithms (re-exports) │ error │ provider │
43+
└───────────────────────────┴─────────┴──────────────┘
44+
│ │
45+
▼ ▼
46+
crypto_primitives cbor_primitives
47+
(IANA algorithm IDs) (CBOR encode/decode)
48+
```
49+
50+
## Modules
51+
52+
| Module | Description |
53+
|--------|-------------|
54+
| `headers` | `CoseHeaderMap`, `CoseHeaderLabel`, `CoseHeaderValue`, `ProtectedHeader` — full CBOR-backed header management |
55+
| `lazy_headers` | `LazyHeaderMap` — lazy-parsed headers cached via `OnceLock` |
56+
| `arc_types` | `ArcSlice` and `ArcStr` — zero-copy shared-ownership byte/string references into an `Arc<[u8]>` buffer |
57+
| `data` | `CoseData` enum — `Buffered` (in-memory) and `Streamed` (seekable reader) message data |
58+
| `algorithms` | Re-exported IANA algorithm constants from `crypto_primitives` |
59+
| `error` | `CoseError` — CBOR, structural, and I/O error variants |
60+
| `provider` | Compile-time CBOR provider singleton selection |
61+
62+
## Key Types
63+
64+
### CoseHeaderMap
65+
66+
The primary type for reading and writing COSE headers:
67+
68+
```rust
69+
use cose_primitives::headers::{CoseHeaderMap, CoseHeaderLabel, CoseHeaderValue};
70+
71+
let mut headers = CoseHeaderMap::new();
72+
73+
// Set algorithm (label 1) to ES256 (-7)
74+
headers.set(CoseHeaderLabel::Int(1), CoseHeaderValue::Int(-7));
75+
76+
// Read a header value
77+
if let Some(CoseHeaderValue::Int(alg)) = headers.get(&CoseHeaderLabel::Int(1)) {
78+
assert_eq!(*alg, -7);
79+
}
80+
```
81+
82+
### ArcSlice / ArcStr
83+
84+
Zero-copy shared-ownership byte slices backed by `Arc<[u8]>`:
85+
86+
```rust
87+
use cose_primitives::arc_types::ArcSlice;
88+
use std::sync::Arc;
89+
90+
// Create from raw bytes — one allocation shared across sub-slices
91+
let buffer: Arc<[u8]> = Arc::from(b"hello world".as_slice());
92+
let slice = ArcSlice::new(buffer.clone(), 0..5); // "hello"
93+
94+
assert_eq!(slice.as_ref(), b"hello");
95+
```
96+
97+
### CoseData
98+
99+
Supports both in-memory and stream-backed message payloads:
100+
101+
```rust
102+
use cose_primitives::data::CoseData;
103+
104+
// Fully buffered payload
105+
let data = CoseData::Buffered { bytes: payload_bytes };
106+
107+
// Streaming payload (headers in memory, body in a seekable reader)
108+
let data = CoseData::Streamed { headers, reader };
109+
```
110+
111+
### LazyHeaderMap
112+
113+
Defers CBOR header parsing until first access:
114+
115+
```rust
116+
use cose_primitives::lazy_headers::LazyHeaderMap;
117+
118+
let lazy = LazyHeaderMap::from_bytes(raw_cbor_bytes);
119+
120+
// No parsing happens until you call .get() or .map()
121+
let map = lazy.map()?; // parsed on first call, cached thereafter
122+
```
123+
124+
## Memory Design
125+
126+
- **Zero-copy throughout**: All decoded data references a shared `Arc<[u8]>` backing
127+
buffer. Sub-structures (headers, payload, signature) hold `ArcSlice` ranges into
128+
the original bytes — no heap allocations for parsed fields.
129+
- **Lazy evaluation**: `LazyHeaderMap` uses `OnceLock` to parse headers exactly
130+
once, on demand.
131+
- **Streaming**: `CoseData::Streamed` keeps only headers in memory while the payload
132+
remains in a seekable stream, enabling large-file processing.
133+
134+
## Dependencies
135+
136+
- `cbor_primitives` — CBOR encoding/decoding trait and EverParse backend
137+
- `crypto_primitives` — IANA algorithm constants and crypto trait definitions
138+
139+
## See Also
140+
141+
- [primitives/cose/sign1/](sign1/) — COSE_Sign1 message type and builder
142+
- [primitives/cbor/](../cbor/) — CBOR provider abstraction
143+
- [primitives/crypto/](../crypto/) — Cryptographic trait definitions
144+
145+
## License
146+
147+
Licensed under the [MIT License](../../../../LICENSE).

0 commit comments

Comments
 (0)