diff --git a/src/types/oid.rs b/src/types/oid.rs index a010a7bc..08f6dd3e 100644 --- a/src/types/oid.rs +++ b/src/types/oid.rs @@ -473,6 +473,24 @@ oids! { JOINT_ISO_ITU_T_REGISTRATION_PROCEDURES_MODULE_DIRECTORY_DEFS => 2, 17, 1, 2; } +// CMS identifiers +oids! { + + ISO_MEMBER_BODY_US_RSADSI_PKCS9_SMIME_CT_CONTENTINFO => 1, 2, 840, 113549, 1, 9, 16, 1, 6; + ISO_MEMBER_BODY_US_RSADSI_PKCS9_CONTENT_TYPE => 1, 2, 840, 113549, 1, 9, 3; + ISO_MEMBER_BODY_US_RSADSI_PKCS9_MESSAGE_DIGEST => 1, 2, 840, 113549, 1, 9, 4; + ISO_MEMBER_BODY_US_RSADSI_PKCS9_SIGNING_TIME => 1, 2, 840, 113549, 1, 9, 5; + ISO_MEMBER_BODY_US_RSADSI_PKCS9_COUNTER_SIGNATURE => 1, 2, 840, 113549, 1, 9, 6; + + // content types + ISO_MEMBER_BODY_US_RSADSI_PKCS7_DATA => 1, 2, 840, 113549, 1, 7, 1; + ISO_MEMBER_BODY_US_RSADSI_PKCS7_SIGNED_DATA => 1, 2, 840, 113549, 1, 7, 2; + ISO_MEMBER_BODY_US_RSADSI_PKCS7_ENVELOPED_DATA => 1, 2, 840, 113549, 1, 7, 3; + ISO_MEMBER_BODY_US_RSADSI_PKCS7_DIGESTED_DATA => 1, 2, 840, 113549, 1, 7, 5; + ISO_MEMBER_BODY_US_RSADSI_PKCS7_ENCRYPTED_DATA => 1, 2, 840, 113549, 1, 7, 6; + ISO_MEMBER_BODY_US_RSADSI_PKCS9_SMIME_CT_AUTHENTICATED_DATA => 1, 2, 840, 113549, 1, 9, 16, 1, 2; +} + #[cfg(test)] mod test { use super::ObjectIdentifier; diff --git a/standards/cms/Cargo.toml b/standards/cms/Cargo.toml new file mode 100644 index 00000000..e2867863 --- /dev/null +++ b/standards/cms/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rasn-cms" +version = "0.4.0" +edition = "2018" +description = "Data types for handling Cryptographic Message Syntax." +license = "Apache-2.0/MIT" + +[dependencies.rasn] +version = "0.4" +path = "../.." + +[dependencies.rasn-pkix] +version = "0.4" +path = "../pkix" diff --git a/standards/cms/src/lib.rs b/standards/cms/src/lib.rs new file mode 100644 index 00000000..161e7eef --- /dev/null +++ b/standards/cms/src/lib.rs @@ -0,0 +1,551 @@ +//! # Cryptographic Message Syntax +//! +//! `rasn-cms` is an implementation of the data types defined in IETF +//! [RFC 5652] also known as CMS or PKCS#7. This does not provide an implementation of a +//! CMS generator or validator, `rasn-cms` provides an +//! implementation of the underlying data types used to decode and +//! encode the CMS structures from/to DER or BER. +//! +//! [RFC 5652]: https://datatracker.ietf.org/doc/html/rfc5652 + +use rasn::prelude::*; +use rasn_pkix::{ + AlgorithmIdentifier, Attribute, Certificate, CertificateList, CertificateSerialNumber, Name, + SubjectKeyIdentifier, +}; + +/// OID of top-level CMS ContentInfo +pub const CONTENT_INFO_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS9_SMIME_CT_CONTENTINFO; + +/// OID of CMS ContentType +pub const CONTENT_TYPE_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS9_CONTENT_TYPE; + +/// OID of MessageDigest +pub const MESSAGE_DIGEST_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS9_MESSAGE_DIGEST; + +/// OID of SigningTime +pub const SIGNING_TIME_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS9_SIGNING_TIME; + +/// OID of CounterSignature +pub const COUNTER_SIGNATURE_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS9_COUNTER_SIGNATURE; + +// content types +/// OID of Data content type +pub const CONTENT_DATA_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS7_DATA; + +/// OID of SignedData content type +pub const CONTENT_SIGNED_DATA_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS7_SIGNED_DATA; + +/// OID of EnvelopedData content type +pub const CONTENT_ENVELOPED_DATA_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS7_ENVELOPED_DATA; + +/// OID of DigestedData content type +pub const CONTENT_DIGESTED_DATA_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS7_DIGESTED_DATA; + +/// OID of EncryptedData content type +pub const CONTENT_ENCRYPTED_DATA_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS7_ENCRYPTED_DATA; + +/// OID of AuthenticatedData content type +pub const CONTENT_AUTHENTICATED_DATA_OID: ConstOid = Oid::ISO_MEMBER_BODY_US_RSADSI_PKCS9_SMIME_CT_AUTHENTICATED_DATA; + +pub type CmsVersion = Integer; +pub type ContentType = ObjectIdentifier; +pub type DigestAlgorithmIdentifier = AlgorithmIdentifier; +pub type DigestAlgorithmIdentifiers = SetOf; +pub type SignatureAlgorithmIdentifier = AlgorithmIdentifier; +pub type ContentEncryptionAlgorithmIdentifier = AlgorithmIdentifier; +pub type KeyEncryptionAlgorithmIdentifier = AlgorithmIdentifier; +pub type KeyDerivationAlgorithmIdentifier = AlgorithmIdentifier; +pub type MessageAuthenticationCodeAlgorithm = AlgorithmIdentifier; +pub type CertificateSet = SetOf; +pub type RevocationInfoChoices = SetOf; +pub type SignerInfos = SetOf; +pub type SignedAttributes = SetOf; +pub type UnsignedAttributes = SetOf; +pub type SignatureValue = OctetString; +pub type RecipientInfos = SetOf; +pub type UnprotectedAttributes = SetOf; +pub type EncryptedContent = OctetString; +pub type EncryptedKey = OctetString; +pub type RecipientEncryptedKeys = SequenceOf; +pub type UserKeyingMaterial = OctetString; +pub type Digest = OctetString; +pub type AuthAttributes = SetOf; +pub type UnauthAttributes = SetOf; +pub type MessageAuthenticationCode = OctetString; +pub type Signature = BitString; + +// ContentInfo ::= SEQUENCE { +// contentType ContentType, +// content [0] EXPLICIT ANY DEFINED BY contentType } + +/// ContentInfo encapsulates a single identified content type, and the +/// identified type may provide further encapsulation. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct ContentInfo { + pub content_type: ContentType, + #[rasn(tag(explicit(0)))] + pub content: Any, +} + +// SignedData ::= SEQUENCE { +// version CMSVersion, +// digestAlgorithms DigestAlgorithmIdentifiers, +// encapContentInfo EncapsulatedContentInfo, +// certificates [0] IMPLICIT CertificateSet OPTIONAL, +// crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, +// signerInfos SignerInfos } + +/// SignedData represents a signed-data content type +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct SignedData { + pub version: CmsVersion, + pub digest_algorithms: DigestAlgorithmIdentifiers, + pub encap_content_info: EncapsulatedContentInfo, + #[rasn(tag(0))] + pub certificates: Option, + #[rasn(tag(1))] + pub crls: Option, + pub signer_infos: SignerInfos, +} + +// EnvelopedData ::= SEQUENCE { +// version CMSVersion, +// originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, +// recipientInfos RecipientInfos, +// encryptedContentInfo EncryptedContentInfo, +// unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + +/// EnvelopedData represents an enveloped-data content type +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct EnvelopedData { + pub version: CmsVersion, + #[rasn(tag(0))] + pub originator_info: Option, + pub recipient_infos: RecipientInfos, + pub encrypted_content_info: EncryptedContentInfo, + #[rasn(tag(1))] + pub unprotected_attrs: Option, +} + +// DigestedData ::= SEQUENCE { +// version CMSVersion, +// digestAlgorithm DigestAlgorithmIdentifier, +// encapContentInfo EncapsulatedContentInfo, +// digest Digest } + +/// DigestedData represents a digested-data content type +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct DigestedData { + pub version: CmsVersion, + pub digest_algorithm: DigestAlgorithmIdentifier, + pub encap_content_info: EncapsulatedContentInfo, + pub digest: Digest, +} + +// EncryptedData ::= SEQUENCE { +// version CMSVersion, +// encryptedContentInfo EncryptedContentInfo, +// unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + +/// EncryptedData represents an encrypted-data content type +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct EncryptedData { + pub version: CmsVersion, + pub encrypted_content_info: EncryptedContentInfo, + #[rasn(tag(1))] + pub unprotected_attrs: Option, +} + +// AuthenticatedData ::= SEQUENCE { +// version CMSVersion, +// originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, +// recipientInfos RecipientInfos, +// macAlgorithm MessageAuthenticationCodeAlgorithm, +// digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL, +// encapContentInfo EncapsulatedContentInfo, +// authAttrs [2] IMPLICIT AuthAttributes OPTIONAL, +// mac MessageAuthenticationCode, +// unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL } + +/// AuthenticatedData represents an authenticated-data content type +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct AuthenticatedData { + pub version: CmsVersion, + #[rasn(tag(0))] + pub originator_info: Option, + pub recipient_infos: RecipientInfos, + pub mac_algorithm: MessageAuthenticationCodeAlgorithm, + #[rasn(tag(1))] + pub digest_algorithm: Option, + pub encap_content_info: EncapsulatedContentInfo, + #[rasn(tag(2))] + pub auth_attrs: Option, + pub mac: MessageAuthenticationCode, + #[rasn(tag(3))] + pub unauth_attrs: Option, +} + +// CertificateChoices ::= CHOICE { +// certificate Certificate, +// extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete +// v1AttrCert [1] IMPLICIT AttributeCertificateV1, -- Obsolete +// v2AttrCert [2] IMPLICIT AttributeCertificateV2, +// other [3] IMPLICIT OtherCertificateFormat } + +/// The CertificateChoices type gives either a PKCS #6 extended +/// certificate [PKCS#6], an X.509 certificate, a version 1 X.509 +/// attribute certificate (ACv1) [X.509-97], a version 2 X.509 attribute +/// certificate (ACv2) [X.509-00], or any other certificate format. +/// This implementation only supports either X.509 or custom certificate formats. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +#[rasn(choice)] +pub enum CertificateChoices { + Certificate(Certificate), + #[rasn(tag(3))] + Other(OtherCertificateFormat), +} + +// OtherCertificateFormat ::= SEQUENCE { +// otherCertFormat OBJECT IDENTIFIER, +// otherCert ANY DEFINED BY otherCertFormat } + +/// OtherCertificateFormat represents a custom certificate format +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct OtherCertificateFormat { + other_cert_format: ObjectIdentifier, + other_cert: Any, +} + +// RevocationInfoChoice ::= CHOICE { +// crl CertificateList, +// other [1] IMPLICIT OtherRevocationInfoFormat } + +/// The RevocationInfoChoice type gives a revocation status +/// information alternatives. It is intended that the set contain +/// information sufficient to determine whether the certificates and +/// attribute certificates with which the set is associated are revoked. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +#[rasn(choice)] +pub enum RevocationInfoChoice { + Crl(CertificateList), + #[rasn(tag(1))] + Other(OtherRevocationInfoFormat), +} + +// OtherRevocationInfoFormat ::= SEQUENCE { +// otherRevInfoFormat OBJECT IDENTIFIER, +// otherRevInfo ANY DEFINED BY otherRevInfoFormat } + +/// The OtherRevocationInfoFormat alternative is provided to support any +/// other revocation information format without further modifications to +/// the CMS. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct OtherRevocationInfoFormat { + other_rev_info_format: ObjectIdentifier, + other_rev_info: Any, +} + +// EncapsulatedContentInfo ::= SEQUENCE { +// eContentType ContentType, +// eContent [0] EXPLICIT OCTET STRING OPTIONAL } + +/// The content is represented in the type EncapsulatedContentInfo +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct EncapsulatedContentInfo { + pub content_type: ContentType, + #[rasn(tag(explicit(0)))] + pub content: Option, +} + +// SignerInfo ::= SEQUENCE { +// version CMSVersion, +// sid SignerIdentifier, +// digestAlgorithm DigestAlgorithmIdentifier, +// signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, +// signatureAlgorithm SignatureAlgorithmIdentifier, +// signature SignatureValue, +// unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } + +/// Per-signer information is represented in the type SignerInfo +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct SignerInfo { + pub version: CmsVersion, + pub sid: SignerIdentifier, + pub digest_algorithm: DigestAlgorithmIdentifier, + #[rasn(tag(0))] + pub signed_attrs: Option, + pub signature_algorithm: SignatureAlgorithmIdentifier, + pub signature: SignatureValue, + #[rasn(tag(1))] + pub unsigned_attrs: Option, +} + +// SignerIdentifier ::= CHOICE { +// issuerAndSerialNumber IssuerAndSerialNumber, +// subjectKeyIdentifier [0] SubjectKeyIdentifier } + +/// SignerIdentifier data type represents the choice of signer identifications +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +#[rasn(choice)] +pub enum SignerIdentifier { + IssuerAndSerialNumber(IssuerAndSerialNumber), + #[rasn(tag(0))] + SubjectKeyIdentifier(SubjectKeyIdentifier), +} + +// IssuerAndSerialNumber ::= SEQUENCE { +// issuer Name, +// serialNumber CertificateSerialNumber } + +/// The IssuerAndSerialNumber type identifies a certificate, and thereby +/// an entity and a public key, by the distinguished name of the +/// certificate issuer and an issuer-specific certificate serial number. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct IssuerAndSerialNumber { + pub issuer: Name, + pub serial_number: CertificateSerialNumber, +} + +// OriginatorInfo ::= SEQUENCE { +// certs [0] IMPLICIT CertificateSet OPTIONAL, +// crls [1] IMPLICIT RevocationInfoChoices OPTIONAL } + +/// OriginatorInfo optionally provides information about the +/// originator. It is present only if required by the key management algorithm. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct OriginatorInfo { + #[rasn(tag(0))] + pub certs: Option, + #[rasn(tag(1))] + pub crls: Option, +} + +// EncryptedContentInfo ::= SEQUENCE { +// contentType ContentType, +// contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, +// encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL } + +/// EncryptedContentInfo is the encrypted content information +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct EncryptedContentInfo { + pub content_type: ContentType, + pub content_encryption_algorithm: ContentEncryptionAlgorithmIdentifier, + #[rasn(tag(0))] + pub encrypted_content: Option, +} + +// RecipientInfo ::= CHOICE { +// ktri KeyTransRecipientInfo, +// kari [1] KeyAgreeRecipientInfo, +// kekri [2] KEKRecipientInfo, +// pwri [3] PasswordRecipientinfo, +// ori [4] OtherRecipientInfo } + +/// RecipientInfo is a per-recipient information. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +#[rasn(choice)] +pub enum RecipientInfo { + KeyTransRecipientInfo(KeyTransRecipientInfo), + #[rasn(tag(1))] + KeyAgreeRecipientInfo(KeyAgreeRecipientInfo), + #[rasn(tag(2))] + KekRecipientInfo(KekRecipientInfo), + #[rasn(tag(3))] + PasswordRecipientInfo(PasswordRecipientInfo), + #[rasn(tag(4))] + OtherRecipientInfo(OtherRecipientInfo), +} + +// KeyTransRecipientInfo ::= SEQUENCE { +// version CMSVersion, -- always set to 0 or 2 +// rid RecipientIdentifier, +// keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, +// encryptedKey EncryptedKey } + +/// Per-recipient information using key transport is represented in the +/// type KeyTransRecipientInfo. Each instance of KeyTransRecipientInfo +/// transfers the content-encryption key to one recipient. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct KeyTransRecipientInfo { + pub version: CmsVersion, + pub rid: RecipientIdentifier, + pub key_encryption_algorithm: KeyEncryptionAlgorithmIdentifier, + pub encrypted_key: EncryptedKey, +} + +// RecipientIdentifier ::= CHOICE { +// issuerAndSerialNumber IssuerAndSerialNumber, +// subjectKeyIdentifier [0] SubjectKeyIdentifier } + +/// RecipientIdentifier specifies the recipient's certificate or key that was used by +/// the sender to protect the content-encryption key. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +#[rasn(choice)] +pub enum RecipientIdentifier { + IssuerAndSerialNumber(IssuerAndSerialNumber), + #[rasn(tag(0))] + SubjectKeyIdentifier(SubjectKeyIdentifier), +} + +// KeyAgreeRecipientInfo ::= SEQUENCE { +// version CMSVersion, -- always set to 3 +// originator [0] EXPLICIT OriginatorIdentifierOrKey, +// ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL, +// keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, +// recipientEncryptedKeys RecipientEncryptedKeys } + +/// Recipient information using key agreement is represented in the type +/// KeyAgreeRecipientInfo. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct KeyAgreeRecipientInfo { + pub version: CmsVersion, + #[rasn(tag(explicit(0)))] + pub originator: OriginatorIdentifierOrKey, + #[rasn(tag(explicit(1)))] + pub user_keying_material: Option, + pub key_encryption_algorithm: KeyEncryptionAlgorithmIdentifier, + pub recipient_encrypted_keys: RecipientEncryptedKeys, +} + +// RecipientEncryptedKey ::= SEQUENCE { +// rid KeyAgreeRecipientIdentifier, +// encryptedKey EncryptedKey } + +/// RecipientEncryptedKey includes a recipient identifier and +/// encrypted key for one or more recipients. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct RecipientEncryptedKey { + pub key_agree_recipient_identifier: KeyAgreeRecipientIdentifier, + pub encrypted_key: EncryptedKey, +} + +// KeyAgreeRecipientIdentifier ::= CHOICE { +// issuerAndSerialNumber IssuerAndSerialNumber, +// rKeyId [0] IMPLICIT RecipientKeyIdentifier } + +/// KeyAgreeRecipientIdentifier is a CHOICE with two alternatives +/// specifying the recipient's certificate, and thereby the +/// recipient's public key, that was used by the sender to generate a +/// pairwise key-encryption key. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +#[rasn(choice)] +pub enum KeyAgreeRecipientIdentifier { + IssuerAndSerialNumber(IssuerAndSerialNumber), + #[rasn(tag(0))] + RecipientKeyIdentifier(RecipientKeyIdentifier), +} + +// RecipientKeyIdentifier ::= SEQUENCE { +// subjectKeyIdentifier SubjectKeyIdentifier, +// date GeneralizedTime OPTIONAL, +// other OtherKeyAttribute OPTIONAL } + +/// RecipientKeyIdentifier identifies the recipient's key. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct RecipientKeyIdentifier { + pub subject_key_identifier: SubjectKeyIdentifier, + pub date: Option, + pub other: Option, +} + +// OtherKeyAttribute ::= SEQUENCE { +// keyAttrId OBJECT IDENTIFIER, +// keyAttr ANY DEFINED BY keyAttrId OPTIONAL } + +/// Additional information used by the recipient to determine +/// the key-encryption key used by the sender. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct OtherKeyAttribute { + pub key_attr_id: ObjectIdentifier, + pub key_attr: Option, +} + +// OriginatorIdentifierOrKey ::= CHOICE { +// issuerAndSerialNumber IssuerAndSerialNumber, +// subjectKeyIdentifier [0] SubjectKeyIdentifier, +// originatorKey [1] OriginatorPublicKey } + +/// OriginatorIdentifierOrKey is a CHOICE with three alternatives specifying the +/// sender's key agreement public key. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +#[rasn(choice)] +pub enum OriginatorIdentifierOrKey { + IssuerAndSerialNumber(IssuerAndSerialNumber), + #[rasn(tag(0))] + SubjectKeyIdentifier(SubjectKeyIdentifier), + #[rasn(tag(1))] + OriginatorPublicKey(OriginatorPublicKey), +} + +// OriginatorPublicKey ::= SEQUENCE { +// algorithm AlgorithmIdentifier, +// publicKey BIT STRING } + +/// The OriginatorPublicKey alternative +/// includes the algorithm identifier and sender's key agreement +/// public key. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct OriginatorPublicKey { + pub algorithm: AlgorithmIdentifier, + pub public_key: BitString, +} + +// KEKRecipientInfo ::= SEQUENCE { +// version CMSVersion, -- always set to 4 +// kekid KEKIdentifier, +// keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, +// encryptedKey EncryptedKey } + +/// Recipient information using previously distributed symmetric keys is +/// represented in the type KEKRecipientInfo. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct KekRecipientInfo { + pub version: CmsVersion, + pub kek_id: KekIdentifier, + pub key_encryption_algorithm: KeyEncryptionAlgorithmIdentifier, + pub encrypted_key: EncryptedKey, +} + +// KEKIdentifier ::= SEQUENCE { +// keyIdentifier OCTET STRING, +// date GeneralizedTime OPTIONAL, +// other OtherKeyAttribute OPTIONAL } + +/// KekIdentifier specifies a symmetric key-encryption key that was previously +/// distributed to the sender and one or more recipients. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct KekIdentifier { + pub key_identifier: OctetString, + pub date: Option, + pub other: Option, +} + +// PasswordRecipientInfo ::= SEQUENCE { +// version CMSVersion, -- always set to 0 +// keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL, +// keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, +// encryptedKey EncryptedKey } + +/// Recipient information using a password or shared secret value is +/// represented in the type PasswordRecipientInfo. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct PasswordRecipientInfo { + pub version: CmsVersion, + #[rasn(tag(0))] + pub key_derivation_algorithm: Option, + pub key_encryption_algorithm: KeyEncryptionAlgorithmIdentifier, + pub encrypted_eey: EncryptedKey, +} + +// OtherRecipientInfo ::= SEQUENCE { +// oriType OBJECT IDENTIFIER, +// oriValue ANY DEFINED BY oriType } + +/// Recipient information for additional key management techniques are +/// represented in the type OtherRecipientInfo. +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord)] +pub struct OtherRecipientInfo { + pub ori_type: ObjectIdentifier, + pub ori_value: Any, +} diff --git a/standards/cms/tests/data/encrypted.cms b/standards/cms/tests/data/encrypted.cms new file mode 100644 index 00000000..705191c1 Binary files /dev/null and b/standards/cms/tests/data/encrypted.cms differ diff --git a/standards/cms/tests/data/signed.cms b/standards/cms/tests/data/signed.cms new file mode 100644 index 00000000..26efd96e Binary files /dev/null and b/standards/cms/tests/data/signed.cms differ diff --git a/standards/cms/tests/test_cms.rs b/standards/cms/tests/test_cms.rs new file mode 100644 index 00000000..93c763d8 --- /dev/null +++ b/standards/cms/tests/test_cms.rs @@ -0,0 +1,35 @@ +use rasn::der::{decode, encode}; + +use rasn_cms::*; + +// from "openssl cms" output +const SIGNED_DATA: &[u8] = include_bytes!("data/signed.cms"); +const ENCRYPTED_DATA: &[u8] = include_bytes!("data/encrypted.cms"); + +#[test] +fn test_cms_signed() { + let info = decode::(SIGNED_DATA).unwrap(); + assert_eq!(CONTENT_SIGNED_DATA_OID, info.content_type); + let data = decode::(info.content.as_bytes()).unwrap(); + println!("{:#?}", data); + + assert_eq!(CONTENT_DATA_OID, data.encap_content_info.content_type); + + let encoded_data = encode(&data).unwrap(); + let decoded_data = decode::(&encoded_data).unwrap(); + assert_eq!(decoded_data, data); +} + +#[test] +fn test_cms_encrypted() { + let info = decode::(ENCRYPTED_DATA).unwrap(); + assert_eq!(CONTENT_ENVELOPED_DATA_OID, info.content_type); + let data = decode::(info.content.as_bytes()).unwrap(); + println!("{:#?}", data); + + assert_eq!(CONTENT_DATA_OID, data.encrypted_content_info.content_type); + + let encoded_data = encode(&data).unwrap(); + let decoded_data = decode::(&encoded_data).unwrap(); + assert_eq!(decoded_data, data); +}