Skip to main content

isideload_cryptographic_message_syntax/
lib.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5/*! Cryptographic Message Syntax (RFC 5652) in Pure Rust
6
7This crate attempts to implement parts of
8[RFC 5652](https://tools.ietf.org/rfc/rfc5652.txt) in pure, safe Rust.
9
10Functionality includes:
11
12* Partial (de)serialization support for ASN.1 data structures. The
13  Rust structs are all defined. But not everything has (de)serialization
14  code implemented.
15* High-level Rust API for extracting useful attributes from a parsed
16  `SignedData` structure and performing common operations, such as verifying
17  signature integrity.
18
19RFC 5652 is quite old. If you are looking to digitally sign content, you may
20want to look at something newer, such as RPKI (RFC 6488). (RPKI appears to
21be the spiritual success to this specification.)
22
23# IMPORTANT SECURITY LIMITATIONS
24
25**The verification functionality in this crate is purposefully limited
26and isn't sufficient for trusting signed data. You need to include additional
27trust verification if you are using this crate for verifying signed data.**
28
29This crate exposes functionality to verify signatures and content integrity
30of *signed data*. Specifically it can verify that an embedded cryptographic
31signature over some arbitrary/embedded content was issued by a known signing
32certificate. This answers the question *did certificate X sign content Y*.
33This is an important question to answer, but it fails to answer other important
34questions such as:
35
36* Is the signature cryptographically strong or weak? Do I trust the signature?
37* Do I trust the signer?
38
39Answering *do I trust the signer* is an extremely difficult and nuanced
40problem. It entails things like:
41
42* Ensuring the signing certificate is using secure cryptography.
43* Validating that the signing certificate is one you think it was or was
44  issued by a trusted party.
45* Validating the certificate isn't expired or hasn't been revoked.
46* Validating that the certificate contains attributes/extensions desired
47  (e.g. a certificate can be earmarked as used for signing code).
48
49If you are using this crate as part of verifying signed content, you need
50to have answers to these hard questions. This will require writing code
51beyond what is available in this crate. You ideally want to use existing
52libraries for this, as getting this correct is difficult. Ideally you would
53consult a security/cryptography domain expert for help.
54
55# Technical Notes
56
57RFC 5652 is based off PKCS #7 version 1.5 (RFC 2315). So common tools/libraries
58for interacting with PKCS #7 may have success parsing this format. For example,
59you can use OpenSSL to read the data structures:
60
61   $ openssl pkcs7 -inform DER -in <filename> -print
62   $ openssl pkcs7 -inform PEM -in <filename> -print
63   $ openssl asn1parse -inform DER -in <filename>
64
65RFC 5652 uses BER (not DER) for serialization. There were attempts to use
66other, more popular BER/DER/ASN.1 serialization crates. However, we could
67only get `bcder` working. In a similar vein, there are other crates
68implementing support for common ASN.1 functionality, such as serializing
69X.509 certificates. Again, many of these depend on serializers that don't
70seem to be compatible with BER. So we've recursively defined ASN.1 data
71structures referenced by RFC5652 and taught them to serialize using `bcder`.
72*/
73
74pub mod asn1;
75
76#[cfg(feature = "http")]
77mod signing;
78#[cfg(feature = "http")]
79mod time_stamp_protocol;
80
81#[cfg(feature = "http")]
82pub use {
83    signing::{SignedDataBuilder, SignerBuilder},
84    time_stamp_protocol::{
85        TimeStampError, TimeStampResponse, time_stamp_message_http, time_stamp_request_http,
86    },
87};
88
89pub use {bcder::Oid, bytes::Bytes};
90
91use {
92    crate::asn1::{
93        rfc3161::OID_TIME_STAMP_TOKEN,
94        rfc5652::{
95            CertificateChoices, OID_CONTENT_TYPE, OID_MESSAGE_DIGEST, OID_SIGNING_TIME,
96            SignerIdentifier, Time,
97        },
98    },
99    aws_lc_rs::{digest::Digest, signature::UnparsedPublicKey},
100    bcder::{Integer, OctetString},
101    pem::PemError,
102    std::{
103        collections::HashSet,
104        fmt::{Debug, Display, Formatter},
105        ops::Deref,
106    },
107    x509_certificate::{
108        CapturedX509Certificate, DigestAlgorithm, SignatureAlgorithm, X509Certificate,
109        X509CertificateError, certificate::certificate_is_subset_of, rfc3280::Name,
110    },
111};
112
113#[derive(Debug)]
114pub enum CmsError {
115    /// An error occurred decoding ASN.1 data.
116    DecodeErr(bcder::decode::DecodeError<std::convert::Infallible>),
117
118    /// The content-type attribute is missing from the SignedAttributes structure.
119    MissingSignedAttributeContentType,
120
121    /// The content-type attribute in the SignedAttributes structure is malformed.
122    MalformedSignedAttributeContentType,
123
124    /// The message-digest attribute is missed from the SignedAttributes structure.
125    MissingSignedAttributeMessageDigest,
126
127    /// The message-digest attribute is malformed.
128    MalformedSignedAttributeMessageDigest,
129
130    /// The signing-time signed attribute is malformed.
131    MalformedSignedAttributeSigningTime,
132
133    /// The time-stamp token unsigned attribute is malformed.
134    MalformedUnsignedAttributeTimeStampToken,
135
136    /// Subject key identifiers in signer info is not supported.
137    SubjectKeyIdentifierUnsupported,
138
139    /// A general I/O error occurred.
140    Io(std::io::Error),
141
142    /// An unknown signing key algorithm was encountered.
143    UnknownKeyAlgorithm(Oid),
144
145    /// An unknown message digest algorithm was encountered.
146    UnknownDigestAlgorithm(Oid),
147
148    /// An unknown signature algorithm was encountered.
149    UnknownSignatureAlgorithm(Oid),
150
151    /// An unknown certificate format was encountered.
152    UnknownCertificateFormat,
153
154    /// A certificate was not found.
155    CertificateNotFound,
156
157    /// Signature verification fail.
158    SignatureVerificationError,
159
160    /// No `SignedAttributes` were present when they should have been.
161    NoSignedAttributes,
162
163    /// Two content digests were not equivalent.
164    DigestNotEqual,
165
166    /// Error encoding/decoding PEM data.
167    Pem(PemError),
168
169    /// Error occurred when creating a signature.
170    SignatureCreation(signature::Error),
171
172    /// Attempted to use a `Certificate` but we couldn't find the backing data for it.
173    CertificateMissingData,
174
175    /// Error occurred parsing a distinguished name field in a certificate.
176    DistinguishedNameParseError,
177
178    #[cfg(feature = "http")]
179    /// Error occurred in Time-Stamp Protocol.
180    TimeStampProtocol(TimeStampError),
181
182    /// Error occurred in the x509-certificate crate.
183    X509Certificate(X509CertificateError),
184}
185
186impl std::error::Error for CmsError {}
187
188impl Display for CmsError {
189    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
190        match self {
191            Self::DecodeErr(e) => std::fmt::Display::fmt(e, f),
192            Self::MissingSignedAttributeContentType => {
193                f.write_str("content-type attribute missing from SignedAttributes")
194            }
195            Self::MalformedSignedAttributeContentType => {
196                f.write_str("content-type attribute in SignedAttributes is malformed")
197            }
198            Self::MissingSignedAttributeMessageDigest => {
199                f.write_str("message-digest attribute missing from SignedAttributes")
200            }
201            Self::MalformedSignedAttributeMessageDigest => {
202                f.write_str("message-digest attribute in SignedAttributes is malformed")
203            }
204            Self::MalformedSignedAttributeSigningTime => {
205                f.write_str("signing-time attribute in SignedAttributes is malformed")
206            }
207            Self::MalformedUnsignedAttributeTimeStampToken => {
208                f.write_str("time-stamp token attribute in UnsignedAttributes is malformed")
209            }
210            Self::SubjectKeyIdentifierUnsupported => {
211                f.write_str("signer info using subject key identifier is not supported")
212            }
213            Self::Io(e) => std::fmt::Display::fmt(e, f),
214            Self::UnknownKeyAlgorithm(oid) => {
215                f.write_fmt(format_args!("unknown signing key algorithm: {}", oid))
216            }
217            Self::UnknownDigestAlgorithm(oid) => {
218                f.write_fmt(format_args!("unknown digest algorithm: {}", oid))
219            }
220            Self::UnknownSignatureAlgorithm(oid) => {
221                f.write_fmt(format_args!("unknown signature algorithm: {}", oid))
222            }
223            Self::UnknownCertificateFormat => f.write_str("unknown certificate format"),
224            Self::CertificateNotFound => f.write_str("certificate not found"),
225            Self::SignatureVerificationError => f.write_str("signature verification failed"),
226            Self::NoSignedAttributes => f.write_str("SignedAttributes structure is missing"),
227            Self::DigestNotEqual => f.write_str("digests not equivalent"),
228            Self::Pem(e) => f.write_fmt(format_args!("PEM error: {}", e)),
229            Self::SignatureCreation(e) => {
230                f.write_fmt(format_args!("error during signature creation: {}", e))
231            }
232            Self::CertificateMissingData => f.write_str("certificate data not available"),
233            Self::DistinguishedNameParseError => {
234                f.write_str("could not parse distinguished name data")
235            }
236            #[cfg(feature = "http")]
237            Self::TimeStampProtocol(e) => {
238                f.write_fmt(format_args!("Time-Stamp Protocol error: {}", e))
239            }
240            Self::X509Certificate(e) => {
241                f.write_fmt(format_args!("X.509 certificate error: {:?}", e))
242            }
243        }
244    }
245}
246
247impl From<bcder::decode::DecodeError<std::convert::Infallible>> for CmsError {
248    fn from(e: bcder::decode::DecodeError<std::convert::Infallible>) -> Self {
249        Self::DecodeErr(e)
250    }
251}
252
253impl From<std::io::Error> for CmsError {
254    fn from(e: std::io::Error) -> Self {
255        Self::Io(e)
256    }
257}
258
259impl From<PemError> for CmsError {
260    fn from(e: PemError) -> Self {
261        Self::Pem(e)
262    }
263}
264
265#[cfg(feature = "http")]
266impl From<TimeStampError> for CmsError {
267    fn from(e: TimeStampError) -> Self {
268        Self::TimeStampProtocol(e)
269    }
270}
271
272impl From<signature::Error> for CmsError {
273    fn from(e: signature::Error) -> Self {
274        Self::SignatureCreation(e)
275    }
276}
277
278impl From<X509CertificateError> for CmsError {
279    fn from(e: X509CertificateError) -> Self {
280        Self::X509Certificate(e)
281    }
282}
283
284/// Represents a CMS SignedData structure.
285///
286/// This is the high-level type representing a CMS signature of some data.
287/// It contains a description of what was signed, the cryptographic signature
288/// of what was signed, and likely the X.509 certificate chain for the
289/// signing key.
290///
291/// This is a high-level data structure that ultimately gets (de)serialized
292/// from/to ASN.1. It exists to facilitate common interactions with the
293/// low-level ASN.1 without exposing the complexity of ASN.1.
294#[derive(Clone)]
295pub struct SignedData {
296    /// Content digest algorithms used.
297    digest_algorithms: HashSet<DigestAlgorithm>,
298
299    /// Content that was signed.
300    ///
301    /// This is optional because signed content can also be articulated
302    /// via signed attributes inside the `SignerInfo` structure.
303    signed_content: Option<Vec<u8>>,
304
305    /// Certificates embedded within the data structure.
306    ///
307    /// While not required, it is common for the SignedData data structure
308    /// to embed the X.509 certificates used to sign the data within. This
309    /// field holds those certificates.
310    ///
311    /// Typically the root CA is first and the actual signing certificate is
312    /// last.
313    certificates: Option<Vec<CapturedX509Certificate>>,
314
315    /// Describes content signatures.
316    signers: Vec<SignerInfo>,
317}
318
319impl Debug for SignedData {
320    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
321        let mut s = f.debug_struct("SignedData");
322        s.field("digest_algorithms", &self.digest_algorithms);
323        s.field(
324            "signed_content",
325            &format_args!("{:?}", self.signed_content.as_ref().map(hex::encode)),
326        );
327        s.field("certificates", &self.certificates);
328        s.field("signers", &self.signers);
329        s.finish()
330    }
331}
332
333impl SignedData {
334    /// Construct an instance by parsing BER data.
335    pub fn parse_ber(data: &[u8]) -> Result<Self, CmsError> {
336        Self::try_from(&crate::asn1::rfc5652::SignedData::decode_ber(data)?)
337    }
338
339    /// Compute the digest of the encapsulated content using a specified algorithm.
340    ///
341    /// The returned value is likely used as the `message-digest` attribute type
342    /// for use within signed attributes.
343    ///
344    /// You can get the raw bytes of the digest by calling its `.as_ref()`.
345    pub fn message_digest_with_algorithm(&self, alg: DigestAlgorithm) -> Digest {
346        let mut hasher = alg.digester();
347
348        if let Some(content) = &self.signed_content {
349            hasher.update(content);
350        }
351
352        hasher.finish()
353    }
354
355    /// Obtain encapsulated content that was signed.
356    ///
357    /// This is the defined `encapContentInfo cContent` value.
358    pub fn signed_content(&self) -> Option<&[u8]> {
359        if let Some(content) = &self.signed_content {
360            Some(content)
361        } else {
362            None
363        }
364    }
365
366    pub fn certificates(&self) -> Box<dyn Iterator<Item = &CapturedX509Certificate> + '_> {
367        match self.certificates.as_ref() {
368            Some(certs) => Box::new(certs.iter()),
369            None => Box::new(std::iter::empty()),
370        }
371    }
372
373    /// Obtain signing information attached to this instance.
374    ///
375    /// Each iterated value represents an entity that cryptographically signed
376    /// the content. Use these objects to validate the signed data.
377    pub fn signers(&self) -> impl Iterator<Item = &SignerInfo> {
378        self.signers.iter()
379    }
380}
381
382impl TryFrom<&crate::asn1::rfc5652::SignedData> for SignedData {
383    type Error = CmsError;
384
385    fn try_from(raw: &crate::asn1::rfc5652::SignedData) -> Result<Self, Self::Error> {
386        let digest_algorithms = raw
387            .digest_algorithms
388            .iter()
389            .map(DigestAlgorithm::try_from)
390            .collect::<Result<HashSet<_>, _>>()?;
391
392        let signed_content = raw
393            .content_info
394            .content
395            .as_ref()
396            .map(|content| content.to_bytes().to_vec());
397
398        let certificates = if let Some(certs) = &raw.certificates {
399            Some(
400                certs
401                    .iter()
402                    .map(|choice| match choice {
403                        CertificateChoices::Certificate(cert) => {
404                            // Doing the ASN.1 round-tripping here isn't ideal and may
405                            // lead to correctness bugs.
406                            let cert = X509Certificate::from(cert.deref().clone());
407                            let cert_ber = cert.encode_ber()?;
408
409                            Ok(CapturedX509Certificate::from_ber(cert_ber)?)
410                        }
411                        _ => Err(CmsError::UnknownCertificateFormat),
412                    })
413                    .collect::<Result<Vec<_>, CmsError>>()?,
414            )
415        } else {
416            None
417        };
418
419        let signers = raw
420            .signer_infos
421            .iter()
422            .map(SignerInfo::try_from)
423            .collect::<Result<Vec<_>, CmsError>>()?;
424
425        Ok(Self {
426            digest_algorithms,
427            signed_content,
428            certificates,
429            signers,
430        })
431    }
432}
433
434/// Represents a CMS SignerInfo structure.
435///
436/// This is a high-level interface to the SignerInfo ASN.1 type. It supports
437/// performing common operations against that type.
438///
439/// Instances of this type are logically equivalent to a single
440/// signed assertion within a `SignedData` payload. There can be multiple
441/// signers per `SignedData`, which is why this type exists on its own.
442#[derive(Clone)]
443pub struct SignerInfo {
444    /// The X.509 certificate issuer.
445    issuer: Name,
446
447    /// The X.509 certificate serial number.
448    serial_number: Integer,
449
450    /// The algorithm used for digesting signed content.
451    digest_algorithm: DigestAlgorithm,
452
453    /// Algorithm used for signing the digest.
454    signature_algorithm: SignatureAlgorithm,
455
456    /// The cryptographic signature.
457    signature: Vec<u8>,
458
459    /// Parsed signed attributes.
460    signed_attributes: Option<SignedAttributes>,
461
462    /// Raw data constituting SignedAttributes that needs to be digested.
463    digested_signed_attributes_data: Option<Vec<u8>>,
464
465    /// Parsed unsigned attributes.
466    unsigned_attributes: Option<UnsignedAttributes>,
467}
468
469impl Debug for SignerInfo {
470    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
471        let mut s = f.debug_struct("SignerInfo");
472        s.field("issuer", &self.issuer);
473        s.field("serial_number", &self.serial_number);
474        s.field("digest_algorithm", &self.digest_algorithm);
475        s.field("signature_algorithm", &self.signature_algorithm);
476        s.field(
477            "signature",
478            &format_args!("{}", hex::encode(&self.signature)),
479        );
480        s.field("signed_attributes", &self.signed_attributes);
481        s.field(
482            "digested_signed_attributes_data",
483            &format_args!(
484                "{:?}",
485                self.digested_signed_attributes_data
486                    .as_ref()
487                    .map(hex::encode)
488            ),
489        );
490        s.field("unsigned_attributes", &self.unsigned_attributes);
491        s.finish()
492    }
493}
494
495impl SignerInfo {
496    /// Obtain the signing X.509 certificate's issuer name and its serial number.
497    ///
498    /// The returned value can be used to locate the certificate so
499    /// verification can be performed.
500    pub fn certificate_issuer_and_serial(&self) -> Option<(&Name, &Integer)> {
501        Some((&self.issuer, &self.serial_number))
502    }
503
504    /// Obtain the message digest algorithm used by this signer.
505    pub fn digest_algorithm(&self) -> DigestAlgorithm {
506        self.digest_algorithm
507    }
508
509    /// Obtain the cryptographic signing algorithm used by this signer.
510    pub fn signature_algorithm(&self) -> SignatureAlgorithm {
511        self.signature_algorithm
512    }
513
514    /// Obtain the raw bytes constituting the cryptographic signature.
515    ///
516    /// This is the signature that should be verified.
517    pub fn signature(&self) -> &[u8] {
518        &self.signature
519    }
520
521    /// Obtain the `SignedAttributes` attached to this instance.
522    pub fn signed_attributes(&self) -> Option<&SignedAttributes> {
523        self.signed_attributes.as_ref()
524    }
525
526    /// Obtain the `UnsignedAttributes` attached to this instance.
527    pub fn unsigned_attributes(&self) -> Option<&UnsignedAttributes> {
528        self.unsigned_attributes.as_ref()
529    }
530
531    /// Verifies the signature defined by this signer given a [SignedData] instance.
532    ///
533    /// This function will perform cryptographic verification that the signature
534    /// contained within this `SignerInfo` instance is valid for the content that
535    /// was signed. The content that was signed is the encapsulated content from
536    /// the `SignedData` instance (its `.signed_data()` value) combined with
537    /// the `SignedAttributes` attached to this instance.
538    ///
539    /// # IMPORTANT SECURITY LIMITATIONS
540    ///
541    /// This method only performs signature verification. It:
542    ///
543    /// * DOES NOT verify the digest hash embedded within `SignedAttributes` (if present).
544    /// * DOES NOT validate the signing certificate in any way.
545    /// * DOES NOT validate that the cryptography used is appropriate.
546    /// * DOES NOT verify the time stamp token, if present.
547    ///
548    /// See the crate's documentation for more on the security implications.
549    pub fn verify_signature_with_signed_data(
550        &self,
551        signed_data: &SignedData,
552    ) -> Result<(), CmsError> {
553        let signed_content = self.signed_content_with_signed_data(signed_data);
554
555        self.verify_signature_with_signed_data_and_content(signed_data, &signed_content)
556    }
557
558    /// Verifies the signature defined by this signer given a [SignedData] and signed content.
559    ///
560    /// This function will perform cryptographic verification that the signature contained within
561    /// this [SignerInfo] is valid for `signed_content`. Unlike
562    /// [Self::verify_signature_with_signed_data()], the content that was signed is passed in
563    /// explicitly instead of derived from [SignedData].
564    ///
565    /// This is a low-level API that bypasses the normal rules for deriving the raw content a
566    /// cryptographic signature was made over. You probably want to use
567    /// [Self::verify_signature_with_signed_data()] instead. Also note that `signed_content` here
568    /// may or may not be the _encapsulated content_ which is ultimately signed.
569    ///
570    /// This method only performs cryptographic signature verification. It is therefore subject
571    /// to the same limitations as [Self::verify_signature_with_signed_data()].
572    pub fn verify_signature_with_signed_data_and_content(
573        &self,
574        signed_data: &SignedData,
575        signed_content: &[u8],
576    ) -> Result<(), CmsError> {
577        let verifier = self.signature_verifier(signed_data.certificates())?;
578        let signature = self.signature();
579
580        verifier
581            .verify(signed_content, signature)
582            .map_err(|_| CmsError::SignatureVerificationError)
583    }
584
585    /// Verifies the digest stored in signed attributes matches that of content in a `SignedData`.
586    ///
587    /// If signed attributes are present on this instance, they must contain
588    /// a `message-digest` attribute defining the digest of data that was
589    /// signed. The specification says this digested data should come from
590    /// the encapsulated content within `SignedData` (`SignedData.signed_content()`).
591    ///
592    /// Note that some utilities of CMS will not store a computed digest
593    /// in `message-digest` that came from `SignedData` or is using
594    /// the digest algorithm indicated by this `SignerInfo`. This is strictly
595    /// in violation of the specification but it does occur.
596    ///
597    /// # IMPORTANT SECURITY LIMITATIONS
598    ///
599    /// This method only performs message digest verification. It:
600    ///
601    /// * DOES NOT verify the signature over the signed data or anything about
602    ///   the signer.
603    /// * DOES NOT validate that the digest algorithm is strong/appropriate.
604    /// * DOES NOT compare the digests in a manner that is immune to timing
605    ///   side-channels.
606    ///
607    /// See the crate's documentation for more on the security implications.
608    pub fn verify_message_digest_with_signed_data(
609        &self,
610        signed_data: &SignedData,
611    ) -> Result<(), CmsError> {
612        let signed_attributes = self
613            .signed_attributes()
614            .ok_or(CmsError::NoSignedAttributes)?;
615
616        let wanted_digest: &[u8] = signed_attributes.message_digest.as_ref();
617        let got_digest = self.compute_digest_with_signed_data(signed_data);
618
619        // Susceptible to timing side-channel but we don't care per function
620        // documentation.
621        if wanted_digest == got_digest.as_ref() {
622            Ok(())
623        } else {
624            Err(CmsError::DigestNotEqual)
625        }
626    }
627
628    /// Verifies the message digest stored in signed attributes using explicit encapsulated content.
629    ///
630    /// Typically, the digest is computed over content stored in the [SignedData] instance.
631    /// However, it is possible for the signed content to be external. This function
632    /// allows you to define the source of that external content.
633    ///
634    /// Behavior is very similar to [SignerInfo::verify_message_digest_with_signed_data]
635    /// except the original content that was digested is explicitly passed in. This
636    /// content is appended with the signed attributes data on this [SignerInfo].
637    ///
638    /// The security limitations from [SignerInfo::verify_message_digest_with_signed_data]
639    /// apply to this function as well.
640    pub fn verify_message_digest_with_content(&self, data: &[u8]) -> Result<(), CmsError> {
641        let signed_attributes = self
642            .signed_attributes()
643            .ok_or(CmsError::NoSignedAttributes)?;
644
645        let wanted_digest: &[u8] = signed_attributes.message_digest.as_ref();
646        let got_digest = self.compute_digest(Some(data));
647
648        // Susceptible to timing side-channel but we don't care per function
649        // documentation.
650        if wanted_digest == got_digest.as_ref() {
651            Ok(())
652        } else {
653            Err(CmsError::DigestNotEqual)
654        }
655    }
656
657    /// Obtain an entity for validating the signature described by this instance.
658    ///
659    /// This will attempt to locate the certificate used by this signing info
660    /// structure in the passed iterable of certificates and then construct
661    /// a signature verifier that can be used to verify content integrity.
662    ///
663    /// If the certificate referenced by this signing info could not be found,
664    /// an error occurs.
665    ///
666    /// If the signing key's algorithm or signature algorithm aren't supported,
667    /// an error occurs.
668    pub fn signature_verifier<'a, C>(
669        &self,
670        mut certs: C,
671    ) -> Result<UnparsedPublicKey<Vec<u8>>, CmsError>
672    where
673        C: Iterator<Item = &'a CapturedX509Certificate>,
674    {
675        // The issuer of this signature is matched against the list of certificates.
676        let signing_cert = certs
677            .find(|cert| {
678                // We're only verifying signatures here, not validating the certificate.
679                // So even if the certificate comparison functionality is incorrect
680                // (the called function does non-exact matching of the RdnSequence in
681                // case the candidate certs have extra fields), that shouldn't have
682                // security implications.
683                certificate_is_subset_of(
684                    &self.serial_number,
685                    &self.issuer,
686                    cert.serial_number_asn1(),
687                    cert.issuer_name(),
688                )
689            })
690            .ok_or(CmsError::CertificateNotFound)?;
691
692        let key_algorithm = signing_cert.key_algorithm().ok_or_else(|| {
693            CmsError::UnknownKeyAlgorithm(signing_cert.key_algorithm_oid().clone())
694        })?;
695
696        let verification_algorithm = self
697            .signature_algorithm
698            .resolve_verification_algorithm(key_algorithm)?;
699
700        let public_key = UnparsedPublicKey::new(
701            verification_algorithm,
702            signing_cert.public_key_data().to_vec(),
703        );
704
705        Ok(public_key)
706    }
707
708    /// Resolve the time-stamp token [SignedData] for this signer.
709    ///
710    /// The time-stamp token is a SignedData ASN.1 structure embedded as an unsigned
711    /// attribute. This is a convenience method to extract it and turn it into
712    /// a [SignedData].
713    ///
714    /// Returns `Ok(Some)` on success, `Ok(None)` if there is no time-stamp token,
715    /// and `Err` if there is a parsing error.
716    pub fn time_stamp_token_signed_data(&self) -> Result<Option<SignedData>, CmsError> {
717        if let Some(attrs) = self.unsigned_attributes() {
718            if let Some(signed_data) = &attrs.time_stamp_token {
719                Ok(Some(SignedData::try_from(signed_data)?))
720            } else {
721                Ok(None)
722            }
723        } else {
724            Ok(None)
725        }
726    }
727
728    /// Verify the time-stamp token in this instance.
729    ///
730    /// The time-stamp token is a SignedData ASN.1 structure embedded as an unsigned
731    /// attribute. So this method reconstructs that data structure and effectively
732    /// calls [SignerInfo::verify_signature_with_signed_data] and
733    /// [SignerInfo::verify_message_digest_with_signed_data].
734    ///
735    /// Returns `Ok(None)` if there is no time-stamp token and `Ok(Some(()))` if
736    /// there is and the token validates. `Err` occurs on any parse or verification
737    /// error.
738    pub fn verify_time_stamp_token(&self) -> Result<Option<()>, CmsError> {
739        let signed_data = match self.time_stamp_token_signed_data()? {
740            Some(v) => v,
741            _ => {
742                return Ok(None);
743            }
744        };
745
746        if signed_data.signers.is_empty() {
747            return Ok(None);
748        }
749
750        for signer in signed_data.signers() {
751            signer.verify_signature_with_signed_data(&signed_data)?;
752            signer.verify_message_digest_with_signed_data(&signed_data)?;
753        }
754
755        Ok(Some(()))
756    }
757
758    /// Obtain the raw bytes of content that was signed given a `SignedData`.
759    ///
760    /// This joins the encapsulated content from `SignedData` with `SignedAttributes`
761    /// on this instance to produce a new blob. This new blob is the message
762    /// that is signed and whose signature is embedded in `SignerInfo` instances.
763    pub fn signed_content_with_signed_data(&self, signed_data: &SignedData) -> Vec<u8> {
764        self.signed_content(signed_data.signed_content())
765    }
766
767    /// Obtain the raw bytes of content that were digested and signed.
768    ///
769    /// The returned value is the message that was signed and whose signature
770    /// of which needs to be verified.
771    ///
772    /// The optional content argument is the `encapContentInfo eContent`
773    /// field, typically the value of `SignedData.signed_content()`.
774    pub fn signed_content(&self, content: Option<&[u8]>) -> Vec<u8> {
775        // Per RFC 5652 Section 5.4:
776        //
777        //    The result of the message digest calculation process depends on
778        //    whether the signedAttrs field is present.  When the field is absent,
779        //    the result is just the message digest of the content as described
780        //    above.  When the field is present, however, the result is the message
781        //    digest of the complete DER encoding of the SignedAttrs value
782        //    contained in the signedAttrs field.  Since the SignedAttrs value,
783        //    when present, must contain the content-type and the message-digest
784        //    attributes, those values are indirectly included in the result.  The
785        //    content-type attribute MUST NOT be included in a countersignature
786        //    unsigned attribute as defined in Section 11.4.  A separate encoding
787        //    of the signedAttrs field is performed for message digest calculation.
788        //    The IMPLICIT [0] tag in the signedAttrs is not used for the DER
789        //    encoding, rather an EXPLICIT SET OF tag is used.  That is, the DER
790        //    encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0]
791        //    tag, MUST be included in the message digest calculation along with
792        //    the length and content octets of the SignedAttributes value.
793
794        if let Some(signed_attributes_data) = &self.digested_signed_attributes_data {
795            signed_attributes_data.clone()
796        } else if let Some(content) = content {
797            content.to_vec()
798        } else {
799            vec![]
800        }
801    }
802
803    /// Obtain the raw bytes constituting `SignerInfo.signedAttrs` as encoded for signatures.
804    ///
805    /// Cryptographic signatures in the `SignerInfo` ASN.1 type are made from the digest
806    /// of the `EXPLICIT SET OF` DER encoding of `SignerInfo.signedAttrs`, if signed
807    /// attributes are present. This function resolves the raw bytes that are used
808    /// for digest computation and later signing.
809    ///
810    /// This should always be `Some` if the instance was constructed from an ASN.1
811    /// value that had signed attributes.
812    pub fn signed_attributes_data(&self) -> Option<&[u8]> {
813        self.digested_signed_attributes_data
814            .as_ref()
815            .map(|x| x.as_ref())
816    }
817
818    /// Compute a message digest using a `SignedData` instance.
819    ///
820    /// This will obtain the encapsulated content blob from a `SignedData`
821    /// and digest it using the algorithm configured on this instance.
822    ///
823    /// The resulting digest is typically stored in the `message-digest`
824    /// attribute of `SignedData`.
825    pub fn compute_digest_with_signed_data(&self, signed_data: &SignedData) -> Digest {
826        self.compute_digest(signed_data.signed_content())
827    }
828
829    /// Compute a message digest using the configured algorithm.
830    ///
831    /// This method calls into `compute_digest_with_algorithm()` using the
832    /// digest algorithm stored in this instance.
833    pub fn compute_digest(&self, content: Option<&[u8]>) -> Digest {
834        self.compute_digest_with_algorithm(content, self.digest_algorithm)
835    }
836
837    /// Compute a message digest using an explicit digest algorithm.
838    ///
839    /// This will compute the hash/digest of the passed in content.
840    pub fn compute_digest_with_algorithm(
841        &self,
842        content: Option<&[u8]>,
843        alg: DigestAlgorithm,
844    ) -> Digest {
845        let mut hasher = alg.digester();
846
847        if let Some(content) = content {
848            hasher.update(content);
849        }
850
851        hasher.finish()
852    }
853}
854
855impl TryFrom<&crate::asn1::rfc5652::SignerInfo> for SignerInfo {
856    type Error = CmsError;
857
858    fn try_from(signer_info: &crate::asn1::rfc5652::SignerInfo) -> Result<Self, Self::Error> {
859        let (issuer, serial_number) = match &signer_info.sid {
860            SignerIdentifier::IssuerAndSerialNumber(issuer) => {
861                (issuer.issuer.clone(), issuer.serial_number.clone())
862            }
863            SignerIdentifier::SubjectKeyIdentifier(_) => {
864                return Err(CmsError::SubjectKeyIdentifierUnsupported);
865            }
866        };
867
868        let digest_algorithm = DigestAlgorithm::try_from(&signer_info.digest_algorithm)?;
869
870        // The "signature" algorithm can also be a key algorithm identifier. So we
871        // attempt to resolve using the more robust mechanism.
872        let signature_algorithm = SignatureAlgorithm::from_oid_and_digest_algorithm(
873            &signer_info.signature_algorithm.algorithm,
874            digest_algorithm,
875        )?;
876
877        let signature = signer_info.signature.to_bytes().to_vec();
878
879        let signed_attributes = if let Some(attributes) = &signer_info.signed_attributes {
880            // Content type attribute MUST be present.
881            let content_type = attributes
882                .iter()
883                .find(|attr| attr.typ == OID_CONTENT_TYPE)
884                .ok_or(CmsError::MissingSignedAttributeContentType)?;
885
886            // Content type attribute MUST have exactly 1 value.
887            if content_type.values.len() != 1 {
888                return Err(CmsError::MalformedSignedAttributeContentType);
889            }
890
891            let content_type = content_type
892                .values
893                .first()
894                .unwrap()
895                .deref()
896                .clone()
897                .decode(Oid::take_from)
898                .map_err(|_| CmsError::MalformedSignedAttributeContentType)?;
899
900            // Message digest attribute MUST be present.
901            let message_digest = attributes
902                .iter()
903                .find(|attr| attr.typ == OID_MESSAGE_DIGEST)
904                .ok_or(CmsError::MissingSignedAttributeMessageDigest)?;
905
906            // Message digest attribute MUST have exactly 1 value.
907            if message_digest.values.len() != 1 {
908                return Err(CmsError::MalformedSignedAttributeMessageDigest);
909            }
910
911            let message_digest = message_digest
912                .values
913                .first()
914                .unwrap()
915                .deref()
916                .clone()
917                .decode(OctetString::take_from)
918                .map_err(|_| CmsError::MalformedSignedAttributeMessageDigest)?
919                .to_bytes()
920                .to_vec();
921
922            // Signing time is optional, but common. So we pull it out for convenience.
923            let signing_time = attributes
924                .iter()
925                .find(|attr| attr.typ == OID_SIGNING_TIME)
926                .map(|attr| {
927                    if attr.values.len() != 1 {
928                        Err(CmsError::MalformedSignedAttributeSigningTime)
929                    } else {
930                        let time = attr
931                            .values
932                            .first()
933                            .unwrap()
934                            .deref()
935                            .clone()
936                            .decode(Time::take_from)?;
937
938                        let time = chrono::DateTime::from(time);
939
940                        Ok(time)
941                    }
942                })
943                .transpose()?;
944
945            Some(SignedAttributes {
946                content_type,
947                message_digest,
948                signing_time,
949                raw: attributes.clone(),
950            })
951        } else {
952            None
953        };
954
955        let digested_signed_attributes_data = signer_info.signed_attributes_digested_content()?;
956
957        let unsigned_attributes = if let Some(attributes) = &signer_info.unsigned_attributes {
958            let time_stamp_token = attributes
959                .iter()
960                .find(|attr| attr.typ == OID_TIME_STAMP_TOKEN)
961                .map(|attr| {
962                    if attr.values.len() != 1 {
963                        Err(CmsError::MalformedUnsignedAttributeTimeStampToken)
964                    } else {
965                        Ok(attr
966                            .values
967                            .first()
968                            .unwrap()
969                            .deref()
970                            .clone()
971                            .decode(crate::asn1::rfc5652::SignedData::decode)?)
972                    }
973                })
974                .transpose()?;
975
976            Some(UnsignedAttributes { time_stamp_token })
977        } else {
978            None
979        };
980
981        Ok(SignerInfo {
982            issuer,
983            serial_number,
984            digest_algorithm,
985            signature_algorithm,
986            signature,
987            signed_attributes,
988            digested_signed_attributes_data,
989            unsigned_attributes,
990        })
991    }
992}
993
994/// Represents the contents of a CMS SignedAttributes structure.
995///
996/// This is a high-level interface to the SignedAttributes ASN.1 type.
997#[derive(Clone)]
998pub struct SignedAttributes {
999    /// The content type of the value being signed.
1000    ///
1001    /// This is often `OID_ID_DATA`.
1002    content_type: Oid,
1003
1004    /// Holds the digest of the content that was signed.
1005    message_digest: Vec<u8>,
1006
1007    /// The time the signature was created.
1008    signing_time: Option<chrono::DateTime<chrono::Utc>>,
1009
1010    /// The raw ASN.1 signed attributes.
1011    raw: crate::asn1::rfc5652::SignedAttributes,
1012}
1013
1014impl SignedAttributes {
1015    pub fn content_type(&self) -> &Oid {
1016        &self.content_type
1017    }
1018
1019    pub fn message_digest(&self) -> &[u8] {
1020        &self.message_digest
1021    }
1022
1023    pub fn signing_time(&self) -> Option<&chrono::DateTime<chrono::Utc>> {
1024        self.signing_time.as_ref()
1025    }
1026
1027    pub fn attributes(&self) -> &crate::asn1::rfc5652::SignedAttributes {
1028        &self.raw
1029    }
1030}
1031
1032impl Debug for SignedAttributes {
1033    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1034        let mut s = f.debug_struct("SignedAttributes");
1035        s.field("content_type", &format_args!("{}", self.content_type));
1036        s.field(
1037            "message_digest",
1038            &format_args!("{}", hex::encode(&self.message_digest)),
1039        );
1040        s.field("signing_time", &self.signing_time);
1041        s.finish()
1042    }
1043}
1044
1045#[derive(Clone, Debug)]
1046pub struct UnsignedAttributes {
1047    /// Time-Stamp Token from a Time-Stamp Protocol server.
1048    time_stamp_token: Option<crate::asn1::rfc5652::SignedData>,
1049}
1050
1051#[cfg(test)]
1052mod tests {
1053    use {
1054        super::*,
1055        bcder::{Mode, encode::Values},
1056    };
1057
1058    // This signature was extracted from the Firefox.app/Contents/MacOS/firefox
1059    // Mach-O executable on a aarch64 machine.
1060    const FIREFOX_SIGNATURE: &[u8] = include_bytes!("testdata/firefox.ber");
1061
1062    const FIREFOX_CODE_DIRECTORY: &[u8] = include_bytes!("testdata/firefox-code-directory");
1063
1064    #[test]
1065    fn parse_firefox() {
1066        let raw = crate::asn1::rfc5652::SignedData::decode_ber(FIREFOX_SIGNATURE).unwrap();
1067
1068        // Try to round trip it.
1069        let mut buffer = Vec::new();
1070        raw.encode_ref()
1071            .write_encoded(Mode::Ber, &mut buffer)
1072            .unwrap();
1073
1074        // The bytes aren't identical because we use definite length encoding, so we can't
1075        // compare that. But we can compare the parsed objects for equivalence.
1076
1077        let raw2 = crate::asn1::rfc5652::SignedData::decode_ber(&buffer).unwrap();
1078        assert_eq!(raw, raw2, "BER round tripping is identical");
1079    }
1080
1081    #[test]
1082    fn verify_firefox() {
1083        let signed_data = SignedData::parse_ber(FIREFOX_SIGNATURE).unwrap();
1084
1085        for signer in signed_data.signers.iter() {
1086            signer
1087                .verify_signature_with_signed_data(&signed_data)
1088                .unwrap();
1089
1090            // The message-digest does NOT match the encapsulated data in Apple code
1091            // signature's use of CMS. So digest verification will fail.
1092            signer
1093                .verify_message_digest_with_signed_data(&signed_data)
1094                .unwrap_err();
1095
1096            // But we know what that value is. So plug it in to verify.
1097            signer
1098                .verify_message_digest_with_content(FIREFOX_CODE_DIRECTORY)
1099                .unwrap();
1100
1101            // Now verify the time-stamp token embedded as an unsigned attribute.
1102            let tst_signed_data = signer.time_stamp_token_signed_data().unwrap().unwrap();
1103
1104            for signer in tst_signed_data.signers() {
1105                signer
1106                    .verify_message_digest_with_signed_data(&tst_signed_data)
1107                    .unwrap();
1108                signer
1109                    .verify_signature_with_signed_data(&tst_signed_data)
1110                    .unwrap();
1111            }
1112        }
1113    }
1114
1115    #[test]
1116    fn parse_no_certificate_version() {
1117        let signed = SignedData::parse_ber(include_bytes!("testdata/no-cert-version.ber")).unwrap();
1118
1119        let cert_orig = signed.certificates().collect::<Vec<_>>()[0].clone();
1120        let cert = CapturedX509Certificate::from_der(cert_orig.encode_ber().unwrap()).unwrap();
1121
1122        assert_eq!(
1123            hex::encode(cert.sha256_fingerprint().unwrap()),
1124            "b7c2eefd8dac7806af67dfcd92eb18126bc08312a7f2d6f3862e46013c7a6135"
1125        );
1126    }
1127
1128    const IZZYSOFT_SIGNED_DATA: &[u8] = include_bytes!("testdata/izzysoft-signeddata");
1129    const IZZYSOFT_DATA: &[u8] = include_bytes!("testdata/izzysoft-data");
1130
1131    #[test]
1132    fn verify_izzysoft() {
1133        let signed = SignedData::parse_ber(IZZYSOFT_SIGNED_DATA).unwrap();
1134        let cert = signed.certificates().next().unwrap();
1135
1136        for signer in signed.signers() {
1137            // The signed data is external. So this method will fail since it isn't looking at
1138            // the correct source data.
1139            assert!(matches!(
1140                signer.verify_signature_with_signed_data(&signed),
1141                Err(CmsError::SignatureVerificationError)
1142            ));
1143
1144            // There are no signed attributes. So this should error for that reason.
1145            assert!(matches!(
1146                signer.verify_message_digest_with_signed_data(&signed),
1147                Err(CmsError::NoSignedAttributes)
1148            ));
1149
1150            assert!(matches!(
1151                signer.verify_message_digest_with_signed_data(&signed),
1152                Err(CmsError::NoSignedAttributes)
1153            ));
1154
1155            // The certificate advertises SHA-256 for digests but the signature was made with
1156            // SHA-1. So the default algorithm choice will fail.
1157            assert!(matches!(
1158                cert.verify_signed_data(IZZYSOFT_DATA, signer.signature()),
1159                Err(X509CertificateError::CertificateSignatureVerificationFailed)
1160            ));
1161
1162            // But it verifies when SHA-1 digests are forced!
1163            cert.verify_signed_data_with_algorithm(
1164                IZZYSOFT_DATA,
1165                signer.signature(),
1166                &aws_lc_rs::signature::RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY,
1167            )
1168            .unwrap();
1169
1170            signer
1171                .verify_signature_with_signed_data_and_content(&signed, IZZYSOFT_DATA)
1172                .unwrap();
1173
1174            let verifier = signer.signature_verifier(signed.certificates()).unwrap();
1175            verifier.verify(IZZYSOFT_DATA, signer.signature()).unwrap();
1176        }
1177    }
1178}