1use 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};
15
16use 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};
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 pub fn into_erased(self) -> Result<ErasedKey> {
83 match self {
84 KeystoreItem::Key(ssh_key_data) => ssh_key_data.into_erased(),
85 KeystoreItem::Cert(cert_data) => cert_data.into_erased(),
86 }
87 }
88}
89
90pub trait ToEncodableKey: From<Self::KeyPair>
106where
107 Self::Key: From<<Self::KeyPair as ToEncodableKey>::Key>,
108{
109 type Key: EncodableItem + 'static;
111
112 type KeyPair: ToEncodableKey;
120
121 fn to_encodable_key(self) -> Self::Key;
123
124 fn from_encodable_key(key: Self::Key) -> Self;
126}
127
128pub trait ToEncodableCert<K: ToEncodableKey>: Clone {
132 type ParsedCert: ItemType + 'static;
134
135 type EncodableCert: EncodableItem + 'static;
137
138 type SigningKey: ToEncodableKey;
140
141 fn validate(
155 cert: Self::ParsedCert,
156 subject: &K,
157 signed_with: &Self::SigningKey,
158 ) -> StdResult<Self, InvalidCertError>;
159
160 fn to_encodable_cert(self) -> Self::EncodableCert;
162}
163
164#[derive(thiserror::Error, Debug, Clone)]
166#[non_exhaustive]
167pub enum InvalidCertError {
168 #[error("Invalid signature")]
170 CertSignature(#[from] tor_cert::CertError),
171
172 #[error("Certificate is expired or not yet valid")]
174 TimeValidity(#[from] tor_checkable::TimeValidityError),
175
176 #[error("Unexpected subject key algorithm")]
178 InvalidSubjectKeyAlgorithm,
179
180 #[error("Certificate certifies the wrong key")]
182 SubjectKeyMismatch,
183
184 #[error("Unexpected cert type")]
186 CertType(tor_cert::CertType),
187}
188
189impl Keygen for curve25519::StaticKeypair {
190 fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
191 where
192 Self: Sized,
193 {
194 let secret = curve25519::StaticSecret::random_from_rng(rng);
195 let public = curve25519::PublicKey::from(&secret);
196
197 Ok(curve25519::StaticKeypair { secret, public })
198 }
199}
200
201impl ItemType for curve25519::StaticKeypair {
202 fn item_type() -> KeystoreItemType
203 where
204 Self: Sized,
205 {
206 KeyType::X25519StaticKeypair.into()
207 }
208}
209
210impl EncodableItem for curve25519::StaticKeypair {
211 fn as_keystore_item(&self) -> Result<KeystoreItem> {
212 let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
213 .map_err(|_| internal!("invalid algorithm name"))?;
214
215 let ssh_public = OpaquePublicKey::new(
216 self.public.to_bytes().to_vec(),
217 Algorithm::Other(algorithm_name),
218 );
219 let keypair = OpaqueKeypair::new(self.secret.to_bytes().to_vec(), ssh_public);
220
221 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
222 }
223}
224
225impl ItemType for curve25519::PublicKey {
226 fn item_type() -> KeystoreItemType
227 where
228 Self: Sized,
229 {
230 KeyType::X25519PublicKey.into()
231 }
232}
233
234impl EncodableItem for curve25519::PublicKey {
235 fn as_keystore_item(&self) -> Result<KeystoreItem> {
236 let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
237 .map_err(|_| internal!("invalid algorithm name"))?;
238
239 let ssh_public =
240 OpaquePublicKey::new(self.to_bytes().to_vec(), Algorithm::Other(algorithm_name));
241
242 SshKeyData::try_from_key_data(KeyData::Other(ssh_public)).map(KeystoreItem::from)
243 }
244}
245
246impl Keygen for ed25519::Keypair {
247 fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self>
248 where
249 Self: Sized,
250 {
251 Ok(ed25519::Keypair::generate(&mut rng))
252 }
253}
254
255impl ItemType for ed25519::Keypair {
256 fn item_type() -> KeystoreItemType
257 where
258 Self: Sized,
259 {
260 KeyType::Ed25519Keypair.into()
261 }
262}
263
264impl EncodableItem for ed25519::Keypair {
265 fn as_keystore_item(&self) -> Result<KeystoreItem> {
266 let keypair = Ed25519Keypair {
267 public: Ed25519PublicKey(self.verifying_key().to_bytes()),
268 private: Ed25519PrivateKey::from_bytes(self.as_bytes()),
269 };
270
271 SshKeyData::try_from_keypair_data(KeypairData::Ed25519(keypair)).map(KeystoreItem::from)
272 }
273}
274
275impl ItemType for ed25519::PublicKey {
276 fn item_type() -> KeystoreItemType
277 where
278 Self: Sized,
279 {
280 KeyType::Ed25519PublicKey.into()
281 }
282}
283
284impl EncodableItem for ed25519::PublicKey {
285 fn as_keystore_item(&self) -> Result<KeystoreItem> {
286 let key_data = Ed25519PublicKey(self.to_bytes());
287
288 SshKeyData::try_from_key_data(ssh_key::public::KeyData::Ed25519(key_data))
289 .map(KeystoreItem::from)
290 }
291}
292
293impl Keygen for ed25519::ExpandedKeypair {
294 fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
295 where
296 Self: Sized,
297 {
298 let keypair = <ed25519::Keypair as Keygen>::generate(rng)?;
299
300 Ok((&keypair).into())
301 }
302}
303
304impl ItemType for ed25519::ExpandedKeypair {
305 fn item_type() -> KeystoreItemType
306 where
307 Self: Sized,
308 {
309 KeyType::Ed25519ExpandedKeypair.into()
310 }
311}
312
313impl EncodableItem for ed25519::ExpandedKeypair {
314 fn as_keystore_item(&self) -> Result<KeystoreItem> {
315 let algorithm_name = AlgorithmName::new(ED25519_EXPANDED_ALGORITHM_NAME)
316 .map_err(|_| internal!("invalid algorithm name"))?;
317
318 let ssh_public = OpaquePublicKey::new(
319 self.public().to_bytes().to_vec(),
320 Algorithm::Other(algorithm_name),
321 );
322
323 let keypair = OpaqueKeypair::new(self.to_secret_key_bytes().to_vec(), ssh_public);
324
325 SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
326 }
327}
328
329impl ItemType for crate::EncodedEd25519Cert {
330 fn item_type() -> KeystoreItemType
331 where
332 Self: Sized,
333 {
334 CertType::Ed25519TorCert.into()
335 }
336}
337
338impl ItemType for crate::ParsedEd25519Cert {
339 fn item_type() -> KeystoreItemType
340 where
341 Self: Sized,
342 {
343 CertType::Ed25519TorCert.into()
344 }
345}
346
347impl EncodableItem for crate::EncodedEd25519Cert {
348 fn as_keystore_item(&self) -> Result<KeystoreItem> {
349 Ok(CertData::TorEd25519Cert(self.clone()).into())
350 }
351}