#![allow(unused)]
use std::cell::RefCell;
use std::collections::VecDeque;
use bytes::BytesMut;
use wolfssl::ContextBuilder;
use wolfssl::IOCallbackResult;
use wolfssl::IOCallbacks;
use wolfssl::Method;
use wolfssl::Poll;
use wolfssl::RootCertificate;
use wolfssl::Secret;
use wolfssl::Session;
use wolfssl::SessionConfig;
use wolfssl::SslVerifyMode;
#[derive(Debug)]
pub enum WolfError {
Wolf(wolfssl::Error),
ContextBuilder(wolfssl::NewContextBuilderError),
Session(wolfssl::NewSessionError),
}
impl From<wolfssl::Error> for WolfError {
fn from(value: wolfssl::Error) -> Self {
WolfError::Wolf(value)
}
}
impl From<wolfssl::NewContextBuilderError> for WolfError {
fn from(value: wolfssl::NewContextBuilderError) -> Self {
WolfError::ContextBuilder(value)
}
}
impl From<wolfssl::NewSessionError> for WolfError {
fn from(value: wolfssl::NewSessionError) -> Self {
WolfError::Session(value)
}
}
#[derive(Debug)]
pub enum DtlsEvent {
Connected,
Data(Vec<u8>),
}
#[derive(Default)]
pub struct IoBuffer {
incoming: RefCell<VecDeque<Vec<u8>>>,
outgoing: RefCell<VecDeque<Vec<u8>>>,
}
impl IoBuffer {
pub fn new() -> Self {
Self::default()
}
pub fn set_incoming(&self, data: &[u8]) {
self.incoming.borrow_mut().push_back(data.to_vec());
}
pub fn pop_outgoing(&self) -> Option<Vec<u8>> {
self.outgoing.borrow_mut().pop_front()
}
}
impl IOCallbacks for IoBuffer {
fn recv(&mut self, buf: &mut [u8]) -> IOCallbackResult<usize> {
let mut incoming = self.incoming.borrow_mut();
if let Some(data) = incoming.pop_front() {
let n = std::cmp::min(buf.len(), data.len());
buf[..n].copy_from_slice(&data[..n]);
IOCallbackResult::Ok(n)
} else {
IOCallbackResult::WouldBlock
}
}
fn send(&mut self, buf: &[u8]) -> IOCallbackResult<usize> {
self.outgoing.borrow_mut().push_back(buf.to_vec());
IOCallbackResult::Ok(buf.len())
}
}
pub struct WolfDtlsCert {
pub cert_der: Vec<u8>,
pub key_der: Vec<u8>,
}
impl WolfDtlsCert {
pub fn new(cert_der: Vec<u8>, key_der: Vec<u8>) -> Self {
Self { cert_der, key_der }
}
pub fn new_dtls13_impl(&self, is_server: bool) -> Result<WolfDtlsImpl, WolfError> {
WolfDtlsImpl::new(self, is_server)
}
}
pub struct WolfDtlsImpl {
session: Session<IoBuffer>,
is_connected: bool,
}
impl WolfDtlsImpl {
pub fn new(cert: &WolfDtlsCert, is_server: bool) -> Result<Self, WolfError> {
let method = if is_server {
Method::DtlsServerV1_3
} else {
Method::DtlsClientV1_3
};
let ctx = ContextBuilder::new(method)?
.with_certificate(Secret::Asn1Buffer(&cert.cert_der))?
.with_private_key(Secret::Asn1Buffer(&cert.key_der))?
.build();
let io = IoBuffer::new();
let session_config = SessionConfig::new(io)
.with_dtls_nonblocking(true)
.with_ssl_verify_mode(SslVerifyMode::SslVerifyNone);
let session = ctx.new_session(session_config)?;
Ok(Self {
session,
is_connected: false,
})
}
pub fn is_connected(&self) -> bool {
self.is_connected
}
pub fn handle_receive(
&mut self,
data: &[u8],
events: &mut VecDeque<DtlsEvent>,
) -> Result<(), WolfError> {
if self.is_connected {
loop {
let mut buf = BytesMut::with_capacity(2048);
match self.session.try_read(&mut buf) {
Ok(Poll::Ready(n)) if n > 0 => {
events.push_back(DtlsEvent::Data(buf[..n].to_vec()));
}
Ok(Poll::PendingRead | Poll::PendingWrite) => break,
Ok(Poll::Ready(_)) => break,
Ok(Poll::AppData(data)) => {
events.push_back(DtlsEvent::Data(data.to_vec()));
}
Err(_) => break, }
}
}
self.session.io_cb_mut().set_incoming(data);
if !self.is_connected {
self.handle_handshake(events)?;
} else {
loop {
let mut buf = BytesMut::with_capacity(2048);
match self.session.try_read(&mut buf) {
Ok(Poll::Ready(n)) if n > 0 => {
events.push_back(DtlsEvent::Data(buf[..n].to_vec()));
}
Ok(Poll::PendingRead | Poll::PendingWrite) => break,
Ok(Poll::Ready(_)) => break,
Ok(Poll::AppData(data)) => {
events.push_back(DtlsEvent::Data(data.to_vec()));
}
Err(e) => return Err(e.into()),
}
}
}
Ok(())
}
fn handle_handshake(&mut self, events: &mut VecDeque<DtlsEvent>) -> Result<(), WolfError> {
loop {
match self.session.try_negotiate() {
Ok(Poll::Ready(())) => {
self.is_connected = true;
events.push_back(DtlsEvent::Connected);
break;
}
Ok(Poll::PendingRead) => {
if self.session.is_init_finished() && !self.is_connected {
self.is_connected = true;
events.push_back(DtlsEvent::Connected);
}
break;
}
Ok(Poll::PendingWrite) => {
if self.session.is_init_finished() && !self.is_connected {
self.is_connected = true;
events.push_back(DtlsEvent::Connected);
break;
}
}
Ok(Poll::AppData(data)) => {
events.push_back(DtlsEvent::Data(data.to_vec()));
}
Err(e) => return Err(e.into()),
}
}
Ok(())
}
pub fn poll_datagram(&mut self) -> Option<Vec<u8>> {
self.session.io_cb_mut().pop_outgoing()
}
pub fn drain_pending_data(&mut self, events: &mut VecDeque<DtlsEvent>) {
if !self.is_connected {
return;
}
loop {
let mut buf = BytesMut::with_capacity(2048);
match self.session.try_read(&mut buf) {
Ok(Poll::Ready(n)) if n > 0 => {
events.push_back(DtlsEvent::Data(buf[..n].to_vec()));
}
Ok(Poll::AppData(data)) => {
events.push_back(DtlsEvent::Data(data.to_vec()));
}
_ => break,
}
}
}
pub fn write(&mut self, data: &[u8]) -> Result<(), WolfError> {
let mut buf = BytesMut::from(data);
match self.session.try_write(&mut buf) {
Ok(Poll::Ready(_)) => Ok(()),
Ok(Poll::PendingRead | Poll::PendingWrite) => Ok(()),
Ok(Poll::AppData(_)) => Ok(()),
Err(e) => Err(WolfError::Wolf(e)),
}
}
pub fn initiate(&mut self) -> Result<(), WolfError> {
match self.session.try_negotiate() {
Ok(_) => Ok(()),
Err(e) => Err(e.into()),
}
}
}