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

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

            
16
use crate::certs::CertData;
17
use crate::key_type::CertType;
18
use crate::{
19
    ssh::{SshKeyData, ED25519_EXPANDED_ALGORITHM_NAME, X25519_ALGORITHM_NAME},
20
    ErasedKey, KeyType, KeystoreItemType, Result,
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
3816
    pub fn item_type(&self) -> Result<KeystoreItemType> {
72
3816
        match self {
73
3657
            KeystoreItem::Key(ssh_key_data) => ssh_key_data.key_type().map(KeystoreItemType::Key),
74
159
            KeystoreItem::Cert(cert) => Ok(KeystoreItemType::Cert(cert.cert_type())),
75
        }
76
3816
    }
77

            
78
    /// 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.
82
106
    pub fn into_erased(self) -> Result<ErasedKey> {
83
106
        match self {
84
106
            KeystoreItem::Key(ssh_key_data) => ssh_key_data.into_erased(),
85
            KeystoreItem::Cert(cert_data) => cert_data.into_erased(),
86
        }
87
106
    }
88
}
89

            
90
/// 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
//
105
pub trait ToEncodableKey: From<Self::KeyPair>
106
where
107
    Self::Key: From<<Self::KeyPair as ToEncodableKey>::Key>,
108
{
109
    /// The key type this can be converted to/from.
110
    type Key: EncodableItem + 'static;
111

            
112
    /// 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
    ///
119
    type KeyPair: ToEncodableKey;
120

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

            
124
    /// Convert an [`EncodableItem`] to another key type.
125
    fn from_encodable_key(key: Self::Key) -> Self;
126
}
127

            
128
/// A trait representing an encodable certificate.
129
///
130
/// `K` represents the (Rust) type of the subject key.
131
pub trait ToEncodableCert<K: ToEncodableKey>: Clone {
132
    /// The low-level type this can be converted from.
133
    type ParsedCert: ItemType + 'static;
134

            
135
    /// The low-level type this can be converted to.
136
    type EncodableCert: EncodableItem + 'static;
137

            
138
    /// The (Rust) type of the signing key.
139
    type SigningKey: ToEncodableKey;
140

            
141
    /// 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`
154
    fn validate(
155
        cert: Self::ParsedCert,
156
        subject: &K,
157
        signed_with: &Self::SigningKey,
158
    ) -> StdResult<Self, InvalidCertError>;
159

            
160
    /// Convert this cert to a type that implements [`EncodableItem`].
161
    fn to_encodable_cert(self) -> Self::EncodableCert;
162
}
163

            
164
/// The error type returned by [`ToEncodableCert::validate`].
165
#[derive(thiserror::Error, Debug, Clone)]
166
#[non_exhaustive]
167
pub enum InvalidCertError {
168
    /// An error caused by a key certificate with an invalid signature.
169
    #[error("Invalid signature")]
170
    CertSignature(#[from] tor_cert::CertError),
171

            
172
    /// An error caused by an untimely key certificate.
173
    #[error("Certificate is expired or not yet valid")]
174
    TimeValidity(#[from] tor_checkable::TimeValidityError),
175

            
176
    /// A key certificate with an unexpected subject key algorithm.
177
    #[error("Unexpected subject key algorithm")]
178
    InvalidSubjectKeyAlgorithm,
179

            
180
    /// An error caused by a key certificate with an unexpected subject key.
181
    #[error("Certificate certifies the wrong key")]
182
    SubjectKeyMismatch,
183

            
184
    /// An error caused by a key certificate with an unexpected `CertType`.
185
    #[error("Unexpected cert type")]
186
    CertType(tor_cert::CertType),
187
}
188

            
189
impl Keygen for curve25519::StaticKeypair {
190
740
    fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
191
740
    where
192
740
        Self: Sized,
193
740
    {
194
740
        let secret = curve25519::StaticSecret::random_from_rng(rng);
195
740
        let public = curve25519::PublicKey::from(&secret);
196
740

            
197
740
        Ok(curve25519::StaticKeypair { secret, public })
198
740
    }
199
}
200

            
201
impl ItemType for curve25519::StaticKeypair {
202
3404
    fn item_type() -> KeystoreItemType
203
3404
    where
204
3404
        Self: Sized,
205
3404
    {
206
3404
        KeyType::X25519StaticKeypair.into()
207
3404
    }
208
}
209

            
210
impl EncodableItem for curve25519::StaticKeypair {
211
777
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
212
777
        let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
213
777
            .map_err(|_| internal!("invalid algorithm name"))?;
214

            
215
777
        let ssh_public = OpaquePublicKey::new(
216
777
            self.public.to_bytes().to_vec(),
217
777
            Algorithm::Other(algorithm_name),
218
777
        );
219
777
        let keypair = OpaqueKeypair::new(self.secret.to_bytes().to_vec(), ssh_public);
220
777

            
221
777
        SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
222
777
    }
223
}
224

            
225
impl ItemType for curve25519::PublicKey {
226
    fn item_type() -> KeystoreItemType
227
    where
228
        Self: Sized,
229
    {
230
        KeyType::X25519PublicKey.into()
231
    }
232
}
233

            
234
impl EncodableItem for curve25519::PublicKey {
235
37
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
236
37
        let algorithm_name = AlgorithmName::new(X25519_ALGORITHM_NAME)
237
37
            .map_err(|_| internal!("invalid algorithm name"))?;
238

            
239
37
        let ssh_public =
240
37
            OpaquePublicKey::new(self.to_bytes().to_vec(), Algorithm::Other(algorithm_name));
241
37

            
242
37
        SshKeyData::try_from_key_data(KeyData::Other(ssh_public)).map(KeystoreItem::from)
243
37
    }
244
}
245

            
246
impl Keygen for ed25519::Keypair {
247
795
    fn generate(mut rng: &mut dyn KeygenRng) -> Result<Self>
248
795
    where
249
795
        Self: Sized,
250
795
    {
251
795
        Ok(ed25519::Keypair::generate(&mut rng))
252
795
    }
253
}
254

            
255
impl ItemType for ed25519::Keypair {
256
3922
    fn item_type() -> KeystoreItemType
257
3922
    where
258
3922
        Self: Sized,
259
3922
    {
260
3922
        KeyType::Ed25519Keypair.into()
261
3922
    }
262
}
263

            
264
impl EncodableItem for ed25519::Keypair {
265
2385
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
266
2385
        let keypair = Ed25519Keypair {
267
2385
            public: Ed25519PublicKey(self.verifying_key().to_bytes()),
268
2385
            private: Ed25519PrivateKey::from_bytes(self.as_bytes()),
269
2385
        };
270
2385

            
271
2385
        SshKeyData::try_from_keypair_data(KeypairData::Ed25519(keypair)).map(KeystoreItem::from)
272
2385
    }
273
}
274

            
275
impl ItemType for ed25519::PublicKey {
276
954
    fn item_type() -> KeystoreItemType
277
954
    where
278
954
        Self: Sized,
279
954
    {
280
954
        KeyType::Ed25519PublicKey.into()
281
954
    }
282
}
283

            
284
impl EncodableItem for ed25519::PublicKey {
285
106
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
286
106
        let key_data = Ed25519PublicKey(self.to_bytes());
287
106

            
288
106
        SshKeyData::try_from_key_data(ssh_key::public::KeyData::Ed25519(key_data))
289
106
            .map(KeystoreItem::from)
290
106
    }
291
}
292

            
293
impl Keygen for ed25519::ExpandedKeypair {
294
53
    fn generate(rng: &mut dyn KeygenRng) -> Result<Self>
295
53
    where
296
53
        Self: Sized,
297
53
    {
298
53
        let keypair = <ed25519::Keypair as Keygen>::generate(rng)?;
299

            
300
53
        Ok((&keypair).into())
301
53
    }
302
}
303

            
304
impl ItemType for ed25519::ExpandedKeypair {
305
1961
    fn item_type() -> KeystoreItemType
306
1961
    where
307
1961
        Self: Sized,
308
1961
    {
309
1961
        KeyType::Ed25519ExpandedKeypair.into()
310
1961
    }
311
}
312

            
313
impl EncodableItem for ed25519::ExpandedKeypair {
314
212
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
315
212
        let algorithm_name = AlgorithmName::new(ED25519_EXPANDED_ALGORITHM_NAME)
316
212
            .map_err(|_| internal!("invalid algorithm name"))?;
317

            
318
212
        let ssh_public = OpaquePublicKey::new(
319
212
            self.public().to_bytes().to_vec(),
320
212
            Algorithm::Other(algorithm_name),
321
212
        );
322
212

            
323
212
        let keypair = OpaqueKeypair::new(self.to_secret_key_bytes().to_vec(), ssh_public);
324
212

            
325
212
        SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
326
212
    }
327
}
328

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

            
338
impl ItemType for crate::ParsedEd25519Cert {
339
    fn item_type() -> KeystoreItemType
340
    where
341
        Self: Sized,
342
    {
343
        CertType::Ed25519TorCert.into()
344
    }
345
}
346

            
347
impl EncodableItem for crate::EncodedEd25519Cert {
348
2
    fn as_keystore_item(&self) -> Result<KeystoreItem> {
349
2
        Ok(CertData::TorEd25519Cert(self.clone()).into())
350
2
    }
351
}