Skip to content

Commit f5e0465

Browse files
committed
Adding error handling and CDDL enforcement
- Adding custom errors. - Enforcing non-empty vectors (CDDL `[ + <TYPE>]`) via `NonEmptyVec` - Adding a Result type. Signed-off-by: Larry Dewey <[email protected]>
1 parent 1a10d5f commit f5e0465

File tree

14 files changed

+687
-85
lines changed

14 files changed

+687
-85
lines changed

src/comid.rs

Lines changed: 134 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@
8585
//! All components support optional extensions through [`ExtensionMap`] for future expandability.
8686
8787
use crate::{
88-
core::{RawValueType, TaggedBytes},
88+
core::{NonEmptyVec, RawValueType, TaggedBytes},
8989
generate_tagged,
9090
triples::{EnvironmentMap, MeasuredElementTypeChoice, MeasurementMap, MeasurementValuesMap},
91-
AttestKeyTripleRecord, ConditionalEndorsementSeriesTripleRecord,
91+
AttestKeyTripleRecord, ComidError, ConditionalEndorsementSeriesTripleRecord,
9292
ConditionalEndorsementTripleRecord, CoswidTripleRecord, DomainDependencyTripleRecord,
9393
DomainMembershipTripleRecord, EndorsedTripleRecord, ExtensionMap, IdentityTripleRecord,
94-
ReferenceTripleRecord, Text, Tstr, Uint, Uri, UuidType,
94+
ReferenceTripleRecord, Result, Text, Tstr, Uint, Uri, UuidType,
9595
};
9696
use derive_more::{Constructor, From, TryFrom};
9797
use serde::{Deserialize, Serialize};
@@ -120,12 +120,13 @@ pub struct ConciseMidTag<'a> {
120120
#[serde(rename = "1")]
121121
pub tag_identity: TagIdentityMap<'a>,
122122
/// List of entities associated with this tag
123+
#[serde(skip_serializing_if = "Option::is_none")]
123124
#[serde(rename = "2")]
124-
pub entities: Vec<ComidEntityMap<'a>>,
125+
pub entities: Option<NonEmptyVec<ComidEntityMap<'a>>>,
125126
/// Optional references to other related tags
126127
#[serde(skip_serializing_if = "Option::is_none")]
127128
#[serde(rename = "3")]
128-
pub linked_tags: Option<Vec<LinkedTagMap<'a>>>,
129+
pub linked_tags: Option<NonEmptyVec<LinkedTagMap<'a>>>,
129130
/// Collection of triples describing the module
130131
#[serde(rename = "4")]
131132
pub triples: TriplesMap<'a>,
@@ -198,7 +199,7 @@ impl<'a> ConciseMidTag<'a> {
198199
environment: &EnvironmentMap<'a>,
199200
mkey: MeasuredElementTypeChoice<'a>,
200201
value: &T,
201-
) -> Result<(), std::io::Error>
202+
) -> std::io::Result<()>
202203
where
203204
T: ?Sized + Serialize,
204205
{
@@ -225,7 +226,7 @@ impl<'a> ConciseMidTag<'a> {
225226
ref_env: environment.clone(),
226227
ref_claims: vec![measurement],
227228
};
228-
self.triples.reference_triples = Some(vec![new_record]);
229+
self.triples.reference_triples = Some(vec![new_record].into());
229230
}
230231
Some(vec) => {
231232
if let Some(record) = vec.iter_mut().find(|r| r.ref_env == *environment) {
@@ -246,7 +247,7 @@ impl<'a> ConciseMidTag<'a> {
246247
environment: &EnvironmentMap<'a>,
247248
mkey: MeasuredElementTypeChoice<'a>,
248249
value: &T,
249-
) -> Result<(), std::io::Error>
250+
) -> std::io::Result<()>
250251
where
251252
T: ?Sized + Serialize,
252253
{
@@ -267,13 +268,13 @@ impl<'a> ConciseMidTag<'a> {
267268
authorized_by: None,
268269
};
269270

270-
match &mut self.triples.endorse_triples {
271+
match &mut self.triples.endorsed_triples {
271272
None => {
272273
let new_record = EndorsedTripleRecord {
273274
condition: environment.clone(),
274275
endorsement: vec![measurement],
275276
};
276-
self.triples.endorse_triples = Some(vec![new_record]);
277+
self.triples.endorsed_triples = Some(vec![new_record].into());
277278
}
278279

279280
Some(vec) => {
@@ -386,58 +387,171 @@ pub enum TagRelTypeChoice {
386387
Replaces,
387388
}
388389

389-
/// Collection of different types of triples describing the module characteristics
390+
/// Collection of different types of triples describing the module characteristics. It is
391+
/// **HIGHLY** recommended to use the TriplesMapBuilder, to ensure the CDDL enforcement of
392+
/// at least one field being present.
390393
#[derive(Default, Debug, Serialize, Deserialize, From, PartialEq, Eq, PartialOrd, Ord, Clone)]
391394
#[repr(C)]
392395
pub struct TriplesMap<'a> {
393396
/// Optional reference triples that link to external references
394397
#[serde(skip_serializing_if = "Option::is_none")]
395398
#[serde(rename = "0")]
396-
pub reference_triples: Option<Vec<ReferenceTripleRecord<'a>>>,
399+
pub reference_triples: Option<NonEmptyVec<ReferenceTripleRecord<'a>>>,
397400

398401
/// Optional endorsement triples that contain verification information
399402
#[serde(skip_serializing_if = "Option::is_none")]
400403
#[serde(rename = "1")]
401-
pub endorse_triples: Option<Vec<EndorsedTripleRecord<'a>>>,
404+
pub endorsed_triples: Option<NonEmptyVec<EndorsedTripleRecord<'a>>>,
402405

403406
/// Optional identity triples that provide identity information
404407
#[serde(skip_serializing_if = "Option::is_none")]
405408
#[serde(rename = "2")]
406-
pub identity_triples: Option<Vec<IdentityTripleRecord<'a>>>,
409+
pub identity_triples: Option<NonEmptyVec<IdentityTripleRecord<'a>>>,
407410

408411
/// Optional attestation key triples containing cryptographic keys
409412
#[serde(skip_serializing_if = "Option::is_none")]
410413
#[serde(rename = "3")]
411-
pub attest_key_triples: Option<Vec<AttestKeyTripleRecord<'a>>>,
414+
pub attest_key_triples: Option<NonEmptyVec<AttestKeyTripleRecord<'a>>>,
412415

413416
/// Optional domain dependency triples describing relationships between domains
414417
#[serde(skip_serializing_if = "Option::is_none")]
415418
#[serde(rename = "4")]
416-
pub dependency_triples: Option<Vec<DomainDependencyTripleRecord<'a>>>,
419+
pub dependency_triples: Option<NonEmptyVec<DomainDependencyTripleRecord<'a>>>,
417420

418421
/// Optional domain membership triples describing domain associations
419422
#[serde(skip_serializing_if = "Option::is_none")]
420423
#[serde(rename = "5")]
421-
pub membership_triples: Option<Vec<DomainMembershipTripleRecord<'a>>>,
424+
pub membership_triples: Option<NonEmptyVec<DomainMembershipTripleRecord<'a>>>,
422425

423426
/// Optional SWID triples containing software identification data
424427
#[serde(skip_serializing_if = "Option::is_none")]
425428
#[serde(rename = "6")]
426-
pub coswid_triples: Option<Vec<CoswidTripleRecord<'a>>>,
429+
pub coswid_triples: Option<NonEmptyVec<CoswidTripleRecord<'a>>>,
427430

428431
/// Optional conditional endorsement series triples for complex endorsement chains
429432
#[serde(skip_serializing_if = "Option::is_none")]
430433
#[serde(rename = "8")]
431434
pub conditional_endorsement_series_triples:
432-
Option<Vec<ConditionalEndorsementSeriesTripleRecord<'a>>>,
435+
Option<NonEmptyVec<ConditionalEndorsementSeriesTripleRecord<'a>>>,
433436

434437
/// Optional conditional endorsement triples for conditional verification
435438
#[serde(skip_serializing_if = "Option::is_none")]
436439
#[serde(rename = "10")]
437-
pub conditional_endorsement_triples: Option<Vec<ConditionalEndorsementTripleRecord<'a>>>,
440+
pub conditional_endorsement_triples:
441+
Option<NonEmptyVec<ConditionalEndorsementTripleRecord<'a>>>,
438442

439443
/// Optional extensible attributes for future expansion
440444
#[serde(skip_serializing_if = "Option::is_none")]
441445
#[serde(flatten)]
442446
pub extension: Option<ExtensionMap<'a>>,
443447
}
448+
449+
#[derive(Default)]
450+
pub struct TriplesMapBuilder<'a> {
451+
reference_triples: Option<NonEmptyVec<ReferenceTripleRecord<'a>>>,
452+
endorsed_triples: Option<NonEmptyVec<EndorsedTripleRecord<'a>>>,
453+
identity_triples: Option<NonEmptyVec<IdentityTripleRecord<'a>>>,
454+
attest_key_triples: Option<NonEmptyVec<AttestKeyTripleRecord<'a>>>,
455+
dependency_triples: Option<NonEmptyVec<DomainDependencyTripleRecord<'a>>>,
456+
membership_triples: Option<NonEmptyVec<DomainMembershipTripleRecord<'a>>>,
457+
coswid_triples: Option<NonEmptyVec<CoswidTripleRecord<'a>>>,
458+
conditional_endorsement_series_triples:
459+
Option<NonEmptyVec<ConditionalEndorsementSeriesTripleRecord<'a>>>,
460+
conditional_endorsement_triples: Option<NonEmptyVec<ConditionalEndorsementTripleRecord<'a>>>,
461+
extension: Option<ExtensionMap<'a>>,
462+
}
463+
464+
impl<'a> TriplesMapBuilder<'a> {
465+
// Setter methods for each field
466+
pub fn reference_triples(mut self, value: NonEmptyVec<ReferenceTripleRecord<'a>>) -> Self {
467+
self.reference_triples = Some(value);
468+
self
469+
}
470+
471+
pub fn endorsed_triples(mut self, value: NonEmptyVec<EndorsedTripleRecord<'a>>) -> Self {
472+
self.endorsed_triples = Some(value);
473+
self
474+
}
475+
476+
pub fn identity_triples(mut self, value: NonEmptyVec<IdentityTripleRecord<'a>>) -> Self {
477+
self.identity_triples = Some(value);
478+
self
479+
}
480+
481+
pub fn attest_key_triples(mut self, value: NonEmptyVec<AttestKeyTripleRecord<'a>>) -> Self {
482+
self.attest_key_triples = Some(value);
483+
self
484+
}
485+
486+
pub fn dependency_triples(
487+
mut self,
488+
value: NonEmptyVec<DomainDependencyTripleRecord<'a>>,
489+
) -> Self {
490+
self.dependency_triples = Some(value);
491+
self
492+
}
493+
494+
pub fn membership_triples(
495+
mut self,
496+
value: NonEmptyVec<DomainMembershipTripleRecord<'a>>,
497+
) -> Self {
498+
self.membership_triples = Some(value);
499+
self
500+
}
501+
502+
pub fn coswid_triples(mut self, value: NonEmptyVec<CoswidTripleRecord<'a>>) -> Self {
503+
self.coswid_triples = Some(value);
504+
self
505+
}
506+
507+
pub fn conditional_endorsement_series_triples(
508+
mut self,
509+
value: NonEmptyVec<ConditionalEndorsementSeriesTripleRecord<'a>>,
510+
) -> Self {
511+
self.conditional_endorsement_series_triples = Some(value);
512+
self
513+
}
514+
515+
pub fn conditional_endorsement_triples(
516+
mut self,
517+
value: NonEmptyVec<ConditionalEndorsementTripleRecord<'a>>,
518+
) -> Self {
519+
self.conditional_endorsement_triples = Some(value);
520+
self
521+
}
522+
523+
pub fn extension(mut self, value: ExtensionMap<'a>) -> Self {
524+
self.extension = Some(value);
525+
self
526+
}
527+
528+
/// Builds the TriplesMap, returning an error if no fields are set
529+
pub fn build(self) -> Result<TriplesMap<'a>> {
530+
if self.reference_triples.is_none()
531+
&& self.endorsed_triples.is_none()
532+
&& self.identity_triples.is_none()
533+
&& self.attest_key_triples.is_none()
534+
&& self.dependency_triples.is_none()
535+
&& self.membership_triples.is_none()
536+
&& self.coswid_triples.is_none()
537+
&& self.conditional_endorsement_series_triples.is_none()
538+
&& self.conditional_endorsement_triples.is_none()
539+
&& self.extension.is_none()
540+
{
541+
return Err(ComidError::EmptyTriplesMap)?;
542+
}
543+
544+
Ok(TriplesMap {
545+
reference_triples: self.reference_triples,
546+
endorsed_triples: self.endorsed_triples,
547+
identity_triples: self.identity_triples,
548+
attest_key_triples: self.attest_key_triples,
549+
dependency_triples: self.dependency_triples,
550+
membership_triples: self.membership_triples,
551+
coswid_triples: self.coswid_triples,
552+
conditional_endorsement_series_triples: self.conditional_endorsement_series_triples,
553+
conditional_endorsement_triples: self.conditional_endorsement_triples,
554+
extension: self.extension,
555+
})
556+
}
557+
}

src/core.rs

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@
3737
//! This module implements core functionality as specified in the IETF CoRIM specification
3838
//! and related standards (RFC 8152 for COSE structures).
3939
40-
use std::{borrow::Cow, collections::BTreeMap};
40+
use std::{
41+
borrow::Cow,
42+
collections::BTreeMap,
43+
ops::{Deref, DerefMut},
44+
};
4145

4246
use derive_more::{AsMut, AsRef, Constructor, From, TryFrom};
4347
use serde::{Deserialize, Serialize};
@@ -137,6 +141,64 @@ generate_tagged!(
137141
(563, TaggedMaskedRawValue, MaskedRawValue, "Represents a masked raw value with its mask"),
138142
);
139143

144+
#[derive(Debug, Serialize, Deserialize, From, PartialEq, Eq, PartialOrd, Ord, Clone)]
145+
pub struct NonEmptyVec<T>(Vec<T>);
146+
147+
impl<T> NonEmptyVec<T> {
148+
pub fn new(one: T, more: Vec<T>) -> Self {
149+
let mut items = Vec::with_capacity(1 + more.len());
150+
items.push(one);
151+
items.extend(more);
152+
Self(items)
153+
}
154+
155+
pub fn len(&self) -> usize {
156+
self.0.len()
157+
}
158+
159+
pub fn push(&mut self, value: T) {
160+
self.0.push(value)
161+
}
162+
}
163+
164+
impl<T> From<T> for NonEmptyVec<T> {
165+
fn from(value: T) -> Self {
166+
Self(vec![value])
167+
}
168+
}
169+
170+
impl<T: Clone> From<&[T]> for NonEmptyVec<T> {
171+
fn from(value: &[T]) -> Self {
172+
Self(value.to_vec())
173+
}
174+
}
175+
176+
impl<T> Deref for NonEmptyVec<T> {
177+
type Target = [T];
178+
179+
fn deref(&self) -> &Self::Target {
180+
&self.0
181+
}
182+
}
183+
184+
impl<T> DerefMut for NonEmptyVec<T> {
185+
fn deref_mut(&mut self) -> &mut Self::Target {
186+
&mut self.0
187+
}
188+
}
189+
190+
impl<T> AsRef<[T]> for NonEmptyVec<T> {
191+
fn as_ref(&self) -> &[T] {
192+
&self.0
193+
}
194+
}
195+
196+
impl<T> AsMut<[T]> for NonEmptyVec<T> {
197+
fn as_mut(&mut self) -> &mut [T] {
198+
&mut self.0
199+
}
200+
}
201+
140202
/// Represents a value that can be either text or bytes
141203
#[repr(C)]
142204
#[derive(Debug, Serialize, Deserialize, From, TryFrom, PartialEq, Eq, PartialOrd, Ord, Clone)]
@@ -191,6 +253,12 @@ pub enum Label<'a> {
191253
Int(Int),
192254
}
193255

256+
impl<'a> From<&'a str> for Label<'a> {
257+
fn from(value: &'a str) -> Self {
258+
Self::Text(std::borrow::Cow::Borrowed(value))
259+
}
260+
}
261+
194262
#[repr(C)]
195263
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, From, TryFrom)]
196264
#[serde(untagged)]
@@ -310,7 +378,7 @@ pub struct Digest<'a> {
310378
#[serde(untagged)]
311379
pub enum CoseKeySetOrKey<'a> {
312380
/// A set of COSE keys
313-
KeySet(Vec<CoseKey<'a>>),
381+
KeySet(NonEmptyVec<CoseKey<'a>>),
314382
/// A single COSE key
315383
Key(CoseKey<'a>),
316384
}
@@ -332,7 +400,7 @@ pub struct CoseKey<'a> {
332400
pub alg: AlgLabel<'a>,
333401
/// Allowed operations for this key
334402
#[serde(rename = "4")]
335-
pub key_ops: OneOrMore<Label<'a>>,
403+
pub key_ops: NonEmptyVec<Label<'a>>,
336404
/// Base initialization vector
337405
#[serde(rename = "5")]
338406
pub base_iv: TaggedBytes,

0 commit comments

Comments
 (0)