| // 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::gen_tpm_cmd; | |
| use super::run_tpm_cmd; | |
| use super::CommandArg; | |
| use super::SessionOption; | |
| use super::TpmiStCommandTag; | |
| use crate::context::Context; | |
| use crate::error::HwsecError; | |
| pub fn nv_write(ctx: &mut impl Context, index: u32, data: Vec<u8>) -> Result<(), HwsecError> { | |
| let tpm_cmd = gen_tpm_cmd( | |
| TpmiStCommandTag::TPM_ST_SESSIONS(SessionOption::EmptyPassword), | |
| CommandArg::TPM_CC_NV_Write(data), | |
| index, | |
| )?; | |
| let response = run_tpm_cmd(ctx, tpm_cmd)?; | |
| if response.success() { | |
| Ok(()) | |
| } else { | |
| Err(HwsecError::Tpm2Error(response.return_code())) | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use crate::context::mock::MockContext; | |
| use crate::tpm2::tests::split_into_hex_strtok; | |
| use crate::tpm2::BOARD_ID_INDEX; | |
| #[test] | |
| fn test_nv_write_successful() { | |
| let index = BOARD_ID_INDEX; | |
| let data: Vec<u8> = vec![0xff, 0x01, 0x23]; | |
| 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 26 00 00 \ | |
| 01 37 01 3f ff 00 01 3f \ | |
| ff 00 00 00 00 09 40 00 \ | |
| 00 09 00 00 00 00 00 00 \ | |
| 03 ff 01 23 00 00", | |
| ), | |
| 0, | |
| "800200000021000000000000000E000C4646524DB9B9ADB27F7F00000000010000", | |
| "", | |
| ); | |
| let result = nv_write(&mut mock_ctx, index, data); | |
| assert_eq!(result, Ok(())); | |
| } | |
| #[test] | |
| fn test_nv_write_bad_formatted_response() { | |
| let index = 0x89abcdef_u32; | |
| let data: Vec<u8> = vec![ | |
| 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, | |
| 0xee, 0xff, | |
| ]; | |
| 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 33 00 00 \ | |
| 01 37 89 ab cd ef 89 ab \ | |
| cd ef 00 00 00 09 40 00 \ | |
| 00 09 00 00 00 00 00 00 \ | |
| 10 00 11 22 33 44 55 66 \ | |
| 77 88 99 aa bb cc dd ee \ | |
| ff 00 00", | |
| ), | |
| 0, | |
| // out[4..12]: 0x0000000B isn't its length, should have been 0x0000000A | |
| // this inaccurate description of length triggers a bad format error, | |
| // which is what we want to test here. | |
| "80010000000B00009487", | |
| "", | |
| ); | |
| let result = nv_write(&mut mock_ctx, index, data); | |
| assert_eq!(result, Err(HwsecError::Tpm2ResponseBadFormatError)); | |
| } | |
| #[test] | |
| fn test_nv_write_nonzero_exit_status() { | |
| let index = 0x89abcdef_u32; | |
| let data: Vec<u8> = vec![ | |
| 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, | |
| 0xee, 0xff, | |
| ]; | |
| 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 33 00 00 \ | |
| 01 37 89 ab cd ef 89 ab \ | |
| cd ef 00 00 00 09 40 00 \ | |
| 00 09 00 00 00 00 00 00 \ | |
| 10 00 11 22 33 44 55 66 \ | |
| 77 88 99 aa bb cc dd ee \ | |
| ff 00 00", | |
| ), | |
| 1, | |
| "", | |
| "", | |
| ); | |
| let result = nv_write(&mut mock_ctx, index, data); | |
| assert_eq!(result, Err(HwsecError::CommandRunnerError)); | |
| } | |
| #[test] | |
| fn test_nv_write_data_too_large() { | |
| let index = BOARD_ID_INDEX; | |
| let data: Vec<u8> = vec![0x99; 1000000]; | |
| let mut mock_ctx = MockContext::new(); | |
| let result = nv_write(&mut mock_ctx, index, data); | |
| assert_eq!(result, Err(HwsecError::InvalidArgumentError)); | |
| } | |
| } |