bc_envelope/extension/signature/
signature_impl.rs

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