1//! All the traits of this crate.
23use downcast_rs::{impl_downcast, Downcast};
4use rand::{CryptoRng, RngCore};
5use ssh_key::{
6 private::{Ed25519Keypair, Ed25519PrivateKey, KeypairData, OpaqueKeypair},
7 public::{Ed25519PublicKey, KeyData, OpaquePublicKey},
8 Algorithm, AlgorithmName,
9};
10use tor_error::internal;
11use tor_llcrypto::{
12 pk::{curve25519, ed25519},
13 rng::EntropicRng,
14};
1516use crate::certs::CertData;
17use crate::key_type::CertType;
18use crate::{
19 ssh::{SshKeyData, ED25519_EXPANDED_ALGORITHM_NAME, X25519_ALGORITHM_NAME},
20 ErasedKey, KeyType, KeystoreItemType, Result,
21};
2223use std::result::Result as StdResult;
2425/// A random number generator for generating [`EncodableItem`]s.
26pub trait KeygenRng: RngCore + CryptoRng + EntropicRng {}
2728impl<T> KeygenRng for T where T: RngCore + CryptoRng + EntropicRng {}
2930/// A trait for generating fresh keys.
31pub trait Keygen {
32/// Generate a new key of this type.
33fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
34where
35Self: Sized;
36}
3738/// A trait for getting the type of an item.
39pub trait ItemType: Downcast {
40/// The type of the key.
41fn item_type() -> KeystoreItemType
42where
43Self: Sized;
44}
45impl_downcast!(ItemType);
4647/// A key that can be serialized to, and deserialized from.
48//
49// When adding a new `EncodableItem` impl, you must also update
50// [`SshKeyData::into_erased`](crate::SshKeyData::into_erased) to
51// return the corresponding concrete type implementing `EncodableItem`
52// (as a `dyn EncodableItem`).
53pub trait EncodableItem: ItemType + Downcast {
54/// Return the key as a [`KeystoreItem`].
55fn as_keystore_item(&self) -> Result<KeystoreItem>;
56}
57impl_downcast!(EncodableItem);
5859/// A public key, keypair, or key certificate.
60#[derive(Debug, Clone, derive_more::From)]
61#[non_exhaustive]
62pub enum KeystoreItem {
63/// A public key or a keypair.
64Key(SshKeyData),
65/// A certificate.
66Cert(CertData),
67}
6869impl KeystoreItem {
70/// Return the [`KeystoreItemType`] of this item.
71pub fn item_type(&self) -> Result<KeystoreItemType> {
72match self {
73 KeystoreItem::Key(ssh_key_data) => ssh_key_data.key_type().map(KeystoreItemType::Key),
74 KeystoreItem::Cert(cert) => Ok(KeystoreItemType::Cert(cert.cert_type())),
75 }
76 }
7778/// Convert the key/cert material into a known type,
79 /// and return the type-erased value.
80 ///
81 /// The caller is expected to downcast the value returned to the correct concrete type.
82pub fn into_erased(self) -> Result<ErasedKey> {
83match self {
84 KeystoreItem::Key(ssh_key_data) => ssh_key_data.into_erased(),
85 KeystoreItem::Cert(cert_data) => cert_data.into_erased(),
86 }
87 }
88}
8990/// A key that can be converted to an [`EncodableItem`].
91//
92// NOTE: Conceptually, the `ToEncodableKey` and `EncodableItem` traits serve the same purpose (they
93// provide information about how to encode/decode a key).
94//
95// The reason we have two traits instead of just one is because `EncodableItem` cannot have an
96// associated type: for instance, if it did, we'd need to either give
97// `tor-keymgr::Keystore::insert` a generic parameter (which would make `Keystore` object-unsafe),
98// or specify a concrete type for the associated type of the `EncodableItem` (which would defeat the
99// whole purpose of the trait, i.e. to enable users to store their own "encodable key" types).
100//
101// `ToEncodableKey` is used in the `KeyMgr` impl, where the associated type isn't an issue because
102// the `KeyMgr` implementation is generic over `K: ToEncodableKey`. The `Keystore`s themselves only
103// receive `&dyn EncodableItem`s.
104//
105pub trait ToEncodableKey: From<Self::KeyPair>
106where
107Self::Key: From<<Self::KeyPair as ToEncodableKey>::Key>,
108{
109/// The key type this can be converted to/from.
110type Key: EncodableItem + 'static;
111112/// The KeyPair (secret+public) of which this key is a subset. For secret
113 /// keys, this type is Self. For public keys, this type is the
114 /// corresponding (secret) keypair.
115 ///
116 /// The associated type constraint (`where`) expresses the fact that a
117 /// public key is always derivable from its corresponding secret key.
118 ///
119type KeyPair: ToEncodableKey;
120121/// Convert this key to a type that implements [`EncodableItem`].
122fn to_encodable_key(self) -> Self::Key;
123124/// Convert an [`EncodableItem`] to another key type.
125fn from_encodable_key(key: Self::Key) -> Self;
126}
127128/// A trait representing an encodable certificate.
129///
130/// `K` represents the (Rust) type of the subject key.
131pub trait ToEncodableCert<K: ToEncodableKey>: Clone {
132/// The low-level type this can be converted from.
133type ParsedCert: ItemType + 'static;
134135/// The low-level type this can be converted to.
136type EncodableCert: EncodableItem + 'static;
137138/// The (Rust) type of the signing key.
139type SigningKey: ToEncodableKey;
140141/// Validate this certificate.
142//
143 // This function will be called from functions such as KeyMgr::get_key_and_cert()
144 // to validate the cert using the provided subject key
145 // (the concrete type of which is given by the `K` in KeyMgr::get_key_and_cert())
146 // and ToEncodableCert::SigningKey.
147 //
148/// This function should return an error if
149 /// * the certificate is not timely
150 /// (i.e. it is expired, or not yet valid), or
151 /// * the certificate is not well-signed, or
152 /// * the subject key or signing key in the certificate do not match
153 /// the subject and signing keys specified in `cert_spec`
154fn validate(
155 cert: Self::ParsedCert,
156 subject: &K,
157 signed_with: &Self::SigningKey,
158 ) -> StdResult<Self, InvalidCertError>;
159160/// Convert this cert to a type that implements [`EncodableItem`].
161fn to_encodable_cert(self) -> Self::EncodableCert;
162}
163164/// The error type returned by [`ToEncodableCert::validate`].
165#[derive(thiserror::Error, Debug, Clone)]
166#[non_exhaustive]
167pub enum InvalidCertError {
168/// An error caused by a key certificate with an invalid signature.
169#[error("Invalid signature")]
170CertSignature(#[from] tor_cert::CertError),
171172/// An error caused by an untimely key certificate.
173#[error("Certificate is expired or not yet valid")]
174TimeValidity(#[from] tor_checkable::TimeValidityError),
175176/// A key certificate with an unexpected subject key algorithm.
177#[error("Unexpected subject key algorithm")]
178InvalidSubjectKeyAlgorithm,
179180/// An error caused by a key certificate with an unexpected subject key.
181#[error("Certificate certifies the wrong key")]
182SubjectKeyMismatch,
183184/// An error caused by a key certificate with an unexpected `CertType`.
185#[error("Unexpected cert type")]
186CertType(tor_cert::CertType),
187}
188189impl Keygen for curve25519::StaticKeypair {
190fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
191where
192Self: Sized,
193 {
194let secret = curve25519::StaticSecret::random_from_rng(rng);
195let public = curve25519::PublicKey::from(&secret);
196197Ok(curve25519::StaticKeypair { secret, public })
198 }
199}
200201impl ItemType for curve25519::StaticKeypair {
202fn item_type() -> KeystoreItemType
203where
204Self: Sized,
205 {
206 KeyType::X25519StaticKeypair.into()
207 }
208}
209210impl EncodableItem for curve25519::StaticKeypair {
211fn as_keystore_item(&self) -> Result<KeystoreItem> {
212let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
213 .map_err(|_| internal!("invalid algorithm name"))?;
214215let ssh_public = OpaquePublicKey::new(
216self.public.to_bytes().to_vec(),
217 Algorithm::Other(algorithm_name),
218 );
219let keypair = OpaqueKeypair::new(self.secret.to_bytes().to_vec(), ssh_public);
220221 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
222 }
223}
224225impl ItemType for curve25519::PublicKey {
226fn item_type() -> KeystoreItemType
227where
228Self: Sized,
229 {
230 KeyType::X25519PublicKey.into()
231 }
232}
233234impl EncodableItem for curve25519::PublicKey {
235fn as_keystore_item(&self) -> Result<KeystoreItem> {
236let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
237 .map_err(|_| internal!("invalid algorithm name"))?;
238239let ssh_public =
240 OpaquePublicKey::new(self.to_bytes().to_vec(), Algorithm::Other(algorithm_name));
241242 SshKeyData::try_from_key_data(KeyData::Other(ssh_public)).map(KeystoreItem::from)
243 }
244}
245246impl Keygen for ed25519::Keypair {
247fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self>
248where
249Self: Sized,
250 {
251Ok(ed25519::Keypair::generate(&mut rng))
252 }
253}
254255impl ItemType for ed25519::Keypair {
256fn item_type() -> KeystoreItemType
257where
258Self: Sized,
259 {
260 KeyType::Ed25519Keypair.into()
261 }
262}
263264impl EncodableItem for ed25519::Keypair {
265fn as_keystore_item(&self) -> Result<KeystoreItem> {
266let keypair = Ed25519Keypair {
267 public: Ed25519PublicKey(self.verifying_key().to_bytes()),
268 private: Ed25519PrivateKey::from_bytes(self.as_bytes()),
269 };
270271 SshKeyData::try_from_keypair_data(KeypairData::Ed25519(keypair)).map(KeystoreItem::from)
272 }
273}
274275impl ItemType for ed25519::PublicKey {
276fn item_type() -> KeystoreItemType
277where
278Self: Sized,
279 {
280 KeyType::Ed25519PublicKey.into()
281 }
282}
283284impl EncodableItem for ed25519::PublicKey {
285fn as_keystore_item(&self) -> Result<KeystoreItem> {
286let key_data = Ed25519PublicKey(self.to_bytes());
287288 SshKeyData::try_from_key_data(ssh_key::public::KeyData::Ed25519(key_data))
289 .map(KeystoreItem::from)
290 }
291}
292293impl Keygen for ed25519::ExpandedKeypair {
294fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
295where
296Self: Sized,
297 {
298let keypair = <ed25519::Keypair as Keygen>::generate(rng)?;
299300Ok((&keypair).into())
301 }
302}
303304impl ItemType for ed25519::ExpandedKeypair {
305fn item_type() -> KeystoreItemType
306where
307Self: Sized,
308 {
309 KeyType::Ed25519ExpandedKeypair.into()
310 }
311}
312313impl EncodableItem for ed25519::ExpandedKeypair {
314fn as_keystore_item(&self) -> Result<KeystoreItem> {
315let algorithm_name = AlgorithmName::new(ED25519_EXPANDED_ALGORITHM_NAME)
316 .map_err(|_| internal!("invalid algorithm name"))?;
317318let ssh_public = OpaquePublicKey::new(
319self.public().to_bytes().to_vec(),
320 Algorithm::Other(algorithm_name),
321 );
322323let keypair = OpaqueKeypair::new(self.to_secret_key_bytes().to_vec(), ssh_public);
324325 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
326 }
327}
328329impl ItemType for crate::EncodedEd25519Cert {
330fn item_type() -> KeystoreItemType
331where
332Self: Sized,
333 {
334 CertType::Ed25519TorCert.into()
335 }
336}
337338impl ItemType for crate::ParsedEd25519Cert {
339fn item_type() -> KeystoreItemType
340where
341Self: Sized,
342 {
343 CertType::Ed25519TorCert.into()
344 }
345}
346347impl EncodableItem for crate::EncodedEd25519Cert {
348fn as_keystore_item(&self) -> Result<KeystoreItem> {
349Ok(CertData::TorEd25519Cert(self.clone()).into())
350 }
351}