1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Much of this code was borrowed with many thanks from the Quinn project:
//! `<https://github.com/quinn-rs/quinn/blob/main/quinn/examples/server.rs>`

use anyhow::{bail, Context, Result};
use openssl::x509::X509;
use quinn::{Connection, IdleTimeout, ServerConfig};
use rustls::server::AllowAnyAuthenticatedClient;
use rustls::{Certificate, PrivateKey, RootCertStore};
use rustls_pemfile::{certs, pkcs8_private_keys, rsa_private_keys};
use std::{fs, path::Path, sync::Arc};

const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"];

#[derive(Default)]
pub struct ConfigOptions {
    pub keylog: bool,
    pub stateless_retry: bool,
    pub max_idle_timeout: IdleTimeout,
}

pub fn server_config(
    root_store: RootCertStore,
    certs: Vec<Certificate>,
    key: PrivateKey,
    options: ConfigOptions,
) -> Result<ServerConfig> {
    let client_cert_verifier = Arc::new(AllowAnyAuthenticatedClient::new(root_store));

    let mut server_crypto = rustls::ServerConfig::builder()
        .with_safe_defaults()
        .with_client_cert_verifier(client_cert_verifier)
        .with_single_cert(certs, key)?;

    server_crypto.alpn_protocols = ALPN_QUIC_HTTP.iter().map(|&x| x.into()).collect();
    if options.keylog {
        server_crypto.key_log = Arc::new(rustls::KeyLogFile::new());
    }

    let mut server_config = ServerConfig::with_crypto(Arc::new(server_crypto));
    let transport_config = Arc::get_mut(&mut server_config.transport).unwrap();
    transport_config.max_concurrent_uni_streams(0_u8.into());
    transport_config.max_idle_timeout(Some(options.max_idle_timeout));
    if options.stateless_retry {
        server_config.use_retry(true);
    }

    Ok(server_config)
}

fn load_key<T: AsRef<Path>>(path: T) -> Result<PrivateKey> {
    let path = path.as_ref();
    let key = fs::read(path).context("failed to read private key")?;
    let key = if path.extension().map_or(false, |x| x == "der") {
        PrivateKey(key)
    } else {
        let pkcs8 = pkcs8_private_keys(&mut &*key).context("malformed PKCS #8 private key")?;
        match pkcs8.into_iter().next() {
            Some(x) => PrivateKey(x),
            None => {
                let rsa = rsa_private_keys(&mut &*key).context("malformed PKCS #1 private key")?;
                match rsa.into_iter().next() {
                    Some(x) => PrivateKey(x),
                    None => {
                        bail!("no private keys found");
                    }
                }
            }
        }
    };

    Ok(key)
}

fn load_certs<T: AsRef<Path>>(path: T) -> Result<Vec<Certificate>> {
    let path = path.as_ref();
    let cert_chain = fs::read(path).context("failed to read certificate chain")?;

    let cert_chain = if path.extension().map_or(false, |x| x == "der") {
        vec![Certificate(cert_chain)]
    } else {
        certs(&mut &*cert_chain)
            .context("invalid PEM-encoded certificate")?
            .into_iter()
            .map(Certificate)
            .collect()
    };

    Ok(cert_chain)
}

pub fn read_certs<T: AsRef<Path>>(
    cert_path: T,
    key_path: T,
) -> Result<(Vec<Certificate>, PrivateKey)> {
    let certs = load_certs(cert_path)?;
    let key = load_key(key_path)?;
    Ok((certs, key))
}

pub fn load_root_store<T: AsRef<Path>>(ca_file: T) -> Result<RootCertStore> {
    let ca_file = ca_file.as_ref();
    let mut store = RootCertStore::empty();
    let certs = load_certs(ca_file)?;
    store.add_parsable_certificates(&certs);

    if store.is_empty() {
        bail!("No valid certs found in file {ca_file:?}");
    }

    Ok(store)
}

pub fn get_pubkey_from_connection(connection: &Connection) -> Result<String> {
    let peer_identity = connection
        .peer_identity()
        .context("Unable to read peer identity")?;

    let certs = peer_identity
        .downcast_ref::<Vec<Certificate>>()
        .context("Unable to read cert")?;

    let pub_key = extract_public_key(certs)?;

    Ok(pub_key)
}

fn extract_public_key(certs: &[Certificate]) -> Result<String> {
    let first_cert = certs.get(0).context("Failed to get first certificate.")?;
    let cert = X509::from_der(first_cert.as_ref())?;
    let pub_key = cert.public_key()?;
    let pem = pub_key.public_key_to_pem()?;
    let result = String::from_utf8(pem)?;

    Ok(result)
}