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
#[non_exhaustive]
25
#[derive(Deftly, PartialEq, Debug, Constructor)]
26
#[derive_deftly(KeySpecifier)]
27
#[deftly(prefix = "relay")]
28
#[deftly(role = "KS_relayid_ed")]
29
#[deftly(summary = "Relay long-term identity keypair")]
30
/// The key specifier of the relay long-term identity key (RelayIdentityKeypair)
31
pub struct RelayIdentityKeypairSpecifier;
32

            
33
#[non_exhaustive]
34
#[derive(Deftly, PartialEq, Debug, Constructor)]
35
#[derive_deftly(KeySpecifier)]
36
#[deftly(prefix = "relay")]
37
#[deftly(role = "KP_relayid_ed")]
38
#[deftly(summary = "Public part of the relay long-term identity keypair")]
39
/// The public part of the long-term identity key of the relay.
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
#[non_exhaustive]
48
#[derive(Deftly, PartialEq, Debug, Constructor)]
49
#[derive_deftly(KeySpecifier)]
50
#[deftly(prefix = "relay")]
51
#[deftly(role = "KS_relayid_rsa")]
52
#[deftly(summary = "Legacy RSA long-term relay identity keypair")]
53
/// The key specifier of the legacy RSA relay long-term identity key (RelayIdentityRsaKeypair)
54
pub struct RelayIdentityRsaKeypairSpecifier;
55

            
56
#[non_exhaustive]
57
#[derive(Deftly, PartialEq, Debug, Constructor)]
58
#[derive_deftly(KeySpecifier)]
59
#[deftly(prefix = "relay")]
60
#[deftly(role = "KP_relayid_rsa")]
61
#[deftly(summary = "Public part of the relay long-term identity keypair")]
62
/// The public part of the long-term identity key of the relay.
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
#[derive(Deftly, PartialEq, Debug, Constructor)]
71
#[derive_deftly(KeySpecifier)]
72
#[deftly(prefix = "relay")]
73
#[deftly(role = "KS_relaysign_ed")]
74
#[deftly(summary = "Relay medium-term signing keypair")]
75
/// The key specifier of the relay medium-term signing key.
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
/// The approximate time when a [`RelaySigningKeypairSpecifier`] was generated.
96
///
97
/// Used as a denotator to distinguish between the different signing keypair instances
98
/// that might be stored in the keystore.
99
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] //
100
#[derive(Into, From)]
101
pub struct Timestamp(Iso8601TimeSlug);
102

            
103
impl From<SystemTime> for Timestamp {
104
2
    fn from(t: SystemTime) -> Self {
105
2
        Self(t.into())
106
2
    }
107
}
108

            
109
impl KeySpecifierComponent for Timestamp {
110
4
    fn to_slug(&self) -> Result<Slug, Bug> {
111
4
        self.0.try_into()
112
4
    }
113

            
114
2
    fn from_slug(s: &Slug) -> Result<Self, InvalidKeyPathComponentValue>
115
2
    where
116
2
        Self: Sized,
117
    {
118
        use std::str::FromStr as _;
119

            
120
2
        let timestamp = Iso8601TimeSlug::from_str(s.as_ref())
121
2
            .map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?;
122

            
123
2
        Ok(Self(timestamp))
124
2
    }
125

            
126
    fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result {
127
        fmt::Display::fmt(&self.0, f)
128
    }
129
}
130

            
131
define_ed25519_keypair!(
132
    /// [KP_link_ed] Short-term signing keypair for link authentication. Rotated frequently.
133
    pub RelayLinkSigning
134
);
135

            
136
#[cfg(test)]
137
mod test {
138
    // @@ begin test lint list maintained by maint/add_warning @@
139
    #![allow(clippy::bool_assert_comparison)]
140
    #![allow(clippy::clone_on_copy)]
141
    #![allow(clippy::dbg_macro)]
142
    #![allow(clippy::mixed_attributes_style)]
143
    #![allow(clippy::print_stderr)]
144
    #![allow(clippy::print_stdout)]
145
    #![allow(clippy::single_char_pattern)]
146
    #![allow(clippy::unwrap_used)]
147
    #![allow(clippy::unchecked_duration_subtraction)]
148
    #![allow(clippy::useless_vec)]
149
    #![allow(clippy::needless_pass_by_value)]
150
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
151
    use super::*;
152

            
153
    use tor_keymgr::test_utils::check_key_specifier;
154

            
155
    #[test]
156
    fn relay_signing_key_specifiers() {
157
        let ts = SystemTime::UNIX_EPOCH;
158
        let key_spec = RelaySigningKeypairSpecifier::new(ts.into());
159

            
160
        assert_eq!(
161
            key_spec.arti_path().unwrap().as_str(),
162
            "relay/ks_relaysign_ed+19700101000000"
163
        );
164

            
165
        check_key_specifier(&key_spec, "relay/ks_relaysign_ed+19700101000000");
166
    }
167

            
168
    #[test]
169
    fn relay_identity_key_specifiers() {
170
        let key_spec = RelayIdentityKeypairSpecifier::new();
171

            
172
        assert_eq!(
173
            key_spec.arti_path().unwrap().as_str(),
174
            "relay/ks_relayid_ed"
175
        );
176

            
177
        check_key_specifier(&key_spec, "relay/ks_relayid_ed");
178

            
179
        let key_spec = RelayIdentityPublicKeySpecifier::new();
180

            
181
        assert_eq!(
182
            key_spec.arti_path().unwrap().as_str(),
183
            "relay/kp_relayid_ed"
184
        );
185

            
186
        check_key_specifier(&key_spec, "relay/kp_relayid_ed");
187
    }
188
}