1use downcast_rs::{Downcast, impl_downcast};
4use rand::{CryptoRng, RngCore};
5use ssh_key::{
6 Algorithm, AlgorithmName,
7 private::{Ed25519Keypair, Ed25519PrivateKey, KeypairData, OpaqueKeypair},
8 public::{Ed25519PublicKey, KeyData, OpaquePublicKey},
9};
10use tor_error::internal;
11use tor_llcrypto::{
12 pk::{curve25519, ed25519, rsa},
13 rng::EntropicRng,
14};
15
16use crate::certs::CertData;
17use crate::key_type::CertType;
18use crate::{
19 KeyType, KeystoreItemType, Result,
20 ssh::{ED25519_EXPANDED_ALGORITHM_NAME, SshKeyData, X25519_ALGORITHM_NAME},
21};
22
23use std::result::Result as StdResult;
24
25pub trait KeygenRng: RngCore + CryptoRng + EntropicRng {}
27
28impl<T> KeygenRng for T where T: RngCore + CryptoRng + EntropicRng {}
29
30pub trait Keygen {
32 fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
34 where
35 Self: Sized;
36}
37
38pub trait ItemType: Downcast {
40 fn item_type() -> KeystoreItemType
42 where
43 Self: Sized;
44}
45impl_downcast!(ItemType);
46
47pub trait EncodableItem: ItemType + Downcast {
54 fn as_keystore_item(&self) -> Result<KeystoreItem>;
56}
57impl_downcast!(EncodableItem);
58
59#[derive(Debug, Clone, derive_more::From)]
61#[non_exhaustive]
62pub enum KeystoreItem {
63 Key(SshKeyData),
65 Cert(CertData),
67}
68
69impl KeystoreItem {
70 pub fn item_type(&self) -> Result<KeystoreItemType> {
72 match 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 }
77}
78
79pub trait ToEncodableKey: From<Self::KeyPair>
95where
96 Self::Key: From<<Self::KeyPair as ToEncodableKey>::Key>,
97{
98 type Key: EncodableItem + 'static;
100
101 type KeyPair: ToEncodableKey;
109
110 fn to_encodable_key(self) -> Self::Key;
112
113 fn from_encodable_key(key: Self::Key) -> Self;
115}
116
117pub trait ToEncodableCert<K: ToEncodableKey>: Clone {
121 type ParsedCert: ItemType + 'static;
123
124 type EncodableCert: EncodableItem + 'static;
126
127 type SigningKey: ToEncodableKey;
129
130 fn validate(
144 cert: Self::ParsedCert,
145 subject: &K,
146 signed_with: &Self::SigningKey,
147 ) -> StdResult<Self, InvalidCertError>;
148
149 fn to_encodable_cert(self) -> Self::EncodableCert;
151}
152
153#[derive(thiserror::Error, Debug, Clone)]
155#[non_exhaustive]
156pub enum InvalidCertError {
157 #[error("Invalid signature")]
159 CertSignature(#[from] tor_cert::CertError),
160
161 #[error("Certificate is expired or not yet valid")]
163 TimeValidity(#[from] tor_checkable::TimeValidityError),
164
165 #[error("Unexpected subject key algorithm")]
167 InvalidSubjectKeyAlgorithm,
168
169 #[error("Certificate certifies the wrong key")]
171 SubjectKeyMismatch,
172
173 #[error("Unexpected cert type")]
175 CertType(tor_cert::CertType),
176}
177
178impl Keygen for curve25519::StaticKeypair {
179 fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
180 where
181 Self: Sized,
182 {
183 let secret = curve25519::StaticSecret::random_from_rng(rng);
184 let public = curve25519::PublicKey::from(&secret);
185
186 Ok(curve25519::StaticKeypair { secret, public })
187 }
188}
189
190impl ItemType for curve25519::StaticKeypair {
191 fn item_type() -> KeystoreItemType
192 where
193 Self: Sized,
194 {
195 KeyType::X25519StaticKeypair.into()
196 }
197}
198
199impl EncodableItem for curve25519::StaticKeypair {
200 fn as_keystore_item(&self) -> Result<KeystoreItem> {
201 let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
202 .map_err(|_| internal!("invalid algorithm name"))?;
203
204 let ssh_public = OpaquePublicKey::new(
205 self.public.to_bytes().to_vec(),
206 Algorithm::Other(algorithm_name),
207 );
208 let keypair = OpaqueKeypair::new(self.secret.to_bytes().to_vec(), ssh_public);
209
210 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
211 }
212}
213
214impl ItemType for curve25519::PublicKey {
215 fn item_type() -> KeystoreItemType
216 where
217 Self: Sized,
218 {
219 KeyType::X25519PublicKey.into()
220 }
221}
222
223impl EncodableItem for curve25519::PublicKey {
224 fn as_keystore_item(&self) -> Result<KeystoreItem> {
225 let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
226 .map_err(|_| internal!("invalid algorithm name"))?;
227
228 let ssh_public =
229 OpaquePublicKey::new(self.to_bytes().to_vec(), Algorithm::Other(algorithm_name));
230
231 SshKeyData::try_from_key_data(KeyData::Other(ssh_public)).map(KeystoreItem::from)
232 }
233}
234
235impl Keygen for ed25519::Keypair {
236 fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self>
237 where
238 Self: Sized,
239 {
240 Ok(ed25519::Keypair::generate(&mut rng))
241 }
242}
243
244impl ItemType for ed25519::Keypair {
245 fn item_type() -> KeystoreItemType
246 where
247 Self: Sized,
248 {
249 KeyType::Ed25519Keypair.into()
250 }
251}
252
253impl EncodableItem for ed25519::Keypair {
254 fn as_keystore_item(&self) -> Result<KeystoreItem> {
255 let keypair = Ed25519Keypair {
256 public: Ed25519PublicKey(self.verifying_key().to_bytes()),
257 private: Ed25519PrivateKey::from_bytes(self.as_bytes()),
258 };
259
260 SshKeyData::try_from_keypair_data(KeypairData::Ed25519(keypair)).map(KeystoreItem::from)
261 }
262}
263
264impl ItemType for ed25519::PublicKey {
265 fn item_type() -> KeystoreItemType
266 where
267 Self: Sized,
268 {
269 KeyType::Ed25519PublicKey.into()
270 }
271}
272
273impl EncodableItem for ed25519::PublicKey {
274 fn as_keystore_item(&self) -> Result<KeystoreItem> {
275 let key_data = Ed25519PublicKey(self.to_bytes());
276
277 SshKeyData::try_from_key_data(ssh_key::public::KeyData::Ed25519(key_data))
278 .map(KeystoreItem::from)
279 }
280}
281
282impl Keygen for ed25519::ExpandedKeypair {
283 fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
284 where
285 Self: Sized,
286 {
287 let keypair = <ed25519::Keypair as Keygen>::generate(rng)?;
288
289 Ok((&keypair).into())
290 }
291}
292
293impl ItemType for ed25519::ExpandedKeypair {
294 fn item_type() -> KeystoreItemType
295 where
296 Self: Sized,
297 {
298 KeyType::Ed25519ExpandedKeypair.into()
299 }
300}
301
302impl EncodableItem for ed25519::ExpandedKeypair {
303 fn as_keystore_item(&self) -> Result<KeystoreItem> {
304 let algorithm_name = AlgorithmName::new(ED25519_EXPANDED_ALGORITHM_NAME)
305 .map_err(|_| internal!("invalid algorithm name"))?;
306
307 let ssh_public = OpaquePublicKey::new(
308 self.public().to_bytes().to_vec(),
309 Algorithm::Other(algorithm_name),
310 );
311
312 let keypair = OpaqueKeypair::new(self.to_secret_key_bytes().to_vec(), ssh_public);
313
314 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
315 }
316}
317
318impl ItemType for crate::EncodedEd25519Cert {
319 fn item_type() -> KeystoreItemType
320 where
321 Self: Sized,
322 {
323 CertType::Ed25519TorCert.into()
324 }
325}
326
327impl ItemType for crate::ParsedEd25519Cert {
328 fn item_type() -> KeystoreItemType
329 where
330 Self: Sized,
331 {
332 CertType::Ed25519TorCert.into()
333 }
334}
335
336impl EncodableItem for crate::EncodedEd25519Cert {
337 fn as_keystore_item(&self) -> Result<KeystoreItem> {
338 Ok(CertData::TorEd25519Cert(self.clone()).into())
339 }
340}
341
342impl Keygen for rsa::KeyPair {
343 fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self>
344 where
345 Self: Sized,
346 {
347 Ok(rsa::KeyPair::generate(&mut rng)?)
348 }
349}
350
351impl ItemType for rsa::KeyPair {
352 fn item_type() -> KeystoreItemType
353 where
354 Self: Sized,
355 {
356 KeyType::RsaKeypair.into()
357 }
358}
359
360impl EncodableItem for rsa::KeyPair {
361 fn as_keystore_item(&self) -> Result<KeystoreItem> {
362 let keypair = self.as_key().try_into().map_err(tor_error::into_internal!(
363 "Error converting rsa::PrivateKey into ssh_key::private::RsaKeypair."
364 ))?;
365
366 SshKeyData::try_from_keypair_data(KeypairData::Rsa(keypair)).map(KeystoreItem::from)
367 }
368}
369
370impl ItemType for rsa::PublicKey {
371 fn item_type() -> KeystoreItemType
372 where
373 Self: Sized,
374 {
375 KeyType::RsaPublicKey.into()
376 }
377}
378
379impl EncodableItem for rsa::PublicKey {
380 fn as_keystore_item(&self) -> Result<KeystoreItem> {
381 let key_data = self.as_key().try_into().map_err(tor_error::into_internal!(
382 "Error converting rsa::PublicKey into ssh_key::public::rsa::RsaPublicKey."
383 ))?;
384
385 SshKeyData::try_from_key_data(ssh_key::public::KeyData::Rsa(key_data))
386 .map(KeystoreItem::from)
387 }
388}