1
//! Key rotation tasks of the relay.
2

            
3
use anyhow::Context;
4
use std::{
5
    sync::Arc,
6
    time::{Duration, SystemTime},
7
};
8
use tor_basic_utils::rand_hostname;
9
use tor_cert::x509::TlsKeyAndCert;
10
use tor_chanmgr::ChanMgr;
11
use tor_proto::RelayIdentities;
12

            
13
use tor_key_forge::ToEncodableCert;
14
use tor_keymgr::{
15
    KeyMgr, KeyPath, KeySpecifier, KeySpecifierPattern, Keygen, KeystoreSelector, ToEncodableKey,
16
};
17
use tor_relay_crypto::{
18
    gen_link_cert, gen_signing_cert, gen_tls_cert,
19
    pk::{
20
        RelayIdentityKeypair, RelayIdentityKeypairSpecifier, RelayIdentityRsaKeypair,
21
        RelayIdentityRsaKeypairSpecifier, RelayLinkSigningKeypair,
22
        RelayLinkSigningKeypairSpecifier, RelayLinkSigningKeypairSpecifierPattern,
23
        RelaySigningKeypair, RelaySigningKeypairSpecifier, RelaySigningKeypairSpecifierPattern,
24
        Timestamp,
25
    },
26
};
27
use tor_rtcompat::{Runtime, SleepProviderExt};
28

            
29
/// Buffer time before key expiry to trigger rotation. This ensures we rotate slightly before the
30
/// key actually expires rather than right at or after expiry.
31
///
32
/// C-tor uses 3 hours for the link/auth key and 1 day for the signing key. Let's use 3 hours here,
33
/// it should be plenty to make it happen even if hiccups happen.
34
const KEY_ROTATION_EXPIRE_BUFFER: Duration = Duration::from_secs(3 * 60 * 60);
35

            
36
/// Key lifefime duration of 2 days
37
const KEY_DURATION_2DAYS: Duration = Duration::from_secs(2 * 24 * 60 * 60);
38
/// Key lifefime duration of 30 days
39
const KEY_DURATION_30DAYS: Duration = Duration::from_secs(30 * 24 * 60 * 60);
40
/// Key lifefime duration of 6 months
41
const KEY_DURATION_6MONTHS: Duration = Duration::from_secs(6 * 30 * 24 * 60 * 60);
42

            
43
/// Trait to help us specify what we need for key rotation. This allows us to have the generic
44
/// function `rotate_key()`.
45
trait RotatableKeySpec {
46
    /// Key specifier type.
47
    type Specifier: KeySpecifier;
48
    /// Key specifier pattern (for the ArtiPath).
49
    type Pattern: KeySpecifierPattern;
50

            
51
    /// Build a new specifier.
52
    fn key_specifier() -> Self::Specifier;
53
    /// For logs.
54
    fn label() -> &'static str;
55
    /// Build a specifier from a [`KeyPath`]
56
    fn spec_from_keypath(keypath: &KeyPath) -> Result<Self::Specifier, tor_keymgr::KeyPathError>;
57
    /// The `valid_until` of the given key specifier.
58
    fn valid_until_from_spec(spec: &Self::Specifier) -> Timestamp;
59
}
60

            
61
impl RotatableKeySpec for RelaySigningKeypair {
62
    type Specifier = RelaySigningKeypairSpecifier;
63
    type Pattern = RelaySigningKeypairSpecifierPattern;
64

            
65
    fn key_specifier() -> Self::Specifier {
66
        let valid_until = Timestamp::from(SystemTime::now() + Duration::from_secs(30 * 86400));
67
        Self::Specifier::new(valid_until)
68
    }
69
    fn label() -> &'static str {
70
        "KP_relaysign_ed"
71
    }
72
    fn spec_from_keypath(keypath: &KeyPath) -> Result<Self::Specifier, tor_keymgr::KeyPathError> {
73
        keypath.try_into()
74
    }
75
    fn valid_until_from_spec(spec: &Self::Specifier) -> Timestamp {
76
        spec.valid_until()
77
    }
78
}
79

            
80
impl RotatableKeySpec for RelayLinkSigningKeypair {
81
    type Specifier = RelayLinkSigningKeypairSpecifier;
82
    type Pattern = RelayLinkSigningKeypairSpecifierPattern;
83

            
84
    fn key_specifier() -> Self::Specifier {
85
        let valid_until = Timestamp::from(SystemTime::now() + Duration::from_secs(2 * 86400));
86
        Self::Specifier::new(valid_until)
87
    }
88
    fn label() -> &'static str {
89
        "KP_link_ed"
90
    }
91
    fn spec_from_keypath(keypath: &KeyPath) -> Result<Self::Specifier, tor_keymgr::KeyPathError> {
92
        keypath.try_into()
93
    }
94
    fn valid_until_from_spec(spec: &Self::Specifier) -> Timestamp {
95
        spec.valid_until()
96
    }
97
}
98

            
99
/// Generate a key `K` directly into the key manager.
100
///
101
/// If the key already exists, the error is ignored as this could happen if the system time drifts
102
/// between the get and the generate.
103
fn generate_key<K>(keymgr: &KeyMgr, spec: &dyn KeySpecifier) -> Result<(), tor_keymgr::Error>
104
where
105
    K: ToEncodableKey,
106
    K::Key: Keygen,
107
{
108
    let mut rng = tor_llcrypto::rng::CautiousRng;
109

            
110
    match keymgr.generate::<K>(spec, KeystoreSelector::default(), &mut rng, false) {
111
        Ok(_) => {}
112
        // Key already existing can happen due to wall clock strangeness,
113
        // so simply ignore it.
114
        Err(tor_keymgr::Error::KeyAlreadyExists) => tracing::warn!(
115
            "Failed to generate key at {:?} because one already exists. Clock drift?",
116
            spec.arti_path(),
117
        ),
118
        Err(e) => return Err(e),
119
    };
120
    Ok(())
121
}
122

            
123
/// Rotate a key implementing the [`RotatableKeySpec`] trait.
124
///
125
/// Rotation is done by listing all keys matching the key specifier pattern and validating the
126
/// valid_until value of the key store entry. If expired, the key is removed from the key manager.
127
///
128
/// Returns a tuple of (rotated, valid_until) where `rotated` indicates if the key was rotated and
129
/// `valid_until` is the earliest expiry time across all keys of this type.
130
fn rotate_key<K>(keymgr: &KeyMgr) -> anyhow::Result<(bool, SystemTime)>
131
where
132
    K: RotatableKeySpec + ToEncodableKey,
133
    <K as ToEncodableKey>::Key: Keygen,
134
{
135
    // Select all signing keypair in the keystore because we need to inspect the valid_until
136
    // field and rotate if expired.
137
    let key_entries = keymgr.list_matching(&K::Pattern::new_any().arti_pattern()?)?;
138

            
139
    let key_specifier = K::key_specifier();
140

            
141
    if key_entries.is_empty() {
142
        generate_key::<K>(keymgr, &key_specifier)?;
143
        let valid_until = K::valid_until_from_spec(&key_specifier).into();
144
        return Ok((true, valid_until));
145
    }
146

            
147
    let mut have_rotated = false;
148
    // Smallest valid_until timestamp of all the keys we are about to look at. Start with the
149
    // biggest value so the first value will change this immediately.
150
    //
151
    // NOTE: This is dicy because if the loop below would not run, we would return a sleep time
152
    // that is massive. The is_empty() above guarantees it won't happen but still. Anyway, this is
153
    // better than an Option<> and dealing with a None at the end.
154
    let mut min_valid_until = None;
155

            
156
    for key in key_entries {
157
        let entry_key_spec: K::Specifier = K::spec_from_keypath(key.key_path())?;
158
        // Min the entry key valid_until.
159
        let entry_valid_until = K::valid_until_from_spec(&entry_key_spec);
160
        min_valid_until = Some(
161
            min_valid_until.map_or(entry_valid_until, |v: Timestamp| v.min(entry_valid_until)),
162
        );
163

            
164
        // Account for the buffer time so we rotate before the key actually expires.
165
        if K::valid_until_from_spec(&entry_key_spec)
166
            <= Timestamp::from(SystemTime::now() + KEY_ROTATION_EXPIRE_BUFFER)
167
        {
168
            tracing::info!(
169
                "Rotating {} key. Next expiry timestamp {:?}",
170
                K::label(),
171
                K::valid_until_from_spec(&key_specifier),
172
            );
173
            keymgr.remove_entry(&key)?;
174
            generate_key::<K>(keymgr, &key_specifier)?;
175
            have_rotated = true;
176
            // Min the new key valid_until.
177
            let new_valid_until = K::valid_until_from_spec(&key_specifier);
178
            min_valid_until =
179
                Some(min_valid_until.map_or(new_valid_until, |v| v.min(new_valid_until)));
180
        }
181
    }
182

            
183
    Ok((
184
        have_rotated,
185
        min_valid_until.expect("valid_until is empty").into(),
186
    ))
187
}
188

            
189
/// Attempt to rotate all rotatable keys.
190
///
191
/// Returns a tuple of (rotated, next_expiry) where `rotated` indicates if any key was rotated and
192
/// `next_expiry` is the earliest expiry time across all rotatable keys.
193
fn try_rotate_keys(keymgr: &KeyMgr) -> anyhow::Result<(bool, SystemTime)> {
194
    // Attempt to rotate the KP_relaysign_ed.
195
    let (mut have_rotated, sign_expiry) = rotate_key::<RelaySigningKeypair>(keymgr)?;
196
    // Attempt to rotate the KP_link_ed.
197
    let (link_rotated, link_expiry) = rotate_key::<RelayLinkSigningKeypair>(keymgr)?;
198
    have_rotated |= link_rotated;
199
    Ok((have_rotated, sign_expiry.min(link_expiry)))
200
}
201

            
202
/// Build a fresh [`RelayIdentities`] object using a [`KeyMgr`].
203
///
204
/// Every single certificate is generated in this function.
205
///
206
/// This function assumes that all required keys are in the keymgr.
207
fn build_proto_identities(keymgr: &KeyMgr) -> anyhow::Result<RelayIdentities> {
208
    let mut rng = tor_llcrypto::rng::CautiousRng;
209
    let now = SystemTime::now();
210

            
211
    // Get the identity keypairs.
212
    let rsa_id_kp: RelayIdentityRsaKeypair = keymgr
213
        .get(&RelayIdentityRsaKeypairSpecifier::new())
214
        .context("Failed to get RSA identity from key manager")?
215
        .context("Missing RSA identity")?;
216
    let ed_id_kp: RelayIdentityKeypair = keymgr
217
        .get(&RelayIdentityKeypairSpecifier::new())
218
        .context("Failed to get Ed25519 identity from key manager")?
219
        .context("Missing Ed25519 identity")?;
220
    // We have to list match here because the key specifier here uses a valid_until. We don't know
221
    // what it is so we list and take the first one.
222
    let link_sign_kp: RelayLinkSigningKeypair = keymgr
223
        .get_entry(
224
            keymgr
225
                .list_matching(&RelayLinkSigningKeypairSpecifierPattern::new_any().arti_pattern()?)?
226
                .first()
227
                .context("No store entry for link authentication key")?,
228
        )
229
        .context("Failed to get link authentication key from key manager")?
230
        .context("Missing link authentication key")?;
231
    let kp_relaysign_id: RelaySigningKeypair = keymgr
232
        .get_entry(
233
            keymgr
234
                .list_matching(&RelaySigningKeypairSpecifierPattern::new_any().arti_pattern()?)?
235
                .first()
236
                .context("No store entry for signing key")?,
237
        )
238
        .context("Failed to get signing key from key manager")?
239
        .context("Missing signing key")?;
240

            
241
    // TLS key and cert. Random hostname like C-tor. We re-use the issuer_hostname for the RSA
242
    // legacy cert.
243
    let issuer_hostname = rand_hostname::random_hostname(&mut rng);
244
    let subject_hostname = rand_hostname::random_hostname(&mut rng);
245
    let tls_key_and_cert =
246
        TlsKeyAndCert::create(&mut rng, now, &issuer_hostname, &subject_hostname)
247
            .context("Failed to create TLS keys and certificates")?;
248

            
249
    // Create the RSA X509 certificate.
250
    let cert_id_x509_rsa = tor_cert::x509::create_legacy_rsa_id_cert(
251
        &mut rng,
252
        SystemTime::now(),
253
        &issuer_hostname,
254
        rsa_id_kp.keypair(),
255
    )
256
    .context("Failed to create legacy RSA identity certificate")?;
257

            
258
    // The following expiry duration have been taken from C-tor.
259

            
260
    let cert_id_rsa = tor_cert::rsa::EncodedRsaCrosscert::encode_and_sign(
261
        rsa_id_kp.keypair(),
262
        &ed_id_kp.to_ed25519_id(),
263
        now + KEY_DURATION_6MONTHS,
264
    )?;
265

            
266
    // Create the signing key cert, link cert and tls cert.
267
    //
268
    // TODO(relay): We need to check the KeyMgr for the signing cert but for now the KeyMgr API
269
    // doesn't allow us to get it out. We will do a re-design of the cert API there. This is fine
270
    // as long as we don't support offline keys.
271
    let cert_id_sign_ed = gen_signing_cert(&ed_id_kp, &kp_relaysign_id, now + KEY_DURATION_30DAYS)?;
272
    let cert_sign_link_auth_ed =
273
        gen_link_cert(&kp_relaysign_id, &link_sign_kp, now + KEY_DURATION_2DAYS)?;
274
    let cert_sign_tls_ed = gen_tls_cert(
275
        &kp_relaysign_id,
276
        *tls_key_and_cert.link_cert_sha256(),
277
        now + KEY_DURATION_2DAYS,
278
    )?;
279

            
280
    Ok(RelayIdentities::new(
281
        &rsa_id_kp.public().into(),
282
        ed_id_kp.to_ed25519_id(),
283
        link_sign_kp,
284
        cert_id_sign_ed.to_encodable_cert(),
285
        cert_sign_tls_ed,
286
        cert_sign_link_auth_ed.to_encodable_cert(),
287
        cert_id_x509_rsa,
288
        cert_id_rsa,
289
        tls_key_and_cert,
290
    ))
291
}
292

            
293
/// Attempt to generate all keys. The list of keys is:
294
///
295
/// * Identity Ed25519 keypair [`RelayIdentityKeypair`].
296
/// * Identity RSA [`RelayIdentityRsaKeypair`].
297
/// * Relay signing keypair [`RelaySigningKeypair`].
298
/// * Relay link signing keypair [`RelayLinkSigningKeypair`].
299
///
300
/// This function is only called when our relay bootstraps in order to attempt to generate any
301
/// missing keys or/and rotate expired keys.
302
pub(crate) fn try_generate_keys(keymgr: &KeyMgr) -> anyhow::Result<RelayIdentities> {
303
    // Note that generate_key() won't error if the key already exists.
304

            
305
    // Attempt to generate our identity keys (ed and RSA). Those keys DO NOT rotate.
306
    generate_key::<RelayIdentityKeypair>(keymgr, &RelayIdentityKeypairSpecifier::new())?;
307
    generate_key::<RelayIdentityRsaKeypair>(keymgr, &RelayIdentityRsaKeypairSpecifier::new())?;
308
    // Attempt to rotate the rotatable keys which will generate any missing.
309
    let _expiry = try_rotate_keys(keymgr)?;
310

            
311
    // Now that we have our up-to-date keys, build the RelayIdentities object.
312
    build_proto_identities(keymgr)
313
}
314

            
315
/// Task to rotate keys when they need to be rotated.
316
pub(crate) async fn rotate_keys_task<R: Runtime>(
317
    runtime: R,
318
    keymgr: Arc<KeyMgr>,
319
    chanmgr: Arc<ChanMgr<R>>,
320
) -> anyhow::Result<void::Void> {
321
    loop {
322
        // Attempt a rotation of all keys.
323
        let (have_rotated, next_expiry) = try_rotate_keys(&keymgr)?;
324
        if have_rotated {
325
            let ids = build_proto_identities(&keymgr)?;
326
            chanmgr
327
                .set_relay_identities(Arc::new(ids))
328
                .context("Failed to set relay identities on ChanMgr")?;
329
        }
330

            
331
        // Sleep until the earliest key expiry minus buffer so we rotate before it expires.
332
        // If the subtraction would underflow, wake up immediately to rotate the expired key.
333
        let next_wake = next_expiry
334
            .checked_sub(KEY_ROTATION_EXPIRE_BUFFER)
335
            .unwrap_or(SystemTime::now());
336
        runtime.sleep_until_wallclock(next_wake).await;
337
    }
338
}