| // 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 "vtpm/commands/nv_read_command.h" |
| |
| #include <utility> |
| |
| #include <base/check.h> |
| #include <base/logging.h> |
| #include <trunks/error_codes.h> |
| #include <trunks/tpm_generated.h> |
| |
| namespace vtpm { |
| |
| NvReadCommand::NvReadCommand(trunks::CommandParser* command_parser, |
| trunks::ResponseSerializer* response_serializer, |
| NvSpaceManager* nv_space_manager) |
| : command_parser_(command_parser), |
| response_serializer_(response_serializer), |
| nv_space_manager_(nv_space_manager) { |
| CHECK(command_parser_); |
| CHECK(response_serializer_); |
| CHECK(nv_space_manager_); |
| } |
| |
| void NvReadCommand::Run(const std::string& command, |
| CommandResponseCallback callback) { |
| std::string data; |
| const trunks::TPM_RC rc = RunInternal(command, data); |
| std::string response; |
| LOG_IF(ERROR, rc) << __func__ << ": Returning " << trunks::GetErrorString(rc); |
| if (rc) { |
| response_serializer_->SerializeHeaderOnlyResponse(rc, &response); |
| } else { |
| trunks::TPM2B_MAX_NV_BUFFER buffer = trunks::Make_TPM2B_MAX_NV_BUFFER(data); |
| response_serializer_->SerializeResponseNvRead(buffer, &response); |
| } |
| std::move(callback).Run(response); |
| } |
| |
| trunks::TPM_RC NvReadCommand::RunInternal(const std::string& command, |
| std::string& data) { |
| std::string buffer = command; |
| trunks::TPMI_RH_NV_AUTH auth_handle; |
| trunks::TPMI_RH_NV_INDEX nv_index; |
| trunks::TPMS_AUTH_COMMAND auth; |
| trunks::UINT16 size; |
| trunks::UINT16 offset; |
| |
| trunks::TPM_RC rc = command_parser_->ParseCommandNvRead( |
| &buffer, &auth_handle, &nv_index, &auth, &size, &offset); |
| |
| if (rc) { |
| return rc; |
| } |
| |
| // Only the password authorization is supported for nv read. Other handle |
| // values are considered to be invalid. |
| if (auth.session_handle != trunks::TPM_RS_PW) { |
| return trunks::TPM_RC_HANDLE; |
| } |
| |
| // Only support owner or nv index itself as the auth handle. |
| if (auth_handle != nv_index && auth_handle != trunks::TPM_RH_OWNER) { |
| LOG(ERROR) << __func__ << ": Unsupported or wrong auth handle."; |
| return trunks::TPM_RC_NV_AUTHORIZATION; |
| } |
| |
| // If the size is even larger than the buffer size, i.e., this virtual TPM's |
| // `MAX_NV_BUFFER_SIZE` defined in `tpm_generated.h`, return `TPM_RC_VALUE` as |
| // what we learnt from some geenric TPMs. |
| if (size > MAX_NV_BUFFER_SIZE) { |
| return trunks::TPM_RC_VALUE; |
| } |
| |
| // Get the password. |
| std::string nv_data; |
| const std::string password(auth.hmac.buffer, |
| auth.hmac.buffer + auth.hmac.size); |
| rc = nv_space_manager_->Read(nv_index, password, nv_data); |
| if (rc) { |
| return rc; |
| } |
| |
| if (nv_data.size() < size + offset) { |
| return trunks::TPM_RC_NV_RANGE; |
| } |
| |
| data = nv_data.substr(offset, size); |
| return trunks::TPM_RC_SUCCESS; |
| } |
| |
| } // namespace vtpm |