use std::{
ffi::{c_void, CStr},
fmt::Debug,
os::raw::c_char,
};
use libcoap_sys::{
coap_bin_const_t, coap_context_t, coap_dtls_cpsk_info_t, coap_dtls_spsk_info_t, coap_session_t, coap_str_const_t,
};
use crate::session::CoapServerSession;
use crate::{context::CoapContext, session::CoapClientSession};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg(feature = "dtls")]
pub struct CoapCryptoPskInfo {
pub identity: Box<CoapCryptoPskIdentity>,
pub key: Box<CoapCryptoPskData>,
}
#[cfg(feature = "dtls")]
impl CoapCryptoPskInfo {
pub fn apply_to_cpsk_info(&self, info: &mut coap_dtls_cpsk_info_t) {
info.identity.s = self.identity.as_ptr();
info.identity.length = self.identity.len();
info.key.s = self.key.as_ptr();
info.key.length = self.key.len();
}
pub fn apply_to_spsk_info(&self, info: &mut coap_dtls_spsk_info_t) {
info.hint.s = self.identity.as_ptr();
info.hint.length = self.identity.len();
info.key.s = self.key.as_ptr();
info.key.length = self.key.len();
}
}
#[cfg(feature = "dtls")]
pub type CoapCryptoPskIdentity = [u8];
#[cfg(feature = "dtls")]
pub type CoapCryptoPskData = [u8];
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg(feature = "dtls")]
pub enum CoapCryptoProviderResponse<T: Debug> {
UseCurrent,
UseNew(T),
Unacceptable,
}
#[cfg(feature = "dtls")]
pub trait CoapClientCryptoProvider: Debug {
fn provide_key_for_hint(
&mut self,
hint: &CoapCryptoPskIdentity,
) -> CoapCryptoProviderResponse<Box<CoapCryptoPskData>>;
fn provide_default_info(&mut self) -> CoapCryptoPskInfo;
}
#[cfg(feature = "dtls")]
pub trait CoapServerCryptoProvider: Debug {
#[allow(unused_variables)]
fn provide_key_for_identity(
&mut self,
identity: &CoapCryptoPskIdentity,
) -> CoapCryptoProviderResponse<Box<CoapCryptoPskData>> {
CoapCryptoProviderResponse::UseCurrent
}
#[allow(unused_variables)]
fn provide_hint_for_sni(&mut self, sni: &str) -> CoapCryptoProviderResponse<CoapCryptoPskInfo> {
CoapCryptoProviderResponse::UseCurrent
}
fn provide_default_info(&mut self) -> CoapCryptoPskInfo;
}
#[cfg(feature = "dtls")]
pub(crate) unsafe extern "C" fn dtls_ih_callback(
hint: *mut coap_str_const_t,
session: *mut coap_session_t,
_userdata: *mut c_void,
) -> *const coap_dtls_cpsk_info_t {
let mut session = CoapClientSession::from_raw(session);
let provided_identity = std::slice::from_raw_parts((*hint).s, (*hint).length);
session
.provide_raw_key_for_hint(provided_identity)
.map(|v| v as *const coap_dtls_cpsk_info_t)
.unwrap_or(std::ptr::null())
}
#[cfg(feature = "dtls")]
pub(crate) unsafe extern "C" fn dtls_server_id_callback(
identity: *mut coap_bin_const_t,
session: *mut coap_session_t,
userdata: *mut c_void,
) -> *const coap_bin_const_t {
let context = CoapContext::from_raw(userdata as *mut coap_context_t);
let provided_identity = std::slice::from_raw_parts((*identity).s, (*identity).length);
let session = CoapServerSession::from_raw(session);
let key = context.provide_raw_key_for_identity(provided_identity, &session);
key.unwrap_or(std::ptr::null())
}
#[cfg(feature = "dtls")]
pub(crate) unsafe extern "C" fn dtls_server_sni_callback(
sni: *const c_char,
_session: *mut coap_session_t,
userdata: *mut c_void,
) -> *const coap_dtls_spsk_info_t {
let context = CoapContext::from_raw(userdata as *mut coap_context_t);
let sni_value = CStr::from_ptr(sni).to_str();
if let Ok(sni_value) = sni_value {
context
.provide_raw_hint_for_sni(sni_value)
.map(|v| (v as *const coap_dtls_spsk_info_t))
.unwrap_or(std::ptr::null())
} else {
std::ptr::null()
}
}