1
//! Code for generating x509 certificates.
2
//!
3
//! For the most part, Tor doesn't actually need x509 certificates.
4
//! We only keep them around for two purposes:
5
//!
6
//! 1. The `RSA_ID_X509` certificate is provided in a CERTS cell,
7
//!    and used to transmit the RSA identity key.
8
//! 2. TLS requires the responder to have an x509 certificate.
9

            
10
// This module uses the `x509-cert` crate to generate certificates;
11
// if we decide to switch, `rcgen` and `x509-certificate`
12
// seem like the likeliest options.
13

            
14
use std::{
15
    sync::Arc,
16
    time::{Duration, SystemTime},
17
};
18

            
19
use digest::Digest;
20
use rand::CryptoRng;
21
use rsa::pkcs8::{EncodePrivateKey as _, SubjectPublicKeyInfo};
22
use tor_error::into_internal;
23
use tor_llcrypto::{pk::rsa::KeyPair as RsaKeypair, util::rng::RngCompat};
24
use x509_cert::{
25
    builder::{Builder, CertificateBuilder, Profile},
26
    der::{DateTime, Encode, asn1::GeneralizedTime, zeroize::Zeroizing},
27
    ext::pkix::{KeyUsage, KeyUsages},
28
    serial_number::SerialNumber,
29
    time::Validity,
30
};
31

            
32
/// Legacy identity keys are required to have this length.
33
const EXPECT_ID_BITS: usize = 1024;
34
/// Legacy identity keys are required to have this exponent.
35
const EXPECT_ID_EXPONENT: u32 = 65537;
36
/// Lifetime of generated id certs, in days.
37
const ID_CERT_LIFETIME_DAYS: u32 = 365;
38

            
39
/// Create an X.509 certificate, for use in a CERTS cell,
40
/// self-certifying the provided RSA identity key.
41
///
42
/// The resulting certificate will be encoded in DER.
43
/// Its cert_type field should be 02 when it is sent in a CERTS cell.
44
///
45
/// The resulting certificate is quite minimal, and has no unnecessary extensions.
46
///
47
/// Returns an error on failure, or if `keypair` is not a 1024-bit RSA key
48
/// with exponent of 65537.
49
2
pub fn create_legacy_rsa_id_cert<Rng: CryptoRng>(
50
2
    rng: &mut Rng,
51
2
    now: SystemTime,
52
2
    hostname: &str,
53
2
    keypair: &RsaKeypair,
54
2
) -> Result<Vec<u8>, X509CertError> {
55
    use rsa::pkcs1v15::SigningKey;
56
    use tor_llcrypto::d::Sha256;
57
2
    let public = keypair.to_public_key();
58
2
    if !public.exponent_is(EXPECT_ID_EXPONENT) {
59
        return Err(X509CertError::InvalidSigningKey("Invalid exponent".into()));
60
2
    }
61
2
    if !public.bits() == EXPECT_ID_BITS {
62
        return Err(X509CertError::InvalidSigningKey(
63
            "Invalid key length".into(),
64
        ));
65
2
    }
66

            
67
2
    let self_signed_profile = Profile::Manual { issuer: None };
68
2
    let serial_number = random_serial_number(rng)?;
69
2
    let (validity, _) = cert_validity(now, ID_CERT_LIFETIME_DAYS)?;
70
    // NOTE: This is how C Tor builds its DNs, but that doesn't mean it's a good idea.
71
2
    let subject: x509_cert::name::Name = format!("CN={hostname}")
72
2
        .parse()
73
2
        .map_err(X509CertError::InvalidHostname)?;
74
2
    let spki = SubjectPublicKeyInfo::from_key(keypair.to_public_key().as_key().clone())?;
75

            
76
2
    let signer = SigningKey::<Sha256>::new(keypair.as_key().clone());
77

            
78
2
    let mut builder = CertificateBuilder::new(
79
2
        self_signed_profile,
80
2
        serial_number,
81
2
        validity,
82
2
        subject,
83
2
        spki,
84
2
        &signer,
85
    )?;
86

            
87
    // We do not, strictly speaking, need this extension: Tor doesn't care that it's there.
88
    // We do, however, need _some_ extension, or else we'll generate a v1 certificate,
89
    // which we don't want to do.
90
2
    builder.add_extension(&KeyUsage(
91
2
        KeyUsages::KeyCertSign | KeyUsages::DigitalSignature,
92
2
    ))?;
93

            
94
2
    let cert = builder.build()?;
95

            
96
2
    let mut output = Vec::new();
97
2
    let _ignore_length: x509_cert::der::Length = cert
98
2
        .encode_to_vec(&mut output)
99
2
        .map_err(X509CertError::CouldNotEncode)?;
100
2
    Ok(output)
101
2
}
102

            
103
/// A set of x.509 certificate information and keys for use with a TLS library.
104
///
105
/// Only relays need this: They should set these as the certificate(s) to be used
106
/// for incoming TLS connections.
107
///
108
/// This is not necessarily the most convenient form to manipulate certificates in:
109
/// rather, it is intended to provide the formats that TLS libraries generally
110
/// expect to get.
111
#[derive(Clone, Debug)]
112
#[non_exhaustive]
113
pub struct TlsKeyAndCert {
114
    /// A list of certificates in DER form.
115
    ///
116
    /// (This may contain more than one certificate, but for now only one certificate is used.)
117
    certificates: Vec<Vec<u8>>,
118

            
119
    /// A private key for use in the TLS handshake.
120
    private_key: ecdsa::SigningKey<p256::NistP256>,
121

            
122
    /// A SHA256 digest of the link certificate
123
    /// (the one certifying the private key's public component).
124
    ///
125
    /// This digest is the one what will be certified by the relay's
126
    /// [`SIGNING_V_TLS_CERT`](crate::CertType::SIGNING_V_TLS_CERT)
127
    /// certificate.
128
    sha256_digest: [u8; 32],
129

            
130
    /// A time after which this set of link information won't be valid,
131
    /// and another should be generated.
132
    expiration: SystemTime,
133
}
134

            
135
/// What lifetime do we pick for a TLS certificate, in days?
136
const TLS_CERT_LIFETIME_DAYS: u32 = 30;
137

            
138
impl TlsKeyAndCert {
139
    /// Return the certificates as a list of DER-encoded values.
140
    pub fn certificates_der(&self) -> Vec<&[u8]> {
141
        self.certificates.iter().map(|der| der.as_ref()).collect()
142
    }
143
    /// Return the certificates as a concatenated list in PEM ("BEGIN CERTIFICATE") format.
144
    pub fn certificate_pem(&self) -> String {
145
        let config = pem::EncodeConfig::new().set_line_ending(pem::LineEnding::LF);
146
        self.certificates
147
            .iter()
148
            .map(|der| pem::encode_config(&pem::Pem::new("CERTIFICATE", &der[..]), config))
149
            .collect()
150
    }
151
    /// Return the private key in (unencrypted) PKCS8 DER format.
152
    pub fn private_key_pkcs8_der(&self) -> Result<Zeroizing<Vec<u8>>, X509CertError> {
153
        Ok(self
154
            .private_key
155
            .to_pkcs8_der()
156
            .map_err(X509CertError::CouldNotFormatPkcs8)?
157
            .to_bytes())
158
    }
159
    /// Return the private key in (unencrypted) PKCS8 PEM ("BEGIN PRIVATE KEY") format.
160
    pub fn private_key_pkcs8_pem(&self) -> Result<Zeroizing<String>, X509CertError> {
161
        self.private_key
162
            .to_pkcs8_pem(p256::pkcs8::LineEnding::LF)
163
            .map_err(X509CertError::CouldNotFormatPkcs8)
164
    }
165
    /// Return the earliest time at which any of these certificates will expire.
166
    pub fn expiration(&self) -> SystemTime {
167
        self.expiration
168
    }
169

            
170
    /// Return the SHA256 digest of the link certificate
171
    ///
172
    /// This digest is the one certified with the relay's
173
    /// [`SIGNING_V_TLS_CERT`](crate::CertType::SIGNING_V_TLS_CERT)
174
    /// certificate.
175
    pub fn link_cert_sha256(&self) -> &[u8; 32] {
176
        &self.sha256_digest
177
    }
178

            
179
    /// Create a new TLS link key and associated certificate(s).
180
    ///
181
    /// The certificate will be valid at `now`, and for a while after.
182
    ///
183
    /// The certificate parameters and keys are chosen for reasonable security,
184
    /// approximate conformance to RFC5280, and limited fingerprinting resistance.
185
    ///
186
    /// Note: The fingerprinting resistance is quite limited.
187
    /// We will likely want to pursue these avenues for better fingerprinting resistance:
188
    ///
189
    /// - Encourage more use of TLS 1.3, where server certificates are encrypted.
190
    ///   (This prevents passive fingerprinting only.)
191
    /// - Adjust this function to make certificates look even more normal
192
    /// - Integrate with ACME-supporting certificate issuers (Letsencrypt, etc)
193
    ///   to get real certificates for Tor relays.
194
2
    pub fn create<Rng: CryptoRng>(
195
2
        rng: &mut Rng,
196
2
        now: SystemTime,
197
2
        issuer_hostname: &str,
198
2
        subject_hostname: &str,
199
2
    ) -> Result<Self, X509CertError> {
200
        // We choose to use p256 here as the most commonly used elliptic curve
201
        // group for X.509 web certificate signing, as of this writing.
202
        //
203
        // We want to use an elliptic curve here for its higher security/performance ratio than RSA,
204
        // and for its _much_ faster key generation time.
205
2
        let private_key = p256::ecdsa::SigningKey::random(&mut RngCompat::new(&mut *rng));
206
2
        let public_key = p256::ecdsa::VerifyingKey::from(&private_key);
207

            
208
        // Note that we'll discard this key after signing the certificate with it:
209
        // The real certification for private_key is done in the SIGNING_V_TLS_CERT
210
        // certificate.
211
2
        let issuer_private_key = p256::ecdsa::SigningKey::random(&mut RngCompat::new(&mut *rng));
212

            
213
        // NOTE: This is how C Tor builds its DNs, but that doesn't mean it's a good idea.
214
2
        let issuer = format!("CN={issuer_hostname}")
215
2
            .parse()
216
2
            .map_err(X509CertError::InvalidHostname)?;
217
2
        let subject: x509_cert::name::Name = format!("CN={subject_hostname}")
218
2
            .parse()
219
2
            .map_err(X509CertError::InvalidHostname)?;
220

            
221
2
        let self_signed_profile = Profile::Leaf {
222
2
            issuer,
223
2
            enable_key_agreement: true,
224
2
            enable_key_encipherment: true,
225
2
            include_subject_key_identifier: true,
226
2
        };
227
2
        let serial_number = random_serial_number(rng)?;
228
2
        let (validity, expiration) = cert_validity(now, TLS_CERT_LIFETIME_DAYS)?;
229
2
        let spki = SubjectPublicKeyInfo::from_key(public_key)?;
230

            
231
2
        let builder = CertificateBuilder::new(
232
2
            self_signed_profile,
233
2
            serial_number,
234
2
            validity,
235
2
            subject,
236
2
            spki,
237
2
            &issuer_private_key,
238
        )?;
239

            
240
2
        let cert = builder.build::<ecdsa::der::Signature<_>>()?;
241

            
242
2
        let mut certificate_der = Vec::new();
243
2
        let _ignore_length: x509_cert::der::Length = cert
244
2
            .encode_to_vec(&mut certificate_der)
245
2
            .map_err(X509CertError::CouldNotEncode)?;
246

            
247
2
        let sha256_digest = tor_llcrypto::d::Sha256::digest(&certificate_der).into();
248
2
        let certificates = vec![certificate_der];
249

            
250
2
        Ok(TlsKeyAndCert {
251
2
            certificates,
252
2
            private_key,
253
2
            sha256_digest,
254
2
            expiration,
255
2
        })
256
2
    }
257
}
258

            
259
/// Return a Validity that includes `now`, and lasts for `lifetime_days` additionally.
260
///
261
/// Additionally, return the time at which the certificate expires.
262
///
263
/// We ensure that our cert is valid at least a day into the past.
264
///
265
/// We obfuscate our current time a little by rounding to the nearest midnight UTC.
266
4
fn cert_validity(
267
4
    now: SystemTime,
268
4
    lifetime_days: u32,
269
4
) -> Result<(Validity, SystemTime), X509CertError> {
270
    const ONE_DAY: Duration = Duration::new(86400, 0);
271

            
272
10
    let start_of_day_containing = |when| -> Result<_, X509CertError> {
273
8
        let dt = DateTime::from_system_time(when)
274
8
            .map_err(into_internal!("Couldn't represent time as a DER DateTime"))?;
275
8
        let dt = DateTime::new(dt.year(), dt.month(), dt.day(), 0, 0, 0)
276
8
            .map_err(into_internal!("Couldn't construct DER DateTime"))?;
277
8
        Ok(x509_cert::time::Time::GeneralTime(
278
8
            GeneralizedTime::from_date_time(dt),
279
8
        ))
280
8
    };
281

            
282
4
    let start_on_day = now - ONE_DAY;
283
4
    let end_on_day = start_on_day + ONE_DAY * lifetime_days;
284

            
285
4
    let validity = Validity {
286
4
        not_before: start_of_day_containing(start_on_day)?,
287
4
        not_after: start_of_day_containing(end_on_day)?,
288
    };
289
4
    let expiration = validity.not_after.into();
290
4
    Ok((validity, expiration))
291
4
}
292

            
293
/// Return a random serial number for use in a new certificate.
294
4
fn random_serial_number<Rng: CryptoRng>(rng: &mut Rng) -> Result<SerialNumber, X509CertError> {
295
    const SER_NUMBER_LEN: usize = 16;
296
4
    let mut buf = [0; SER_NUMBER_LEN];
297
4
    rng.fill_bytes(&mut buf[..]);
298
4
    Ok(SerialNumber::new(&buf[..]).map_err(into_internal!("Couldn't construct serial number!"))?)
299
4
}
300

            
301
/// An error that has occurred while trying to create a certificate.
302
#[derive(Clone, Debug, thiserror::Error)]
303
#[non_exhaustive]
304
pub enum X509CertError {
305
    /// We received a signing key that we can't use.
306
    #[error("Provided signing key not valid: {0}")]
307
    InvalidSigningKey(String),
308

            
309
    /// We received a subject key that we can't use.
310
    #[error("Couldn't use provided key as a subject")]
311
    SubjectKeyError(#[from] x509_cert::spki::Error),
312

            
313
    /// We received a hostname that we couldn't use:
314
    /// probably, it contained an equals sign or a comma.
315
    #[error("Unable to set hostname when creating certificate")]
316
    InvalidHostname(#[source] x509_cert::der::Error),
317

            
318
    /// We couldn't construct the certificate.
319
    #[error("Unable to build certificate")]
320
    CouldNotBuild(#[source] Arc<x509_cert::builder::Error>),
321

            
322
    /// We constructed the certificate, but couldn't encode it as DER.
323
    #[error("Unable to encode certificate")]
324
    CouldNotEncode(#[source] x509_cert::der::Error),
325

            
326
    /// We constructed a key but couldn't format it as PKCS8.
327
    #[error("Unable to format key as PKCS8")]
328
    CouldNotFormatPkcs8(#[source] p256::pkcs8::Error),
329

            
330
    /// We've encountered some kind of a bug.
331
    #[error("Internal error while creating certificate")]
332
    Bug(#[from] tor_error::Bug),
333
}
334

            
335
impl From<x509_cert::builder::Error> for X509CertError {
336
    fn from(value: x509_cert::builder::Error) -> Self {
337
        X509CertError::CouldNotBuild(Arc::new(value))
338
    }
339
}
340

            
341
#[cfg(test)]
342
mod test {
343
    // @@ begin test lint list maintained by maint/add_warning @@
344
    #![allow(clippy::bool_assert_comparison)]
345
    #![allow(clippy::clone_on_copy)]
346
    #![allow(clippy::dbg_macro)]
347
    #![allow(clippy::mixed_attributes_style)]
348
    #![allow(clippy::print_stderr)]
349
    #![allow(clippy::print_stdout)]
350
    #![allow(clippy::single_char_pattern)]
351
    #![allow(clippy::unwrap_used)]
352
    #![allow(clippy::unchecked_time_subtraction)]
353
    #![allow(clippy::useless_vec)]
354
    #![allow(clippy::needless_pass_by_value)]
355
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
356

            
357
    use super::*;
358
    use tor_basic_utils::test_rng::testing_rng;
359

            
360
    #[test]
361
    fn identity_cert_generation() {
362
        let mut rng = testing_rng();
363
        let keypair = RsaKeypair::generate(&mut rng).unwrap();
364
        let cert = create_legacy_rsa_id_cert(
365
            &mut rng,
366
            SystemTime::now(),
367
            "www.house-of-pancakes.example.com",
368
            &keypair,
369
        )
370
        .unwrap();
371

            
372
        let key_extracted = tor_llcrypto::util::x509_extract_rsa_subject_kludge(&cert[..]).unwrap();
373
        assert_eq!(key_extracted, keypair.to_public_key());
374

            
375
        // TODO: It would be neat to validate this certificate with an independent x509 implementation,
376
        // but afaict most of them sensibly refuse to handle RSA1024.
377
        //
378
        // I've checked the above-generated cert using `openssl verify`, but that's it.
379
    }
380

            
381
    #[test]
382
    fn tls_cert_info() {
383
        let mut rng = testing_rng();
384
        let certified = TlsKeyAndCert::create(
385
            &mut rng,
386
            SystemTime::now(),
387
            "foo.example.com",
388
            "bar.example.com",
389
        )
390
        .unwrap();
391
        dbg!(certified);
392
    }
393
}