Skip to content

Commit 7dba47e

Browse files
committed
updated to use cert select callback instead of the sni callback.
1 parent 634104c commit 7dba47e

File tree

4 files changed

+218
-121
lines changed

4 files changed

+218
-121
lines changed

src/http.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
#[cfg(all(
2+
esp_idf_esp_tls_server_cert_select_hook,
3+
esp_idf_comp_esp_http_server_enabled
4+
))]
5+
pub mod cert_select;
16
#[cfg(esp_idf_comp_esp_http_client_enabled)]
27
pub mod client;
38
#[cfg(esp_idf_comp_esp_http_server_enabled)]
49
pub mod server;
5-
#[cfg(all(esp_idf_esp_tls_server_sni_hook, esp_idf_comp_esp_http_server_enabled))]
6-
pub mod sni;

src/http/cert_select.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use esp_idf_sys::*;
2+
use log::*;
3+
use std::ffi::CStr;
4+
use std::ptr;
5+
6+
// Workaround for unstable feature 'trait_alias'
7+
pub trait CertSelectCallback<'a>: FnMut(&'a str) -> CallbackResult<'a> {}
8+
9+
// Workaround for unstable feature 'trait_alias'
10+
impl<'a, T> CertSelectCallback<'a> for T where T: FnMut(&'a str) -> CallbackResult<'a> {}
11+
12+
pub struct HandshakeServerCertificate<'a> {
13+
pub pk: &'a mut mbedtls_pk_context,
14+
pub cert: &'a mut mbedtls_x509_crt,
15+
}
16+
17+
pub struct HandshakeCertifiacteAuthority<'a> {
18+
pub ca: &'a mut mbedtls_x509_crt,
19+
pub crl: &'a mut mbedtls_x509_crl,
20+
}
21+
22+
pub struct HandshakeVerifyMode(c_types::c_int);
23+
24+
pub struct CallbackResult<'a> {
25+
server_certificate: Option<HandshakeServerCertificate<'a>>,
26+
certificate_authority: Option<HandshakeCertifiacteAuthority<'a>>,
27+
verify_mode: Option<HandshakeVerifyMode>,
28+
}
29+
30+
impl<'a> CallbackResult<'a> {
31+
pub fn new() -> CallbackResult<'a> {
32+
CallbackResult {
33+
server_certificate: None,
34+
certificate_authority: None,
35+
verify_mode: None,
36+
}
37+
}
38+
39+
pub fn set_hs_server_certficate(
40+
mut self,
41+
pk: &'a mut mbedtls_pk_context,
42+
cert: &'a mut mbedtls_x509_crt,
43+
) -> CallbackResult<'a> {
44+
self.server_certificate = Some(HandshakeServerCertificate { pk, cert });
45+
self
46+
}
47+
48+
pub fn set_hs_certificate_authority(
49+
mut self,
50+
ca: &'a mut mbedtls_x509_crt,
51+
crl: &'a mut mbedtls_x509_crl,
52+
) -> CallbackResult<'a> {
53+
self.certificate_authority = Some(HandshakeCertifiacteAuthority { ca, crl });
54+
self
55+
}
56+
57+
pub fn set_hs_verify_mode(mut self, verify_mode: u32) -> CallbackResult<'a> {
58+
self.verify_mode = Some(HandshakeVerifyMode(verify_mode as _));
59+
self
60+
}
61+
}
62+
63+
unsafe extern "C" fn f_rng(_arg: *mut c_types::c_void, ptr: *mut u8, bytes: u32) -> i32 {
64+
esp_fill_random(ptr as _, bytes);
65+
bytes as _
66+
}
67+
68+
pub(crate) unsafe extern "C" fn cert_select_trampoline<'a>(
69+
ssl: *mut mbedtls_ssl_context,
70+
) -> esp_err_t {
71+
// Need to use ->private_user_data as the getter function is static inline, and
72+
// bindgen can't generate bindings for static inline yet.
73+
// https://github.com/rust-lang/rust-bindgen/issues/1090
74+
75+
let ssl_conf = (*ssl).private_conf;
76+
77+
if ssl_conf == ptr::null_mut() {
78+
return ESP_ERR_INVALID_ARG;
79+
}
80+
81+
let cb_ptr = (*ssl_conf).private_user_data.p;
82+
83+
if cb_ptr == ptr::null_mut() {
84+
return ESP_ERR_INVALID_ARG;
85+
}
86+
87+
let cb = &mut *(cb_ptr as *mut Box<dyn CertSelectCallback<'a>>);
88+
let mut namelen: u32 = 0;
89+
90+
let name = mbedtls_ssl_get_hs_sni(ssl, &mut namelen);
91+
let name = CStr::from_ptr(name as _).to_str().unwrap();
92+
93+
let CallbackResult {
94+
server_certificate,
95+
certificate_authority,
96+
verify_mode,
97+
} = cb(name);
98+
99+
if let Some(HandshakeServerCertificate { pk, cert }) = server_certificate {
100+
if let Err(err) = esp!(mbedtls_pk_check_pair(
101+
&mut cert.pk,
102+
pk,
103+
Some(f_rng),
104+
ptr::null_mut()
105+
)) {
106+
error!(
107+
"Certificate and private key supplied by the SNI callback do not match: {:?}",
108+
err
109+
);
110+
return err.code();
111+
};
112+
113+
if let Err(err) = esp!(mbedtls_ssl_set_hs_own_cert(ssl, cert, pk)) {
114+
error!(
115+
"Could not set handshake certificate and private key: {:?}",
116+
err
117+
);
118+
return err.code();
119+
};
120+
};
121+
122+
if let Some(HandshakeCertifiacteAuthority { ca, crl }) = certificate_authority {
123+
mbedtls_ssl_set_hs_ca_chain(ssl, ca, crl)
124+
};
125+
126+
if let Some(HandshakeVerifyMode(authmode)) = verify_mode {
127+
mbedtls_ssl_set_hs_authmode(ssl, authmode)
128+
};
129+
130+
return ESP_OK;
131+
}

src/http/server.rs

Lines changed: 82 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,19 @@ use crate::private::common::Newtype;
3030
use crate::private::cstr::{CStr, CString};
3131
use crate::private::mutex::{Mutex, RawMutex};
3232

33-
#[cfg(all(esp_idf_esp_tls_server_sni_hook, esp_idf_comp_esp_http_server_enabled))]
34-
use super::sni::*;
35-
36-
#[cfg_attr(not(esp_idf_esp_tls_server_sni_hook), derive(Debug))]
33+
#[cfg(all(
34+
esp_idf_esp_tls_server_cert_select_hook,
35+
esp_idf_comp_esp_http_server_enabled
36+
))]
37+
use super::cert_select::*;
38+
39+
#[cfg_attr(
40+
not(all(
41+
esp_idf_esp_https_server_enable,
42+
esp_idf_esp_tls_server_cert_select_hook
43+
)),
44+
derive(Debug)
45+
)]
3746
pub struct Configuration<'a> {
3847
pub http_port: u16,
3948
pub https_port: u16,
@@ -48,10 +57,16 @@ pub struct Configuration<'a> {
4857
pub server_certificate: Option<&'static str>,
4958
#[cfg(esp_idf_esp_https_server_enable)]
5059
pub private_key: Option<&'static str>,
51-
#[cfg(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook))]
52-
pub sni: Option<Box<dyn SNICB<'a>>>,
53-
#[cfg(not(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook)))]
54-
pub _phantom_data: std::marker::PhantomData<&'a ()>
60+
#[cfg(all(
61+
esp_idf_esp_https_server_enable,
62+
esp_idf_esp_tls_server_cert_select_hook
63+
))]
64+
pub cert_select: Option<Box<dyn CertSelectCallback<'a>>>,
65+
#[cfg(not(all(
66+
esp_idf_esp_https_server_enable,
67+
esp_idf_esp_tls_server_cert_select_hook
68+
)))]
69+
pub _phantom_data: std::marker::PhantomData<&'a ()>,
5570
}
5671

5772
impl<'a> Default for Configuration<'a> {
@@ -73,25 +88,40 @@ impl<'a> Default for Configuration<'a> {
7388
server_certificate: None,
7489
#[cfg(esp_idf_esp_https_server_enable)]
7590
private_key: None,
76-
#[cfg(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook))]
77-
sni: None,
78-
#[cfg(not(all(esp_idf_esp_https_server_enable, esp_idf_esp_tls_server_sni_hook)))]
79-
_phantom_data: Default::default()
91+
#[cfg(all(
92+
esp_idf_esp_https_server_enable,
93+
esp_idf_esp_tls_server_cert_select_hook
94+
))]
95+
cert_select: None,
96+
#[cfg(not(all(
97+
esp_idf_esp_https_server_enable,
98+
esp_idf_esp_tls_server_cert_select_hook
99+
)))]
100+
_phantom_data: Default::default(),
80101
}
81102
}
82103
}
83104

84-
//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
85-
#[cfg(esp_idf_esp_tls_server_sni_hook)]
105+
//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
106+
#[cfg(all(
107+
esp_idf_esp_https_server_enable,
108+
esp_idf_esp_tls_server_cert_select_hook
109+
))]
86110
impl<'a> Debug for Configuration<'a> {
87111
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
88-
89-
let sni_s = if self.sni.is_some() {
90-
"Some(..)"
91-
} else { "None" };
112+
let cert_select_s = if self.cert_select.is_some() {
113+
let ptr = self
114+
.cert_select
115+
.as_ref()
116+
.map(|cb| cb as *const _ as *mut c_types::c_void)
117+
.unwrap_or(ptr::null_mut());
118+
format!("Some({:?})", ptr)
119+
} else {
120+
"None".into()
121+
};
92122

93123
f.write_fmt(format_args!(
94-
"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 = {} }}",
124+
"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 = {} }}",
95125
self.http_port,
96126
self.https_port,
97127
self.max_sessions,
@@ -103,7 +133,7 @@ impl<'a> Debug for Configuration<'a> {
103133
self.lru_purge_enable,
104134
self.server_certificate,
105135
self.private_key,
106-
sni_s
136+
cert_select_s
107137
))
108138
}
109139
}
@@ -187,26 +217,32 @@ impl<'a> From<&Configuration<'a>> for Newtype<httpd_ssl_config_t> {
187217
let http_config: Newtype<httpd_config_t> = conf.into();
188218
// start in insecure mode if no certificates are set
189219

190-
#[cfg(not(esp_idf_esp_tls_server_sni_hook))]
191-
let transport_mode = match (conf.server_certificate.is_some(), conf.private_key.is_some()) {
220+
#[cfg(not(esp_idf_esp_tls_server_cert_select_hook))]
221+
let transport_mode = match (
222+
conf.server_certificate.is_some(),
223+
conf.private_key.is_some(),
224+
) {
192225
(true, true) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE,
193226
_ => {
194227
warn!("Starting server in insecure mode because no certificates were set in the http config.");
195228
httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_INSECURE
196229
}
197230
};
198231

199-
#[cfg(esp_idf_esp_tls_server_sni_hook)]
200-
let transport_mode = match (conf.server_certificate.is_some(), conf.private_key.is_some(), conf.sni.is_some()) {
232+
#[cfg(esp_idf_esp_tls_server_cert_select_hook)]
233+
let transport_mode = match (
234+
conf.server_certificate.is_some(),
235+
conf.private_key.is_some(),
236+
conf.cert_select.is_some(),
237+
) {
201238
(_, _, true) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE,
202239
(true, true, _) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE,
203240
_ => {
204-
warn!("Starting server in insecure mode because no certificates were set in the http config and no SNI callback is defined.");
241+
warn!("Starting server in insecure mode because no certificates were set in the http config and no certificate selection callback is defined.");
205242
httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_INSECURE
206243
}
207244
};
208245

209-
210246
// Default values taken from: https://github.com/espressif/esp-idf/blob/master/components/esp_https_server/include/esp_https_server.h#L114
211247
Self(httpd_ssl_config_t {
212248
httpd: http_config.0,
@@ -218,15 +254,27 @@ impl<'a> From<&Configuration<'a>> for Newtype<httpd_ssl_config_t> {
218254
cacert_len: 0,
219255
prvtkey_pem: ptr::null(),
220256
prvtkey_len: 0,
257+
#[cfg(esp_idf_version_major = "5")]
221258
servercert: ptr::null(),
259+
#[cfg(esp_idf_version_major = "5")]
222260
servercert_len: 0,
261+
#[cfg(esp_idf_version_major = "4")]
262+
client_verify_cert_pem: ptr::null(),
263+
#[cfg(esp_idf_version_major = "4")]
264+
client_verify_cert_len: 0,
223265
user_cb: None,
224266
#[cfg(esp_idf_version_major = "5")]
225267
use_secure_element: false,
226-
#[cfg(esp_idf_esp_tls_server_sni_hook)]
227-
sni_callback: Some(sni_trampoline),
228-
#[cfg(esp_idf_esp_tls_server_sni_hook)]
229-
sni_callback_p_info: conf.sni.as_ref().map(|cb| cb as *const _ as *mut c_types::c_void).unwrap_or(ptr::null_mut()),
268+
#[cfg(esp_idf_esp_tls_server_cert_select_hook)]
269+
cert_select_cb: Some(cert_select_trampoline),
270+
#[cfg(esp_idf_esp_tls_server_cert_select_hook)]
271+
ssl_userdata: conf
272+
.cert_select
273+
.as_ref()
274+
.map(|cb| cb as *const _ as *mut c_types::c_void)
275+
.unwrap_or(ptr::null_mut()),
276+
#[cfg(not(esp_idf_esp_tls_server_cert_select_hook))]
277+
ssl_userdata: ptr::null_mut(),
230278
})
231279
}
232280
}
@@ -325,13 +373,13 @@ impl EspHttpServer {
325373
config.0.prvtkey_len = private_key.len() as u32;
326374
};
327375

376+
//See above why this is duplicated
377+
esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?;
378+
} else {
379+
esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?;
328380
}
329-
330-
esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?;
331381
}
332382

333-
info!("Started Httpd server with config {:?}", conf);
334-
335383
let server = EspHttpServer {
336384
sd: handle,
337385
registrations: Vec::new(),

0 commit comments

Comments
 (0)