use std::io::BufReader;
use rustls::crypto::CryptoProvider;
use rustls::pki_types::PrivateKeyDer;
use rustls_pki_types::CertificateDer;
use tokio::sync::watch;
use crate::credentials::ProtocolInfo;
use crate::private;
pub mod client;
mod key_log;
pub mod server;
mod tls_stream;
const ALPN_PROTO_STR_H2: &[u8; 2] = b"h2";
#[derive(Debug, Clone)]
pub struct RootCertificates {
pem: Vec<u8>,
}
impl RootCertificates {
pub fn from_pem(pem: impl AsRef<[u8]>) -> Self {
let pem = pem.as_ref().into();
Self { pem }
}
fn get_ref(&self) -> &[u8] {
self.pem.as_slice()
}
}
#[derive(Debug, Clone)]
pub struct Identity {
certs: Vec<u8>,
key: Vec<u8>,
}
pub type IdentityList = Vec<Identity>;
impl Identity {
pub fn from_pem(cert: impl AsRef<[u8]>, key: impl AsRef<[u8]>) -> Self {
let cert = cert.as_ref().into();
let key = key.as_ref().into();
Self { certs: cert, key }
}
}
pub trait Provider<T> {
#[doc(hidden)]
fn get_receiver(self, _token: private::Internal) -> watch::Receiver<T>;
}
pub struct StaticProvider<T> {
inner: T,
}
impl<T> StaticProvider<T> {
pub fn new(value: T) -> Self {
Self { inner: value }
}
}
impl<T> Provider<T> for StaticProvider<T> {
fn get_receiver(self, _token: private::Internal) -> watch::Receiver<T> {
let (_tx, rx) = watch::channel(self.inner);
rx
}
}
pub type StaticRootCertificatesProvider = StaticProvider<RootCertificates>;
pub type StaticIdentityProvider = StaticProvider<Identity>;
static TLS_PROTO_INFO: ProtocolInfo = ProtocolInfo {
security_protocol: "tls",
};
fn sanitize_crypto_provider(mut crypto_provider: CryptoProvider) -> Result<CryptoProvider, String> {
crypto_provider.cipher_suites.retain(|suite| match suite {
rustls::SupportedCipherSuite::Tls13(suite) => true,
rustls::SupportedCipherSuite::Tls12(suite) => {
matches!(
suite.common.suite,
rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
| rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
| rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
| rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
| rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
| rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
)
}
});
if crypto_provider.cipher_suites.is_empty() {
return Err("Crypto provider has no cipher suites matching the security policy (TLS1.3 or TLS1.2+ECDHE)".to_string());
}
Ok(crypto_provider)
}
fn parse_certs(pem: &[u8]) -> Result<Vec<CertificateDer<'static>>, String> {
let mut reader = BufReader::new(pem);
rustls_pemfile::certs(&mut reader)
.map(|result| result.map_err(|e| e.to_string()))
.collect()
}
fn parse_key(pem: &[u8]) -> Result<PrivateKeyDer<'static>, String> {
let mut reader = BufReader::new(pem);
loop {
match rustls_pemfile::read_one(&mut reader).map_err(|e| e.to_string())? {
Some(rustls_pemfile::Item::Pkcs1Key(key)) => return Ok(key.into()),
Some(rustls_pemfile::Item::Pkcs8Key(key)) => return Ok(key.into()),
Some(rustls_pemfile::Item::Sec1Key(key)) => return Ok(key.into()),
None => return Err("no private key found".to_string()),
_ => continue,
}
}
}