diff --git a/rust/signed_doc/Cargo.toml b/rust/signed_doc/Cargo.toml index 7c2412a40e..b6a8c8f06a 100644 --- a/rust/signed_doc/Cargo.toml +++ b/rust/signed_doc/Cargo.toml @@ -12,12 +12,13 @@ workspace = true [dependencies] catalyst-types = { version = "0.0.3", path = "../catalyst-types" } +cbork-utils = { version = "0.0.1", path = "../cbork-utils" } anyhow = "1.0.95" serde = { version = "1.0.217", features = ["derive"] } serde_json = "1.0.134" -coset = "0.3.8" -minicbor = { version = "0.25.1", features = ["half"] } +coset = { version = "0.3.8", features = ["std"] } +minicbor = { version = "0.25.1", features = ["std", "half"] } brotli = "7.0.0" ed25519-dalek = { version = "2.1.1", features = ["rand_core", "pem"] } hex = "0.4.3" @@ -29,6 +30,7 @@ futures = "0.3.31" ed25519-bip32 = "0.4.1" # used by the `mk_signed_doc` cli tool tracing = "0.1.40" thiserror = "2.0.11" +indexmap = "2.9.0" [dev-dependencies] base64-url = "3.0.0" diff --git a/rust/signed_doc/bins/mk_signed_doc.rs b/rust/signed_doc/bins/mk_signed_doc.rs index a22b1ddf91..4ecdf4de53 100644 --- a/rust/signed_doc/bins/mk_signed_doc.rs +++ b/rust/signed_doc/bins/mk_signed_doc.rs @@ -9,7 +9,7 @@ use std::{ }; use anyhow::Context; -use catalyst_signed_doc::{Builder, CatalystId, CatalystSignedDocument}; +use catalyst_signed_doc::{CatalystId, CatalystSignedDocument, CoseSignBuilder}; use clap::Parser; fn main() { @@ -66,7 +66,7 @@ impl Cli { // Possibly encode if Metadata has an encoding set. let payload = serde_json::to_vec(&json_doc)?; // Start with no signatures. - let signed_doc = Builder::new() + let signed_doc = CoseSignBuilder::new() .with_decoded_content(payload) .with_json_metadata(metadata)? .build(); diff --git a/rust/signed_doc/src/builder.rs b/rust/signed_doc/src/builder.rs deleted file mode 100644 index 6efdca778d..0000000000 --- a/rust/signed_doc/src/builder.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Catalyst Signed Document Builder. -use catalyst_types::{catalyst_id::CatalystId, problem_report::ProblemReport}; - -use crate::{ - signature::Signature, CatalystSignedDocument, Content, InnerCatalystSignedDocument, Metadata, - Signatures, PROBLEM_REPORT_CTX, -}; - -/// Catalyst Signed Document Builder. -#[derive(Debug)] -pub struct Builder(InnerCatalystSignedDocument); - -impl Default for Builder { - fn default() -> Self { - Self::new() - } -} - -impl Builder { - /// Start building a signed document - #[must_use] - pub fn new() -> Self { - let report = ProblemReport::new(PROBLEM_REPORT_CTX); - Self(InnerCatalystSignedDocument { - report, - metadata: Metadata::default(), - content: Content::default(), - signatures: Signatures::default(), - raw_bytes: None, - }) - } - - /// Set document metadata in JSON format - /// Collect problem report if some fields are missing. - /// - /// # Errors - /// - Fails if it is invalid metadata fields JSON object. - pub fn with_json_metadata(mut self, json: serde_json::Value) -> anyhow::Result { - let metadata = serde_json::from_value(json)?; - self.0.metadata = Metadata::from_metadata_fields(metadata, &self.0.report); - Ok(self) - } - - /// Set decoded (original) document content bytes - #[must_use] - pub fn with_decoded_content(mut self, content: Vec) -> Self { - self.0.content = Content::from_decoded(content); - self - } - - /// Add a signature to the document - /// - /// # Errors - /// - /// Fails if a `CatalystSignedDocument` cannot be created due to missing metadata or - /// content, due to malformed data, or when the signed document cannot be - /// converted into `coset::CoseSign`. - pub fn add_signature( - mut self, sign_fn: impl FnOnce(Vec) -> Vec, kid: &CatalystId, - ) -> anyhow::Result { - let cose_sign = self - .0 - .as_cose_sign() - .map_err(|e| anyhow::anyhow!("Failed to sign: {e}"))?; - - let protected_header = coset::HeaderBuilder::new().key_id(kid.to_string().into_bytes()); - - let mut signature = coset::CoseSignatureBuilder::new() - .protected(protected_header.build()) - .build(); - let data_to_sign = cose_sign.tbs_data(&[], &signature); - signature.signature = sign_fn(data_to_sign); - if let Some(sign) = Signature::from_cose_sig(signature, &self.0.report) { - self.0.signatures.push(sign); - } - - Ok(self) - } - - /// Build a signed document with the collected error report. - /// Could provide an invalid document. - #[must_use] - pub fn build(self) -> CatalystSignedDocument { - self.0.into() - } -} - -impl From<&CatalystSignedDocument> for Builder { - fn from(value: &CatalystSignedDocument) -> Self { - Self(InnerCatalystSignedDocument { - metadata: value.inner.metadata.clone(), - content: value.inner.content.clone(), - signatures: value.inner.signatures.clone(), - report: value.inner.report.clone(), - raw_bytes: None, - }) - } -} diff --git a/rust/signed_doc/src/cose_sign/helpers.rs b/rust/signed_doc/src/cose_sign/helpers.rs new file mode 100644 index 0000000000..a5f849942a --- /dev/null +++ b/rust/signed_doc/src/cose_sign/helpers.rs @@ -0,0 +1,101 @@ +use minicbor::{ + bytes::{ByteArray, ByteSlice}, + data::Tagged, + Encode as _, +}; + +use super::VecEncodeError; + +/// Encode headers using the provided cbor-encoded key-value pairs, +/// conforming to the [RFC 8152 specification](https://datatracker.ietf.org/doc/html/rfc8152#autoid-8). +pub fn encode_headers<'a, I>(iter: I) -> Vec +where I: IntoIterator { + let mut encoder = minicbor::Encoder::new(vec![]); + + let iter = iter.into_iter(); + let map_len = u64::try_from(iter.len()).unwrap_or(u64::MAX); + encoder.map(map_len); + + for (encoded_key, encoded_v) in iter { + // Writing a pre-encoded field of the map. + encoder.writer_mut().extend_from_slice(encoded_key); + encoder.writer_mut().extend_from_slice(encoded_v); + } + + encoder.into_writer() +} + +/// Encode a single protected `kid` header for the COSE Signature. +/// +/// # Errors +/// +/// - If encoding of the `kid` fails. +pub fn encoed_kid_header(kid: &[u8]) -> Result, VecEncodeError> { + /// The KID label as per [RFC 8152 3.1 section](https://datatracker.ietf.org/doc/html/rfc8152#section-3.1). + pub const KID_LABEL: u8 = 4; + + let mut encoder = minicbor::Encoder::new(vec![]); + // A map with a single `kid` field. + encoder.map(1u64)?.u8(KID_LABEL)?.bytes(kid)?; + Ok(encoder.into_writer()) +} + +/// Create a binary blob that will be signed. No support for unprotected headers. +/// +/// Described in [section 2 of RFC 8152](https://datatracker.ietf.org/doc/html/rfc8152#section-2). +pub fn encode_tbs_data( + protected_headers: &[u8], signature_header: &[u8], content: Option<&[u8]>, +) -> Result, VecEncodeError> { + /// The context string as per [RFC 8152 section 4.4](https://datatracker.ietf.org/doc/html/rfc8152#section-4.4). + const SIGNATURE_CONTEXT: &str = "Signature"; + + minicbor::to_vec(( + SIGNATURE_CONTEXT, + <&ByteSlice>::from(protected_headers), + <&ByteSlice>::from(signature_header), + ByteArray::from([]), // no aad. + <&ByteSlice>::from(content.unwrap_or(&[])), // allowing no payload (i.e. no content). + )) +} + +/// Encode COSE signature. +/// +/// Signature bytes should represent a cryptographic signature. +pub fn encode_cose_signature( + protected_header: &[u8], signature_bytes: &[u8], +) -> Result, VecEncodeError> { + minicbor::to_vec([ + <&ByteSlice>::from(protected_header), + <&ByteSlice>::from(signature_bytes), + ]) +} + +/// Encode an array from an iterator of pre-encoded COSE Signature items. +fn encode_cose_signature_array(signatures: S) -> Result, VecEncodeError> +where S: IntoIterator, IntoIter: ExactSizeIterator> { + let iter = signatures.into_iter(); + let array_len = u64::try_from(iter.len().saturating_add(1)).unwrap_or(u64::MAX); + let mut encoder = minicbor::Encoder::new(vec![]); + encoder.array(array_len)?; + for signature in iter { + encoder.bytes(signature.as_ref())?; + } + Ok(encoder.into_writer()) +} + +/// Make cbor-encoded tagged [RFC9052-CoseSign](https://datatracker.ietf.org/doc/html/rfc9052). +pub fn encode_cose_sign( + e: &mut minicbor::encode::Encoder, protected: &[u8], payload: Option<&[u8]>, signatures: S, +) -> Result<(), minicbor::encode::Error> +where S: IntoIterator, IntoIter: ExactSizeIterator> { + /// From the table in [section 2 of RFC 8152](https://datatracker.ietf.org/doc/html/rfc8152#section-2). + const COSE_SIGN_TAG: u64 = 98; + + let tagged_array = Tagged::::new(( + <&ByteSlice>::from(protected), + ByteArray::from([]), // unprotected. + payload.map(<&ByteSlice>::from), // allowing `NULL`. + encode_cose_signature_array(signatures).map_err(minicbor::encode::Error::custom)?, + )); + tagged_array.encode(e, &mut ()) +} diff --git a/rust/signed_doc/src/cose_sign/mod.rs b/rust/signed_doc/src/cose_sign/mod.rs new file mode 100644 index 0000000000..d4aac1d710 --- /dev/null +++ b/rust/signed_doc/src/cose_sign/mod.rs @@ -0,0 +1,175 @@ +//! Catalyst Signed Document Builder. + +/// Encoding helpers. +mod helpers; + +use std::{convert::Infallible, fmt::Debug, sync::Arc}; + +use catalyst_types::catalyst_id::CatalystId; +use helpers::{ + encode_cose_sign, encode_cose_signature, encode_headers, encode_tbs_data, encoed_kid_header, +}; +use indexmap::IndexMap; + +pub type VecEncodeError = minicbor::encode::Error; + +/// [RFC9052-CoseSign] builder without unprotected fields. +/// +/// [RFC9052-CoseSign]: https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si +#[derive(Debug, Default)] +pub struct CoseSignBuilder { + /// Mapping from encoded keys to encoded values within COSE protected header. + protected: IndexMap, Vec>, + /// Encoded COSE payload. + payload: Option>, +} + +impl CoseSignBuilder { + /// Start building a [`CoseSign`]. + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// Sets COSE payload bytes. If content is encoded, it should be aligned with the + /// encoding algorithm from the `content-encoding` field. + #[must_use] + pub fn with_payload(&mut self, payload: T) -> &mut Self + where Arc<[u8]>: From { + self.payload = Some(payload.into()); + self + } + + /// Add a protected header. + /// + /// If the key is already present, the value is updated. + /// + /// # Errors + /// + /// - Fails if it the CBOR encoding fails. + /// - Fails if the key is already present. + pub fn add_protected_header( + &mut self, ctx: &mut C, key: K, v: V, + ) -> Result<&mut Self, VecEncodeError> + where + K: minicbor::Encode + Debug, + V: minicbor::Encode, + { + let (encoded_key, encoded_v) = ( + minicbor::to_vec_with(&key, ctx)?, + minicbor::to_vec_with(v, ctx)?, + ); + let indexmap::map::Entry::Vacant(entry) = self.protected.entry(encoded_key) else { + return Err(VecEncodeError::message(format!( + "Trying to build a CoseSign with duplicate protected keys (key: {key:?})" + ))); + }; + entry.insert(encoded_v); + Ok(self) + } + + /// Wraps around [`Self::add_protected_header`]. + /// Doesn't add fields with values equal to [`Default::default`]. + pub fn add_protected_header_if_not_default( + &mut self, ctx: &mut C, key: K, v: V, + ) -> Result<&mut Self, VecEncodeError> + where + K: minicbor::Encode + Debug, + V: minicbor::Encode + Default + PartialEq, + { + if V::default() == v { + Ok(self) + } else { + self.add_protected_header(ctx, key, v) + } + } + + /// Encode [`Self::metadata`] by [`make_metadata_header`] with fields in insertion + /// order. + // Question: maybe this should be cached (e.g. frozen once filled)? + fn encode_protected_header(&self) -> Vec { + // This iterates in insertion order. + let metadata_fields = self + .protected + .iter() + .map(|(key, v)| (key.as_slice(), v.as_slice())); + encode_headers(metadata_fields) + } + + fn to_cose_sign(&self) -> CoseSign { + let protected = self.encode_protected_header(); + CoseSign { + protected, + payload: self.payload.clone(), + signatures: vec![], + } + } + + /// Add a signature. + /// + /// Returns [`CoseSign`], which implements [`minicbor::Encode`]. + /// More signatures can then be added with [`CoseSign::add_signature`]. + /// + /// # Errors + /// + /// - If CBOR encoding of the [`CatalystId`] fails. + pub fn add_signature) -> Vec>( + &self, kid: CatalystId, sign_fn: F, + ) -> Result { + let mut signer = self.to_cose_sign(); + signer.add_signature(kid, sign_fn)?; + Ok(signer) + } +} + +/// [RFC9052-CoseSign](https://datatracker.ietf.org/doc/html/rfc9052). +pub struct CoseSign { + /// Encoded COSE protected header. + protected: Vec, + /// Encoded COSE payload. + payload: Option>, + /// Encoded COSE signatures. + signatures: Vec>, +} + +impl CoseSign { + /// Start building a [`CoseSign`]. Shortcut for the [`CoseSignBuilder::new`]. + pub fn builder() -> CoseSignBuilder { + CoseSignBuilder::new() + } + + /// Add another signature to the [`CoseSign`]. + /// + /// # Errors + /// + /// - If CBOR encoding of the [`CatalystId`] fails. + pub fn add_signature) -> Vec>( + &mut self, kid: CatalystId, sign_fn: F, + ) -> Result<&mut Self, VecEncodeError> { + let kid_str = kid.to_string().into_bytes(); + let signature_header = encoed_kid_header(kid_str.as_slice())?; + + let tbs_data = + encode_tbs_data(&self.protected, &signature_header, self.payload.as_deref())?; + let signature_bytes = sign_fn(tbs_data); + + // This shouldn't fail. + let signature = encode_cose_signature(&signature_header, &signature_bytes)?; + self.signatures.push(signature); + + Ok(self) + } +} + +impl minicbor::Encode for CoseSign { + fn encode( + &self, e: &mut minicbor::Encoder, _: &mut C, + ) -> Result<(), minicbor::encode::Error> { + encode_cose_sign( + e, + &self.protected, + self.payload.as_deref(), + &self.signatures, + ) + } +} diff --git a/rust/signed_doc/src/lib.rs b/rust/signed_doc/src/lib.rs index 75e0681a48..217a377672 100644 --- a/rust/signed_doc/src/lib.rs +++ b/rust/signed_doc/src/lib.rs @@ -1,7 +1,7 @@ //! Catalyst documents signing crate -mod builder; mod content; +mod cose_sign; mod decode_context; pub mod doc_types; mod metadata; @@ -16,12 +16,13 @@ use std::{ }; use anyhow::Context; -pub use builder::Builder; pub use catalyst_types::{ problem_report::ProblemReport, uuid::{Uuid, UuidV4, UuidV7}, }; pub use content::Content; +use cose_sign::CoseSign; +pub use cose_sign::CoseSignBuilder; use coset::{CborSerializable, Header, TaggedCborSerializable}; pub use metadata::{ ContentEncoding, ContentType, DocType, DocumentRef, ExtraFields, Metadata, Section, @@ -45,10 +46,10 @@ struct InnerCatalystSignedDocument { /// the other validation errors report: ProblemReport, - /// raw CBOR bytes of the `CatalystSignedDocument` object. + /// Raw CBOR bytes of the `CatalystSignedDocument` object. /// It is important to keep them to have a consistency what comes from the decoding /// process, so we would return the same data again - raw_bytes: Option>, + raw_bytes: Vec, } /// Keep all the contents private. @@ -184,8 +185,10 @@ impl CatalystSignedDocument { /// Returns a signed document `Builder` pre-loaded with the current signed document's /// data. #[must_use] - pub fn into_builder(&self) -> Builder { - self.into() + pub fn into_builder(&self) -> CoseSignBuilder { + let mut builder = CoseSign::builder(); + // TOOD! + todo!() } } @@ -254,7 +257,7 @@ impl Decode<'_, ()> for CatalystSignedDocument { content, signatures, report, - raw_bytes: Some(cose_bytes.to_vec()), + raw_bytes: cose_bytes.to_vec(), } .into()) } @@ -264,13 +267,8 @@ impl Encode<()> for CatalystSignedDocument { fn encode( &self, e: &mut encode::Encoder, _ctx: &mut (), ) -> Result<(), encode::Error> { - let cose_sign = self.as_cose_sign().map_err(encode::Error::message)?; - let cose_bytes = cose_sign.to_tagged_vec().map_err(|e| { - minicbor::encode::Error::message(format!("Failed to encode COSE Sign document: {e}")) - })?; - e.writer_mut() - .write_all(&cose_bytes) + .write_all(&self.inner.raw_bytes) .map_err(|_| minicbor::encode::Error::message("Failed to encode to CBOR")) } } diff --git a/rust/signed_doc/src/metadata/content_encoding.rs b/rust/signed_doc/src/metadata/content_encoding.rs index d47f696e7f..afff0356ce 100644 --- a/rust/signed_doc/src/metadata/content_encoding.rs +++ b/rust/signed_doc/src/metadata/content_encoding.rs @@ -1,16 +1,29 @@ //! Document Payload Content Encoding. -use std::{ - fmt::{Display, Formatter}, - str::FromStr, -}; +use serde::{Deserialize, Serialize}; +use strum::{Display, EnumString, IntoStaticStr, VariantArray}; -use serde::{de, Deserialize, Deserializer}; +use super::utils::transcode_ciborium_with; /// IANA `CoAP` Content Encoding. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +// TODO: add custom parse error type when the [strum issue]([`issue`](https://github.com/Peternator7/strum/issues/430)) fix is merged. +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + VariantArray, + EnumString, + Display, + IntoStaticStr, + Serialize, + Deserialize, +)] +#[serde(try_from = "&str", into = "&str")] pub enum ContentEncoding { /// Brotli compression.format. + #[strum(to_string = "br")] Brotli, } @@ -43,44 +56,38 @@ impl ContentEncoding { }, } } -} -impl Display for ContentEncoding { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - Self::Brotli => write!(f, "br"), - } + /// An error returned on [`minicbor::Decode::decode`] failure. + fn decode_error(input: &str) -> minicbor::decode::Error { + minicbor::decode::Error::message(format!( + "Unsupported Content Type {input:?}, Supported only: {:?}", + ContentEncoding::VARIANTS + .iter() + .map(<&str>::from) + .collect::>() + )) } } -impl FromStr for ContentEncoding { - type Err = anyhow::Error; - - fn from_str(encoding: &str) -> Result { - match encoding { - "br" => Ok(ContentEncoding::Brotli), - _ => anyhow::bail!("Unsupported Content Encoding: {encoding:?}"), - } +impl minicbor::Encode for ContentEncoding { + fn encode( + &self, e: &mut minicbor::Encoder, _: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.str(<&str>::from(self))?.ok() } } -impl<'de> Deserialize<'de> for ContentEncoding { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - let s = String::deserialize(deserializer)?; - FromStr::from_str(&s).map_err(de::Error::custom) +impl<'b, C> minicbor::Decode<'b, C> for ContentEncoding { + fn decode(d: &mut minicbor::Decoder<'b>, _: &mut C) -> Result { + let s = d.str()?; + s.parse().map_err(|_| Self::decode_error(s)) } } impl TryFrom<&coset::cbor::Value> for ContentEncoding { - type Error = anyhow::Error; + type Error = minicbor::decode::Error; - fn try_from(val: &coset::cbor::Value) -> anyhow::Result { - match val.as_text() { - Some(encoding) => encoding.parse(), - None => { - anyhow::bail!("Expected Content Encoding to be a string"); - }, - } + fn try_from(val: &coset::cbor::Value) -> Result { + transcode_ciborium_with(val, &mut ()) } } diff --git a/rust/signed_doc/src/metadata/content_type.rs b/rust/signed_doc/src/metadata/content_type.rs index b72cb4b9c2..075af84845 100644 --- a/rust/signed_doc/src/metadata/content_type.rs +++ b/rust/signed_doc/src/metadata/content_type.rs @@ -1,20 +1,32 @@ //! Document Payload Content Type. -use std::{ - fmt::{Display, Formatter}, - str::FromStr, -}; +use serde::{Deserialize, Serialize}; +use strum::{Display as EnumDisplay, EnumString, IntoStaticStr, VariantArray}; -use coset::iana::CoapContentFormat; -use serde::{de, Deserialize, Deserializer}; -use strum::VariantArray; +use super::utils::{transcode_ciborium_with, transcode_coset_with}; /// Payload Content Type. -#[derive(Debug, Copy, Clone, PartialEq, Eq, VariantArray)] +// TODO: add custom parse error type when the [strum issue]([`issue`](https://github.com/Peternator7/strum/issues/430)) fix is merged. +#[derive( + Debug, + Copy, + Clone, + PartialEq, + Eq, + VariantArray, + EnumString, + EnumDisplay, + IntoStaticStr, + Serialize, + Deserialize, +)] +#[serde(try_from = "&str", into = "&str")] pub enum ContentType { /// 'application/cbor' + #[strum(to_string = "application/cbor")] Cbor, /// 'application/json' + #[strum(to_string = "application/json")] Json, } @@ -35,77 +47,55 @@ impl ContentType { } Ok(()) } -} -impl Display for ContentType { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - Self::Cbor => write!(f, "application/cbor"), - Self::Json => write!(f, "application/json"), - } + /// An error returned on [`minicbor::Decode::decode`] failure. + fn decode_error(input: &str) -> minicbor::decode::Error { + minicbor::decode::Error::message(format!( + "Unsupported Content Type {input:?}, Supported only: {:?}", + ContentType::VARIANTS + .iter() + .map(<&str>::from) + .collect::>() + )) } } -impl FromStr for ContentType { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s { - "application/cbor" => Ok(Self::Cbor), - "application/json" => Ok(Self::Json), - _ => { - anyhow::bail!( - "Unsupported Content Type: {s:?}, Supported only: {:?}", - ContentType::VARIANTS - .iter() - .map(ToString::to_string) - .collect::>() - ) - }, - } +impl minicbor::Encode for ContentType { + fn encode( + &self, e: &mut minicbor::Encoder, _: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.str(<&str>::from(self))?.ok() } } -impl<'de> Deserialize<'de> for ContentType { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - let s = String::deserialize(deserializer)?; - FromStr::from_str(&s).map_err(de::Error::custom) +impl<'b, C> minicbor::Decode<'b, C> for ContentType { + fn decode(d: &mut minicbor::Decoder<'b>, _: &mut C) -> Result { + let s = d.str()?; + s.parse().map_err(|_| Self::decode_error(s)) } } -impl From for CoapContentFormat { - fn from(value: ContentType) -> Self { - match value { - ContentType::Cbor => Self::Cbor, - ContentType::Json => Self::Json, - } +impl TryFrom<&coset::cbor::Value> for ContentType { + type Error = minicbor::decode::Error; + + fn try_from(val: &coset::cbor::Value) -> Result { + transcode_ciborium_with(val, &mut ()) } } -impl TryFrom<&coset::ContentType> for ContentType { - type Error = anyhow::Error; - - fn try_from(value: &coset::ContentType) -> Result { - let content_type = match value { - coset::ContentType::Assigned(CoapContentFormat::Json) => ContentType::Json, - coset::ContentType::Assigned(CoapContentFormat::Cbor) => ContentType::Cbor, - _ => { - anyhow::bail!( - "Unsupported Content Type {value:?}, Supported only: {:?}", - ContentType::VARIANTS - .iter() - .map(ToString::to_string) - .collect::>() - ) - }, - }; - Ok(content_type) +type CosetLabel = coset::RegisteredLabel; + +impl TryFrom<&CosetLabel> for ContentType { + type Error = minicbor::decode::Error; + + fn try_from(val: &CosetLabel) -> Result { + transcode_coset_with(val.clone(), &mut ()) } } - #[cfg(test)] mod tests { + use std::str::FromStr as _; + use super::*; #[test] diff --git a/rust/signed_doc/src/metadata/document_ref.rs b/rust/signed_doc/src/metadata/document_ref.rs index 00e0bba241..d01f2219e1 100644 --- a/rust/signed_doc/src/metadata/document_ref.rs +++ b/rust/signed_doc/src/metadata/document_ref.rs @@ -2,12 +2,13 @@ use std::fmt::Display; -use coset::cbor::Value; +use catalyst_types::uuid::CborContext; +use cbork_utils::decode_helper; -use super::{utils::CborUuidV7, UuidV7}; +use super::{utils::transcode_ciborium_with, UuidV7}; /// Reference to a Document. -#[derive(Copy, Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Copy, Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)] pub struct DocumentRef { /// Reference to the Document Id pub id: UuidV7, @@ -21,35 +22,35 @@ impl Display for DocumentRef { } } -impl TryFrom for Value { - type Error = anyhow::Error; +impl minicbor::Encode for DocumentRef { + fn encode( + &self, e: &mut minicbor::Encoder, ctx: &mut CborContext, + ) -> Result<(), minicbor::encode::Error> { + [self.id, self.ver].encode(e, ctx) + } +} - fn try_from(value: DocumentRef) -> Result { - Ok(Value::Array(vec![ - Value::try_from(CborUuidV7(value.id))?, - Value::try_from(CborUuidV7(value.ver))?, - ])) +impl minicbor::Decode<'_, CborContext> for DocumentRef { + fn decode( + d: &mut minicbor::Decoder, ctx: &mut CborContext, + ) -> Result { + let (id, ver): (UuidV7, UuidV7) = + decode_helper::decode_helper(d, "document reference", ctx).map_err(|err| { + err.with_message("Document Reference array of two UUIDs was expected") + })?; + if ver < id { + return Err(minicbor::decode::Error::message( + "Document Reference Version can never be smaller than its ID", + )); + } + Ok(Self { id, ver }) } } -impl TryFrom<&Value> for DocumentRef { - type Error = anyhow::Error; - - #[allow(clippy::indexing_slicing)] - fn try_from(val: &Value) -> anyhow::Result { - let Some(array) = val.as_array() else { - anyhow::bail!("Document Reference must be either a single UUID or an array of two"); - }; - anyhow::ensure!( - array.len() == 2, - "Document Reference array of two UUIDs was expected" - ); - let CborUuidV7(id) = CborUuidV7::try_from(&array[0])?; - let CborUuidV7(ver) = CborUuidV7::try_from(&array[1])?; - anyhow::ensure!( - ver >= id, - "Document Reference Version can never be smaller than its ID" - ); - Ok(DocumentRef { id, ver }) +impl TryFrom<&coset::cbor::Value> for DocumentRef { + type Error = minicbor::decode::Error; + + fn try_from(val: &coset::cbor::Value) -> Result { + transcode_ciborium_with(val, &mut CborContext::Tagged) } } diff --git a/rust/signed_doc/src/metadata/extra_fields.rs b/rust/signed_doc/src/metadata/extra_fields.rs index 855e0a1832..f012789d57 100644 --- a/rust/signed_doc/src/metadata/extra_fields.rs +++ b/rust/signed_doc/src/metadata/extra_fields.rs @@ -1,12 +1,14 @@ //! Catalyst Signed Document Extra Fields. use catalyst_types::problem_report::ProblemReport; -use coset::{cbor::Value, Label, ProtectedHeader}; +use coset::{Label, ProtectedHeader}; +use serde::{Deserialize, Serialize}; use super::{ cose_protected_header_find, utils::decode_document_field_from_protected_header, DocumentRef, Section, }; +use crate::cose_sign::VecEncodeError; /// `ref` field COSE key value const REF_KEY: &str = "ref"; @@ -30,7 +32,7 @@ const CATEGORY_ID_KEY: &str = "category_id"; /// Extra Metadata Fields. /// /// These values are extracted from the COSE Sign protected header labels. -#[derive(Clone, Default, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct ExtraFields { /// Reference to the latest document. #[serde(rename = "ref", skip_serializing_if = "Option::is_none")] @@ -89,38 +91,6 @@ impl ExtraFields { self.parameters } - /// Fill the COSE header `ExtraFields` data into the header builder. - pub(super) fn fill_cose_header_fields( - &self, mut builder: coset::HeaderBuilder, - ) -> anyhow::Result { - if let Some(doc_ref) = &self.doc_ref { - builder = builder.text_value(REF_KEY.to_string(), Value::try_from(*doc_ref)?); - } - if let Some(template) = &self.template { - builder = builder.text_value(TEMPLATE_KEY.to_string(), Value::try_from(*template)?); - } - if let Some(reply) = &self.reply { - builder = builder.text_value(REPLY_KEY.to_string(), Value::try_from(*reply)?); - } - - if let Some(section) = &self.section { - builder = builder.text_value(SECTION_KEY.to_string(), Value::from(section.clone())); - } - - if !self.collabs.is_empty() { - builder = builder.text_value( - COLLABS_KEY.to_string(), - Value::Array(self.collabs.iter().cloned().map(Value::Text).collect()), - ); - } - - if let Some(parameters) = &self.parameters { - builder = builder.text_value(PARAMETERS_KEY.to_string(), Value::try_from(*parameters)?); - } - - Ok(builder) - } - /// Converting COSE Protected Header to `ExtraFields`. pub(crate) fn from_protected_header( protected: &ProtectedHeader, error_report: &ProblemReport, @@ -223,6 +193,26 @@ impl ExtraFields { extra } + + /// Add [`Self`] fields to the builder as protected headers. + /// + /// # Errors + /// + /// - If encoding of one of the fields fails, [`crate::CoseSignBuilder`] becomes + /// corrupt and an error is returned + #[allow(const_item_mutation, reason = "expected")] + pub(crate) fn fill_cose_sign_builder<'a>( + &self, uuid_ctx: &mut catalyst_types::uuid::CborContext, + builder: &'a mut crate::CoseSignBuilder, + ) -> Result<&'a mut crate::CoseSignBuilder, VecEncodeError> { + builder.add_protected_header_if_not_default(uuid_ctx, REF_KEY, self.doc_ref())?; + builder.add_protected_header_if_not_default(uuid_ctx, TEMPLATE_KEY, self.template())?; + builder.add_protected_header_if_not_default(uuid_ctx, REPLY_KEY, self.reply())?; + builder.add_protected_header_if_not_default(&mut (), SECTION_KEY, self.section())?; + builder.add_protected_header_if_not_default(&mut (), COLLABS_KEY, self.collabs())?; + builder.add_protected_header_if_not_default(uuid_ctx, PARAMETERS_KEY, self.parameters())?; + builder.add_protected_header_if_not_default(uuid_ctx, PARAMETERS_KEY, self.parameters()) + } } #[cfg(test)] diff --git a/rust/signed_doc/src/metadata/mod.rs b/rust/signed_doc/src/metadata/mod.rs index 8597f8ba7f..c6d331bd65 100644 --- a/rust/signed_doc/src/metadata/mod.rs +++ b/rust/signed_doc/src/metadata/mod.rs @@ -15,7 +15,6 @@ use catalyst_types::{ }; pub use content_encoding::ContentEncoding; pub use content_type::ContentType; -use coset::{cbor::Value, iana::CoapContentFormat}; pub use doc_type::DocType; pub use document_ref::DocumentRef; pub use extra_fields::ExtraFields; @@ -24,6 +23,8 @@ use utils::{ cose_protected_header_find, decode_document_field_from_protected_header, CborUuidV4, CborUuidV7, }; +use crate::cose_sign::VecEncodeError; + /// `content_encoding` field COSE key value const CONTENT_ENCODING_KEY: &str = "Content-Encoding"; /// `doc_type` field COSE key value @@ -32,6 +33,8 @@ const TYPE_KEY: &str = "type"; const ID_KEY: &str = "id"; /// `ver` field COSE key value const VER_KEY: &str = "ver"; +/// `content_type` field COSE key value +const CONTENT_TYPE: u8 = 3; /// Document Metadata. /// @@ -138,6 +141,47 @@ impl Metadata { let metadata = InnerMetadata::from_protected_header(protected, report); Self::from_metadata_fields(metadata, report) } + + /// Add [`Self`] fields to the builder as protected headers. + pub(crate) fn fill_cose_sign_builder<'a>( + &self, uuid_ctx: &mut catalyst_types::uuid::CborContext, + builder: &'a mut crate::CoseSignBuilder, + ) -> Result<&'a mut crate::CoseSignBuilder, VecEncodeError> { + /// `content_encoding` field COSE key value + const CONTENT_ENCODING_KEY: &str = "Content-Encoding"; + /// `doc_type` field COSE key value + const TYPE_KEY: &str = "type"; + /// `id` field COSE key value + const ID_KEY: &str = "id"; + /// `ver` field COSE key value + const VER_KEY: &str = "ver"; + builder.add_protected_header( + &mut (), + CONTENT_TYPE, + self.content_type().map_err(VecEncodeError::message)?, + )?; + builder.add_protected_header_if_not_default( + &mut (), + CONTENT_ENCODING_KEY, + self.content_encoding(), + )?; + builder.add_protected_header( + uuid_ctx, + TYPE_KEY, + self.doc_type().map_err(VecEncodeError::message)?, + )?; + builder.add_protected_header( + uuid_ctx, + ID_KEY, + self.doc_id().map_err(VecEncodeError::message)?, + )?; + builder.add_protected_header( + uuid_ctx, + VER_KEY, + self.doc_ver().map_err(VecEncodeError::message)?, + )?; + self.extra().fill_cose_sign_builder(uuid_ctx, builder) + } } impl InnerMetadata { @@ -227,37 +271,3 @@ impl Display for Metadata { writeln!(f, "}}") } } - -impl TryFrom<&Metadata> for coset::Header { - type Error = anyhow::Error; - - fn try_from(meta: &Metadata) -> Result { - let mut builder = coset::HeaderBuilder::new() - .content_format(CoapContentFormat::from(meta.content_type()?)); - - if let Some(content_encoding) = meta.content_encoding() { - builder = builder.text_value( - CONTENT_ENCODING_KEY.to_string(), - format!("{content_encoding}").into(), - ); - } - - builder = builder - .text_value( - TYPE_KEY.to_string(), - Value::try_from(CborUuidV4(meta.doc_type()?))?, - ) - .text_value( - ID_KEY.to_string(), - Value::try_from(CborUuidV7(meta.doc_id()?))?, - ) - .text_value( - VER_KEY.to_string(), - Value::try_from(CborUuidV7(meta.doc_ver()?))?, - ); - - builder = meta.0.extra.fill_cose_header_fields(builder)?; - - Ok(builder.build()) - } -} diff --git a/rust/signed_doc/src/metadata/section.rs b/rust/signed_doc/src/metadata/section.rs index 01e6a02a1b..45d5c07713 100644 --- a/rust/signed_doc/src/metadata/section.rs +++ b/rust/signed_doc/src/metadata/section.rs @@ -2,11 +2,13 @@ use std::{fmt::Display, str::FromStr}; -use coset::cbor::Value; use serde::{Deserialize, Serialize}; +use super::utils::transcode_ciborium_with; + /// 'section' field type definition, which is a JSON path string -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(into = "String", try_from = "&str")] pub struct Section(jsonpath_rust::JsonPath); impl Display for Section { @@ -15,44 +17,46 @@ impl Display for Section { } } -impl Serialize for Section { - fn serialize(&self, serializer: S) -> Result - where S: serde::Serializer { - self.to_string().serialize(serializer) +impl From
for String { + fn from(value: Section) -> Self { + value.to_string() } } -impl<'de> Deserialize<'de> for Section { - fn deserialize(deserializer: D) -> Result - where D: serde::Deserializer<'de> { - let str = String::deserialize(deserializer)?; - Self::from_str(&str).map_err(serde::de::Error::custom) +impl FromStr for Section { + type Err = jsonpath_rust::JsonPathParserError; + + fn from_str(s: &str) -> Result { + s.parse().map(Self) } } -impl FromStr for Section { - type Err = anyhow::Error; +impl TryFrom<&str> for Section { + type Error = jsonpath_rust::JsonPathParserError; - fn from_str(s: &str) -> Result { - Ok(Self( - jsonpath_rust::JsonPath::::from_str(s)?, - )) + fn try_from(s: &str) -> Result { + s.parse() } } -impl From
for Value { - fn from(value: Section) -> Self { - Value::Text(value.to_string()) +impl minicbor::Encode for Section { + fn encode( + &self, e: &mut minicbor::Encoder, _: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.str(&self.0.to_string())?.ok() + } +} + +impl<'b, C> minicbor::Decode<'b, C> for Section { + fn decode(d: &mut minicbor::Decoder<'b>, _: &mut C) -> Result { + d.str()?.parse().map_err(minicbor::decode::Error::custom) } } -impl TryFrom<&Value> for Section { - type Error = anyhow::Error; +impl TryFrom<&coset::cbor::Value> for Section { + type Error = minicbor::decode::Error; - fn try_from(val: &Value) -> anyhow::Result { - let str = val - .as_text() - .ok_or(anyhow::anyhow!("Not a cbor string type"))?; - Self::from_str(str) + fn try_from(val: &coset::cbor::Value) -> Result { + transcode_ciborium_with(val, &mut ()) } } diff --git a/rust/signed_doc/src/metadata/utils.rs b/rust/signed_doc/src/metadata/utils.rs index 0e54f10c43..96dffb5524 100644 --- a/rust/signed_doc/src/metadata/utils.rs +++ b/rust/signed_doc/src/metadata/utils.rs @@ -5,6 +5,8 @@ use catalyst_types::{ uuid::{CborContext, UuidV4, UuidV7}, }; use coset::{CborSerializable, Label, ProtectedHeader}; +use minicbor::decode::Decode; +use serde::Serialize; /// Find a value for a predicate in the protected header. pub(crate) fn cose_protected_header_find( @@ -100,3 +102,33 @@ fn decode_cbor_uuid minicbor::decode::Decode<'a, CborContext>>( minicbor::decode_with(&cbor_bytes, &mut CborContext::Tagged) .map_err(|e| anyhow::anyhow!("Invalid UUID, err: {e}")) } + +/// Transcode [`ciborium`](coset::cbor) to a type implementing [`minicbor::Decode`]. +/// +/// This is rather inefficient, but allows to keep a single CBOR implementation. +pub(crate) fn transcode_ciborium_with( + value: &T, ctx: &mut C, +) -> Result +where + T: Serialize, + U: for<'a> Decode<'a, C>, +{ + let mut cbor_bytes = Vec::new(); + coset::cbor::ser::into_writer(value, &mut cbor_bytes) + .map_err(minicbor::decode::Error::custom)?; + minicbor::decode_with(&cbor_bytes, ctx) +} + +/// Transcode [`coset::CborSerializable`] to a type implementing [`minicbor::Decode`]. +/// +/// This is rather inefficient, but allows to keep a single CBOR implementation. +pub(crate) fn transcode_coset_with( + value: T, ctx: &mut C, +) -> Result +where + T: coset::CborSerializable, + U: for<'a> minicbor::decode::Decode<'a, C>, +{ + let cbor_bytes = value.to_vec().map_err(minicbor::decode::Error::custom)?; + minicbor::decode_with(&cbor_bytes, ctx) +} diff --git a/rust/signed_doc/src/validator/mod.rs b/rust/signed_doc/src/validator/mod.rs index 0c755bdcb5..e20389f981 100644 --- a/rust/signed_doc/src/validator/mod.rs +++ b/rust/signed_doc/src/validator/mod.rs @@ -362,7 +362,7 @@ mod tests { use crate::{ providers::{tests::TestCatalystSignedDocumentProvider, CatalystSignedDocumentProvider}, validator::{document_rules_init, validate_id_and_ver}, - Builder, UuidV7, + CoseSignBuilder, UuidV7, }; #[test] @@ -374,7 +374,7 @@ mod tests { .as_secs(); let uuid_v7 = UuidV7::new(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": uuid_v7.to_string(), "ver": uuid_v7.to_string() @@ -388,7 +388,7 @@ mod tests { let ver = Uuid::new_v7(Timestamp::from_unix_time(now - 1, 0, 0, 0)); let id = Uuid::new_v7(Timestamp::from_unix_time(now + 1, 0, 0, 0)); assert!(ver < id); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": id.to_string(), "ver": ver.to_string() @@ -405,7 +405,7 @@ mod tests { 0, 0, )); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": to_far_in_past.to_string(), "ver": to_far_in_past.to_string() @@ -422,7 +422,7 @@ mod tests { 0, 0, )); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": to_far_in_future.to_string(), "ver": to_far_in_future.to_string() diff --git a/rust/signed_doc/src/validator/rules/content_encoding.rs b/rust/signed_doc/src/validator/rules/content_encoding.rs index f75bcf81e3..be6986fed6 100644 --- a/rust/signed_doc/src/validator/rules/content_encoding.rs +++ b/rust/signed_doc/src/validator/rules/content_encoding.rs @@ -38,7 +38,7 @@ impl ContentEncodingRule { #[cfg(test)] mod tests { use super::*; - use crate::Builder; + use crate::CoseSignBuilder; #[tokio::test] async fn content_encoding_rule_test() { @@ -49,7 +49,7 @@ mod tests { optional: true, }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata( serde_json::json!({"content-encoding": content_encoding.to_string() }), ) @@ -57,7 +57,7 @@ mod tests { .build(); assert!(rule.check(&doc).await.unwrap()); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({})) .unwrap() .build(); diff --git a/rust/signed_doc/src/validator/rules/content_type.rs b/rust/signed_doc/src/validator/rules/content_type.rs index 26aa702fa7..364b1414ed 100644 --- a/rust/signed_doc/src/validator/rules/content_type.rs +++ b/rust/signed_doc/src/validator/rules/content_type.rs @@ -53,7 +53,7 @@ impl ContentTypeRule { #[cfg(test)] mod tests { use super::*; - use crate::Builder; + use crate::CoseSignBuilder; #[tokio::test] async fn content_type_rule_test() { @@ -61,34 +61,34 @@ mod tests { let rule = ContentTypeRule { exp: content_type }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"content-type": content_type.to_string() })) .unwrap() .with_decoded_content(serde_json::to_vec(&serde_json::json!({})).unwrap()) .build(); assert!(rule.check(&doc).await.unwrap()); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"content-type": ContentType::Cbor.to_string() })) .unwrap() .with_decoded_content(serde_json::to_vec(&serde_json::json!({})).unwrap()) .build(); assert!(!rule.check(&doc).await.unwrap()); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"content-type": content_type.to_string() })) .unwrap() .build(); assert!(!rule.check(&doc).await.unwrap()); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"content-type": content_type.to_string() })) .unwrap() .with_decoded_content(vec![]) .build(); assert!(!rule.check(&doc).await.unwrap()); - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(!rule.check(&doc).await.unwrap()); } } diff --git a/rust/signed_doc/src/validator/rules/doc_ref.rs b/rust/signed_doc/src/validator/rules/doc_ref.rs index 53fec6825f..1cb95c4cab 100644 --- a/rust/signed_doc/src/validator/rules/doc_ref.rs +++ b/rust/signed_doc/src/validator/rules/doc_ref.rs @@ -86,7 +86,7 @@ mod tests { use catalyst_types::uuid::UuidV7; use super::*; - use crate::{providers::tests::TestCatalystSignedDocumentProvider, Builder}; + use crate::{providers::tests::TestCatalystSignedDocumentProvider, CoseSignBuilder}; #[tokio::test] async fn ref_rule_specified_test() { @@ -103,7 +103,7 @@ mod tests { // prepare replied documents { - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": valid_referenced_doc_id.to_string(), "ver": valid_referenced_doc_ver.to_string(), @@ -114,7 +114,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // reply doc with other `type` field - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": another_type_referenced_doc_id.to_string(), "ver": another_type_referenced_doc_ver.to_string(), @@ -125,7 +125,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // missing `type` field in the referenced document - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": missing_type_referenced_doc_id.to_string(), "ver": missing_type_referenced_doc_ver.to_string(), @@ -140,7 +140,7 @@ mod tests { exp_ref_type, optional: false, }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": {"id": valid_referenced_doc_id.to_string(), "ver": valid_referenced_doc_ver.to_string() } })) @@ -153,7 +153,7 @@ mod tests { exp_ref_type, optional: true, }; - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc, &provider).await.unwrap()); // missing `ref` field, but its required @@ -161,11 +161,11 @@ mod tests { exp_ref_type, optional: false, }; - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(!rule.check(&doc, &provider).await.unwrap()); // reference to the document with another `type` field - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": {"id": another_type_referenced_doc_id.to_string(), "ver": another_type_referenced_doc_ver.to_string() } })) @@ -174,7 +174,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // missing `type` field in the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": {"id": missing_type_referenced_doc_id.to_string(), "ver": missing_type_referenced_doc_ver.to_string() } })) @@ -183,7 +183,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // cannot find a referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": {"id": UuidV7::new().to_string(), "ver": UuidV7::new().to_string() } })) @@ -197,12 +197,12 @@ mod tests { let rule = RefRule::NotSpecified; let provider = TestCatalystSignedDocumentProvider::default(); - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc, &provider).await.unwrap()); let ref_id = UuidV7::new(); let ref_ver = UuidV7::new(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"ref": {"id": ref_id.to_string(), "ver": ref_ver.to_string() } })) .unwrap() .build(); diff --git a/rust/signed_doc/src/validator/rules/parameters.rs b/rust/signed_doc/src/validator/rules/parameters.rs index 290d158439..a600d2cbf0 100644 --- a/rust/signed_doc/src/validator/rules/parameters.rs +++ b/rust/signed_doc/src/validator/rules/parameters.rs @@ -75,7 +75,7 @@ mod tests { use catalyst_types::uuid::{UuidV4, UuidV7}; use super::*; - use crate::{providers::tests::TestCatalystSignedDocumentProvider, Builder}; + use crate::{providers::tests::TestCatalystSignedDocumentProvider, CoseSignBuilder}; #[tokio::test] async fn ref_rule_specified_test() { @@ -92,7 +92,7 @@ mod tests { // prepare replied documents { - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": valid_category_doc_id.to_string(), "ver": valid_category_doc_ver.to_string(), @@ -103,7 +103,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // reply doc with other `type` field - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": another_type_category_doc_id.to_string(), "ver": another_type_category_doc_ver.to_string(), @@ -114,7 +114,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // missing `type` field in the referenced document - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": missing_type_category_doc_id.to_string(), "ver": missing_type_category_doc_ver.to_string(), @@ -129,7 +129,7 @@ mod tests { exp_parameters_type, optional: false, }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "parameters": {"id": valid_category_doc_id.to_string(), "ver": valid_category_doc_ver } })) @@ -142,7 +142,7 @@ mod tests { exp_parameters_type, optional: true, }; - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc, &provider).await.unwrap()); // missing `parameters` field, but its required @@ -150,11 +150,11 @@ mod tests { exp_parameters_type, optional: false, }; - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(!rule.check(&doc, &provider).await.unwrap()); // reference to the document with another `type` field - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "parameters": {"id": another_type_category_doc_id.to_string(), "ver": another_type_category_doc_ver.to_string() } })) @@ -163,7 +163,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // missing `type` field in the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "parameters": {"id": missing_type_category_doc_id.to_string(), "ver": missing_type_category_doc_ver.to_string() } })) @@ -172,7 +172,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // cannot find a referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "parameters": {"id": UuidV7::new().to_string(), "ver": UuidV7::new().to_string() } })) @@ -186,12 +186,12 @@ mod tests { let rule = ParametersRule::NotSpecified; let provider = TestCatalystSignedDocumentProvider::default(); - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc, &provider).await.unwrap()); let ref_id = UuidV7::new(); let ref_ver = UuidV7::new(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"parameters": {"id": ref_id.to_string(), "ver": ref_ver.to_string() } })) .unwrap() .build(); diff --git a/rust/signed_doc/src/validator/rules/reply.rs b/rust/signed_doc/src/validator/rules/reply.rs index 5ac256667d..1c6c5817cb 100644 --- a/rust/signed_doc/src/validator/rules/reply.rs +++ b/rust/signed_doc/src/validator/rules/reply.rs @@ -95,7 +95,7 @@ mod tests { use catalyst_types::uuid::{UuidV4, UuidV7}; use super::*; - use crate::{providers::tests::TestCatalystSignedDocumentProvider, Builder}; + use crate::{providers::tests::TestCatalystSignedDocumentProvider, CoseSignBuilder}; #[allow(clippy::too_many_lines)] #[tokio::test] @@ -117,7 +117,7 @@ mod tests { // prepare replied documents { - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "id": valid_replied_doc_id.to_string(), @@ -129,7 +129,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // reply doc with other `type` field - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "id": another_type_replied_doc_id.to_string(), @@ -141,7 +141,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // missing `ref` field in the referenced document - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": missing_ref_replied_doc_id.to_string(), "ver": missing_ref_replied_doc_ver.to_string(), @@ -152,7 +152,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // missing `type` field in the referenced document - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "id": missing_type_replied_doc_id.to_string(), @@ -168,7 +168,7 @@ mod tests { exp_reply_type, optional: false, }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "reply": { "id": valid_replied_doc_id.to_string(), "ver": valid_replied_doc_ver.to_string() } @@ -182,7 +182,7 @@ mod tests { exp_reply_type, optional: true, }; - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc, &provider).await.unwrap()); // missing `reply` field, but its required @@ -190,7 +190,7 @@ mod tests { exp_reply_type, optional: false, }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, })) @@ -199,7 +199,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // missing `ref` field - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "reply": { "id": valid_replied_doc_id.to_string(), "ver": valid_replied_doc_ver.to_string() } })) @@ -208,7 +208,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // reference to the document with another `type` field - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "reply": { "id": another_type_replied_doc_id.to_string(), "ver": another_type_replied_doc_ver.to_string() } @@ -218,7 +218,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // missing `ref` field in the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "reply": { "id": missing_ref_replied_doc_id.to_string(), "ver": missing_type_replied_doc_ver.to_string() } @@ -228,7 +228,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // missing `type` field in the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "reply": { "id": missing_type_replied_doc_id.to_string(), "ver": missing_type_replied_doc_ver.to_string() } @@ -238,7 +238,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // `ref` field does not align with the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": UuidV7::new().to_string(), "ver": UuidV7::new().to_string() }, "reply": { "id": valid_replied_doc_id.to_string(), "ver": valid_replied_doc_ver.to_string() } @@ -248,7 +248,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // cannot find a referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "ref": { "id": common_ref_id.to_string(), "ver": common_ref_ver.to_string() }, "reply": {"id": UuidV7::new().to_string(), "ver": UuidV7::new().to_string() } @@ -263,12 +263,12 @@ mod tests { let rule = ReplyRule::NotSpecified; let provider = TestCatalystSignedDocumentProvider::default(); - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc, &provider).await.unwrap()); let ref_id = UuidV7::new(); let ref_ver = UuidV7::new(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"reply": {"id": ref_id.to_string(), "ver": ref_ver.to_string() } })) .unwrap() .build(); diff --git a/rust/signed_doc/src/validator/rules/section.rs b/rust/signed_doc/src/validator/rules/section.rs index 8720353425..05c2ea5e25 100644 --- a/rust/signed_doc/src/validator/rules/section.rs +++ b/rust/signed_doc/src/validator/rules/section.rs @@ -42,11 +42,11 @@ impl SectionRule { #[cfg(test)] mod tests { use super::*; - use crate::Builder; + use crate::CoseSignBuilder; #[tokio::test] async fn section_rule_specified_test() { - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "section": "$".to_string() })) @@ -55,11 +55,11 @@ mod tests { let rule = SectionRule::Specified { optional: false }; assert!(rule.check(&doc).await.unwrap()); - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); let rule = SectionRule::Specified { optional: true }; assert!(rule.check(&doc).await.unwrap()); - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); let rule = SectionRule::Specified { optional: false }; assert!(!rule.check(&doc).await.unwrap()); } @@ -68,10 +68,10 @@ mod tests { async fn section_rule_not_specified_test() { let rule = SectionRule::NotSpecified; - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc).await.unwrap()); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "section": "$".to_string() })) diff --git a/rust/signed_doc/src/validator/rules/signature_kid.rs b/rust/signed_doc/src/validator/rules/signature_kid.rs index 2e45517b8e..e4d111b94a 100644 --- a/rust/signed_doc/src/validator/rules/signature_kid.rs +++ b/rust/signed_doc/src/validator/rules/signature_kid.rs @@ -47,7 +47,7 @@ mod tests { use ed25519_dalek::ed25519::signature::Signer; use super::*; - use crate::{Builder, ContentType}; + use crate::{ContentType, CoseSignBuilder}; #[tokio::test] async fn signature_kid_rule_test() { @@ -59,7 +59,7 @@ mod tests { let pk = sk.verifying_key(); let kid = CatalystId::new("cardano", None, pk).with_role(RoleId::Role0); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_decoded_content(serde_json::to_vec(&serde_json::Value::Null).unwrap()) .with_json_metadata(serde_json::json!({ "type": UuidV4::new().to_string(), diff --git a/rust/signed_doc/src/validator/rules/template.rs b/rust/signed_doc/src/validator/rules/template.rs index 0d5b0c9aaa..344dbaed6e 100644 --- a/rust/signed_doc/src/validator/rules/template.rs +++ b/rust/signed_doc/src/validator/rules/template.rs @@ -184,7 +184,7 @@ mod tests { use catalyst_types::uuid::UuidV7; use super::*; - use crate::{providers::tests::TestCatalystSignedDocumentProvider, Builder}; + use crate::{providers::tests::TestCatalystSignedDocumentProvider, CoseSignBuilder}; #[allow(clippy::too_many_lines)] #[tokio::test] @@ -205,7 +205,7 @@ mod tests { // prepare replied documents { - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": valid_template_doc_id.to_string(), "ver": valid_template_doc_id.to_string(), @@ -218,7 +218,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // reply doc with other `type` field - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": another_type_template_doc_id.to_string(), "ver": another_type_template_doc_id.to_string(), @@ -231,7 +231,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // missing `type` field in the referenced document - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": missing_type_template_doc_id.to_string(), "ver": missing_type_template_doc_id.to_string(), @@ -243,7 +243,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // missing `content-type` field in the referenced document - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": missing_content_type_template_doc_id.to_string(), "ver": missing_content_type_template_doc_id.to_string(), @@ -255,7 +255,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // missing content - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": missing_content_template_doc_id.to_string(), "ver": missing_content_template_doc_id.to_string(), @@ -267,7 +267,7 @@ mod tests { provider.add_document(ref_doc).unwrap(); // invalid content, must be json encoded - let ref_doc = Builder::new() + let ref_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": invalid_content_template_doc_id.to_string(), "ver": invalid_content_template_doc_id.to_string(), @@ -282,7 +282,7 @@ mod tests { // all correct let rule = ContentRule::Templated { exp_template_type }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": valid_template_doc_id.to_string(), "ver": valid_template_doc_id.to_string() } })) @@ -292,7 +292,7 @@ mod tests { assert!(rule.check(&doc, &provider).await.unwrap()); // missing `template` field, but its required - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({})) .unwrap() .with_decoded_content(json_content.clone()) @@ -301,7 +301,7 @@ mod tests { // missing content let rule = ContentRule::Templated { exp_template_type }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": valid_template_doc_id.to_string(), "ver": valid_template_doc_id.to_string() } })) @@ -311,7 +311,7 @@ mod tests { // content not a json encoded let rule = ContentRule::Templated { exp_template_type }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": valid_template_doc_id.to_string(), "ver": valid_template_doc_id.to_string() } })) @@ -321,7 +321,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // reference to the document with another `type` field - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": another_type_template_doc_id.to_string(), "ver": another_type_template_doc_id.to_string() } })) @@ -331,7 +331,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // missing `type` field in the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": missing_type_template_doc_id.to_string(), "ver": missing_type_template_doc_id.to_string() } })) @@ -342,7 +342,7 @@ mod tests { // missing `content-type` field in the referenced doc let rule = ContentRule::Templated { exp_template_type }; - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": missing_content_type_template_doc_id.to_string(), "ver": missing_content_type_template_doc_id.to_string() } })) @@ -352,7 +352,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // missing content in the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": missing_content_template_doc_id.to_string(), "ver": missing_content_template_doc_id.to_string() } })) @@ -362,7 +362,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // content not a json encoded in the referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": invalid_content_template_doc_id.to_string(), "ver": invalid_content_template_doc_id.to_string() } })) @@ -372,7 +372,7 @@ mod tests { assert!(!rule.check(&doc, &provider).await.unwrap()); // cannot find a referenced document - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "template": {"id": UuidV7::new().to_string(), "ver": UuidV7::new().to_string() } })) @@ -397,23 +397,23 @@ mod tests { // all correct let rule = ContentRule::Static(json_schema); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_decoded_content(json_content.clone()) .build(); assert!(rule.check(&doc, &provider).await.unwrap()); // missing content - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(!rule.check(&doc, &provider).await.unwrap()); // content not a json encoded - let doc = Builder::new().with_decoded_content(vec![]).build(); + let doc = CoseSignBuilder::new().with_decoded_content(vec![]).build(); assert!(!rule.check(&doc, &provider).await.unwrap()); // defined `template` field which should be absent let ref_id = UuidV7::new(); let ref_ver = UuidV7::new(); - let doc = Builder::new().with_decoded_content(json_content) + let doc = CoseSignBuilder::new().with_decoded_content(json_content) .with_json_metadata(serde_json::json!({"template": {"id": ref_id.to_string(), "ver": ref_ver.to_string() } })) .unwrap() .build(); @@ -425,13 +425,13 @@ mod tests { let rule = ContentRule::NotSpecified; let provider = TestCatalystSignedDocumentProvider::default(); - let doc = Builder::new().build(); + let doc = CoseSignBuilder::new().build(); assert!(rule.check(&doc, &provider).await.unwrap()); // defined `template` field which should be absent let ref_id = UuidV7::new(); let ref_ver = UuidV7::new(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({"template": {"id": ref_id.to_string(), "ver": ref_ver.to_string() } })) .unwrap() .build(); diff --git a/rust/signed_doc/tests/comment.rs b/rust/signed_doc/tests/comment.rs index 1c746e589c..30eca79e17 100644 --- a/rust/signed_doc/tests/comment.rs +++ b/rust/signed_doc/tests/comment.rs @@ -54,7 +54,7 @@ async fn test_valid_comment_doc_with_reply() { let comment_doc_id = UuidV7::new(); let comment_doc_ver = UuidV7::new(); - let comment_doc = Builder::new() + let comment_doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "id": comment_doc_id, "ver": comment_doc_ver, diff --git a/rust/signed_doc/tests/common/mod.rs b/rust/signed_doc/tests/common/mod.rs index d7ea84150b..1293cdd57c 100644 --- a/rust/signed_doc/tests/common/mod.rs +++ b/rust/signed_doc/tests/common/mod.rs @@ -52,7 +52,7 @@ pub fn create_dummy_doc( let doc_id = UuidV7::new(); let doc_ver = UuidV7::new(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "content-type": ContentType::Json.to_string(), "type": doc_type_id, @@ -80,7 +80,7 @@ pub fn create_dummy_signed_doc( )> { let (sk, pk, kid) = create_dummy_key_pair(with_role_index)?; - let signed_doc = Builder::new() + let signed_doc = CoseSignBuilder::new() .with_decoded_content(content) .with_json_metadata(metadata)? .add_signature(|m| sk.sign(&m).to_vec(), &kid)? diff --git a/rust/signed_doc/tests/decoding.rs b/rust/signed_doc/tests/decoding.rs index 18697703c2..70167b76cf 100644 --- a/rust/signed_doc/tests/decoding.rs +++ b/rust/signed_doc/tests/decoding.rs @@ -17,7 +17,7 @@ fn catalyst_signed_doc_cbor_roundtrip_kid_as_id_test() { let content = serde_json::to_vec(&serde_json::Value::Null).unwrap(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(metadata_fields.clone()) .unwrap() .with_decoded_content(content.clone()) @@ -38,7 +38,7 @@ async fn catalyst_signed_doc_parameters_aliases_test() { let content = serde_json::to_vec(&serde_json::Value::Null).unwrap(); - let doc = Builder::new() + let doc = CoseSignBuilder::new() .with_json_metadata(metadata_fields.clone()) .unwrap() .with_decoded_content(content.clone()) @@ -188,7 +188,7 @@ fn signed_doc_with_all_fields_case() -> TestCase { bytes_gen: Box::new({ let kid = kid.clone(); move || { - Builder::new() + CoseSignBuilder::new() .with_json_metadata(serde_json::json!({ "content-type": ContentType::Json.to_string(), "content-encoding": ContentEncoding::Brotli.to_string(), diff --git a/rust/signed_doc/tests/signature.rs b/rust/signed_doc/tests/signature.rs index 5c93ec25bb..ed7ac1faf6 100644 --- a/rust/signed_doc/tests/signature.rs +++ b/rust/signed_doc/tests/signature.rs @@ -46,7 +46,7 @@ async fn multiple_signatures_validation_test() { let (sk3, pk3, kid3) = common::create_dummy_key_pair(RoleId::Role0).unwrap(); let (_, pk_n, kid_n) = common::create_dummy_key_pair(RoleId::Role0).unwrap(); - let signed_doc = Builder::new() + let signed_doc = CoseSignBuilder::new() .with_decoded_content(serde_json::to_vec(&serde_json::Value::Null).unwrap()) .with_json_metadata(common::test_metadata().2) .unwrap()