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

            
4
use std::fmt;
5

            
6
use derive_deftly::Deftly;
7
use derive_more::Constructor;
8
use derive_more::derive::{From, Into};
9

            
10
use tor_error::Bug;
11
use tor_key_forge::{define_ed25519_keypair, define_rsa_keypair};
12
use tor_keymgr::{
13
    InvalidKeyPathComponentValue, KeySpecifier, KeySpecifierComponent,
14
    derive_deftly_template_CertSpecifier, derive_deftly_template_KeySpecifier,
15
};
16
use tor_persist::slug::{Slug, timestamp::Iso8601TimeSlug};
17
use web_time_compat::SystemTime;
18

            
19
define_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")]
31
pub 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")]
40
pub struct RelayIdentityPublicKeySpecifier;
41

            
42
define_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")]
54
pub 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")]
63
pub struct RelayIdentityRsaPublicKeySpecifier;
64

            
65
define_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")]
76
pub 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

            
95
impl RelaySigningKeypairSpecifier {
96
    /// Returns the time at which this key becomes invalid.
97
714
    pub fn valid_until(&self) -> Timestamp {
98
714
        self.valid_until
99
714
    }
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(keypair_specifier = "RelaySigningKeypairSpecifier")]
109
pub struct RelaySigningPublicKeySpecifier {
110
    /// The expiration time of this key.
111
    ///
112
    /// This **must** be the same as the expiration timestamp from the
113
    /// `K_relaysign_ed` certificate of this key.
114
    ///
115
    /// This serves as a unique identifier for this key instance,
116
    /// and is used for deciding which `K_relaysign_ed` key to use
117
    /// (we use the newest key that is not yet expired according to
118
    /// the `valid_until` timestamp from its specifier).
119
    ///
120
    /// **Important**: this timestamp should not be used for anything other than
121
    /// distinguishing between different signing keypair instances.
122
    /// In particular, it should **not** be used for validating the keypair,
123
    /// or for checking its timeliness.
124
    #[deftly(denotator)]
125
    pub(crate) valid_until: Timestamp,
126
}
127

            
128
impl From<&RelaySigningPublicKeySpecifier> for RelaySigningKeypairSpecifier {
129
1224
    fn from(public_key_specifier: &RelaySigningPublicKeySpecifier) -> RelaySigningKeypairSpecifier {
130
1224
        RelaySigningKeypairSpecifier::new(public_key_specifier.valid_until)
131
1224
    }
132
}
133

            
134
impl RelaySigningPublicKeySpecifier {
135
    /// Returns the time at which this key becomes invalid.
136
510
    pub fn valid_until(&self) -> Timestamp {
137
510
        self.valid_until
138
510
    }
139
}
140

            
141
/// Certificate specifier for the [`RelaySigningPublicKeySpecifier`] certificate.
142
///
143
/// Represents `KP_relaysign_ed` signed by the `KS_relayid_ed` identity key.
144
#[derive(Deftly, Constructor)]
145
#[derive_deftly(CertSpecifier)]
146
pub struct RelaySigningKeyCertSpecifier {
147
    /// The subject key of this certificate.
148
    #[deftly(subject)]
149
    subject: RelaySigningPublicKeySpecifier,
150
}
151

            
152
/// The approximate time when a [`RelaySigningKeypairSpecifier`] was generated.
153
///
154
/// Used as a denotator to distinguish between the different signing keypair instances
155
/// that might be stored in the keystore.
156
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] //
157
#[derive(Into, From)]
158
pub struct Timestamp(Iso8601TimeSlug);
159

            
160
impl From<SystemTime> for Timestamp {
161
3778
    fn from(t: SystemTime) -> Self {
162
3778
        Self(t.into())
163
3778
    }
164
}
165

            
166
impl From<Timestamp> for SystemTime {
167
1020
    fn from(t: Timestamp) -> Self {
168
1020
        t.0.into()
169
1020
    }
170
}
171

            
172
impl KeySpecifierComponent for Timestamp {
173
6030
    fn to_slug(&self) -> Result<Slug, Bug> {
174
6030
        self.0.try_into()
175
6030
    }
176

            
177
2248
    fn from_slug(s: &Slug) -> Result<Self, InvalidKeyPathComponentValue>
178
2248
    where
179
2248
        Self: Sized,
180
    {
181
        use std::str::FromStr as _;
182

            
183
2248
        let timestamp = Iso8601TimeSlug::from_str(s.as_ref())
184
2248
            .map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?;
185

            
186
2248
        Ok(Self(timestamp))
187
2248
    }
188

            
189
    fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result {
190
        fmt::Display::fmt(&self.0, f)
191
    }
192
}
193

            
194
define_ed25519_keypair!(
195
    /// [KP_link_ed] Short-term signing keypair for link authentication. Rotated frequently.
196
    pub RelayLinkSigning
197
);
198

            
199
/// The key specifier of the relay link authentication key.
200
#[derive(Deftly, PartialEq, Debug, Constructor)]
201
#[derive_deftly(KeySpecifier)]
202
#[deftly(prefix = "relay")]
203
#[deftly(role = "KS_link_ed")]
204
#[deftly(summary = "Relay short-term link authentication keypair")]
205
pub struct RelayLinkSigningKeypairSpecifier {
206
    /// The expiration time of this key.
207
    ///
208
    /// This **must** be the same as the expiration timestamp from the
209
    /// `KP_link_ed` certificate of this key.
210
    ///
211
    /// This serves as a unique identifier for this key instance,
212
    /// and is used for deciding which `KP_link_ed` key to use
213
    /// (we use the newest key that is not yet expired according to
214
    /// the `valid_until` timestamp from its specifier).
215
    ///
216
    /// **Important**: this timestamp should not be used for anything other than
217
    /// distinguishing between different signing keypair instances.
218
    /// In particular, it should **not** be used for validating the keypair,
219
    /// or for checking its timeliness.
220
    #[deftly(denotator)]
221
    pub(crate) valid_until: Timestamp,
222
}
223

            
224
impl RelayLinkSigningKeypairSpecifier {
225
    /// Returns the time at which this key becomes invalid.
226
510
    pub fn valid_until(&self) -> Timestamp {
227
510
        self.valid_until
228
510
    }
229
}
230

            
231
#[cfg(test)]
232
mod test {
233
    // @@ begin test lint list maintained by maint/add_warning @@
234
    #![allow(clippy::bool_assert_comparison)]
235
    #![allow(clippy::clone_on_copy)]
236
    #![allow(clippy::dbg_macro)]
237
    #![allow(clippy::mixed_attributes_style)]
238
    #![allow(clippy::print_stderr)]
239
    #![allow(clippy::print_stdout)]
240
    #![allow(clippy::single_char_pattern)]
241
    #![allow(clippy::unwrap_used)]
242
    #![allow(clippy::unchecked_time_subtraction)]
243
    #![allow(clippy::useless_vec)]
244
    #![allow(clippy::needless_pass_by_value)]
245
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
246
    use super::*;
247

            
248
    use tor_keymgr::test_utils::check_key_specifier;
249
    use tor_keymgr::{CertSpecifierPattern, KeyCertificateSpecifier, KeyPathPattern};
250

            
251
    #[test]
252
    fn relay_signing_key_specifiers() {
253
        let ts = SystemTime::UNIX_EPOCH;
254
        let key_spec = RelaySigningKeypairSpecifier::new(ts.into());
255

            
256
        assert_eq!(
257
            key_spec.arti_path().unwrap().as_str(),
258
            "relay/ks_relaysign_ed+19700101000000"
259
        );
260

            
261
        check_key_specifier(&key_spec, "relay/ks_relaysign_ed+19700101000000");
262

            
263
        let pubkey_spec = RelaySigningPublicKeySpecifier::new(ts.into());
264

            
265
        assert_eq!(
266
            pubkey_spec.arti_path().unwrap().as_str(),
267
            "relay/kp_relaysign_ed+19700101000000"
268
        );
269

            
270
        check_key_specifier(&pubkey_spec, "relay/kp_relaysign_ed+19700101000000");
271
        let cert_spec = RelaySigningKeyCertSpecifier {
272
            subject: pubkey_spec,
273
        };
274

            
275
        assert_eq!(
276
            cert_spec.subject_key_specifier().arti_path().unwrap(),
277
            pubkey_spec.arti_path().unwrap()
278
        );
279

            
280
        assert_eq!(
281
            RelaySigningKeyCertSpecifierPattern::new_any()
282
                .arti_pattern()
283
                .unwrap(),
284
            KeyPathPattern::Arti("relay/kp_relaysign_ed+*".to_string())
285
        );
286
    }
287

            
288
    #[test]
289
    fn relay_identity_key_specifiers() {
290
        let key_spec = RelayIdentityKeypairSpecifier::new();
291

            
292
        assert_eq!(
293
            key_spec.arti_path().unwrap().as_str(),
294
            "relay/ks_relayid_ed"
295
        );
296

            
297
        check_key_specifier(&key_spec, "relay/ks_relayid_ed");
298

            
299
        let key_spec = RelayIdentityPublicKeySpecifier::new();
300

            
301
        assert_eq!(
302
            key_spec.arti_path().unwrap().as_str(),
303
            "relay/kp_relayid_ed"
304
        );
305

            
306
        check_key_specifier(&key_spec, "relay/kp_relayid_ed");
307
    }
308
}