use std::sync::{Arc, LazyLock};
use lexe_common::{constants, env::DeployEnv};
use lexe_crypto::ed25519;
use rustls::{
RootCertStore,
client::WebPkiServerVerifier,
server::{WebPkiClientVerifier, danger::ClientCertVerifier},
};
use super::types::{CertWithKey, LxCertificateDer, LxPrivatePkcs8KeyDer};
pub fn app_gateway_client_config(
deploy_env: DeployEnv,
) -> rustls::ClientConfig {
let lexe_verifier = lexe_server_verifier(deploy_env);
let mut config = lexe_tls_core::client_config_builder()
.with_webpki_verifier(lexe_verifier)
.with_no_client_auth();
config
.alpn_protocols
.clone_from(&lexe_tls_core::LEXE_ALPN_PROTOCOLS);
config
}
pub fn lexe_ca_cert(deploy_env: DeployEnv) -> LxCertificateDer {
match deploy_env {
DeployEnv::Dev =>
LxCertificateDer(constants::LEXE_DUMMY_CA_CERT_DER.to_vec()),
DeployEnv::Staging =>
LxCertificateDer(constants::LEXE_STAGING_CA_CERT_DER.to_vec()),
DeployEnv::Prod =>
LxCertificateDer(constants::LEXE_PROD_CA_CERT_DER.to_vec()),
}
}
pub fn lexe_server_verifier(
deploy_env: DeployEnv,
) -> Arc<WebPkiServerVerifier> {
let lexe_ca_cert = lexe_ca_cert(deploy_env);
let mut lexe_roots = RootCertStore::empty();
lexe_roots
.add(lexe_ca_cert.into())
.expect("Checked in tests");
WebPkiServerVerifier::builder_with_provider(
Arc::new(lexe_roots),
lexe_tls_core::LEXE_CRYPTO_PROVIDER.clone(),
)
.build()
.expect("Checked in tests")
}
pub fn lexe_client_verifier(
deploy_env: DeployEnv,
) -> Arc<dyn ClientCertVerifier + 'static> {
let lexe_ca_cert = lexe_ca_cert(deploy_env);
let mut roots = RootCertStore::empty();
roots.add(lexe_ca_cert.into()).expect("Checked in tests");
WebPkiClientVerifier::builder_with_provider(
Arc::new(roots),
lexe_tls_core::LEXE_CRYPTO_PROVIDER.clone(),
)
.build()
.expect("Checked in tests")
}
pub fn dummy_lexe_ca_key_pair() -> &'static ed25519::KeyPair {
static DUMMY_LEXE_CA_KEY_PAIR: LazyLock<ed25519::KeyPair> =
LazyLock::new(|| ed25519::KeyPair::from_seed_owned([69; 32]));
&DUMMY_LEXE_CA_KEY_PAIR
}
pub fn dummy_lexe_ca_cert() -> CertWithKey {
let dummy_key_pair = dummy_lexe_ca_key_pair();
let dummy_cert_key_der =
LxPrivatePkcs8KeyDer(dummy_key_pair.serialize_pkcs8_der().to_vec());
let dummy_cert_der =
LxCertificateDer(constants::LEXE_DUMMY_CA_CERT_DER.to_vec());
CertWithKey {
cert_der: dummy_cert_der,
cert_chain_der: vec![],
key_der: dummy_cert_key_der,
}
}
#[cfg(test)]
mod test {
use proptest::{arbitrary::any, proptest, test_runner::Config};
use super::*;
use crate::ed25519_ext::Ed25519KeyPairExt;
fn gen_dummy_lexe_ca_cert() -> CertWithKey {
let dummy_key_pair = dummy_lexe_ca_key_pair();
let dummy_cert_params = crate::build_rcgen_cert_params(
"Lexe CA cert",
rcgen::date_time_ymd(1975, 1, 1),
rcgen::date_time_ymd(4096, 1, 1),
crate::DEFAULT_SUBJECT_ALT_NAMES.clone(),
dummy_key_pair.public_key(),
|params: &mut rcgen::CertificateParams| {
params.is_ca =
rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
params.name_constraints = None;
},
);
let issuer = rcgen::Issuer::from_params(
&dummy_cert_params,
dummy_key_pair.rcgen(),
);
let dummy_cert = dummy_cert_params
.signed_by(&dummy_key_pair.rcgen(), &issuer)
.unwrap();
let dummy_cert_der = LxCertificateDer(dummy_cert.der().to_vec());
let dummy_cert_key_der =
LxPrivatePkcs8KeyDer(dummy_key_pair.serialize_pkcs8_der().to_vec());
CertWithKey {
cert_der: dummy_cert_der,
cert_chain_der: vec![],
key_der: dummy_cert_key_der,
}
}
#[test]
fn verifier_helpers_dont_panic() {
let config = Config::with_cases(4);
proptest!(config, |(deploy_env in any::<DeployEnv>())| {
lexe_server_verifier(deploy_env);
lexe_client_verifier(deploy_env);
})
}
#[test]
#[cfg_attr(target_env = "sgx", ignore = "Can't read files in SGX")]
fn test_dummy_lexe_ca_cert_eq() {
let cert1 = gen_dummy_lexe_ca_cert().cert_der.0;
let cert2 =
std::fs::read("../lexe-common/data/lexe-dummy-root-ca-cert.der")
.unwrap();
assert_eq!(
cert1, cert2,
"The generated dummy Lexe CA cert doesn't match the checked in \
version. Regenerate it:\n\
\n\
$ cargo test -p lexe-tls -- --ignored dump_dummy_lexe_ca\n\
\n"
);
}
#[ignore]
#[test]
fn dump_dummy_lexe_ca_cert() {
let cert = gen_dummy_lexe_ca_cert().cert_der;
std::fs::write(
"../lexe-common/data/lexe-dummy-root-ca-cert.new.der",
&cert.0,
)
.unwrap();
}
}