use crate::{
ApplicationProtocol, KeyLogIntent, ProtocolVersion, TlsAlpn, TlsKeyLog, TlsSupportedVersions,
client::ClientHello,
};
use rama_core::{
error::BoxError,
extensions::{Extension, Extensions},
};
use rama_crypto::cert::generate_server_auth;
pub use rama_crypto::cert::{
CertificateAuthorityData, CertificateIdentity, CertificateKeyKind, CertificateSubject,
CertificateValidity, GeneratedServerAuthConfig, LeafCertConfig, LeafCertRequest,
SelfSignedCaConfig,
};
use rama_crypto::pki_types::{CertificateDer, PrivateKeyDer};
use rama_utils::{collections::smallvec::SmallVec, macros::generate_set_and_with};
#[derive(Debug, Default)]
pub struct TlsServerConfig(Extensions);
impl TlsServerConfig {
#[must_use]
pub fn new() -> Self {
Self(Extensions::new())
}
pub fn default_http() -> Result<Self, BoxError> {
Ok(Self::new()
.try_with_generated_server_auth(GeneratedServerAuthConfig::default())?
.with_alpn_http_auto()
.with_keylog(KeyLogIntent::Environment))
}
pub fn generated_http_auto() -> Result<Self, BoxError> {
Ok(Self::new()
.try_with_generated_server_auth(GeneratedServerAuthConfig::default())?
.with_alpn_http_auto())
}
pub fn write_to(&self, extensions: &Extensions) {
extensions.extend(&self.0);
}
generate_set_and_with! {
pub fn server_auth(mut self, auth: ServerAuthData) -> Self {
self.0.insert(TlsServerAuth(auth));
self
}
}
generate_set_and_with! {
pub fn generated_server_auth(
mut self,
config: GeneratedServerAuthConfig,
) -> Result<Self, BoxError> {
self.0
.insert(TlsServerAuth(ServerAuthData::new_generated(config)?));
Ok(self)
}
}
generate_set_and_with! {
pub fn single_cert(mut self, data: ServerAuthData) -> Self {
self.0.insert(TlsServerAuth(data));
self
}
}
generate_set_and_with! {
pub fn alpn(mut self, protocols: SmallVec<[ApplicationProtocol; 2]>) -> Self {
self.0.insert(TlsAlpn(protocols));
self
}
}
generate_set_and_with! {
pub fn alpn_http_auto(mut self) -> Self {
self.0.insert(TlsAlpn::http_auto());
self
}
}
generate_set_and_with! {
pub fn alpn_http_1(mut self) -> Self {
self.0.insert(TlsAlpn::http_1());
self
}
}
generate_set_and_with! {
pub fn alpn_http_2(mut self) -> Self {
self.0.insert(TlsAlpn::http_2());
self
}
}
generate_set_and_with! {
pub fn supported_versions(mut self, versions: Vec<ProtocolVersion>) -> Self {
self.0.insert(TlsSupportedVersions(versions));
self
}
}
generate_set_and_with! {
pub fn keylog(mut self, intent: KeyLogIntent) -> Self {
self.0.insert(TlsKeyLog(intent));
self
}
}
generate_set_and_with! {
pub fn client_verify(mut self, mode: ClientVerifyMode) -> Self {
self.0.insert(TlsClientVerify(mode));
self
}
}
generate_set_and_with! {
pub fn store_client_cert_chain(mut self, store: bool) -> Self {
self.0.insert(TlsStoreClientCertChain(store));
self
}
}
pub fn as_extensions(&self) -> &Extensions {
&self.0
}
#[doc(hidden)]
pub fn insert<T: Extension>(&self, piece: T) {
self.0.insert(piece);
}
}
impl Clone for TlsServerConfig {
fn clone(&self) -> Self {
let clone = Self::new();
clone.as_extensions().extend(self.as_extensions());
clone
}
}
#[derive(Debug)]
pub struct ServerAuthData {
pub private_key: PrivateKeyDer<'static>,
pub cert_chain: Vec<CertificateDer<'static>>,
pub ocsp: Option<Vec<u8>>,
}
impl ServerAuthData {
#[must_use]
pub fn new(
cert_chain: Vec<CertificateDer<'static>>,
private_key: PrivateKeyDer<'static>,
) -> Self {
Self {
cert_chain,
private_key,
ocsp: None,
}
}
pub fn new_generated(config: GeneratedServerAuthConfig) -> Result<Self, BoxError> {
let (cert_chain, private_key) = generate_server_auth(config)?;
Ok(Self {
cert_chain,
private_key,
ocsp: None,
})
}
pub fn new_self_signed_leaf(request: LeafCertRequest) -> Result<Self, BoxError> {
Self::new_generated(GeneratedServerAuthConfig::SelfSignedLeaf(request))
}
pub fn new_generated_ca(
ca: SelfSignedCaConfig,
leaf: LeafCertRequest,
) -> Result<Self, BoxError> {
Self::new_generated(GeneratedServerAuthConfig::GeneratedCa { ca, leaf })
}
pub fn new_issued_by(
ca: &CertificateAuthorityData,
request: LeafCertRequest,
) -> Result<Self, BoxError> {
let (cert_chain, private_key) = ca.issue_leaf(request)?;
Ok(Self::new(cert_chain, private_key))
}
}
impl Clone for ServerAuthData {
fn clone(&self) -> Self {
Self {
cert_chain: self.cert_chain.clone(),
ocsp: self.ocsp.clone(),
private_key: self.private_key.clone_key(),
}
}
}
pub trait DynamicCertIssuer: Send + Sync + 'static {
fn issue_cert(
&self,
context: CertificateIssuanceContext,
) -> impl Future<Output = Result<ServerAuthData, BoxError>> + Send + '_;
fn normalize_identity(&self, _identity: &CertificateIdentity) -> Option<CertificateIdentity> {
None
}
}
#[derive(Debug, Clone)]
pub struct CertificateIssuanceContext {
pub client_hello: ClientHello,
pub server_identity: Option<CertificateIdentity>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub enum ClientVerifyMode {
#[default]
Auto,
Disable,
ClientAuth(Vec<CertificateDer<'static>>),
}
#[derive(Debug, Clone, Extension)]
#[extension(tags(tls))]
pub struct TlsServerAuth(pub ServerAuthData);
#[derive(Debug, Clone, Extension)]
#[extension(tags(tls))]
pub struct TlsClientVerify(pub ClientVerifyMode);
#[derive(Debug, Clone, Extension)]
#[extension(tags(tls))]
pub struct TlsStoreClientCertChain(pub bool);