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}