traits.rs
1 //! All the traits of this crate. 2 3 use downcast_rs::{impl_downcast, Downcast}; 4 use rand::RngCore; 5 use ssh_key::{ 6 private::{Ed25519Keypair, Ed25519PrivateKey, KeypairData, OpaqueKeypair}, 7 public::{Ed25519PublicKey, KeyData, OpaquePublicKey}, 8 rand_core::CryptoRng, 9 Algorithm, AlgorithmName, 10 }; 11 use tor_error::internal; 12 use tor_llcrypto::pk::{curve25519, ed25519}; 13 14 use crate::certs::CertData; 15 use crate::key_type::CertType; 16 use crate::{ 17 ssh::{SshKeyData, ED25519_EXPANDED_ALGORITHM_NAME, X25519_ALGORITHM_NAME}, 18 ErasedKey, KeyType, KeystoreItemType, Result, 19 }; 20 21 use std::result::Result as StdResult; 22 23 /// A random number generator for generating [`EncodableItem`]s. 24 pub trait KeygenRng: RngCore + CryptoRng {} 25 26 impl<T> KeygenRng for T where T: RngCore + CryptoRng {} 27 28 /// A trait for generating fresh keys. 29 pub trait Keygen { 30 /// Generate a new key of this type. 31 fn generate(rng: &mut dyn KeygenRng) -> Result<Self> 32 where 33 Self: Sized; 34 } 35 36 /// A trait for getting the type of an item. 37 pub trait ItemType: Downcast { 38 /// The type of the key. 39 fn item_type() -> KeystoreItemType 40 where 41 Self: Sized; 42 } 43 impl_downcast!(ItemType); 44 45 /// A key that can be serialized to, and deserialized from. 46 // 47 // When adding a new `EncodableItem` impl, you must also update 48 // [`SshKeyData::into_erased`](crate::SshKeyData::into_erased) to 49 // return the corresponding concrete type implementing `EncodableItem` 50 // (as a `dyn EncodableItem`). 51 pub trait EncodableItem: ItemType + Downcast { 52 /// Return the key as a [`KeystoreItem`]. 53 fn as_keystore_item(&self) -> Result<KeystoreItem>; 54 } 55 impl_downcast!(EncodableItem); 56 57 /// A public key, keypair, or key certificate. 58 #[derive(Debug, Clone, derive_more::From)] 59 #[non_exhaustive] 60 pub enum KeystoreItem { 61 /// A public key or a keypair. 62 Key(SshKeyData), 63 /// A certificate. 64 Cert(CertData), 65 } 66 67 impl KeystoreItem { 68 /// Return the [`KeystoreItemType`] of this item. 69 pub fn item_type(&self) -> Result<KeystoreItemType> { 70 match self { 71 KeystoreItem::Key(ssh_key_data) => ssh_key_data.key_type().map(KeystoreItemType::Key), 72 KeystoreItem::Cert(cert) => Ok(KeystoreItemType::Cert(cert.cert_type())), 73 } 74 } 75 76 /// Convert the key/cert material into a known type, 77 /// and return the type-erased value. 78 /// 79 /// The caller is expected to downcast the value returned to the correct concrete type. 80 pub fn into_erased(self) -> Result<ErasedKey> { 81 match self { 82 KeystoreItem::Key(ssh_key_data) => ssh_key_data.into_erased(), 83 KeystoreItem::Cert(cert_data) => cert_data.into_erased(), 84 } 85 } 86 } 87 88 /// A key that can be converted to an [`EncodableItem`]. 89 // 90 // NOTE: Conceptually, the `ToEncodableKey` and `EncodableItem` traits serve the same purpose (they 91 // provide information about how to encode/decode a key). 92 // 93 // The reason we have two traits instead of just one is because `EncodableItem` cannot have an 94 // associated type: for instance, if it did, we'd need to either give 95 // `tor-keymgr::Keystore::insert` a generic parameter (which would make `Keystore` object-unsafe), 96 // or specify a concrete type for the associated type of the `EncodableItem` (which would defeat the 97 // whole purpose of the trait, i.e. to enable users to store their own "encodable key" types). 98 // 99 // `ToEncodableKey` is used in the `KeyMgr` impl, where the associated type isn't an issue because 100 // the `KeyMgr` implementation is generic over `K: ToEncodableKey`. The `Keystore`s themselves only 101 // receive `&dyn EncodableItem`s. 102 // 103 pub trait ToEncodableKey: From<Self::KeyPair> 104 where 105 Self::Key: From<<Self::KeyPair as ToEncodableKey>::Key>, 106 { 107 /// The key type this can be converted to/from. 108 type Key: EncodableItem + 'static; 109 110 /// The KeyPair (secret+public) of which this key is a subset. For secret 111 /// keys, this type is Self. For public keys, this type is the 112 /// corresponding (secret) keypair. 113 /// 114 /// The associated type constraint (`where`) expresses the fact that a 115 /// public key is always derivable from its corresponding secret key. 116 /// 117 type KeyPair: ToEncodableKey; 118 119 /// Convert this key to a type that implements [`EncodableItem`]. 120 fn to_encodable_key(self) -> Self::Key; 121 122 /// Convert an [`EncodableItem`] to another key type. 123 fn from_encodable_key(key: Self::Key) -> Self; 124 } 125 126 /// A trait representing an encodable certificate. 127 /// 128 /// `K` represents the (Rust) type of the subject key. 129 pub trait ToEncodableCert<K: ToEncodableKey>: Clone { 130 /// The low-level type this can be converted from. 131 type ParsedCert: ItemType + 'static; 132 133 /// The low-level type this can be converted to. 134 type EncodableCert: EncodableItem + 'static; 135 136 /// The (Rust) type of the signing key. 137 type SigningKey: ToEncodableKey; 138 139 /// Validate this certificate. 140 // 141 // This function will be called from functions such as KeyMgr::get_key_and_cert() 142 // to validate the cert using the provided subject key 143 // (the concrete type of which is given by the `K` in KeyMgr::get_key_and_cert()) 144 // and ToEncodableCert::SigningKey. 145 // 146 /// This function should return an error if 147 /// * the certificate is not timely 148 /// (i.e. it is expired, or not yet valid), or 149 /// * the certificate is not well-signed, or 150 /// * the subject key or signing key in the certificate do not match 151 /// the subject and signing keys specified in `cert_spec` 152 fn validate( 153 cert: Self::ParsedCert, 154 subject: &K, 155 signed_with: &Self::SigningKey, 156 ) -> StdResult<Self, InvalidCertError>; 157 158 /// Convert this cert to a type that implements [`EncodableItem`]. 159 fn to_encodable_cert(self) -> Self::EncodableCert; 160 } 161 162 /// The error type returned by [`ToEncodableCert::validate`]. 163 #[derive(thiserror::Error, Debug, Clone)] 164 #[non_exhaustive] 165 pub enum InvalidCertError { 166 /// An error caused by a key certificate with an invalid signature. 167 #[error("Invalid signature")] 168 CertSignature(#[from] tor_cert::CertError), 169 170 /// An error caused by an untimely key certificate. 171 #[error("Certificate is expired or not yet valid")] 172 TimeValidity(#[from] tor_checkable::TimeValidityError), 173 174 /// A key certificate with an unexpected subject key algorithm. 175 #[error("Unexpected subject key algorithm")] 176 InvalidSubjectKeyAlgorithm, 177 178 /// An error caused by a key certificate with an unexpected subject key. 179 #[error("Certificate certifies the wrong key")] 180 SubjectKeyMismatch, 181 182 /// An error caused by a key certificate with an unexpected `CertType`. 183 #[error("Unexpected cert type")] 184 CertType(tor_cert::CertType), 185 } 186 187 impl Keygen for curve25519::StaticKeypair { 188 fn generate(rng: &mut dyn KeygenRng) -> Result<Self> 189 where 190 Self: Sized, 191 { 192 let secret = curve25519::StaticSecret::random_from_rng(rng); 193 let public = curve25519::PublicKey::from(&secret); 194 195 Ok(curve25519::StaticKeypair { secret, public }) 196 } 197 } 198 199 impl ItemType for curve25519::StaticKeypair { 200 fn item_type() -> KeystoreItemType 201 where 202 Self: Sized, 203 { 204 KeyType::X25519StaticKeypair.into() 205 } 206 } 207 208 impl EncodableItem for curve25519::StaticKeypair { 209 fn as_keystore_item(&self) -> Result<KeystoreItem> { 210 let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME) 211 .map_err(|_| internal!("invalid algorithm name"))?; 212 213 let ssh_public = OpaquePublicKey::new( 214 self.public.to_bytes().to_vec(), 215 Algorithm::Other(algorithm_name), 216 ); 217 let keypair = OpaqueKeypair::new(self.secret.to_bytes().to_vec(), ssh_public); 218 219 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from) 220 } 221 } 222 223 impl ItemType for curve25519::PublicKey { 224 fn item_type() -> KeystoreItemType 225 where 226 Self: Sized, 227 { 228 KeyType::X25519PublicKey.into() 229 } 230 } 231 232 impl EncodableItem for curve25519::PublicKey { 233 fn as_keystore_item(&self) -> Result<KeystoreItem> { 234 let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME) 235 .map_err(|_| internal!("invalid algorithm name"))?; 236 237 let ssh_public = 238 OpaquePublicKey::new(self.to_bytes().to_vec(), Algorithm::Other(algorithm_name)); 239 240 SshKeyData::try_from_key_data(KeyData::Other(ssh_public)).map(KeystoreItem::from) 241 } 242 } 243 244 impl Keygen for ed25519::Keypair { 245 fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self> 246 where 247 Self: Sized, 248 { 249 Ok(ed25519::Keypair::generate(&mut rng)) 250 } 251 } 252 253 impl ItemType for ed25519::Keypair { 254 fn item_type() -> KeystoreItemType 255 where 256 Self: Sized, 257 { 258 KeyType::Ed25519Keypair.into() 259 } 260 } 261 262 impl EncodableItem for ed25519::Keypair { 263 fn as_keystore_item(&self) -> Result<KeystoreItem> { 264 let keypair = Ed25519Keypair { 265 public: Ed25519PublicKey(self.verifying_key().to_bytes()), 266 private: Ed25519PrivateKey::from_bytes(self.as_bytes()), 267 }; 268 269 SshKeyData::try_from_keypair_data(KeypairData::Ed25519(keypair)).map(KeystoreItem::from) 270 } 271 } 272 273 impl ItemType for ed25519::PublicKey { 274 fn item_type() -> KeystoreItemType 275 where 276 Self: Sized, 277 { 278 KeyType::Ed25519PublicKey.into() 279 } 280 } 281 282 impl EncodableItem for ed25519::PublicKey { 283 fn as_keystore_item(&self) -> Result<KeystoreItem> { 284 let key_data = Ed25519PublicKey(self.to_bytes()); 285 286 SshKeyData::try_from_key_data(ssh_key::public::KeyData::Ed25519(key_data)) 287 .map(KeystoreItem::from) 288 } 289 } 290 291 impl Keygen for ed25519::ExpandedKeypair { 292 fn generate(rng: &mut dyn KeygenRng) -> Result<Self> 293 where 294 Self: Sized, 295 { 296 let keypair = <ed25519::Keypair as Keygen>::generate(rng)?; 297 298 Ok((&keypair).into()) 299 } 300 } 301 302 impl ItemType for ed25519::ExpandedKeypair { 303 fn item_type() -> KeystoreItemType 304 where 305 Self: Sized, 306 { 307 KeyType::Ed25519ExpandedKeypair.into() 308 } 309 } 310 311 impl EncodableItem for ed25519::ExpandedKeypair { 312 fn as_keystore_item(&self) -> Result<KeystoreItem> { 313 let algorithm_name = AlgorithmName::new(ED25519_EXPANDED_ALGORITHM_NAME) 314 .map_err(|_| internal!("invalid algorithm name"))?; 315 316 let ssh_public = OpaquePublicKey::new( 317 self.public().to_bytes().to_vec(), 318 Algorithm::Other(algorithm_name), 319 ); 320 321 let keypair = OpaqueKeypair::new(self.to_secret_key_bytes().to_vec(), ssh_public); 322 323 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from) 324 } 325 } 326 327 impl ItemType for crate::EncodedEd25519Cert { 328 fn item_type() -> KeystoreItemType 329 where 330 Self: Sized, 331 { 332 CertType::Ed25519TorCert.into() 333 } 334 } 335 336 impl ItemType for crate::ParsedEd25519Cert { 337 fn item_type() -> KeystoreItemType 338 where 339 Self: Sized, 340 { 341 CertType::Ed25519TorCert.into() 342 } 343 } 344 345 impl EncodableItem for crate::EncodedEd25519Cert { 346 fn as_keystore_item(&self) -> Result<KeystoreItem> { 347 Ok(CertData::TorEd25519Cert(self.clone()).into()) 348 } 349 }