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.
34use std::fmt;
5use std::time::SystemTime;
67use derive_deftly::Deftly;
8use derive_more::derive::{From, Into};
9use derive_more::Constructor;
1011use tor_error::Bug;
12use tor_key_forge::define_ed25519_keypair;
13use tor_keymgr::{
14 derive_deftly_template_KeySpecifier, InvalidKeyPathComponentValue, KeySpecifier,
15 KeySpecifierComponent,
16};
17use tor_persist::slug::{timestamp::Iso8601TimeSlug, Slug};
1819// TODO: The legacy RSA key is needed. Require support in tor-key-forge and keystore.
20// See https://gitlab.torproject.org/tpo/core/arti/-/work_items/1598
2122define_ed25519_keypair!(
23/// [KP_relayid_ed] Long-term identity keypair. Never rotates.
24pub RelayIdentity
25);
2627#[non_exhaustive]
28#[derive(Deftly, PartialEq, Debug, Constructor)]
29#[derive_deftly(KeySpecifier)]
30#[deftly(prefix = "relay")]
31#[deftly(role = "KS_relayid_ed")]
32#[deftly(summary = "Relay long-term identity keypair")]
33/// The key specifier of the relay long-term identity key (RelayIdentityKeypair)
34pub struct RelayIdentityKeypairSpecifier;
3536#[non_exhaustive]
37#[derive(Deftly, PartialEq, Debug, Constructor)]
38#[derive_deftly(KeySpecifier)]
39#[deftly(prefix = "relay")]
40#[deftly(role = "KP_relayid_ed")]
41#[deftly(summary = "Public part of the relay long-term identity keypair")]
42/// The public part of the long-term identity key of the relay.
43pub struct RelayIdentityPublicKeySpecifier;
4445define_ed25519_keypair!(
46/// [KP_relaysign_ed] Medium-term signing keypair. Rotated periodically.
47pub RelaySigning
48);
4950#[derive(Deftly, PartialEq, Debug, Constructor)]
51#[derive_deftly(KeySpecifier)]
52#[deftly(prefix = "relay")]
53#[deftly(role = "KS_relaysign_ed")]
54#[deftly(summary = "Relay medium-term signing keypair")]
55/// The key specifier of the relay medium-term signing key.
56pub struct RelaySigningKeypairSpecifier {
57/// The expiration time of this key.
58 ///
59 /// This **must** be the same as the expiration timestamp from the
60 /// `K_relaysign_ed` certificate of this key.
61 ///
62 /// This serves as a unique identifier for this key instance,
63 /// and is used for deciding which `K_relaysign_ed` key to use
64 /// (we use the newest key that is not yet expired according to
65 /// the `valid_until` timestamp from its specifier).
66 ///
67 /// **Important**: this timestamp should not be used for anything other than
68 /// distinguishing between different signing keypair instances.
69 /// In particular, it should **not** be used for validating the keypair,
70 /// or for checking its timeliness.
71#[deftly(denotator)]
72pub(crate) valid_until: Timestamp,
73}
7475/// The approximate time when a [`RelaySigningKeypairSpecifier`] was generated.
76///
77/// Used as a denotator to distinguish between the different signing keypair instances
78/// that might be stored in the keystore.
79#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] //
80#[derive(Into, From)]
81pub struct Timestamp(Iso8601TimeSlug);
8283impl From<SystemTime> for Timestamp {
84fn from(t: SystemTime) -> Self {
85Self(t.into())
86 }
87}
8889impl KeySpecifierComponent for Timestamp {
90fn to_slug(&self) -> Result<Slug, Bug> {
91self.0.try_into()
92 }
9394fn from_slug(s: &Slug) -> Result<Self, InvalidKeyPathComponentValue>
95where
96Self: Sized,
97 {
98use std::str::FromStr as _;
99100let timestamp = Iso8601TimeSlug::from_str(s.as_ref())
101 .map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?;
102103Ok(Self(timestamp))
104 }
105106fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result {
107 fmt::Display::fmt(&self.0, f)
108 }
109}
110111define_ed25519_keypair!(
112/// [KP_link_ed] Short-term signing keypair for link authentication. Rotated frequently.
113pub RelayLinkSigning
114);
115116#[cfg(test)]
117mod test {
118// @@ begin test lint list maintained by maint/add_warning @@
119#![allow(clippy::bool_assert_comparison)]
120 #![allow(clippy::clone_on_copy)]
121 #![allow(clippy::dbg_macro)]
122 #![allow(clippy::mixed_attributes_style)]
123 #![allow(clippy::print_stderr)]
124 #![allow(clippy::print_stdout)]
125 #![allow(clippy::single_char_pattern)]
126 #![allow(clippy::unwrap_used)]
127 #![allow(clippy::unchecked_duration_subtraction)]
128 #![allow(clippy::useless_vec)]
129 #![allow(clippy::needless_pass_by_value)]
130//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
131use super::*;
132133use tor_keymgr::test_utils::check_key_specifier;
134135#[test]
136fn relay_signing_key_specifiers() {
137let ts = SystemTime::UNIX_EPOCH;
138let key_spec = RelaySigningKeypairSpecifier::new(ts.into());
139140assert_eq!(
141 key_spec.arti_path().unwrap().as_str(),
142"relay/ks_relaysign_ed+19700101000000"
143);
144145 check_key_specifier(&key_spec, "relay/ks_relaysign_ed+19700101000000");
146 }
147148#[test]
149fn relay_identity_key_specifiers() {
150let key_spec = RelayIdentityKeypairSpecifier::new();
151152assert_eq!(
153 key_spec.arti_path().unwrap().as_str(),
154"relay/ks_relayid_ed"
155);
156157 check_key_specifier(&key_spec, "relay/ks_relayid_ed");
158159let key_spec = RelayIdentityPublicKeySpecifier::new();
160161assert_eq!(
162 key_spec.arti_path().unwrap().as_str(),
163"relay/kp_relayid_ed"
164);
165166 check_key_specifier(&key_spec, "relay/kp_relayid_ed");
167 }
168}