diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b61db88..4d14797 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,6 +66,14 @@ jobs: ./ xtask + - name: Detect esp-mbedtls-sys/ changes + uses: dorny/paths-filter@v3 + id: detect-changes + with: + filters: | + libs: + - 'esp-mbedtls-sys/**' + - name: Install Rust for Xtensa and Espressif LLVM installation (optional) uses: esp-rs/xtensa-toolchain@v1.6 with: @@ -77,14 +85,6 @@ jobs: }} # ==== Build libs ==== - - name: Detect esp-mbedtls-sys/ changes - uses: dorny/paths-filter@v3 - id: detect-changes - with: - filters: | - libs: - - 'esp-mbedtls-sys/**' - - name: Build libraries and bindings if: | steps.detect-changes.outputs.libs == 'true' || diff --git a/esp-mbedtls-sys/gen/include/soc/esp32/config.h b/esp-mbedtls-sys/gen/include/soc/esp32/config.h index 4236b79..b7955ab 100644 --- a/esp-mbedtls-sys/gen/include/soc/esp32/config.h +++ b/esp-mbedtls-sys/gen/include/soc/esp32/config.h @@ -185,7 +185,7 @@ * * Enable this layer to allow use of alternative memory allocators. */ -//#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_MEMORY /** * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS diff --git a/esp-mbedtls-sys/gen/include/soc/esp32c3/config.h b/esp-mbedtls-sys/gen/include/soc/esp32c3/config.h index 0869f14..f141e2a 100644 --- a/esp-mbedtls-sys/gen/include/soc/esp32c3/config.h +++ b/esp-mbedtls-sys/gen/include/soc/esp32c3/config.h @@ -185,7 +185,7 @@ * * Enable this layer to allow use of alternative memory allocators. */ -//#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_MEMORY /** * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS diff --git a/esp-mbedtls-sys/gen/include/soc/esp32s2/config.h b/esp-mbedtls-sys/gen/include/soc/esp32s2/config.h index ffabff8..e44ddce 100644 --- a/esp-mbedtls-sys/gen/include/soc/esp32s2/config.h +++ b/esp-mbedtls-sys/gen/include/soc/esp32s2/config.h @@ -185,7 +185,7 @@ * * Enable this layer to allow use of alternative memory allocators. */ -//#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_MEMORY /** * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS diff --git a/esp-mbedtls-sys/gen/include/soc/esp32s3/config.h b/esp-mbedtls-sys/gen/include/soc/esp32s3/config.h index ffabff8..e44ddce 100644 --- a/esp-mbedtls-sys/gen/include/soc/esp32s3/config.h +++ b/esp-mbedtls-sys/gen/include/soc/esp32s3/config.h @@ -185,7 +185,7 @@ * * Enable this layer to allow use of alternative memory allocators. */ -//#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_MEMORY /** * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS diff --git a/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedcrypto.a b/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedcrypto.a index 9037841..2fc8181 100644 Binary files a/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedcrypto.a and b/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedcrypto.a differ diff --git a/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedtls.a b/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedtls.a index 7669983..2e51b1f 100644 Binary files a/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedtls.a and b/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedtls.a differ diff --git a/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedx509.a b/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedx509.a index 9cafe28..79abde1 100644 Binary files a/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedx509.a and b/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedx509.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedcrypto.a b/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedcrypto.a index abf178a..3e79158 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedcrypto.a and b/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedcrypto.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedtls.a b/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedtls.a index 1e6e53d..8ef2350 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedtls.a and b/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedtls.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedx509.a b/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedx509.a index bb731ec..4accebf 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedx509.a and b/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedx509.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedcrypto.a b/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedcrypto.a index 884c37d..9955296 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedcrypto.a and b/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedcrypto.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedtls.a b/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedtls.a index 8255e78..dc8d5f1 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedtls.a and b/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedtls.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedx509.a b/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedx509.a index bb731ec..4accebf 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedx509.a and b/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedx509.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedcrypto.a b/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedcrypto.a index 884c37d..aa3e86d 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedcrypto.a and b/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedcrypto.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedtls.a b/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedtls.a index 8255e78..dc8d5f1 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedtls.a and b/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedtls.a differ diff --git a/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedx509.a b/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedx509.a index bb731ec..4accebf 100644 Binary files a/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedx509.a and b/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedx509.a differ diff --git a/esp-mbedtls-sys/src/extra_impls.rs b/esp-mbedtls-sys/src/extra_impls.rs new file mode 100644 index 0000000..d3d2d80 --- /dev/null +++ b/esp-mbedtls-sys/src/extra_impls.rs @@ -0,0 +1,50 @@ +//! Provide extra implementations to the generated bindings +use core::ffi::{c_char, c_int, CStr}; + +impl core::fmt::Debug for crate::bindings::mbedtls_x509_time { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + // ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ + "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z", + self.year, self.mon, self.day, self.hour, self.min, self.sec + ) + } +} + +impl core::fmt::Debug for crate::bindings::mbedtls_x509_crt { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut crt: *const crate::bindings::mbedtls_x509_crt = self; + let mut index = 0; + let mut buf = [0u8; 1024]; + while !crt.is_null() { + index += 1; + buf.fill(0); + let buf_ptr = buf.as_mut_ptr() as *mut c_char; + let ret: c_int = unsafe { + crate::bindings::mbedtls_x509_crt_info(buf_ptr, buf.len() - 1, c"".as_ptr(), crt) + }; + if ret < 0 { + writeln!( + f, + "Certificate #{}: mbedtls_x509_crt_info failed with code {}", + index, ret + )?; + } else { + let cstr = unsafe { CStr::from_ptr(buf_ptr) }; + match cstr.to_str() { + Ok(s) => write!(f, "\nCertificate #{}:\n{}", index, s)?, + Err(_) => { + writeln!(f, "\nCertificate #{}: mbedtls_x509_crt_info returned invalid UTF-8 in output", index)?; + let slice = &buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]; + for line in slice.split(|&b| b == b'\n') { + writeln!(f, "{:?}", core::str::from_utf8(line))?; + } + } + } + } + crt = unsafe { (*crt).next }; + } + Ok(()) + } +} diff --git a/esp-mbedtls-sys/src/include/esp32.rs b/esp-mbedtls-sys/src/include/esp32.rs index de8bfb9..81176d8 100644 --- a/esp-mbedtls-sys/src/include/esp32.rs +++ b/esp-mbedtls-sys/src/include/esp32.rs @@ -296,6 +296,7 @@ pub const RE_DUP_MAX: u32 = 255; pub const MB_LEN_MAX: u32 = 1; pub const NL_ARGMAX: u32 = 32; pub const _POSIX2_RE_DUP_MAX: u32 = 255; +pub const CHAR_MIN: u32 = 0; pub const __int20: u32 = 2; pub const __int20__: u32 = 2; pub const __INT8: &[u8; 3] = b"hh\0"; diff --git a/esp-mbedtls-sys/src/include/esp32c3.rs b/esp-mbedtls-sys/src/include/esp32c3.rs index 564a1d4..940e694 100644 --- a/esp-mbedtls-sys/src/include/esp32c3.rs +++ b/esp-mbedtls-sys/src/include/esp32c3.rs @@ -199,127 +199,8 @@ pub const PSA_WANT_KEY_TYPE_DERIVE: u32 = 1; pub const PSA_WANT_KEY_TYPE_PASSWORD: u32 = 1; pub const PSA_WANT_KEY_TYPE_PASSWORD_HASH: u32 = 1; pub const PSA_WANT_KEY_TYPE_RAW_DATA: u32 = 1; -pub const _LIBC_LIMITS_H_: u32 = 1; -pub const __NEWLIB_H__: u32 = 1; -pub const _NEWLIB_VERSION_H__: u32 = 1; -pub const _NEWLIB_VERSION: &[u8; 6] = b"4.3.0\0"; -pub const __NEWLIB__: u32 = 4; -pub const __NEWLIB_MINOR__: u32 = 3; -pub const __NEWLIB_PATCHLEVEL__: u32 = 0; -pub const _ATEXIT_DYNAMIC_ALLOC: u32 = 1; -pub const _FSEEK_OPTIMIZATION: u32 = 1; -pub const _FVWRITE_IN_STREAMIO: u32 = 1; -pub const _HAVE_CC_INHIBIT_LOOP_TO_LIBCALL: u32 = 1; -pub const _HAVE_INITFINI_ARRAY: u32 = 1; -pub const _HAVE_LONG_DOUBLE: u32 = 1; -pub const _ICONV_ENABLED: u32 = 1; -pub const _MB_LEN_MAX: u32 = 1; -pub const _NANO_MALLOC: u32 = 1; -pub const _REENT_CHECK_VERIFY: u32 = 1; -pub const _RETARGETABLE_LOCKING: u32 = 1; -pub const _UNBUF_STREAM_OPT: u32 = 1; -pub const _WANT_IO_C99_FORMATS: u32 = 1; -pub const _WANT_IO_LONG_LONG: u32 = 1; -pub const _WANT_IO_POS_ARGS: u32 = 1; -pub const _WANT_REENT_BACKWARD_BINARY_COMPAT: u32 = 1; -pub const _WANT_REENT_SMALL: u32 = 1; -pub const _WANT_USE_GDTOA: u32 = 1; -pub const _DEFAULT_SOURCE: u32 = 1; -pub const _POSIX_SOURCE: u32 = 1; -pub const _POSIX_C_SOURCE: u32 = 200809; -pub const _ATFILE_SOURCE: u32 = 1; -pub const __ATFILE_VISIBLE: u32 = 1; -pub const __BSD_VISIBLE: u32 = 1; -pub const __GNU_VISIBLE: u32 = 0; -pub const __ISO_C_VISIBLE: u32 = 2011; -pub const __LARGEFILE_VISIBLE: u32 = 0; -pub const __MISC_VISIBLE: u32 = 1; -pub const __POSIX_VISIBLE: u32 = 200809; -pub const __SVID_VISIBLE: u32 = 1; -pub const __XSI_VISIBLE: u32 = 0; -pub const __SSP_FORTIFY_LEVEL: u32 = 0; -pub const _POSIX_THREADS: u32 = 1; -pub const _POSIX_TIMEOUTS: u32 = 1; -pub const _POSIX_TIMERS: u32 = 1; -pub const _POSIX_MONOTONIC_CLOCK: u32 = 200112; -pub const _POSIX_CLOCK_SELECTION: u32 = 200112; -pub const _UNIX98_THREAD_MUTEX_ATTRIBUTES: u32 = 1; -pub const _POSIX_READER_WRITER_LOCKS: u32 = 200112; -pub const __have_longlong64: u32 = 1; -pub const __have_long32: u32 = 1; -pub const ___int8_t_defined: u32 = 1; -pub const ___int16_t_defined: u32 = 1; -pub const ___int32_t_defined: u32 = 1; -pub const ___int64_t_defined: u32 = 1; -pub const ___int_least8_t_defined: u32 = 1; -pub const ___int_least16_t_defined: u32 = 1; -pub const ___int_least32_t_defined: u32 = 1; -pub const ___int_least64_t_defined: u32 = 1; -pub const __GNUCLIKE_ASM: u32 = 3; -pub const __GNUCLIKE___TYPEOF: u32 = 1; -pub const __GNUCLIKE___SECTION: u32 = 1; -pub const __GNUCLIKE_CTOR_SECTION_HANDLING: u32 = 1; -pub const __GNUCLIKE_BUILTIN_CONSTANT_P: u32 = 1; -pub const __GNUCLIKE_BUILTIN_VARARGS: u32 = 1; -pub const __GNUCLIKE_BUILTIN_STDARG: u32 = 1; -pub const __GNUCLIKE_BUILTIN_VAALIST: u32 = 1; -pub const __GNUC_VA_LIST_COMPATIBILITY: u32 = 1; -pub const __GNUCLIKE_BUILTIN_NEXT_ARG: u32 = 1; -pub const __GNUCLIKE_BUILTIN_MEMCPY: u32 = 1; -pub const __CC_SUPPORTS_INLINE: u32 = 1; -pub const __CC_SUPPORTS___INLINE: u32 = 1; -pub const __CC_SUPPORTS___INLINE__: u32 = 1; -pub const __CC_SUPPORTS___FUNC__: u32 = 1; -pub const __CC_SUPPORTS_WARNING: u32 = 1; -pub const __CC_SUPPORTS_VARADIC_XXX: u32 = 1; -pub const __CC_SUPPORTS_DYNAMIC_ARRAY_INIT: u32 = 1; -pub const ARG_MAX: u32 = 65536; -pub const CHILD_MAX: u32 = 40; -pub const LINK_MAX: u32 = 32767; -pub const MAX_CANON: u32 = 255; -pub const MAX_INPUT: u32 = 255; -pub const NAME_MAX: u32 = 255; -pub const NGROUPS_MAX: u32 = 16; -pub const OPEN_MAX: u32 = 64; -pub const PATH_MAX: u32 = 1024; -pub const PIPE_BUF: u32 = 512; -pub const IOV_MAX: u32 = 1024; -pub const BC_BASE_MAX: u32 = 99; -pub const BC_DIM_MAX: u32 = 2048; -pub const BC_SCALE_MAX: u32 = 99; -pub const BC_STRING_MAX: u32 = 1000; -pub const COLL_WEIGHTS_MAX: u32 = 0; -pub const EXPR_NEST_MAX: u32 = 32; -pub const LINE_MAX: u32 = 2048; -pub const RE_DUP_MAX: u32 = 255; pub const MB_LEN_MAX: u32 = 1; -pub const NL_ARGMAX: u32 = 32; -pub const _POSIX2_RE_DUP_MAX: u32 = 255; pub const CHAR_MIN: u32 = 0; -pub const __int20: u32 = 2; -pub const __int20__: u32 = 2; -pub const __INT8: &[u8; 3] = b"hh\0"; -pub const __INT16: &[u8; 2] = b"h\0"; -pub const __INT64: &[u8; 3] = b"ll\0"; -pub const __FAST8: &[u8; 3] = b"hh\0"; -pub const __FAST16: &[u8; 2] = b"h\0"; -pub const __FAST64: &[u8; 3] = b"ll\0"; -pub const __LEAST8: &[u8; 3] = b"hh\0"; -pub const __LEAST16: &[u8; 2] = b"h\0"; -pub const __LEAST64: &[u8; 3] = b"ll\0"; -pub const __int8_t_defined: u32 = 1; -pub const __int16_t_defined: u32 = 1; -pub const __int32_t_defined: u32 = 1; -pub const __int64_t_defined: u32 = 1; -pub const __int_least8_t_defined: u32 = 1; -pub const __int_least16_t_defined: u32 = 1; -pub const __int_least32_t_defined: u32 = 1; -pub const __int_least64_t_defined: u32 = 1; -pub const __int_fast8_t_defined: u32 = 1; -pub const __int_fast16_t_defined: u32 = 1; -pub const __int_fast32_t_defined: u32 = 1; -pub const __int_fast64_t_defined: u32 = 1; -pub const WINT_MIN: u32 = 0; pub const MBEDTLS_ERR_MPI_FILE_IO_ERROR: i32 = -2; pub const MBEDTLS_ERR_MPI_BAD_INPUT_DATA: i32 = -4; pub const MBEDTLS_ERR_MPI_INVALID_CHARACTER: i32 = -6; @@ -1062,26 +943,25 @@ pub const MBEDTLS_CTR_DRBG_MAX_SEED_INPUT: u32 = 384; pub const MBEDTLS_CTR_DRBG_PR_OFF: u32 = 0; pub const MBEDTLS_CTR_DRBG_PR_ON: u32 = 1; pub const MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN: u32 = 0; -pub type __int8_t = crate::c_types::c_schar; -pub type __uint8_t = crate::c_types::c_uchar; -pub type __int16_t = crate::c_types::c_short; -pub type __uint16_t = crate::c_types::c_ushort; -pub type __int32_t = crate::c_types::c_int; -pub type __uint32_t = crate::c_types::c_uint; -pub type __int64_t = crate::c_types::c_longlong; -pub type __uint64_t = crate::c_types::c_ulonglong; -pub type __int_least8_t = crate::c_types::c_schar; -pub type __uint_least8_t = crate::c_types::c_uchar; -pub type __int_least16_t = crate::c_types::c_short; -pub type __uint_least16_t = crate::c_types::c_ushort; -pub type __int_least32_t = crate::c_types::c_int; -pub type __uint_least32_t = crate::c_types::c_uint; -pub type __int_least64_t = crate::c_types::c_longlong; -pub type __uint_least64_t = crate::c_types::c_ulonglong; -pub type __intmax_t = crate::c_types::c_longlong; -pub type __uintmax_t = crate::c_types::c_ulonglong; -pub type __intptr_t = crate::c_types::c_int; -pub type __uintptr_t = crate::c_types::c_uint; +pub type int_least64_t = i64; +pub type uint_least64_t = u64; +pub type int_fast64_t = i64; +pub type uint_fast64_t = u64; +pub type int_least32_t = i32; +pub type uint_least32_t = u32; +pub type int_fast32_t = i32; +pub type uint_fast32_t = u32; +pub type int_least16_t = i16; +pub type uint_least16_t = u16; +pub type int_fast16_t = i16; +pub type uint_fast16_t = u16; +pub type int_least8_t = i8; +pub type uint_least8_t = u8; +pub type int_fast8_t = i8; +pub type uint_fast8_t = u8; +pub type intmax_t = crate::c_types::c_longlong; +pub type uintmax_t = crate::c_types::c_ulonglong; +pub type mbedtls_iso_c_forbids_empty_translation_units = crate::c_types::c_int; pub type wchar_t = crate::c_types::c_int; #[repr(C)] #[repr(align(16))] @@ -1091,25 +971,6 @@ pub struct max_align_t { pub __bindgen_padding_0: u64, pub __clang_max_align_nonce2: u128, } -pub type intmax_t = __intmax_t; -pub type uintmax_t = __uintmax_t; -pub type int_least8_t = __int_least8_t; -pub type uint_least8_t = __uint_least8_t; -pub type int_least16_t = __int_least16_t; -pub type uint_least16_t = __uint_least16_t; -pub type int_least32_t = __int_least32_t; -pub type uint_least32_t = __uint_least32_t; -pub type int_least64_t = __int_least64_t; -pub type uint_least64_t = __uint_least64_t; -pub type int_fast8_t = crate::c_types::c_schar; -pub type uint_fast8_t = crate::c_types::c_uchar; -pub type int_fast16_t = crate::c_types::c_short; -pub type uint_fast16_t = crate::c_types::c_ushort; -pub type int_fast32_t = crate::c_types::c_int; -pub type uint_fast32_t = crate::c_types::c_uint; -pub type int_fast64_t = crate::c_types::c_longlong; -pub type uint_fast64_t = crate::c_types::c_ulonglong; -pub type mbedtls_iso_c_forbids_empty_translation_units = crate::c_types::c_int; extern "C" { /// \brief Securely zeroize a buffer /// diff --git a/esp-mbedtls-sys/src/include/esp32s2.rs b/esp-mbedtls-sys/src/include/esp32s2.rs index 7a0f825..577d5f7 100644 --- a/esp-mbedtls-sys/src/include/esp32s2.rs +++ b/esp-mbedtls-sys/src/include/esp32s2.rs @@ -296,6 +296,7 @@ pub const RE_DUP_MAX: u32 = 255; pub const MB_LEN_MAX: u32 = 1; pub const NL_ARGMAX: u32 = 32; pub const _POSIX2_RE_DUP_MAX: u32 = 255; +pub const CHAR_MIN: u32 = 0; pub const __int20: u32 = 2; pub const __int20__: u32 = 2; pub const __INT8: &[u8; 3] = b"hh\0"; diff --git a/esp-mbedtls-sys/src/include/esp32s3.rs b/esp-mbedtls-sys/src/include/esp32s3.rs index 7a0f825..577d5f7 100644 --- a/esp-mbedtls-sys/src/include/esp32s3.rs +++ b/esp-mbedtls-sys/src/include/esp32s3.rs @@ -296,6 +296,7 @@ pub const RE_DUP_MAX: u32 = 255; pub const MB_LEN_MAX: u32 = 1; pub const NL_ARGMAX: u32 = 32; pub const _POSIX2_RE_DUP_MAX: u32 = 255; +pub const CHAR_MIN: u32 = 0; pub const __int20: u32 = 2; pub const __int20__: u32 = 2; pub const __INT8: &[u8; 3] = b"hh\0"; diff --git a/esp-mbedtls-sys/src/lib.rs b/esp-mbedtls-sys/src/lib.rs index 58c5ce7..be1f4f3 100644 --- a/esp-mbedtls-sys/src/lib.rs +++ b/esp-mbedtls-sys/src/lib.rs @@ -11,6 +11,7 @@ use esp_wifi as _; #[cfg(not(target_os = "espidf"))] mod c_types; +mod extra_impls; #[allow( non_camel_case_types, diff --git a/esp-mbedtls/src/edge_nal.rs b/esp-mbedtls/src/edge_nal.rs index 0da1c28..799dbdb 100644 --- a/esp-mbedtls/src/edge_nal.rs +++ b/esp-mbedtls/src/edge_nal.rs @@ -4,13 +4,14 @@ use core::net::SocketAddr; use embedded_io::Error; use crate::asynch::Session; -use crate::{Certificates, Mode, TlsError, TlsReference, TlsVersion}; +use crate::{AuthMode, Certificates, Mode, SessionConfig, TlsError, TlsReference, TlsVersion}; /// An implementation of `edge-nal`'s `TcpAccept` trait over TLS. pub struct TlsAcceptor<'d, T> { acceptor: T, + auth_mode: AuthMode, min_version: TlsVersion, - certificates: Certificates<'d>, + certificates: &'d Certificates<'d>, tls_ref: TlsReference<'d>, } @@ -23,17 +24,20 @@ where /// Arguments: /// /// * `acceptor` - The underlying TCP acceptor + /// * `auth_mode` - Certificates verification mode /// * `min_version` - The minimum TLS version to support /// * `certificates` - The certificates to use for each accepted TLS connection /// * `tls_ref` - A reference to the active `Tls` instance pub const fn new( acceptor: T, + auth_mode: AuthMode, min_version: TlsVersion, - certificates: Certificates<'d>, + certificates: &'d Certificates<'d>, tls_ref: TlsReference<'d>, ) -> Self { Self { acceptor, + auth_mode, min_version, certificates, tls_ref, @@ -63,8 +67,11 @@ where let session = Session::new( socket, - Mode::Server, - self.min_version, + SessionConfig { + mode: Mode::Server, + auth_mode: self.auth_mode, + min_version: self.min_version, + }, self.certificates, self.tls_ref, )?; @@ -77,8 +84,9 @@ where pub struct TlsConnector<'d, T> { connector: T, servername: &'d CStr, + auth_mode: AuthMode, min_version: TlsVersion, - certificates: Certificates<'d>, + certificates: &'d Certificates<'d>, tls_ref: TlsReference<'d>, } @@ -92,19 +100,22 @@ where /// /// * `connector` - The underlying TCP connector /// * `servername` - The server name to check against the certificate presented by the server + /// * `auth_mode` - Certificates verification mode /// * `min_version` - The minimum TLS version to support /// * `certificates` - The certificates to use for each established TLS connection /// * `tls_ref` - A reference to the active `Tls` instance pub const fn new( connector: T, servername: &'d CStr, + auth_mode: AuthMode, min_version: TlsVersion, - certificates: Certificates<'d>, + certificates: &'d Certificates<'d>, tls_ref: TlsReference<'d>, ) -> Self { Self { connector, servername, + auth_mode, min_version, certificates, tls_ref, @@ -133,10 +144,13 @@ where let session = Session::new( socket, - Mode::Client { - servername: self.servername, + SessionConfig { + mode: Mode::Client { + servername: self.servername, + }, + auth_mode: self.auth_mode, + min_version: self.min_version, }, - self.min_version, self.certificates, self.tls_ref, )?; diff --git a/esp-mbedtls/src/esp_hal/sha/sha1.rs b/esp-mbedtls/src/esp_hal/sha/sha1.rs index f49688e..c223310 100644 --- a/esp-mbedtls/src/esp_hal/sha/sha1.rs +++ b/esp-mbedtls/src/esp_hal/sha/sha1.rs @@ -25,7 +25,7 @@ pub unsafe extern "C" fn mbedtls_sha1_init(ctx: *mut mbedtls_sha1_context) { #[no_mangle] pub unsafe extern "C" fn mbedtls_sha1_free(ctx: *mut mbedtls_sha1_context) { if !ctx.is_null() && !(*ctx).hasher.is_null() { - crate::free((*ctx).hasher as *const c_void); + crate::mbedtls_free((*ctx).hasher as *const c_void); (*ctx).hasher = core::ptr::null_mut(); } } diff --git a/esp-mbedtls/src/esp_hal/sha/sha256.rs b/esp-mbedtls/src/esp_hal/sha/sha256.rs index 722520b..e490e1b 100644 --- a/esp-mbedtls/src/esp_hal/sha/sha256.rs +++ b/esp-mbedtls/src/esp_hal/sha/sha256.rs @@ -32,11 +32,11 @@ pub unsafe extern "C" fn mbedtls_sha256_init(ctx: *mut mbedtls_sha256_context) { pub unsafe extern "C" fn mbedtls_sha256_free(ctx: *mut mbedtls_sha256_context) { if !ctx.is_null() { if !(*ctx).sha224_hasher.is_null() { - crate::free((*ctx).sha224_hasher as *const c_void); + crate::mbedtls_free((*ctx).sha224_hasher as *const c_void); (*ctx).sha224_hasher = core::ptr::null_mut(); } if !(*ctx).sha256_hasher.is_null() { - crate::free((*ctx).sha256_hasher as *const c_void); + crate::mbedtls_free((*ctx).sha256_hasher as *const c_void); (*ctx).sha256_hasher = core::ptr::null_mut(); } } diff --git a/esp-mbedtls/src/esp_hal/sha/sha512.rs b/esp-mbedtls/src/esp_hal/sha/sha512.rs index 42c6d0e..4b68c1d 100644 --- a/esp-mbedtls/src/esp_hal/sha/sha512.rs +++ b/esp-mbedtls/src/esp_hal/sha/sha512.rs @@ -32,11 +32,11 @@ pub unsafe extern "C" fn mbedtls_sha512_init(ctx: *mut mbedtls_sha512_context) { pub unsafe extern "C" fn mbedtls_sha512_free(ctx: *mut mbedtls_sha512_context) { if !ctx.is_null() { if !(*ctx).sha384_hasher.is_null() { - crate::free((*ctx).sha384_hasher as *const c_void); + crate::mbedtls_free((*ctx).sha384_hasher as *const c_void); (*ctx).sha384_hasher = core::ptr::null_mut(); } if !(*ctx).sha512_hasher.is_null() { - crate::free((*ctx).sha512_hasher as *const c_void); + crate::mbedtls_free((*ctx).sha512_hasher as *const c_void); (*ctx).sha512_hasher = core::ptr::null_mut(); } } diff --git a/esp-mbedtls/src/lib.rs b/esp-mbedtls/src/lib.rs index f19d983..4c855eb 100644 --- a/esp-mbedtls/src/lib.rs +++ b/esp-mbedtls/src/lib.rs @@ -47,15 +47,15 @@ unsafe fn aligned_calloc(_align: usize, size: usize) -> *const c_void { // panic!("Cannot allocate with alignment > 4 bytes: {_align}"); // } - calloc(1, size) + mbedtls_calloc(1, size) } // Baremetal: these will come from `esp-wifi` (i.e. this can only be used together with esp-wifi) // STD: these will come from `libc` indirectly via the Rust standard library extern "C" { - fn free(ptr: *const c_void); + fn mbedtls_free(ptr: *const c_void); - fn calloc(number: usize, size: usize) -> *const c_void; + fn mbedtls_calloc(nmemb: usize, size: usize) -> *const c_void; fn random() -> c_ulong; } @@ -119,6 +119,69 @@ impl TlsVersion { } } +/// Certificate verification mode used for a session +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum AuthMode { + /// Peer certificate is not checked (default on server) (insecure on client) + None, + /// Peer certificate is checked, however the handshake continues even if verification failed; + /// [mbedtls_ssl_get_verify_result()] can be called after the handshake is complete. + Optional, + /// Peer *must* present a valid certificate, handshake is aborted if verification failed. (default on client) + Required, + /// Used only for sni_authmode + Unset, +} + +impl AuthMode { + fn to_mbedtls_authmode(&self) -> i32 { + (match self { + AuthMode::None => MBEDTLS_SSL_VERIFY_NONE, + AuthMode::Optional => MBEDTLS_SSL_VERIFY_OPTIONAL, + AuthMode::Required => MBEDTLS_SSL_VERIFY_REQUIRED, + AuthMode::Unset => MBEDTLS_SSL_VERIFY_UNSET, + }) as i32 + } +} + +/// Configuration for a TLS session +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SessionConfig<'a> { + /// The mode of operation of a TLS `Session` instance + mode: Mode<'a>, + /// The minimum TLS version that will be supported by a particular `Session` instance + min_version: TlsVersion, + /// Certificate verification mode. Can be overriden. + /// By default, the following we be used depending on the mode: + /// - [AuthMode::None] on server + /// - [AuthMode::Required] on client + auth_mode: AuthMode, +} + +impl<'a> SessionConfig<'a> { + /// Create a config for a session + /// + /// # Arguments + /// + /// * `mode` - The mode of operation of a TLS `Session` instance + /// * `min_version` - The minimum TLS version that will be supported by a particular `Session` instance + pub fn new(mode: Mode<'a>, min_version: TlsVersion) -> Self { + Self { + mode, + min_version, + auth_mode: match mode { + Mode::Client { servername: _ } => AuthMode::Required, + Mode::Server => AuthMode::None, + }, + } + } + + /// Override the auth mode to use a specific one + pub fn set_auth_mode(&mut self, auth_mode: AuthMode) { + self.auth_mode = auth_mode + } +} + /// Error type for TLS operations #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TlsError { @@ -134,6 +197,8 @@ pub enum TlsError { Eof, /// X509 certificate missing null terminator X509MissingNullTerminator, + /// The X509 is in an unexpected format (PEM instead of DER and vice-versa) + InvalidFormat, /// The client has given no certificates for the request NoClientCertificate, /// IO error @@ -151,6 +216,12 @@ impl fmt::Display for TlsError { Self::X509MissingNullTerminator => { write!(f, "X509 certificate missing null terminator") } + Self::InvalidFormat => { + write!( + f, + "The X509 is in an unexpected format (PEM instead of DER and vice-versa)" + ) + } Self::NoClientCertificate => write!(f, "No client certificate"), Self::Io(e) => write!(f, "IO error: {e:?}"), } @@ -168,7 +239,7 @@ impl embedded_io::Error for TlsError { /// Format type for [X509] #[derive(Debug, Clone, Copy, Eq, PartialEq)] -enum CertificateFormat { +pub enum CertificateFormat { PEM, DER, } @@ -228,6 +299,11 @@ impl<'a> X509<'a> { self.bytes } + /// Returns the encoding format of a certificate + pub fn format(&self) -> CertificateFormat { + self.format + } + /// Returns the length of the certificate pub(crate) fn len(&self) -> usize { self.data().len() @@ -244,12 +320,195 @@ impl<'a> X509<'a> { } } -/// Certificates used for a connection. -/// -/// # Note: -/// Both [certificate](Certificates::certificate) and [private_key](Certificates::private_key) must be set in pair. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Certificates<'a> { +/// Creates a wrapper over [mbedtls_x509_crt] to safely manage allocation and freeing on drop +#[derive(Debug)] +struct MbedTLSX509Crt<'d> { + crt: *mut mbedtls_x509_crt, + _t: PhantomData<&'d ()>, +} + +impl MbedTLSX509Crt<'static> { + /// Parse an X509 certificate into RAM by making a copy + /// + /// # Arguments + /// + /// * `certificate` - The X509 certificate in PEM or DER format + /// + /// # Errors + /// + /// This will return an error if an error occurs during parsing such as passing a DER encoded + /// certificate in a PEM format, and vice-versa. + fn new(certificate: X509<'_>) -> Result { + unsafe { + let ptr = aligned_calloc( + align_of::(), + size_of::(), + ) as *mut mbedtls_x509_crt; + if ptr.is_null() { + return Err(TlsError::OutOfMemory); + } + mbedtls_x509_crt_init(ptr); + + let cleanup = || { + mbedtls_x509_crt_free(ptr); + mbedtls_free(ptr as *const _); + }; + + match certificate.format { + CertificateFormat::PEM => { + error_checked!( + mbedtls_x509_crt_parse(ptr, certificate.as_ptr(), certificate.len()), + cleanup + ) + } + CertificateFormat::DER => { + error_checked!( + mbedtls_x509_crt_parse_der(ptr, certificate.as_ptr(), certificate.len()), + cleanup + ) + } + } + .map_err(|err| { + if matches!(err, TlsError::MbedTlsError(-8576)) { + TlsError::InvalidFormat + } else { + err + } + })?; + Ok(Self { + crt: ptr, + _t: PhantomData, + }) + } + } +} + +impl<'d> MbedTLSX509Crt<'d> { + /// Parse an X509 certificate without making a copy in RAM. This requires that the underlying data + /// lives for the lifetime of the certificate. + /// Note: This is currently only supported for DER encoded certificates + /// + /// # Arguments + /// + /// * `certificate` - The X509 certificate in DER format only + /// + /// # Errors + /// + /// This will return an error if an error occurs during parsing. + /// [TlsError::InvalidFormat] will be returned if a PEM encoded certificate is passed. + fn new_no_copy(certificate: X509<'d>) -> Result { + // Currently no copy is only supported by DER certificates + if matches!(certificate.format(), CertificateFormat::PEM) { + return Err(TlsError::InvalidFormat); + } + unsafe { + let ptr = aligned_calloc( + align_of::(), + size_of::(), + ) as *mut mbedtls_x509_crt; + if ptr.is_null() { + return Err(TlsError::OutOfMemory); + } + mbedtls_x509_crt_init(ptr); + + let cleanup = || { + mbedtls_x509_crt_free(ptr); + mbedtls_free(ptr as *const _); + }; + + error_checked!( + mbedtls_x509_crt_parse_der_nocopy(ptr, certificate.as_ptr(), certificate.len()), + cleanup + ) + .map_err(|err| { + if matches!(err, TlsError::MbedTlsError(-8576)) { + TlsError::InvalidFormat + } else { + err + } + })?; + + Ok(Self { + crt: ptr, + _t: PhantomData, + }) + } + } +} + +impl Drop for MbedTLSX509Crt<'_> { + fn drop(&mut self) { + unsafe { + mbedtls_x509_crt_free(self.crt); + mbedtls_free(self.crt as *const _); + } + } +} + +/// Creates a wrapper over [mbedtls_pk_context] to safely manage allocation and freeing on drop +#[derive(Debug)] +struct PkContext(*mut mbedtls_pk_context); + +impl PkContext { + /// Parse an X509 private key into RAM and returns a wrapped pointer if successful. + /// + /// # Arguments + /// + /// * `private_key` - The X509 private key in DER or PEM format + /// * `password` - The optional password if the private key is password protected + /// + /// # Errors + /// + /// This will return an error if an error occurs during parsing such as passing a DER encoded + /// private key in a PEM format, and vice-versa. + fn new<'a>(private_key: X509<'a>, password: Option<&'a str>) -> Result { + unsafe { + let ptr = aligned_calloc( + align_of::(), + size_of::(), + ) as *mut mbedtls_pk_context; + if ptr.is_null() { + return Err(TlsError::OutOfMemory); + } + + mbedtls_pk_init(ptr); + + let (password_ptr, password_len) = if let Some(password) = password { + (password.as_ptr(), password.len()) + } else { + (core::ptr::null(), 0) + }; + error_checked!( + mbedtls_pk_parse_key( + ptr, + private_key.as_ptr(), + private_key.len(), + password_ptr, + password_len, + None, + core::ptr::null_mut(), + ), + || { + mbedtls_pk_free(ptr); + mbedtls_free(ptr as *const _); + } + )?; + Ok(Self(ptr)) + } + } +} + +impl Drop for PkContext { + fn drop(&mut self) { + unsafe { + mbedtls_pk_free(self.0); + mbedtls_free(self.0 as *const _); + } + } +} + +#[derive(Debug)] +pub struct Certificates<'d> { /// Trusted CA (Certificate Authority) chain to be used for certificate /// verification during the SSL/TLS handshake. /// @@ -261,11 +520,10 @@ pub struct Certificates<'a> { /// that will be used to verify the server's certificate during the handshake. /// /// # Server: - /// In server mode, the CA chain should contain the trusted CA certificates - /// that will be used to verify the client's certificate during the handshake. - /// When set to [None] the server will not request nor perform any verification - /// on the client certificates. Only set when you want to use client authentication. - pub ca_chain: Option>, + /// In server mode, the CA chain should contain the trusted CA certificates that will be + /// provided to the client and that will be used to verify the client's certificate + /// during the handshake, if enabled. + ca_chain: Option>, /// Own certificate chain used for requests /// It should contain in order from the bottom up your certificate chain. @@ -279,23 +537,79 @@ pub struct Certificates<'a> { /// # Server: /// In server mode, this will be the certificate given to the client when /// performing a handshake. - pub certificate: Option>, + /// When set to [None] the server will not request nor perform any verification + /// on the client certificates. Only set when you want to use client authentication. + certificate: Option>, /// Private key paired with the certificate. Must be set when [Certificates::certificate] /// is not [None] - pub private_key: Option>, - - /// Password used for the private key. - /// Use [None] when the private key doesn't have a password. - pub password: Option<&'a str>, + private_key: Option, } +unsafe impl Send for Certificates<'_> {} + impl Default for Certificates<'_> { fn default() -> Self { Self::new() } } +impl<'d> Certificates<'d> { + /// Initialize the own certificate chain and private key used for requests without making an + /// internal copy in RAM. + /// + /// Note: This only work for a certificate encoded in PEM format, else [TlsError::InvalidFormat] will be returned + /// + /// It should contain in order from the bottom up your certificate chain. + /// The top certificate (self-signed) can be omitted. + /// + /// # Client: + /// In client mode, this certificate will be used for client authentication + /// when communicating wiht the server. Do not call this function if you don't want to use + /// client authentication + /// + /// # Server: + /// In server mode, this will be the certificate given to the client when + /// performing a handshake. + /// + /// # Arguments + /// + /// * `certificate` - The X509 certificate in DER format + /// * `private_key` - The X509 private key in DER or PEM format + /// * `password` - The optional password if the private key is password protected + /// + /// # Errors + /// + /// - This function will fail with [TlsError::OutOfMemory] if there's not enough memory to + /// allocate certificates. + /// - [TlsError::InvalidFormat] will be returned if a PEM encoded certificate is passed. + pub fn with_certificates_no_copy( + mut self, + certificate: X509<'d>, + private_key: X509<'_>, + password: Option<&'_ str>, + ) -> Result { + self.certificate = Some(MbedTLSX509Crt::new_no_copy(certificate)?); + self.private_key = Some(PkContext::new(private_key, password)?); + Ok(self) + } + + /// Initialize the Certificate Authority chain used for requests without making an internal + /// copy in RAM. + /// Note: This currently only work for certificates in DER format. + /// + /// # Errors + /// + /// - This function will fail with [TlsError::OutOfMemory] if there's not enough memory to + /// allocate certificates. + /// - This function will fail with [TlsError::InvalidFormat] if a PEM encoded certificate is + /// provided. + pub fn with_ca_chain_no_copy(mut self, ca_chain: X509<'d>) -> Result { + self.ca_chain = Some(MbedTLSX509Crt::new_no_copy(ca_chain)?); + Ok(self) + } +} + impl Certificates<'_> { /// Create a new instance of [Certificates] with no certificates whatsoever pub const fn new() -> Self { @@ -303,33 +617,90 @@ impl Certificates<'_> { ca_chain: None, certificate: None, private_key: None, - password: None, } } - // Initialize the SSL using this set of certificates + /// Get a reference to the underlying parsed X509 peer certificate, if configured + pub fn certificate(&self) -> Option<&mbedtls_x509_crt> { + self.certificate.as_ref().and_then(|certificate| { + let ptr = certificate.crt; + if ptr.is_null() { + None + } else { + Some(unsafe { &*ptr }) + } + }) + } + + /// Get a reference to the underlying parsed CA Chain X509 certificate, if configured + pub fn ca_chain(&self) -> Option<&mbedtls_x509_crt> { + self.ca_chain.as_ref().and_then(|ca_chain| { + let ptr = ca_chain.crt; + if ptr.is_null() { + None + } else { + Some(unsafe { &*ptr }) + } + }) + } + + /// Initialize the own certificate chain and private key used for requests + /// It should contain in order from the bottom up your certificate chain. + /// The top certificate (self-signed) can be omitted. + /// + /// # Client: + /// In client mode, this certificate will be used for client authentication + /// when communicating wiht the server. Do not call this function if you don't want to use + /// client authentication + /// + /// # Server: + /// In server mode, this will be the certificate given to the client when + /// performing a handshake. + /// + /// # Arguments + /// + /// * `certificate` - The X509 certificate in DER or PEM format + /// * `private_key` - The X509 private key in DER or PEM format + /// * `password` - The optional password if the private key is password protected + /// + /// # Errors + /// + /// This function will fail with [TlsError::OutOfMemory] if there's not enough memory to + /// allocate certificates. + pub fn with_certificates( + mut self, + certificate: X509<'_>, + private_key: X509<'_>, + password: Option<&'_ str>, + ) -> Result { + self.certificate = Some(MbedTLSX509Crt::new(certificate)?); + self.private_key = Some(PkContext::new(private_key, password)?); + Ok(self) + } + + /// Initialize the Certificate Authority chain used for requests + /// + /// # Errors + /// + /// This function will fail with [TlsError::OutOfMemory] if there's not enough memory to + /// allocate certificates. + pub fn with_ca_chain(mut self, ca_chain: X509<'_>) -> Result { + self.ca_chain = Some(MbedTLSX509Crt::new(ca_chain)?); + Ok(self) + } + + /// Initialize the SSL using this set of certificates fn init_ssl( &self, - mode: Mode, - min_version: TlsVersion, + config: SessionConfig<'_>, ) -> Result< ( *mut mbedtls_ctr_drbg_context, *mut mbedtls_ssl_context, *mut mbedtls_ssl_config, - *mut mbedtls_x509_crt, - *mut mbedtls_x509_crt, - *mut mbedtls_pk_context, ), TlsError, > { - // Make sure that both certificate and private_key are either Some() or None - assert_eq!( - self.certificate.is_some(), - self.private_key.is_some(), - "Both certificate and private_key must be Some() or None" - ); - // TODO: Allocate a lot of these things: // - In one chunk // - With a `Box`, which is safer @@ -356,7 +727,7 @@ impl Certificates<'_> { size_of::(), ) as *mut mbedtls_ssl_context; if ssl_context.is_null() { - free(drbg_context as *const _); + mbedtls_free(drbg_context as *const _); return Err(TlsError::OutOfMemory); } @@ -365,55 +736,13 @@ impl Certificates<'_> { size_of::(), ) as *mut mbedtls_ssl_config; if ssl_config.is_null() { - free(drbg_context as *const _); - free(ssl_context as *const _); - return Err(TlsError::OutOfMemory); - } - - let crt = aligned_calloc( - align_of::(), - size_of::(), - ) as *mut mbedtls_x509_crt; - if crt.is_null() { - free(drbg_context as *const _); - free(ssl_context as *const _); - free(ssl_config as *const _); - return Err(TlsError::OutOfMemory); - } - - let certificate = aligned_calloc( - align_of::(), - size_of::(), - ) as *mut mbedtls_x509_crt; - if certificate.is_null() { - free(drbg_context as *const _); - free(ssl_context as *const _); - free(ssl_config as *const _); - free(crt as *const _); - return Err(TlsError::OutOfMemory); - } - - let private_key = aligned_calloc( - align_of::(), - size_of::(), - ) as *mut mbedtls_pk_context; - if private_key.is_null() { - free(drbg_context as *const _); - free(ssl_context as *const _); - free(ssl_config as *const _); - free(crt as *const _); - free(certificate as *const _); + mbedtls_free(drbg_context as *const _); + mbedtls_free(ssl_context as *const _); return Err(TlsError::OutOfMemory); } mbedtls_ssl_init(ssl_context); mbedtls_ssl_config_init(ssl_config); - // Initialize CA chain - mbedtls_x509_crt_init(crt); - // Initialize certificate - mbedtls_x509_crt_init(certificate); - // Initialize private key - mbedtls_pk_init(private_key); //(*ssl_config).private_f_dbg = Some(dbg_print); mbedtls_ssl_conf_dbg(ssl_config, Some(dbg_print), core::ptr::null_mut()); @@ -428,21 +757,15 @@ impl Certificates<'_> { mbedtls_ctr_drbg_free(drbg_context); mbedtls_ssl_config_free(ssl_config); mbedtls_ssl_free(ssl_context); - mbedtls_x509_crt_free(crt); - mbedtls_x509_crt_free(certificate); - mbedtls_pk_free(private_key); - free(drbg_context as *const _); - free(ssl_context as *const _); - free(ssl_config as *const _); - free(crt as *const _); - free(certificate as *const _); - free(private_key as *const _); + mbedtls_free(drbg_context as *const _); + mbedtls_free(ssl_context as *const _); + mbedtls_free(ssl_config as *const _); }; error_checked!( mbedtls_ssl_config_defaults( ssl_config, - mode.to_mbed_tls(), + config.mode.to_mbed_tls(), MBEDTLS_SSL_TRANSPORT_STREAM as i32, MBEDTLS_SSL_PRESET_DEFAULT as i32, ), @@ -451,86 +774,27 @@ impl Certificates<'_> { // Set the minimum TLS version // Use a ddirect field modified for compatibility with the `esp-idf-svc` mbedtls - (*ssl_config).private_min_tls_version = min_version.to_mbed_tls_version(); + (*ssl_config).private_min_tls_version = config.min_version.to_mbed_tls_version(); - mbedtls_ssl_conf_authmode( - ssl_config, - if self.ca_chain.is_some() { - MBEDTLS_SSL_VERIFY_REQUIRED as i32 - } else { - // Use this config when in server mode - // Ref: https://os.mbed.com/users/markrad/code/mbedtls/docs/tip/ssl_8h.html#a5695285c9dbfefec295012b566290f37 - MBEDTLS_SSL_VERIFY_NONE as i32 - }, - ); + mbedtls_ssl_conf_authmode(ssl_config, config.auth_mode.to_mbedtls_authmode()); - if let Mode::Client { servername } = mode { + if let Mode::Client { servername } = config.mode { error_checked!( mbedtls_ssl_set_hostname(ssl_context, servername.as_ptr(),), cleanup )?; } - if let Some(ca_chain) = self.ca_chain { - error_checked!( - mbedtls_x509_crt_parse(crt, ca_chain.as_ptr(), ca_chain.len()), - cleanup - )?; + if let (Some(certificate), Some(private_key)) = (&self.certificate, &self.private_key) { + mbedtls_ssl_conf_own_cert(ssl_config, certificate.crt, private_key.0); } - if let (Some(cert), Some(key)) = (self.certificate, self.private_key) { - // Certificate - match cert.format { - CertificateFormat::PEM => { - error_checked!( - mbedtls_x509_crt_parse(certificate, cert.as_ptr(), cert.len()), - cleanup - )?; - } - CertificateFormat::DER => { - error_checked!( - mbedtls_x509_crt_parse_der_nocopy( - certificate, - cert.as_ptr(), - cert.len(), - ), - cleanup - )?; - } - } - - // Private key - let (password_ptr, password_len) = if let Some(password) = self.password { - (password.as_ptr(), password.len()) - } else { - (core::ptr::null(), 0) - }; - error_checked!( - mbedtls_pk_parse_key( - private_key, - key.as_ptr(), - key.len(), - password_ptr, - password_len, - None, - core::ptr::null_mut(), - ), - cleanup - )?; - - mbedtls_ssl_conf_own_cert(ssl_config, certificate, private_key); + if let Some(ref ca_chain) = self.ca_chain { + mbedtls_ssl_conf_ca_chain(ssl_config, ca_chain.crt, core::ptr::null_mut()); } - mbedtls_ssl_conf_ca_chain(ssl_config, crt, core::ptr::null_mut()); error_checked!(mbedtls_ssl_setup(ssl_context, ssl_config), cleanup)?; - Ok(( - drbg_context, - ssl_context, - ssl_config, - crt, - certificate, - private_key, - )) + Ok((drbg_context, ssl_context, ssl_config)) } } } @@ -671,9 +935,6 @@ pub struct Session<'a, T> { drbg_context: *mut mbedtls_ctr_drbg_context, ssl_context: *mut mbedtls_ssl_context, ssl_config: *mut mbedtls_ssl_config, - crt: *mut mbedtls_x509_crt, - client_crt: *mut mbedtls_x509_crt, - private_key: *mut mbedtls_pk_context, state: SessionState, _tls_ref: TlsReference<'a>, } @@ -686,6 +947,7 @@ impl<'a, T> Session<'a, T> { /// * `stream` - The stream for the connection. /// * `mode` - Use [Mode::Client] if you are running a client. [Mode::Server] if you are /// running a server. + /// * `auth_mode` - Certificate verification mode /// * `min_version` - The minimum TLS version for the connection, that will be accepted. /// * `certificates` - Certificate chain for the connection. Will play a different role /// depending on if running as client or server. See [Certificates] for more information. @@ -698,21 +960,16 @@ impl<'a, T> Session<'a, T> { /// invalid format. pub fn new( stream: T, - mode: Mode, - min_version: TlsVersion, - certificates: Certificates, + config: SessionConfig<'_>, + certificates: &'a Certificates<'a>, tls_ref: TlsReference<'a>, ) -> Result { - let (drbg_context, ssl_context, ssl_config, crt, client_crt, private_key) = - certificates.init_ssl(mode, min_version)?; + let (drbg_context, ssl_context, ssl_config) = certificates.init_ssl(config)?; Ok(Self { stream, drbg_context, ssl_context, ssl_config, - crt, - client_crt, - private_key, state: SessionState::Initial, _tls_ref: tls_ref, }) @@ -911,15 +1168,9 @@ impl Drop for Session<'_, T> { mbedtls_ctr_drbg_free(self.drbg_context); mbedtls_ssl_config_free(self.ssl_config); mbedtls_ssl_free(self.ssl_context); - mbedtls_x509_crt_free(self.crt); - mbedtls_x509_crt_free(self.client_crt); - mbedtls_pk_free(self.private_key); - free(self.drbg_context as *const _); - free(self.ssl_config as *const _); - free(self.ssl_context as *const _); - free(self.crt as *const _); - free(self.client_crt as *const _); - free(self.private_key as *const _); + mbedtls_free(self.drbg_context as *const _); + mbedtls_free(self.ssl_config as *const _); + mbedtls_free(self.ssl_context as *const _); } } } @@ -985,9 +1236,6 @@ pub mod asynch { drbg_context: *mut mbedtls_ctr_drbg_context, ssl_context: *mut mbedtls_ssl_context, ssl_config: *mut mbedtls_ssl_config, - crt: *mut mbedtls_x509_crt, - client_crt: *mut mbedtls_x509_crt, - private_key: *mut mbedtls_pk_context, state: SessionState, read_byte: Option, write_byte: Option, @@ -1002,6 +1250,7 @@ pub mod asynch { /// * `stream` - The stream for the connection. /// * `mode` - Use [Mode::Client] if you are running a client. [Mode::Server] if you are /// running a server. + /// * `auth_mode` - Certificate verification mode /// * `min_version` - The minimum TLS version for the connection, that will be accepted. /// * `certificates` - Certificate chain for the connection. Will play a different role /// depending on if running as client or server. See [Certificates] for more information. @@ -1014,21 +1263,16 @@ pub mod asynch { /// invalid format. pub fn new( stream: T, - mode: Mode, - min_version: TlsVersion, - certificates: Certificates, + config: SessionConfig<'_>, + certificates: &'a Certificates<'a>, tls_ref: TlsReference<'a>, ) -> Result { - let (drbg_context, ssl_context, ssl_config, crt, client_crt, private_key) = - certificates.init_ssl(mode, min_version)?; + let (drbg_context, ssl_context, ssl_config) = certificates.init_ssl(config)?; Ok(Self { stream, drbg_context, ssl_context, ssl_config, - crt, - client_crt, - private_key, state: SessionState::Initial, read_byte: None, write_byte: None, @@ -1045,15 +1289,9 @@ pub mod asynch { mbedtls_ctr_drbg_free(self.drbg_context); mbedtls_ssl_config_free(self.ssl_config); mbedtls_ssl_free(self.ssl_context); - mbedtls_x509_crt_free(self.crt); - mbedtls_x509_crt_free(self.client_crt); - mbedtls_pk_free(self.private_key); - free(self.drbg_context as *const _); - free(self.ssl_config as *const _); - free(self.ssl_context as *const _); - free(self.crt as *const _); - free(self.client_crt as *const _); - free(self.private_key as *const _); + mbedtls_free(self.drbg_context as *const _); + mbedtls_free(self.ssl_config as *const _); + mbedtls_free(self.ssl_context as *const _); } } } diff --git a/examples/async_client.rs b/examples/async_client.rs index b79eb1c..4f47950 100644 --- a/examples/async_client.rs +++ b/examples/async_client.rs @@ -21,7 +21,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_mbedtls::{asynch::Session, Certificates, Mode, TlsVersion}; -use esp_mbedtls::{Tls, X509}; +use esp_mbedtls::{SessionConfig, Tls, X509}; use esp_println::logger::init_logger; use esp_println::{print, println}; use esp_wifi::wifi::{ @@ -140,28 +140,26 @@ async fn main(spawner: Spawner) -> ! { cfg_if::cfg_if! { if #[cfg(feature = "mtls")] { - let certificates = Certificates { - ca_chain: X509::pem( - concat!(include_str!("./certs/certauth.cryptomix.com.pem"), "\0").as_bytes(), + let certificates = Certificates::new() + .with_certificates( + X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()).unwrap(), + X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()).unwrap(), + None, ) - .ok(), - certificate: X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()) - .ok(), - private_key: X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()) - .ok(), - password: None, - }; + .unwrap() + .with_ca_chain( + X509::pem(concat!(include_str!("./certs/certauth.cryptomix.com.pem"), "\0").as_bytes()) + .unwrap(), + ); } else { - let certificates = Certificates { - ca_chain: X509::pem( - concat!(include_str!("./certs/www.google.com.pem"), "\0").as_bytes(), - ) - .ok(), - ..Default::default() - }; + let certificates = Certificates::new().with_ca_chain( + X509::pem(concat!(include_str!("./certs/www.google.com.pem"), "\0").as_bytes()).unwrap(), + ); } } + let certificates = certificates.unwrap(); + let mut tls = Tls::new(peripherals.SHA) .unwrap() .with_hardware_rsa(peripherals.RSA); @@ -170,11 +168,13 @@ async fn main(spawner: Spawner) -> ! { let mut session = Session::new( &mut socket, - Mode::Client { - servername: SERVERNAME, - }, - TlsVersion::Tls1_3, - certificates, + SessionConfig::new( + Mode::Client { + servername: SERVERNAME, + }, + TlsVersion::Tls1_3, + ), + &certificates, tls.reference(), ) .unwrap(); diff --git a/examples/async_server.rs b/examples/async_server.rs index 3c994fb..6603d48 100644 --- a/examples/async_server.rs +++ b/examples/async_server.rs @@ -40,8 +40,8 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_alloc as _; use esp_backtrace as _; -use esp_mbedtls::{asynch::Session, Certificates, Mode, TlsVersion}; -use esp_mbedtls::{Tls, TlsError, X509}; +use esp_mbedtls::{asynch::Session, AuthMode, Certificates, Mode, TlsVersion}; +use esp_mbedtls::{SessionConfig, Tls, TlsError, X509}; use esp_println::logger::init_logger; use esp_println::{print, println}; use esp_wifi::wifi::{ @@ -144,6 +144,25 @@ async fn main(spawner: Spawner) -> ! { let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(Duration::from_secs(10))); + + let certificates = Certificates::new() + .with_certificates_no_copy( + X509::der(include_bytes!("./certs/certificate.der")), + X509::der(include_bytes!("./certs/private_key.der")), + None, + ) + .unwrap() + .with_ca_chain( + X509::pem(concat!(include_str!("./certs/ca_cert.pem"), "\0").as_bytes()).unwrap(), + ) + .unwrap(); + + let mut config = SessionConfig::new(Mode::Server, TlsVersion::Tls1_2); + + if cfg!(feature = "mtls") { + config.set_auth_mode(AuthMode::Required); + } + loop { println!("Waiting for connection..."); let r = socket @@ -163,29 +182,8 @@ async fn main(spawner: Spawner) -> ! { let mut buffer = [0u8; 1024]; let mut pos = 0; - let mut session = Session::new( - &mut socket, - Mode::Server, - TlsVersion::Tls1_2, - Certificates { - // Provide a ca_chain if you want to enable mTLS for the server. - #[cfg(feature = "mtls")] - ca_chain: X509::pem(concat!(include_str!("./certs/ca_cert.pem"), "\0").as_bytes()) - .ok(), - // Use self-signed certificates - certificate: X509::pem( - concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes(), - ) - .ok(), - private_key: X509::pem( - concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes(), - ) - .ok(), - ..Default::default() - }, - tls.reference(), - ) - .unwrap(); + let mut session = + Session::new(&mut socket, config, &certificates, tls.reference()).unwrap(); println!("Start tls connect"); match session.connect().await { diff --git a/examples/certs/certificate.der b/examples/certs/certificate.der new file mode 100644 index 0000000..be98eea Binary files /dev/null and b/examples/certs/certificate.der differ diff --git a/examples/certs/private_key.der b/examples/certs/private_key.der new file mode 100644 index 0000000..c6835fe Binary files /dev/null and b/examples/certs/private_key.der differ diff --git a/examples/edge_server.rs b/examples/edge_server.rs index 5da99f6..b686f67 100644 --- a/examples/edge_server.rs +++ b/examples/edge_server.rs @@ -27,7 +27,7 @@ use embassy_net::{Config, Runner, StackResources}; use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; -use esp_mbedtls::{Certificates, Tls, TlsVersion}; +use esp_mbedtls::{AuthMode, Certificates, Tls, TlsVersion}; use esp_mbedtls::{TlsError, X509}; use esp_println::logger::init_logger; use esp_println::println; @@ -149,14 +149,13 @@ async fn main(spawner: Spawner) -> ! { .await .unwrap(); - let certificates = Certificates { - // Use self-signed certificates - certificate: X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()) - .ok(), - private_key: X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()) - .ok(), - ..Default::default() - }; + let certificates = Certificates::new() + .with_certificates_no_copy( + X509::der(include_bytes!("./certs/certificate.der")), + X509::der(include_bytes!("./certs/private_key.der")), + None, + ) + .unwrap(); let mut tls = Tls::new(peripherals.SHA) .unwrap() @@ -167,8 +166,9 @@ async fn main(spawner: Spawner) -> ! { loop { let tls_acceptor = esp_mbedtls::asynch::TlsAcceptor::new( &acceptor, + AuthMode::None, TlsVersion::Tls1_2, - certificates, + &certificates, tls.reference(), ); match server diff --git a/examples/sync_client.rs b/examples/sync_client.rs index ab1ea6f..b4b2336 100644 --- a/examples/sync_client.rs +++ b/examples/sync_client.rs @@ -16,7 +16,7 @@ use blocking_network_stack::Stack; use esp_alloc as _; use esp_backtrace as _; -use esp_mbedtls::{Certificates, Session}; +use esp_mbedtls::{Certificates, Session, SessionConfig}; use esp_mbedtls::{Mode, Tls, TlsVersion, X509}; use esp_println::{logger::init_logger, print, println}; use esp_wifi::{ @@ -136,28 +136,26 @@ fn main() -> ! { cfg_if::cfg_if! { if #[cfg(feature = "mtls")] { - let certificates = Certificates { - ca_chain: X509::pem( - concat!(include_str!("./certs/certauth.cryptomix.com.pem"), "\0").as_bytes(), + let certificates = Certificates::new() + .with_certificates( + X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()).unwrap(), + X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()).unwrap(), + None, ) - .ok(), - certificate: X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()) - .ok(), - private_key: X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()) - .ok(), - password: None, - }; + .unwrap() + .with_ca_chain( + X509::pem(concat!(include_str!("./certs/certauth.cryptomix.com.pem"), "\0").as_bytes()) + .unwrap(), + ); } else { - let certificates = Certificates { - ca_chain: X509::pem( - concat!(include_str!("./certs/www.google.com.pem"), "\0").as_bytes(), - ) - .ok(), - ..Default::default() - }; + let certificates = Certificates::new().with_ca_chain( + X509::pem(concat!(include_str!("./certs/www.google.com.pem"), "\0").as_bytes()).unwrap(), + ); } } + let certificates = certificates.unwrap(); + let mut tls = Tls::new(peripherals.SHA) .unwrap() .with_hardware_rsa(peripherals.RSA); @@ -166,11 +164,13 @@ fn main() -> ! { let mut session = Session::new( &mut socket, - Mode::Client { - servername: SERVERNAME, - }, - TlsVersion::Tls1_3, - certificates, + SessionConfig::new( + Mode::Client { + servername: SERVERNAME, + }, + TlsVersion::Tls1_3, + ), + &certificates, tls.reference(), ) .unwrap(); diff --git a/examples/sync_server.rs b/examples/sync_server.rs index a79b2aa..625b286 100644 --- a/examples/sync_server.rs +++ b/examples/sync_server.rs @@ -35,7 +35,7 @@ use blocking_network_stack::Stack; use embedded_io::*; use esp_backtrace as _; -use esp_mbedtls::{Certificates, Session}; +use esp_mbedtls::{AuthMode, Certificates, Session, SessionConfig}; use esp_mbedtls::{Mode, Tls, TlsError, TlsVersion, X509}; use esp_println::{logger::init_logger, print, println}; use esp_wifi::{ @@ -147,6 +147,24 @@ fn main() -> ! { tls.set_debug(0); + let certificates = Certificates::new() + .with_certificates_no_copy( + X509::der(include_bytes!("./certs/certificate.der")), + X509::der(include_bytes!("./certs/private_key.der")), + None, + ) + .unwrap() + .with_ca_chain( + X509::pem(concat!(include_str!("./certs/ca_cert.pem"), "\0").as_bytes()).unwrap(), + ) + .unwrap(); + + let mut config = SessionConfig::new(Mode::Server, TlsVersion::Tls1_2); + + if cfg!(feature = "mtls") { + config.set_auth_mode(AuthMode::Required); + } + loop { socket.work(); @@ -162,31 +180,8 @@ fn main() -> ! { let mut buffer = [0u8; 1024]; let mut pos = 0; - let mut session = Session::new( - &mut socket, - Mode::Server, - TlsVersion::Tls1_2, - Certificates { - // Provide a ca_chain if you want to enable mTLS for the server. - #[cfg(feature = "mtls")] - ca_chain: X509::pem( - concat!(include_str!("./certs/ca_cert.pem"), "\0").as_bytes(), - ) - .ok(), - // Use self-signed certificates - certificate: X509::pem( - concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes(), - ) - .ok(), - private_key: X509::pem( - concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes(), - ) - .ok(), - ..Default::default() - }, - tls.reference(), - ) - .unwrap(); + let mut session = + Session::new(&mut socket, config, &certificates, tls.reference()).unwrap(); match session.connect() { Ok(_) => { diff --git a/genssl.sh b/genssl.sh index a321c02..8c492d0 100755 --- a/genssl.sh +++ b/genssl.sh @@ -43,3 +43,9 @@ openssl x509 \ # Remove csr rm $CERTS_DIR/csr.pem + +# Converts to DER format +# Certificate +openssl x509 -in $CERTS_DIR/certificate.pem -out $CERTS_DIR/certificate.der -outform DER +# Private Key +openssl rsa -in $CERTS_DIR/private_key.pem -out $CERTS_DIR/private_key.der -outform DER diff --git a/justfile b/justfile index 3e379d6..d698f62 100644 --- a/justfile +++ b/justfile @@ -2,6 +2,7 @@ export SSID := "Dummy" export PASSWORD := "Dummy" all: (check "esp32" "esp") (check "esp32s3" "esp") (check "esp32c3" "nightly") + cargo +nightly b --example crypto_self_test_std --features="examples-std" --target x86_64-unknown-linux-gnu -Z build-std=std,panic_abort cd esp-mbedtls && cargo +nightly fmt --all -- --check [private] @@ -16,5 +17,4 @@ check arch toolchain: cargo +{{ toolchain }} b{{ arch }} --example async_server --features="examples-async, mtls" cargo +{{ toolchain }} b{{ arch }} --example edge_server --features="examples-async" cargo +{{ toolchain }} b{{ arch }} --example crypto_self_test --features="examples" - cargo +{{ toolchain }} b --example crypto_self_test_std --features="examples-std" --target x86_64-unknown-linux-gnu -Z build-std=std,panic_abort cargo +{{ toolchain }} fmt --all -- --check