Skip to main content

tor_checkable/
signed.rs

1//! Convenience implementation of a SelfSigned object.
2
3use tor_llcrypto::pk::{self, ValidatableSignature};
4
5/// 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.
10    obj: T,
11    /// A list of ValidatableSignature; these all must be valid, or the
12    /// underlying object is incorrect.
13    signatures: Vec<Box<dyn ValidatableSignature>>,
14}
15
16impl<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.
19    pub fn new(obj: T, signatures: Vec<Box<dyn ValidatableSignature>>) -> Self {
20        SignatureGated { obj, signatures }
21    }
22
23    /// 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]
30    pub fn dangerously_map<F, U>(self, f: F) -> SignatureGated<U>
31    where
32        F: FnOnce(T) -> U,
33    {
34        SignatureGated {
35            obj: f(self.obj),
36            signatures: self.signatures,
37        }
38    }
39}
40
41impl<T> super::SelfSigned<T> for SignatureGated<T> {
42    type Error = signature::Error;
43    fn dangerously_assume_wellsigned(self) -> T {
44        self.obj
45    }
46    fn is_well_signed(&self) -> Result<(), Self::Error> {
47        if pk::validate_all_sigs(&self.signatures[..]) {
48            Ok(())
49        } else {
50            Err(signature::Error::new())
51        }
52    }
53}
54
55#[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_time_subtraction)]
67    #![allow(clippy::useless_vec)]
68    #![allow(clippy::needless_pass_by_value)]
69    #![allow(clippy::string_slice)] // See arti#2571
70    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
71    use super::*;
72    use crate::SelfSigned;
73    use tor_llcrypto::pk::ValidatableSignature;
74
75    struct BadSig;
76    struct GoodSig;
77    impl ValidatableSignature for BadSig {
78        fn is_valid(&self) -> bool {
79            false
80        }
81    }
82    impl ValidatableSignature for GoodSig {
83        fn is_valid(&self) -> bool {
84            true
85        }
86    }
87
88    #[test]
89    fn test_sig_gated() {
90        // no signature objects means it's valid
91        let sg = SignatureGated::new(3_u32, Vec::new());
92        assert_eq!(sg.check_signature().unwrap(), 3_u32);
93
94        // any bad signature means it's bad.
95        let sg = SignatureGated::new(77_u32, vec![Box::new(BadSig)]);
96        assert!(sg.check_signature().is_err());
97        let sg = SignatureGated::new(
98            77_u32,
99            vec![Box::new(GoodSig), Box::new(BadSig), Box::new(GoodSig)],
100        );
101        assert!(sg.check_signature().is_err());
102
103        // All good signatures means it's good.
104        let sg = SignatureGated::new(103_u32, vec![Box::new(GoodSig)]);
105        assert_eq!(sg.check_signature().unwrap(), 103_u32);
106        let sg = SignatureGated::new(
107            104_u32,
108            vec![Box::new(GoodSig), Box::new(GoodSig), Box::new(GoodSig)],
109        );
110        assert_eq!(sg.check_signature().unwrap(), 104_u32);
111    }
112
113    #[test]
114    fn test_map() {
115        let good = SignatureGated::new("hello world...", vec![Box::new(GoodSig)]);
116        let good = good.dangerously_map(|s| &s[..11]);
117        let s = good.check_signature().unwrap();
118        assert_eq!(s, "hello world");
119
120        let bad = SignatureGated::new("hello world...", vec![Box::new(BadSig)]);
121        let still_bad = bad.dangerously_map(|s| &s[..11]);
122        assert!(still_bad.check_signature().is_err());
123    }
124}