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

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

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

            
21
use std::result::Result as StdResult;
22

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

            
26
impl<T> KeygenRng for T where T: RngCore + CryptoRng {}
27

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

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

            
45
/// A key that can be serialized to, and deserialized from.
46
//
47
// When adding a new `EncodableItem` impl, you must also update
48
// [`SshKeyData::into_erased`](crate::SshKeyData::into_erased) to
49
// return the corresponding concrete type implementing `EncodableItem`
50
// (as a `dyn EncodableItem`).
51
pub trait EncodableItem: ItemType + Downcast {
52
    /// Return the key as a [`KeystoreItem`].
53
    fn as_keystore_item(&self) -> Result<KeystoreItem>;
54
}
55
impl_downcast!(EncodableItem);
56

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

            
67
impl KeystoreItem {
68
    /// Return the [`KeystoreItemType`] of this item.
69
288
    pub fn item_type(&self) -> Result<KeystoreItemType> {
70
288
        match self {
71
288
            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
288
    }
75

            
76
    /// Convert the key/cert material into a known type,
77
    /// and return the type-erased value.
78
    ///
79
    /// The caller is expected to downcast the value returned to the correct concrete type.
80
96
    pub fn into_erased(self) -> Result<ErasedKey> {
81
96
        match self {
82
96
            KeystoreItem::Key(ssh_key_data) => ssh_key_data.into_erased(),
83
            KeystoreItem::Cert(cert_data) => cert_data.into_erased(),
84
        }
85
96
    }
86
}
87

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

            
110
    /// The KeyPair (secret+public) of which this key is a subset.  For secret
111
    /// keys, this type is Self.  For public keys, this type is the
112
    /// corresponding (secret) keypair.
113
    ///
114
    /// The associated type constraint (`where`) expresses the fact that a
115
    /// public key is always derivable from its corresponding secret key.
116
    ///
117
    type KeyPair: ToEncodableKey;
118

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

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

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

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

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

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

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

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

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

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

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

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

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

            
195
434
        Ok(curve25519::StaticKeypair { secret, public })
196
434
    }
197
}
198

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

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

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

            
219
434
        SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
220
434
    }
221
}
222

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

            
232
impl 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

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

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

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

            
269
2160
        SshKeyData::try_from_keypair_data(KeypairData::Ed25519(keypair)).map(KeystoreItem::from)
270
2160
    }
271
}
272

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

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

            
286
384
        SshKeyData::try_from_key_data(ssh_key::public::KeyData::Ed25519(key_data))
287
384
            .map(KeystoreItem::from)
288
384
    }
289
}
290

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

            
298
32
        Ok((&keypair).into())
299
32
    }
300
}
301

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

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

            
316
352
        let ssh_public = OpaquePublicKey::new(
317
352
            self.public().to_bytes().to_vec(),
318
352
            Algorithm::Other(algorithm_name),
319
352
        );
320
352

            
321
352
        let keypair = OpaqueKeypair::new(self.to_secret_key_bytes().to_vec(), ssh_public);
322
352

            
323
352
        SshKeyData::try_from_keypair_data(KeypairData::Other(keypair)).map(KeystoreItem::from)
324
352
    }
325
}
326

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

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

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