1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Profile extension framework for CoRIM.
//!
//! CoRIM is intentionally extensible via the `corim-map.profile` field
//! (§4.1.4 of draft-ietf-rats-corim-10) — a URI or OID that names a
//! profile defining additional measurement-values keys, expression
//! tags, appraisal semantics, and media-type discriminators. Examples
//! include the in-progress Intel profile
//! (`draft-cds-rats-intel-corim-profile`, OID
//! `2.16.840.1.113741.1.16.1`).
//!
//! The `corim` core crate is profile-agnostic: it preserves
//! profile-defined keys verbatim via the
//! [`MeasurementValuesMap::extra_entries`][crate::types::measurement::MeasurementValuesMap::extra_entries]
//! field but does **not** interpret or appraise them. Profile-aware
//! semantics live in dedicated modules that implement the [`Profile`](crate::profile::Profile)
//! trait and register an instance with a [`ProfileRegistry`](crate::profile::ProfileRegistry). The
//! registry is then passed to the validate/diagnose entry points that
//! accept it.
//!
//! # First-party profiles
//!
//! First-party profile implementations ship inside this crate behind
//! opt-in Cargo features:
//!
//! | Feature | Module | Spec |
//! |-------------------|-----------------------------------------------|-----------------------------------------|
//! | `profile-intel` | [`intel`](crate::profile::intel) | `draft-cds-rats-intel-corim-profile-03` |
//!
//! Third-party profiles are first-class — the [`Profile`](crate::profile::Profile) trait is
//! public and stable, and out-of-tree crates may publish their own
//! profile implementations without coordinating with this crate.
//!
//! # Minimal example
//!
//! A no-op profile that recognises its identifier but defers all
//! behaviour to the crate's defaults:
//!
//! ```rust
//! use corim::profile::{Profile, ProfileRegistry};
//! use corim::types::corim::ProfileChoice;
//!
//! struct ExampleProfile {
//! id: ProfileChoice,
//! }
//! impl Profile for ExampleProfile {
//! fn identifier(&self) -> &ProfileChoice { &self.id }
//! }
//!
//! let profile = ExampleProfile {
//! id: ProfileChoice::Uri("urn:example:profile".into()),
//! };
//! let mut registry = ProfileRegistry::new();
//! registry.register(Box::new(profile));
//! assert_eq!(registry.len(), 1);
//! ```
//!
//! # Writing your own profile
//!
//! Three trait methods govern profile behaviour. Only
//! [`Profile::identifier`](crate::profile::Profile::identifier) is required;
//! the others carry no-op defaults and can be left out if not needed.
//!
//! ## 1. `identifier` (required)
//!
//! Return a stable [`ProfileChoice`][crate::types::corim::ProfileChoice] (URI
//! or OID). The registry uses this as a map key, so calls must always return
//! the same value for a given instance. Typically this is built once in the
//! constructor and returned by reference.
//!
//! ## 2. `match_measurement` (optional, for appraisal)
//!
//! Override when the profile defines a custom matching policy for one
//! or more keys in
//! [`MeasurementValuesMap::extra_entries`][crate::types::measurement::MeasurementValuesMap::extra_entries].
//! The contract is a three-valued verdict:
//!
//! - `Some(true)` — the pair satisfies the profile's policy AND any
//! core structural fields agree. The pair is treated as a match.
//! - `Some(false)` — the profile rejects the pair (e.g. an operator
//! expression failed, or a required extra key is absent from
//! evidence). The pair is NOT a match; no fallback runs.
//! - `None` — the profile has nothing to say about this pair (e.g.
//! the reference contains no profile-specific keys). The crate falls
//! back to the default exact-match logic used by
//! [`crate::validate::match_reference_values`].
//!
//! When combining a profile-specific verdict with core structural
//! checks, call [`crate::validate::core_fields_match`] to evaluate the
//! non-extension fields (`mkey`, `digests`, `svn`, etc.) — this keeps
//! profile implementations from accidentally bypassing core
//! invariants. The [`intel::IntelProfile`](crate::profile::intel::IntelProfile)
//! implementation is a worked example of this composition pattern.
//!
//! ### Per-call context: [`MatchContext`](crate::profile::MatchContext)
//!
//! [`MatchContext`](crate::profile::MatchContext) carries verifier-side state
//! that profiles may need but shouldn't own (currently just
//! `now: Option<CborTime>` for epoch-based comparisons). The type is
//! `#[non_exhaustive]` so new fields can be added without breaking existing
//! implementations. Profiles that don't need any context can ignore the
//! parameter.
//!
//! When `MatchContext::now` is `None` (no clock available), time-based
//! reference values should return a "skip" verdict — i.e. behave as if
//! the key were absent — rather than failing closed, so a verifier
//! running without a clock can still appraise the non-time keys. See
//! `intel::eval` for one implementation of this policy.
//!
//! ## 3. `diagnose_mval_entry` (optional, for `--diagnose`)
//!
//! Override to provide human-readable labels for profile-defined
//! integer keys in the `--diagnose` walker output. The walker calls
//! this for every entry in `extra_entries`; return `Some(label)` for
//! keys this profile recognises, `None` for everything else (the
//! walker falls back to `"extension key {n}"`).
//!
//! This method is independent of `match_measurement` — a profile may
//! provide pretty-printing only (no matching policy) or vice versa.
//!
//! ## Registering and dispatching
//!
//! Construct a [`ProfileRegistry`](crate::profile::ProfileRegistry) once at
//! application startup and register every profile the application needs to
//! understand:
//!
//! ```no_run
//! use corim::profile::ProfileRegistry;
//! # use corim::profile::Profile;
//! # use corim::types::corim::ProfileChoice;
//! # struct MyProfile;
//! # impl Profile for MyProfile {
//! # fn identifier(&self) -> &ProfileChoice { todo!() }
//! # }
//!
//! let mut registry = ProfileRegistry::new();
//! registry.register(Box::new(MyProfile));
//! // ... pass `®istry` to diagnose / validate entry points.
//! ```
//!
//! At appraisal time, look the profile up by the manifest's `profile`
//! field and pass it to the `*_with_profile` validate entry points
//! (e.g. [`crate::validate::match_reference_values_with_profile`]).
//! Those functions are generic over `P: ?Sized + Profile`, so the
//! `&(dyn Profile + Send + Sync)` reference returned by
//! [`ProfileRegistry::get`](crate::profile::ProfileRegistry::get) flows
//! through directly without a cast.
use crate*;
use crateValue;
use crateCborTime;
use crateProfileChoice;
use crateMeasurementMap;
/// First-party Intel CoRIM profile (`draft-cds-rats-intel-corim-profile`).
///
/// Gated on the `profile-intel` Cargo feature. Provides
/// [`intel::IntelProfile`], the `#6.60010` expression decoder, and the
/// per-key evaluator.
// ---------------------------------------------------------------------------
// MatchContext
// ---------------------------------------------------------------------------
/// Per-call context threaded through profile-aware matching.
///
/// Built once per appraisal call by the verifier and passed by reference
/// into [`Profile::match_measurement`] (and from there into the
/// profile-aware variants of the [`crate::validate`] entry points). The
/// caller is the source of truth for verifier-side state that the
/// profile may need but should not own — currently just
/// verifier-current-time for epoch-based reference values.
///
/// Construct with [`MatchContext::new`] (empty) or, with the `std`
/// feature, [`MatchContext::system_now`] (clock from
/// `std::time::SystemTime`). Chain [`MatchContext::with_now`] to set
/// the clock explicitly.
///
/// Designed to grow: future fields (nonce, evidence-source-class, etc.)
/// can be added without breaking the trait signature again — hence
/// `#[non_exhaustive]`.
/// Trait implemented by profile crates to teach `corim` about a CoRIM
/// profile's extension semantics.
///
/// All non-identifier methods carry default no-op implementations so
/// implementers only need to define the methods they actually want to
/// override. A profile that only wants to provide pretty-printing in
/// `--diagnose` output, for example, needs only to override
/// [`Profile::diagnose_mval_entry`].
///
/// Implementations are typically registered with a [`ProfileRegistry`]
/// and looked up at validate/diagnose time by matching the manifest's
/// `corim-map.profile` field against [`Profile::identifier`].
/// Type alias for owned, thread-safe boxed profiles stored in a
/// [`ProfileRegistry`]. Requires implementations to be `Send + Sync`
/// so registries can be shared across threads via `Arc<ProfileRegistry>`.
pub type BoxedProfile = ;
/// Owns a set of [`Profile`] implementations keyed by [`ProfileChoice`].
///
/// Construct once at application startup, register every profile the
/// application needs to understand, and pass the registry by reference
/// to validate/diagnose entry points that accept it. A registry with
/// no entries is functionally equivalent to passing no registry at all.