pk.rs
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::derive::{From, Into}; 9 use derive_more::Constructor; 10 11 use tor_error::Bug; 12 use tor_key_forge::define_ed25519_keypair; 13 use tor_keymgr::{ 14 derive_deftly_template_KeySpecifier, InvalidKeyPathComponentValue, KeySpecifier, 15 KeySpecifierComponent, 16 }; 17 use tor_persist::slug::{timestamp::Iso8601TimeSlug, Slug}; 18 19 // 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 21 22 define_ed25519_keypair!( 23 /// [KP_relayid_ed] Long-term identity keypair. Never rotates. 24 pub RelayIdentity 25 ); 26 27 #[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) 34 pub struct RelayIdentityKeypairSpecifier; 35 36 #[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. 43 pub struct RelayIdentityPublicKeySpecifier; 44 45 define_ed25519_keypair!( 46 /// [KP_relaysign_ed] Medium-term signing keypair. Rotated periodically. 47 pub RelaySigning 48 ); 49 50 #[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. 56 pub 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)] 72 pub(crate) valid_until: Timestamp, 73 } 74 75 /// 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)] 81 pub struct Timestamp(Iso8601TimeSlug); 82 83 impl From<SystemTime> for Timestamp { 84 fn from(t: SystemTime) -> Self { 85 Self(t.into()) 86 } 87 } 88 89 impl KeySpecifierComponent for Timestamp { 90 fn to_slug(&self) -> Result<Slug, Bug> { 91 self.0.try_into() 92 } 93 94 fn from_slug(s: &Slug) -> Result<Self, InvalidKeyPathComponentValue> 95 where 96 Self: Sized, 97 { 98 use std::str::FromStr as _; 99 100 let timestamp = Iso8601TimeSlug::from_str(s.as_ref()) 101 .map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?; 102 103 Ok(Self(timestamp)) 104 } 105 106 fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result { 107 fmt::Display::fmt(&self.0, f) 108 } 109 } 110 111 define_ed25519_keypair!( 112 /// [KP_link_ed] Short-term signing keypair for link authentication. Rotated frequently. 113 pub RelayLinkSigning 114 ); 115 116 #[cfg(test)] 117 mod 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 @@ --> 131 use super::*; 132 133 use tor_keymgr::test_utils::check_key_specifier; 134 135 #[test] 136 fn relay_signing_key_specifiers() { 137 let ts = SystemTime::UNIX_EPOCH; 138 let key_spec = RelaySigningKeypairSpecifier::new(ts.into()); 139 140 assert_eq!( 141 key_spec.arti_path().unwrap().as_str(), 142 "relay/ks_relaysign_ed+19700101000000" 143 ); 144 145 check_key_specifier(&key_spec, "relay/ks_relaysign_ed+19700101000000"); 146 } 147 148 #[test] 149 fn relay_identity_key_specifiers() { 150 let key_spec = RelayIdentityKeypairSpecifier::new(); 151 152 assert_eq!( 153 key_spec.arti_path().unwrap().as_str(), 154 "relay/ks_relayid_ed" 155 ); 156 157 check_key_specifier(&key_spec, "relay/ks_relayid_ed"); 158 159 let key_spec = RelayIdentityPublicKeySpecifier::new(); 160 161 assert_eq!( 162 key_spec.arti_path().unwrap().as_str(), 163 "relay/kp_relayid_ed" 164 ); 165 166 check_key_specifier(&key_spec, "relay/kp_relayid_ed"); 167 } 168 }