Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
89 changes: 89 additions & 0 deletions bindings/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions bindings/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"] }
42 changes: 42 additions & 0 deletions bindings/rust/build.rs
Original file line number Diff line number Diff line change
@@ -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");
}
4 changes: 4 additions & 0 deletions bindings/rust/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "nightly-2026-05-14"
components = ["rustfmt", "clippy"]
profile = "minimal"
3 changes: 3 additions & 0 deletions bindings/rust/rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
style_edition = "2024"
imports_granularity = "Crate"
group_imports = "StdExternalCrate"
78 changes: 78 additions & 0 deletions bindings/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment about how this is calculated. Or we can also extern this value from C (if any).


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,
);
}
111 changes: 111 additions & 0 deletions bindings/rust/src/macros.rs
Original file line number Diff line number Diff line change
@@ -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);
}; }; }
Loading