Skip to main content

didbot_tls/
test_support.rs

1//! Certificates for a test that needs a server a real client can verify.
2//!
3//! Behind the `test-support` feature, so nothing ships it.
4//!
5//! Every client in this workspace verifies what it connects to, and there is
6//! no way to switch that off — so a test that stands up a server over TLS
7//! has to hand its client an authority to trust. [`issue_for`] is that: a
8//! throwaway authority, a leaf under it, and the authority's PEM to put in
9//! the client's root store.
10//!
11//! Separate from [`crate::local`], which is a machine's one authority kept
12//! on disk and trusted once. Nothing here touches disk or outlives the
13//! process.
14
15use std::sync::Arc;
16
17use rcgen::{
18    BasicConstraints, CertificateParams, DistinguishedName, DnType, ExtendedKeyUsagePurpose, IsCa,
19    Issuer, KeyPair, KeyUsagePurpose,
20};
21use time::{Duration, OffsetDateTime};
22
23/// A leaf, its key and the authority that signed it.
24pub struct TestCertificate {
25    /// The leaf followed by the authority, PEM, for a server to present.
26    pub chain_pem: String,
27    /// The leaf's private key, PEM.
28    pub key_pem: String,
29    /// The authority's certificate, PEM, for a client to trust.
30    pub ca_pem: String,
31}
32
33/// A fresh authority and a leaf covering `names`, which may be hostnames or
34/// address literals.
35///
36/// Two calls produce two authorities: a test that wants one server's
37/// certificate refused by another server's client gets that by calling this
38/// twice.
39pub fn issue_for(names: &[&str]) -> TestCertificate {
40    let ca_key = KeyPair::generate().expect("a key pair");
41    let mut ca = CertificateParams::new(Vec::<String>::new()).expect("no names is valid");
42    ca.is_ca = IsCa::Ca(BasicConstraints::Constrained(0));
43    ca.distinguished_name = DistinguishedName::new();
44    ca.distinguished_name
45        .push(DnType::CommonName, "didbot test authority");
46    ca.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
47    let ca_pem = ca.self_signed(&ca_key).expect("a self-signed ca").pem();
48    let issuer = Issuer::new(ca, ca_key);
49
50    let mut leaf =
51        CertificateParams::new(names.iter().map(|n| (*n).to_owned()).collect::<Vec<_>>())
52            .expect("valid names");
53    let now = OffsetDateTime::now_utc();
54    leaf.not_before = now - Duration::hours(1);
55    leaf.not_after = now + Duration::days(1);
56    leaf.distinguished_name = DistinguishedName::new();
57    leaf.distinguished_name
58        .push(DnType::CommonName, names.first().copied().unwrap_or("test"));
59    leaf.use_authority_key_identifier_extension = true;
60    leaf.key_usages = vec![
61        KeyUsagePurpose::DigitalSignature,
62        KeyUsagePurpose::KeyEncipherment,
63    ];
64    leaf.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth];
65    let leaf_key = KeyPair::generate().expect("a key pair");
66    let signed = leaf.signed_by(&leaf_key, &issuer).expect("a signed leaf");
67
68    TestCertificate {
69        chain_pem: format!("{}{ca_pem}", signed.pem()),
70        key_pem: leaf_key.serialize_pem(),
71        ca_pem,
72    }
73}
74
75/// A `rustls::ServerConfig` covering `names`, and the authority a client has
76/// to trust to reach it.
77pub fn server_config(names: &[&str]) -> (Arc<rustls::ServerConfig>, String) {
78    let _ = rustls::crypto::ring::default_provider().install_default();
79    let provider = rustls::crypto::ring::default_provider();
80    let issued = issue_for(names);
81    let certified =
82        crate::cert::certified_key_from_pem(&issued.chain_pem, &issued.key_pem, &provider)
83            .expect("the pair this module just signed loads");
84    let mut config = rustls::ServerConfig::builder()
85        .with_no_client_auth()
86        .with_cert_resolver(crate::resolver::SwappableCert::new(certified));
87    config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
88    (Arc::new(config), issued.ca_pem)
89}
90
91/// A self-signed certificate and its private key, both PEM, for `name`.
92///
93/// Two calls with different `name`s produce certificates with different
94/// serial numbers and keys, which is all a rotation test needs to tell
95/// "old" and "new" apart. Nothing verifies one of these: a test that needs
96/// a client to complete a handshake wants [`issue_for`].
97pub fn self_signed_pem(name: &str) -> (String, String) {
98    let rcgen::CertifiedKey { cert, signing_key } =
99        rcgen::generate_simple_self_signed(vec![name.to_owned()])
100            .expect("self-signed generation for a valid DNS name does not fail");
101    (cert.pem(), signing_key.serialize_pem())
102}