diff --git a/Cargo.lock b/Cargo.lock index da4c0723..c0d9c202 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1047,14 +1047,12 @@ dependencies = [ [[package]] name = "mbedtls-platform-support" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be354d52c70402fbfb37bad9ae2aa99ab52af79f37423cb9d6c41c8fb863abc7" dependencies = [ "cc", "cfg-if", "chrono", "mbedtls-sys-auto", - "spin 0.4.10", + "spin 0.5.2", ] [[package]] @@ -1709,12 +1707,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "spin" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" - [[package]] name = "spin" version = "0.5.2" diff --git a/Cargo.toml b/Cargo.toml index c6a670a3..74e9f9db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,3 +73,4 @@ resolver = "2" [patch.crates-io] ring = { path = "external/ring" } webpki = { path = "external/webpki" } + mbedtls-platform-support = { path = "spdmlib_crypto_mbedtls/mbedtls-platform-support" } \ No newline at end of file diff --git a/spdmlib_crypto_mbedtls/mbedtls-platform-support/Cargo.toml b/spdmlib_crypto_mbedtls/mbedtls-platform-support/Cargo.toml new file mode 100644 index 00000000..7f1ddb73 --- /dev/null +++ b/spdmlib_crypto_mbedtls/mbedtls-platform-support/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "mbedtls-platform-support" +version = "0.1.1" +authors = ["Yuxiang Cao "] +build = "build.rs" +edition = "2018" +license = "Apache-2.0 OR GPL-2.0-or-later" +description = """ +This Rust crate is a support library for the `mbedtls` crate, providing platform and target specific +implementations of all necessary functions. By separating this logic into a separate crate, multiple +versions of the mbedtls crate can coexist within a single crate.This helps to avoid link name conflict +errors. The crate exports Rust functions and defines C functions to support external overrides as +needed for custom implementation under various platforms or targets. +""" +readme = "../README.md" +repository = "https://github.com/fortanix/rust-mbedtls" +documentation = "https://docs.rs/mbedtls-platform-support/" +keywords = ["MbedTLS", "mbed", "TLS", "SSL", "cryptography"] +links = "mbedtls-platform-support" + +[dependencies] +cfg-if = "1.0.0" +spin = { version = "0.5.2", default-features = false, optional = true } +chrono = { version = "0.4", optional = true } + +[target.x86_64-fortanix-unknown-sgx.dependencies] +chrono = "0.4" + +[dependencies.mbedtls-sys-auto] +version = "2.25.0" +default-features = false +features = ["threading", "custom_printf"] + +[build-dependencies] +cc = "1.0" + +[features] +time = ["mbedtls-sys-auto/time"] +std = ["mbedtls-sys-auto/std"] +spin_threading = ["spin", "mbedtls-sys-auto/custom_threading"] +rust_threading = ["mbedtls-sys-auto/custom_threading", "std"] +custom_gmtime_r = ["mbedtls-sys-auto/custom_gmtime_r", "chrono"] +custom_time = ["mbedtls-sys-auto/custom_time", "chrono"] +force_aesni_support = ["mbedtls-sys-auto/custom_has_support","mbedtls-sys-auto/aes_alt", "aesni"] +aesni = ["mbedtls-sys-auto/aesni"] diff --git a/spdmlib_crypto_mbedtls/mbedtls-platform-support/Readme.md b/spdmlib_crypto_mbedtls/mbedtls-platform-support/Readme.md new file mode 100644 index 00000000..bfcb9f83 --- /dev/null +++ b/spdmlib_crypto_mbedtls/mbedtls-platform-support/Readme.md @@ -0,0 +1 @@ +Customized mbedtls-platform-support crate for rust-mbedtls diff --git a/spdmlib_crypto_mbedtls/mbedtls-platform-support/build.rs b/spdmlib_crypto_mbedtls/mbedtls-platform-support/build.rs new file mode 100644 index 00000000..98074ad8 --- /dev/null +++ b/spdmlib_crypto_mbedtls/mbedtls-platform-support/build.rs @@ -0,0 +1,39 @@ +/* Copyright (c) Fortanix, Inc. + * + * Licensed under the GNU General Public License, version 2 or the Apache License, Version + * 2.0 , at your + * option. This file may not be copied, modified, or distributed except + * according to those terms. */ + +use std::collections::{HashMap, HashSet}; +use std::env; + +fn main() { + let env_components = env::var("DEP_MBEDTLS_PLATFORM_COMPONENTS").unwrap(); + let mut sys_platform_components = HashMap::<_, HashSet<_>>::new(); + for mut kv in env_components.split(",").map(|component| component.splitn(2, "=")) { + let k = kv.next().unwrap(); + let v = kv.next().unwrap(); + sys_platform_components.entry(k).or_insert_with(Default::default).insert(v); + println!(r#"cargo:rustc-cfg=sys_{}="{}""#, k, v); + } + + let mut b = cc::Build::new(); + b.include(env::var_os("DEP_MBEDTLS_INCLUDE").unwrap()); + let config_file = format!(r#""{}""#, env::var("DEP_MBEDTLS_CONFIG_H").unwrap()); + b.define("MBEDTLS_CONFIG_FILE", + Some(config_file.as_str())); + + b.file("src/rust_printf.c"); + if sys_platform_components.get("c_compiler").map_or(false, |comps| comps.contains("freestanding")) { + b.flag("-U_FORTIFY_SOURCE") + .define("_FORTIFY_SOURCE", Some("0")) + .flag("-ffreestanding"); + } + b.compile("librust-mbedtls-platform-support.a"); + // Force correct link order for mbedtls_printf + println!("cargo:rustc-link-lib=static=mbedtls"); + println!("cargo:rustc-link-lib=static=mbedx509"); + println!("cargo:rustc-link-lib=static=mbedcrypto"); +} diff --git a/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/lib.rs b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/lib.rs new file mode 100644 index 00000000..b9572636 --- /dev/null +++ b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/lib.rs @@ -0,0 +1,108 @@ +/* Copyright (c) Fortanix, Inc. + * + * Licensed under the GNU General Public License, version 2 or the Apache License, Version + * 2.0 , at your + * option. This file may not be copied, modified, or distributed except + * according to those terms. */ + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +#[allow(unused)] +#[macro_use] +extern crate alloc as rust_alloc; + +#[cfg(not(feature = "std"))] +mod alloc_prelude { + #![allow(unused)] + pub(crate) use rust_alloc::borrow::ToOwned; + pub(crate) use rust_alloc::boxed::Box; + pub(crate) use rust_alloc::sync::Arc; + pub(crate) use rust_alloc::string::String; + pub(crate) use rust_alloc::string::ToString; + pub(crate) use rust_alloc::vec::Vec; + pub(crate) use rust_alloc::borrow::Cow; +} + +pub mod self_test; + +#[cfg(any(feature = "spin_threading", feature = "rust_threading", sys_threading_component = "custom"))] +#[doc(hidden)] +pub mod threading; + +#[cfg(any(feature = "force_aesni_support", target_env = "sgx"))] +#[doc(hidden)] +#[no_mangle] +// needs to be pub for global visibility +pub extern "C" fn mbedtls_aesni_has_support(_what: u32) -> i32 { + return 1; +} + +#[cfg(any(feature = "force_aesni_support", target_env = "sgx"))] +#[doc(hidden)] +#[no_mangle] +// needs to be pub for global visibility +pub extern "C" fn mbedtls_internal_aes_encrypt(_ctx: *mut mbedtls_sys::types::raw_types::c_void, + _input: *const u8, + _output: *mut u8) -> i32 { + panic!("AES-NI support is forced but the T-tables code was invoked") +} + +#[cfg(any(feature = "force_aesni_support", target_env = "sgx"))] +#[doc(hidden)] +#[no_mangle] +// needs to be pub for global visibility +pub extern "C" fn mbedtls_internal_aes_decrypt(_ctx: *mut mbedtls_sys::types::raw_types::c_void, + _input: *const u8, + _output: *mut u8) -> i32 { + panic!("AES-NI support is forced but the T-tables code was invoked") +} + + +#[cfg(any(all(feature = "time", feature = "custom_gmtime_r"), sys_time_component = "custom"))] +#[doc(hidden)] +#[no_mangle] +// needs to be pub for global visibility +pub unsafe extern "C" fn mbedtls_platform_gmtime_r(tt: *const mbedtls_sys::types::time_t, tp: *mut mbedtls_sys::types::tm) -> *mut mbedtls_sys::types::tm { + use chrono::prelude::*; + + //0 means no TZ offset + let naive = if tp.is_null() { + return core::ptr::null_mut() + } else { + match NaiveDateTime::from_timestamp_opt(*tt, 0) { + Some(t) => t, + None => return core::ptr::null_mut() + } + }; + let utc = DateTime::::from_utc(naive, Utc); + + let tp = &mut *tp; + tp.tm_sec = utc.second() as i32; + tp.tm_min = utc.minute() as i32; + tp.tm_hour = utc.hour() as i32; + tp.tm_mday = utc.day() as i32; + tp.tm_mon = utc.month0() as i32; + tp.tm_year = match (utc.year() as i32).checked_sub(1900) { + Some(year) => year, + None => return core::ptr::null_mut() + }; + tp.tm_wday = utc.weekday().num_days_from_sunday() as i32; + tp.tm_yday = utc.ordinal0() as i32; + tp.tm_isdst = 0; + + tp +} + +#[cfg(any(all(feature = "time", feature = "custom_time"), sys_time_component = "custom"))] +#[doc(hidden)] +#[no_mangle] +// needs to be pub for global visibility +pub unsafe extern "C" fn mbedtls_time(tp: *mut mbedtls_sys::types::time_t) -> mbedtls_sys::types::time_t { + let timestamp = chrono::Utc::now().timestamp() as mbedtls_sys::types::time_t; + if !tp.is_null() { + *tp = timestamp; + } + timestamp +} diff --git a/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/rust_printf.c b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/rust_printf.c new file mode 100644 index 00000000..d11d02e4 --- /dev/null +++ b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/rust_printf.c @@ -0,0 +1,43 @@ +/* Copyright (c) Fortanix, Inc. + * + * Licensed under the GNU General Public License, version 2 or the Apache License, Version + * 2.0 , at your + * option. This file may not be copied, modified, or distributed except + * according to those terms. */ + +#include +#include +#ifdef _WIN32 +#define alloca _alloca +#include +#else +#include +#endif + +extern void mbedtls_log(const char* msg); + +extern int mbedtls_printf(const char *fmt, ...) { + va_list ap; + + va_start(ap,fmt); + int n=vsnprintf(0,0,fmt,ap); + va_end(ap); + + if (n<0) + return -1; + + n++; + char *p = alloca(n); + + va_start(ap,fmt); + n=vsnprintf(p,n,fmt,ap); + va_end(ap); + + if (n<0) + return -1; + + mbedtls_log(p); + + return n; +} diff --git a/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/self_test.rs b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/self_test.rs new file mode 100644 index 00000000..37bb5ffb --- /dev/null +++ b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/self_test.rs @@ -0,0 +1,104 @@ +/* Copyright (c) Fortanix, Inc. + * + * Licensed under the GNU General Public License, version 2 or the Apache License, Version + * 2.0 , at your + * option. This file may not be copied, modified, or distributed except + * according to those terms. */ + +//! MbedTLS self tests. +//! +//! Calling MbedTLS self test functions before they're enabled using the +//! `enable()` function here will result in a panic. +//! +//! Using this module in multithreaded or async environment will fail. The self +//! test functions rely on global variables to track operations and anything +//! non-self-test related operations will clobber these variables, resulting in +//! self test failures. Make sure no other code uses MbedTLS while running the +//! self tests. Multiple self test operations done simultaneously may also +//! return failures. + +use mbedtls_sys::types::raw_types::{c_char, c_int}; + +cfg_if::cfg_if! { + if #[cfg(feature = "std")] { + // needs to be pub for global visiblity + #[doc(hidden)] + #[no_mangle] + pub unsafe extern "C" fn mbedtls_log(msg: *const std::os::raw::c_char) { + print!("{}", std::ffi::CStr::from_ptr(msg).to_string_lossy()); + } + } else { + #[allow(non_upper_case_globals)] + static mut log_f: Option = None; + + // needs to be pub for global visiblity + #[doc(hidden)] + #[no_mangle] + pub unsafe extern "C" fn mbedtls_log(msg: *const c_char) { + log_f.expect("Called self-test log without enabling self-test")(msg) + } + } +} + +#[cfg(any(not(feature = "std"), target_env = "sgx"))] +#[allow(non_upper_case_globals)] +static mut rand_f: Option c_int> = None; + +// needs to be pub for global visiblity +#[cfg(all(any(not(feature = "std"), target_env = "sgx"), not(target_env = "msvc")))] +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn rand() -> c_int { + rand_f.expect("Called self-test rand without enabling self-test")() +} + +/// Set callback functions to enable the MbedTLS self tests. +/// +/// `rand` only needs to be set on platforms that don't have a `rand()` +/// function in libc. `log` only needs to be set when using `no_std`, i.e. +/// the `std` feature of this create is not enabled. If neither function +/// needs to be set, you don't have to call `enable()`. +/// +/// # Safety +/// +/// The caller needs to ensure this function is not called while any other +/// function in this module is called. +#[allow(unused)] +pub unsafe fn enable(rand: fn() -> c_int, log: Option) { + #[cfg(any(not(feature = "std"), target_env = "sgx"))] { + rand_f = Some(rand); + } + #[cfg(not(feature = "std"))] { + log_f = log; + } +} + +/// # Safety +/// +/// The caller needs to ensure this function is not called while any other +/// function in this module is called. +pub unsafe fn disable() { + #[cfg(any(not(feature = "std"), target_env = "sgx"))] { + rand_f = None; + } + #[cfg(not(feature = "std"))] { + log_f = None; + } +} + +/// # Safety +/// +/// The caller needs to ensure this function is not called while *any other* +/// MbedTLS function is called. See the module documentation for more +/// information. +pub use mbedtls_sys::{ + aes_self_test as aes, arc4_self_test as arc4, aria_self_test as aria, base64_self_test as base64, + camellia_self_test as camellia, ccm_self_test as ccm, ctr_drbg_self_test as ctr_drbg, + des_self_test as des, dhm_self_test as dhm, ecjpake_self_test as ecjpake, ecp_self_test as ecp, + entropy_self_test as entropy, gcm_self_test as gcm, hmac_drbg_self_test as hmac_drbg, + md2_self_test as md2, md4_self_test as md4, md5_self_test as md5, mpi_self_test as mpi, + pkcs5_self_test as pkcs5, ripemd160_self_test as ripemd160, rsa_self_test as rsa, + sha1_self_test as sha1, sha256_self_test as sha256, sha512_self_test as sha512, + x509_self_test as x509, xtea_self_test as xtea, nist_kw_self_test as nist_kw, cmac_self_test as cmac +}; diff --git a/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/threading.rs b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/threading.rs new file mode 100644 index 00000000..94aa72d7 --- /dev/null +++ b/spdmlib_crypto_mbedtls/mbedtls-platform-support/src/threading.rs @@ -0,0 +1,116 @@ +/* Copyright (c) Fortanix, Inc. + * + * Licensed under the GNU General Public License, version 2 or the Apache License, Version + * 2.0 , at your + * option. This file may not be copied, modified, or distributed except + * according to those terms. */ + +#[cfg(not(feature = "std"))] +use crate::alloc_prelude::*; + +// use cfg_if to ensure conditional compilation is compatible with v0.7 code +cfg_if::cfg_if! { + if #[cfg(any(all(feature = "spin_threading", not(feature = "rust_threading")), not(feature = "std")))] { + use spin::{Mutex, MutexGuard}; + } else if #[cfg(any(feature = "rust_threading", feature = "std"))] { + use std::sync::{Mutex, MutexGuard}; + } else { + {} + } +} + +use core::ptr; + +use mbedtls_sys::types::raw_types::c_int; + +pub struct StaticMutex { + guard: Option>, + mutex: Mutex<()>, +} + +#[no_mangle] +#[allow(non_upper_case_globals)] +pub static mut mbedtls_mutex_init: unsafe extern "C" fn(mutex: *mut *mut StaticMutex) = StaticMutex::init; +#[no_mangle] +#[allow(non_upper_case_globals)] +pub static mut mbedtls_mutex_free: unsafe extern "C" fn(mutex: *mut *mut StaticMutex) = StaticMutex::free; +#[no_mangle] +#[allow(non_upper_case_globals)] +pub static mut mbedtls_mutex_lock: unsafe extern "C" fn(mutex: *mut *mut StaticMutex) -> c_int = StaticMutex::lock; +#[no_mangle] +#[allow(non_upper_case_globals)] +pub static mut mbedtls_mutex_unlock: unsafe extern "C" fn(mutex: *mut *mut StaticMutex) -> c_int = StaticMutex::unlock; + +// The nightly compiler complains that StaticMutex has no representation hint, +// but this is not an issue because this pointer is opaque to mbedtls +#[allow(improper_ctypes)] +impl StaticMutex { + unsafe extern "C" fn init(mutex: *mut *mut StaticMutex) { + if let Some(m) = mutex.as_mut() { + *m = Box::into_raw(Box::new(StaticMutex { + guard: None, + mutex: Mutex::new(()), + })); + } + } + + unsafe extern "C" fn free(mutex: *mut *mut StaticMutex) { + if let Some(m) = mutex.as_mut() { + if *m != ptr::null_mut() { + let mut mutex = Box::from_raw(*m); + mutex.guard.take(); + *m = ptr::null_mut(); + } + } + } + + unsafe extern "C" fn lock(mutex: *mut *mut StaticMutex) -> c_int { + if let Some(m) = mutex.as_mut().and_then(|p| p.as_mut()) { + let guard = m.mutex.lock(); + + // use cfg_if to ensure conditional compilation is compatible with v0.7 code + cfg_if::cfg_if! { + if #[cfg(any(not(feature = "std"), feature = "spin_threading"))] { + m.guard = Some(guard); + } else if #[cfg(any(feature = "std", all(feature = "rust_threading", not(feature = "spin_threading"))))] { + m.guard = Some(guard.unwrap()); + } else { + {} + } + } + + 0 + } else { + ::mbedtls_sys::ERR_THREADING_BAD_INPUT_DATA + } + } + + unsafe extern "C" fn unlock(mutex: *mut *mut StaticMutex) -> c_int { + if let Some(m) = mutex.as_mut().and_then(|p| p.as_mut()) { + m.guard.take(); + 0 + } else { + ::mbedtls_sys::ERR_THREADING_BAD_INPUT_DATA + } + } +} + +pub fn test_double_free() { + unsafe { + let mut mutex: *mut StaticMutex = ptr::null_mut(); + mbedtls_mutex_init(&mut mutex); + mbedtls_mutex_free(&mut mutex); + mbedtls_mutex_free(&mut mutex); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn double_free() { + test_double_free() + } +}