use std::io::{Read, Write};
use std::sync::Arc;
use wolfcrypt_sys::*;
use crate::certificate::{Certificate, PrivateKey, RootCertStore};
use crate::config::CtxInner;
use crate::error::{expect_wolfssl_success, Result, TlsError};
use crate::protocol::{self, ProtocolVersion};
use crate::{ensure_init, SslGuard, TlsSocket};
#[derive(Clone)]
pub struct TlsServerConfig {
pub(crate) inner: Arc<CtxInner>,
}
pub struct TlsServerConfigBuilder {
protocol_versions: Option<Vec<ProtocolVersion>>,
cert: Option<Certificate>,
key: Option<PrivateKey>,
client_ca_store: Option<RootCertStore>,
}
impl TlsServerConfig {
pub fn builder() -> TlsServerConfigBuilder {
TlsServerConfigBuilder {
protocol_versions: None,
cert: None,
key: None,
client_ca_store: None,
}
}
}
impl TlsServerConfigBuilder {
pub fn with_protocol_versions(mut self, versions: &[ProtocolVersion]) -> Self {
self.protocol_versions = Some(versions.to_vec());
self
}
pub fn with_certificate_chain(mut self, cert: Certificate, key: PrivateKey) -> Self {
self.cert = Some(cert);
self.key = Some(key);
self
}
pub fn with_no_client_auth(self) -> Self {
self
}
pub fn with_client_auth(mut self, client_ca_store: RootCertStore) -> Self {
self.client_ca_store = Some(client_ca_store);
self
}
pub fn build(self) -> Result<TlsServerConfig> {
ensure_init();
let cert = self
.cert
.ok_or(TlsError::InvalidConfig("server certificate is required"))?;
let key = self
.key
.ok_or(TlsError::InvalidConfig("server private key is required"))?;
let method = unsafe {
protocol::resolve_method(protocol::Side::Server, self.protocol_versions.as_deref())?
};
let ctx = unsafe { wolfSSL_CTX_new(method) };
if ctx.is_null() {
return Err(TlsError::AllocFailed {
func: "wolfSSL_CTX_new",
});
}
let inner = Arc::new(CtxInner { ctx });
let ret = unsafe {
wolfSSL_CTX_use_certificate_buffer(
inner.ctx,
cert.data().as_ptr(),
cert.data().len() as core::ffi::c_long,
cert.format().as_c_int(),
)
};
expect_wolfssl_success(ret, "wolfSSL_CTX_use_certificate_buffer")?;
let ret = unsafe {
wolfSSL_CTX_use_PrivateKey_buffer(
inner.ctx,
key.data().as_ptr(),
key.data().len() as core::ffi::c_long,
key.format().as_c_int(),
)
};
expect_wolfssl_success(ret, "wolfSSL_CTX_use_PrivateKey_buffer")?;
if let Some(ref ca_store) = self.client_ca_store {
for (cert_data, format) in ca_store.iter() {
let ret = unsafe {
wolfSSL_CTX_load_verify_buffer(
inner.ctx,
cert_data.as_ptr(),
cert_data.len() as core::ffi::c_long,
format.as_c_int(),
)
};
expect_wolfssl_success(ret, "wolfSSL_CTX_load_verify_buffer")?;
}
unsafe {
wolfSSL_CTX_set_verify(
inner.ctx,
(WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) as core::ffi::c_int,
None,
);
}
}
Ok(TlsServerConfig { inner })
}
}
pub struct TlsAcceptor {
config: TlsServerConfig,
}
impl TlsAcceptor {
pub fn new(config: TlsServerConfig) -> Self {
TlsAcceptor { config }
}
pub fn accept<S: Read + Write + TlsSocket>(&self, stream: S) -> Result<TlsServer<S>> {
let ssl = unsafe { wolfSSL_new(self.config.inner.ctx) };
if ssl.is_null() {
return Err(TlsError::AllocFailed {
func: "wolfSSL_new",
});
}
let guard = SslGuard(ssl);
let fd = stream.tls_raw_fd();
let ret = unsafe { wolfSSL_set_fd(guard.as_ptr(), fd) };
if ret != WOLFSSL_SUCCESS as core::ffi::c_int {
return Err(TlsError::Ffi {
code: ret,
func: "wolfSSL_set_fd",
});
}
let ret = unsafe { wolfSSL_accept(guard.as_ptr()) };
if ret != WOLFSSL_SUCCESS as core::ffi::c_int {
let err = unsafe { wolfSSL_get_error(guard.as_ptr(), ret) };
return Err(TlsError::Ffi {
code: err,
func: "wolfSSL_accept",
});
}
Ok(TlsServer {
ssl: guard.into_raw(),
stream,
config: self.config.clone(),
})
}
}
pub struct TlsServer<S> {
ssl: *mut WOLFSSL,
#[allow(dead_code)]
stream: S,
#[allow(dead_code)]
config: TlsServerConfig,
}
impl<S> std::fmt::Debug for TlsServer<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TlsServer").field("ssl", &self.ssl).finish()
}
}
unsafe impl<S: Send> Send for TlsServer<S> {}
crate::impl_tls_io!(TlsServer);