-
Notifications
You must be signed in to change notification settings - Fork 172
Adds SignedData type to pkcs7
#813
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
be61382
0e4dd77
062734b
c4e0387
7cb1639
2a7a5c6
83a9b2d
52d4356
ef41b30
2bd8e06
70a4d14
a339132
dbea0d2
61a5d8a
4650341
9b35f6d
90f0834
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| //! `CertificateChoices` [RFC 5652 10.2.2](https://datatracker.ietf.org/doc/html/rfc5652#section-10.2.2) | ||
| use core::cmp::Ordering; | ||
|
|
||
| use der::{Choice, asn1::{BitStringRef}, ValueOrd, Sequence, AnyRef, | ||
| }; | ||
| use spki::ObjectIdentifier; | ||
| use x509_cert::{Certificate}; | ||
|
|
||
| // TODO (smndtrl): Should come from x509 - for now I haven't found a test case in real world | ||
| pub type AttributeCertificateV1<'a> = BitStringRef<'a>; | ||
| pub type AttributeCertificateV2<'a> = BitStringRef<'a>; | ||
| pub type ExtendedCertificate<'a> = BitStringRef<'a>; | ||
|
|
||
|
|
||
| /// ```text | ||
| /// OtherCertificateFormat ::= SEQUENCE { | ||
| /// otherCertFormat OBJECT IDENTIFIER, | ||
| /// otherCert ANY DEFINED BY otherCertFormat } | ||
| /// ``` | ||
| #[derive(Clone, Debug, PartialEq, Eq, Sequence)] | ||
| pub struct OtherCertificateFormat<'a> { | ||
| other_cert_format: ObjectIdentifier, | ||
| other_cert: AnyRef<'a> | ||
| } | ||
|
|
||
| /// ```text | ||
| /// CertificateChoices ::= CHOICE { | ||
| /// certificate Certificate, | ||
| /// extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete | ||
| /// v1AttrCert [1] IMPLICIT AttributeCertificateV1, -- Obsolete | ||
| /// v2AttrCert [2] IMPLICIT AttributeCertificateV2, | ||
| /// other [3] IMPLICIT OtherCertificateFormat } | ||
| /// | ||
| /// OtherCertificateFormat ::= SEQUENCE { | ||
| /// otherCertFormat OBJECT IDENTIFIER, | ||
| /// otherCert ANY DEFINED BY otherCertFormat } | ||
| /// ``` | ||
| #[derive(Clone, Debug, PartialEq, Eq, Choice)] | ||
| #[allow(clippy::large_enum_variant)] | ||
| pub enum CertificateChoices<'a> { | ||
| Certificate(Certificate<'a>), | ||
|
|
||
| #[deprecated] | ||
| #[asn1(context_specific = "0", tag_mode = "IMPLICIT")] | ||
| ExtendedCertificate(ExtendedCertificate<'a>), | ||
|
|
||
| #[deprecated] | ||
| #[asn1(context_specific = "1", tag_mode = "IMPLICIT")] | ||
| V1AttrCert(AttributeCertificateV1<'a>), | ||
|
|
||
| #[asn1(context_specific = "2", tag_mode = "IMPLICIT")] | ||
| V2AttrCert(AttributeCertificateV2<'a>), | ||
|
|
||
| #[asn1(context_specific = "3", tag_mode = "IMPLICIT")] | ||
| Other(OtherCertificateFormat<'a>), | ||
| } | ||
|
|
||
| // TODO: figure out what ordering makes sense - if any | ||
| impl ValueOrd for CertificateChoices<'_> { | ||
| fn value_cmp(&self, _other: &Self) -> der::Result<Ordering> { | ||
| Ok(Ordering::Equal) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| use der::{FixedTag, Tag, DecodeValue, EncodeValue, Length, Writer, Reader, Header}; | ||
|
|
||
|
|
||
|
|
||
| /// The CMSVersion type gives a syntax version number, for compatibility | ||
| /// with future revisions of this specification. | ||
| /// ```text | ||
| /// CMSVersion ::= INTEGER | ||
| /// { v0(0), v1(1), v2(2), v3(3), v4(4), v5(5) } | ||
| /// ``` | ||
| /// | ||
| /// See [RFC 5652 10.2.5](https://datatracker.ietf.org/doc/html/rfc5652#section-10.2.5). | ||
| #[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
| pub enum CMSVersion { | ||
smndtrl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| V0 = 0, | ||
| V1 = 1, | ||
| V2 = 2, | ||
| V3 = 3, | ||
| V4 = 4, | ||
| V5 = 5 | ||
| } | ||
|
|
||
| impl FixedTag for CMSVersion { | ||
| const TAG: Tag = Tag::Integer; | ||
| } | ||
|
|
||
| impl From<CMSVersion> for u8 { | ||
| fn from(version: CMSVersion) -> Self { | ||
| version as u8 | ||
| } | ||
| } | ||
|
|
||
| impl TryFrom<u8> for CMSVersion { | ||
| type Error = der::Error; | ||
| fn try_from(byte: u8) -> der::Result<CMSVersion> { | ||
| match byte { | ||
| 0 => Ok(CMSVersion::V0), | ||
| 1 => Ok(CMSVersion::V1), | ||
| 2 => Ok(CMSVersion::V2), | ||
| 3 => Ok(CMSVersion::V3), | ||
| 4 => Ok(CMSVersion::V4), | ||
| 5 => Ok(CMSVersion::V5), | ||
| _ => Err(Self::TAG.value_error()), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl<'a> DecodeValue<'a> for CMSVersion { | ||
| fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<CMSVersion> { | ||
| CMSVersion::try_from(u8::decode_value(reader, header)?) | ||
| } | ||
| } | ||
|
|
||
| impl EncodeValue for CMSVersion { | ||
| fn value_len(&self) -> der::Result<Length> { | ||
| u8::from(*self).value_len() | ||
| } | ||
|
|
||
| fn encode_value(&self, writer: &mut dyn Writer) -> der::Result<()> { | ||
| u8::from(*self).encode_value(writer) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| //! `encapsulated-data` content type [RFC 5652 § 5.2](https://datatracker.ietf.org/doc/html/rfc5652#section-5.2) | ||
| use crate::{ContentType}; | ||
| use der::{Sequence, AnyRef}; | ||
|
|
||
| /// Encapsulated content information [RFC 5652 § 5.2](https://datatracker.ietf.org/doc/html/rfc5652#section-5.2) | ||
| /// | ||
| /// ```text | ||
| /// EncapsulatedContentInfo ::= SEQUENCE { | ||
| /// eContentType ContentType, | ||
| /// eContent [0] EXPLICIT OCTET STRING OPTIONAL } | ||
| /// ``` | ||
| /// Due to a difference in PKCS #7 and CMS the contents type can be either | ||
| /// ```text | ||
| /// content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL | ||
| /// ``` | ||
| /// or | ||
| /// ```text | ||
| /// eContent [0] EXPLICIT OCTET STRING OPTIONAL | ||
| /// ``` | ||
| #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] | ||
| pub struct EncapsulatedContentInfo<'a> { | ||
| /// indicates the type of content. | ||
| pub e_content_type: ContentType, | ||
smndtrl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// encapsulated content | ||
| #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] | ||
| pub e_content: Option<AnyRef<'a>>, | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| //! `RevocationInfoChoices` [RFC 5652 10.2.1](https://datatracker.ietf.org/doc/html/rfc5652#section-10.2.1) | ||
|
|
||
| use core::cmp::Ordering; | ||
|
|
||
| use der::{Choice, Sequence, asn1::{SetOfVec}, ValueOrd, AnyRef, | ||
| }; | ||
| use spki::{ObjectIdentifier}; | ||
| use x509_cert::{crl::CertificateList}; | ||
|
|
||
| /// ```text | ||
| /// RevocationInfoChoices ::= SET OF RevocationInfoChoice | ||
| /// RevocationInfoChoice ::= CHOICE { | ||
| /// crl CertificateList, | ||
| /// other [1] IMPLICIT OtherRevocationInfoFormat } | ||
| /// OtherRevocationInfoFormat ::= SEQUENCE { | ||
| /// otherRevInfoFormat OBJECT IDENTIFIER, | ||
| /// otherRevInfo ANY DEFINED BY otherRevInfoFormat } | ||
| /// ``` | ||
| #[derive(Clone, Debug, PartialEq, Eq, Choice)] | ||
| #[allow(clippy::large_enum_variant)] | ||
| pub enum RevocationInfoChoice<'a> { | ||
| Crl(CertificateList<'a>), | ||
|
|
||
| #[asn1(context_specific = "1", tag_mode = "IMPLICIT", constructed = "true")] | ||
| Other(OtherRevocationInfoFormat<'a>), | ||
| } | ||
|
|
||
| /// ```text | ||
| /// RevocationInfoChoices ::= SET OF RevocationInfoChoice | ||
| /// ``` | ||
| pub type RevocationInfoChoices<'a> = SetOfVec<RevocationInfoChoice<'a>>; | ||
|
|
||
| /// ```text | ||
| /// OtherRevocationInfoFormat ::= SEQUENCE { | ||
| /// otherRevInfoFormat OBJECT IDENTIFIER, | ||
| /// otherRevInfo ANY DEFINED BY otherRevInfoFormat } | ||
| /// ``` | ||
| #[derive(Clone, Debug, PartialEq, Eq, Sequence)] | ||
| pub struct OtherRevocationInfoFormat<'a> { | ||
| other_rev_info_format: ObjectIdentifier, | ||
| other_rev_info: AnyRef<'a> | ||
| } | ||
|
|
||
| // TODO: figure out what ordering makes sense - if any | ||
| impl ValueOrd for RevocationInfoChoice<'_> { | ||
| fn value_cmp(&self, _other: &Self) -> der::Result<Ordering> { | ||
| Ok(Ordering::Equal) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| //! `signed-data` content type [RFC 5652 § 5](https://datatracker.ietf.org/doc/html/rfc5652#section-5) | ||
| use crate::{signer_info::{SignerInfos}, encapsulated_content_info::EncapsulatedContentInfo, certificate_choices::CertificateChoices, revocation_info_choices::RevocationInfoChoices, cms_version::CMSVersion}; | ||
| use der::{Sequence, asn1::{SetOfVec}}; | ||
| use spki::{AlgorithmIdentifierRef}; | ||
|
|
||
| /// ```text | ||
| /// DigestAlgorithmIdentifier ::= AlgorithmIdentifier | ||
| /// ``` | ||
| type DigestAlgorithmIdentifier<'a> = AlgorithmIdentifierRef<'a>; | ||
|
|
||
| /// ```text | ||
| /// DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier | ||
| /// ``` | ||
| type DigestAlgorithmIdentifiers<'a> = SetOfVec<DigestAlgorithmIdentifier<'a>>; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe I did something weird locally, but I'm surprised this isn't complaining about the lack of the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that you say it I'm wondering as well. I ran everything without additional features enabled.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it built for me locally without additional features as well, strange.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're pulling in the
Since that's the case, you might as well unconditionally link liballoc and activate the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for explaining! If there is interest in maintaining a non- [features]
alloc = ["der/alloc"]
std = ["alloc"]
signed-data = ["alloc", "dep:x509-cert"](with
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing that, like #765, this crate should probably move to all owned types and make
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What should we do for now? I don't want to mix this PR with the larger effort of doing something like #765 for this crate as well.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm +1 on doing the owned refactor in a follow-up (I can help with that) to keep the diff small 🙂 |
||
|
|
||
| /// ```text | ||
| /// CertificateSet ::= SET OF CertificateChoices | ||
| /// ``` | ||
| type CertificateSet<'a> = SetOfVec<CertificateChoices<'a>>; | ||
|
|
||
| /// Signed-data content type [RFC 5652 § 5](https://datatracker.ietf.org/doc/html/rfc5652#section-5) | ||
| /// | ||
| /// ```text | ||
| /// SignedData ::= SEQUENCE { | ||
| /// version CMSVersion, | ||
| /// digestAlgorithms DigestAlgorithmIdentifiers, | ||
| /// encapContentInfo EncapsulatedContentInfo, | ||
| /// certificates [0] IMPLICIT CertificateSet OPTIONAL, | ||
| /// crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, | ||
| /// signerInfos SignerInfos } | ||
| /// ``` | ||
| #[derive(Clone, Debug, Eq, PartialEq, Sequence)] | ||
| pub struct SignedDataContent<'a> { | ||
| /// the syntax version number. | ||
| pub version: CMSVersion, | ||
|
|
||
| /// digest algorithm | ||
| pub digest_algorithms: DigestAlgorithmIdentifiers<'a>, | ||
|
|
||
| /// content | ||
| pub encap_content_info: EncapsulatedContentInfo<'a>, | ||
|
|
||
| /// certs | ||
| #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] | ||
| pub certificates: Option<CertificateSet<'a>>, | ||
|
|
||
| /// crls | ||
| #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] | ||
| pub crls: Option<RevocationInfoChoices<'a>>, | ||
|
|
||
| /// signer info | ||
| pub signer_infos: SignerInfos<'a> | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.