Skip to main content

tor_relay_crypto/
pk.rs

1//! This module is where all relay related keys are declared along their key specifier for the
2//! KeyMgr so some of them can be stored on disk.
3
4use std::fmt;
5use std::time::SystemTime;
6
7use derive_deftly::Deftly;
8use derive_more::Constructor;
9use derive_more::derive::{From, Into};
10
11use tor_error::Bug;
12use tor_key_forge::{define_ed25519_keypair, define_rsa_keypair};
13use tor_keymgr::{
14    InvalidKeyPathComponentValue, KeySpecifier, KeySpecifierComponent,
15    derive_deftly_template_KeySpecifier,
16};
17use tor_persist::slug::{Slug, timestamp::Iso8601TimeSlug};
18
19define_ed25519_keypair!(
20    /// [KP_relayid_ed] Long-term identity keypair. Never rotates.
21    pub RelayIdentity
22);
23
24/// The key specifier of the relay long-term identity key (RelayIdentityKeypair)
25#[non_exhaustive]
26#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
27#[derive_deftly(KeySpecifier)]
28#[deftly(prefix = "relay")]
29#[deftly(role = "KS_relayid_ed")]
30#[deftly(summary = "Relay long-term identity keypair")]
31pub struct RelayIdentityKeypairSpecifier;
32
33/// The public part of the long-term identity key of the relay.
34#[non_exhaustive]
35#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
36#[derive_deftly(KeySpecifier)]
37#[deftly(prefix = "relay")]
38#[deftly(role = "KP_relayid_ed")]
39#[deftly(summary = "Public part of the relay long-term identity keypair")]
40pub struct RelayIdentityPublicKeySpecifier;
41
42define_rsa_keypair!(
43    /// [KP_relayid_rsa] Legacy RSA long-term identity keypair. Never rotates.
44    pub RelayIdentityRsa
45);
46
47/// The key specifier of the legacy RSA relay long-term identity key (RelayIdentityRsaKeypair)
48#[non_exhaustive]
49#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
50#[derive_deftly(KeySpecifier)]
51#[deftly(prefix = "relay")]
52#[deftly(role = "KS_relayid_rsa")]
53#[deftly(summary = "Legacy RSA long-term relay identity keypair")]
54pub struct RelayIdentityRsaKeypairSpecifier;
55
56/// The public part of the long-term identity key of the relay.
57#[non_exhaustive]
58#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
59#[derive_deftly(KeySpecifier)]
60#[deftly(prefix = "relay")]
61#[deftly(role = "KP_relayid_rsa")]
62#[deftly(summary = "Public part of the relay long-term identity keypair")]
63pub struct RelayIdentityRsaPublicKeySpecifier;
64
65define_ed25519_keypair!(
66    /// [KP_relaysign_ed] Medium-term signing keypair. Rotated periodically.
67    pub RelaySigning
68);
69
70/// The key specifier of the relay medium-term signing key.
71#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
72#[derive_deftly(KeySpecifier)]
73#[deftly(prefix = "relay")]
74#[deftly(role = "KS_relaysign_ed")]
75#[deftly(summary = "Relay medium-term signing keypair")]
76pub struct RelaySigningKeypairSpecifier {
77    /// The expiration time of this key.
78    ///
79    /// This **must** be the same as the expiration timestamp from the
80    /// `K_relaysign_ed` certificate of this key.
81    ///
82    /// This serves as a unique identifier for this key instance,
83    /// and is used for deciding which `K_relaysign_ed` key to use
84    /// (we use the newest key that is not yet expired according to
85    /// the `valid_until` timestamp from its specifier).
86    ///
87    /// **Important**: this timestamp should not be used for anything other than
88    /// distinguishing between different signing keypair instances.
89    /// In particular, it should **not** be used for validating the keypair,
90    /// or for checking its timeliness.
91    #[deftly(denotator)]
92    pub(crate) valid_until: Timestamp,
93}
94
95impl RelaySigningKeypairSpecifier {
96    /// Returns the time at which this key becomes invalid.
97    pub fn valid_until(&self) -> Timestamp {
98        self.valid_until
99    }
100}
101
102/// The key specifier of the public part of the relay medium-term signing key.
103#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
104#[derive_deftly(KeySpecifier)]
105#[deftly(prefix = "relay")]
106#[deftly(role = "KP_relaysign_ed")]
107#[deftly(summary = "Public part of the relay medium-term signing keypair")]
108#[deftly(has_certificate(
109    certificate = "RelaySigningKeyCertSpecifier",
110    signed_with = "RelayIdentityKeypairSpecifier",
111))]
112#[deftly(keypair_specifier = "RelaySigningKeypairSpecifier")]
113pub struct RelaySigningPublicKeySpecifier {
114    /// The expiration time of this key.
115    ///
116    /// This **must** be the same as the expiration timestamp from the
117    /// `K_relaysign_ed` certificate of this key.
118    ///
119    /// This serves as a unique identifier for this key instance,
120    /// and is used for deciding which `K_relaysign_ed` key to use
121    /// (we use the newest key that is not yet expired according to
122    /// the `valid_until` timestamp from its specifier).
123    ///
124    /// **Important**: this timestamp should not be used for anything other than
125    /// distinguishing between different signing keypair instances.
126    /// In particular, it should **not** be used for validating the keypair,
127    /// or for checking its timeliness.
128    #[deftly(denotator)]
129    pub(crate) valid_until: Timestamp,
130}
131
132impl From<&RelaySigningPublicKeySpecifier> for RelaySigningKeypairSpecifier {
133    fn from(public_key_specifier: &RelaySigningPublicKeySpecifier) -> RelaySigningKeypairSpecifier {
134        RelaySigningKeypairSpecifier::new(public_key_specifier.valid_until)
135    }
136}
137
138/// The approximate time when a [`RelaySigningKeypairSpecifier`] was generated.
139///
140/// Used as a denotator to distinguish between the different signing keypair instances
141/// that might be stored in the keystore.
142#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] //
143#[derive(Into, From)]
144pub struct Timestamp(Iso8601TimeSlug);
145
146impl From<SystemTime> for Timestamp {
147    fn from(t: SystemTime) -> Self {
148        Self(t.into())
149    }
150}
151
152impl From<Timestamp> for SystemTime {
153    fn from(t: Timestamp) -> Self {
154        t.0.into()
155    }
156}
157
158impl KeySpecifierComponent for Timestamp {
159    fn to_slug(&self) -> Result<Slug, Bug> {
160        self.0.try_into()
161    }
162
163    fn from_slug(s: &Slug) -> Result<Self, InvalidKeyPathComponentValue>
164    where
165        Self: Sized,
166    {
167        use std::str::FromStr as _;
168
169        let timestamp = Iso8601TimeSlug::from_str(s.as_ref())
170            .map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?;
171
172        Ok(Self(timestamp))
173    }
174
175    fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result {
176        fmt::Display::fmt(&self.0, f)
177    }
178}
179
180define_ed25519_keypair!(
181    /// [KP_link_ed] Short-term signing keypair for link authentication. Rotated frequently.
182    pub RelayLinkSigning
183);
184
185/// The key specifier of the relay link authentication key.
186#[derive(Deftly, PartialEq, Debug, Constructor)]
187#[derive_deftly(KeySpecifier)]
188#[deftly(prefix = "relay")]
189#[deftly(role = "KS_link_ed")]
190#[deftly(summary = "Relay short-term link authentication keypair")]
191pub struct RelayLinkSigningKeypairSpecifier {
192    /// The expiration time of this key.
193    ///
194    /// This **must** be the same as the expiration timestamp from the
195    /// `KP_link_ed` certificate of this key.
196    ///
197    /// This serves as a unique identifier for this key instance,
198    /// and is used for deciding which `KP_link_ed` key to use
199    /// (we use the newest key that is not yet expired according to
200    /// the `valid_until` timestamp from its specifier).
201    ///
202    /// **Important**: this timestamp should not be used for anything other than
203    /// distinguishing between different signing keypair instances.
204    /// In particular, it should **not** be used for validating the keypair,
205    /// or for checking its timeliness.
206    #[deftly(denotator)]
207    pub(crate) valid_until: Timestamp,
208}
209
210impl RelayLinkSigningKeypairSpecifier {
211    /// Returns the time at which this key becomes invalid.
212    pub fn valid_until(&self) -> Timestamp {
213        self.valid_until
214    }
215}
216
217#[cfg(test)]
218mod test {
219    // @@ begin test lint list maintained by maint/add_warning @@
220    #![allow(clippy::bool_assert_comparison)]
221    #![allow(clippy::clone_on_copy)]
222    #![allow(clippy::dbg_macro)]
223    #![allow(clippy::mixed_attributes_style)]
224    #![allow(clippy::print_stderr)]
225    #![allow(clippy::print_stdout)]
226    #![allow(clippy::single_char_pattern)]
227    #![allow(clippy::unwrap_used)]
228    #![allow(clippy::unchecked_time_subtraction)]
229    #![allow(clippy::useless_vec)]
230    #![allow(clippy::needless_pass_by_value)]
231    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
232    use super::*;
233
234    use tor_keymgr::KeyCertificateSpecifier;
235    use tor_keymgr::test_utils::check_key_specifier;
236
237    #[test]
238    fn relay_signing_key_specifiers() {
239        let ts = SystemTime::UNIX_EPOCH;
240        let key_spec = RelaySigningKeypairSpecifier::new(ts.into());
241
242        assert_eq!(
243            key_spec.arti_path().unwrap().as_str(),
244            "relay/ks_relaysign_ed+19700101000000"
245        );
246
247        check_key_specifier(&key_spec, "relay/ks_relaysign_ed+19700101000000");
248
249        let pubkey_spec = RelaySigningPublicKeySpecifier::new(ts.into());
250
251        assert_eq!(
252            pubkey_spec.arti_path().unwrap().as_str(),
253            "relay/kp_relaysign_ed+19700101000000"
254        );
255
256        check_key_specifier(&pubkey_spec, "relay/kp_relaysign_ed+19700101000000");
257        let relayid_spec = RelayIdentityKeypairSpecifier::new();
258        let cert_spec = RelaySigningKeyCertSpecifier {
259            signed_with: Some(relayid_spec),
260            subject: pubkey_spec,
261        };
262
263        assert_eq!(
264            cert_spec
265                .signing_key_specifier()
266                .unwrap()
267                .arti_path()
268                .unwrap(),
269            relayid_spec.arti_path().unwrap()
270        );
271
272        assert_eq!(
273            cert_spec.subject_key_specifier().arti_path().unwrap(),
274            pubkey_spec.arti_path().unwrap()
275        );
276    }
277
278    #[test]
279    fn relay_identity_key_specifiers() {
280        let key_spec = RelayIdentityKeypairSpecifier::new();
281
282        assert_eq!(
283            key_spec.arti_path().unwrap().as_str(),
284            "relay/ks_relayid_ed"
285        );
286
287        check_key_specifier(&key_spec, "relay/ks_relayid_ed");
288
289        let key_spec = RelayIdentityPublicKeySpecifier::new();
290
291        assert_eq!(
292            key_spec.arti_path().unwrap().as_str(),
293            "relay/kp_relayid_ed"
294        );
295
296        check_key_specifier(&key_spec, "relay/kp_relayid_ed");
297    }
298}