diff --git a/pkcs7/src/content_info.rs b/pkcs7/src/content_info.rs index 6355e0daf..4d9e219a5 100644 --- a/pkcs7/src/content_info.rs +++ b/pkcs7/src/content_info.rs @@ -16,24 +16,26 @@ const CONTENT_TAG: TagNumber = TagNumber::new(0); /// ContentInfo ::= SEQUENCE { /// contentType ContentType, /// content -/// [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } +/// [0] EXPLICIT ANY DEFINED BY contentType } /// ``` +/// +/// Note: `content` field was previously optional in [RFC 2315 ยง 7](https://datatracker.ietf.org/doc/html/rfc2315#section-7). #[derive(Clone, Debug)] pub enum ContentInfo<'a> { /// Content type `data` - Data(Option>), + Data(DataContent<'a>), /// Content type `encrypted-data` - EncryptedData(Option>), + EncryptedData(EncryptedDataContent<'a>), /// Content type `signed-data` - SignedData(Option>), + SignedData(SignedDataContent<'a>), /// Catch-all case for content types that are not explicitly supported /// - enveloped-data /// - signed-and-enveloped-data /// - digested-data - Other((ContentType, Option>)), + Other((ContentType, OctetStringRef<'a>)), } impl<'a> ContentInfo<'a> { @@ -51,24 +53,14 @@ impl<'a> ContentInfo<'a> { impl<'a> ContentInfo<'a> { /// new ContentInfo of `data` content type pub fn new_data(content: &'a [u8]) -> Self { - ContentInfo::Data(Some(content.into())) - } - - /// new ContentInfo of given content type with empty content - pub fn new_empty(content_type: ContentType) -> Self { - match content_type { - ContentType::Data => ContentInfo::Data(None), - ContentType::EncryptedData => ContentInfo::EncryptedData(None), - ContentType::SignedData => ContentInfo::SignedData(None), - _ => ContentInfo::Other((content_type, None)), - } + ContentInfo::Data(content.into()) } /// new Content info of given content type with given raw content pub fn new_raw(content_type: ContentType, content: &'a [u8]) -> der::Result { Ok(ContentInfo::Other(( content_type, - Some(OctetStringRef::new(content)?), + OctetStringRef::new(content)?, ))) } } @@ -79,21 +71,52 @@ impl<'a> DecodeValue<'a> for ContentInfo<'a> { let content_type = reader.decode()?; match content_type { ContentType::Data => Ok(ContentInfo::Data( - reader.context_specific::>(CONTENT_TAG, TagMode::Explicit)?, + ContextSpecific::>::decode_explicit(reader, CONTENT_TAG)? + .ok_or_else(|| { + der::Tag::ContextSpecific { + number: CONTENT_TAG, + constructed: false, + } + .value_error() + })? + .value, )), ContentType::EncryptedData => Ok(ContentInfo::EncryptedData( - reader.context_specific(CONTENT_TAG, TagMode::Explicit)?, + ContextSpecific::>::decode_explicit( + reader, + CONTENT_TAG, + )? + .ok_or_else(|| { + der::Tag::ContextSpecific { + number: CONTENT_TAG, + constructed: false, + } + .value_error() + })? + .value, )), ContentType::SignedData => Ok(ContentInfo::SignedData( - reader.context_specific::>( - CONTENT_TAG, - TagMode::Explicit, - )?, + ContextSpecific::>::decode_explicit(reader, CONTENT_TAG)? + .ok_or_else(|| { + der::Tag::ContextSpecific { + number: CONTENT_TAG, + constructed: false, + } + .value_error() + })? + .value, )), _ => Ok(ContentInfo::Other(( content_type, - reader - .context_specific::>(CONTENT_TAG, TagMode::Explicit)?, + ContextSpecific::>::decode_explicit(reader, CONTENT_TAG)? + .ok_or_else(|| { + der::Tag::ContextSpecific { + number: CONTENT_TAG, + constructed: false, + } + .value_error() + })? + .value, ))), } }) @@ -104,77 +127,61 @@ impl EncodeValue for ContentInfo<'_> { fn value_len(&self) -> der::Result { self.content_type().encoded_len()? + match self { - Self::Data(data) => data - .as_ref() - .map(|d| ContextSpecific { - tag_number: CONTENT_TAG, - tag_mode: TagMode::Explicit, - value: *d, - }) - .encoded_len(), - Self::EncryptedData(data) => data - .as_ref() - .map(|d| ContextSpecific { - tag_number: CONTENT_TAG, - tag_mode: TagMode::Explicit, - value: *d, - }) - .encoded_len(), - Self::SignedData(data) => data - .as_ref() - .map(|d| ContextSpecific { - tag_number: CONTENT_TAG, - tag_mode: TagMode::Explicit, - value: d.clone(), - }) - .encoded_len(), - Self::Other((_, opt_oct_str)) => opt_oct_str - .as_ref() - .map(|d| ContextSpecific { - tag_number: CONTENT_TAG, - tag_mode: TagMode::Explicit, - value: *d, - }) - .encoded_len(), - }? - } - - fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - self.content_type().encode(writer)?; - - match self { - Self::Data(data) => data - .as_ref() - .map(|d| ContextSpecific { + Self::Data(data) => ContextSpecific { tag_number: CONTENT_TAG, tag_mode: TagMode::Explicit, - value: *d, - }) - .encode(writer)?, - Self::EncryptedData(data) => data - .as_ref() - .map(|d| ContextSpecific { + value: *data, + } + .encoded_len(), + Self::EncryptedData(data) => ContextSpecific { tag_number: CONTENT_TAG, tag_mode: TagMode::Explicit, - value: *d, - }) - .encode(writer)?, - Self::SignedData(data) => data - .as_ref() - .map(|d| ContextSpecific { + value: *data, + } + .encoded_len(), + Self::SignedData(data) => ContextSpecific { tag_number: CONTENT_TAG, tag_mode: TagMode::Explicit, - value: d.clone(), - }) - .encode(writer)?, - Self::Other((_, opt_oct_str)) => opt_oct_str - .as_ref() - .map(|d| ContextSpecific { + value: data.clone(), + } + .encoded_len(), + Self::Other((_, oct_str)) => ContextSpecific { tag_number: CONTENT_TAG, tag_mode: TagMode::Explicit, - value: *d, - }) - .encode(writer)?, + value: *oct_str, + } + .encoded_len(), + }? + } + + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { + self.content_type().encode(writer)?; + + match self { + Self::Data(data) => ContextSpecific { + tag_number: CONTENT_TAG, + tag_mode: TagMode::Explicit, + value: *data, + } + .encode(writer)?, + Self::EncryptedData(data) => ContextSpecific { + tag_number: CONTENT_TAG, + tag_mode: TagMode::Explicit, + value: *data, + } + .encode(writer)?, + Self::SignedData(data) => ContextSpecific { + tag_number: CONTENT_TAG, + tag_mode: TagMode::Explicit, + value: data.clone(), + } + .encode(writer)?, + Self::Other((_, oct_str)) => ContextSpecific { + tag_number: CONTENT_TAG, + tag_mode: TagMode::Explicit, + value: *oct_str, + } + .encode(writer)?, } Ok(()) @@ -189,54 +196,6 @@ mod tests { use core::convert::TryFrom; use der::{asn1::OctetStringRef, Decode, Encode, Length, SliceWriter, TagMode, TagNumber}; - #[test] - fn empty_data() -> der::Result<()> { - let mut in_buf = [0u8; 32]; - - let mut encoder = SliceWriter::new(&mut in_buf); - encoder.sequence(crate::PKCS_7_DATA_OID.encoded_len()?, |encoder| { - crate::PKCS_7_DATA_OID.encode(encoder) - })?; - let encoded_der = encoder.finish().expect("encoding success"); - - let info = ContentInfo::from_der(encoded_der)?; - match info { - ContentInfo::Data(None) => (), - _ => panic!("unexpected case"), - } - - let mut out_buf = [0u8; 32]; - let encoded_der2 = info.encode_to_slice(&mut out_buf)?; - - assert_eq!(encoded_der, encoded_der2); - - Ok(()) - } - - #[test] - fn empty_encrypted_data() -> der::Result<()> { - let mut in_buf = [0u8; 32]; - - let mut encoder = SliceWriter::new(&mut in_buf); - encoder.sequence(crate::PKCS_7_ENCRYPTED_DATA_OID.encoded_len()?, |encoder| { - (crate::PKCS_7_ENCRYPTED_DATA_OID).encode(encoder) - })?; - let encoded_der = encoder.finish().expect("encoding success"); - - let info = ContentInfo::from_der(encoded_der)?; - match info { - ContentInfo::EncryptedData(None) => (), - _ => panic!("unexpected case"), - } - - let mut out_buf = [0u8; 32]; - let encoded_der2 = info.encode_to_slice(&mut out_buf)?; - - assert_eq!(encoded_der, encoded_der2); - - Ok(()) - } - #[test] fn simple_data() -> der::Result<()> { let mut in_buf = [0u8; 32]; @@ -270,7 +229,7 @@ mod tests { let info = ContentInfo::from_der(encoded_der)?; match info { - ContentInfo::Data(Some(DataContent { content })) => assert_eq!(hello, content), + ContentInfo::Data(DataContent { content }) => assert_eq!(hello, content), _ => panic!("unexpected case"), } diff --git a/pkcs7/tests/content_tests.rs b/pkcs7/tests/content_tests.rs index 86be1b3ee..116e47fb0 100644 --- a/pkcs7/tests/content_tests.rs +++ b/pkcs7/tests/content_tests.rs @@ -27,7 +27,7 @@ fn decode_cert_example() { let content = ContentInfo::from_der(&bytes).expect("expected valid data"); match content { - ContentInfo::Data(Some(data)) => assert_eq!(data.content.len(), 781), + ContentInfo::Data(data) => assert_eq!(data.content.len(), 781), _ => panic!("expected ContentInfo::Data(Some(_))"), } @@ -47,7 +47,7 @@ fn decode_encrypted_key_example() { let expected_oid = ObjectIdentifier::new("1.2.840.113549.1.12.1.6").unwrap(); let expected_salt = &hex!("ad2d4b4e87b34d67"); match content { - ContentInfo::EncryptedData(Some(EncryptedDataContent { + ContentInfo::EncryptedData(EncryptedDataContent { version: _, encrypted_content_info: EncryptedContentInfo { @@ -59,7 +59,7 @@ fn decode_encrypted_key_example() { }, encrypted_content: Some(bytes), }, - })) => { + }) => { assert_eq!(oid, expected_oid); let (salt, iter) = any @@ -91,7 +91,7 @@ fn decode_signed_mdm_example() { let content = ContentInfo::from_der(&bytes).expect("expected valid data"); match content { - ContentInfo::SignedData(Some(SignedDataContent { + ContentInfo::SignedData(SignedDataContent { version: _, digest_algorithms: _, encap_content_info: @@ -102,7 +102,7 @@ fn decode_signed_mdm_example() { certificates: _, crls: _, signer_infos: _, - })) => { + }) => { let _content = content .decode_as::() .expect("Content should be in the correct format: SequenceRef"); @@ -119,7 +119,7 @@ fn decode_signed_scep_example() { let content = ContentInfo::from_der(&bytes).expect("expected valid data"); match content { - ContentInfo::SignedData(Some(SignedDataContent { + ContentInfo::SignedData(SignedDataContent { version: ver, digest_algorithms: _, encap_content_info: @@ -130,7 +130,7 @@ fn decode_signed_scep_example() { certificates: _, crls: _, signer_infos: _, - })) => { + }) => { let _content = content .decode_as::() .expect("Content should be in the correct format: OctetStringRef"); @@ -148,7 +148,7 @@ fn decode_signed_ber() { let bytes = include_bytes!("examples/cms_ber.bin"); let content = match ContentInfo::from_der(bytes) { - Ok(ContentInfo::SignedData(Some(data))) => data, + Ok(ContentInfo::SignedData(data)) => data, other => panic!("unexpected result: {:?}", other), }; @@ -170,7 +170,7 @@ fn decode_signed_der() { let bytes = include_bytes!("examples/cms_der.bin"); let content = match ContentInfo::from_der(bytes) { - Ok(ContentInfo::SignedData(Some(data))) => data, + Ok(ContentInfo::SignedData(data)) => data, other => panic!("unexpected result: {:?}", other), };