bc_envelope/extension/signature/
signature_impl.rs

1use anyhow::{Result, bail};
2use bc_components::{
3    DigestProvider, Signature, Signer, SigningOptions, Verifier,
4};
5#[cfg(feature = "known_value")]
6use known_values;
7
8use super::SignatureMetadata;
9use crate::{Envelope, EnvelopeEncodable, Error};
10
11/// Support for signing envelopes and verifying signatures.
12///
13/// This implementation provides methods for digitally signing envelopes and
14/// verifying signatures. It supports both basic signatures and signatures with
15/// metadata, as well as multi-signature scenarios.
16impl Envelope {
17    /// Creates a signature for the envelope's subject and returns a new
18    /// envelope with a `'signed': Signature` assertion.
19    ///
20    /// - Parameters:
21    ///   - private_key: The signer's `SigningPrivateKey`
22    ///
23    /// - Returns: The signed envelope.
24    pub fn add_signature(&self, private_key: &dyn Signer) -> Self {
25        self.add_signature_opt(private_key, None, None)
26    }
27
28    #[doc(hidden)]
29    /// Creates a signature for the envelope's subject and returns a new
30    /// envelope with a `'signed': Signature` assertion.
31    ///
32    /// - Parameters:
33    ///   - private_key: A signer's `PrivateKeyBase` or `SigningPrivateKey`.
34    ///   - options: Optional signing options.
35    ///   - metadata: Optional metadata for the signature, which itself will be
36    ///     signed.
37    ///
38    /// - Returns: The signed envelope.
39    pub fn add_signature_opt(
40        &self,
41        private_key: &dyn Signer,
42        options: Option<SigningOptions>,
43        metadata: Option<SignatureMetadata>,
44    ) -> Self {
45        let digest = *self.subject().digest().data();
46        let mut signature = Envelope::new(
47            private_key
48                .sign_with_options(&digest as &dyn AsRef<[u8]>, options.clone())
49                .unwrap(),
50        );
51
52        if let Some(metadata) = metadata {
53            if metadata.has_assertions() {
54                let mut signature_with_metadata = signature;
55
56                metadata.assertions().iter().for_each(|assertion| {
57                    signature_with_metadata = signature_with_metadata
58                        .add_assertion_envelope(assertion.to_envelope())
59                        .unwrap();
60                });
61
62                signature_with_metadata = signature_with_metadata.wrap();
63
64                let outer_signature = Envelope::new(
65                    private_key
66                        .sign_with_options(
67                            &signature_with_metadata.digest().as_ref(),
68                            options,
69                        )
70                        .unwrap(),
71                );
72                signature = signature_with_metadata
73                    .add_assertion(known_values::SIGNED, outer_signature);
74            }
75        }
76
77        self.add_assertion(known_values::SIGNED, signature)
78    }
79
80    #[doc(hidden)]
81    /// Creates several signatures for the envelope's subject and returns a new
82    /// envelope with additional `'signed': Signature` assertions.
83    ///
84    /// - Parameters:
85    ///  - private_keys: An array of signers' `SigningPrivateKey`s.
86    ///
87    /// - Returns: The signed envelope.
88    pub fn add_signatures(&self, private_keys: &[&dyn Signer]) -> Self {
89        private_keys
90            .iter()
91            .fold(self.clone(), |envelope, private_key| {
92                envelope.add_signature(*private_key)
93            })
94    }
95
96    #[doc(hidden)]
97    /// Creates several signatures for the envelope's subject and returns a new
98    /// envelope with additional `'signed': Signature` assertions.
99    ///
100    /// - Parameters:
101    ///   - private_keys: An array of signers' `SigningPrivateKey`s and optional
102    ///     `SigningOptions`.
103    ///
104    /// - Returns: The signed envelope.
105    pub fn add_signatures_opt(
106        &self,
107        private_keys: &[(
108            &dyn Signer,
109            Option<SigningOptions>,
110            Option<SignatureMetadata>,
111        )],
112    ) -> Self {
113        private_keys.iter().fold(
114            self.clone(),
115            |envelope, (private_key, options, metadata)| {
116                envelope.add_signature_opt(
117                    *private_key,
118                    options.clone(),
119                    metadata.clone(),
120                )
121            },
122        )
123    }
124
125    /// Convenience constructor for a `'signed': Signature` assertion envelope.
126    ///
127    /// - Parameters:
128    ///   - signature: The `Signature` for the object.
129    ///   - note: An optional note to be added to the `Signature`.
130    ///
131    /// - Returns: The new assertion envelope.
132    pub fn make_signed_assertion(
133        &self,
134        signature: &Signature,
135        note: Option<&str>,
136    ) -> Self {
137        let mut envelope =
138            Envelope::new_assertion(known_values::SIGNED, signature.clone());
139        if let Some(note) = note {
140            envelope = envelope.add_assertion(known_values::NOTE, note);
141        }
142        envelope
143    }
144
145    /// Returns whether the given signature is valid.
146    ///
147    /// - Parameters:
148    ///   - signature: The `Signature` to be checked.
149    ///   - public_key: The potential signer's `Verifier`.
150    ///
151    /// - Returns: `true` if the signature is valid for this envelope's subject,
152    ///   `false` otherwise.
153    pub fn is_verified_signature(
154        &self,
155        signature: &Signature,
156        public_key: &dyn Verifier,
157    ) -> bool {
158        self.is_signature_from_key(signature, public_key)
159    }
160
161    /// Checks whether the given signature is valid for the given public key.
162    ///
163    /// Used for chaining a series of operations that include validating
164    /// signatures.
165    ///
166    /// - Parameters:
167    ///   - signature: The `Signature` to be checked.
168    ///   - public_key: The potential signer's `Verifier`.
169    ///
170    /// - Returns: This envelope.
171    ///
172    /// - Throws: Throws `EnvelopeError.unverifiedSignature` if the signature is
173    ///   not valid. valid.
174    pub fn verify_signature(
175        &self,
176        signature: &Signature,
177        public_key: &dyn Verifier,
178    ) -> Result<Self> {
179        if !self.is_signature_from_key(signature, public_key) {
180            bail!(Error::UnverifiedSignature);
181        }
182        Ok(self.clone())
183    }
184
185    /// Returns whether the envelope's subject has a valid signature from the
186    /// given public key.
187    ///
188    /// - Parameters:
189    ///   - public_key: The potential signer's `Verifier`.
190    ///
191    /// - Returns: `true` if any signature is valid for this envelope's subject,
192    ///   `false` otherwise.
193    ///
194    /// - Throws: Throws an exception if any `'signed'` assertion doesn't
195    ///   contain a valid `Signature` as its object.
196    pub fn has_signature_from(
197        &self,
198        public_key: &dyn Verifier,
199    ) -> Result<bool> {
200        self.has_some_signature_from_key(public_key)
201    }
202
203    /// Returns whether the envelope's subject has a valid signature from the
204    /// given public key by returning the signature metadata.
205    ///
206    /// - Parameters:
207    ///  - public_key: The potential signer's `Verifier`.
208    ///
209    /// - Returns: The metadata envelope if the signature is valid, `None`
210    ///   otherwise.
211    pub fn has_signature_from_returning_metadata(
212        &self,
213        public_key: &dyn Verifier,
214    ) -> Result<Option<Envelope>> {
215        self.has_some_signature_from_key_returning_metadata(public_key)
216    }
217
218    /// Returns whether the envelope's subject has a valid signature from the
219    /// given public key.
220    ///
221    /// Used for chaining a series of operations that include validating
222    /// signatures.
223    ///
224    /// - Parameters:
225    ///   - public_key: The potential signer's `Verifier`.
226    ///
227    /// - Returns: This envelope.
228    ///
229    /// - Throws: Throws `EnvelopeError.unverifiedSignature` if the signature is
230    ///   not valid. valid.
231    pub fn verify_signature_from(
232        &self,
233        public_key: &dyn Verifier,
234    ) -> Result<Self> {
235        if !self.has_some_signature_from_key(public_key)? {
236            bail!(Error::UnverifiedSignature);
237        }
238        Ok(self.clone())
239    }
240
241    pub fn verify_signature_from_returning_metadata(
242        &self,
243        public_key: &dyn Verifier,
244    ) -> Result<Envelope> {
245        let metadata =
246            self.has_some_signature_from_key_returning_metadata(public_key)?;
247        if metadata.is_none() {
248            bail!(Error::UnverifiedSignature);
249        }
250        Ok(metadata.unwrap())
251    }
252
253    /// Checks whether the envelope's subject has a set of signatures.
254    pub fn has_signatures_from(
255        &self,
256        public_keys: &[&dyn Verifier],
257    ) -> Result<bool> {
258        self.has_signatures_from_threshold(public_keys, None)
259    }
260
261    /// Returns whether the envelope's subject has some threshold of signatures.
262    ///
263    /// If `threshold` is `nil`, then *all* signers in `public_keys` must have
264    /// signed. If `threshold` is `1`, then at least one signer must have
265    /// signed.
266    ///
267    /// - Parameters:
268    ///   - public_keys: An array of potential signers' `Verifier`s.
269    ///   - threshold: Optional minimum number of signers.
270    ///
271    /// - Returns: `true` if the threshold of valid signatures is met, `false`
272    ///   otherwise.
273    ///
274    /// - Throws: Throws an exception if any `'signed'` assertion doesn't
275    ///   contain a valid `Signature` as its object.
276    pub fn has_signatures_from_threshold(
277        &self,
278        public_keys: &[&dyn Verifier],
279        threshold: Option<usize>,
280    ) -> Result<bool> {
281        let threshold = threshold.unwrap_or(public_keys.len());
282        let mut count = 0;
283        for key in public_keys {
284            if self.clone().has_some_signature_from_key(*key)? {
285                count += 1;
286                if count >= threshold {
287                    return Ok(true);
288                }
289            }
290        }
291        Ok(false)
292    }
293
294    /// Checks whether the envelope's subject has some threshold of signatures.
295    ///
296    /// If `threshold` is `nil`, then *all* signers in `public_keys` must have
297    /// signed. If `threshold` is `1`, then at least one signer must have
298    /// signed.
299    ///
300    /// Used for chaining a series of operations that include validating
301    /// signatures.
302    ///
303    /// - Parameters:
304    ///   - public_keys: An array of potential signers' `Verifier`s.
305    ///   - threshold: Optional minimum number of signers.
306    ///
307    /// - Returns: This envelope.
308    ///
309    /// - Throws: Throws an exception if the threshold of valid signatures is
310    ///   not met.
311    pub fn verify_signatures_from_threshold(
312        &self,
313        public_keys: &[&dyn Verifier],
314        threshold: Option<usize>,
315    ) -> Result<Self> {
316        if !self.has_signatures_from_threshold(public_keys, threshold)? {
317            bail!(Error::UnverifiedSignature);
318        }
319        Ok(self.clone())
320    }
321
322    /// Checks whether the envelope's subject has a set of signatures.
323    pub fn verify_signatures_from(
324        &self,
325        public_keys: &[&dyn Verifier],
326    ) -> Result<Self> {
327        self.verify_signatures_from_threshold(public_keys, None)
328    }
329}
330
331/// Internal implementation details for signature operations.
332#[doc(hidden)]
333impl Envelope {
334    fn is_signature_from_key(
335        &self,
336        signature: &Signature,
337        key: &dyn Verifier,
338    ) -> bool {
339        key.verify(signature, self.subject().digest().as_ref())
340    }
341
342    fn has_some_signature_from_key(&self, key: &dyn Verifier) -> Result<bool> {
343        self.has_some_signature_from_key_returning_metadata(key)
344            .map(|x| x.is_some())
345    }
346
347    fn has_some_signature_from_key_returning_metadata(
348        &self,
349        key: &dyn Verifier,
350    ) -> Result<Option<Envelope>> {
351        // Valid signature objects are either:
352        //
353        // - `Signature` objects, or
354        // - `Signature` objects with additional metadata assertions, wrapped
355        // and then signed by the same key.
356        let signature_objects =
357            self.objects_for_predicate(known_values::SIGNED);
358        let result: Option<Result<Option<Envelope>>> =
359            signature_objects.iter().find_map(|signature_object| {
360                let signature_object_subject = signature_object.subject();
361                if signature_object_subject.is_wrapped() {
362                    if let Ok(outer_signature_object) = signature_object
363                        .object_for_predicate(known_values::SIGNED)
364                    {
365                        if let Ok(outer_signature) = outer_signature_object
366                            .extract_subject::<Signature>(
367                        ) {
368                            if !signature_object_subject
369                                .is_signature_from_key(&outer_signature, key)
370                            {
371                                return None;
372                            }
373                        } else {
374                            return Some(Err(anyhow::anyhow!(
375                                Error::InvalidOuterSignatureType
376                            )));
377                        }
378                    }
379
380                    let signature_metadata_envelope =
381                        signature_object_subject.try_unwrap().unwrap();
382                    if let Ok(signature) = signature_metadata_envelope
383                        .extract_subject::<Signature>()
384                    {
385                        let signing_target = self.subject();
386                        if !signing_target
387                            .is_signature_from_key(&signature, key)
388                        {
389                            return Some(Err(anyhow::anyhow!(
390                                Error::UnverifiedInnerSignature
391                            )));
392                        }
393                        Some(Ok(Some(signature_metadata_envelope)))
394                    } else {
395                        Some(Err(anyhow::anyhow!(
396                            Error::InvalidInnerSignatureType
397                        )))
398                    }
399                } else if let Ok(signature) =
400                    signature_object.extract_subject::<Signature>()
401                {
402                    if !self.is_signature_from_key(&signature, key) {
403                        return None;
404                    }
405                    Some(Ok(Some(signature_object.clone())))
406                } else {
407                    Some(Err(anyhow::anyhow!(Error::InvalidSignatureType)))
408                }
409            });
410
411        match result {
412            Some(Ok(Some(envelope))) => Ok(Some(envelope)),
413            Some(Err(err)) => Err(err),
414            _ => Ok(None),
415        }
416    }
417}
418
419/// Convenience methods for signing and verifying envelopes.
420///
421/// These methods provide a simpler API for common signature operations,
422/// particularly for signing entire envelopes by automatically wrapping them.
423impl Envelope {
424    /// Signs the entire envelope (subject and assertions) by wrapping it first.
425    ///
426    /// This is a convenience method that wraps the envelope before signing,
427    /// ensuring that all assertions are included in the signature, not just
428    /// the subject.
429    ///
430    /// # Parameters
431    ///
432    /// * `signer` - The signer that will produce the signature.
433    ///
434    /// # Returns
435    ///
436    /// A new envelope with the wrapped envelope as subject and a signature
437    /// assertion.
438    pub fn sign(&self, signer: &dyn Signer) -> Envelope {
439        self.sign_opt(signer, None)
440    }
441
442    /// Signs the entire envelope with options but no metadata.
443    ///
444    /// This is a convenience method that wraps the envelope before signing with
445    /// the specified options.
446    ///
447    /// # Parameters
448    ///
449    /// * `signer` - The signer that will produce the signature.
450    /// * `options` - Optional signing options to customize the signature
451    ///   generation.
452    ///
453    /// # Returns
454    ///
455    /// A new envelope with the wrapped envelope as subject and a signature
456    /// assertion.
457    pub fn sign_opt(
458        &self,
459        signer: &dyn Signer,
460        options: Option<SigningOptions>,
461    ) -> Envelope {
462        self.wrap().add_signature_opt(signer, options, None)
463    }
464
465    /// Verifies that the envelope has a valid signature from the specified
466    /// verifier.
467    ///
468    /// This method assumes the envelope is wrapped (i.e., was signed using
469    /// `sign()` rather than `add_signature()`), and unwraps it after
470    /// verification.
471    ///
472    /// # Parameters
473    ///
474    /// * `verifier` - The verifier to check the signature against.
475    ///
476    /// # Returns
477    ///
478    /// The unwrapped envelope if verification succeeds, otherwise an error.
479    ///
480    /// # Errors
481    ///
482    /// Returns an error if the signature verification fails or if the envelope
483    /// cannot be unwrapped.
484    pub fn verify(&self, verifier: &dyn Verifier) -> Result<Envelope> {
485        self.verify_signature_from(verifier)?.try_unwrap()
486    }
487
488    /// Verifies the envelope's signature and returns both the unwrapped
489    /// envelope and signature metadata.
490    ///
491    /// This method verifies that the envelope has a valid signature from the
492    /// specified verifier, then unwraps it and returns both the envelope
493    /// and any metadata associated with the signature.
494    ///
495    /// # Parameters
496    ///
497    /// * `verifier` - The verifier to check the signature against.
498    ///
499    /// # Returns
500    ///
501    /// A tuple containing the unwrapped envelope and the signature metadata
502    /// envelope if verification succeeds, otherwise an error.
503    ///
504    /// # Errors
505    ///
506    /// Returns an error if the signature verification fails or if the envelope
507    /// cannot be unwrapped.
508    pub fn verify_returning_metadata(
509        &self,
510        verifier: &dyn Verifier,
511    ) -> Result<(Envelope, Envelope)> {
512        let metadata =
513            self.verify_signature_from_returning_metadata(verifier)?;
514        Ok((self.try_unwrap()?, metadata))
515    }
516}