blob: ca9a5b6a5bf7c58b7e0424aa732ae288668ce721 [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 crate::context::Context;
use crate::error::HwsecError;
use crate::tpm2::gen_tpm_cmd;
use crate::tpm2::run_tpm_cmd;
use crate::tpm2::CommandArg;
use crate::tpm2::SessionOption;
use crate::tpm2::TpmiStCommandTag;
pub fn nv_read(ctx: &mut impl Context, index: u32, length: u16) -> Result<Vec<u8>, HwsecError> {
const SESSION_DESCRIPTION_LENGTH: usize = 6;
let tpm_cmd = gen_tpm_cmd(
TpmiStCommandTag::TPM_ST_SESSIONS(SessionOption::EmptyPassword),
CommandArg::TPM_CC_NV_Read(length),
index,
)?;
let response = run_tpm_cmd(ctx, tpm_cmd)?;
if response.success() {
if response.body().len() < SESSION_DESCRIPTION_LENGTH + length as usize {
// This only happens when TPM is not functioning correctly
// by returning less bytes than we requested.
Err(HwsecError::InternalError)
} else {
Ok(response.body()
[SESSION_DESCRIPTION_LENGTH..(SESSION_DESCRIPTION_LENGTH + length as usize)]
.to_vec())
}
} else {
Err(HwsecError::Tpm2Error(response.return_code()))
}
}
#[cfg(test)]
mod tests {
use crate::context::mock::MockContext;
use crate::context::Context;
use crate::error::HwsecError;
use crate::tpm2::nv_read;
use crate::tpm2::tests::split_into_hex_strtok;
use crate::tpm2::BOARD_ID_INDEX;
use crate::tpm2::BOARD_ID_LENGTH;
#[test]
fn test_nv_read_successful() {
let index = BOARD_ID_INDEX;
let length = BOARD_ID_LENGTH;
let mut mock_ctx = MockContext::new();
mock_ctx.cmd_runner().set_trunksd_running(true);
mock_ctx.cmd_runner().add_tpm_interaction(
"trunks_send",
vec!["--raw"],
split_into_hex_strtok(
"80 02 00 00 00 23 00 00 \
01 4e 01 3f ff 00 01 3f \
ff 00 00 00 00 09 40 00 \
00 09 00 00 00 00 00 00 \
0c 00 00",
),
0,
"800200000021000000000000000E000C4646524DB9B9ADB27F7F00000000010000",
"",
);
let result = nv_read(&mut mock_ctx, index, length);
assert_eq!(
result,
Ok(vec![
0x46, 0x46, 0x52, 0x4d, 0xb9, 0xb9, 0xad, 0xb2, 0x7f, 0x7f, 0x00, 0x00
])
);
}
#[test]
fn test_nv_read_length_too_large() {
let index = BOARD_ID_INDEX;
let length = 13_u16;
let mut mock_ctx = MockContext::new();
mock_ctx.cmd_runner().set_trunksd_running(true);
mock_ctx.cmd_runner().add_tpm_interaction(
"trunks_send",
vec!["--raw"],
split_into_hex_strtok(
"80 02 00 00 00 23 00 00 \
01 4e 01 3f ff 00 01 3f \
ff 00 00 00 00 09 40 00 \
00 09 00 00 00 00 00 00 \
0d 00 00",
),
0,
"80010000000A00000146",
"",
);
let result = nv_read(&mut mock_ctx, index, length);
// return code 0x00000146 = TPM_RC_NV_RANGE = RC_VER1(0x100) + 0x046
assert_eq!(result, Err(HwsecError::Tpm2Error(0x00000146)));
}
#[test]
fn test_nv_read_nonzero_exit_status() {
let index = BOARD_ID_INDEX;
let length = 13_u16;
let mut mock_ctx = MockContext::new();
mock_ctx.cmd_runner().set_trunksd_running(true);
mock_ctx.cmd_runner().add_tpm_interaction(
"trunks_send",
vec!["--raw"],
split_into_hex_strtok(
"80 02 00 00 00 23 00 00 \
01 4e 01 3f ff 00 01 3f \
ff 00 00 00 00 09 40 00 \
00 09 00 00 00 00 00 00 \
0d 00 00",
),
1,
"",
"",
);
let result = nv_read(&mut mock_ctx, index, length);
assert_eq!(result, Err(HwsecError::CommandRunnerError));
}
#[test]
fn test_tpmc_raw_successful() {
let index = BOARD_ID_INDEX;
let length = 12_u16;
let mut mock_ctx = MockContext::new();
mock_ctx.cmd_runner().set_trunksd_running(false);
mock_ctx.cmd_runner().add_tpm_interaction(
"tpmc",
vec!["raw"],
split_into_hex_strtok(
"80 02 00 00 00 23 00 00 \
01 4e 01 3f ff 00 01 3f \
ff 00 00 00 00 09 40 00 \
00 09 00 00 00 00 00 00 \
0c 00 00",
),
0,
"0x80 0x02 0x00 0x00 0x00 0x21 0x00 0x00 \n
0x00 0x00 0x00 0x00 0x00 0x0e 0x00 0x0c \n
0x46 0x46 0x52 0x4d 0xb9 0xb9 0xad 0xb2 \n
0x7f 0x7f 0x00 0x00 0x00 0x00 0x01 0x00 \n
0x00",
"",
);
let result = nv_read(&mut mock_ctx, index, length);
assert_eq!(
result,
Ok(vec![
0x46, 0x46, 0x52, 0x4d, 0xb9, 0xb9, 0xad, 0xb2, 0x7f, 0x7f, 0x00, 0x00
])
);
}
#[test]
fn nonzero_tpmc_return_code() {
let index = BOARD_ID_INDEX;
let length = 12_u16;
let mut mock_ctx = MockContext::new();
mock_ctx.cmd_runner().set_trunksd_running(false);
mock_ctx.cmd_runner().add_tpm_interaction(
"tpmc",
vec!["raw"],
split_into_hex_strtok(
"80 02 00 00 00 23 00 00 \
01 4e 01 3f ff 00 01 3f \
ff 00 00 00 00 09 40 00 \
00 09 00 00 00 00 00 00 \
0c 00 00",
),
-1,
"",
"bad byte value \"8002000000230000014e013\
fff00013fff0000000009400000090000000000000c0000\"",
);
let result = nv_read(&mut mock_ctx, index, length);
assert_eq!(result, Err(HwsecError::CommandRunnerError));
}
}