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}