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
use std::time::SystemTime;
6

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

            
11
use tor_error::Bug;
12
use tor_key_forge::{define_ed25519_keypair, define_rsa_keypair};
13
use tor_keymgr::{
14
    InvalidKeyPathComponentValue, KeySpecifier, KeySpecifierComponent,
15
    derive_deftly_template_KeySpecifier,
16
};
17
use tor_persist::slug::{Slug, timestamp::Iso8601TimeSlug};
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
    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")]
113
pub 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

            
132
impl 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)]
144
pub struct Timestamp(Iso8601TimeSlug);
145

            
146
impl From<SystemTime> for Timestamp {
147
4
    fn from(t: SystemTime) -> Self {
148
4
        Self(t.into())
149
4
    }
150
}
151

            
152
impl From<Timestamp> for SystemTime {
153
    fn from(t: Timestamp) -> Self {
154
        t.0.into()
155
    }
156
}
157

            
158
impl KeySpecifierComponent for Timestamp {
159
12
    fn to_slug(&self) -> Result<Slug, Bug> {
160
12
        self.0.try_into()
161
12
    }
162

            
163
4
    fn from_slug(s: &Slug) -> Result<Self, InvalidKeyPathComponentValue>
164
4
    where
165
4
        Self: Sized,
166
    {
167
        use std::str::FromStr as _;
168

            
169
4
        let timestamp = Iso8601TimeSlug::from_str(s.as_ref())
170
4
            .map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?;
171

            
172
4
        Ok(Self(timestamp))
173
4
    }
174

            
175
    fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result {
176
        fmt::Display::fmt(&self.0, f)
177
    }
178
}
179

            
180
define_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")]
191
pub 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

            
210
impl 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)]
218
mod 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
}