blob: c69946ccd168b477c014710bda09ace1d967df82 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use super::CommandArg;
use super::TpmCmdArg;
use super::TpmCmdResponse;
use super::TpmiStCommandTag;
use crate::command_runner::CommandRunner;
use crate::context::Context;
use crate::error::HwsecError;
// Check the field description here.
// Reference: https://trustedcomputinggroup.org/wp-content/uploads/TCG_TPM2_r1p59_Part3_Commands_pub.pdf#page=406
pub fn gen_tpm_cmd(
tag: TpmiStCommandTag,
cmd_arg: CommandArg,
index: u32,
) -> Result<Vec<u8>, HwsecError> {
let mut ret = Vec::<u8>::new();
ret.extend_from_slice(&tag.command_code());
ret.extend_from_slice(&0x00000000_u32.to_be_bytes()); // size: will be overwritten later
ret.extend_from_slice(&cmd_arg.command_code());
ret.extend_from_slice(&index.to_be_bytes());
ret.extend_from_slice(&index.to_be_bytes());
let TpmiStCommandTag::TPM_ST_SESSIONS(session_option) = tag;
ret.extend_from_slice(&session_option.command_code());
match cmd_arg {
CommandArg::TPM_CC_NV_Write(data) => {
if data.len() > u16::MAX as usize {
return Err(HwsecError::InvalidArgumentError);
}
ret.extend_from_slice(&(data.len() as u16).to_be_bytes());
ret.extend_from_slice(&data);
// offset, which is always 0x0000 in this scenario
ret.extend_from_slice(&0x0000_u16.to_be_bytes());
}
CommandArg::TPM_CC_NV_WriteLock => {
// empty cmd_param
}
CommandArg::TPM_CC_NV_Read(data_len) => {
ret.extend_from_slice(&data_len.to_be_bytes());
// offset, which is always 0x0000 in this scenario
ret.extend_from_slice(&0x0000_u16.to_be_bytes());
}
};
let cmd_size = (ret.len() as u32).to_be_bytes();
ret[2..6].clone_from_slice(&cmd_size);
Ok(ret)
}
fn trunksd_is_running(ctx: &mut impl Context) -> bool {
if let Ok(o) = ctx.cmd_runner().run("status", vec!["trunksd"]) {
std::str::from_utf8(&o.stdout)
.unwrap_or("stopped")
.contains("running")
} else {
false
}
}
pub fn run_tpm_cmd(ctx: &mut impl Context, tpm_cmd: Vec<u8>) -> Result<TpmCmdResponse, HwsecError> {
let trunksd_on: bool = trunksd_is_running(ctx);
let send_util = if trunksd_on { "trunks_send" } else { "tpmc" };
let flag: Vec<&str> = if trunksd_on {
vec!["--raw"]
} else {
vec!["raw"]
};
let arg = TpmCmdArg::new(tpm_cmd);
let output = ctx
.cmd_runner()
.run(
send_util,
[
&flag[..],
&arg.to_hex_tokens()
.iter()
.map(AsRef::as_ref)
.collect::<Vec<&str>>()[..],
]
.concat(),
)
.map_err(|_| HwsecError::CommandRunnerError)?;
if output.status.success() {
Ok(TpmCmdResponse::from_send_util_output(output.stdout)?)
} else {
Err(HwsecError::CommandRunnerError)
}
}
#[cfg(test)]
pub mod tests {
pub fn split_into_hex_strtok(hex_code: &str) -> Vec<&str> {
// e.g. "12 34 56 78" -> ["12", "34", "56", "78"]
hex_code.split(' ').collect::<Vec<&str>>()
}
}