| // 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>>() | |
| } | |
| } |