blob: fe58364b06867932fc8535a29284829fa0d9d20a [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <base/logging.h>
#include <linux/vtpm_proxy.h>
#include <tpm2/tpm_simulator.hpp>
#include "tpm2-simulator/tpm_executor_tpm2_impl.h"
namespace {
std::string CommandWithCode(uint32_t code) {
std::string response;
response.resize(10);
unsigned char* buffer = reinterpret_cast<unsigned char*>(response.data());
tpm2::TPM_ST tag = TPM_ST_NO_SESSIONS;
tpm2::INT32 size = 10;
tpm2::UINT32 len = size;
tpm2::TPMI_ST_COMMAND_TAG_Marshal(&tag, &buffer, &size);
tpm2::UINT32_Marshal(&len, &buffer, &size);
tpm2::TPM_CC_Marshal(&code, &buffer, &size);
return response;
}
} // namespace
namespace tpm2_simulator {
void TpmExecutorTpm2Impl::InitializeVTPM() {
// Initialize TPM.
tpm2::_plat__Signal_PowerOn();
/*
* Make sure NV RAM metadata is initialized, needed to check
* manufactured status. This is a speculative call which will have to
* be repeated in case the TPM has not been through the manufacturing
* sequence yet. No harm in calling it twice in that case.
*/
tpm2::_TPM_Init();
tpm2::_plat__SetNvAvail();
if (!tpm2::tpm_manufactured()) {
tpm2::TPM_Manufacture(true);
// TODO(b/132145000): Verify if the second call to _TPM_Init() is necessary.
tpm2::_TPM_Init();
if (!tpm2::tpm_endorse())
LOG(ERROR) << __func__ << " Failed to endorse TPM with a fixed key.";
}
LOG(INFO) << "vTPM Initialize.";
}
size_t TpmExecutorTpm2Impl::GetCommandSize(const std::string& command) {
unsigned char* header =
reinterpret_cast<unsigned char*>(const_cast<char*>(command.data()));
int32_t header_size = command.size();
tpm2::TPMI_ST_COMMAND_TAG tag;
uint32_t command_size;
tpm2::TPM_RC rc =
tpm2::TPMI_ST_COMMAND_TAG_Unmarshal(&tag, &header, &header_size);
if (rc != TPM_RC_SUCCESS) {
LOG(ERROR) << "Failed to parse tag";
return command.size();
}
rc = tpm2::UINT32_Unmarshal(&command_size, &header, &header_size);
if (rc != TPM_RC_SUCCESS) {
LOG(ERROR) << "Failed to parse size";
return command.size();
}
return command_size;
}
std::string TpmExecutorTpm2Impl::RunCommand(const std::string& command) {
// TODO(yich): ExecuteCommand would mutate the command buffer, so we created a
// copy of the input command at here.
std::string command_copy = command;
unsigned char* command_ptr =
reinterpret_cast<unsigned char*>(command_copy.data());
unsigned char* header = command_ptr;
int32_t header_size = command.size();
tpm2::TPMI_ST_COMMAND_TAG tag;
uint32_t command_size;
tpm2::TPM_CC command_code = 0;
tpm2::TPM_RC rc =
tpm2::TPMI_ST_COMMAND_TAG_Unmarshal(&tag, &header, &header_size);
if (rc != TPM_RC_SUCCESS) {
return CommandWithCode(rc);
}
rc = tpm2::UINT32_Unmarshal(&command_size, &header, &header_size);
if (rc != TPM_RC_SUCCESS) {
return CommandWithCode(rc);
}
rc = tpm2::TPM_CC_Unmarshal(&command_code, &header, &header_size);
if (command_code == TPM2_CC_SET_LOCALITY) {
// Ignoring TPM2_CC_SET_LOCALITY command.
return CommandWithCode(TPM_RC_SUCCESS);
}
unsigned int response_size;
unsigned char* response;
tpm2::ExecuteCommand(command.size(), command_ptr, &response_size, &response);
return std::string(reinterpret_cast<char*>(response), response_size);
}
} // namespace tpm2_simulator