1
//! All the traits of this crate.
2

            
3
use downcast_rs::{Downcast, impl_downcast};
4
use rand::{CryptoRng, RngCore};
5
use ssh_key::{
6
    Algorithm, AlgorithmName,
7
    private::{Ed25519Keypair, Ed25519PrivateKey, KeypairData, OpaqueKeypair},
8
    public::{Ed25519PublicKey, KeyData, OpaquePublicKey},
9
};
10
use tor_error::internal;
11
use tor_llcrypto::{
12
    pk::{curve25519, ed25519, rsa},
13
    rng::EntropicRng,
14
};
15

            
16
use crate::certs::CertData;
17
use crate::key_type::CertType;
18
use crate::{
19
    KeyType, KeystoreItemType, Result,
20
    ssh::{ED25519_EXPANDED_ALGORITHM_NAME, SshKeyData, X25519_ALGORITHM_NAME},
21
};
22

            
23
use std::result::Result as StdResult;
24

            
25
/// A random number generator for generating [`EncodableItem`]s.
26
pub trait KeygenRng: RngCore + CryptoRng + EntropicRng {}
27

            
28
impl<T> KeygenRng for T where T: RngCore + CryptoRng + EntropicRng {}
29

            
30
/// A trait for generating fresh keys.
31
pub trait Keygen {
32
    /// Generate a new key of this type.
33
    fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
34
    where
35
        Self: Sized;
36
}
37

            
38
/// A trait for getting the type of an item.
39
pub trait ItemType: Downcast {
40
    /// The type of the key.
41
    fn item_type() -> KeystoreItemType
42
    where
43
        Self: Sized;
44
}
45
impl_downcast!(ItemType);
46

            
47
/// 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`).
53
pub trait EncodableItem: ItemType + Downcast {
54
    /// Return the key as a [`KeystoreItem`].
55
    fn as_keystore_item(&self) -> Result<KeystoreItem>;
56
}
57
impl_downcast!(EncodableItem);
58

            
59
/// A public key, keypair, or key certificate.
60
#[derive(Debug, Clone, derive_more::From)]
61
#[non_exhaustive]
62
pub enum KeystoreItem {
63
    /// A public key or a keypair.
64
    Key(SshKeyData),
65
    /// A certificate.
66
    Cert(CertData),
67
}
68

            
69
impl KeystoreItem {
70
    /// Return the [`KeystoreItemType`] of this item.
71
15370
    pub fn item_type(&self) -> Result<KeystoreItemType> {
72
15370
        match self {
73
13282
            KeystoreItem::Key(ssh_key_data) => ssh_key_data.key_type().map(KeystoreItemType::Key),
74
2088
            KeystoreItem::Cert(cert) => Ok(KeystoreItemType::Cert(cert.cert_type())),
75
        }
76
15370
    }
77
}
78

            
79
/// A key that can be converted to an [`EncodableItem`].
80
//
81
// NOTE: Conceptually, the `ToEncodableKey` and `EncodableItem` traits serve the same purpose (they
82
// provide information about how to encode/decode a key).
83
//
84
// The reason we have two traits instead of just one is because `EncodableItem` cannot have an
85
// associated type: for instance, if it did, we'd need to either give
86
// `tor-keymgr::Keystore::insert` a generic parameter (which would make `Keystore` object-unsafe),
87
// or specify a concrete type for the associated type of the `EncodableItem` (which would defeat the
88
// whole purpose of the trait, i.e. to enable users to store their own "encodable key" types).
89
//
90
// `ToEncodableKey` is used in the `KeyMgr` impl, where the associated type isn't an issue because
91
// the `KeyMgr` implementation is generic over `K: ToEncodableKey`. The `Keystore`s themselves only
92
// receive `&dyn EncodableItem`s.
93
//
94
pub trait ToEncodableKey: From<Self::KeyPair>
95
where
96
    Self::Key: From<<Self::KeyPair as ToEncodableKey>::Key>,
97
{
98
    /// The key type this can be converted to/from.
99
    type Key: EncodableItem + 'static;
100

            
101
    /// The KeyPair (secret+public) of which this key is a subset.  For secret
102
    /// keys, this type is Self.  For public keys, this type is the
103
    /// corresponding (secret) keypair.
104
    ///
105
    /// The associated type constraint (`where`) expresses the fact that a
106
    /// public key is always derivable from its corresponding secret key.
107
    ///
108
    type KeyPair: ToEncodableKey;
109

            
110
    /// Convert this key to a type that implements [`EncodableItem`].
111
    fn to_encodable_key(self) -> Self::Key;
112

            
113
    /// Convert an [`EncodableItem`] to another key type.
114
    fn from_encodable_key(key: Self::Key) -> Self;
115
}
116

            
117
/// A trait representing an encodable certificate.
118
///
119
/// `K` represents the (Rust) type of the subject key.
120
pub trait ToEncodableCert<K: ToEncodableKey>: Clone {
121
    /// The low-level type this can be converted from.
122
    type ParsedCert: ItemType + 'static;
123

            
124
    /// The low-level type this can be converted to.
125
    type EncodableCert: EncodableItem + 'static;
126

            
127
    /// The (Rust) type of the signing key.
128
    type SigningKey: ToEncodableKey;
129

            
130
    /// Validate this certificate.
131
    //
132
    // This function will be called from functions such as KeyMgr::get_key_and_cert()
133
    // to validate the cert using the provided subject key
134
    // (the concrete type of which is given by the `K` in KeyMgr::get_key_and_cert())
135
    // and ToEncodableCert::SigningKey.
136
    //
137
    /// This function should return an error if
138
    ///   * the certificate is not timely
139
    ///     (i.e. it is expired, or not yet valid), or
140
    ///   * the certificate is not well-signed, or
141
    ///   * the subject key or signing key in the certificate do not match
142
    ///     the subject and signing keys specified in `cert_spec`
143
    fn validate(
144
        cert: Self::ParsedCert,
145
        subject: &K,
146
        signed_with: &Self::SigningKey,
147
    ) -> StdResult<Self, InvalidCertError>;
148

            
149
    /// Convert this cert to a type that implements [`EncodableItem`].
150
    fn to_encodable_cert(self) -> Self::EncodableCert;
151
}
152

            
153
/// The error type returned by [`ToEncodableCert::validate`].
154
#[derive(thiserror::Error, Debug, Clone)]
155
#[non_exhaustive]
156
pub enum InvalidCertError {
157
    /// An error caused by a key certificate with an invalid signature.
158
    #[error("Invalid signature")]
159
    CertSignature(#[from] tor_cert::CertError),
160

            
161
    /// An error caused by an untimely key certificate.
162
    #[error("Certificate is expired or not yet valid")]
163
    TimeValidity(#[from] tor_checkable::TimeValidityError),
164

            
165
    /// A key certificate with an unexpected subject key algorithm.
166
    #[error("Unexpected subject key algorithm")]
167
    InvalidSubjectKeyAlgorithm,
168

            
169
    /// An error caused by a key certificate with an unexpected subject key.
170
    #[error("Certificate certifies the wrong key")]
171
    SubjectKeyMismatch,
172

            
173
    /// An error caused by a key certificate with an unexpected `CertType`.
174
    #[error("Unexpected cert type")]
175
    CertType(tor_cert::CertType),
176
}
177

            
178
impl Keygen for curve25519::StaticKeypair {
179
1800
    fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
180
1800
    where
181
1800
        Self: Sized,
182
    {
183
1800
        let secret = curve25519::StaticSecret::random_from_rng(rng);
184
1800
        let public = curve25519::PublicKey::from(&secret);
185

            
186
1800
        Ok(curve25519::StaticKeypair { secret, public })
187
1800
    }
188
}
189

            
190
impl ItemType for curve25519::StaticKeypair {
191
11700
    fn item_type() -> KeystoreItemType
192
11700
    where
193
11700
        Self: Sized,
194
    {
195
11700
        KeyType::X25519StaticKeypair.into()
196
11700
    }
197
}
198

            
199
impl EncodableItem for curve25519::StaticKeypair {
200
2150
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
201
2150
        let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
202
2150
            .map_err(|_| internal!("invalid algorithm name"))?;
203

            
204
2150
        let ssh_public = OpaquePublicKey::new(
205
2150
            self.public.to_bytes().to_vec(),
206
2150
            Algorithm::Other(algorithm_name),
207
        );
208
2150
        let keypair = OpaqueKeypair::new(self.secret.to_bytes().to_vec(), ssh_public);
209

            
210
2150
        SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
211
2150
    }
212
}
213

            
214
impl ItemType for curve25519::PublicKey {
215
    fn item_type() -> KeystoreItemType
216
    where
217
        Self: Sized,
218
    {
219
        KeyType::X25519PublicKey.into()
220
    }
221
}
222

            
223
impl EncodableItem for curve25519::PublicKey {
224
50
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
225
50
        let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
226
50
            .map_err(|_| internal!("invalid algorithm name"))?;
227

            
228
50
        let ssh_public =
229
50
            OpaquePublicKey::new(self.to_bytes().to_vec(), Algorithm::Other(algorithm_name));
230

            
231
50
        SshKeyData::try_from_key_data(KeyData::Other(ssh_public)).map(KeystoreItem::from)
232
50
    }
233
}
234

            
235
impl Keygen for ed25519::Keypair {
236
3150
    fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self>
237
3150
    where
238
3150
        Self: Sized,
239
    {
240
3150
        Ok(ed25519::Keypair::generate(&mut rng))
241
3150
    }
242
}
243

            
244
impl ItemType for ed25519::Keypair {
245
29300
    fn item_type() -> KeystoreItemType
246
29300
    where
247
29300
        Self: Sized,
248
    {
249
29300
        KeyType::Ed25519Keypair.into()
250
29300
    }
251
}
252

            
253
impl EncodableItem for ed25519::Keypair {
254
5500
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
255
5500
        let keypair = Ed25519Keypair {
256
5500
            public: Ed25519PublicKey(self.verifying_key().to_bytes()),
257
5500
            private: Ed25519PrivateKey::from_bytes(self.as_bytes()),
258
5500
        };
259

            
260
5500
        SshKeyData::try_from_keypair_data(KeypairData::Ed25519(keypair)).map(KeystoreItem::from)
261
5500
    }
262
}
263

            
264
impl ItemType for ed25519::PublicKey {
265
14500
    fn item_type() -> KeystoreItemType
266
14500
    where
267
14500
        Self: Sized,
268
    {
269
14500
        KeyType::Ed25519PublicKey.into()
270
14500
    }
271
}
272

            
273
impl EncodableItem for ed25519::PublicKey {
274
500
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
275
500
        let key_data = Ed25519PublicKey(self.to_bytes());
276

            
277
500
        SshKeyData::try_from_key_data(ssh_key::public::KeyData::Ed25519(key_data))
278
500
            .map(KeystoreItem::from)
279
500
    }
280
}
281

            
282
impl Keygen for ed25519::ExpandedKeypair {
283
50
    fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
284
50
    where
285
50
        Self: Sized,
286
    {
287
50
        let keypair = <ed25519::Keypair as Keygen>::generate(rng)?;
288

            
289
50
        Ok((&keypair).into())
290
50
    }
291
}
292

            
293
impl ItemType for ed25519::ExpandedKeypair {
294
51000
    fn item_type() -> KeystoreItemType
295
51000
    where
296
51000
        Self: Sized,
297
    {
298
51000
        KeyType::Ed25519ExpandedKeypair.into()
299
51000
    }
300
}
301

            
302
impl EncodableItem for ed25519::ExpandedKeypair {
303
750
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
304
750
        let algorithm_name = AlgorithmName::new(ED25519_EXPANDED_ALGORITHM_NAME)
305
750
            .map_err(|_| internal!("invalid algorithm name"))?;
306

            
307
750
        let ssh_public = OpaquePublicKey::new(
308
750
            self.public().to_bytes().to_vec(),
309
750
            Algorithm::Other(algorithm_name),
310
        );
311

            
312
750
        let keypair = OpaqueKeypair::new(self.to_secret_key_bytes().to_vec(), ssh_public);
313

            
314
750
        SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
315
750
    }
316
}
317

            
318
impl ItemType for crate::EncodedEd25519Cert {
319
    fn item_type() -> KeystoreItemType
320
    where
321
        Self: Sized,
322
    {
323
        CertType::Ed25519TorCert.into()
324
    }
325
}
326

            
327
impl ItemType for crate::ParsedEd25519Cert {
328
3016
    fn item_type() -> KeystoreItemType
329
3016
    where
330
3016
        Self: Sized,
331
    {
332
3016
        CertType::Ed25519TorCert.into()
333
3016
    }
334
}
335

            
336
impl EncodableItem for crate::EncodedEd25519Cert {
337
51
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
338
51
        Ok(CertData::TorEd25519Cert(self.clone()).into())
339
51
    }
340
}
341

            
342
impl Keygen for rsa::KeyPair {
343
588
    fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self>
344
588
    where
345
588
        Self: Sized,
346
    {
347
588
        Ok(rsa::KeyPair::generate(&mut rng)?)
348
588
    }
349
}
350

            
351
impl ItemType for rsa::KeyPair {
352
882
    fn item_type() -> KeystoreItemType
353
882
    where
354
882
        Self: Sized,
355
    {
356
882
        KeyType::RsaKeypair.into()
357
882
    }
358
}
359

            
360
impl EncodableItem for rsa::KeyPair {
361
588
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
362
588
        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
588
        SshKeyData::try_from_keypair_data(KeypairData::Rsa(keypair)).map(KeystoreItem::from)
367
588
    }
368
}
369

            
370
impl ItemType for rsa::PublicKey {
371
    fn item_type() -> KeystoreItemType
372
    where
373
        Self: Sized,
374
    {
375
        KeyType::RsaPublicKey.into()
376
    }
377
}
378

            
379
impl 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
}