pub mod constants;
use std::{
fs::OpenOptions,
io::{Read, Write},
thread,
time::Duration,
};
use crate::{LOG_FATAL, keys, kv_get};
pub const TPM_MAX_RETRIES: u32 = 5;
pub const TPM_RETRY_DELAY_MS: u64 = 100;
pub fn tpm_xmit(
sendbuf: *const u8,
send_size: usize,
recvbuf: *mut u8,
recv_len: *mut usize,
) -> u32 {
const TPM_HEADER_SIZE: usize = 10;
let tpm_path: String = kv_get(keys::TPM_PATH);
if tpm_path.is_empty() {
LOG_FATAL!("TPM_PATH not set! cannot continue!");
}
let send_data = unsafe { core::slice::from_raw_parts(sendbuf, send_size) };
let mut tpm_file = {
let mut opened = None;
for attempt in 0..TPM_MAX_RETRIES {
match OpenOptions::new().read(true).write(true).open(&tpm_path) {
Ok(file) => {
opened = Some(file);
break;
}
Err(_) => {
if attempt + 1 < TPM_MAX_RETRIES {
thread::sleep(Duration::from_millis(TPM_RETRY_DELAY_MS));
}
}
}
}
match opened {
Some(file) => file,
None => return constants::TPM_E_COMMUNICATION_ERROR,
}
};
if tpm_file.write_all(send_data).is_err() {
return constants::TPM_E_COMMUNICATION_ERROR;
}
if !recvbuf.is_null() && !recv_len.is_null() {
let recv_cap = unsafe { *recv_len };
if recv_cap < TPM_HEADER_SIZE {
return constants::TPM_E_RESPONSE_TOO_LARGE;
}
let recv_data = unsafe { core::slice::from_raw_parts_mut(recvbuf, recv_cap) };
if tpm_file
.read_exact(&mut recv_data[..TPM_HEADER_SIZE])
.is_err()
{
return constants::TPM_E_COMMUNICATION_ERROR;
}
let total_size =
u32::from_be_bytes([recv_data[2], recv_data[3], recv_data[4], recv_data[5]]) as usize;
if total_size < TPM_HEADER_SIZE {
return constants::TPM_E_COMMUNICATION_ERROR;
}
if total_size > recv_cap {
unsafe {
*recv_len = total_size;
}
return constants::TPM_E_RESPONSE_TOO_LARGE;
}
if tpm_file
.read_exact(&mut recv_data[TPM_HEADER_SIZE..total_size])
.is_err()
{
return constants::TPM_E_COMMUNICATION_ERROR;
}
unsafe {
*recv_len = total_size;
}
}
return constants::TPM_SUCCESS;
}
pub fn vb2ex_tpm_send_recv(
request: *const u8,
request_length: u32,
response: *mut u8,
response_length: *mut u32,
) -> u32 {
let mut len: usize = unsafe { *response_length } as usize;
if tpm_xmit(request, request_length as usize, response, &mut len) != constants::TPM_SUCCESS {
return constants::TPM_E_COMMUNICATION_ERROR;
}
if len > unsafe { *response_length } as usize {
return constants::TPM_E_RESPONSE_TOO_LARGE;
}
unsafe {
*response_length = len as u32;
}
constants::TPM_SUCCESS
}
pub mod commands;
pub mod permissions;
#[cfg(feature = "tpm1_2")]
pub mod tpm12;
#[cfg(feature = "tpm2_0")]
pub mod tpm20;
pub use commands::*;
pub use permissions::*;