1
//! Convenience implementation of a SelfSigned object.
2

            
3
use 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.
7
pub 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

            
16
impl<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
2859
    pub fn new(obj: T, signatures: Vec<Box<dyn ValidatableSignature>>) -> Self {
20
2859
        SignatureGated { obj, signatures }
21
2859
    }
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
684
    pub fn dangerously_map<F, U>(self, f: F) -> SignatureGated<U>
31
684
    where
32
684
        F: FnOnce(T) -> U,
33
684
    {
34
684
        SignatureGated {
35
684
            obj: f(self.obj),
36
684
            signatures: self.signatures,
37
684
        }
38
684
    }
39
}
40

            
41
impl<T> super::SelfSigned<T> for SignatureGated<T> {
42
    type Error = signature::Error;
43
947
    fn dangerously_assume_wellsigned(self) -> T {
44
947
        self.obj
45
947
    }
46
917
    fn is_well_signed(&self) -> Result<(), Self::Error> {
47
917
        if pk::validate_all_sigs(&self.signatures[..]) {
48
907
            Ok(())
49
        } else {
50
10
            Err(signature::Error::new())
51
        }
52
917
    }
53
}
54

            
55
#[cfg(test)]
56
mod 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 @@ -->
70
    use super::*;
71
    use crate::SelfSigned;
72
    use tor_llcrypto::pk::ValidatableSignature;
73

            
74
    struct BadSig;
75
    struct GoodSig;
76
    impl ValidatableSignature for BadSig {
77
        fn is_valid(&self) -> bool {
78
            false
79
        }
80
    }
81
    impl ValidatableSignature for GoodSig {
82
        fn is_valid(&self) -> bool {
83
            true
84
        }
85
    }
86

            
87
    #[test]
88
    fn test_sig_gated() {
89
        // no signature objects means it's valid
90
        let sg = SignatureGated::new(3_u32, Vec::new());
91
        assert_eq!(sg.check_signature().unwrap(), 3_u32);
92

            
93
        // any bad signature means it's bad.
94
        let sg = SignatureGated::new(77_u32, vec![Box::new(BadSig)]);
95
        assert!(sg.check_signature().is_err());
96
        let sg = SignatureGated::new(
97
            77_u32,
98
            vec![Box::new(GoodSig), Box::new(BadSig), Box::new(GoodSig)],
99
        );
100
        assert!(sg.check_signature().is_err());
101

            
102
        // All good signatures means it's good.
103
        let sg = SignatureGated::new(103_u32, vec![Box::new(GoodSig)]);
104
        assert_eq!(sg.check_signature().unwrap(), 103_u32);
105
        let sg = SignatureGated::new(
106
            104_u32,
107
            vec![Box::new(GoodSig), Box::new(GoodSig), Box::new(GoodSig)],
108
        );
109
        assert_eq!(sg.check_signature().unwrap(), 104_u32);
110
    }
111

            
112
    #[test]
113
    fn test_map() {
114
        let good = SignatureGated::new("hello world...", vec![Box::new(GoodSig)]);
115
        let good = good.dangerously_map(|s| &s[..11]);
116
        let s = good.check_signature().unwrap();
117
        assert_eq!(s, "hello world");
118

            
119
        let bad = SignatureGated::new("hello world...", vec![Box::new(BadSig)]);
120
        let still_bad = bad.dangerously_map(|s| &s[..11]);
121
        assert!(still_bad.check_signature().is_err());
122
    }
123
}