1//! Convenience implementation of a SelfSigned object.
23use tor_llcrypto::pk::{self, ValidatableSignature};
45/// A SignatureGated object is a self-signed object that's well-signed
6/// when one or more ValidatableSignature objects are correct.
7pub struct SignatureGated<T> {
8/// The underlying object, which we only want to expose if the
9 /// signature(s) are right.
10obj: T,
11/// A list of ValidatableSignature; these all must be valid, or the
12 /// underlying object is incorrect.
13signatures: Vec<Box<dyn ValidatableSignature>>,
14}
1516impl<T> SignatureGated<T> {
17/// Return a new SignatureGated object that will be treated as
18 /// correct if every one of the given set of signatures is valid.
19pub fn new(obj: T, signatures: Vec<Box<dyn ValidatableSignature>>) -> Self {
20 SignatureGated { obj, signatures }
21 }
2223/// Consume this [`SignatureGated`], and return a new one with the same
24 /// bounds, applying `f` to its protected value.
25 ///
26 /// The caller must ensure that `f` does not make any assumptions about the
27 /// well-signedness of the protected value, or leak any of its contents in
28 /// an inappropriate way.
29#[must_use]
30pub fn dangerously_map<F, U>(self, f: F) -> SignatureGated<U>
31where
32F: FnOnce(T) -> U,
33 {
34 SignatureGated {
35 obj: f(self.obj),
36 signatures: self.signatures,
37 }
38 }
39}
4041impl<T> super::SelfSigned<T> for SignatureGated<T> {
42type Error = signature::Error;
43fn dangerously_assume_wellsigned(self) -> T {
44self.obj
45 }
46fn is_well_signed(&self) -> Result<(), Self::Error> {
47if pk::validate_all_sigs(&self.signatures[..]) {
48Ok(())
49 } else {
50Err(signature::Error::new())
51 }
52 }
53}
5455#[cfg(test)]
56mod test {
57// @@ begin test lint list maintained by maint/add_warning @@
58#![allow(clippy::bool_assert_comparison)]
59 #![allow(clippy::clone_on_copy)]
60 #![allow(clippy::dbg_macro)]
61 #![allow(clippy::mixed_attributes_style)]
62 #![allow(clippy::print_stderr)]
63 #![allow(clippy::print_stdout)]
64 #![allow(clippy::single_char_pattern)]
65 #![allow(clippy::unwrap_used)]
66 #![allow(clippy::unchecked_duration_subtraction)]
67 #![allow(clippy::useless_vec)]
68 #![allow(clippy::needless_pass_by_value)]
69//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
70use super::*;
71use crate::SelfSigned;
72use tor_llcrypto::pk::ValidatableSignature;
7374struct BadSig;
75struct GoodSig;
76impl ValidatableSignature for BadSig {
77fn is_valid(&self) -> bool {
78false
79}
80 }
81impl ValidatableSignature for GoodSig {
82fn is_valid(&self) -> bool {
83true
84}
85 }
8687#[test]
88fn test_sig_gated() {
89// no signature objects means it's valid
90let sg = SignatureGated::new(3_u32, Vec::new());
91assert_eq!(sg.check_signature().unwrap(), 3_u32);
9293// any bad signature means it's bad.
94let sg = SignatureGated::new(77_u32, vec![Box::new(BadSig)]);
95assert!(sg.check_signature().is_err());
96let sg = SignatureGated::new(
9777_u32,
98vec![Box::new(GoodSig), Box::new(BadSig), Box::new(GoodSig)],
99 );
100assert!(sg.check_signature().is_err());
101102// All good signatures means it's good.
103let sg = SignatureGated::new(103_u32, vec![Box::new(GoodSig)]);
104assert_eq!(sg.check_signature().unwrap(), 103_u32);
105let sg = SignatureGated::new(
106104_u32,
107vec![Box::new(GoodSig), Box::new(GoodSig), Box::new(GoodSig)],
108 );
109assert_eq!(sg.check_signature().unwrap(), 104_u32);
110 }
111112#[test]
113fn test_map() {
114let good = SignatureGated::new("hello world...", vec![Box::new(GoodSig)]);
115let good = good.dangerously_map(|s| &s[..11]);
116let s = good.check_signature().unwrap();
117assert_eq!(s, "hello world");
118119let bad = SignatureGated::new("hello world...", vec![Box::new(BadSig)]);
120let still_bad = bad.dangerously_map(|s| &s[..11]);
121assert!(still_bad.check_signature().is_err());
122 }
123}