cms/
builder.rs

1#![cfg(feature = "builder")]
2
3//! CMS Builder
4
5use crate::cert::CertificateChoices;
6use crate::content_info::{CmsVersion, ContentInfo};
7use crate::enveloped_data::{
8    EncryptedContentInfo, EncryptedKey, EnvelopedData, KekIdentifier, KeyTransRecipientInfo,
9    OriginatorIdentifierOrKey, OriginatorInfo, RecipientIdentifier, RecipientInfo, RecipientInfos,
10    UserKeyingMaterial,
11};
12use crate::revocation::{RevocationInfoChoice, RevocationInfoChoices};
13use crate::signed_data::{
14    CertificateSet, DigestAlgorithmIdentifiers, EncapsulatedContentInfo, SignatureValue,
15    SignedAttributes, SignedData, SignerIdentifier, SignerInfo, SignerInfos, UnsignedAttributes,
16};
17use aes::{Aes128, Aes192, Aes256};
18use alloc::borrow::ToOwned;
19use alloc::boxed::Box;
20use alloc::string::String;
21use alloc::vec::Vec;
22use cipher::block_padding::Pkcs7;
23use cipher::rand_core::{CryptoRng, CryptoRngCore, RngCore};
24use cipher::BlockEncryptMut;
25use cipher::{Key, KeyIvInit, KeySizeUser};
26use const_oid::ObjectIdentifier;
27use core::cmp::Ordering;
28use core::fmt;
29use der::asn1::{BitString, OctetStringRef, SetOfVec};
30use der::oid::db::DB;
31use der::Tag::OctetString;
32use der::{Any, AnyRef, DateTime, Decode, Encode, ErrorKind, Tag};
33use digest::Digest;
34use rsa::Pkcs1v15Encrypt;
35use sha2::digest;
36use signature::digest::DynDigest;
37use signature::{Keypair, Signer};
38use spki::{AlgorithmIdentifierOwned, DynSignatureAlgorithmIdentifier, SignatureBitStringEncoding};
39use std::time::SystemTime;
40use std::vec;
41use x509_cert::attr::{Attribute, AttributeValue, Attributes};
42use x509_cert::builder::Builder;
43use zeroize::Zeroize;
44
45/// Error type
46#[derive(Debug)]
47#[non_exhaustive]
48pub enum Error {
49    /// ASN.1 DER-related errors.
50    Asn1(der::Error),
51
52    /// Public key errors propagated from the [`spki::Error`] type.
53    PublicKey(spki::Error),
54
55    /// Signing error propagated for the [`signature::Signer`] type.
56    Signature(signature::Error),
57
58    /// Builder no table to build, because the struct is not properly configured
59    Builder(String),
60}
61
62impl fmt::Display for Error {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Error::Asn1(err) => write!(f, "ASN.1 error: {}", err),
66            Error::PublicKey(err) => write!(f, "public key error: {}", err),
67            Error::Signature(err) => write!(f, "signature error: {}", err),
68            Error::Builder(message) => write!(f, "builder error: {message}"),
69        }
70    }
71}
72
73impl From<der::Error> for Error {
74    fn from(err: der::Error) -> Error {
75        Error::Asn1(err)
76    }
77}
78
79impl From<spki::Error> for Error {
80    fn from(err: spki::Error) -> Error {
81        Error::PublicKey(err)
82    }
83}
84
85impl From<signature::Error> for Error {
86    fn from(err: signature::Error) -> Error {
87        Error::Signature(err)
88    }
89}
90
91type Result<T> = core::result::Result<T, Error>;
92
93/// Collect info needed for creating a `SignerInfo`.
94/// Calling `build()` on this struct will
95/// - calculate the correct `CMSVersion` (depends on `sid`)
96/// - calculate the signature
97/// - set the signing time attribute
98/// - create a `SignerInfo` object
99pub struct SignerInfoBuilder<'s, S> {
100    signer: &'s S,
101    sid: SignerIdentifier,
102    digest_algorithm: AlgorithmIdentifierOwned,
103    signed_attributes: Option<Vec<Attribute>>,
104    unsigned_attributes: Option<Vec<Attribute>>,
105    encapsulated_content_info: &'s EncapsulatedContentInfo,
106    external_message_digest: Option<&'s [u8]>,
107}
108
109impl<'s, S> SignerInfoBuilder<'s, S>
110where
111    S: Keypair + DynSignatureAlgorithmIdentifier,
112{
113    /// Create a new `SignerInfoBuilder`. This is used for adding `SignerInfo`s to `SignedData`
114    /// structures.
115    /// The content to be signed can be stored externally. In this case `eContent` in
116    /// `encapsulated_content_info` must be `None` and the message digest must be passed with
117    /// `external_message_digest`. `digest_algorithm` must match the used digest algorithm.
118    pub fn new(
119        signer: &'s S,
120        sid: SignerIdentifier,
121        digest_algorithm: AlgorithmIdentifierOwned,
122        encapsulated_content_info: &'s EncapsulatedContentInfo,
123        external_message_digest: Option<&'s [u8]>,
124    ) -> Result<Self> {
125        Ok(SignerInfoBuilder {
126            signer,
127            sid,
128            digest_algorithm,
129            signed_attributes: None,
130            unsigned_attributes: None,
131            encapsulated_content_info,
132            external_message_digest,
133        })
134    }
135
136    /// Add a "signed" attribute. The attribute will be signed together with the other "signed"
137    /// attributes, when `build()` is called.
138    pub fn add_signed_attribute(&mut self, signed_attribute: Attribute) -> Result<&mut Self> {
139        if let Some(signed_attributes) = &mut self.signed_attributes {
140            signed_attributes.push(signed_attribute);
141        } else {
142            self.signed_attributes = Some(vec![signed_attribute]);
143        }
144        Ok(self)
145    }
146
147    /// Add an unsigned attribute.
148    pub fn add_unsigned_attribute(&mut self, unsigned_attribute: Attribute) -> Result<&mut Self> {
149        if let Some(unsigned_attributes) = &mut self.unsigned_attributes {
150            unsigned_attributes.push(unsigned_attribute);
151        } else {
152            self.unsigned_attributes = Some(vec![unsigned_attribute]);
153        }
154        Ok(self)
155    }
156
157    /// Calculate the CMSVersion of the signer info.
158    /// Intended to be called during building the `SignerInfo`.
159    /// RFC 5652 § 5.3: version is the syntax version number.  If the SignerIdentifier is
160    /// the CHOICE issuerAndSerialNumber, then the version MUST be 1. If
161    /// the SignerIdentifier is subjectKeyIdentifier, then the version MUST be 3.
162    pub fn version(&self) -> CmsVersion {
163        match self.sid {
164            SignerIdentifier::IssuerAndSerialNumber(_) => CmsVersion::V1,
165            SignerIdentifier::SubjectKeyIdentifier(_) => CmsVersion::V3,
166        }
167    }
168}
169
170impl<'s, S> Builder for SignerInfoBuilder<'s, S>
171where
172    S: Keypair + DynSignatureAlgorithmIdentifier,
173{
174    type Signer = S;
175    type Output = SignerInfo;
176
177    fn signer(&self) -> &Self::Signer {
178        self.signer
179    }
180
181    /// Calculate the data to be signed
182    /// [RFC 5652 § 5.4](https://datatracker.ietf.org/doc/html/rfc5652#section-5.4)
183    /// If an `external_message_digest` is passed in, it is assumed, that we are signing external
184    /// content (see RFC 5652 § 5.2). In this case, the `eContent` in `EncapsulatedContentInfo`
185    /// must be `None`.
186    fn finalize(&mut self) -> der::Result<Vec<u8>> {
187        let message_digest = match self.external_message_digest {
188            Some(external_content_digest) => {
189                if self.encapsulated_content_info.econtent.is_some() {
190                    // Encapsulated content must be empty, if external digest is given.
191                    return Err(der::Error::from(ErrorKind::Failed));
192                }
193                Some(external_content_digest.to_vec())
194            }
195            None => match &self.encapsulated_content_info.econtent {
196                None => {
197                    // This case is allowed. E.g. for degenerate certificates-only messages.
198                    // See RFC 5652 § 5.2 or RFC 8894 § 3.4.
199                    None
200                }
201                Some(content) => {
202                    let mut hasher = get_hasher(&self.digest_algorithm).ok_or_else(|| {
203                        // Unsupported hash algorithm: {}, &self.digest_algorithm.oid.to_string()
204                        der::Error::from(ErrorKind::Failed)
205                    })?;
206                    // Only the octets comprising the value of the eContent
207                    // OCTET STRING are input to the message digest algorithm, not the tag
208                    // or the length octets.
209                    let content_value = content.value();
210                    hasher.update(content_value);
211                    Some(hasher.finalize_reset().to_vec())
212                }
213            },
214        };
215
216        // This implementation uses signed attributes to store the message digest.
217        if self.signed_attributes.is_none() {
218            self.signed_attributes = Some(vec![]);
219        }
220
221        let signed_attributes = self
222            .signed_attributes
223            .as_mut()
224            .expect("Signed attributes must be present.");
225
226        if let Some(message_digest) = message_digest {
227            // Add digest attribute to (to be) signed attributes
228            signed_attributes.push(
229                create_message_digest_attribute(&message_digest)
230                    .map_err(|_| der::Error::from(ErrorKind::Failed))?,
231            );
232
233            // The content-type attribute type specifies the content type of the
234            // ContentInfo within signed-data or authenticated-data.  The content-
235            // type attribute type MUST be present whenever signed attributes are
236            // present in signed-data or authenticated attributes present in
237            // authenticated-data.  The content-type attribute value MUST match the
238            // encapContentInfo eContentType value in the signed-data or
239            // authenticated-data.
240            let econtent_type = self.encapsulated_content_info.econtent_type;
241            let signed_attributes_content_type = signed_attributes.iter().find(|attr| {
242                attr.oid.cmp(&const_oid::db::rfc5911::ID_CONTENT_TYPE) == Ordering::Equal
243            });
244            if let Some(signed_attributes_content_type) = signed_attributes_content_type {
245                // Check against `eContentType`
246                if signed_attributes_content_type.oid != econtent_type {
247                    // Mismatch between content types: encapsulated content info <-> signed attributes.
248                    return Err(der::Error::from(ErrorKind::Failed));
249                }
250            } else {
251                signed_attributes.push(
252                    create_content_type_attribute(econtent_type)
253                        .map_err(|_| der::Error::from(ErrorKind::Failed))?,
254                );
255            }
256        }
257
258        // Now use `signer` to sign the DER encoded signed attributes
259        let signed_attributes = SignedAttributes::try_from(signed_attributes.to_owned())
260            .map_err(|_| der::Error::from(ErrorKind::Failed))?;
261        let mut signed_attributes_der = Vec::new();
262        signed_attributes.encode_to_vec(&mut signed_attributes_der)?;
263
264        Ok(signed_attributes_der)
265    }
266
267    fn assemble(
268        self,
269        signature: BitString,
270    ) -> core::result::Result<Self::Output, x509_cert::builder::Error> {
271        let signed_attrs = self.signed_attributes.as_ref().map(|signed_attributes| {
272            SignedAttributes::try_from(signed_attributes.to_owned()).unwrap()
273        });
274        let unsigned_attrs = self
275            .unsigned_attributes
276            .as_ref()
277            .map(|unsigned_attributes| {
278                UnsignedAttributes::try_from(unsigned_attributes.to_owned()).unwrap()
279            });
280
281        let signature_value =
282            SignatureValue::new(signature.raw_bytes()).map_err(x509_cert::builder::Error::from)?;
283
284        let signature_algorithm = self.signer.signature_algorithm_identifier()?;
285
286        Ok(SignerInfo {
287            version: self.version(),
288            sid: self.sid.clone(),
289            digest_alg: self.digest_algorithm,
290            signed_attrs,
291            signature_algorithm,
292            signature: signature_value,
293            unsigned_attrs,
294        })
295    }
296}
297
298/// Builder for signedData (CMS and PKCS #7)
299pub struct SignedDataBuilder<'s> {
300    digest_algorithms: Vec<AlgorithmIdentifierOwned>,
301    encapsulated_content_info: &'s EncapsulatedContentInfo,
302    certificates: Option<Vec<CertificateChoices>>,
303    crls: Option<Vec<RevocationInfoChoice>>,
304    signer_infos: Vec<SignerInfo>,
305}
306
307impl<'s> SignedDataBuilder<'s> {
308    /// Create a new builder for `SignedData`
309    pub fn new(encapsulated_content_info: &'s EncapsulatedContentInfo) -> SignedDataBuilder<'s> {
310        Self {
311            digest_algorithms: Vec::new(),
312            encapsulated_content_info,
313            certificates: None,
314            crls: None,
315            signer_infos: Vec::new(),
316        }
317    }
318
319    /// Add a digest algorithm to the collection of message digest algorithms.
320    /// RFC 5652 § 5.1: digestAlgorithms is a collection of message digest algorithm
321    /// identifiers.  There MAY be any number of elements in the
322    /// collection, including zero.  Each element identifies the message
323    /// digest algorithm, along with any associated parameters, used by
324    /// one or more signer.  The collection is intended to list the
325    /// message digest algorithms employed by all of the signers, in any
326    /// order, to facilitate one-pass signature verification.
327    pub fn add_digest_algorithm(
328        &mut self,
329        digest_algorithm: AlgorithmIdentifierOwned,
330    ) -> Result<&mut Self> {
331        self.digest_algorithms.push(digest_algorithm);
332        Ok(self)
333    }
334
335    /// Add a certificate to the certificate collection.
336    /// RFC 5652 § 5.1:
337    /// certificates is a collection of certificates.  It is intended that
338    /// the set of certificates be sufficient to contain certification
339    /// paths from a recognized "root" or "top-level certification
340    /// authority" to all of the signers in the signerInfos field.  There
341    /// may be more certificates than necessary, and there may be
342    /// certificates sufficient to contain certification paths from two or
343    /// more independent top-level certification authorities.  There may
344    /// also be fewer certificates than necessary, if it is expected that
345    /// recipients have an alternate means of obtaining necessary
346    /// certificates (e.g., from a previous set of certificates).  The
347    /// signer's certificate MAY be included.  The use of version 1
348    /// attribute certificates is strongly discouraged.
349    pub fn add_certificate(&mut self, certificate: CertificateChoices) -> Result<&mut Self> {
350        if self.certificates.is_none() {
351            self.certificates = Some(Vec::new());
352        }
353        if let Some(certificates) = &mut self.certificates {
354            certificates.push(certificate);
355        }
356        Ok(self)
357    }
358
359    /// Add a CRL to the collection of CRLs.
360    /// RFC 5652 § 5.1:
361    /// crls is a collection of revocation status information.  It is
362    /// intended that the collection contain information sufficient to
363    /// determine whether the certificates in the certificates field are
364    /// valid, but such correspondence is not necessary.  Certificate
365    /// revocation lists (CRLs) are the primary source of revocation
366    /// status information.  There MAY be more CRLs than necessary, and
367    /// there MAY also be fewer CRLs than necessary.
368    pub fn add_crl(&mut self, crl: RevocationInfoChoice) -> Result<&mut Self> {
369        if self.crls.is_none() {
370            self.crls = Some(Vec::new());
371        }
372        if let Some(crls) = &mut self.crls {
373            crls.push(crl);
374        }
375        Ok(self)
376    }
377
378    /// Add a signer info. The signature will be calculated. Note that the encapsulated content
379    /// must not be changed after the first signer info was added.
380    pub fn add_signer_info<S, Signature>(
381        &mut self,
382        signer_info_builder: SignerInfoBuilder<'_, S>,
383    ) -> Result<&mut Self>
384    where
385        S: Keypair + DynSignatureAlgorithmIdentifier,
386        S: Signer<Signature>,
387        Signature: SignatureBitStringEncoding,
388    {
389        let signer_info = signer_info_builder
390            .build::<Signature>()
391            .map_err(|_| der::Error::from(ErrorKind::Failed))?;
392        self.signer_infos.push(signer_info);
393
394        Ok(self)
395    }
396
397    /// This method returns a `ContentInfo` of type `signedData`.
398    pub fn build(&mut self) -> Result<ContentInfo> {
399        let digest_algorithms =
400            DigestAlgorithmIdentifiers::try_from(self.digest_algorithms.to_owned()).unwrap();
401
402        let encap_content_info = self.encapsulated_content_info.clone();
403
404        let certificates = self
405            .certificates
406            .as_mut()
407            .map(|certificates| CertificateSet::try_from(certificates.to_owned()).unwrap());
408
409        let crls = self
410            .crls
411            .as_mut()
412            .map(|crls| RevocationInfoChoices::try_from(crls.to_owned()).unwrap());
413
414        let signer_infos = SignerInfos::try_from(self.signer_infos.clone()).unwrap();
415
416        let signed_data = SignedData {
417            version: self.calculate_version(),
418            digest_algorithms,
419            encap_content_info,
420            certificates,
421            crls,
422            signer_infos,
423        };
424
425        let signed_data_der = signed_data.to_der()?;
426        let content = AnyRef::try_from(signed_data_der.as_slice())?;
427
428        let signed_data = ContentInfo {
429            content_type: const_oid::db::rfc5911::ID_SIGNED_DATA,
430            content: Any::from(content),
431        };
432
433        Ok(signed_data)
434    }
435
436    fn calculate_version(&self) -> CmsVersion {
437        // RFC 5652, 5.1.  SignedData Type
438        // IF ((certificates is present) AND
439        //             (any certificates with a type of other are present)) OR
440        //             ((crls is present) AND
441        //             (any crls with a type of other are present))
442        //          THEN version MUST be 5
443        //          ELSE
444        //             IF (certificates is present) AND
445        //                (any version 2 attribute certificates are present)
446        //             THEN version MUST be 4
447        //             ELSE
448        //                IF ((certificates is present) AND
449        //                   (any version 1 attribute certificates are present)) OR
450        //                   (any SignerInfo structures are version 3) OR
451        //                   (encapContentInfo eContentType is other than id-data)
452        //                THEN version MUST be 3
453        //                ELSE version MUST be 1
454        let other_certificates_are_present = if let Some(certificates) = &self.certificates {
455            certificates
456                .iter()
457                .any(|certificate| matches!(certificate, CertificateChoices::Other(_)))
458        } else {
459            false
460        };
461        // v1 and v2 currently not supported
462        // let v2_certificates_are_present = if let Some(certificates) = &self.certificates {
463        //     certificates.iter().any(|certificate| match certificate {
464        //         CertificateChoices::V2AttrCert(_) => true,
465        //         _ => false,
466        //     })
467        // } else {
468        //     false
469        // };
470        // let v1_certificates_are_present = if let Some(certificates) = &self.certificates {
471        //     certificates.iter().any(|certificate| match certificate {
472        //         CertificateChoices::V1AttrCert(_) => true,
473        //         _ => false,
474        //     })
475        // } else {
476        //     false
477        // };
478        let v2_certificates_are_present = false;
479        let v1_certificates_are_present = false;
480        let other_crls_are_present = if let Some(crls) = &self.crls {
481            crls.iter().any(|revocation_info_choice| {
482                matches!(revocation_info_choice, RevocationInfoChoice::Other(_))
483            })
484        } else {
485            false
486        };
487        let v3_signer_infos_present = self
488            .signer_infos
489            .iter()
490            .any(|signer_info| signer_info.version == CmsVersion::V3);
491        let content_not_data =
492            self.encapsulated_content_info.econtent_type != const_oid::db::rfc5911::ID_DATA;
493
494        if other_certificates_are_present || other_crls_are_present {
495            CmsVersion::V5
496        } else if v2_certificates_are_present {
497            CmsVersion::V4
498        } else if v1_certificates_are_present || v3_signer_infos_present || content_not_data {
499            CmsVersion::V3
500        } else {
501            CmsVersion::V1
502        }
503    }
504}
505
506/// Trait for builders of a `RecipientInfo`. RFC 5652 § 6 defines 5 different `RecipientInfo`
507/// formats. All implementations must implement this trait.
508pub trait RecipientInfoBuilder {
509    /// Return the recipient info type
510    fn recipient_info_type(&self) -> RecipientInfoType;
511
512    /// Return the recipient info version
513    fn recipient_info_version(&self) -> CmsVersion;
514
515    /// Encrypt the `content_encryption_key` using a method, that is specific for the implementing
516    /// builder type. Finally return a `RecipientInfo`.
517    fn build(&mut self, content_encryption_key: &[u8]) -> Result<RecipientInfo>;
518}
519
520/// `RecipientInfoBuilder` must be implemented for these 5 recipient info types
521/// as defined in RFC 5652 § 6:
522#[derive(Clone, Debug, Eq, PartialEq)]
523pub enum RecipientInfoType {
524    /// KeyTransRecipientInfo
525    Ktri,
526    /// KeyAgreeRecipientInfo
527    Kari,
528    /// KekRecipientInfo
529    Kekri,
530    /// PasswordRecipientInfo
531    Pwri,
532    /// OtherRecipientInfo
533    Ori,
534}
535
536/// Contains information required to encrypt the content encryption key with a specific method
537#[derive(Clone, Debug, Eq, PartialEq)]
538pub enum KeyEncryptionInfo {
539    /// Encrypt key with RSA
540    Rsa(rsa::RsaPublicKey),
541    // to be extended here with other asymmetric encryption algorithms
542}
543
544/// Builds a `KeyTransRecipientInfo` according to RFC 5652 § 6.
545/// This type uses the recipient's public key to encrypt the content-encryption key.
546pub struct KeyTransRecipientInfoBuilder<'a, R>
547where
548    R: CryptoRngCore,
549{
550    /// Identifies the recipient
551    pub rid: RecipientIdentifier,
552    /// Info for key encryption
553    pub key_encryption_info: KeyEncryptionInfo,
554    /// Rng
555    rng: &'a mut R,
556}
557
558impl<'a, R> KeyTransRecipientInfoBuilder<'a, R>
559where
560    R: CryptoRngCore,
561{
562    /// Creates a `KeyTransRecipientInfoBuilder`
563    pub fn new(
564        rid: RecipientIdentifier,
565        key_encryption_info: KeyEncryptionInfo,
566        rng: &'a mut R,
567    ) -> Result<KeyTransRecipientInfoBuilder<'a, R>> {
568        Ok(KeyTransRecipientInfoBuilder {
569            rid,
570            key_encryption_info,
571            rng,
572        })
573    }
574}
575
576impl<'a, R> RecipientInfoBuilder for KeyTransRecipientInfoBuilder<'a, R>
577where
578    R: CryptoRngCore,
579{
580    fn recipient_info_type(&self) -> RecipientInfoType {
581        RecipientInfoType::Ktri
582    }
583
584    fn recipient_info_version(&self) -> CmsVersion {
585        match self.rid {
586            RecipientIdentifier::IssuerAndSerialNumber(_) => CmsVersion::V0,
587            RecipientIdentifier::SubjectKeyIdentifier(_) => CmsVersion::V2,
588        }
589    }
590
591    /// Build a `KeyTransRecipientInfo`. See RFC 5652 § 6.2.1
592    /// `content_encryption_key` will be encrypted with the recipient's public key.
593    fn build(&mut self, content_encryption_key: &[u8]) -> Result<RecipientInfo> {
594        // Encrypt key
595        let (encrypted_key, key_enc_alg) = match &self.key_encryption_info {
596            // RSA encryption
597            KeyEncryptionInfo::Rsa(recipient_public_key) => (
598                recipient_public_key
599                    .encrypt(self.rng, Pkcs1v15Encrypt, content_encryption_key)
600                    .map_err(|_| Error::Builder(String::from("Could not encrypt key")))?,
601                AlgorithmIdentifierOwned {
602                    oid: const_oid::db::rfc5912::RSA_ENCRYPTION,
603                    parameters: None,
604                },
605            ),
606        };
607        let enc_key = EncryptedKey::new(encrypted_key)?;
608
609        Ok(RecipientInfo::Ktri(KeyTransRecipientInfo {
610            version: self.recipient_info_version(),
611            rid: self.rid.clone(),
612            key_enc_alg,
613            enc_key,
614        }))
615    }
616}
617
618/// Builds a `KeyAgreeRecipientInfo` according to RFC 5652 § 6.
619/// This type uses key agreement:  the recipient's public key and the sender's
620/// private key are used to generate a pairwise symmetric key, then
621/// the content-encryption key is encrypted in the pairwise symmetric key.
622pub struct KeyAgreeRecipientInfoBuilder {
623    /// A CHOICE with three alternatives specifying the sender's key agreement public key.
624    pub originator: OriginatorIdentifierOrKey,
625    /// Optional information which helps generating different keys every time.
626    pub ukm: Option<UserKeyingMaterial>,
627    /// Encryption algorithm to be used for key encryption
628    pub key_enc_alg: AlgorithmIdentifierOwned,
629}
630
631impl KeyAgreeRecipientInfoBuilder {
632    /// Creates a `KeyAgreeRecipientInfoBuilder`
633    pub fn new(
634        originator: OriginatorIdentifierOrKey,
635        ukm: Option<UserKeyingMaterial>,
636        key_enc_alg: AlgorithmIdentifierOwned,
637    ) -> Result<KeyAgreeRecipientInfoBuilder> {
638        Ok(KeyAgreeRecipientInfoBuilder {
639            originator,
640            ukm,
641            key_enc_alg,
642        })
643    }
644}
645
646impl RecipientInfoBuilder for KeyAgreeRecipientInfoBuilder {
647    /// Returns the RecipientInfoType
648    fn recipient_info_type(&self) -> RecipientInfoType {
649        RecipientInfoType::Kari
650    }
651
652    /// Returns the `CMSVersion` for this `RecipientInfo`
653    fn recipient_info_version(&self) -> CmsVersion {
654        CmsVersion::V3
655    }
656
657    /// Build a `KeyAgreeRecipientInfoBuilder`. See RFC 5652 § 6.2.1
658    fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
659        Err(Error::Builder(String::from(
660            "Building KeyAgreeRecipientInfo is not implemented, yet.",
661        )))
662    }
663}
664
665/// Builds a `KekRecipientInfo` according to RFC 5652 § 6.
666/// Uses symmetric key-encryption keys: the content-encryption key is
667/// encrypted in a previously distributed symmetric key-encryption key.
668pub struct KekRecipientInfoBuilder {
669    /// Specifies a symmetric key-encryption key that was previously distributed to the sender and
670    /// one or more recipients.
671    pub kek_id: KekIdentifier,
672    /// Encryption algorithm to be used for key encryption
673    pub key_enc_alg: AlgorithmIdentifierOwned,
674}
675
676impl KekRecipientInfoBuilder {
677    /// Creates a `KekRecipientInfoBuilder`
678    pub fn new(
679        kek_id: KekIdentifier,
680        key_enc_alg: AlgorithmIdentifierOwned,
681    ) -> Result<KekRecipientInfoBuilder> {
682        Ok(KekRecipientInfoBuilder {
683            kek_id,
684            key_enc_alg,
685        })
686    }
687}
688
689impl RecipientInfoBuilder for KekRecipientInfoBuilder {
690    /// Returns the RecipientInfoType
691    fn recipient_info_type(&self) -> RecipientInfoType {
692        RecipientInfoType::Kekri
693    }
694
695    /// Returns the `CMSVersion` for this `RecipientInfo`
696    fn recipient_info_version(&self) -> CmsVersion {
697        CmsVersion::V4
698    }
699
700    /// Build a `KekRecipientInfoBuilder`. See RFC 5652 § 6.2.1
701    fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
702        Err(Error::Builder(String::from(
703            "Building KekRecipientInfo is not implemented, yet.",
704        )))
705    }
706}
707
708/// Builds a `PasswordRecipientInfo` according to RFC 5652 § 6.
709/// Uses a password or shared secret value to encrypt the content-encryption key.
710pub struct PasswordRecipientInfoBuilder {
711    /// Identifies the key-derivation algorithm, and any associated parameters, used to derive the
712    /// key-encryption key from the password or shared secret value. If this field is `None`,
713    /// the key-encryption key is supplied from an external source, for example a hardware crypto
714    /// token such as a smart card.
715    pub key_derivation_alg: Option<AlgorithmIdentifierOwned>,
716    /// Encryption algorithm to be used for key encryption
717    pub key_enc_alg: AlgorithmIdentifierOwned,
718}
719
720impl PasswordRecipientInfoBuilder {
721    /// Creates a `PasswordRecipientInfoBuilder`
722    pub fn new(
723        key_derivation_alg: Option<AlgorithmIdentifierOwned>,
724        key_enc_alg: AlgorithmIdentifierOwned,
725    ) -> Result<PasswordRecipientInfoBuilder> {
726        Ok(PasswordRecipientInfoBuilder {
727            key_derivation_alg,
728            key_enc_alg,
729        })
730    }
731}
732
733impl RecipientInfoBuilder for PasswordRecipientInfoBuilder {
734    /// Returns the RecipientInfoType
735    fn recipient_info_type(&self) -> RecipientInfoType {
736        RecipientInfoType::Pwri
737    }
738
739    /// Returns the `CMSVersion` for this `RecipientInfo`
740    fn recipient_info_version(&self) -> CmsVersion {
741        CmsVersion::V0
742    }
743
744    /// Build a `PasswordRecipientInfoBuilder`. See RFC 5652 § 6.2.1
745    fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
746        Err(Error::Builder(String::from(
747            "Building PasswordRecipientInfo is not implemented, yet.",
748        )))
749    }
750}
751
752/// Builds an `OtherRecipientInfo` according to RFC 5652 § 6.
753/// This type makes no assumption about the encryption method or the needed information.
754pub struct OtherRecipientInfoBuilder {
755    /// Identifies the key management technique.
756    pub ori_type: ObjectIdentifier,
757    /// Contains the protocol data elements needed by a recipient using the identified key
758    /// management technique
759    pub ori_value: Any,
760}
761
762impl OtherRecipientInfoBuilder {
763    /// Creates a `OtherRecipientInfoBuilder`
764    pub fn new(ori_type: ObjectIdentifier, ori_value: Any) -> Result<OtherRecipientInfoBuilder> {
765        Ok(OtherRecipientInfoBuilder {
766            ori_type,
767            ori_value,
768        })
769    }
770}
771
772impl RecipientInfoBuilder for OtherRecipientInfoBuilder {
773    /// Returns the RecipientInfoType
774    fn recipient_info_type(&self) -> RecipientInfoType {
775        RecipientInfoType::Ori
776    }
777
778    /// Returns the `CMSVersion` for this `RecipientInfo`
779    fn recipient_info_version(&self) -> CmsVersion {
780        panic!("Ori has no CMSVersion")
781    }
782
783    /// Build a `OtherRecipientInfoBuilder`. See RFC 5652 § 6.2.1
784    fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
785        panic!("Ori has no common build method.")
786    }
787}
788
789/// Supported content encryption algorithms.
790#[derive(Clone, Debug, Eq, PartialEq)]
791pub enum ContentEncryptionAlgorithm {
792    /// AES-128 CBC
793    Aes128Cbc,
794    /// AES-192 CBC
795    Aes192Cbc,
796    /// AES-256 CBC
797    Aes256Cbc,
798}
799
800impl ContentEncryptionAlgorithm {
801    /// Return the OID of the algorithm.
802    pub fn oid(&self) -> ObjectIdentifier {
803        match self {
804            ContentEncryptionAlgorithm::Aes128Cbc => const_oid::db::rfc5911::ID_AES_128_CBC,
805            ContentEncryptionAlgorithm::Aes192Cbc => const_oid::db::rfc5911::ID_AES_192_CBC,
806            ContentEncryptionAlgorithm::Aes256Cbc => const_oid::db::rfc5911::ID_AES_256_CBC,
807        }
808    }
809}
810
811/// Builds CMS `EnvelopedData` according to RFC 5652 § 6.
812pub struct EnvelopedDataBuilder<'c> {
813    originator_info: Option<OriginatorInfo>,
814    recipient_infos: Vec<Box<dyn RecipientInfoBuilder + 'c>>,
815    unencrypted_content: &'c [u8],
816    // TODO bk Not good to offer both, `content_encryptor` and `content_encryption_algorithm`.
817    // We should
818    // (1) either derive `content_encryption_algorithm` from `content_encryptor` (but this is not
819    //            yet supported by RustCrypto),
820    // (2) or     pass `content_encryption_algorithm` and create an encryptor for it.
821    // In the first case, we might need a new trait here, e.g. `DynEncryptionAlgorithmIdentifier` in
822    // analogy to `DynSignatureAlgorithmIdentifier`.
823    // Going for (2)
824    //  content_encryptor: E,
825    content_encryption_algorithm: ContentEncryptionAlgorithm,
826    unprotected_attributes: Option<Attributes>,
827}
828
829impl<'c> EnvelopedDataBuilder<'c> {
830    /// Create a new builder for `EnvelopedData`
831    pub fn new(
832        originator_info: Option<OriginatorInfo>,
833        unencrypted_content: &'c [u8],
834        content_encryption_algorithm: ContentEncryptionAlgorithm,
835        unprotected_attributes: Option<Attributes>,
836    ) -> Result<EnvelopedDataBuilder<'c>> {
837        Ok(EnvelopedDataBuilder {
838            originator_info,
839            recipient_infos: Vec::new(),
840            unencrypted_content,
841            content_encryption_algorithm,
842            unprotected_attributes,
843        })
844    }
845
846    /// Add recipient info. A builder is used, which generates a `RecipientInfo` according to
847    /// RFC 5652 § 6.2, when `EnvelopedData` is built.
848    pub fn add_recipient_info(
849        &mut self,
850        recipient_info_builder: impl RecipientInfoBuilder + 'c,
851    ) -> Result<&mut Self> {
852        self.recipient_infos.push(Box::new(recipient_info_builder));
853
854        Ok(self)
855    }
856
857    /// Generate an `EnvelopedData` object according to RFC 5652 § 6 using a provided
858    /// random number generator.
859    pub fn build_with_rng(&mut self, rng: &mut impl CryptoRngCore) -> Result<EnvelopedData> {
860        // Generate content encryption key
861        // Encrypt content
862        // Build recipient infos
863        // Make sure, content encryption key is securely destroyed
864        let (encrypted_content, mut content_encryption_key, content_enc_alg) = encrypt_data(
865            self.unencrypted_content,
866            &self.content_encryption_algorithm,
867            None,
868            rng,
869        )?;
870        let encrypted_content_octetstring = der::asn1::OctetString::new(encrypted_content)?;
871        let encrypted_content_info = EncryptedContentInfo {
872            content_type: const_oid::db::rfc5911::ID_DATA, // TODO bk should this be configurable?
873            content_enc_alg,
874            encrypted_content: Some(encrypted_content_octetstring), // TODO bk `None` (external content) should also be possible
875        };
876
877        let recipient_infos_vec = self
878            .recipient_infos
879            .iter_mut()
880            .map(|ri| ri.build(&content_encryption_key))
881            .collect::<Result<Vec<RecipientInfo>>>()?;
882        content_encryption_key.zeroize();
883        let recip_infos = RecipientInfos::try_from(recipient_infos_vec).unwrap();
884
885        Ok(EnvelopedData {
886            version: self.calculate_version(),
887            originator_info: self.originator_info.clone(),
888            recip_infos,
889            encrypted_content: encrypted_content_info,
890            unprotected_attrs: self.unprotected_attributes.clone(),
891        })
892    }
893
894    /// Calculate the `CMSVersion` of the `EnvelopedData` according to RFC 5652 § 6.1
895    fn calculate_version(&self) -> CmsVersion {
896        // IF (originatorInfo is present) AND
897        //    ((any certificates with a type of other are present) OR
898        //    (any crls with a type of other are present))
899        // THEN version is 4
900        // ELSE
901        //    IF ((originatorInfo is present) AND
902        //       (any version 2 attribute certificates are present)) OR
903        //       (any RecipientInfo structures include pwri) OR
904        //       (any RecipientInfo structures include ori)
905        //    THEN version is 3
906        //    ELSE
907        //       IF (originatorInfo is absent) AND
908        //          (unprotectedAttrs is absent) AND
909        //          (all RecipientInfo structures are version 0)
910        //       THEN version is 0
911        //       ELSE version is 2
912        let originator_info_present = self.originator_info.is_some();
913        let other_certificates_present = if let Some(originator_info) = &self.originator_info {
914            if let Some(certificates) = &originator_info.certs {
915                certificates
916                    .0
917                    .iter()
918                    .any(|certificate| matches!(certificate, CertificateChoices::Other(_)))
919            } else {
920                false
921            }
922        } else {
923            false
924        };
925        let other_crls_present = if let Some(originator_info) = &self.originator_info {
926            if let Some(crls) = &originator_info.crls {
927                crls.0
928                    .iter()
929                    .any(|crl| matches!(crl, RevocationInfoChoice::Other(_)))
930            } else {
931                false
932            }
933        } else {
934            false
935        };
936        // v2 certificates currently not supported
937        // let v2_certificates_present = if let Some(certificate_option) = &self.originator_info {
938        //     if let Some(certificates) = certificate_option {
939        //         certificates
940        //             .iter()
941        //             .any(|certificate| matches!(certificate, CertificateChoices::V2AttrCert))
942        //     } else {
943        //         false
944        //     }
945        // } else {
946        //     false
947        // };
948        let v2_certificates_present = false;
949        let pwri_recipient_info_present = self.recipient_infos.iter().any(|recipient_info| {
950            matches!(
951                recipient_info.recipient_info_type(),
952                RecipientInfoType::Pwri
953            )
954        });
955        let ori_recipient_info_present = self.recipient_infos.iter().any(|recipient_info| {
956            matches!(recipient_info.recipient_info_type(), RecipientInfoType::Ori)
957        });
958        let unprotected_attributes_present = self.unprotected_attributes.is_some();
959        let all_recipient_infos_are_v0 = self
960            .recipient_infos
961            .iter()
962            .all(|ri| ri.recipient_info_version() == CmsVersion::V0);
963
964        if originator_info_present && (other_certificates_present || other_crls_present) {
965            CmsVersion::V4
966        } else if (originator_info_present && v2_certificates_present)
967            || pwri_recipient_info_present
968            || ori_recipient_info_present
969        {
970            CmsVersion::V3
971        } else if !originator_info_present
972            && !unprotected_attributes_present
973            && all_recipient_infos_are_v0
974        {
975            CmsVersion::V0
976        } else {
977            CmsVersion::V2
978        }
979    }
980}
981
982/// Get a hasher for a given digest algorithm
983fn get_hasher(
984    digest_algorithm_identifier: &AlgorithmIdentifierOwned,
985) -> Option<Box<dyn DynDigest>> {
986    let digest_name = DB.by_oid(&digest_algorithm_identifier.oid)?;
987    match digest_name {
988        "id-sha1" => Some(Box::new(sha1::Sha1::new())),
989        "id-sha256" => Some(Box::new(sha2::Sha256::new())),
990        "id-sha384" => Some(Box::new(sha2::Sha384::new())),
991        "id-sha512" => Some(Box::new(sha2::Sha512::new())),
992        "id-sha224" => Some(Box::new(sha2::Sha224::new())),
993        "id-sha-3-224" => Some(Box::new(sha3::Sha3_224::new())),
994        "id-sha-3-256" => Some(Box::new(sha3::Sha3_256::new())),
995        "id-sha-3-384" => Some(Box::new(sha3::Sha3_384::new())),
996        "id-sha-3-512" => Some(Box::new(sha3::Sha3_512::new())),
997        _ => None,
998    }
999}
1000
1001/// Helps encrypting.
1002macro_rules! encrypt_block_mode {
1003    ($data:expr, $block_mode:ident::$typ:ident<$alg:ident>, $key:expr, $rng:expr, $oid:expr) => {{
1004        let (key, iv) = match $key {
1005            None => $block_mode::$typ::<$alg>::generate_key_iv($rng),
1006            Some(key) => {
1007                if key.len() != $alg::key_size() {
1008                    return Err(Error::Builder(String::from(
1009                        "Invalid key size for chosen algorithm",
1010                    )));
1011                }
1012                (
1013                    Key::<$block_mode::$typ<$alg>>::from_slice(key).to_owned(),
1014                    $block_mode::$typ::<$alg>::generate_iv($rng),
1015                )
1016            }
1017        };
1018        let encryptor = $block_mode::$typ::<$alg>::new(&key.into(), &iv.into());
1019        Ok((
1020            encryptor.encrypt_padded_vec_mut::<Pkcs7>($data),
1021            key.to_vec(),
1022            AlgorithmIdentifierOwned {
1023                oid: $oid,
1024                parameters: Some(Any::new(OctetString, iv.to_vec())?),
1025            },
1026        ))
1027    }};
1028}
1029
1030/// Symmetrically encrypt data.
1031/// Returns encrypted content, content-encryption key and the used algorithm identifier (including
1032/// the used algorithm parameters).
1033///
1034/// TODO Which encryption algorithms shall also be supported?
1035fn encrypt_data<R>(
1036    data: &[u8],
1037    encryption_algorithm_identifier: &ContentEncryptionAlgorithm,
1038    key: Option<&[u8]>,
1039    rng: &mut R,
1040) -> Result<(Vec<u8>, Vec<u8>, AlgorithmIdentifierOwned)>
1041where
1042    R: CryptoRng + RngCore,
1043{
1044    match encryption_algorithm_identifier {
1045        ContentEncryptionAlgorithm::Aes128Cbc => encrypt_block_mode!(
1046            data,
1047            cbc::Encryptor<Aes128>,
1048            key,
1049            rng,
1050            encryption_algorithm_identifier.oid()
1051        ),
1052        ContentEncryptionAlgorithm::Aes192Cbc => encrypt_block_mode!(
1053            data,
1054            cbc::Encryptor<Aes192>,
1055            key,
1056            rng,
1057            encryption_algorithm_identifier.oid()
1058        ),
1059        ContentEncryptionAlgorithm::Aes256Cbc => encrypt_block_mode!(
1060            data,
1061            cbc::Encryptor<Aes256>,
1062            key,
1063            rng,
1064            encryption_algorithm_identifier.oid()
1065        ),
1066    }
1067}
1068
1069/// Create a content-type attribute according to
1070/// [RFC 5652 § 11.1](https://datatracker.ietf.org/doc/html/rfc5652#section-11.1)
1071pub fn create_content_type_attribute(content_type: ObjectIdentifier) -> Result<Attribute> {
1072    let content_type_attribute_value =
1073        AttributeValue::new(Tag::ObjectIdentifier, content_type.as_bytes())?;
1074    let mut values = SetOfVec::new();
1075    values.insert(content_type_attribute_value)?;
1076    let attribute = Attribute {
1077        oid: const_oid::db::rfc5911::ID_CONTENT_TYPE,
1078        values,
1079    };
1080    Ok(attribute)
1081}
1082
1083/// Create a message digest attribute according to
1084/// [RFC 5652 § 11.2](https://datatracker.ietf.org/doc/html/rfc5652#section-11.2)
1085pub fn create_message_digest_attribute(message_digest: &[u8]) -> Result<Attribute> {
1086    let message_digest_der = OctetStringRef::new(message_digest)?;
1087    let message_digest_attribute_value =
1088        AttributeValue::new(OctetString, message_digest_der.as_bytes())?;
1089    let mut values = SetOfVec::new();
1090    values.insert(message_digest_attribute_value)?;
1091    let attribute = Attribute {
1092        oid: const_oid::db::rfc5911::ID_MESSAGE_DIGEST,
1093        values,
1094    };
1095    Ok(attribute)
1096}
1097
1098/// Create a signing time attribute according to
1099/// [RFC 5652 § 11.3](https://datatracker.ietf.org/doc/html/rfc5652#section-11.3)
1100/// Dates between 1 January 1950 and 31 December 2049 (inclusive) MUST be
1101/// encoded as UTCTime.  Any dates with year values before 1950 or after
1102/// 2049 MUST be encoded as GeneralizedTime.
1103pub fn create_signing_time_attribute() -> Result<Attribute> {
1104    let now = DateTime::from_system_time(SystemTime::now())?;
1105    let tag = if now.year() < 1950 || now.year() > 2049 {
1106        Tag::GeneralizedTime
1107    } else {
1108        Tag::UtcTime
1109    };
1110    // let mut signing_time_buf = Vec::new();
1111    let time_der = if tag == Tag::GeneralizedTime {
1112        // der::asn1::GeneralizedTime::from_date_time(now).encode_to_vec(&mut signing_time_buf)?;
1113        der::asn1::GeneralizedTime::from_date_time(now).to_der()?
1114    } else {
1115        // der::asn1::UtcTime::from_date_time(now)?.encode_to_vec(&mut signing_time_buf)?;
1116        der::asn1::UtcTime::from_date_time(now)?.to_der()?
1117    };
1118    let signing_time_attribute_value = AttributeValue::from_der(&time_der)?;
1119    let mut values = SetOfVec::<AttributeValue>::new();
1120    values.insert(signing_time_attribute_value)?;
1121    let attribute = Attribute {
1122        oid: const_oid::db::rfc5911::ID_SIGNING_TIME,
1123        values,
1124    };
1125    Ok(attribute)
1126}