//! This module is where all relay related keys are declared along their key specifier for the //! KeyMgr so some of them can be stored on disk. use std::fmt; use derive_deftly::Deftly; use derive_more::Constructor; use derive_more::derive::{From, Into}; use tor_error::Bug; use tor_key_forge::{define_ed25519_keypair, define_rsa_keypair}; use tor_keymgr::{ InvalidKeyPathComponentValue, KeySpecifier, KeySpecifierComponent, derive_deftly_template_CertSpecifier, derive_deftly_template_KeySpecifier, }; use tor_persist::slug::{Slug, timestamp::Iso8601TimeSlug}; use web_time_compat::SystemTime; define_ed25519_keypair!( /// [KP_relayid_ed] Long-term identity keypair. Never rotates. pub RelayIdentity ); /// The key specifier of the relay long-term identity key (RelayIdentityKeypair) #[non_exhaustive] #[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)] #[derive_deftly(KeySpecifier)] #[deftly(prefix = "relay")] #[deftly(role = "KS_relayid_ed")] #[deftly(summary = "Relay long-term identity keypair")] pub struct RelayIdentityKeypairSpecifier; /// The public part of the long-term identity key of the relay. #[non_exhaustive] #[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)] #[derive_deftly(KeySpecifier)] #[deftly(prefix = "relay")] #[deftly(role = "KP_relayid_ed")] #[deftly(summary = "Public part of the relay long-term identity keypair")] pub struct RelayIdentityPublicKeySpecifier; define_rsa_keypair!( /// [KP_relayid_rsa] Legacy RSA long-term identity keypair. Never rotates. pub RelayIdentityRsa ); /// The key specifier of the legacy RSA relay long-term identity key (RelayIdentityRsaKeypair) #[non_exhaustive] #[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)] #[derive_deftly(KeySpecifier)] #[deftly(prefix = "relay")] #[deftly(role = "KS_relayid_rsa")] #[deftly(summary = "Legacy RSA long-term relay identity keypair")] pub struct RelayIdentityRsaKeypairSpecifier; /// The public part of the long-term identity key of the relay. #[non_exhaustive] #[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)] #[derive_deftly(KeySpecifier)] #[deftly(prefix = "relay")] #[deftly(role = "KP_relayid_rsa")] #[deftly(summary = "Public part of the relay long-term identity keypair")] pub struct RelayIdentityRsaPublicKeySpecifier; define_ed25519_keypair!( /// [KP_relaysign_ed] Medium-term signing keypair. Rotated periodically. pub RelaySigning ); /// The key specifier of the relay medium-term signing key. #[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)] #[derive_deftly(KeySpecifier)] #[deftly(prefix = "relay")] #[deftly(role = "KS_relaysign_ed")] #[deftly(summary = "Relay medium-term signing keypair")] pub struct RelaySigningKeypairSpecifier { /// The expiration time of this key. /// /// This **must** be the same as the expiration timestamp from the /// `K_relaysign_ed` certificate of this key. /// /// This serves as a unique identifier for this key instance, /// and is used for deciding which `K_relaysign_ed` key to use /// (we use the newest key that is not yet expired according to /// the `valid_until` timestamp from its specifier). /// /// **Important**: this timestamp should not be used for anything other than /// distinguishing between different signing keypair instances. /// In particular, it should **not** be used for validating the keypair, /// or for checking its timeliness. #[deftly(denotator)] pub(crate) valid_until: Timestamp, } impl RelaySigningKeypairSpecifier { /// Returns the time at which this key becomes invalid. pub fn valid_until(&self) -> Timestamp { self.valid_until } } /// The key specifier of the public part of the relay medium-term signing key. #[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)] #[derive_deftly(KeySpecifier)] #[deftly(prefix = "relay")] #[deftly(role = "KP_relaysign_ed")] #[deftly(summary = "Public part of the relay medium-term signing keypair")] #[deftly(keypair_specifier = "RelaySigningKeypairSpecifier")] pub struct RelaySigningPublicKeySpecifier { /// The expiration time of this key. /// /// This **must** be the same as the expiration timestamp from the /// `K_relaysign_ed` certificate of this key. /// /// This serves as a unique identifier for this key instance, /// and is used for deciding which `K_relaysign_ed` key to use /// (we use the newest key that is not yet expired according to /// the `valid_until` timestamp from its specifier). /// /// **Important**: this timestamp should not be used for anything other than /// distinguishing between different signing keypair instances. /// In particular, it should **not** be used for validating the keypair, /// or for checking its timeliness. #[deftly(denotator)] pub(crate) valid_until: Timestamp, } impl From<&RelaySigningPublicKeySpecifier> for RelaySigningKeypairSpecifier { fn from(public_key_specifier: &RelaySigningPublicKeySpecifier) -> RelaySigningKeypairSpecifier { RelaySigningKeypairSpecifier::new(public_key_specifier.valid_until) } } impl RelaySigningPublicKeySpecifier { /// Returns the time at which this key becomes invalid. pub fn valid_until(&self) -> Timestamp { self.valid_until } } /// Certificate specifier for the [`RelaySigningPublicKeySpecifier`] certificate. /// /// Represents `KP_relaysign_ed` signed by the `KS_relayid_ed` identity key. #[derive(Deftly, Constructor)] #[derive_deftly(CertSpecifier)] pub struct RelaySigningKeyCertSpecifier { /// The subject key of this certificate. #[deftly(subject)] subject: RelaySigningPublicKeySpecifier, } /// The approximate time when a [`RelaySigningKeypairSpecifier`] was generated. /// /// Used as a denotator to distinguish between the different signing keypair instances /// that might be stored in the keystore. #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] // #[derive(Into, From)] pub struct Timestamp(Iso8601TimeSlug); impl From for Timestamp { fn from(t: SystemTime) -> Self { Self(t.into()) } } impl From for SystemTime { fn from(t: Timestamp) -> Self { t.0.into() } } impl KeySpecifierComponent for Timestamp { fn to_slug(&self) -> Result { self.0.try_into() } fn from_slug(s: &Slug) -> Result where Self: Sized, { use std::str::FromStr as _; let timestamp = Iso8601TimeSlug::from_str(s.as_ref()) .map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?; Ok(Self(timestamp)) } fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } define_ed25519_keypair!( /// [KP_link_ed] Short-term signing keypair for link authentication. Rotated frequently. pub RelayLinkSigning ); /// The key specifier of the relay link authentication key. #[derive(Deftly, PartialEq, Debug, Constructor)] #[derive_deftly(KeySpecifier)] #[deftly(prefix = "relay")] #[deftly(role = "KS_link_ed")] #[deftly(summary = "Relay short-term link authentication keypair")] pub struct RelayLinkSigningKeypairSpecifier { /// The expiration time of this key. /// /// This **must** be the same as the expiration timestamp from the /// `KP_link_ed` certificate of this key. /// /// This serves as a unique identifier for this key instance, /// and is used for deciding which `KP_link_ed` key to use /// (we use the newest key that is not yet expired according to /// the `valid_until` timestamp from its specifier). /// /// **Important**: this timestamp should not be used for anything other than /// distinguishing between different signing keypair instances. /// In particular, it should **not** be used for validating the keypair, /// or for checking its timeliness. #[deftly(denotator)] pub(crate) valid_until: Timestamp, } impl RelayLinkSigningKeypairSpecifier { /// Returns the time at which this key becomes invalid. pub fn valid_until(&self) -> Timestamp { self.valid_until } } #[cfg(test)] mod test { // @@ begin test lint list maintained by maint/add_warning @@ #![allow(clippy::bool_assert_comparison)] #![allow(clippy::clone_on_copy)] #![allow(clippy::dbg_macro)] #![allow(clippy::mixed_attributes_style)] #![allow(clippy::print_stderr)] #![allow(clippy::print_stdout)] #![allow(clippy::single_char_pattern)] #![allow(clippy::unwrap_used)] #![allow(clippy::unchecked_time_subtraction)] #![allow(clippy::useless_vec)] #![allow(clippy::needless_pass_by_value)] //! use super::*; use tor_keymgr::test_utils::check_key_specifier; use tor_keymgr::{CertSpecifierPattern, KeyCertificateSpecifier, KeyPathPattern}; #[test] fn relay_signing_key_specifiers() { let ts = SystemTime::UNIX_EPOCH; let key_spec = RelaySigningKeypairSpecifier::new(ts.into()); assert_eq!( key_spec.arti_path().unwrap().as_str(), "relay/ks_relaysign_ed+19700101000000" ); check_key_specifier(&key_spec, "relay/ks_relaysign_ed+19700101000000"); let pubkey_spec = RelaySigningPublicKeySpecifier::new(ts.into()); assert_eq!( pubkey_spec.arti_path().unwrap().as_str(), "relay/kp_relaysign_ed+19700101000000" ); check_key_specifier(&pubkey_spec, "relay/kp_relaysign_ed+19700101000000"); let cert_spec = RelaySigningKeyCertSpecifier { subject: pubkey_spec, }; assert_eq!( cert_spec.subject_key_specifier().arti_path().unwrap(), pubkey_spec.arti_path().unwrap() ); assert_eq!( RelaySigningKeyCertSpecifierPattern::new_any() .arti_pattern() .unwrap(), KeyPathPattern::Arti("relay/kp_relaysign_ed+*".to_string()) ); } #[test] fn relay_identity_key_specifiers() { let key_spec = RelayIdentityKeypairSpecifier::new(); assert_eq!( key_spec.arti_path().unwrap().as_str(), "relay/ks_relayid_ed" ); check_key_specifier(&key_spec, "relay/ks_relayid_ed"); let key_spec = RelayIdentityPublicKeySpecifier::new(); assert_eq!( key_spec.arti_path().unwrap().as_str(), "relay/kp_relayid_ed" ); check_key_specifier(&key_spec, "relay/kp_relayid_ed"); } }