libcros 0.6.6

A Rust library that provides easy-to-use functions for interacting with a Chrome device
Documentation
#![allow(non_snake_case)]

use crate::tlcl::{
  constants::{
    TPM_E_AUTHFAIL, TPM_E_BUFFER_SIZE, TPM_E_INVALID_RESPONSE, TPM_E_NO_SUCH_COMMAND,
    TPM_E_RESPONSE_TOO_LARGE, TPM_SUCCESS,
  },
  tpm12::{
    constants::{
      TPM_AUTH_DATA_LEN, TPM_BUFFER_SIZE, TPM_CAP_NV_INDEX, TPM_NV_AUTH_POLICY,
      TPM_ORD_GetCapability, TPM_ORD_NV_DefineSpace, TPM_TAG_RQU_COMMAND, TPM_TAG_RSP_COMMAND,
      tpm1_nv_define_space_cmd,
    },
    tpm_get_response_code,
    utils::{
      decode_pcr_info, init_default_nv_auth_policy, init_define_space_default_auth_policy,
      read_be16, read_be32, write_be16, write_be32,
    },
  },
  vb2ex_tpm_send_recv,
};

pub fn TlclDefineSpace(index: u32, perm: u32, size: u32) -> u32 {
  TlclDefineSpaceEx(
    core::ptr::null(),
    0,
    index,
    perm,
    size,
    core::ptr::null(),
    0,
  )
}

pub fn TlclUndefineSpace(index: u32) -> u32 {
  TlclUndefineSpaceEx(core::ptr::null(), 0, index)
}

pub fn TlclUndefineSpaceEx(owner_auth: *const u8, owner_auth_size: u32, index: u32) -> u32 {
  TlclDefineSpaceEx(
    owner_auth,
    owner_auth_size,
    index,
    0,
    0,
    core::ptr::null(),
    0,
  )
}

pub fn TlclDefineSpaceEx(
  owner_auth: *const u8,
  owner_auth_size: u32,
  index: u32,
  perm: u32,
  size: u32,
  auth_policy: *const core::ffi::c_void,
  auth_policy_size: u32,
) -> u32 {
  if !owner_auth.is_null() || owner_auth_size != 0 {
    if owner_auth_size as usize != TPM_AUTH_DATA_LEN {
      return TPM_E_AUTHFAIL;
    }
    return TPM_E_NO_SUCH_COMMAND;
  }

  if !auth_policy.is_null() && auth_policy_size != core::mem::size_of::<TPM_NV_AUTH_POLICY>() as u32
  {
    return TPM_E_BUFFER_SIZE;
  }

  let mut default_policy: TPM_NV_AUTH_POLICY = unsafe { core::mem::zeroed() };
  let policy_ref = if auth_policy.is_null() {
    init_define_space_default_auth_policy(&mut default_policy);
    &default_policy
  } else {
    unsafe { &*(auth_policy as *const TPM_NV_AUTH_POLICY) }
  };

  let cmd = tpm1_nv_define_space_cmd {
    nvIndex: index,
    perm,
    size,
    auth_policy: policy_ref as *const TPM_NV_AUTH_POLICY,
  };

  tpm_get_response_code(
    TPM_ORD_NV_DefineSpace,
    &cmd as *const tpm1_nv_define_space_cmd as *const core::ffi::c_void,
  )
}

pub fn TlclInitNvAuthPolicy(
  _pcr_selection_bitmap: u32,
  _pcr_values: *const u8,
  auth_policy: *mut core::ffi::c_void,
  auth_policy_size: &mut u32,
) -> u32 {
  let required = core::mem::size_of::<TPM_NV_AUTH_POLICY>() as u32;
  let provided = *auth_policy_size;
  *auth_policy_size = required;

  if auth_policy.is_null() || provided < required {
    return TPM_E_BUFFER_SIZE;
  }

  init_default_nv_auth_policy(auth_policy as *mut TPM_NV_AUTH_POLICY);

  TPM_SUCCESS
}

pub fn TlclGetSpaceInfo(
  index: u32,
  attributes: &mut u32,
  size: &mut u32,
  auth_policy: *mut core::ffi::c_void,
  auth_policy_size: &mut u32,
) -> u32 {
  let needed_policy_size = core::mem::size_of::<TPM_NV_AUTH_POLICY>() as u32;
  let provided_policy_size = *auth_policy_size;
  *auth_policy_size = needed_policy_size;
  if auth_policy.is_null() || provided_policy_size < needed_policy_size {
    return TPM_E_BUFFER_SIZE;
  }

  let mut cmd = [0u8; 22];
  write_be16(cmd.as_mut_ptr(), TPM_TAG_RQU_COMMAND);
  write_be32(unsafe { cmd.as_mut_ptr().add(2) }, cmd.len() as u32);
  write_be32(unsafe { cmd.as_mut_ptr().add(6) }, TPM_ORD_GetCapability);
  write_be32(unsafe { cmd.as_mut_ptr().add(10) }, TPM_CAP_NV_INDEX);
  write_be32(
    unsafe { cmd.as_mut_ptr().add(14) },
    core::mem::size_of::<u32>() as u32,
  );
  write_be32(unsafe { cmd.as_mut_ptr().add(18) }, index);

  let mut response = [0u8; TPM_BUFFER_SIZE];
  let mut response_size = TPM_BUFFER_SIZE as u32;
  let rv = vb2ex_tpm_send_recv(
    cmd.as_ptr(),
    cmd.len() as u32,
    response.as_mut_ptr(),
    &mut response_size,
  );
  if rv != TPM_SUCCESS {
    return rv;
  }

  if response_size as usize > response.len() {
    return TPM_E_RESPONSE_TOO_LARGE;
  }
  if response_size < 14 {
    return TPM_E_INVALID_RESPONSE;
  }

  if read_be16(response.as_ptr()) != TPM_TAG_RSP_COMMAND {
    return TPM_E_INVALID_RESPONSE;
  }

  let tpm_rc = read_be32(unsafe { response.as_ptr().add(6) });
  if tpm_rc != TPM_SUCCESS {
    return tpm_rc;
  }

  let mut cursor = 10usize;
  let cap_size = read_be32(unsafe { response.as_ptr().add(cursor) }) as usize;
  cursor += 4;
  if cap_size > response_size as usize - cursor {
    return TPM_E_INVALID_RESPONSE;
  }
  let end = cursor + cap_size;

  if end.saturating_sub(cursor) < 6 {
    return TPM_E_INVALID_RESPONSE;
  }
  cursor += 2;
  let response_index = read_be32(unsafe { response.as_ptr().add(cursor) });
  cursor += 4;
  if response_index != index {
    return TPM_E_INVALID_RESPONSE;
  }

  let policy = auth_policy as *mut TPM_NV_AUTH_POLICY;
  let pcr_read = unsafe { core::ptr::addr_of_mut!((*policy).pcr_info_read) };
  let pcr_write = unsafe { core::ptr::addr_of_mut!((*policy).pcr_info_write) };
  if !decode_pcr_info(&response, &mut cursor, end, pcr_read)
    || !decode_pcr_info(&response, &mut cursor, end, pcr_write)
  {
    return TPM_E_INVALID_RESPONSE;
  }

  if end.saturating_sub(cursor) != 13 {
    return TPM_E_INVALID_RESPONSE;
  }

  cursor += 2;
  *attributes = read_be32(unsafe { response.as_ptr().add(cursor) });
  cursor += 4;
  cursor += 3;
  *size = read_be32(unsafe { response.as_ptr().add(cursor) });

  TPM_SUCCESS
}

pub fn TlclGetPermissions(index: u32, permissions: &mut u32) -> u32 {
  let mut dummy_size: u32 = 0;
  let mut dummy_policy: TPM_NV_AUTH_POLICY = unsafe { core::mem::zeroed() };
  let mut dummy_policy_size: u32 = core::mem::size_of::<TPM_NV_AUTH_POLICY>() as u32;

  TlclGetSpaceInfo(
    index,
    permissions,
    &mut dummy_size,
    &mut dummy_policy as *mut TPM_NV_AUTH_POLICY as *mut core::ffi::c_void,
    &mut dummy_policy_size,
  )
}