1use 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 pub RelayIdentity
22);
23
24#[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#[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 pub RelayIdentityRsa
45);
46
47#[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#[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 pub RelaySigning
68);
69
70#[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 #[deftly(denotator)]
92 pub(crate) valid_until: Timestamp,
93}
94
95impl RelaySigningKeypairSpecifier {
96 pub fn valid_until(&self) -> Timestamp {
98 self.valid_until
99 }
100}
101
102#[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 #[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#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[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 pub RelayLinkSigning
183);
184
185#[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 #[deftly(denotator)]
207 pub(crate) valid_until: Timestamp,
208}
209
210impl RelayLinkSigningKeypairSpecifier {
211 pub fn valid_until(&self) -> Timestamp {
213 self.valid_until
214 }
215}
216
217#[cfg(test)]
218mod test {
219 #![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 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}