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        time_stamp_message_http, time_stamp_request_http, TimeStampError, TimeStampResponse,
86    },
87};
88
89pub use {bcder::Oid, bytes::Bytes};
90
91use {
92    crate::asn1::{
93        rfc3161::OID_TIME_STAMP_TOKEN,
94        rfc5652::{
95            CertificateChoices, SignerIdentifier, Time, OID_CONTENT_TYPE, OID_MESSAGE_DIGEST,
96            OID_SIGNING_TIME,
97        },
98    },
99    bcder::{Integer, OctetString},
100    pem::PemError,
101    ring::{digest::Digest, signature::UnparsedPublicKey},
102    std::{
103        collections::HashSet,
104        fmt::{Debug, Display, Formatter},
105        ops::Deref,
106    },
107    x509_certificate::{
108        certificate::certificate_is_subset_of, rfc3280::Name, CapturedX509Certificate,
109        DigestAlgorithm, SignatureAlgorithm, X509Certificate, X509CertificateError,
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()? { Some(v) => {
740            v
741        } _ => {
742            return Ok(None);
743        }};
744
745        if signed_data.signers.is_empty() {
746            return Ok(None);
747        }
748
749        for signer in signed_data.signers() {
750            signer.verify_signature_with_signed_data(&signed_data)?;
751            signer.verify_message_digest_with_signed_data(&signed_data)?;
752        }
753
754        Ok(Some(()))
755    }
756
757    /// Obtain the raw bytes of content that was signed given a `SignedData`.
758    ///
759    /// This joins the encapsulated content from `SignedData` with `SignedAttributes`
760    /// on this instance to produce a new blob. This new blob is the message
761    /// that is signed and whose signature is embedded in `SignerInfo` instances.
762    pub fn signed_content_with_signed_data(&self, signed_data: &SignedData) -> Vec<u8> {
763        self.signed_content(signed_data.signed_content())
764    }
765
766    /// Obtain the raw bytes of content that were digested and signed.
767    ///
768    /// The returned value is the message that was signed and whose signature
769    /// of which needs to be verified.
770    ///
771    /// The optional content argument is the `encapContentInfo eContent`
772    /// field, typically the value of `SignedData.signed_content()`.
773    pub fn signed_content(&self, content: Option<&[u8]>) -> Vec<u8> {
774        // Per RFC 5652 Section 5.4:
775        //
776        //    The result of the message digest calculation process depends on
777        //    whether the signedAttrs field is present.  When the field is absent,
778        //    the result is just the message digest of the content as described
779        //    above.  When the field is present, however, the result is the message
780        //    digest of the complete DER encoding of the SignedAttrs value
781        //    contained in the signedAttrs field.  Since the SignedAttrs value,
782        //    when present, must contain the content-type and the message-digest
783        //    attributes, those values are indirectly included in the result.  The
784        //    content-type attribute MUST NOT be included in a countersignature
785        //    unsigned attribute as defined in Section 11.4.  A separate encoding
786        //    of the signedAttrs field is performed for message digest calculation.
787        //    The IMPLICIT [0] tag in the signedAttrs is not used for the DER
788        //    encoding, rather an EXPLICIT SET OF tag is used.  That is, the DER
789        //    encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0]
790        //    tag, MUST be included in the message digest calculation along with
791        //    the length and content octets of the SignedAttributes value.
792
793        if let Some(signed_attributes_data) = &self.digested_signed_attributes_data {
794            signed_attributes_data.clone()
795        } else if let Some(content) = content {
796            content.to_vec()
797        } else {
798            vec![]
799        }
800    }
801
802    /// Obtain the raw bytes constituting `SignerInfo.signedAttrs` as encoded for signatures.
803    ///
804    /// Cryptographic signatures in the `SignerInfo` ASN.1 type are made from the digest
805    /// of the `EXPLICIT SET OF` DER encoding of `SignerInfo.signedAttrs`, if signed
806    /// attributes are present. This function resolves the raw bytes that are used
807    /// for digest computation and later signing.
808    ///
809    /// This should always be `Some` if the instance was constructed from an ASN.1
810    /// value that had signed attributes.
811    pub fn signed_attributes_data(&self) -> Option<&[u8]> {
812        self.digested_signed_attributes_data
813            .as_ref()
814            .map(|x| x.as_ref())
815    }
816
817    /// Compute a message digest using a `SignedData` instance.
818    ///
819    /// This will obtain the encapsulated content blob from a `SignedData`
820    /// and digest it using the algorithm configured on this instance.
821    ///
822    /// The resulting digest is typically stored in the `message-digest`
823    /// attribute of `SignedData`.
824    pub fn compute_digest_with_signed_data(&self, signed_data: &SignedData) -> Digest {
825        self.compute_digest(signed_data.signed_content())
826    }
827
828    /// Compute a message digest using the configured algorithm.
829    ///
830    /// This method calls into `compute_digest_with_algorithm()` using the
831    /// digest algorithm stored in this instance.
832    pub fn compute_digest(&self, content: Option<&[u8]>) -> Digest {
833        self.compute_digest_with_algorithm(content, self.digest_algorithm)
834    }
835
836    /// Compute a message digest using an explicit digest algorithm.
837    ///
838    /// This will compute the hash/digest of the passed in content.
839    pub fn compute_digest_with_algorithm(
840        &self,
841        content: Option<&[u8]>,
842        alg: DigestAlgorithm,
843    ) -> Digest {
844        let mut hasher = alg.digester();
845
846        if let Some(content) = content {
847            hasher.update(content);
848        }
849
850        hasher.finish()
851    }
852}
853
854impl TryFrom<&crate::asn1::rfc5652::SignerInfo> for SignerInfo {
855    type Error = CmsError;
856
857    fn try_from(signer_info: &crate::asn1::rfc5652::SignerInfo) -> Result<Self, Self::Error> {
858        let (issuer, serial_number) = match &signer_info.sid {
859            SignerIdentifier::IssuerAndSerialNumber(issuer) => {
860                (issuer.issuer.clone(), issuer.serial_number.clone())
861            }
862            SignerIdentifier::SubjectKeyIdentifier(_) => {
863                return Err(CmsError::SubjectKeyIdentifierUnsupported);
864            }
865        };
866
867        let digest_algorithm = DigestAlgorithm::try_from(&signer_info.digest_algorithm)?;
868
869        // The "signature" algorithm can also be a key algorithm identifier. So we
870        // attempt to resolve using the more robust mechanism.
871        let signature_algorithm = SignatureAlgorithm::from_oid_and_digest_algorithm(
872            &signer_info.signature_algorithm.algorithm,
873            digest_algorithm,
874        )?;
875
876        let signature = signer_info.signature.to_bytes().to_vec();
877
878        let signed_attributes = if let Some(attributes) = &signer_info.signed_attributes {
879            // Content type attribute MUST be present.
880            let content_type = attributes
881                .iter()
882                .find(|attr| attr.typ == OID_CONTENT_TYPE)
883                .ok_or(CmsError::MissingSignedAttributeContentType)?;
884
885            // Content type attribute MUST have exactly 1 value.
886            if content_type.values.len() != 1 {
887                return Err(CmsError::MalformedSignedAttributeContentType);
888            }
889
890            let content_type = content_type
891                .values
892                .first()
893                .unwrap()
894                .deref()
895                .clone()
896                .decode(Oid::take_from)
897                .map_err(|_| CmsError::MalformedSignedAttributeContentType)?;
898
899            // Message digest attribute MUST be present.
900            let message_digest = attributes
901                .iter()
902                .find(|attr| attr.typ == OID_MESSAGE_DIGEST)
903                .ok_or(CmsError::MissingSignedAttributeMessageDigest)?;
904
905            // Message digest attribute MUST have exactly 1 value.
906            if message_digest.values.len() != 1 {
907                return Err(CmsError::MalformedSignedAttributeMessageDigest);
908            }
909
910            let message_digest = message_digest
911                .values
912                .first()
913                .unwrap()
914                .deref()
915                .clone()
916                .decode(OctetString::take_from)
917                .map_err(|_| CmsError::MalformedSignedAttributeMessageDigest)?
918                .to_bytes()
919                .to_vec();
920
921            // Signing time is optional, but common. So we pull it out for convenience.
922            let signing_time = attributes
923                .iter()
924                .find(|attr| attr.typ == OID_SIGNING_TIME)
925                .map(|attr| {
926                    if attr.values.len() != 1 {
927                        Err(CmsError::MalformedSignedAttributeSigningTime)
928                    } else {
929                        let time = attr
930                            .values
931                            .first()
932                            .unwrap()
933                            .deref()
934                            .clone()
935                            .decode(Time::take_from)?;
936
937                        let time = chrono::DateTime::from(time);
938
939                        Ok(time)
940                    }
941                })
942                .transpose()?;
943
944            Some(SignedAttributes {
945                content_type,
946                message_digest,
947                signing_time,
948                raw: attributes.clone(),
949            })
950        } else {
951            None
952        };
953
954        let digested_signed_attributes_data = signer_info.signed_attributes_digested_content()?;
955
956        let unsigned_attributes = if let Some(attributes) = &signer_info.unsigned_attributes {
957            let time_stamp_token = attributes
958                .iter()
959                .find(|attr| attr.typ == OID_TIME_STAMP_TOKEN)
960                .map(|attr| {
961                    if attr.values.len() != 1 {
962                        Err(CmsError::MalformedUnsignedAttributeTimeStampToken)
963                    } else {
964                        Ok(attr
965                            .values
966                            .first()
967                            .unwrap()
968                            .deref()
969                            .clone()
970                            .decode(crate::asn1::rfc5652::SignedData::decode)?)
971                    }
972                })
973                .transpose()?;
974
975            Some(UnsignedAttributes { time_stamp_token })
976        } else {
977            None
978        };
979
980        Ok(SignerInfo {
981            issuer,
982            serial_number,
983            digest_algorithm,
984            signature_algorithm,
985            signature,
986            signed_attributes,
987            digested_signed_attributes_data,
988            unsigned_attributes,
989        })
990    }
991}
992
993/// Represents the contents of a CMS SignedAttributes structure.
994///
995/// This is a high-level interface to the SignedAttributes ASN.1 type.
996#[derive(Clone)]
997pub struct SignedAttributes {
998    /// The content type of the value being signed.
999    ///
1000    /// This is often `OID_ID_DATA`.
1001    content_type: Oid,
1002
1003    /// Holds the digest of the content that was signed.
1004    message_digest: Vec<u8>,
1005
1006    /// The time the signature was created.
1007    signing_time: Option<chrono::DateTime<chrono::Utc>>,
1008
1009    /// The raw ASN.1 signed attributes.
1010    raw: crate::asn1::rfc5652::SignedAttributes,
1011}
1012
1013impl SignedAttributes {
1014    pub fn content_type(&self) -> &Oid {
1015        &self.content_type
1016    }
1017
1018    pub fn message_digest(&self) -> &[u8] {
1019        &self.message_digest
1020    }
1021
1022    pub fn signing_time(&self) -> Option<&chrono::DateTime<chrono::Utc>> {
1023        self.signing_time.as_ref()
1024    }
1025
1026    pub fn attributes(&self) -> &crate::asn1::rfc5652::SignedAttributes {
1027        &self.raw
1028    }
1029}
1030
1031impl Debug for SignedAttributes {
1032    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1033        let mut s = f.debug_struct("SignedAttributes");
1034        s.field("content_type", &format_args!("{}", self.content_type));
1035        s.field(
1036            "message_digest",
1037            &format_args!("{}", hex::encode(&self.message_digest)),
1038        );
1039        s.field("signing_time", &self.signing_time);
1040        s.finish()
1041    }
1042}
1043
1044#[derive(Clone, Debug)]
1045pub struct UnsignedAttributes {
1046    /// Time-Stamp Token from a Time-Stamp Protocol server.
1047    time_stamp_token: Option<crate::asn1::rfc5652::SignedData>,
1048}
1049
1050#[cfg(test)]
1051mod tests {
1052    use {
1053        super::*,
1054        bcder::{encode::Values, Mode},
1055    };
1056
1057    // This signature was extracted from the Firefox.app/Contents/MacOS/firefox
1058    // Mach-O executable on a aarch64 machine.
1059    const FIREFOX_SIGNATURE: &[u8] = include_bytes!("testdata/firefox.ber");
1060
1061    const FIREFOX_CODE_DIRECTORY: &[u8] = include_bytes!("testdata/firefox-code-directory");
1062
1063    #[test]
1064    fn parse_firefox() {
1065        let raw = crate::asn1::rfc5652::SignedData::decode_ber(FIREFOX_SIGNATURE).unwrap();
1066
1067        // Try to round trip it.
1068        let mut buffer = Vec::new();
1069        raw.encode_ref()
1070            .write_encoded(Mode::Ber, &mut buffer)
1071            .unwrap();
1072
1073        // The bytes aren't identical because we use definite length encoding, so we can't
1074        // compare that. But we can compare the parsed objects for equivalence.
1075
1076        let raw2 = crate::asn1::rfc5652::SignedData::decode_ber(&buffer).unwrap();
1077        assert_eq!(raw, raw2, "BER round tripping is identical");
1078    }
1079
1080    #[test]
1081    fn verify_firefox() {
1082        let signed_data = SignedData::parse_ber(FIREFOX_SIGNATURE).unwrap();
1083
1084        for signer in signed_data.signers.iter() {
1085            signer
1086                .verify_signature_with_signed_data(&signed_data)
1087                .unwrap();
1088
1089            // The message-digest does NOT match the encapsulated data in Apple code
1090            // signature's use of CMS. So digest verification will fail.
1091            signer
1092                .verify_message_digest_with_signed_data(&signed_data)
1093                .unwrap_err();
1094
1095            // But we know what that value is. So plug it in to verify.
1096            signer
1097                .verify_message_digest_with_content(FIREFOX_CODE_DIRECTORY)
1098                .unwrap();
1099
1100            // Now verify the time-stamp token embedded as an unsigned attribute.
1101            let tst_signed_data = signer.time_stamp_token_signed_data().unwrap().unwrap();
1102
1103            for signer in tst_signed_data.signers() {
1104                signer
1105                    .verify_message_digest_with_signed_data(&tst_signed_data)
1106                    .unwrap();
1107                signer
1108                    .verify_signature_with_signed_data(&tst_signed_data)
1109                    .unwrap();
1110            }
1111        }
1112    }
1113
1114    #[test]
1115    fn parse_no_certificate_version() {
1116        let signed = SignedData::parse_ber(include_bytes!("testdata/no-cert-version.ber")).unwrap();
1117
1118        let cert_orig = signed.certificates().collect::<Vec<_>>()[0].clone();
1119        let cert = CapturedX509Certificate::from_der(cert_orig.encode_ber().unwrap()).unwrap();
1120
1121        assert_eq!(
1122            hex::encode(cert.sha256_fingerprint().unwrap()),
1123            "b7c2eefd8dac7806af67dfcd92eb18126bc08312a7f2d6f3862e46013c7a6135"
1124        );
1125    }
1126
1127    const IZZYSOFT_SIGNED_DATA: &[u8] = include_bytes!("testdata/izzysoft-signeddata");
1128    const IZZYSOFT_DATA: &[u8] = include_bytes!("testdata/izzysoft-data");
1129
1130    #[test]
1131    fn verify_izzysoft() {
1132        let signed = SignedData::parse_ber(IZZYSOFT_SIGNED_DATA).unwrap();
1133        let cert = signed.certificates().next().unwrap();
1134
1135        for signer in signed.signers() {
1136            // The signed data is external. So this method will fail since it isn't looking at
1137            // the correct source data.
1138            assert!(matches!(
1139                signer.verify_signature_with_signed_data(&signed),
1140                Err(CmsError::SignatureVerificationError)
1141            ));
1142
1143            // There are no signed attributes. So this should error for that reason.
1144            assert!(matches!(
1145                signer.verify_message_digest_with_signed_data(&signed),
1146                Err(CmsError::NoSignedAttributes)
1147            ));
1148
1149            assert!(matches!(
1150                signer.verify_message_digest_with_signed_data(&signed),
1151                Err(CmsError::NoSignedAttributes)
1152            ));
1153
1154            // The certificate advertises SHA-256 for digests but the signature was made with
1155            // SHA-1. So the default algorithm choice will fail.
1156            assert!(matches!(
1157                cert.verify_signed_data(IZZYSOFT_DATA, signer.signature()),
1158                Err(X509CertificateError::CertificateSignatureVerificationFailed)
1159            ));
1160
1161            // But it verifies when SHA-1 digests are forced!
1162            cert.verify_signed_data_with_algorithm(
1163                IZZYSOFT_DATA,
1164                signer.signature(),
1165                &ring::signature::RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY,
1166            )
1167            .unwrap();
1168
1169            signer
1170                .verify_signature_with_signed_data_and_content(&signed, IZZYSOFT_DATA)
1171                .unwrap();
1172
1173            let verifier = signer.signature_verifier(signed.certificates()).unwrap();
1174            verifier.verify(IZZYSOFT_DATA, signer.signature()).unwrap();
1175        }
1176    }
1177}