libcros 0.6.5

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

use crate::{
  LOG_DBG,
  tlcl::{
    bytes::{read_be16, read_be32},
    tpm20::constants::{
      TPM_CC, TPM_ST_NO_SESSIONS, TPM_ST_SESSIONS, TPM2_Clear, TPM2_NV_DefineSpace, TPM2_NV_Read,
      TPM2_NV_ReadPublic, TPM2_NV_UndefineSpace, TPM2_NV_Write, TPM2_Shutdown, TPM2_Startup, TPM2B,
      TPMS_NV_PUBLIC, nv_read_public_response, nv_read_response, tpm2_response,
    },
  },
};

pub fn unmarshal_u8(buffer: &mut *const u8, buffer_space: &mut i32) -> u8 {
  let value: u8;

  if *buffer_space < core::mem::size_of::<u8>() as i32 {
    *buffer_space = -1;
    return 0;
  }

  unsafe {
    value = **buffer;
    *buffer = (*buffer).add(core::mem::size_of::<u8>());
  }
  *buffer_space -= core::mem::size_of::<u8>() as i32;

  value
}

pub fn unmarshal_u16(buffer: &mut *const u8, buffer_space: &mut i32) -> u16 {
  let value: u16;

  if *buffer_space < core::mem::size_of::<u16>() as i32 {
    *buffer_space = -1;
    return 0;
  }

  value = read_be16(*buffer);
  unsafe {
    *buffer = (*buffer).add(core::mem::size_of::<u16>());
  }
  *buffer_space -= core::mem::size_of::<u16>() as i32;

  value
}

pub fn unmarshal_u32(buffer: &mut *const u8, buffer_space: &mut i32) -> u32 {
  let value: u32;

  if *buffer_space < core::mem::size_of::<u32>() as i32 {
    *buffer_space = -1;
    return 0;
  }

  value = read_be32(*buffer);
  unsafe {
    *buffer = (*buffer).add(core::mem::size_of::<u32>());
  }
  *buffer_space -= core::mem::size_of::<u32>() as i32;

  value
}

pub fn unmarshal_TPM2B(buffer: &mut *const u8, size: &mut i32, tpm2b: &mut TPM2B) {
  tpm2b.size = unmarshal_u16(buffer, size);
  if tpm2b.size as i32 > *size {
    tpm2b.buffer = core::ptr::null();
    tpm2b.size = 0;
    *size = -1;
    return;
  }

  tpm2b.buffer = *buffer;
  unsafe {
    *buffer = (*buffer).add(tpm2b.size as usize);
  }
  *size -= tpm2b.size as i32;
}

pub fn unmarshal_authorization_section(buffer: &mut *const u8, size: &mut i32, cmd_name: &str) {
  if *size != 5 {
    LOG_DBG!(
      "unexepcted authorization section size {} for {}",
      *size,
      &cmd_name
    );
  }
  *buffer = ((*buffer as usize) + (*size as usize)) as *const u8;
  *size = 0;
}

pub fn unmarshal_nv_read(buffer: &mut *const u8, size: &mut i32, nvr: &mut nv_read_response) {
  nvr.params_size = unmarshal_u32(buffer, size);
  unmarshal_TPM2B(buffer, size, &mut nvr.buffer);

  if nvr.params_size != (nvr.buffer.size as u32 + core::mem::size_of::<u16>() as u32) {
    return;
  }

  if *size < 0 {
    return;
  }

  unmarshal_authorization_section(buffer, size, "NV_Read");
}

pub fn unmarshal_nv_write(buffer: &mut *const u8, size: &mut i32) {
  unmarshal_authorization_section(buffer, size, "NV_Write");
}

pub fn unmarshal_TPMS_NV_PUBLIC(
  buffer: &mut *const u8,
  size: &mut i32,
  pub_data: &mut TPMS_NV_PUBLIC,
) {
  let mut tpm2b_size = unmarshal_u16(buffer, size) as i32;
  if tpm2b_size > *size {
    *size = -1;
    return;
  }
  *size -= tpm2b_size;

  pub_data.nvIndex = unmarshal_u32(buffer, &mut tpm2b_size);
  pub_data.nameAlg = unmarshal_u16(buffer, &mut tpm2b_size);
  pub_data.attributes = unmarshal_u32(buffer, &mut tpm2b_size);
  unmarshal_TPM2B(buffer, &mut tpm2b_size, &mut pub_data.authPolicy);
  pub_data.dataSize = unmarshal_u16(buffer, &mut tpm2b_size);

  if tpm2b_size != 0 {
    *size = -1;
  }
}

pub fn unmarshal_nv_read_public(
  buffer: &mut *const u8,
  size: &mut i32,
  nv_pub: &mut nv_read_public_response,
) {
  let mut nv_public: TPMS_NV_PUBLIC = unsafe { core::mem::zeroed() };
  let mut nv_name: TPM2B = unsafe { core::mem::zeroed() };

  unmarshal_TPMS_NV_PUBLIC(buffer, size, &mut nv_public);
  unmarshal_TPM2B(buffer, size, &mut nv_name);

  if *size < 0 {
    return;
  }

  if *size > 0 {
    *size = -1;
    return;
  }

  unsafe {
    core::ptr::addr_of_mut!(nv_pub.nvPublic).write_unaligned(nv_public);
    core::ptr::addr_of_mut!(nv_pub.nvName).write_unaligned(nv_name);
  }
}

pub fn tpm_unmarshal_response(
  command: TPM_CC,
  response_body: *const core::ffi::c_void,
  mut cr_size: i32,
  response: &mut tpm2_response,
) -> i32 {
  let mut buffer = response_body as *const u8;

  if cr_size < core::mem::size_of::<crate::tlcl::tpm20::constants::tpm_header>() as i32 {
    return -1;
  }

  response.hdr.tpm_tag = unmarshal_u16(&mut buffer, &mut cr_size);
  response.hdr.tpm_size = unmarshal_u32(&mut buffer, &mut cr_size);
  response.hdr.tpm_code = unmarshal_u32(&mut buffer, &mut cr_size);

  if response.hdr.tpm_tag != TPM_ST_NO_SESSIONS && response.hdr.tpm_tag != TPM_ST_SESSIONS {
    return -1;
  }

  if response.hdr.tpm_size
    < core::mem::size_of::<crate::tlcl::tpm20::constants::tpm_header>() as u32
  {
    return -1;
  }

  if cr_size == 0 {
    return 0;
  }

  match command {
    TPM2_NV_Read => {
      let mut nvr = nv_read_response {
        params_size: 0,
        buffer: TPM2B {
          size: 0,
          buffer: core::ptr::null(),
        },
      };
      unmarshal_nv_read(&mut buffer, &mut cr_size, &mut nvr);
      response.body.nvr = core::mem::ManuallyDrop::new(nvr);
    }
    TPM2_NV_ReadPublic => {
      let mut nv_pub: nv_read_public_response = unsafe { core::mem::zeroed() };
      unmarshal_nv_read_public(&mut buffer, &mut cr_size, &mut nv_pub);
      response.body.nv_read_public = core::mem::ManuallyDrop::new(nv_pub);
    }
    TPM2_NV_Write
    | TPM2_NV_DefineSpace
    | TPM2_NV_UndefineSpace
    | TPM2_Clear
    | TPM2_Startup
    | TPM2_Shutdown => {
      cr_size = 0;
    }
    _ => {
      return -1;
    }
  }

  if cr_size != 0 {
    return -1;
  }

  0
}