-
Notifications
You must be signed in to change notification settings - Fork 141
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
Adds SignedData type to pkcs7
#813
Changes from all 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,58 @@ | ||
//! `CertificateChoices` [RFC 5652 10.2.2](https://datatracker.ietf.org/doc/html/rfc5652#section-10.2.2) | ||
use der::{asn1::BitStringRef, AnyRef, Choice, Sequence, ValueOrd}; | ||
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 | ||
type AttributeCertificateV1<'a> = BitStringRef<'a>; | ||
type AttributeCertificateV2<'a> = BitStringRef<'a>; | ||
type ExtendedCertificate<'a> = BitStringRef<'a>; | ||
|
||
/// ```text | ||
/// OtherCertificateFormat ::= SEQUENCE { | ||
/// otherCertFormat OBJECT IDENTIFIER, | ||
/// otherCert ANY DEFINED BY otherCertFormat } | ||
/// ``` | ||
#[derive(Clone, Debug, PartialEq, Eq, Sequence, ValueOrd)] | ||
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, ValueOrd)] | ||
#[allow(clippy::large_enum_variant)] | ||
pub enum CertificateChoices<'a> { | ||
/// X.509 certificate | ||
Certificate(Certificate<'a>), | ||
|
||
/// PKCS #6 extended certificate (obsolete) | ||
#[deprecated] | ||
#[asn1(context_specific = "0", tag_mode = "IMPLICIT")] | ||
ExtendedCertificate(ExtendedCertificate<'a>), | ||
|
||
/// version 1 X.509 attribute certificate (ACv1) X.509-97 (obsolete) | ||
#[deprecated] | ||
#[asn1(context_specific = "1", tag_mode = "IMPLICIT")] | ||
V1AttrCert(AttributeCertificateV1<'a>), | ||
|
||
/// version 2 X.509 attribute certificate (ACv2) X.509-00 | ||
#[asn1(context_specific = "2", tag_mode = "IMPLICIT")] | ||
V2AttrCert(AttributeCertificateV2<'a>), | ||
|
||
/// any other certificate forma | ||
#[asn1(context_specific = "3", tag_mode = "IMPLICIT")] | ||
Other(OtherCertificateFormat<'a>), | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//! `CMSVersion` [RFC 5652 § 10.2.5](https://datatracker.ietf.org/doc/html/rfc5652#section-10.2.5) | ||
use der::Enumerated; | ||
|
||
/// 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, Enumerated, Eq, PartialEq)] | ||
#[asn1(type = "INTEGER")] | ||
#[repr(u8)] | ||
pub enum CmsVersion { | ||
/// syntax version 0 | ||
V0 = 0, | ||
/// syntax version 1 | ||
V1 = 1, | ||
/// syntax version 2 | ||
V2 = 2, | ||
/// syntax version 3 | ||
V3 = 3, | ||
/// syntax version 4 | ||
V4 = 4, | ||
/// syntax version 5 | ||
V5 = 5, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//! `encapsulated-data` content type [RFC 5652 § 5.2](https://datatracker.ietf.org/doc/html/rfc5652#section-5.2) | ||
use der::{AnyRef, Sequence}; | ||
use spki::ObjectIdentifier; | ||
|
||
/// 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: ObjectIdentifier, | ||
|
||
/// 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,52 @@ | ||
//! `RevocationInfoChoices` [RFC 5652 10.2.1](https://datatracker.ietf.org/doc/html/rfc5652#section-10.2.1) | ||
use core::cmp::Ordering; | ||
|
||
use der::{asn1::SetOfVec, AnyRef, Choice, Sequence, ValueOrd}; | ||
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> { | ||
/// The CertificateList type gives a certificate revocation list (CRL). | ||
Crl(CertificateList<'a>), | ||
|
||
/// The OtherRevocationInfoFormat alternative is provided to support any | ||
/// other revocation information format without further modifications to | ||
/// the CMS. | ||
#[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,58 @@ | ||
//! `signed-data` content type [RFC 5652 § 5](https://datatracker.ietf.org/doc/html/rfc5652#section-5) | ||
use crate::{ | ||
certificate_choices::CertificateChoices, cms_version::CmsVersion, | ||
encapsulated_content_info::EncapsulatedContentInfo, | ||
revocation_info_choices::RevocationInfoChoices, signer_info::SignerInfos, | ||
}; | ||
use der::{asn1::SetOfVec, Sequence}; | ||
use spki::AlgorithmIdentifierRef; | ||
|
||
/// ```text | ||
/// DigestAlgorithmIdentifier ::= AlgorithmIdentifier | ||
/// ``` | ||
type DigestAlgorithmIdentifier<'a> = AlgorithmIdentifierRef<'a>; | ||
|
||
/// ```text | ||
/// DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier | ||
/// ``` | ||
type DigestAlgorithmIdentifiers<'a> = SetOfVec<DigestAlgorithmIdentifier<'a>>; | ||
|
||
/// ```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>, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
//! `SignerInfo` data type [RFC 5652 § 5.3](https://datatracker.ietf.org/doc/html/rfc5652#section-5.3) | ||
use core::cmp::Ordering; | ||
|
||
use crate::cms_version::CmsVersion; | ||
use der::{ | ||
asn1::{OctetStringRef, SetOfVec}, | ||
Choice, Sequence, ValueOrd, | ||
}; | ||
use spki::AlgorithmIdentifierRef; | ||
use x509_cert::{ | ||
attr::Attribute, ext::pkix::SubjectKeyIdentifier, name::Name, serial_number::SerialNumber, | ||
}; | ||
|
||
/// ```text | ||
/// DigestAlgorithmIdentifier ::= AlgorithmIdentifier | ||
/// ``` | ||
type DigestAlgorithmIdentifier<'a> = AlgorithmIdentifierRef<'a>; | ||
|
||
/// ```text | ||
/// SignatureAlgorithmIdentifier ::= AlgorithmIdentifier | ||
/// ``` | ||
type SignatureAlgorithmIdentifier<'a> = AlgorithmIdentifierRef<'a>; | ||
|
||
/// ```text | ||
/// SignedAttributes ::= SET SIZE (1..MAX) OF Attribute | ||
/// ``` | ||
type SignedAttributes<'a> = SetOfVec<Attribute>; | ||
|
||
/// ```text | ||
/// UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute | ||
/// ``` | ||
type UnsignedAttributes<'a> = SetOfVec<Attribute>; | ||
|
||
/// ```text | ||
/// SignerIdentifier ::= CHOICE { | ||
// issuerAndSerialNumber IssuerAndSerialNumber, | ||
// subjectKeyIdentifier [0] SubjectKeyIdentifier } | ||
/// ``` | ||
#[derive(Clone, Debug, PartialEq, Eq, Choice)] | ||
pub enum SignerIdentifier<'a> { | ||
/// issuer and serial number | ||
IssuerAndSerialNumber(IssuerAndSerialNumber), | ||
|
||
/// subject key identifier | ||
#[asn1(context_specific = "0")] | ||
SubjectKeyIdentifier(SubjectKeyIdentifier<'a>), | ||
} | ||
|
||
#[derive(Clone, Debug, Eq, PartialEq, Sequence)] | ||
#[allow(missing_docs)] | ||
pub struct IssuerAndSerialNumber { | ||
pub name: Name, | ||
pub serial_number: SerialNumber, | ||
} | ||
|
||
/// ```text | ||
/// SignerInfos ::= SET OF SignerInfo | ||
/// ``` | ||
pub type SignerInfos<'a> = SetOfVec<SignerInfo<'a>>; | ||
|
||
/// `SignerInfo` data type [RFC 5652 § 5.3](https://datatracker.ietf.org/doc/html/rfc5652#section-5.3) | ||
/// | ||
/// ```text | ||
/// SignerInfo ::= SEQUENCE { | ||
/// version CMSVersion, | ||
/// sid SignerIdentifier, | ||
/// digestAlgorithm DigestAlgorithmIdentifier, | ||
/// signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, | ||
/// signatureAlgorithm SignatureAlgorithmIdentifier, | ||
/// signature SignatureValue, | ||
/// unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } | ||
/// ``` | ||
#[derive(Clone, Debug, Eq, PartialEq, Sequence)] | ||
pub struct SignerInfo<'a> { | ||
/// the syntax version number. | ||
pub version: CmsVersion, | ||
|
||
/// the signer identifier | ||
pub sid: SignerIdentifier<'a>, | ||
|
||
/// the message digest algorithm | ||
pub digest_algorithm: DigestAlgorithmIdentifier<'a>, | ||
|
||
/// the signed attributes | ||
#[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] | ||
pub signed_attributes: Option<SignedAttributes<'a>>, | ||
|
||
/// the signature algorithm | ||
pub signature_algorithm: SignatureAlgorithmIdentifier<'a>, | ||
|
||
/// the signature for content or detached | ||
pub signature: OctetStringRef<'a>, | ||
|
||
/// the unsigned attributes | ||
#[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] | ||
pub unsigned_attributes: Option<UnsignedAttributes<'a>>, | ||
} | ||
|
||
// TODO: figure out what ordering makes sense - if any | ||
impl ValueOrd for SignerInfo<'_> { | ||
fn value_cmp(&self, _other: &Self) -> der::Result<Ordering> { | ||
Ok(Ordering::Equal) | ||
} | ||
} | ||
Comment on lines
+100
to
+105
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 should be able to derive 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. That'll end up requiring ValueOrd on CmsVersion and SignerIdentifier (which works nice with just adding ValueOrd there) but
which ends up in when adding ValueOrd
on 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. Alright, I can go ahead and merge and see if I can figure it out 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. Opened #825 to address this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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
alloc
feature from theder
crate. Did you build with all features enabled locally?There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it built for me locally without additional features as well, strange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're pulling in the
x509-cert
crate which unconditionally activates thealloc
feature, and feature unification means it's activated here too.It would probably be good to factor the relevant parts into a common crate which can be shared. We had theEdit: oh wait, you needx501
crate for this purpose at one point, although I'm not sure that's quite what you need.Certificate
. Never mind.Since that's the case, you might as well unconditionally link liballoc and activate the
alloc
feature of theder
crate directly for clarity.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining!
If there is interest in maintaining a non-
alloc
part ofpkcs7
, this is how I did it in my own changes:(with
x509-cert
then being marked as optional.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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
alloc
a hard dependency, since heapless support probably won't be practical for real-world use casesThere was a problem hiding this comment.
Choose a reason for hiding this comment
The 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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 🙂