libcros 0.4.2

A Rust library that provides easy-to-use functions for interacting with a Chrome device
Documentation
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::*;

// const TPM_MAX_RETRIES: u32 = 5;
// const TPM_RETRY_DELAY_MS: u64 = 100;