blob: 6014b4b43ad94ad338e2f3e017c4a1be50535eb7 [file] [log] [blame]
// 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.
#include "trunks/real_command_parser.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "trunks/password_authorization_delegate.h"
#include "trunks/tpm_generated.h"
namespace trunks {
// A placeholder test fixture.
class RealCommandParserTest : public testing::Test {
protected:
RealCommandParser parser_;
};
namespace {
std::string ResizeSerializedBuffer(std::string command, int resize) {
const int new_size = static_cast<int>(command.size()) + resize;
if (new_size < kHeaderSize) {
return "";
}
// Copy the "tag" part.
std::string buffer = command.substr(0, sizeof(TPMI_ST_COMMAND_TAG));
// Append `new_size` to `buffer`.
if (Serialize_UINT32(new_size, &buffer) != TPM_RC_SUCCESS) {
return "";
}
// Skip "tag" and "size" in the original command.
buffer += command.substr(buffer.size(), std::string::npos);
// Resize the whole buffer to `new_size`.
buffer.resize(new_size, '\0');
return buffer;
}
TEST_F(RealCommandParserTest, ParseHeaderSuccessHeaderOnlyCommand) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
// TPM2_GetTestResult has no either handles or parameters.
ASSERT_EQ(
Tpm::SerializeCommand_GetTestResult(&command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc), TPM_RC_SUCCESS);
EXPECT_EQ(tag, TPM_ST_NO_SESSIONS);
EXPECT_EQ(size, kHeaderSize);
EXPECT_EQ(cc, TPM_CC_GetTestResult);
}
TEST_F(RealCommandParserTest, ParseHeaderSuccessCommandWithPayload) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
TPMI_YES_NO full_test = {};
ASSERT_EQ(Tpm::SerializeCommand_SelfTest(full_test, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc), TPM_RC_SUCCESS);
EXPECT_EQ(tag, TPM_ST_NO_SESSIONS);
// TPM2_SelfTest has one parameter of TPMI_YES_NO type.
EXPECT_EQ(size, kHeaderSize + sizeof(TPMI_YES_NO));
EXPECT_EQ(cc, TPM_CC_SelfTest);
}
TEST_F(RealCommandParserTest, ParseHeaderFailureHeaderCommandTooShort) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
// TPM2_GetTestResult has no either handles or parameters.
ASSERT_EQ(
Tpm::SerializeCommand_GetTestResult(&command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Make the command too short.
command.pop_back();
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc),
TPM_RC_COMMAND_SIZE);
}
TEST_F(RealCommandParserTest, ParseHeaderFailureHeaderNoSize) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
// TPM2_GetTestResult has no either handles or parameters.
ASSERT_EQ(
Tpm::SerializeCommand_GetTestResult(&command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Make the command too short.
command.resize(sizeof(tag));
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc),
TPM_RC_INSUFFICIENT);
}
TEST_F(RealCommandParserTest, ParseHeaderFailureEmpty) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc),
TPM_RC_INSUFFICIENT);
}
TEST_F(RealCommandParserTest, ParseHeaderFailurePayloadTooLong) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
TPMI_YES_NO full_test = {};
ASSERT_EQ(Tpm::SerializeCommand_SelfTest(full_test, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Make the command too long.
command += 'X';
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc),
TPM_RC_COMMAND_SIZE);
}
TEST_F(RealCommandParserTest, ParseHeaderFailurePayloadTooShort) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
TPMI_YES_NO full_test = {};
ASSERT_EQ(Tpm::SerializeCommand_SelfTest(full_test, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Make the command too short.
command.pop_back();
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc),
TPM_RC_COMMAND_SIZE);
}
TEST_F(RealCommandParserTest, ParseHeaderFailureBadTag) {
std::string command;
TPMI_ST_COMMAND_TAG tag = TPM_ST_SESSIONS;
UINT32 size = 0;
TPM_CC cc = TPM_CC_FIRST;
// TPM2_GetTestResult has no either handles or parameters.
ASSERT_EQ(
Tpm::SerializeCommand_GetTestResult(&command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Replace the data with a bad tag.
std::string bad_tag;
ASSERT_EQ(Serialize_TPMI_ST_COMMAND_TAG(TPM_ST_NULL, &bad_tag),
TPM_RC_SUCCESS);
for (int i = 0; i < bad_tag.size(); ++i) {
command[i] = bad_tag[i];
}
EXPECT_EQ(parser_.ParseHeader(&command, &tag, &size, &cc), TPM_RC_BAD_TAG);
}
TEST_F(RealCommandParserTest, ParseCommandGetCapabilitySuccess) {
std::string command;
const TPM_CAP cap = TPM_CAP_HANDLES;
const UINT32 fake_property = 123;
const UINT32 property_count = 1;
ASSERT_EQ(Tpm::SerializeCommand_GetCapability(
cap, fake_property, property_count, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
TPM_CAP cap_out = TPM_CAP_FIRST;
UINT32 property_out = 0;
UINT32 property_count_out = 0;
EXPECT_EQ(parser_.ParseCommandGetCapability(&command, &cap_out, &property_out,
&property_count_out),
TPM_RC_SUCCESS);
EXPECT_EQ(cap_out, cap);
EXPECT_EQ(property_out, fake_property);
EXPECT_EQ(property_count_out, property_count);
}
TEST_F(RealCommandParserTest, ParseCommandGetCapabilityFailureWrongHeader) {
std::string command;
const TPM_CAP cap = TPM_CAP_HANDLES;
const UINT32 fake_property = 123;
const UINT32 property_count = 1;
ASSERT_EQ(Tpm::SerializeCommand_GetCapability(
cap, fake_property, property_count, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Breaks the tag.
command[0] = ~command[0];
TPM_CAP cap_out = TPM_CAP_FIRST;
UINT32 property_out = 0;
UINT32 property_count_out = 0;
EXPECT_NE(parser_.ParseCommandGetCapability(&command, &cap_out, &property_out,
&property_count_out),
TPM_RC_SUCCESS);
}
TEST_F(RealCommandParserTest,
ParseCommandGetCapabilityFailureParamNoPropertyCount) {
std::string command;
const TPM_CAP cap = TPM_CAP_HANDLES;
const UINT32 fake_property = 123;
const UINT32 property_count = 1;
ASSERT_EQ(Tpm::SerializeCommand_GetCapability(
cap, fake_property, property_count, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
command = ResizeSerializedBuffer(command, -4);
TPM_CAP cap_out = TPM_CAP_FIRST;
UINT32 property_out = 0;
UINT32 property_count_out = 0;
EXPECT_EQ(parser_.ParseCommandGetCapability(&command, &cap_out, &property_out,
&property_count_out),
TPM_RC_INSUFFICIENT);
}
TEST_F(RealCommandParserTest, ParseCommandGetCapabilityFailureParamNoProperty) {
std::string command;
const TPM_CAP cap = TPM_CAP_HANDLES;
const UINT32 fake_property = 123;
const UINT32 property_count = 1;
ASSERT_EQ(Tpm::SerializeCommand_GetCapability(
cap, fake_property, property_count, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
command = ResizeSerializedBuffer(command, -8);
TPM_CAP cap_out = TPM_CAP_FIRST;
UINT32 property_out = 0;
UINT32 property_count_out = 0;
EXPECT_EQ(parser_.ParseCommandGetCapability(&command, &cap_out, &property_out,
&property_count_out),
TPM_RC_INSUFFICIENT);
}
TEST_F(RealCommandParserTest, ParseCommandGetCapabilityFailureParamNoCap) {
std::string command;
const TPM_CAP cap = TPM_CAP_HANDLES;
const UINT32 fake_property = 123;
const UINT32 property_count = 1;
ASSERT_EQ(Tpm::SerializeCommand_GetCapability(
cap, fake_property, property_count, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
command = ResizeSerializedBuffer(command, -12);
TPM_CAP cap_out = TPM_CAP_FIRST;
UINT32 property_out = 0;
UINT32 property_count_out = 0;
EXPECT_EQ(parser_.ParseCommandGetCapability(&command, &cap_out, &property_out,
&property_count_out),
TPM_RC_INSUFFICIENT);
}
TEST_F(RealCommandParserTest, ParseCommandGetCapabilityFailureParamTooLong) {
std::string command;
const TPM_CAP cap = TPM_CAP_HANDLES;
const UINT32 fake_property = 123;
const UINT32 property_count = 1;
ASSERT_EQ(Tpm::SerializeCommand_GetCapability(
cap, fake_property, property_count, &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
command = ResizeSerializedBuffer(command, 2);
TPM_CAP cap_out = TPM_CAP_FIRST;
UINT32 property_out = 0;
UINT32 property_count_out = 0;
EXPECT_EQ(parser_.ParseCommandGetCapability(&command, &cap_out, &property_out,
&property_count_out),
TPM_RC_SIZE);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadSuccess) {
std::string command;
const TPMI_RH_NV_AUTH auth_handle = 111;
const std::string auth_handle_name = "auth_name";
const TPMI_RH_NV_INDEX nv_index = 222;
const std::string nv_index_name = "index_name";
const UINT16 size = 69;
const UINT16 offset = 449;
const std::string fake_password = "password";
PasswordAuthorizationDelegate delegate(fake_password);
ASSERT_EQ(Tpm::SerializeCommand_NV_Read(auth_handle, auth_handle_name,
nv_index, nv_index_name, size, offset,
&command, &delegate),
TPM_RC_SUCCESS);
TPMI_RH_NV_AUTH auth_handle_out = 0;
TPMI_RH_NV_INDEX nv_index_out = 0;
TPMS_AUTH_COMMAND auth_out;
UINT16 size_out = 0;
UINT16 offset_out = 0;
EXPECT_EQ(
parser_.ParseCommandNvRead(&command, &auth_handle_out, &nv_index_out,
&auth_out, &size_out, &offset_out),
TPM_RC_SUCCESS);
EXPECT_EQ(auth_handle_out, auth_handle);
EXPECT_EQ(nv_index_out, nv_index);
EXPECT_EQ(size_out, size);
EXPECT_EQ(offset_out, offset);
EXPECT_EQ(auth_out.session_handle, TPM_RS_PW);
EXPECT_EQ(std::string(auth_out.hmac.buffer,
auth_out.hmac.buffer + auth_out.hmac.size),
fake_password);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadFailureWrongHeader) {
std::string command;
const TPMI_RH_NV_AUTH auth_handle = 111;
const std::string auth_handle_name = "auth_name";
const TPMI_RH_NV_INDEX nv_index = 222;
const std::string nv_index_name = "index_name";
const UINT16 size = 69;
const UINT16 offset = 449;
const std::string fake_password = "password";
PasswordAuthorizationDelegate delegate(fake_password);
ASSERT_EQ(Tpm::SerializeCommand_NV_Read(auth_handle, auth_handle_name,
nv_index, nv_index_name, size, offset,
&command, &delegate),
TPM_RC_SUCCESS);
// Breaks the tag.
command[0] = ~command[0];
TPMI_RH_NV_AUTH auth_handle_out = 0;
TPMI_RH_NV_INDEX nv_index_out = 0;
TPMS_AUTH_COMMAND auth_out;
UINT16 size_out = 0;
UINT16 offset_out = 0;
EXPECT_NE(
parser_.ParseCommandNvRead(&command, &auth_handle_out, &nv_index_out,
&auth_out, &size_out, &offset_out),
TPM_RC_SUCCESS);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadFailureShortParam) {
std::string command;
const TPMI_RH_NV_AUTH auth_handle = 111;
const std::string auth_handle_name = "auth_name";
const TPMI_RH_NV_INDEX nv_index = 222;
const std::string nv_index_name = "index_name";
const UINT16 size = 69;
const UINT16 offset = 449;
const std::string fake_password = "password";
PasswordAuthorizationDelegate delegate(fake_password);
ASSERT_EQ(Tpm::SerializeCommand_NV_Read(auth_handle, auth_handle_name,
nv_index, nv_index_name, size, offset,
&command, &delegate),
TPM_RC_SUCCESS);
// Make it short.
command = ResizeSerializedBuffer(command, -2);
TPMI_RH_NV_AUTH auth_handle_out = 0;
TPMI_RH_NV_INDEX nv_index_out = 0;
TPMS_AUTH_COMMAND auth_out;
UINT16 size_out = 0;
UINT16 offset_out = 0;
EXPECT_EQ(
parser_.ParseCommandNvRead(&command, &auth_handle_out, &nv_index_out,
&auth_out, &size_out, &offset_out),
TPM_RC_INSUFFICIENT);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadFailureParamTooLong) {
std::string command;
const TPMI_RH_NV_AUTH auth_handle = 111;
const std::string auth_handle_name = "auth_name";
const TPMI_RH_NV_INDEX nv_index = 222;
const std::string nv_index_name = "index_name";
const UINT16 size = 69;
const UINT16 offset = 449;
const std::string fake_password = "password";
PasswordAuthorizationDelegate delegate(fake_password);
ASSERT_EQ(Tpm::SerializeCommand_NV_Read(auth_handle, auth_handle_name,
nv_index, nv_index_name, size, offset,
&command, &delegate),
TPM_RC_SUCCESS);
// Make it short.
command = ResizeSerializedBuffer(command, 2);
TPMI_RH_NV_AUTH auth_handle_out = 0;
TPMI_RH_NV_INDEX nv_index_out = 0;
TPMS_AUTH_COMMAND auth_out;
UINT16 size_out = 0;
UINT16 offset_out = 0;
EXPECT_EQ(
parser_.ParseCommandNvRead(&command, &auth_handle_out, &nv_index_out,
&auth_out, &size_out, &offset_out),
TPM_RC_SIZE);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadPublicSuccess) {
std::string command;
const TPMI_RH_NV_INDEX nv_index = 222;
ASSERT_EQ(Tpm::SerializeCommand_NV_ReadPublic(
nv_index, /*nv_index_name=*/"unused name", &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
TPMI_RH_NV_INDEX nv_index_out = 0;
EXPECT_EQ(parser_.ParseCommandNvReadPublic(&command, &nv_index_out),
TPM_RC_SUCCESS);
EXPECT_EQ(nv_index_out, nv_index);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadPublicFailureWrongHeader) {
std::string command;
const TPMI_RH_NV_INDEX nv_index = 222;
ASSERT_EQ(Tpm::SerializeCommand_NV_ReadPublic(
nv_index, /*nv_index_name=*/"unused name", &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Breaks the tag.
command[0] = ~command[0];
TPMI_RH_NV_INDEX nv_index_out = 0;
EXPECT_NE(parser_.ParseCommandNvReadPublic(&command, &nv_index_out),
TPM_RC_SUCCESS);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadPublicFailureShortParam) {
std::string command;
const TPMI_RH_NV_INDEX nv_index = 222;
ASSERT_EQ(Tpm::SerializeCommand_NV_ReadPublic(
nv_index, /*nv_index_name=*/"unused name", &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Make it short.
command = ResizeSerializedBuffer(command, -1);
TPMI_RH_NV_INDEX nv_index_out = 0;
EXPECT_EQ(parser_.ParseCommandNvReadPublic(&command, &nv_index_out),
TPM_RC_INSUFFICIENT);
}
TEST_F(RealCommandParserTest, ParseCommandNvReadPublicFailureParamTooLong) {
std::string command;
const TPMI_RH_NV_INDEX nv_index = 222;
ASSERT_EQ(Tpm::SerializeCommand_NV_ReadPublic(
nv_index, /*nv_index_name=*/"unused name", &command,
/*authorization_delegate=*/nullptr),
TPM_RC_SUCCESS);
// Make it short.
command = ResizeSerializedBuffer(command, 1);
TPMI_RH_NV_INDEX nv_index_out = 0;
EXPECT_EQ(parser_.ParseCommandNvReadPublic(&command, &nv_index_out),
TPM_RC_SIZE);
}
} // namespace
} // namespace trunks