diff --git a/src/encrypt/mod.rs b/src/encrypt/mod.rs index db38de5..b5f5a98 100644 --- a/src/encrypt/mod.rs +++ b/src/encrypt/mod.rs @@ -496,7 +496,9 @@ pub fn enc_structure_data( ) -> Vec { let arr = vec![ Value::Text(context.text().to_owned()), - protected.cbor_bstr().expect("failed to serialize header"), // safe: always serializable + protected + .to_be_authenticated() + .expect("failed to serialize header"), // safe: always serializable Value::Bytes(external_aad.to_vec()), ]; diff --git a/src/header/mod.rs b/src/header/mod.rs index c19835f..12df533 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -385,6 +385,21 @@ impl ProtectedHeader { )) } + /// Convert this protected header into a [`Value`] that represents the binary data used for + /// authentication (i.e. for inclusion in `Sig_structure`, `Enc_structure` or `MAC_structure`). + pub fn to_be_authenticated(self) -> Result { + let result = self.cbor_bstr()?; + // protected header might have been encoded as a zero length map, only containing + // the byte 0xA0 (see RFC 9052, Section 3). + // However, this byte should not be included during authentication (RFC 9052, Section 4.4, + // 5.3 and 6.3), so we need to return an empty byte string here instead. + if result.eq(&Value::Bytes(vec![0xA0])) { + Ok(Value::Bytes(vec![])) + } else { + Ok(result) + } + } + /// Indicate whether the `ProtectedHeader` is empty. pub fn is_empty(&self) -> bool { self.header.is_empty() diff --git a/src/header/tests.rs b/src/header/tests.rs index 9dff115..51e26f8 100644 --- a/src/header/tests.rs +++ b/src/header/tests.rs @@ -184,7 +184,7 @@ fn test_header_encode() { assert_eq!(*header, got.header); assert_eq!( *header_data, - hex::encode(&got.original_data.expect("missing original data")) + hex::encode(got.original_data.expect("missing original data")) ); } } diff --git a/src/mac/mod.rs b/src/mac/mod.rs index a16bfa3..ada131a 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -336,7 +336,9 @@ pub fn mac_structure_data( ) -> Vec { let arr = vec![ Value::Text(context.text().to_owned()), - protected.cbor_bstr().expect("failed to serialize header"), // safe: always serializable + protected + .to_be_authenticated() + .expect("failed to serialize header"), // safe: always serializable Value::Bytes(external_aad.to_vec()), Value::Bytes(payload.to_vec()), ]; diff --git a/src/sign/mod.rs b/src/sign/mod.rs index 141df2a..e664072 100644 --- a/src/sign/mod.rs +++ b/src/sign/mod.rs @@ -520,11 +520,14 @@ pub fn sig_structure_data( ) -> Vec { let mut arr = vec![ Value::Text(context.text().to_owned()), - body.cbor_bstr().expect("failed to serialize header"), // safe: always serializable + body.to_be_authenticated() + .expect("failed to serialize header"), // safe: always serializable ]; if let Some(sign) = sign { - arr.push(sign.cbor_bstr().expect("failed to serialize header")); // safe: always - // serializable + arr.push( + sign.to_be_authenticated() + .expect("failed to serialize header"), // safe: always serializable + ); } arr.push(Value::Bytes(aad.to_vec())); arr.push(Value::Bytes(payload.to_vec()));