1
//! Facilities to construct AuthCert objects.
2
//!
3
//! (These are only for testing right now, since we don't yet
4
//! support signing or encoding.)
5

            
6
use super::{AuthCert, AuthCertKeyIds};
7

            
8
use crate::{BuildError as Error, BuildResult};
9
use std::net::SocketAddrV4;
10
use std::ops::Range;
11
use std::time::SystemTime;
12
use tor_llcrypto::pk::rsa;
13

            
14
/// A builder object used to construct an authority certificate.
15
///
16
/// Create one of these with the [`AuthCert::builder`] method.
17
///
18
/// This facility is only enabled when the crate is built with
19
/// the `build_docs` feature.
20
#[cfg_attr(docsrs, doc(cfg(feature = "build_docs")))]
21
pub struct AuthCertBuilder {
22
    /// See [`AuthCert::address`]
23
    address: Option<SocketAddrV4>,
24
    /// See [`AuthCert::identity_key`]
25
    identity_key: Option<rsa::PublicKey>,
26
    /// See [`AuthCert::signing_key`]
27
    signing_key: Option<rsa::PublicKey>,
28
    /// See [`AuthCert::published`]
29
    published: Option<SystemTime>,
30
    /// See [`AuthCert::expires`]
31
    expires: Option<SystemTime>,
32
}
33

            
34
impl AuthCertBuilder {
35
    /// Make a new AuthCertBuilder
36
10
    pub(crate) fn new() -> Self {
37
10
        AuthCertBuilder {
38
10
            address: None,
39
10
            identity_key: None,
40
10
            signing_key: None,
41
10
            published: None,
42
10
            expires: None,
43
10
        }
44
10
    }
45

            
46
    /// Set the IPv4 address for this authority.
47
    ///
48
    /// This field is optional.
49
2
    pub fn address(&mut self, address: SocketAddrV4) -> &mut Self {
50
2
        self.address = Some(address);
51
2
        self
52
2
    }
53

            
54
    /// Set the identity key for this authority.
55
    ///
56
    /// This field is required.
57
8
    pub fn identity_key(&mut self, key: rsa::PublicKey) -> &mut Self {
58
8
        self.identity_key = Some(key);
59
8
        self
60
8
    }
61

            
62
    /// Set the identity key for this certificate.
63
    ///
64
    /// This field is required.
65
8
    pub fn signing_key(&mut self, key: rsa::PublicKey) -> &mut Self {
66
8
        self.signing_key = Some(key);
67
8
        self
68
8
    }
69

            
70
    /// Set the lifespan for this certificate.
71
    ///
72
    /// These fields are required.
73
8
    pub fn lifespan(&mut self, lifespan: Range<SystemTime>) -> &mut Self {
74
8
        self.published = Some(lifespan.start);
75
8
        self.expires = Some(lifespan.end);
76
8
        self
77
8
    }
78

            
79
    /// Try to construct an [`AuthCert`] from this builder.
80
    ///
81
    /// This function can fail if any of the builder's fields are
82
    /// missing or ill-formed.
83
    ///
84
    /// # Danger
85
    ///
86
    /// This function is dangerous because it can be used to construct a
87
    /// certificate where no certificate actually exists: The identity key
88
    /// here has not, in fact, attested to the signing key.
89
    ///
90
    /// You should only use this function for testing.
91
10
    pub fn dangerous_testing_cert(&self) -> BuildResult<AuthCert> {
92
10
        let published = self
93
10
            .published
94
10
            .ok_or(Error::CannotBuild("Missing published time"))?;
95
8
        let expires = self
96
8
            .expires
97
8
            .ok_or(Error::CannotBuild("Missing expiration time"))?;
98
8
        if expires < published {
99
2
            return Err(Error::CannotBuild("Expires before published time."));
100
6
        }
101
6
        let identity_key = self
102
6
            .identity_key
103
6
            .as_ref()
104
6
            .ok_or(Error::CannotBuild("Missing identity key."))?
105
4
            .clone();
106
4
        let signing_key = self
107
4
            .signing_key
108
4
            .as_ref()
109
4
            .ok_or(Error::CannotBuild("Missing signing key."))?
110
2
            .clone();
111
2

            
112
2
        let id_fingerprint = identity_key.to_rsa_identity();
113
2
        let sk_fingerprint = signing_key.to_rsa_identity();
114
2

            
115
2
        let key_ids = AuthCertKeyIds {
116
2
            id_fingerprint,
117
2
            sk_fingerprint,
118
2
        };
119
2

            
120
2
        Ok(AuthCert {
121
2
            address: self.address,
122
2
            identity_key,
123
2
            signing_key,
124
2
            published,
125
2
            expires,
126
2
            key_ids,
127
2
        })
128
10
    }
129
}
130

            
131
#[cfg(test)]
132
mod test {
133
    // @@ begin test lint list maintained by maint/add_warning @@
134
    #![allow(clippy::bool_assert_comparison)]
135
    #![allow(clippy::clone_on_copy)]
136
    #![allow(clippy::dbg_macro)]
137
    #![allow(clippy::mixed_attributes_style)]
138
    #![allow(clippy::print_stderr)]
139
    #![allow(clippy::print_stdout)]
140
    #![allow(clippy::single_char_pattern)]
141
    #![allow(clippy::unwrap_used)]
142
    #![allow(clippy::unchecked_duration_subtraction)]
143
    #![allow(clippy::useless_vec)]
144
    #![allow(clippy::needless_pass_by_value)]
145
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
146
    use super::*;
147
    use hex_literal::hex;
148
    use std::time::Duration;
149

            
150
    fn rsa1() -> rsa::PublicKey {
151
        let der = hex!("30818902818100d527b6c63d6e81d39c328a94ce157dccdc044eb1ad8c210c9c9e22487b4cfade6d4041bd10469a657e3d82bc00cf62ac3b6a99247e573b54c10c47f5dc849b0accda031eca6f6e5dc85677f76dec49ff24d2fcb2b5887fb125aa204744119bb6417f45ee696f8dfc1c2fc21b2bae8e9e37a19dc2518a2c24e7d8fd7fac0f46950203010001");
152
        rsa::PublicKey::from_der(&der).unwrap()
153
    }
154

            
155
    fn rsa2() -> rsa::PublicKey {
156
        let der = hex!("3082010a0282010100d4e420607eddac8264d888cf89a7af78e619db21db5a4671497797614826316f13e2136fd65ed12bbebb724aa6c214d9ceb30a28053778c3da25b87cdb24a246ba427726e17c60b507ed26d8c6377aa14f611dc12f7a7e67ada07fd04e42225a0b84331e347373590f41410c11853e42ee9a34e95a7715edddb651b063e12bf3a58b8c5dce5efd2681d1d4a6ba02def665eb2ba64520577f4d659849858a10f9303fbd934be8a1a461dbe5d7bf0c12c2a3281c63dcdd28f77f5516046253cf7f7a907c15ed2f7baf0aac4c9be3092ec173e15881aebc5d53b5c73dbc545684165510926d8ca202f2e06faaf0da35950c162bf36a2868006837b8b39b61c5b2b10203010001");
157
        rsa::PublicKey::from_der(&der).unwrap()
158
    }
159

            
160
    #[test]
161
    fn simple_cert() {
162
        let now = SystemTime::now();
163
        let one_hour = Duration::new(3600, 0);
164
        let later = now + one_hour * 2;
165
        let addr = "192.0.0.1:9090".parse().unwrap();
166
        let cert = AuthCert::builder()
167
            .identity_key(rsa2())
168
            .signing_key(rsa1())
169
            .address(addr)
170
            .lifespan(now..later)
171
            .dangerous_testing_cert()
172
            .unwrap();
173

            
174
        assert_eq!(cert.key_ids().id_fingerprint, rsa2().to_rsa_identity());
175
        assert_eq!(cert.key_ids().sk_fingerprint, rsa1().to_rsa_identity());
176
        assert_eq!(cert.published(), now);
177
        assert_eq!(cert.expires(), later);
178
    }
179

            
180
    #[test]
181
    fn failing_cert() {
182
        let now = SystemTime::now();
183
        let one_hour = Duration::new(3600, 0);
184
        let later = now + one_hour * 2;
185

            
186
        {
187
            let c = AuthCert::builder()
188
                .identity_key(rsa1())
189
                .lifespan(now..later)
190
                .dangerous_testing_cert();
191
            assert!(c.is_err()); // no signing key.
192
        }
193

            
194
        {
195
            let c = AuthCert::builder()
196
                .signing_key(rsa1())
197
                .lifespan(now..later)
198
                .dangerous_testing_cert();
199
            assert!(c.is_err()); // no identity key.
200
        }
201

            
202
        {
203
            let c = AuthCert::builder()
204
                .signing_key(rsa1())
205
                .identity_key(rsa2())
206
                .dangerous_testing_cert();
207
            assert!(c.is_err()); // no lifespan.
208
        }
209

            
210
        {
211
            let c = AuthCert::builder()
212
                .signing_key(rsa1())
213
                .identity_key(rsa2())
214
                .lifespan(later..now)
215
                .dangerous_testing_cert();
216
            assert!(c.is_err()); // bad lifespan.
217
        }
218
    }
219
}