1#[cfg(all(esp_idf_esp_tls_psk_verification, feature = "alloc"))]
4use core::convert::TryFrom;
5use core::fmt::Debug;
6
7use crate::private::cstr::{c_char, CStr};
8#[cfg(all(esp_idf_esp_tls_psk_verification, feature = "alloc"))]
9use crate::sys::EspError;
10
11#[cfg(all(
12 esp_idf_comp_esp_tls_enabled,
13 any(esp_idf_esp_tls_using_mbedtls, esp_idf_esp_tls_using_wolfssl)
14))]
15pub use self::esptls::*;
16
17#[derive(Copy, Clone, Eq, PartialEq)]
18pub struct Psk<'a> {
19 pub key: &'a [u8],
20 pub hint: &'a str,
21}
22
23impl Debug for Psk<'_> {
24 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
25 f.debug_struct("Psk")
26 .field("hint", &self.hint)
27 .finish_non_exhaustive()
28 }
29}
30
31#[cfg(all(esp_idf_esp_tls_psk_verification, feature = "alloc"))]
37pub(crate) struct TlsPsk {
38 pub(crate) psk: alloc::boxed::Box<crate::hal::sys::psk_hint_key_t>,
39 pub(crate) _cstrs: crate::private::cstr::RawCstrs,
40}
41#[cfg(not(all(esp_idf_esp_tls_psk_verification, feature = "alloc")))]
43#[allow(dead_code)]
44pub(crate) struct TlsPsk {}
45
46#[cfg(all(esp_idf_esp_tls_psk_verification, feature = "alloc"))]
47impl Debug for TlsPsk {
48 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
49 f.debug_struct("TlsPsk")
50 .field("psk", &self.psk)
51 .finish_non_exhaustive()
52 }
53}
54
55#[cfg(all(esp_idf_esp_tls_psk_verification, feature = "alloc"))]
56impl<'a> TryFrom<&'a Psk<'a>> for TlsPsk {
57 type Error = EspError;
58
59 fn try_from(conf: &Psk) -> Result<Self, EspError> {
60 let mut cstrs = crate::private::cstr::RawCstrs::new();
61 let psk = alloc::boxed::Box::new(crate::hal::sys::psk_hint_key_t {
62 key: conf.key.as_ptr(),
63 key_size: conf.key.len(),
64 hint: cstrs.as_ptr(conf.hint)?,
65 });
66
67 Ok(TlsPsk { psk, _cstrs: cstrs })
68 }
69}
70
71#[derive(Copy, Clone, Eq, PartialEq)]
72pub struct X509<'a>(&'a [u8]);
73
74impl<'a> X509<'a> {
75 pub fn pem(cstr: &'a CStr) -> Self {
76 Self(cstr.to_bytes_with_nul())
77 }
78
79 pub const fn pem_until_nul(bytes: &'a [u8]) -> Self {
80 let mut nul_pos = 0;
82 while nul_pos < bytes.len() {
83 if bytes[nul_pos] == 0 {
84 let slice = unsafe { core::slice::from_raw_parts(bytes.as_ptr(), nul_pos + 1) };
86 return Self(slice);
87 }
88 nul_pos += 1;
89 }
90 panic!("PEM certificates should end with a NIL (`\\0`) ASCII character.")
91 }
92
93 pub const fn der(bytes: &'a [u8]) -> Self {
94 Self(bytes)
95 }
96
97 pub fn data(&self) -> &[u8] {
98 self.0
99 }
100
101 #[allow(unused)]
102 pub(crate) fn as_esp_idf_raw_ptr(&self) -> *const c_char {
103 self.data().as_ptr().cast()
104 }
105
106 #[allow(unused)]
107 pub(crate) fn as_esp_idf_raw_len(&self) -> usize {
108 self.data().len()
109 }
110}
111
112impl Debug for X509<'_> {
113 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
114 f.debug_struct("X509").finish_non_exhaustive()
115 }
116}
117
118#[cfg(all(
119 esp_idf_comp_esp_tls_enabled,
120 any(esp_idf_esp_tls_using_mbedtls, esp_idf_esp_tls_using_wolfssl)
121))]
122mod esptls {
123 use core::ffi::c_char;
124 #[cfg(esp_idf_esp_tls_server_cert_select_hook)]
125 use core::ffi::c_int;
126 use core::task::{Context, Poll};
127 use core::time::Duration;
128 #[allow(unused_imports)]
129 use core::{pin::Pin, task::ready};
130
131 use embedded_svc::io;
132
133 use super::X509;
134
135 use crate::{
136 io::EspIOError,
137 private::cstr::{cstr_arr_from_str_slice, cstr_from_str_truncating, CStr},
138 sys::{
139 self, EspError, ESP_ERR_NO_MEM, ESP_FAIL, ESP_TLS_ERR_SSL_WANT_READ,
140 ESP_TLS_ERR_SSL_WANT_WRITE, EWOULDBLOCK,
141 },
142 };
143
144 const MAX_COMMON_NAME_LENGTH: usize = 64;
146
147 pub struct Config<'a> {
148 pub alpn_protos: Option<&'a [&'a str]>,
150 pub ca_cert: Option<X509<'a>>,
151 pub client_cert: Option<X509<'a>>,
152 pub client_key: Option<X509<'a>>,
153 pub client_key_password: Option<&'a str>,
154 pub non_block: bool,
155 pub use_secure_element: bool,
156 pub timeout_ms: u32,
157 pub use_global_ca_store: bool,
158 pub common_name: Option<&'a str>,
159 pub skip_common_name: bool,
160 pub keep_alive_cfg: Option<KeepAliveConfig>,
161 pub psk_hint_key: Option<PskHintKey<'a>>,
162 #[cfg(esp_idf_mbedtls_certificate_bundle)]
164 pub use_crt_bundle_attach: bool,
165 pub is_plain_tcp: bool,
167 }
168
169 impl Config<'_> {
170 pub const fn new() -> Self {
171 Self {
172 alpn_protos: None,
173 ca_cert: None,
174 client_cert: None,
175 client_key: None,
176 client_key_password: None,
177 non_block: false,
178 use_secure_element: false,
179 timeout_ms: 4000,
180 use_global_ca_store: false,
181 common_name: None,
182 skip_common_name: false,
183 keep_alive_cfg: None,
184 psk_hint_key: None,
185 #[cfg(esp_idf_mbedtls_certificate_bundle)]
186 use_crt_bundle_attach: true,
187 is_plain_tcp: false,
188 }
189 }
190
191 fn try_into_raw(&self, bufs: &mut RawConfigBufs) -> Result<sys::esp_tls_cfg, EspError> {
192 let mut rcfg: sys::esp_tls_cfg = Default::default();
193
194 if let Some(ca_cert) = self.ca_cert {
195 rcfg.__bindgen_anon_1.cacert_buf = ca_cert.data().as_ptr();
196 rcfg.__bindgen_anon_2.cacert_bytes = ca_cert.data().len() as u32;
197 }
198
199 if let Some(client_cert) = self.client_cert {
200 rcfg.__bindgen_anon_3.clientcert_buf = client_cert.data().as_ptr();
201 rcfg.__bindgen_anon_4.clientcert_bytes = client_cert.data().len() as u32;
202 }
203
204 if let Some(client_key) = self.client_key {
205 rcfg.__bindgen_anon_5.clientkey_buf = client_key.data().as_ptr();
206 rcfg.__bindgen_anon_6.clientkey_bytes = client_key.data().len() as u32;
207 }
208
209 if let Some(ckp) = self.client_key_password {
210 rcfg.clientkey_password = ckp.as_ptr();
211 rcfg.clientkey_password_len = ckp.len() as u32;
212 }
213
214 if let Some(protos) = self.alpn_protos {
216 bufs.alpn_protos = cstr_arr_from_str_slice(protos, &mut bufs.alpn_protos_cbuf)?;
217 rcfg.alpn_protos = bufs.alpn_protos.as_mut_ptr();
218 }
219
220 rcfg.non_block = self.non_block;
221 rcfg.use_secure_element = self.use_secure_element;
222 rcfg.timeout_ms = self.timeout_ms as i32;
223 rcfg.use_global_ca_store = self.use_global_ca_store;
224
225 if let Some(common_name) = self.common_name {
226 rcfg.common_name =
227 cstr_from_str_truncating(common_name, &mut bufs.common_name_buf).as_ptr();
228 }
229
230 rcfg.skip_common_name = self.skip_common_name;
231
232 let mut raw_kac: sys::tls_keep_alive_cfg;
233 if let Some(kac) = &self.keep_alive_cfg {
234 raw_kac = sys::tls_keep_alive_cfg {
235 keep_alive_enable: kac.enable,
236 keep_alive_idle: kac.idle.as_secs() as i32,
237 keep_alive_interval: kac.interval.as_secs() as i32,
238 keep_alive_count: kac.count as i32,
239 };
240 rcfg.keep_alive_cfg = &mut raw_kac as *mut _;
241 }
242
243 #[cfg(any(
244 esp_idf_esp_tls_psk_verification,
245 esp_idf_version_major = "4",
246 esp_idf_version = "5.0",
247 esp_idf_version = "5.1",
248 esp_idf_version = "5.2",
249 esp_idf_version = "5.3",
250 esp_idf_version = "5.4",
251 ))]
252 {
253 let mut raw_psk: sys::psk_key_hint;
254 if let Some(psk) = &self.psk_hint_key {
255 raw_psk = sys::psk_key_hint {
256 key: psk.key.as_ptr(),
257 key_size: psk.key.len(),
258 hint: psk.hint.as_ptr(),
259 };
260 rcfg.psk_hint_key = &mut raw_psk as *mut _;
261 }
262 }
263
264 #[cfg(esp_idf_mbedtls_certificate_bundle)]
265 if self.use_crt_bundle_attach {
266 rcfg.crt_bundle_attach = Some(sys::esp_crt_bundle_attach);
267 }
268
269 rcfg.is_plain_tcp = self.is_plain_tcp;
270
271 #[cfg(esp_idf_comp_lwip_enabled)]
272 {
273 rcfg.if_name = core::ptr::null_mut();
274 }
275
276 Ok(rcfg)
277 }
278 }
279
280 impl Default for Config<'_> {
281 fn default() -> Self {
282 Self::new()
283 }
284 }
285
286 struct RawConfigBufs {
287 alpn_protos: [*const c_char; 10],
288 alpn_protos_cbuf: [u8; 99],
289 common_name_buf: [u8; MAX_COMMON_NAME_LENGTH + 1],
290 }
291
292 unsafe impl Send for RawConfigBufs {}
293
294 impl Default for RawConfigBufs {
295 fn default() -> Self {
296 RawConfigBufs {
297 alpn_protos: [core::ptr::null(); 10],
298 alpn_protos_cbuf: [0; 99],
299 common_name_buf: [0; MAX_COMMON_NAME_LENGTH + 1],
300 }
301 }
302 }
303
304 type AlpnBuf = [u8; 16];
305
306 #[derive(Clone, Default)]
307 pub struct CompletedHandshake {
308 alpn: AlpnBuf,
309 }
310
311 impl CompletedHandshake {
312 pub fn alpn_proto(&self) -> Option<&str> {
313 let p = CStr::from_bytes_until_nul(self.alpn.as_slice()).unwrap();
314 let p = unsafe { core::str::from_utf8_unchecked(p.to_bytes()) };
316
317 if !p.is_empty() {
319 Some(p)
320 } else {
321 None
322 }
323 }
324
325 unsafe fn extract(raw: *mut sys::esp_tls) -> CompletedHandshake {
327 CompletedHandshake {
328 alpn: unsafe { Self::extract_alpn(raw) }.unwrap_or_default(),
329 }
330 }
331
332 #[cfg(not(all(
333 not(esp_idf_version_major = "4"),
334 esp_idf_comp_esp_tls_enabled,
335 esp_idf_esp_tls_using_mbedtls,
336 esp_idf_mbedtls_ssl_alpn
337 )))]
338 unsafe fn extract_alpn(_raw: *mut sys::esp_tls) -> Option<AlpnBuf> {
339 None
340 }
341
342 #[cfg(all(
343 not(esp_idf_version_major = "4"),
344 esp_idf_comp_esp_tls_enabled,
345 esp_idf_esp_tls_using_mbedtls,
346 esp_idf_mbedtls_ssl_alpn
347 ))]
348 #[warn(unsafe_op_in_unsafe_fn)]
349 unsafe fn extract_alpn(raw: *mut sys::esp_tls) -> Option<AlpnBuf> {
350 let raw: *mut sys::mbedtls_ssl_context =
351 unsafe { sys::esp_tls_get_ssl_context(raw) }.cast();
352
353 if raw.is_null() {
354 return None;
355 }
356
357 let chosen = unsafe { sys::mbedtls_ssl_get_alpn_protocol(raw) };
358 if chosen.is_null() {
359 return None;
360 }
361
362 let mut proto = AlpnBuf::default();
363 let chosen = unsafe { CStr::from_ptr(chosen) };
364 let chosen_bytes = chosen.to_bytes_with_nul();
365 if chosen_bytes.len() > proto.len() {
366 return None;
367 }
368
369 proto[..chosen_bytes.len()].copy_from_slice(chosen_bytes);
370
371 Some(proto)
372 }
373 }
374
375 #[derive(Clone, Debug)]
376 pub struct KeepAliveConfig {
377 pub enable: bool,
379 pub idle: Duration,
381 pub interval: Duration,
383 pub count: u32,
385 }
386
387 pub struct PskHintKey<'a> {
388 pub key: &'a [u8],
389 pub hint: &'a CStr,
390 }
391
392 #[cfg(any(
393 esp_idf_esp_tls_server,
394 all(esp_idf_version_at_least_5_3_0, esp_idf_esp_tls_using_mbedtls),
395 ))]
396 pub struct ServerConfig<'a> {
397 pub alpn_protos: Option<&'a [&'a str]>,
399 pub ca_cert: Option<X509<'a>>,
400 pub server_cert: Option<X509<'a>>,
401 pub server_key: Option<X509<'a>>,
402 pub server_key_password: Option<&'a str>,
403 pub use_secure_element: bool,
404 #[cfg(esp_idf_version_at_least_5_5_0)]
416 pub tls_handshake_timeout_ms: u32,
417 #[cfg(esp_idf_esp_tls_server_cert_select_hook)]
418 pub handshake_callback: Option<extern "C" fn(*mut sys::mbedtls_ssl_context) -> c_int>,
419 }
420
421 #[cfg(any(
422 esp_idf_esp_tls_server,
423 all(esp_idf_version_at_least_5_3_0, esp_idf_esp_tls_using_mbedtls),
424 ))]
425 impl<'a> ServerConfig<'a> {
426 pub const fn new() -> Self {
427 Self {
428 alpn_protos: None,
429 ca_cert: None,
430 server_cert: None,
431 server_key: None,
432 server_key_password: None,
433 use_secure_element: false,
434 #[cfg(esp_idf_version_at_least_5_5_0)]
435 tls_handshake_timeout_ms: 0,
436 #[cfg(esp_idf_esp_tls_server_cert_select_hook)]
437 handshake_callback: None,
438 }
439 }
440
441 fn try_into_raw(
442 &self,
443 bufs: &mut RawConfigBufs,
444 ) -> Result<sys::esp_tls_cfg_server, EspError> {
445 let mut rcfg: sys::esp_tls_cfg_server = Default::default();
446
447 if let Some(ca_cert) = self.ca_cert {
448 rcfg.__bindgen_anon_1.cacert_buf = ca_cert.data().as_ptr();
449 rcfg.__bindgen_anon_2.cacert_bytes = ca_cert.data().len() as u32;
450 }
451
452 if let Some(server_cert) = self.server_cert {
453 rcfg.__bindgen_anon_3.servercert_buf = server_cert.data().as_ptr();
454 rcfg.__bindgen_anon_4.servercert_bytes = server_cert.data().len() as u32;
455 }
456
457 if let Some(server_key) = self.server_key {
458 rcfg.__bindgen_anon_5.serverkey_buf = server_key.data().as_ptr();
459 rcfg.__bindgen_anon_6.serverkey_bytes = server_key.data().len() as u32;
460 }
461
462 if let Some(ckp) = self.server_key_password {
463 rcfg.serverkey_password = ckp.as_ptr();
464 rcfg.serverkey_password_len = ckp.len() as u32;
465 }
466
467 if let Some(protos) = self.alpn_protos {
469 bufs.alpn_protos = cstr_arr_from_str_slice(protos, &mut bufs.alpn_protos_cbuf)?;
470 rcfg.alpn_protos = bufs.alpn_protos.as_mut_ptr();
471 }
472
473 rcfg.use_secure_element = self.use_secure_element;
474 #[cfg(esp_idf_version_at_least_5_5_0)]
475 {
476 rcfg.tls_handshake_timeout_ms = self.tls_handshake_timeout_ms;
477 }
478
479 #[cfg(esp_idf_esp_tls_server_cert_select_hook)]
480 if let Some(cb) = self.handshake_callback {
481 rcfg.cert_select_cb = cb;
482 }
483
484 Ok(rcfg)
485 }
486 }
487
488 #[cfg(any(
489 esp_idf_esp_tls_server,
490 all(esp_idf_version_at_least_5_3_0, esp_idf_esp_tls_using_mbedtls),
491 ))]
492 impl<'a> Default for ServerConfig<'a> {
493 fn default() -> Self {
494 Self::new()
495 }
496 }
497
498 pub trait Socket {
499 fn handle(&self) -> i32;
501 fn release(&mut self) -> Result<(), EspError>;
505 }
506
507 pub trait PollableSocket: Socket {
508 fn poll_readable(&self, ctx: &mut Context) -> Poll<Result<(), EspError>>;
509 fn poll_writable(&self, ctx: &mut Context) -> Poll<Result<(), EspError>>;
510 }
511
512 pub struct InternalSocket(());
513
514 impl Socket for InternalSocket {
515 fn handle(&self) -> i32 {
516 unreachable!()
517 }
518
519 fn release(&mut self) -> Result<(), EspError> {
520 Ok(())
521 }
522 }
523
524 pub struct EspTls<S>
526 where
527 S: Socket,
528 {
529 raw: *mut sys::esp_tls,
530 socket: S,
531 #[cfg(any(
532 esp_idf_esp_tls_server,
533 all(esp_idf_version_at_least_5_3_0, esp_idf_esp_tls_using_mbedtls,),
534 ))]
535 server_session: bool,
536 }
537
538 #[cfg(all(
542 esp_idf_comp_esp_tls_enabled,
543 esp_idf_esp_tls_using_mbedtls,
544 esp_idf_mbedtls_threading_c
545 ))]
546 unsafe impl<S> Send for EspTls<S> where S: Send + Socket {}
547
548 impl EspTls<InternalSocket> {
549 pub fn new() -> Result<Self, EspError> {
555 let raw = unsafe { sys::esp_tls_init() };
556 if !raw.is_null() {
557 Ok(Self {
558 raw,
559 socket: InternalSocket(()),
560 #[cfg(any(
561 esp_idf_esp_tls_server,
562 all(esp_idf_version_at_least_5_3_0, esp_idf_esp_tls_using_mbedtls,),
563 ))]
564 server_session: false,
565 })
566 } else {
567 Err(EspError::from_infallible::<ESP_ERR_NO_MEM>())
568 }
569 }
570
571 pub fn connect(
581 &mut self,
582 host: &str,
583 port: u16,
584 cfg: &Config,
585 ) -> Result<CompletedHandshake, EspError> {
586 let mut bufs = RawConfigBufs::default();
587 let rcfg = cfg.try_into_raw(&mut bufs)?;
588
589 let res = self.internal_connect(host, port, cfg.non_block, &rcfg);
590
591 #[allow(clippy::drop_non_drop)]
593 drop(bufs);
594
595 res
596 }
597 }
598
599 impl<S> EspTls<S>
600 where
601 S: Socket,
602 {
603 #[cfg(all(
610 not(esp_idf_version_major = "4"),
611 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
612 ))]
613 pub fn adopt(socket: S) -> Result<Self, EspError> {
614 let raw = unsafe { sys::esp_tls_init() };
615 if !raw.is_null() {
616 sys::esp!(unsafe { sys::esp_tls_set_conn_sockfd(raw, socket.handle()) })?;
617
618 sys::esp!(unsafe {
619 sys::esp_tls_set_conn_state(raw, sys::esp_tls_conn_state_ESP_TLS_CONNECTING)
620 })?;
621
622 Ok(Self {
623 raw,
624 socket,
625 #[cfg(any(
626 esp_idf_esp_tls_server,
627 all(esp_idf_version_at_least_5_3_0, esp_idf_esp_tls_using_mbedtls,),
628 ))]
629 server_session: false,
630 })
631 } else {
632 Err(EspError::from_infallible::<ESP_ERR_NO_MEM>())
633 }
634 }
635
636 #[cfg(all(
646 not(esp_idf_version_major = "4"),
647 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
648 ))]
649 pub fn negotiate(
650 &mut self,
651 host: &str,
652 cfg: &Config,
653 ) -> Result<CompletedHandshake, EspError> {
654 let mut bufs = RawConfigBufs::default();
655 let rcfg = cfg.try_into_raw(&mut bufs)?;
656
657 let res = self.internal_connect(host, 0, cfg.non_block, &rcfg);
658
659 #[allow(clippy::drop_non_drop)]
661 drop(bufs);
662
663 res
664 }
665
666 #[cfg(any(
679 esp_idf_esp_tls_server,
680 all(esp_idf_version_at_least_5_3_0, esp_idf_esp_tls_using_mbedtls),
681 ))]
682 pub fn negotiate_server(&mut self, cfg: &ServerConfig) -> Result<(), EspError> {
683 let mut bufs = RawConfigBufs::default();
684 let mut rcfg = cfg.try_into_raw(&mut bufs)?;
685
686 unsafe {
687 let error =
688 sys::esp_tls_server_session_create(&mut rcfg, self.socket.handle(), self.raw);
689 if error != 0 {
690 log::error!("failed to create tls server session (error {error})");
691 return Err(EspError::from_infallible::<ESP_FAIL>());
692 }
693 }
694 self.server_session = true;
695
696 #[allow(clippy::drop_non_drop)]
698 drop(bufs);
699
700 Ok(())
701 }
702
703 #[cfg(all(esp_idf_version_at_least_5_5_0, esp_idf_esp_tls_using_mbedtls,))]
715 pub fn negotiate_server_init(&mut self, cfg: &ServerConfig) -> Result<(), EspError> {
716 let mut bufs = RawConfigBufs::default();
717 let mut rcfg = cfg.try_into_raw(&mut bufs)?;
718
719 sys::esp!(unsafe {
721 sys::esp_tls_server_session_init(&mut rcfg, self.socket.handle(), self.raw)
722 })?;
723 self.server_session = true;
724
725 #[allow(clippy::drop_non_drop)]
726 drop(bufs);
727
728 Ok(())
729 }
730
731 #[allow(clippy::unnecessary_cast)]
744 #[cfg(all(esp_idf_version_at_least_5_5_0, esp_idf_esp_tls_using_mbedtls,))]
745 pub fn negotiate_server_continue(&mut self) -> Result<(), EspError> {
746 let ret = unsafe { sys::esp_tls_server_session_continue_async(self.raw) };
747
748 match ret {
749 0 => Ok(()),
750 ESP_TLS_ERR_SSL_WANT_READ => Err(EspError::from_infallible::<
751 { ESP_TLS_ERR_SSL_WANT_READ as i32 },
752 >()),
753 ESP_TLS_ERR_SSL_WANT_WRITE => Err(EspError::from_infallible::<
754 { ESP_TLS_ERR_SSL_WANT_WRITE as i32 },
755 >()),
756 _ => {
757 log::error!("TLS server handshake continue failed (error {ret})");
758 Err(EspError::from_infallible::<ESP_FAIL>())
759 }
760 }
761 }
762
763 #[allow(clippy::unnecessary_cast)]
764 fn internal_connect(
765 &mut self,
766 host: &str,
767 port: u16,
768 asynch: bool,
769 cfg: &sys::esp_tls_cfg,
770 ) -> Result<CompletedHandshake, EspError> {
771 let ret = unsafe {
772 if asynch {
773 sys::esp_tls_conn_new_async(
774 host.as_bytes().as_ptr() as *const c_char,
775 host.len() as i32,
776 port as i32,
777 cfg,
778 self.raw,
779 )
780 } else {
781 sys::esp_tls_conn_new_sync(
782 host.as_bytes().as_ptr() as *const c_char,
783 host.len() as i32,
784 port as i32,
785 cfg,
786 self.raw,
787 )
788 }
789 };
790
791 match ret {
792 1 => Ok(unsafe { CompletedHandshake::extract(self.raw) }),
793 ESP_TLS_ERR_SSL_WANT_READ => Err(EspError::from_infallible::<
794 { ESP_TLS_ERR_SSL_WANT_READ as i32 },
795 >()),
796 ESP_TLS_ERR_SSL_WANT_WRITE => Err(EspError::from_infallible::<
797 { ESP_TLS_ERR_SSL_WANT_WRITE as i32 },
798 >()),
799 0 => Err(EspError::from_infallible::<{ EWOULDBLOCK as i32 }>()),
800 _ => Err(EspError::from_infallible::<ESP_FAIL>()),
801 }
802 }
803
804 pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, EspError> {
812 if buf.is_empty() {
813 return Ok(0);
814 }
815
816 let ret = self.read_raw(buf);
817 if ret >= 0 {
819 Ok(ret as usize)
820 } else {
821 Err(EspError::from(ret as i32).unwrap())
822 }
823 }
824
825 #[cfg(esp_idf_version_major = "4")]
826 fn read_raw(&mut self, buf: &mut [u8]) -> isize {
827 let esp_tls = unsafe { core::ptr::read_unaligned(self.raw) };
829 let read_func = esp_tls.read.unwrap();
830 unsafe { read_func(self.raw, buf.as_mut_ptr() as *mut c_char, buf.len()) }
831 }
832
833 #[cfg(not(esp_idf_version_major = "4"))]
834 fn read_raw(&mut self, buf: &mut [u8]) -> isize {
835 use core::ffi::c_void;
836
837 unsafe { sys::esp_tls_conn_read(self.raw, buf.as_mut_ptr() as *mut c_void, buf.len()) }
838 }
839
840 pub fn write(&mut self, buf: &[u8]) -> Result<usize, EspError> {
847 if buf.is_empty() {
848 return Ok(0);
849 }
850
851 let ret = self.write_raw(buf);
852 if ret >= 0 {
853 Ok(ret as usize)
854 } else {
855 Err(EspError::from(ret as i32).unwrap())
856 }
857 }
858
859 pub fn write_all(&mut self, buf: &[u8]) -> Result<(), EspError> {
860 let mut buf = buf;
861
862 while !buf.is_empty() {
863 match self.write(buf) {
864 Ok(0) => panic!("zero-length write."),
865 Ok(n) => buf = &buf[n..],
866 Err(e) => return Err(e),
867 }
868 }
869
870 Ok(())
871 }
872
873 #[cfg(esp_idf_version_major = "4")]
874 fn write_raw(&mut self, buf: &[u8]) -> isize {
875 let esp_tls = unsafe { core::ptr::read_unaligned(self.raw) };
877 let write_func = esp_tls.write.unwrap();
878 unsafe { write_func(self.raw, buf.as_ptr() as *const c_char, buf.len()) }
879 }
880
881 #[cfg(not(esp_idf_version_major = "4"))]
882 fn write_raw(&mut self, buf: &[u8]) -> isize {
883 use core::ffi::c_void;
884
885 unsafe { sys::esp_tls_conn_write(self.raw, buf.as_ptr() as *const c_void, buf.len()) }
886 }
887
888 pub fn context_handle(&self) -> *mut sys::esp_tls {
889 self.raw
890 }
891 }
892
893 impl<S> Drop for EspTls<S>
894 where
895 S: Socket,
896 {
897 fn drop(&mut self) {
898 let _ = self.socket.release();
899
900 unsafe {
901 sys::esp_tls_conn_destroy(self.raw);
903 }
904 }
905 }
906
907 impl<S> io::ErrorType for EspTls<S>
908 where
909 S: Socket,
910 {
911 type Error = EspIOError;
912 }
913
914 impl<S> io::Read for EspTls<S>
915 where
916 S: Socket,
917 {
918 fn read(&mut self, buf: &mut [u8]) -> Result<usize, EspIOError> {
919 EspTls::read(self, buf).map_err(EspIOError)
920 }
921 }
922
923 impl<S> io::Write for EspTls<S>
924 where
925 S: Socket,
926 {
927 fn write(&mut self, buf: &[u8]) -> Result<usize, EspIOError> {
928 EspTls::write(self, buf).map_err(EspIOError)
929 }
930
931 fn flush(&mut self) -> Result<(), EspIOError> {
932 Ok(())
933 }
934 }
935 #[cfg(all(
936 not(esp_idf_version_major = "4"),
937 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
938 ))]
939 pub struct EspAsyncTls<S>(crate::private::mutex::Mutex<EspTls<S>>)
940 where
941 S: PollableSocket;
942
943 #[cfg(all(
944 not(esp_idf_version_major = "4"),
945 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
946 ))]
947 impl<S> EspAsyncTls<S>
948 where
949 S: PollableSocket,
950 {
951 pub fn adopt(socket: S) -> Result<Self, EspError> {
958 Ok(Self(crate::private::mutex::Mutex::new(EspTls::adopt(
959 socket,
960 )?)))
961 }
962
963 pub async fn negotiate(
970 &mut self,
971 hostname: &str,
972 cfg: &Config<'_>,
973 ) -> Result<CompletedHandshake, EspError> {
974 struct AssertSend<T>(T);
975 unsafe impl<T> Send for AssertSend<T> {}
976
977 let mut bufs = RawConfigBufs::default();
978 let mut rcfg: AssertSend<sys::esp_tls_cfg> = AssertSend(cfg.try_into_raw(&mut bufs)?);
979
980 rcfg.0.non_block = false;
993
994 let res = loop {
995 let res = self
996 .0
997 .get_mut()
998 .internal_connect(hostname, 0, true, &rcfg.0);
999
1000 match res {
1001 Err(e) => self.wait(e).await?,
1002 other => break other,
1003 }
1004 };
1005
1006 #[allow(clippy::drop_non_drop)]
1008 drop(bufs);
1009
1010 res
1011 }
1012
1013 #[cfg(all(esp_idf_version_at_least_5_5_0, esp_idf_esp_tls_using_mbedtls))]
1026 pub async fn negotiate_server(&mut self, cfg: &ServerConfig<'_>) -> Result<(), EspError> {
1027 self.0.get_mut().negotiate_server_init(cfg)?;
1028
1029 loop {
1030 let res = self.0.get_mut().negotiate_server_continue();
1031
1032 match res {
1033 Err(e) => self.wait(e).await?,
1034 Ok(()) => break Ok(()),
1035 }
1036 }
1037 }
1038
1039 pub async fn read(&self, buf: &mut [u8]) -> Result<usize, EspError> {
1041 core::future::poll_fn(|ctx| self.poll_read(ctx, buf)).await
1042 }
1043
1044 pub fn poll_read(
1045 &self,
1046 ctx: &mut Context<'_>,
1047 buf: &mut [u8],
1048 ) -> Poll<Result<usize, EspError>> {
1049 loop {
1050 let res = self.0.lock().read(buf);
1051
1052 match res {
1053 Err(e) => ready!(self.poll_wait(ctx, e))?,
1054 Ok(n) => break Poll::Ready(Ok(n)),
1055 }
1056 }
1057 }
1058
1059 pub async fn write(&self, buf: &[u8]) -> Result<usize, EspError> {
1061 core::future::poll_fn(|ctx| self.poll_write(ctx, buf)).await
1062 }
1063
1064 pub fn poll_write(
1065 &self,
1066 ctx: &mut Context<'_>,
1067 buf: &[u8],
1068 ) -> Poll<Result<usize, EspError>> {
1069 loop {
1070 let res = self.0.lock().write(buf);
1071
1072 match res {
1073 Err(e) => ready!(self.poll_wait(ctx, e))?,
1074 Ok(n) => break Poll::Ready(Ok(n)),
1075 }
1076 }
1077 }
1078
1079 pub async fn write_all(&self, buf: &[u8]) -> Result<(), EspError> {
1080 let mut buf = buf;
1081
1082 while !buf.is_empty() {
1083 match self.write(buf).await {
1084 Ok(0) => panic!("zero-length write."),
1085 Ok(n) => buf = &buf[n..],
1086 Err(e) => return Err(e),
1087 }
1088 }
1089
1090 Ok(())
1091 }
1092
1093 fn poll_wait(&self, ctx: &mut Context<'_>, error: EspError) -> Poll<Result<(), EspError>> {
1094 const EWOULDBLOCK_I32: i32 = EWOULDBLOCK as i32;
1095
1096 match error.code() {
1097 EWOULDBLOCK_I32 => {
1102 let res = self.0.lock().socket.poll_writable(ctx);
1103 crate::hal::delay::FreeRtos::delay_ms(0);
1104 res
1105 }
1106 ESP_TLS_ERR_SSL_WANT_READ => self.0.lock().socket.poll_readable(ctx),
1107 ESP_TLS_ERR_SSL_WANT_WRITE => self.0.lock().socket.poll_writable(ctx),
1108 _ => Poll::Ready(Err(error)),
1109 }
1110 }
1111
1112 async fn wait(&self, error: EspError) -> Result<(), EspError> {
1113 core::future::poll_fn(|ctx| self.poll_wait(ctx, error)).await
1114 }
1115
1116 pub fn context_handle(&self) -> *mut sys::esp_tls {
1117 self.0.lock().context_handle()
1118 }
1119 }
1120
1121 #[cfg(all(
1122 not(esp_idf_version_major = "4"),
1123 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
1124 ))]
1125 impl<S> io::ErrorType for EspAsyncTls<S>
1126 where
1127 S: PollableSocket,
1128 {
1129 type Error = EspIOError;
1130 }
1131
1132 #[cfg(all(
1133 not(esp_idf_version_major = "4"),
1134 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
1135 ))]
1136 impl<S> io::asynch::Read for EspAsyncTls<S>
1137 where
1138 S: PollableSocket,
1139 {
1140 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
1141 EspAsyncTls::read(self, buf).await.map_err(EspIOError)
1142 }
1143 }
1144
1145 #[cfg(all(
1146 not(esp_idf_version_major = "4"),
1147 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
1148 ))]
1149 impl<S> io::asynch::Write for EspAsyncTls<S>
1150 where
1151 S: PollableSocket,
1152 {
1153 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1154 EspAsyncTls::write(self, buf).await.map_err(EspIOError)
1155 }
1156
1157 async fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(())
1159 }
1160 }
1161
1162 #[cfg(all(
1163 feature = "std",
1164 not(esp_idf_version_major = "4"),
1165 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
1166 ))]
1167 impl<S> futures_io::AsyncRead for EspAsyncTls<S>
1168 where
1169 S: PollableSocket,
1170 {
1171 fn poll_read(
1172 self: Pin<&mut Self>,
1173 ctx: &mut Context<'_>,
1174 buf: &mut [u8],
1175 ) -> Poll<std::io::Result<usize>> {
1176 self.as_ref()
1177 .poll_read(ctx, buf)
1178 .map_err(std::io::Error::other)
1179 }
1180 }
1181
1182 #[cfg(all(
1183 feature = "std",
1184 not(esp_idf_version_major = "4"),
1185 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
1186 ))]
1187 impl<S> futures_io::AsyncRead for &EspAsyncTls<S>
1188 where
1189 S: PollableSocket,
1190 {
1191 fn poll_read(
1192 self: Pin<&mut Self>,
1193 ctx: &mut Context<'_>,
1194 buf: &mut [u8],
1195 ) -> Poll<std::io::Result<usize>> {
1196 self.as_ref()
1197 .poll_read(ctx, buf)
1198 .map_err(std::io::Error::other)
1199 }
1200 }
1201
1202 #[cfg(all(
1203 feature = "std",
1204 not(esp_idf_version_major = "4"),
1205 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
1206 ))]
1207 impl<S> futures_io::AsyncWrite for EspAsyncTls<S>
1208 where
1209 S: PollableSocket,
1210 {
1211 fn poll_write(
1212 self: Pin<&mut Self>,
1213 ctx: &mut Context<'_>,
1214 buf: &[u8],
1215 ) -> Poll<std::io::Result<usize>> {
1216 self.as_ref()
1217 .poll_write(ctx, buf)
1218 .map_err(std::io::Error::other)
1219 }
1220
1221 fn poll_flush(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
1222 Poll::Ready(Ok(()))
1223 }
1224
1225 fn poll_close(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
1226 Poll::Ready(Ok(()))
1227 }
1228 }
1229
1230 #[cfg(all(
1231 feature = "std",
1232 not(esp_idf_version_major = "4"),
1233 any(not(esp_idf_version_major = "5"), not(esp_idf_version_minor = "0"))
1234 ))]
1235 impl<S> futures_io::AsyncWrite for &EspAsyncTls<S>
1236 where
1237 S: PollableSocket,
1238 {
1239 fn poll_write(
1240 self: Pin<&mut Self>,
1241 ctx: &mut Context<'_>,
1242 buf: &[u8],
1243 ) -> Poll<std::io::Result<usize>> {
1244 self.as_ref()
1245 .poll_write(ctx, buf)
1246 .map_err(std::io::Error::other)
1247 }
1248
1249 fn poll_flush(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
1250 Poll::Ready(Ok(()))
1251 }
1252
1253 fn poll_close(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
1254 Poll::Ready(Ok(()))
1255 }
1256 }
1257}