tor_netdoc/doc/authcert/
build.rs

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
6use super::{AuthCert, AuthCertKeyIds};
7
8use crate::{BuildError as Error, BuildResult};
9use std::net::SocketAddrV4;
10use std::ops::Range;
11use std::time::SystemTime;
12use 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")))]
21pub 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
34impl AuthCertBuilder {
35    /// Make a new AuthCertBuilder
36    pub(crate) fn new() -> Self {
37        AuthCertBuilder {
38            address: None,
39            identity_key: None,
40            signing_key: None,
41            published: None,
42            expires: None,
43        }
44    }
45
46    /// Set the IPv4 address for this authority.
47    ///
48    /// This field is optional.
49    pub fn address(&mut self, address: SocketAddrV4) -> &mut Self {
50        self.address = Some(address);
51        self
52    }
53
54    /// Set the identity key for this authority.
55    ///
56    /// This field is required.
57    pub fn identity_key(&mut self, key: rsa::PublicKey) -> &mut Self {
58        self.identity_key = Some(key);
59        self
60    }
61
62    /// Set the identity key for this certificate.
63    ///
64    /// This field is required.
65    pub fn signing_key(&mut self, key: rsa::PublicKey) -> &mut Self {
66        self.signing_key = Some(key);
67        self
68    }
69
70    /// Set the lifespan for this certificate.
71    ///
72    /// These fields are required.
73    pub fn lifespan(&mut self, lifespan: Range<SystemTime>) -> &mut Self {
74        self.published = Some(lifespan.start);
75        self.expires = Some(lifespan.end);
76        self
77    }
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    pub fn dangerous_testing_cert(&self) -> BuildResult<AuthCert> {
92        let published = self
93            .published
94            .ok_or(Error::CannotBuild("Missing published time"))?;
95        let expires = self
96            .expires
97            .ok_or(Error::CannotBuild("Missing expiration time"))?;
98        if expires < published {
99            return Err(Error::CannotBuild("Expires before published time."));
100        }
101        let identity_key = self
102            .identity_key
103            .as_ref()
104            .ok_or(Error::CannotBuild("Missing identity key."))?
105            .clone();
106        let signing_key = self
107            .signing_key
108            .as_ref()
109            .ok_or(Error::CannotBuild("Missing signing key."))?
110            .clone();
111
112        let id_fingerprint = identity_key.to_rsa_identity();
113        let sk_fingerprint = signing_key.to_rsa_identity();
114
115        let key_ids = AuthCertKeyIds {
116            id_fingerprint,
117            sk_fingerprint,
118        };
119
120        Ok(AuthCert {
121            address: self.address,
122            identity_key,
123            signing_key,
124            published,
125            expires,
126            key_ids,
127        })
128    }
129}
130
131#[cfg(test)]
132mod 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}