1use downcast_rs::{impl_downcast, Downcast};
4use rand::RngCore;
5use ssh_key::{
6 private::{Ed25519Keypair, Ed25519PrivateKey, KeypairData, OpaqueKeypair},
7 public::{Ed25519PublicKey, KeyData, OpaquePublicKey},
8 rand_core::CryptoRng,
9 Algorithm, AlgorithmName,
10};
11use tor_error::internal;
12use tor_llcrypto::pk::{curve25519, ed25519};
13
14use crate::certs::CertData;
15use crate::key_type::CertType;
16use crate::{
17 ssh::{SshKeyData, ED25519_EXPANDED_ALGORITHM_NAME, X25519_ALGORITHM_NAME},
18 ErasedKey, KeyType, KeystoreItemType, Result,
19};
20
21use std::result::Result as StdResult;
22
23pub trait KeygenRng: RngCore + CryptoRng {}
25
26impl<T> KeygenRng for T where T: RngCore + CryptoRng {}
27
28pub trait Keygen {
30 fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
32 where
33 Self: Sized;
34}
35
36pub trait ItemType: Downcast {
38 fn item_type() -> KeystoreItemType
40 where
41 Self: Sized;
42}
43impl_downcast!(ItemType);
44
45pub trait EncodableItem: ItemType + Downcast {
52 fn as_keystore_item(&self) -> Result<KeystoreItem>;
54}
55impl_downcast!(EncodableItem);
56
57#[derive(Debug, Clone, derive_more::From)]
59#[non_exhaustive]
60pub enum KeystoreItem {
61 Key(SshKeyData),
63 Cert(CertData),
65}
66
67impl KeystoreItem {
68 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 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
88pub trait ToEncodableKey: From<Self::KeyPair>
104where
105 Self::Key: From<<Self::KeyPair as ToEncodableKey>::Key>,
106{
107 type Key: EncodableItem + 'static;
109
110 type KeyPair: ToEncodableKey;
118
119 fn to_encodable_key(self) -> Self::Key;
121
122 fn from_encodable_key(key: Self::Key) -> Self;
124}
125
126pub trait ToEncodableCert<K: ToEncodableKey>: Clone {
130 type ParsedCert: ItemType + 'static;
132
133 type EncodableCert: EncodableItem + 'static;
135
136 type SigningKey: ToEncodableKey;
138
139 fn validate(
153 cert: Self::ParsedCert,
154 subject: &K,
155 signed_with: &Self::SigningKey,
156 ) -> StdResult<Self, InvalidCertError>;
157
158 fn to_encodable_cert(self) -> Self::EncodableCert;
160}
161
162#[derive(thiserror::Error, Debug, Clone)]
164#[non_exhaustive]
165pub enum InvalidCertError {
166 #[error("Invalid signature")]
168 CertSignature(#[from] tor_cert::CertError),
169
170 #[error("Certificate is expired or not yet valid")]
172 TimeValidity(#[from] tor_checkable::TimeValidityError),
173
174 #[error("Unexpected subject key algorithm")]
176 InvalidSubjectKeyAlgorithm,
177
178 #[error("Certificate certifies the wrong key")]
180 SubjectKeyMismatch,
181
182 #[error("Unexpected cert type")]
184 CertType(tor_cert::CertType),
185}
186
187impl 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
199impl ItemType for curve25519::StaticKeypair {
200 fn item_type() -> KeystoreItemType
201 where
202 Self: Sized,
203 {
204 KeyType::X25519StaticKeypair.into()
205 }
206}
207
208impl 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
223impl ItemType for curve25519::PublicKey {
224 fn item_type() -> KeystoreItemType
225 where
226 Self: Sized,
227 {
228 KeyType::X25519PublicKey.into()
229 }
230}
231
232impl 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
244impl 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
253impl ItemType for ed25519::Keypair {
254 fn item_type() -> KeystoreItemType
255 where
256 Self: Sized,
257 {
258 KeyType::Ed25519Keypair.into()
259 }
260}
261
262impl 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
273impl ItemType for ed25519::PublicKey {
274 fn item_type() -> KeystoreItemType
275 where
276 Self: Sized,
277 {
278 KeyType::Ed25519PublicKey.into()
279 }
280}
281
282impl 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
291impl 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
302impl ItemType for ed25519::ExpandedKeypair {
303 fn item_type() -> KeystoreItemType
304 where
305 Self: Sized,
306 {
307 KeyType::Ed25519ExpandedKeypair.into()
308 }
309}
310
311impl 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
327impl ItemType for crate::EncodedEd25519Cert {
328 fn item_type() -> KeystoreItemType
329 where
330 Self: Sized,
331 {
332 CertType::Ed25519TorCert.into()
333 }
334}
335
336impl ItemType for crate::ParsedEd25519Cert {
337 fn item_type() -> KeystoreItemType
338 where
339 Self: Sized,
340 {
341 CertType::Ed25519TorCert.into()
342 }
343}
344
345impl EncodableItem for crate::EncodedEd25519Cert {
346 fn as_keystore_item(&self) -> Result<KeystoreItem> {
347 Ok(CertData::TorEd25519Cert(self.clone()).into())
348 }
349}