bc_envelope/extension/signature/
signature_impl.rs

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