@@ -21,7 +21,6 @@ pub use catalyst_types::{
2121 uuid:: { Uuid , UuidV4 , UuidV7 } ,
2222} ;
2323pub use content:: Content ;
24- use coset:: { CborSerializable , TaggedCborSerializable } ;
2524use decode_context:: { CompatibilityPolicy , DecodeContext } ;
2625pub use metadata:: {
2726 ContentEncoding , ContentType , DocLocator , DocType , DocumentRef , DocumentRefs , Metadata , Section ,
@@ -31,8 +30,8 @@ pub use signature::{CatalystId, Signatures};
3130
3231use crate :: builder:: SignaturesBuilder ;
3332
34- /// A problem report content string
35- const PROBLEM_REPORT_CTX : & str = "Catalyst Signed Document" ;
33+ /// `COSE_Sign` object CBOR tag <https://datatracker.ietf.org/doc/html/rfc8152#page-8>
34+ const COSE_SIGN_CBOR_TAG : minicbor :: data :: Tag = minicbor :: data :: Tag :: new ( 98 ) ;
3635
3736/// Inner type that holds the Catalyst Signed Document with parsing errors.
3837#[ derive( Debug ) ]
@@ -212,34 +211,51 @@ impl CatalystSignedDocument {
212211
213212impl Decode < ' _ , ( ) > for CatalystSignedDocument {
214213 fn decode ( d : & mut Decoder < ' _ > , _ctx : & mut ( ) ) -> Result < Self , decode:: Error > {
215- let start = d. position ( ) ;
216- d. skip ( ) ?;
217- let end = d. position ( ) ;
218- let cose_bytes = d
219- . input ( )
220- . get ( start..end)
221- . ok_or ( minicbor:: decode:: Error :: end_of_input ( ) ) ?;
222-
223- let cose_sign = coset:: CoseSign :: from_tagged_slice ( cose_bytes)
224- . or_else ( |_| coset:: CoseSign :: from_slice ( cose_bytes) )
225- . map_err ( |e| {
226- minicbor:: decode:: Error :: message ( format ! ( "Invalid COSE Sign document: {e}" ) )
227- } ) ?;
228-
229- let mut report = ProblemReport :: new ( PROBLEM_REPORT_CTX ) ;
214+ let mut report = ProblemReport :: new ( "Catalyst Signed Document Decoding" ) ;
230215 let mut ctx = DecodeContext {
231216 compatibility_policy : CompatibilityPolicy :: Accept ,
232217 report : & mut report,
233218 } ;
234- let metadata = Metadata :: from_protected_header ( & cose_sign. protected , & mut ctx) ;
235- let signatures = Signatures :: from_cose_sig_list ( & cose_sign. signatures , & report) ;
219+ let start = d. position ( ) ;
236220
237- let content = if let Some ( payload) = cose_sign. payload {
238- payload. into ( )
221+ if let Ok ( tag) = d. tag ( ) {
222+ if tag != COSE_SIGN_CBOR_TAG {
223+ return Err ( minicbor:: decode:: Error :: message ( format ! (
224+ "Must be equal to the COSE_Sign tag value: {COSE_SIGN_CBOR_TAG}"
225+ ) ) ) ;
226+ }
239227 } else {
240- report. missing_field ( "COSE Sign Payload" , "Missing document content (payload)" ) ;
241- Content :: default ( )
242- } ;
228+ d. set_position ( start) ;
229+ }
230+
231+ if !matches ! ( d. array( ) ?, Some ( 4 ) ) {
232+ return Err ( minicbor:: decode:: Error :: message (
233+ "Must be a definite size array of 4 elements" ,
234+ ) ) ;
235+ }
236+
237+ let metadata_bytes = d. bytes ( ) ?;
238+ let metadata = Metadata :: decode ( & mut minicbor:: Decoder :: new ( metadata_bytes) , & mut ctx) ?;
239+
240+ // empty unprotected headers
241+ let mut map =
242+ cbork_utils:: deterministic_helper:: decode_map_deterministically ( d) ?. into_iter ( ) ;
243+ if map. next ( ) . is_some ( ) {
244+ ctx. report . unknown_field (
245+ "unprotected headers" ,
246+ "non empty unprotected headers" ,
247+ "COSE unprotected headers must be empty" ,
248+ ) ;
249+ }
250+
251+ let content = Content :: decode ( d, & mut ( ) ) ?;
252+ let signatures = Signatures :: decode ( d, & mut ctx) ?;
253+
254+ let end = d. position ( ) ;
255+ let cose_bytes = d
256+ . input ( )
257+ . get ( start..end)
258+ . ok_or ( minicbor:: decode:: Error :: end_of_input ( ) ) ?;
243259
244260 Ok ( InnerCatalystSignedDocument {
245261 metadata,
0 commit comments