From 634104c6c74ad9b606d18fe51fbc21ca9cb0b178 Mon Sep 17 00:00:00 2001 From: Akos Vandra Date: Sun, 2 Oct 2022 15:44:32 +0200 Subject: [PATCH 1/2] add sni support --- src/http.rs | 2 + src/http/server.rs | 107 +++++++++++++++++++++++++++++++++++++-------- src/http/sni.rs | 85 +++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 src/http/sni.rs diff --git a/src/http.rs b/src/http.rs index cdab339ea09..8e518ac4a5b 100644 --- a/src/http.rs +++ b/src/http.rs @@ -2,3 +2,5 @@ pub mod client; #[cfg(esp_idf_comp_esp_http_server_enabled)] pub mod server; +#[cfg(all(esp_idf_esp_tls_server_sni_hook, esp_idf_comp_esp_http_server_enabled))] +pub mod sni; diff --git a/src/http/server.rs b/src/http/server.rs index e23473a74ee..534b440b3df 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -1,5 +1,5 @@ use core::cell::UnsafeCell; -use core::fmt::{Debug, Display}; +use core::fmt::{Debug, Display, Formatter}; use core::sync::atomic::{AtomicBool, Ordering}; use core::time::*; use core::{mem, ptr}; @@ -30,8 +30,11 @@ use crate::private::common::Newtype; use crate::private::cstr::{CStr, CString}; use crate::private::mutex::{Mutex, RawMutex}; -#[derive(Copy, Clone, Debug)] -pub struct Configuration { +#[cfg(all(esp_idf_esp_tls_server_sni_hook, esp_idf_comp_esp_http_server_enabled))] +use super::sni::*; + +#[cfg_attr(not(esp_idf_esp_tls_server_sni_hook), derive(Debug))] +pub struct Configuration<'a> { pub http_port: u16, pub https_port: u16, pub max_sessions: usize, @@ -45,9 +48,13 @@ pub struct Configuration { pub server_certificate: Option<&'static str>, #[cfg(esp_idf_esp_https_server_enable)] pub private_key: Option<&'static str>, + #[cfg(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook))] + pub sni: Option>>, + #[cfg(not(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook)))] + pub _phantom_data: std::marker::PhantomData<&'a ()> } -impl Default for Configuration { +impl<'a> Default for Configuration<'a> { fn default() -> Self { Configuration { http_port: 80, @@ -66,13 +73,44 @@ impl Default for Configuration { server_certificate: None, #[cfg(esp_idf_esp_https_server_enable)] private_key: None, + #[cfg(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook))] + sni: None, + #[cfg(not(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook)))] + _phantom_data: Default::default() } } } -impl From<&Configuration> for Newtype { +//TODO: Can we simply ignore the sni field in the Derive macro somehow? Derivative crate is supposed to be for that, but can't get it to work +#[cfg(esp_idf_esp_tls_server_sni_hook)] +impl<'a> Debug for Configuration<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + + let sni_s = if self.sni.is_some() { + "Some(..)" + } else { "None" }; + + f.write_fmt(format_args!( + "Configuration {{ http_port = {}, https_port = {}, max_sessions = {}, session_timeout = {:?}, stack_size = {}, max_open_sockets = {}, max_uri_handlers = {}, max_resp_handlers = {}, lru_purge_enable = {}, server_certificate = {:?}, private_key = {:?}, sni = {} }}", + self.http_port, + self.https_port, + self.max_sessions, + self.session_timeout, + self.stack_size, + self.max_open_sockets, + self.max_uri_handlers, + self.max_resp_handlers, + self.lru_purge_enable, + self.server_certificate, + self.private_key, + sni_s + )) + } +} + +impl<'a> From<&Configuration<'a>> for Newtype { #[allow(clippy::needless_update)] - fn from(conf: &Configuration) -> Self { + fn from(conf: &Configuration<'a>) -> Self { Self(httpd_config_t { task_priority: 5, stack_size: conf.stack_size as _, @@ -144,17 +182,31 @@ impl From> for Method { } #[cfg(esp_idf_esp_https_server_enable)] -impl From<&Configuration> for Newtype { - fn from(conf: &Configuration) -> Self { +impl<'a> From<&Configuration<'a>> for Newtype { + fn from(conf: &Configuration<'a>) -> Self { let http_config: Newtype = conf.into(); // start in insecure mode if no certificates are set - let transport_mode = match (conf.server_certificate, conf.private_key) { - (Some(_), Some(_)) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE, + + #[cfg(not(esp_idf_esp_tls_server_sni_hook))] + let transport_mode = match (conf.server_certificate.is_some(), conf.private_key.is_some()) { + (true, true) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE, _ => { warn!("Starting server in insecure mode because no certificates were set in the http config."); httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_INSECURE } }; + + #[cfg(esp_idf_esp_tls_server_sni_hook)] + let transport_mode = match (conf.server_certificate.is_some(), conf.private_key.is_some(), conf.sni.is_some()) { + (_, _, true) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE, + (true, true, _) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE, + _ => { + warn!("Starting server in insecure mode because no certificates were set in the http config and no SNI callback is defined."); + httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_INSECURE + } + }; + + // Default values taken from: https://github.com/espressif/esp-idf/blob/master/components/esp_https_server/include/esp_https_server.h#L114 Self(httpd_ssl_config_t { httpd: http_config.0, @@ -166,9 +218,15 @@ impl From<&Configuration> for Newtype { cacert_len: 0, prvtkey_pem: ptr::null(), prvtkey_len: 0, - client_verify_cert_pem: ptr::null(), - client_verify_cert_len: 0, + servercert: ptr::null(), + servercert_len: 0, user_cb: None, + #[cfg(esp_idf_version_major = "5")] + use_secure_element: false, + #[cfg(esp_idf_esp_tls_server_sni_hook)] + sni_callback: Some(sni_trampoline), + #[cfg(esp_idf_esp_tls_server_sni_hook)] + sni_callback_p_info: conf.sni.as_ref().map(|cb| cb as *const _ as *mut c_types::c_void).unwrap_or(ptr::null_mut()), }) } } @@ -249,16 +307,27 @@ impl EspHttpServer { let cert = CString::new(cert).unwrap().into_bytes_with_nul(); let private_key = CString::new(private_key).unwrap().into_bytes_with_nul(); - config.0.cacert_pem = cert.as_ptr(); - config.0.cacert_len = cert.len() as u32; + #[cfg(not(esp_idf_version_major = "5"))] + { + config.0.cacert_pem = cert.as_ptr(); + config.0.cacert_len = cert.len() as u32; - config.0.prvtkey_pem = private_key.as_ptr() as _; - config.0.prvtkey_len = private_key.len() as u32; + config.0.prvtkey_pem = private_key.as_ptr() as _; + config.0.prvtkey_len = private_key.len() as u32; + }; + + #[cfg(esp_idf_version_major = "5")] + { + config.0.servercert = cert.as_ptr(); + config.0.servercert_len = cert.len() as u32; + + config.0.prvtkey_pem = private_key.as_ptr() as _; + config.0.prvtkey_len = private_key.len() as u32; + }; - esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?; - } else { - esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?; } + + esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?; } info!("Started Httpd server with config {:?}", conf); diff --git a/src/http/sni.rs b/src/http/sni.rs new file mode 100644 index 00000000000..685fbd89752 --- /dev/null +++ b/src/http/sni.rs @@ -0,0 +1,85 @@ +use std::ffi::CStr; +use std::ptr; +use esp_idf_sys::*; +use log::*; + +// Workaround for unstable feature 'trait_alias' +pub trait SNICB<'a>: FnMut(&'a str) -> SNIResult<'a> { } + +// Workaround for unstable feature 'trait_alias' +impl<'a, T> SNICB<'a> for T + where T: FnMut(&'a str) -> SNIResult<'a> { +} + +pub struct HandshakeServerCertificate<'a> { + pub pk: &'a mut mbedtls_pk_context, + pub cert: &'a mut mbedtls_x509_crt, +} + +pub struct HandshakeCertifiacteAuthority<'a> { + pub ca: &'a mut mbedtls_x509_crt, + pub crl: &'a mut mbedtls_x509_crl, +} + +pub struct HandshakeVerifyMode(c_types::c_int); + +pub struct SNIResult<'a> { + server_certificate: Option>, + certificate_authority: Option>, + verify_mode: Option +} + +impl<'a> SNIResult<'a> { + pub fn new() -> SNIResult<'a> { SNIResult { server_certificate: None, certificate_authority: None, verify_mode: None }} + + pub fn set_hs_server_certficate(mut self, pk: &'a mut mbedtls_pk_context, cert: &'a mut mbedtls_x509_crt) -> SNIResult<'a> { + self.server_certificate = Some(HandshakeServerCertificate { pk, cert }); + self + } + + pub fn set_hs_certificate_authority(mut self, ca: &'a mut mbedtls_x509_crt, crl: &'a mut mbedtls_x509_crl) -> SNIResult<'a> { + self.certificate_authority = Some(HandshakeCertifiacteAuthority { ca, crl }); + self + } + + pub fn set_hs_verify_mode(mut self, verify_mode: u32) -> SNIResult<'a> { + self.verify_mode = Some(HandshakeVerifyMode(verify_mode as _)); + self + } +} + +unsafe extern "C" fn f_rng(_arg: *mut c_types::c_void, ptr: *mut u8 , bytes: u32) -> i32 { + esp_fill_random(ptr as _, bytes); + bytes as _ +} + +pub(crate) unsafe extern "C" fn sni_trampoline<'a>(p_info: *mut c_types::c_void, ssl: *mut mbedtls_ssl_context, name: *const c_types::c_uchar, _len: c_types::c_uint) -> esp_err_t +{ + let cb = &mut *(p_info as *mut Box>); + + let name = CStr::from_ptr(name as _).to_str().unwrap(); + + let SNIResult { server_certificate, certificate_authority, verify_mode } = cb(name); + + if let Some(HandshakeServerCertificate { pk, cert }) = server_certificate { + if let Err(err) = esp!(mbedtls_pk_check_pair(&mut cert.pk, pk, Some(f_rng), ptr::null_mut())) { + error!("Certificate and private key supplied by the SNI callback do not match: {:?}", err); + return err.code() + }; + + if let Err(err) = esp!(mbedtls_ssl_set_hs_own_cert(ssl, cert, pk)) { + error!("Could not set handshake certificate and private key: {:?}", err); + return err.code() + }; + }; + + if let Some(HandshakeCertifiacteAuthority { ca, crl }) = certificate_authority { + mbedtls_ssl_set_hs_ca_chain(ssl, ca, crl) + }; + + if let Some(HandshakeVerifyMode(authmode)) = verify_mode { + mbedtls_ssl_set_hs_authmode(ssl, authmode) + }; + + return ESP_OK; +} From 7dba47edc5c8608ab4ca082a50ce140bc0322628 Mon Sep 17 00:00:00 2001 From: Akos Vandra Date: Mon, 10 Oct 2022 17:42:13 +0200 Subject: [PATCH 2/2] updated to use cert select callback instead of the sni callback. --- src/http.rs | 7 ++- src/http/cert_select.rs | 131 ++++++++++++++++++++++++++++++++++++++++ src/http/server.rs | 116 ++++++++++++++++++++++++----------- src/http/sni.rs | 85 -------------------------- 4 files changed, 218 insertions(+), 121 deletions(-) create mode 100644 src/http/cert_select.rs delete mode 100644 src/http/sni.rs diff --git a/src/http.rs b/src/http.rs index 8e518ac4a5b..4212383c147 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,6 +1,9 @@ +#[cfg(all( + esp_idf_esp_tls_server_cert_select_hook, + esp_idf_comp_esp_http_server_enabled +))] +pub mod cert_select; #[cfg(esp_idf_comp_esp_http_client_enabled)] pub mod client; #[cfg(esp_idf_comp_esp_http_server_enabled)] pub mod server; -#[cfg(all(esp_idf_esp_tls_server_sni_hook, esp_idf_comp_esp_http_server_enabled))] -pub mod sni; diff --git a/src/http/cert_select.rs b/src/http/cert_select.rs new file mode 100644 index 00000000000..3d83ceaada3 --- /dev/null +++ b/src/http/cert_select.rs @@ -0,0 +1,131 @@ +use esp_idf_sys::*; +use log::*; +use std::ffi::CStr; +use std::ptr; + +// Workaround for unstable feature 'trait_alias' +pub trait CertSelectCallback<'a>: FnMut(&'a str) -> CallbackResult<'a> {} + +// Workaround for unstable feature 'trait_alias' +impl<'a, T> CertSelectCallback<'a> for T where T: FnMut(&'a str) -> CallbackResult<'a> {} + +pub struct HandshakeServerCertificate<'a> { + pub pk: &'a mut mbedtls_pk_context, + pub cert: &'a mut mbedtls_x509_crt, +} + +pub struct HandshakeCertifiacteAuthority<'a> { + pub ca: &'a mut mbedtls_x509_crt, + pub crl: &'a mut mbedtls_x509_crl, +} + +pub struct HandshakeVerifyMode(c_types::c_int); + +pub struct CallbackResult<'a> { + server_certificate: Option>, + certificate_authority: Option>, + verify_mode: Option, +} + +impl<'a> CallbackResult<'a> { + pub fn new() -> CallbackResult<'a> { + CallbackResult { + server_certificate: None, + certificate_authority: None, + verify_mode: None, + } + } + + pub fn set_hs_server_certficate( + mut self, + pk: &'a mut mbedtls_pk_context, + cert: &'a mut mbedtls_x509_crt, + ) -> CallbackResult<'a> { + self.server_certificate = Some(HandshakeServerCertificate { pk, cert }); + self + } + + pub fn set_hs_certificate_authority( + mut self, + ca: &'a mut mbedtls_x509_crt, + crl: &'a mut mbedtls_x509_crl, + ) -> CallbackResult<'a> { + self.certificate_authority = Some(HandshakeCertifiacteAuthority { ca, crl }); + self + } + + pub fn set_hs_verify_mode(mut self, verify_mode: u32) -> CallbackResult<'a> { + self.verify_mode = Some(HandshakeVerifyMode(verify_mode as _)); + self + } +} + +unsafe extern "C" fn f_rng(_arg: *mut c_types::c_void, ptr: *mut u8, bytes: u32) -> i32 { + esp_fill_random(ptr as _, bytes); + bytes as _ +} + +pub(crate) unsafe extern "C" fn cert_select_trampoline<'a>( + ssl: *mut mbedtls_ssl_context, +) -> esp_err_t { + // Need to use ->private_user_data as the getter function is static inline, and + // bindgen can't generate bindings for static inline yet. + // https://github.com/rust-lang/rust-bindgen/issues/1090 + + let ssl_conf = (*ssl).private_conf; + + if ssl_conf == ptr::null_mut() { + return ESP_ERR_INVALID_ARG; + } + + let cb_ptr = (*ssl_conf).private_user_data.p; + + if cb_ptr == ptr::null_mut() { + return ESP_ERR_INVALID_ARG; + } + + let cb = &mut *(cb_ptr as *mut Box>); + let mut namelen: u32 = 0; + + let name = mbedtls_ssl_get_hs_sni(ssl, &mut namelen); + let name = CStr::from_ptr(name as _).to_str().unwrap(); + + let CallbackResult { + server_certificate, + certificate_authority, + verify_mode, + } = cb(name); + + if let Some(HandshakeServerCertificate { pk, cert }) = server_certificate { + if let Err(err) = esp!(mbedtls_pk_check_pair( + &mut cert.pk, + pk, + Some(f_rng), + ptr::null_mut() + )) { + error!( + "Certificate and private key supplied by the SNI callback do not match: {:?}", + err + ); + return err.code(); + }; + + if let Err(err) = esp!(mbedtls_ssl_set_hs_own_cert(ssl, cert, pk)) { + error!( + "Could not set handshake certificate and private key: {:?}", + err + ); + return err.code(); + }; + }; + + if let Some(HandshakeCertifiacteAuthority { ca, crl }) = certificate_authority { + mbedtls_ssl_set_hs_ca_chain(ssl, ca, crl) + }; + + if let Some(HandshakeVerifyMode(authmode)) = verify_mode { + mbedtls_ssl_set_hs_authmode(ssl, authmode) + }; + + return ESP_OK; +} diff --git a/src/http/server.rs b/src/http/server.rs index 534b440b3df..813c200e759 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -30,10 +30,19 @@ use crate::private::common::Newtype; use crate::private::cstr::{CStr, CString}; use crate::private::mutex::{Mutex, RawMutex}; -#[cfg(all(esp_idf_esp_tls_server_sni_hook, esp_idf_comp_esp_http_server_enabled))] -use super::sni::*; - -#[cfg_attr(not(esp_idf_esp_tls_server_sni_hook), derive(Debug))] +#[cfg(all( + esp_idf_esp_tls_server_cert_select_hook, + esp_idf_comp_esp_http_server_enabled +))] +use super::cert_select::*; + +#[cfg_attr( + not(all( + esp_idf_esp_https_server_enable, + esp_idf_esp_tls_server_cert_select_hook + )), + derive(Debug) +)] pub struct Configuration<'a> { pub http_port: u16, pub https_port: u16, @@ -48,10 +57,16 @@ pub struct Configuration<'a> { pub server_certificate: Option<&'static str>, #[cfg(esp_idf_esp_https_server_enable)] pub private_key: Option<&'static str>, - #[cfg(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook))] - pub sni: Option>>, - #[cfg(not(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook)))] - pub _phantom_data: std::marker::PhantomData<&'a ()> + #[cfg(all( + esp_idf_esp_https_server_enable, + esp_idf_esp_tls_server_cert_select_hook + ))] + pub cert_select: Option>>, + #[cfg(not(all( + esp_idf_esp_https_server_enable, + esp_idf_esp_tls_server_cert_select_hook + )))] + pub _phantom_data: std::marker::PhantomData<&'a ()>, } impl<'a> Default for Configuration<'a> { @@ -73,25 +88,40 @@ impl<'a> Default for Configuration<'a> { server_certificate: None, #[cfg(esp_idf_esp_https_server_enable)] private_key: None, - #[cfg(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook))] - sni: None, - #[cfg(not(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook)))] - _phantom_data: Default::default() + #[cfg(all( + esp_idf_esp_https_server_enable, + esp_idf_esp_tls_server_cert_select_hook + ))] + cert_select: None, + #[cfg(not(all( + esp_idf_esp_https_server_enable, + esp_idf_esp_tls_server_cert_select_hook + )))] + _phantom_data: Default::default(), } } } -//TODO: Can we simply ignore the sni field in the Derive macro somehow? Derivative crate is supposed to be for that, but can't get it to work -#[cfg(esp_idf_esp_tls_server_sni_hook)] +//TODO: Can we simply ignore the cert select field in the Derive macro somehow? Derivative crate is supposed to be for that, but can't get it to work +#[cfg(all( + esp_idf_esp_https_server_enable, + esp_idf_esp_tls_server_cert_select_hook +))] impl<'a> Debug for Configuration<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - - let sni_s = if self.sni.is_some() { - "Some(..)" - } else { "None" }; + let cert_select_s = if self.cert_select.is_some() { + let ptr = self + .cert_select + .as_ref() + .map(|cb| cb as *const _ as *mut c_types::c_void) + .unwrap_or(ptr::null_mut()); + format!("Some({:?})", ptr) + } else { + "None".into() + }; f.write_fmt(format_args!( - "Configuration {{ http_port = {}, https_port = {}, max_sessions = {}, session_timeout = {:?}, stack_size = {}, max_open_sockets = {}, max_uri_handlers = {}, max_resp_handlers = {}, lru_purge_enable = {}, server_certificate = {:?}, private_key = {:?}, sni = {} }}", + "Configuration {{ http_port = {}, https_port = {}, max_sessions = {}, session_timeout = {:?}, stack_size = {}, max_open_sockets = {}, max_uri_handlers = {}, max_resp_handlers = {}, lru_purge_enable = {}, server_certificate = {:?}, private_key = {:?}, cert_select = {} }}", self.http_port, self.https_port, self.max_sessions, @@ -103,7 +133,7 @@ impl<'a> Debug for Configuration<'a> { self.lru_purge_enable, self.server_certificate, self.private_key, - sni_s + cert_select_s )) } } @@ -187,8 +217,11 @@ impl<'a> From<&Configuration<'a>> for Newtype { let http_config: Newtype = conf.into(); // start in insecure mode if no certificates are set - #[cfg(not(esp_idf_esp_tls_server_sni_hook))] - let transport_mode = match (conf.server_certificate.is_some(), conf.private_key.is_some()) { + #[cfg(not(esp_idf_esp_tls_server_cert_select_hook))] + let transport_mode = match ( + conf.server_certificate.is_some(), + conf.private_key.is_some(), + ) { (true, true) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE, _ => { warn!("Starting server in insecure mode because no certificates were set in the http config."); @@ -196,17 +229,20 @@ impl<'a> From<&Configuration<'a>> for Newtype { } }; - #[cfg(esp_idf_esp_tls_server_sni_hook)] - let transport_mode = match (conf.server_certificate.is_some(), conf.private_key.is_some(), conf.sni.is_some()) { + #[cfg(esp_idf_esp_tls_server_cert_select_hook)] + let transport_mode = match ( + conf.server_certificate.is_some(), + conf.private_key.is_some(), + conf.cert_select.is_some(), + ) { (_, _, true) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE, (true, true, _) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE, _ => { - warn!("Starting server in insecure mode because no certificates were set in the http config and no SNI callback is defined."); + warn!("Starting server in insecure mode because no certificates were set in the http config and no certificate selection callback is defined."); httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_INSECURE } }; - // Default values taken from: https://github.com/espressif/esp-idf/blob/master/components/esp_https_server/include/esp_https_server.h#L114 Self(httpd_ssl_config_t { httpd: http_config.0, @@ -218,15 +254,27 @@ impl<'a> From<&Configuration<'a>> for Newtype { cacert_len: 0, prvtkey_pem: ptr::null(), prvtkey_len: 0, + #[cfg(esp_idf_version_major = "5")] servercert: ptr::null(), + #[cfg(esp_idf_version_major = "5")] servercert_len: 0, + #[cfg(esp_idf_version_major = "4")] + client_verify_cert_pem: ptr::null(), + #[cfg(esp_idf_version_major = "4")] + client_verify_cert_len: 0, user_cb: None, #[cfg(esp_idf_version_major = "5")] use_secure_element: false, - #[cfg(esp_idf_esp_tls_server_sni_hook)] - sni_callback: Some(sni_trampoline), - #[cfg(esp_idf_esp_tls_server_sni_hook)] - sni_callback_p_info: conf.sni.as_ref().map(|cb| cb as *const _ as *mut c_types::c_void).unwrap_or(ptr::null_mut()), + #[cfg(esp_idf_esp_tls_server_cert_select_hook)] + cert_select_cb: Some(cert_select_trampoline), + #[cfg(esp_idf_esp_tls_server_cert_select_hook)] + ssl_userdata: conf + .cert_select + .as_ref() + .map(|cb| cb as *const _ as *mut c_types::c_void) + .unwrap_or(ptr::null_mut()), + #[cfg(not(esp_idf_esp_tls_server_cert_select_hook))] + ssl_userdata: ptr::null_mut(), }) } } @@ -325,13 +373,13 @@ impl EspHttpServer { config.0.prvtkey_len = private_key.len() as u32; }; + //See above why this is duplicated + esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?; + } else { + esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?; } - - esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?; } - info!("Started Httpd server with config {:?}", conf); - let server = EspHttpServer { sd: handle, registrations: Vec::new(), diff --git a/src/http/sni.rs b/src/http/sni.rs deleted file mode 100644 index 685fbd89752..00000000000 --- a/src/http/sni.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::ffi::CStr; -use std::ptr; -use esp_idf_sys::*; -use log::*; - -// Workaround for unstable feature 'trait_alias' -pub trait SNICB<'a>: FnMut(&'a str) -> SNIResult<'a> { } - -// Workaround for unstable feature 'trait_alias' -impl<'a, T> SNICB<'a> for T - where T: FnMut(&'a str) -> SNIResult<'a> { -} - -pub struct HandshakeServerCertificate<'a> { - pub pk: &'a mut mbedtls_pk_context, - pub cert: &'a mut mbedtls_x509_crt, -} - -pub struct HandshakeCertifiacteAuthority<'a> { - pub ca: &'a mut mbedtls_x509_crt, - pub crl: &'a mut mbedtls_x509_crl, -} - -pub struct HandshakeVerifyMode(c_types::c_int); - -pub struct SNIResult<'a> { - server_certificate: Option>, - certificate_authority: Option>, - verify_mode: Option -} - -impl<'a> SNIResult<'a> { - pub fn new() -> SNIResult<'a> { SNIResult { server_certificate: None, certificate_authority: None, verify_mode: None }} - - pub fn set_hs_server_certficate(mut self, pk: &'a mut mbedtls_pk_context, cert: &'a mut mbedtls_x509_crt) -> SNIResult<'a> { - self.server_certificate = Some(HandshakeServerCertificate { pk, cert }); - self - } - - pub fn set_hs_certificate_authority(mut self, ca: &'a mut mbedtls_x509_crt, crl: &'a mut mbedtls_x509_crl) -> SNIResult<'a> { - self.certificate_authority = Some(HandshakeCertifiacteAuthority { ca, crl }); - self - } - - pub fn set_hs_verify_mode(mut self, verify_mode: u32) -> SNIResult<'a> { - self.verify_mode = Some(HandshakeVerifyMode(verify_mode as _)); - self - } -} - -unsafe extern "C" fn f_rng(_arg: *mut c_types::c_void, ptr: *mut u8 , bytes: u32) -> i32 { - esp_fill_random(ptr as _, bytes); - bytes as _ -} - -pub(crate) unsafe extern "C" fn sni_trampoline<'a>(p_info: *mut c_types::c_void, ssl: *mut mbedtls_ssl_context, name: *const c_types::c_uchar, _len: c_types::c_uint) -> esp_err_t -{ - let cb = &mut *(p_info as *mut Box>); - - let name = CStr::from_ptr(name as _).to_str().unwrap(); - - let SNIResult { server_certificate, certificate_authority, verify_mode } = cb(name); - - if let Some(HandshakeServerCertificate { pk, cert }) = server_certificate { - if let Err(err) = esp!(mbedtls_pk_check_pair(&mut cert.pk, pk, Some(f_rng), ptr::null_mut())) { - error!("Certificate and private key supplied by the SNI callback do not match: {:?}", err); - return err.code() - }; - - if let Err(err) = esp!(mbedtls_ssl_set_hs_own_cert(ssl, cert, pk)) { - error!("Could not set handshake certificate and private key: {:?}", err); - return err.code() - }; - }; - - if let Some(HandshakeCertifiacteAuthority { ca, crl }) = certificate_authority { - mbedtls_ssl_set_hs_ca_chain(ssl, ca, crl) - }; - - if let Some(HandshakeVerifyMode(authmode)) = verify_mode { - mbedtls_ssl_set_hs_authmode(ssl, authmode) - }; - - return ESP_OK; -}