From 62a1df305d43b3c67abaa7f1f89f1daca80a0839 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Wed, 20 May 2026 19:38:25 +0000 Subject: [PATCH 1/2] Add .gitingnore for Rust target/ directory Signed-off-by: Joe Richey --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9194a7e..83458dd 100644 --- a/.gitignore +++ b/.gitignore @@ -369,3 +369,6 @@ TPMCmd/tpm/src/libtpm.a # ignore Visual Studio's default output directory for CMake projects TPMCmd/out/ testing/Temporary/CTestCostData.txt + +# Rust bindings +bindings/rust/target/ From 2f60d9d02192895ce607aaa83840d4854289610d Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 21 May 2026 23:10:52 +0000 Subject: [PATCH 2/2] Add Rust Bindings Signed-off-by: Joe Richey --- bindings/rust/Cargo.lock | 89 +++++++++++ bindings/rust/Cargo.toml | 13 ++ bindings/rust/build.rs | 42 +++++ bindings/rust/rust-toolchain.toml | 4 + bindings/rust/rustfmt.toml | 3 + bindings/rust/src/lib.rs | 78 ++++++++++ bindings/rust/src/macros.rs | 111 ++++++++++++++ bindings/rust/src/platform.rs | 150 ++++++++++++++++++ bindings/rust/src/tests.rs | 245 ++++++++++++++++++++++++++++++ 9 files changed, 735 insertions(+) create mode 100644 bindings/rust/Cargo.lock create mode 100644 bindings/rust/Cargo.toml create mode 100644 bindings/rust/build.rs create mode 100644 bindings/rust/rust-toolchain.toml create mode 100644 bindings/rust/rustfmt.toml create mode 100644 bindings/rust/src/lib.rs create mode 100644 bindings/rust/src/macros.rs create mode 100644 bindings/rust/src/platform.rs create mode 100644 bindings/rust/src/tests.rs diff --git a/bindings/rust/Cargo.lock b/bindings/rust/Cargo.lock new file mode 100644 index 0000000..56fa18e --- /dev/null +++ b/bindings/rust/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cc" +version = "1.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "tpm2-ref-sys" +version = "0.0.5" +dependencies = [ + "cc", +] + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml new file mode 100644 index 0000000..c33d171 --- /dev/null +++ b/bindings/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "tpm2-ref-sys" +version = "0.0.5" +edition = "2024" +rust-version = "1.95" +license = "Apache-2.0" +keywords = ["tpm", "tss", "tpm2"] +categories = ["cryptography", "no-std"] + +[dependencies] + +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs new file mode 100644 index 0000000..789302d --- /dev/null +++ b/bindings/rust/build.rs @@ -0,0 +1,42 @@ +use std::{ffi::OsStr, fs::read_dir}; + +fn main() { + let mut build = cc::Build::new(); + + // Add all .c files from ../c + for entry in read_dir("../c").unwrap() { + let path = entry.unwrap().path(); + if path.extension().and_then(OsStr::to_str) == Some("c") { + build.file(path); + } + } + + // Add includes + build.include("../../TPMCmd/TpmConfiguration/"); + build.include("../../TPMCmd/tpm/include/"); + build.include("../../TPMCmd/tpm/include/private/"); + build.include("../../TPMCmd/tpm/include/private/prototypes/"); + build.include("../../TPMCmd/tpm/cryptolibs/common/include/"); + build.include("../../TPMCmd/tpm/cryptolibs/Ossl/include/"); + build.include("../../TPMCmd/tpm/cryptolibs/TpmBigNum/"); + build.include("../../TPMCmd/tpm/cryptolibs/TpmBigNum/include/"); + + // Add defines + build.define("SYM_LIB", "Ossl"); + build.define("HASH_LIB", "Ossl"); + build.define("MATH_LIB", "TpmBigNum"); + build.define("BN_MATH_LIB", "Ossl"); + + // Add flags + build.flag("-std=c11"); + build.warnings(true); + build.extra_warnings(true); + build.flag("-pedantic"); + build.flag("-Wno-cast-function-type"); + + // Compile + build.compile("tpm2_ref"); + + // Link against OpenSSL + println!("cargo:rustc-link-lib=crypto"); +} diff --git a/bindings/rust/rust-toolchain.toml b/bindings/rust/rust-toolchain.toml new file mode 100644 index 0000000..4e03498 --- /dev/null +++ b/bindings/rust/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2026-05-14" +components = ["rustfmt", "clippy"] +profile = "minimal" diff --git a/bindings/rust/rustfmt.toml b/bindings/rust/rustfmt.toml new file mode 100644 index 0000000..ab70690 --- /dev/null +++ b/bindings/rust/rustfmt.toml @@ -0,0 +1,3 @@ +style_edition = "2024" +imports_granularity = "Crate" +group_imports = "StdExternalCrate" diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs new file mode 100644 index 0000000..dc0f454 --- /dev/null +++ b/bindings/rust/src/lib.rs @@ -0,0 +1,78 @@ +//! Bindings to the TPM2 Reference Implementation in C +//! +//! This includes the entrypoints to the reference code: +//! - [`TPM_Manufacture`]: manufacture the NV Data +//! - [`_TPM_Init`]: initialize the reference code +//! - [`_TPM_Hash_Start`]/[`_TPM_Hash_Data`]/[`_TPM_Hash_End`]: H-CRTM +//! - [`ExecuteCommand`]: run a command +//! +//! It also includes the [`Platform`] trait, so that a user can provide the +//! platform-specific functionality required by the Reference Implementation. +//! A `&'static impl Platform` can be registered via [`register_platform!`], +//! or an external platform implementation can be linked in. +#![no_std] +#![feature(c_variadic)] // About to be stabilized, see: https://github.com/rust-lang/rust/issues/44930 + +mod macros; +mod platform; +mod tests; + +use core::ffi::c_int; + +pub use platform::*; + +pub const MAX_RESPONSE_SIZE: u32 = 0x1000 - 0x80; + +pub type BOOL = c_int; + +unsafe extern "C" { + /// Manufactures the TPM's NV Data in preparation for the first use. + pub fn TPM_Manufacture(firstTime: BOOL) -> c_int; + + /// Initializes the TPM values and subsystem. + /// + /// This function must be called before: + /// - [`_TPM_Hash_Start`] + /// - [`ExecuteCommand`] + /// + /// # Safety + /// - NV Data must be initialized via [`TPM_Manufacture`] beforehand. + pub fn _TPM_Init(); + + /// Starts an H-CRTM Event Sequence. + /// + /// # Safety + /// - [`_TPM_Init`] must be called beforehand. + pub fn _TPM_Hash_Start() -> BOOL; + /// Sends data to be hashed as part of an H-CRTM Event Sequence. + /// + /// # Safety + /// - [`_TPM_Hash_Start`] must be called beforehand. + pub fn _TPM_Hash_Data(dataSize: u32, data: *const u8) -> BOOL; + /// Completes an H-CRTM Event Sequence. + /// + /// # Safety + /// - [`_TPM_Hash_Start`]/[`_TPM_Hash_Data`] must be called beforehand. + pub fn _TPM_Hash_End() -> BOOL; + + /// Executes a raw TPM command. + /// + /// When calling this function: + /// - `request` / `requestSize` contain the raw request buffer. + /// - `response` / `responseSize` contain the raw response buffer. + /// + /// On return, `response` / `responseSize` contain the response. Note that + /// the `response` pointer may contain a new value. + /// + /// # Safety + /// - `request` must point to `requestSize` bytes. + /// - `*response` must point to `responseSize` bytes. + /// - `responseSize` must be at least [`MAX_RESPONSE_SIZE`]. + /// - [`_TPM_Init`] must be called beforehand. + pub fn ExecuteCommand( + requestSize: u32, + request: *const u8, + responseSize: *mut u32, + response: *mut *mut u8, + ); +} diff --git a/bindings/rust/src/macros.rs b/bindings/rust/src/macros.rs new file mode 100644 index 0000000..2c8a177 --- /dev/null +++ b/bindings/rust/src/macros.rs @@ -0,0 +1,111 @@ +#[doc(hidden)] +#[macro_export] +macro_rules! bind { + ($trait_name:ident, $c_name:ident ($($arg:ident : $typ:ty),*) -> $ret:ty) => { + #[unsafe(no_mangle)] + pub unsafe extern "C" fn $c_name($($arg : $typ),*) -> $ret { + unsafe { Platform::$trait_name(P, $($arg),*) } + } + }; + ($trait_name:ident, $c_name:ident ($($arg:ident : $typ:ty ,)* ...) -> $ret:ty) => { + #[unsafe(no_mangle)] + pub unsafe extern "C" fn $c_name($($arg : $typ,)* args: ...) -> $ret { + unsafe { Platform::$trait_name(P, $($arg,)* args) } + } + }; +} + +/// Registers a [`&'static impl Platform`][crate::Platform] with the reference implementation. +/// +/// This macro sets up the required global bindings and FFI symbols expected by the C library. +#[macro_export] +macro_rules! register_platform { ($P:expr) => { const _: () = { + use core::ffi::{c_char, c_int, c_void}; + + use $crate::{BOOL, Platform, SpecCapabilityValue, bind}; + + const P: &'static dyn Platform = $P; + + // Status + bind!(locality_get, _plat__LocalityGet() -> u8); + bind!(is_canceled, _plat__IsCanceled() -> BOOL); + bind!(physical_presence_asserted, _plat__PhysicalPresenceAsserted() -> BOOL); + + // Init + bind!(was_power_lost, _plat__WasPowerLost() -> BOOL); + bind!(start_tpm_init, _plat__StartTpmInit() -> ()); + bind!(end_ok_tpm_init, _plat__EndOkTpmInit() -> ()); + + // Manufacture + bind!(tear_down, _plat__TearDown() -> ()); + bind!(get_platform_manufacture_data, _plat__GetPlatformManufactureData(buf: *mut u8, buf_size: u32) -> ()); + + // Cryptography + bind!(get_entropy, _plat__GetEntropy(entropy: *mut u8, amount: u32) -> i32); + bind!(get_enabled_self_test, _plat_GetEnabledSelfTest(full_test: u8, p_to_test_vector: *mut u8, to_test_vector_size: usize) -> ()); + + // Debug + bind!(debug_print, _plat_debug_print(str: *const c_char) -> ()); + bind!(debug_printf, _plat_debug_printf(str: *const c_char, ...) -> ()); + + // Timer + bind!(timer_read, _plat__TimerRead() -> u64); + bind!(timer_was_reset, _plat__TimerWasReset() -> BOOL); + bind!(timer_was_stopped, _plat__TimerWasStopped() -> BOOL); + bind!(clock_rate_adjust, _plat__ClockRateAdjust(adjustment: i32) -> ()); + + // NV Memory + bind!(nv_enable, _plat__NVEnable(plat_parameter: *mut c_void, param_size: usize) -> c_int); + bind!(get_nv_ready_state, _plat__GetNvReadyState() -> c_int); + bind!(nv_memory_read, _plat__NvMemoryRead(start_offset: u32, size: u32, data: *mut c_void) -> BOOL); + bind!(nv_get_changed_status, _plat__NvGetChangedStatus(start_offset: u32, size: u32, data: *mut c_void) -> c_int); + bind!(nv_memory_write, _plat__NvMemoryWrite(start_offset: u32, size: u32, data: *mut c_void) -> BOOL); + bind!(nv_memory_clear, _plat__NvMemoryClear(start_offset: u32, size: u32) -> BOOL); + bind!(nv_memory_move, _plat__NvMemoryMove(src_offset: u32, dst_offset: u32, size: u32) -> BOOL); + bind!(nv_commit, _plat__NvCommit() -> c_int); + + // ACT + bind!(act_get_implemented, _plat__ACT_GetImplemented(act: u32) -> BOOL); + bind!(act_get_remaining, _plat__ACT_GetRemaining(act: u32) -> u32); + bind!(act_get_signaled, _plat__ACT_GetSignaled(act: u32) -> BOOL); + bind!(act_set_signaled, _plat__ACT_SetSignaled(act: u32, on: BOOL) -> ()); + bind!(act_update_counter, _plat__ACT_UpdateCounter(act: u32, new_value: u32) -> BOOL); + bind!(act_enable_ticks, _plat__ACT_EnableTicks(enable: BOOL) -> ()); + bind!(act_initialize, _plat__ACT_Initialize() -> BOOL); + + // Capabilities + bind!(get_manufacturer_capability_code, _plat__GetManufacturerCapabilityCode() -> u32); + bind!(get_vendor_capability_code, _plat__GetVendorCapabilityCode(index: c_int) -> u32); + bind!(get_spec_capability_value, _plat_GetSpecCapabilityValue(return_data: *mut SpecCapabilityValue) -> ()); + bind!(get_vendor_tpm_type, _plat__GetVendorTpmType() -> u32); + + // Firmware + bind!(get_tpm_firmware_version_high, _plat__GetTpmFirmwareVersionHigh() -> u32); + bind!(get_tpm_firmware_version_low, _plat__GetTpmFirmwareVersionLow() -> u32); + bind!(get_tpm_firmware_svn, _plat__GetTpmFirmwareSvn() -> u16); + bind!(get_tpm_firmware_max_svn, _plat__GetTpmFirmwareMaxSvn() -> u16); + bind!(get_tpm_firmware_secret, _plat__GetTpmFirmwareSecret(buf_size: u16, buf: *mut u8, out_size: *mut u16) -> c_int); + bind!(get_tpm_firmware_svn_secret, _plat__GetTpmFirmwareSvnSecret(svn: u16, buf_size: u16, buf: *mut u8, out_size: *mut u16) -> c_int); + + // PCRs + bind!(number_of_pcrs, _platPcr__NumberOfPcrs() -> u32); + bind!(is_pcr_bank_default_active, _platPcr_IsPcrBankDefaultActive(pcr_alg: u16) -> BOOL); + bind!(get_initial_value_for_pcr, _platPcr__GetInitialValueForPcr(pcr_number: u32, pcr_alg: u16, startup_locality: u8, pcr_buffer: *mut u8, buffer_size: u16, pcr_length: *mut u16) -> u32); + bind!(get_pcr_initialization_attributes, _platPcr__GetPcrInitializationAttributes(pcr_number: u32) -> u32); + + // Failure Mode + bind!(fail, _plat__Fail(function: *const c_char, line: c_int, location_code: u64, failure_code: c_int) -> ()); + bind!(in_failure_mode, _plat__InFailureMode() -> BOOL); + bind!(get_failure_code, _plat__GetFailureCode() -> u32); + bind!(get_failure_location, _plat__GetFailureLocation() -> u64); + bind!(get_failure_function_name, _plat__GetFailureFunctionName() -> *const c_char); + bind!(get_failure_line, _plat__GetFailureLine() -> u32); + + // Virtual NV + bind!(nv_virtual_populate_nv_index_info, _plat__NvVirtual_PopulateNvIndexInfo(handle: u32, public_area: *mut c_void, auth_value: *mut c_void) -> u32); + bind!(nv_virtual_read, _plat__NvVirtual_Read(data_in: *const c_void, data_out: *mut c_void) -> u32); + bind!(nv_virtual_read_public, _plat__NvVirtual_ReadPublic(data_in: *const c_void, data_out: *mut c_void) -> u32); + bind!(nv_virtual_cap_get_index, _plat__NvVirtual_CapGetIndex(handle: u32, count: u32, handle_list: *mut c_void) -> u8); + bind!(nv_operation_accepts_virtual_handles, _plat__NvOperationAcceptsVirtualHandles(arg_0: u32) -> BOOL); + bind!(is_nv_virtual_index, _plat__IsNvVirtualIndex(arg_0: u32) -> BOOL); +}; }; } diff --git a/bindings/rust/src/platform.rs b/bindings/rust/src/platform.rs new file mode 100644 index 0000000..543477d --- /dev/null +++ b/bindings/rust/src/platform.rs @@ -0,0 +1,150 @@ +use core::ffi::{VaList, c_char, c_int, c_void}; + +use crate::BOOL; + +/// Values returned by [`Platform::get_spec_capability_value`]. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SpecCapabilityValue { + pub tpm_spec_level: u32, + pub tpm_spec_version: u32, + pub tpm_spec_year: u32, + pub tpm_spec_day_of_year: u32, + + pub platform_family: u32, + pub platform_level: u32, + pub platform_revision: u32, + pub platform_year: u32, + pub platform_day_of_year: u32, +} + +/// Platform-specific functionality called by the Core TPM library. +pub trait Platform { + // Status + unsafe fn locality_get(&self) -> u8; + unsafe fn is_canceled(&self) -> BOOL; + unsafe fn physical_presence_asserted(&self) -> BOOL; + + // Init + unsafe fn was_power_lost(&self) -> BOOL; + unsafe fn start_tpm_init(&self); + unsafe fn end_ok_tpm_init(&self); + + // Manufacture + unsafe fn tear_down(&self); + unsafe fn get_platform_manufacture_data(&self, buf: *mut u8, buf_size: u32); + + // Cryptography + unsafe fn get_entropy(&self, entropy: *mut u8, amount: u32) -> i32; + unsafe fn get_enabled_self_test( + &self, + full_test: u8, + test_vector: *mut u8, + test_vector_size: usize, + ); + + // Debug + unsafe fn debug_print(&self, str: *const c_char); + unsafe fn debug_printf(&self, str: *const c_char, args: VaList); + + // Timer + unsafe fn timer_read(&self) -> u64; + unsafe fn timer_was_reset(&self) -> BOOL; + unsafe fn timer_was_stopped(&self) -> BOOL; + unsafe fn clock_rate_adjust(&self, adjustment: i32); + + // NV Memory + unsafe fn nv_enable(&self, plat_parameter: *mut c_void, param_size: usize) -> c_int; + unsafe fn get_nv_ready_state(&self) -> c_int; + unsafe fn nv_memory_read(&self, start_offset: u32, size: u32, data: *mut c_void) -> BOOL; + unsafe fn nv_get_changed_status( + &self, + start_offset: u32, + size: u32, + data: *mut c_void, + ) -> c_int; + unsafe fn nv_memory_write(&self, start_offset: u32, size: u32, data: *mut c_void) -> BOOL; + unsafe fn nv_memory_clear(&self, start_offset: u32, size: u32) -> BOOL; + unsafe fn nv_memory_move(&self, src_offset: u32, dst_offset: u32, size: u32) -> BOOL; + unsafe fn nv_commit(&self) -> c_int; + + // ACT + unsafe fn act_get_implemented(&self, act: u32) -> BOOL; + unsafe fn act_get_remaining(&self, act: u32) -> u32; + unsafe fn act_get_signaled(&self, act: u32) -> BOOL; + unsafe fn act_set_signaled(&self, act: u32, on: BOOL); + unsafe fn act_update_counter(&self, act: u32, new_value: u32) -> BOOL; + unsafe fn act_enable_ticks(&self, enable: BOOL); + unsafe fn act_initialize(&self) -> BOOL; + + // Capabilities + unsafe fn get_manufacturer_capability_code(&self) -> u32; + unsafe fn get_vendor_capability_code(&self, index: c_int) -> u32; + unsafe fn get_spec_capability_value(&self, return_data: *mut SpecCapabilityValue); + unsafe fn get_vendor_tpm_type(&self) -> u32; + + // Firmware + unsafe fn get_tpm_firmware_version_high(&self) -> u32; + unsafe fn get_tpm_firmware_version_low(&self) -> u32; + unsafe fn get_tpm_firmware_svn(&self) -> u16; + unsafe fn get_tpm_firmware_max_svn(&self) -> u16; + unsafe fn get_tpm_firmware_secret( + &self, + buf_size: u16, + buf: *mut u8, + out_size: *mut u16, + ) -> c_int; + unsafe fn get_tpm_firmware_svn_secret( + &self, + svn: u16, + buf_size: u16, + buf: *mut u8, + out_size: *mut u16, + ) -> c_int; + + // PCRs + unsafe fn number_of_pcrs(&self) -> u32; + unsafe fn is_pcr_bank_default_active(&self, pcr_alg: u16) -> BOOL; + unsafe fn get_initial_value_for_pcr( + &self, + pcr_number: u32, + pcr_alg: u16, + startup_locality: u8, + pcr_buffer: *mut u8, + buffer_size: u16, + pcr_length: *mut u16, + ) -> u32; + unsafe fn get_pcr_initialization_attributes(&self, pcr_number: u32) -> u32; + + // Failure Mode + unsafe fn fail( + &self, + function: *const c_char, + line: c_int, + location_code: u64, + failure_code: c_int, + ); + unsafe fn in_failure_mode(&self) -> BOOL; + unsafe fn get_failure_code(&self) -> u32; + unsafe fn get_failure_location(&self) -> u64; + unsafe fn get_failure_function_name(&self) -> *const c_char; + unsafe fn get_failure_line(&self) -> u32; + + // Virtual NV + unsafe fn nv_virtual_populate_nv_index_info( + &self, + handle: u32, + public_area: *mut c_void, + auth_value: *mut c_void, + ) -> u32; + unsafe fn nv_virtual_read(&self, data_in: *const c_void, data_out: *mut c_void) -> u32; + unsafe fn nv_virtual_read_public(&self, data_in: *const c_void, data_out: *mut c_void) -> u32; + unsafe fn nv_virtual_cap_get_index( + &self, + handle: u32, + count: u32, + handle_list: *mut c_void, + ) -> u8; + unsafe fn nv_operation_accepts_virtual_handles(&self, arg_0: u32) -> BOOL; + unsafe fn is_nv_virtual_index(&self, arg_0: u32) -> BOOL; +} diff --git a/bindings/rust/src/tests.rs b/bindings/rust/src/tests.rs new file mode 100644 index 0000000..754d28e --- /dev/null +++ b/bindings/rust/src/tests.rs @@ -0,0 +1,245 @@ +//! Ensure we link correctly with a "always failing" platform implementation. +#![cfg(test)] + +use core::{ + ffi::{c_char, c_int, c_void}, + ptr, slice, +}; + +use super::*; + +const FALSE: BOOL = 0; +const TRUE: BOOL = 1; + +const TPM_RC_FAILURE: u32 = 0x101; +const TPM_RC_NO_RESULT: u32 = 0x154; +const NV_WRITEFAILURE: c_int = 1; +const NV_INVALID_LOCATION: c_int = -1; + +#[test] +fn test_hcrtm() { + unsafe { _TPM_Init() }; + + assert_eq!(unsafe { _TPM_Hash_Start() }, TRUE); + + let data = [1, 2, 3, 4]; + let (data_ptr, data_len) = (data.as_ptr(), data.len() as u32); + assert_eq!(unsafe { _TPM_Hash_Data(data_len, data_ptr) }, TRUE); + + assert_eq!(unsafe { _TPM_Hash_End() }, TRUE); +} + +#[test] +fn fail_execute_command() { + let cmd = []; + let (cmd_ptr, cmd_len) = (cmd.as_ptr(), cmd.len() as u32); + let mut rsp = [0u8; 4096]; + let (mut rsp_ptr, mut rsp_len) = (rsp.as_mut_ptr(), rsp.len() as u32); + + unsafe { ExecuteCommand(cmd_len, cmd_ptr, &mut rsp_len, &mut rsp_ptr) }; + + const FAILURE: [u8; 10] = [ + 0x80, 0x01, // tag = 0x8001 (TPM_ST_NO_SESSIONS) + 0x00, 0x00, 0x00, 0x0a, // responseSize = 10 + 0x00, 0x00, 0x01, 0x01, // responseCode = 0x101 (TPM_RC_FAILURE) + ]; + let rsp_out = unsafe { slice::from_raw_parts(rsp_ptr, rsp_len as usize) }; + assert_eq!(rsp_out, &FAILURE); +} + +#[test] +fn fail_tpm_manufacture() { + const MANUF_INVALID_CONFIG: c_int = -1; + assert_eq!(unsafe { TPM_Manufacture(1) }, MANUF_INVALID_CONFIG); +} + +struct FailPlatform; +register_platform!(&FailPlatform); + +impl Platform for FailPlatform { + // Status + unsafe fn locality_get(&self) -> u8 { + 0 + } + unsafe fn is_canceled(&self) -> BOOL { + FALSE + } + unsafe fn physical_presence_asserted(&self) -> BOOL { + FALSE + } + + // Init + unsafe fn was_power_lost(&self) -> BOOL { + FALSE + } + unsafe fn start_tpm_init(&self) {} + unsafe fn end_ok_tpm_init(&self) {} + + // Manufacture + unsafe fn tear_down(&self) {} + unsafe fn get_platform_manufacture_data(&self, _: *mut u8, _: u32) {} + + // Cryptography + unsafe fn get_entropy(&self, _: *mut u8, _: u32) -> i32 { + -1 + } + unsafe fn get_enabled_self_test(&self, _: u8, _: *mut u8, _: usize) {} + + // Debug + unsafe fn debug_print(&self, _: *const c_char) {} + unsafe fn debug_printf(&self, _: *const c_char, _: core::ffi::VaList) {} + + // Timer + unsafe fn timer_read(&self) -> u64 { + 0 + } + unsafe fn timer_was_reset(&self) -> BOOL { + FALSE + } + unsafe fn timer_was_stopped(&self) -> BOOL { + FALSE + } + unsafe fn clock_rate_adjust(&self, _: i32) {} + + // NV Memory + unsafe fn nv_enable(&self, _: *mut c_void, _: usize) -> c_int { + -1 + } + unsafe fn get_nv_ready_state(&self) -> c_int { + NV_WRITEFAILURE + } + unsafe fn nv_memory_read(&self, _: u32, _: u32, _: *mut c_void) -> BOOL { + FALSE + } + unsafe fn nv_get_changed_status(&self, _: u32, _: u32, _: *mut c_void) -> c_int { + NV_INVALID_LOCATION + } + unsafe fn nv_memory_write(&self, _: u32, _: u32, _: *mut c_void) -> BOOL { + FALSE + } + unsafe fn nv_memory_clear(&self, _: u32, _: u32) -> BOOL { + FALSE + } + unsafe fn nv_memory_move(&self, _: u32, _: u32, _: u32) -> BOOL { + FALSE + } + unsafe fn nv_commit(&self) -> c_int { + -1 + } + + // ACT + unsafe fn act_get_implemented(&self, _: u32) -> BOOL { + FALSE + } + unsafe fn act_get_remaining(&self, _: u32) -> u32 { + 0 + } + unsafe fn act_get_signaled(&self, _: u32) -> BOOL { + FALSE + } + unsafe fn act_set_signaled(&self, _: u32, _: BOOL) {} + unsafe fn act_update_counter(&self, _: u32, _: u32) -> BOOL { + FALSE + } + unsafe fn act_enable_ticks(&self, _: BOOL) {} + unsafe fn act_initialize(&self) -> BOOL { + FALSE + } + + // Capabilities + unsafe fn get_manufacturer_capability_code(&self) -> u32 { + 0 + } + unsafe fn get_vendor_capability_code(&self, _: c_int) -> u32 { + 0 + } + unsafe fn get_spec_capability_value(&self, _: *mut SpecCapabilityValue) {} + unsafe fn get_vendor_tpm_type(&self) -> u32 { + 0 + } + + // Firmware + unsafe fn get_tpm_firmware_version_high(&self) -> u32 { + 0 + } + unsafe fn get_tpm_firmware_version_low(&self) -> u32 { + 0 + } + unsafe fn get_tpm_firmware_svn(&self) -> u16 { + 0 + } + unsafe fn get_tpm_firmware_max_svn(&self) -> u16 { + 0 + } + unsafe fn get_tpm_firmware_secret(&self, _: u16, _: *mut u8, _: *mut u16) -> c_int { + -1 + } + unsafe fn get_tpm_firmware_svn_secret(&self, _: u16, _: u16, _: *mut u8, _: *mut u16) -> c_int { + -1 + } + + // PCRs + unsafe fn number_of_pcrs(&self) -> u32 { + 0 + } + unsafe fn is_pcr_bank_default_active(&self, _: u16) -> BOOL { + FALSE + } + unsafe fn get_initial_value_for_pcr( + &self, + _: u32, + _: u16, + _: u8, + _: *mut u8, + _: u16, + _: *mut u16, + ) -> u32 { + TPM_RC_FAILURE + } + unsafe fn get_pcr_initialization_attributes(&self, _: u32) -> u32 { + 0 + } + + // Failure Mode + unsafe fn fail(&self, _: *const c_char, _: c_int, _: u64, _: c_int) {} + unsafe fn in_failure_mode(&self) -> BOOL { + TRUE + } + unsafe fn get_failure_code(&self) -> u32 { + 0 + } + unsafe fn get_failure_location(&self) -> u64 { + 0 + } + unsafe fn get_failure_function_name(&self) -> *const c_char { + ptr::null() + } + unsafe fn get_failure_line(&self) -> u32 { + 0 + } + + // Virtual NV + unsafe fn nv_virtual_populate_nv_index_info( + &self, + _: u32, + _: *mut c_void, + _: *mut c_void, + ) -> u32 { + TPM_RC_NO_RESULT + } + unsafe fn nv_virtual_read(&self, _: *const c_void, _: *mut c_void) -> u32 { + TPM_RC_NO_RESULT + } + unsafe fn nv_virtual_read_public(&self, _: *const c_void, _: *mut c_void) -> u32 { + TPM_RC_NO_RESULT + } + unsafe fn nv_virtual_cap_get_index(&self, _: u32, _: u32, _: *mut c_void) -> u8 { + 0 + } + unsafe fn nv_operation_accepts_virtual_handles(&self, _: u32) -> BOOL { + FALSE + } + unsafe fn is_nv_virtual_index(&self, _: u32) -> BOOL { + FALSE + } +}