use std::sync::{Arc, OnceLock};
use ps_rustcrypto::policy::ct::CtVerifier;
use rustls::pki_types::SignatureVerificationAlgorithm;
use rustls::{
CipherSuite, RootCertStore, SignatureScheme, SupportedCipherSuite, Tls12CipherSuite,
client::{WebPkiServerVerifier, danger::ServerCertVerifier},
crypto::{CipherSuiteCommon, CryptoProvider},
};
pub fn chacha_provider() -> Arc<CryptoProvider> {
static PROVIDER: OnceLock<Arc<CryptoProvider>> = OnceLock::new();
Arc::clone(PROVIDER.get_or_init(|| {
let mut provider = ps_rustcrypto::provider_with_rsa_pss();
static CERT_ALGORITHMS: OnceLock<Vec<&'static dyn SignatureVerificationAlgorithm>> =
OnceLock::new();
let algorithms = CERT_ALGORITHMS.get_or_init(|| {
let mut all = provider.signature_verification_algorithms.all.to_vec();
for (scheme, verifiers) in provider.signature_verification_algorithms.mapping {
if matches!(
scheme,
SignatureScheme::RSA_PSS_SHA256
| SignatureScheme::RSA_PSS_SHA384
| SignatureScheme::RSA_PSS_SHA512
) {
all.extend_from_slice(verifiers);
}
}
all
});
provider.signature_verification_algorithms.all = algorithms;
static RSA_SUITE: OnceLock<Tls12CipherSuite> = OnceLock::new();
let rsa = RSA_SUITE.get_or_init(|| {
let SupportedCipherSuite::Tls12(base) =
ps_rustcrypto::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
else {
panic!("the TLS 1.2 provider constant changed protocol");
};
Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: base.common.hash_provider,
confidentiality_limit: base.common.confidentiality_limit,
},
prf_provider: base.prf_provider,
kx: base.kx,
sign: &[
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
],
aead_alg: base.aead_alg,
}
});
provider.cipher_suites = vec![
ps_rustcrypto::TLS13_CHACHA20_POLY1305_SHA256,
ps_rustcrypto::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
SupportedCipherSuite::Tls12(rsa),
];
Arc::new(provider)
}))
}
pub fn certificate_verifier(
roots: RootCertStore,
public: RootCertStore,
) -> Result<Arc<CtVerifier>, String> {
let inner = WebPkiServerVerifier::builder_with_provider(Arc::new(roots), chacha_provider())
.build()
.map_err(|error| error.to_string())?;
let inner: Arc<dyn ServerCertVerifier> = inner;
if public.is_empty() {
return Ok(CtVerifier::without_public_roots(inner));
}
let public = WebPkiServerVerifier::builder_with_provider(Arc::new(public), chacha_provider())
.build()
.map_err(|error| error.to_string())?;
Ok(CtVerifier::public_only(inner, public))
}
pub fn prepare_native_tls() -> Result<(), String> {
super::h1::prepare_native_tls()
}
#[cfg(feature = "sandbox2-witness")]
pub(super) fn add_witness_roots(roots: &mut RootCertStore) -> Result<(), String> {
use rustls::pki_types::{CertificateDer, pem::PemObject};
if let Some(path) = std::env::var_os("SANDBOX2_TLS_CA_FILE") {
for certificate in CertificateDer::pem_file_iter(path).map_err(|error| error.to_string())? {
roots
.add(certificate.map_err(|error| error.to_string())?)
.map_err(|error| error.to_string())?;
}
}
Ok(())
}