Skip to main content

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#![allow(deprecated)]
6
7use super::{AuthCert, AuthCertVersion, CrossCert, CrossCertObject};
8
9use crate::{BuildError as Error, BuildResult};
10use std::net::SocketAddrV4;
11use std::ops::Range;
12use std::time::SystemTime;
13use tor_llcrypto::pk::rsa;
14
15/// A builder object used to construct an authority certificate.
16///
17/// Create one of these with the [`AuthCert::builder`] method.
18///
19/// This facility is only enabled when the crate is built with
20/// the `build_docs` feature.
21#[deprecated = "use AuthCertConstructor instead"]
22#[cfg_attr(docsrs, doc(cfg(feature = "build_docs")))]
23pub struct AuthCertBuilder {
24    /// See [`AuthCert::dir_address`]
25    address: Option<SocketAddrV4>,
26    /// See [`AuthCert::dir_identity_key`]
27    identity_key: Option<rsa::PublicKey>,
28    /// See [`AuthCert::signing_key`]
29    signing_key: Option<rsa::PublicKey>,
30    /// See [`AuthCert::published`]
31    published: Option<SystemTime>,
32    /// See [`AuthCert::expires`]
33    expires: Option<SystemTime>,
34}
35
36impl AuthCertBuilder {
37    /// Make a new AuthCertBuilder
38    pub(crate) fn new() -> Self {
39        AuthCertBuilder {
40            address: None,
41            identity_key: None,
42            signing_key: None,
43            published: None,
44            expires: None,
45        }
46    }
47
48    /// Set the IPv4 address for this authority.
49    ///
50    /// This field is optional.
51    pub fn address(&mut self, address: SocketAddrV4) -> &mut Self {
52        self.address = Some(address);
53        self
54    }
55
56    /// Set the identity key for this authority.
57    ///
58    /// This field is required.
59    pub fn identity_key(&mut self, key: rsa::PublicKey) -> &mut Self {
60        self.identity_key = Some(key);
61        self
62    }
63
64    /// Set the identity key for this certificate.
65    ///
66    /// This field is required.
67    pub fn signing_key(&mut self, key: rsa::PublicKey) -> &mut Self {
68        self.signing_key = Some(key);
69        self
70    }
71
72    /// Set the lifespan for this certificate.
73    ///
74    /// These fields are required.
75    pub fn lifespan(&mut self, lifespan: Range<SystemTime>) -> &mut Self {
76        self.published = Some(lifespan.start);
77        self.expires = Some(lifespan.end);
78        self
79    }
80
81    /// Try to construct an [`AuthCert`] from this builder.
82    ///
83    /// This function can fail if any of the builder's fields are
84    /// missing or ill-formed.
85    ///
86    /// # Danger
87    ///
88    /// This function is dangerous because it can be used to construct a
89    /// certificate where no certificate actually exists: The identity key
90    /// here has not, in fact, attested to the signing key.
91    ///
92    /// You should only use this function for testing.
93    pub fn dangerous_testing_cert(&self) -> BuildResult<AuthCert> {
94        let dir_key_published = self
95            .published
96            .ok_or(Error::CannotBuild("Missing published time"))?
97            .into();
98        let dir_key_expires = self
99            .expires
100            .ok_or(Error::CannotBuild("Missing expiration time"))?
101            .into();
102        if dir_key_expires < dir_key_published {
103            return Err(Error::CannotBuild("Expires before published time."));
104        }
105        let dir_identity_key = self
106            .identity_key
107            .as_ref()
108            .ok_or(Error::CannotBuild("Missing identity key."))?
109            .clone();
110        let dir_signing_key = self
111            .signing_key
112            .as_ref()
113            .ok_or(Error::CannotBuild("Missing signing key."))?
114            .clone();
115
116        let id_fingerprint = dir_identity_key.to_rsa_identity();
117
118        // This is a nonsense value, but the tests don't look at it.
119        let dir_key_crosscert = CrossCert {
120            signature: CrossCertObject(vec![]),
121        };
122
123        Ok(AuthCert {
124            dir_address: self.address,
125            dir_identity_key,
126            dir_signing_key,
127            dir_key_published,
128            dir_key_expires,
129            fingerprint: crate::types::Fingerprint(id_fingerprint),
130            dir_key_certificate_version: AuthCertVersion::V3,
131            dir_key_crosscert,
132            __non_exhaustive: (),
133        })
134    }
135}
136
137#[cfg(test)]
138mod test {
139    // @@ begin test lint list maintained by maint/add_warning @@
140    #![allow(clippy::bool_assert_comparison)]
141    #![allow(clippy::clone_on_copy)]
142    #![allow(clippy::dbg_macro)]
143    #![allow(clippy::mixed_attributes_style)]
144    #![allow(clippy::print_stderr)]
145    #![allow(clippy::print_stdout)]
146    #![allow(clippy::single_char_pattern)]
147    #![allow(clippy::unwrap_used)]
148    #![allow(clippy::unchecked_time_subtraction)]
149    #![allow(clippy::useless_vec)]
150    #![allow(clippy::needless_pass_by_value)]
151    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
152    use super::*;
153    use hex_literal::hex;
154    use std::time::Duration;
155    use web_time_compat::SystemTimeExt;
156
157    fn rsa1() -> rsa::PublicKey {
158        let der = hex!(
159            "30818902818100d527b6c63d6e81d39c328a94ce157dccdc044eb1ad8c210c9c9e22487b4cfade6d4041bd10469a657e3d82bc00cf62ac3b6a99247e573b54c10c47f5dc849b0accda031eca6f6e5dc85677f76dec49ff24d2fcb2b5887fb125aa204744119bb6417f45ee696f8dfc1c2fc21b2bae8e9e37a19dc2518a2c24e7d8fd7fac0f46950203010001"
160        );
161        rsa::PublicKey::from_der(&der).unwrap()
162    }
163
164    fn rsa2() -> rsa::PublicKey {
165        let der = hex!(
166            "3082010a0282010100d4e420607eddac8264d888cf89a7af78e619db21db5a4671497797614826316f13e2136fd65ed12bbebb724aa6c214d9ceb30a28053778c3da25b87cdb24a246ba427726e17c60b507ed26d8c6377aa14f611dc12f7a7e67ada07fd04e42225a0b84331e347373590f41410c11853e42ee9a34e95a7715edddb651b063e12bf3a58b8c5dce5efd2681d1d4a6ba02def665eb2ba64520577f4d659849858a10f9303fbd934be8a1a461dbe5d7bf0c12c2a3281c63dcdd28f77f5516046253cf7f7a907c15ed2f7baf0aac4c9be3092ec173e15881aebc5d53b5c73dbc545684165510926d8ca202f2e06faaf0da35950c162bf36a2868006837b8b39b61c5b2b10203010001"
167        );
168        rsa::PublicKey::from_der(&der).unwrap()
169    }
170
171    #[test]
172    fn simple_cert() {
173        let now = SystemTime::get();
174        let one_hour = Duration::new(3600, 0);
175        let later = now + one_hour * 2;
176        let addr = "192.0.0.1:9090".parse().unwrap();
177        let cert = AuthCert::builder()
178            .identity_key(rsa2())
179            .signing_key(rsa1())
180            .address(addr)
181            .lifespan(now..later)
182            .dangerous_testing_cert()
183            .unwrap();
184
185        assert_eq!(cert.key_ids().id_fingerprint, rsa2().to_rsa_identity());
186        assert_eq!(cert.key_ids().sk_fingerprint, rsa1().to_rsa_identity());
187        assert_eq!(cert.published(), now);
188        assert_eq!(cert.expires(), later);
189    }
190
191    #[test]
192    fn failing_cert() {
193        let now = SystemTime::get();
194        let one_hour = Duration::new(3600, 0);
195        let later = now + one_hour * 2;
196
197        {
198            let c = AuthCert::builder()
199                .identity_key(rsa1())
200                .lifespan(now..later)
201                .dangerous_testing_cert();
202            assert!(c.is_err()); // no signing key.
203        }
204
205        {
206            let c = AuthCert::builder()
207                .signing_key(rsa1())
208                .lifespan(now..later)
209                .dangerous_testing_cert();
210            assert!(c.is_err()); // no identity key.
211        }
212
213        {
214            let c = AuthCert::builder()
215                .signing_key(rsa1())
216                .identity_key(rsa2())
217                .dangerous_testing_cert();
218            assert!(c.is_err()); // no lifespan.
219        }
220
221        {
222            let c = AuthCert::builder()
223                .signing_key(rsa1())
224                .identity_key(rsa2())
225                .lifespan(later..now)
226                .dangerous_testing_cert();
227            assert!(c.is_err()); // bad lifespan.
228        }
229    }
230}