blob: df25a8c04ce608da4b453aedae2a4e5283b218cf [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.
#include "vtpm/commands/virtualizer.h"
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <base/files/file_path.h>
#include <base/functional/callback.h>
#include <trunks/command_parser.h>
#include <trunks/response_serializer.h>
#include <trunks/tpm_generated.h>
#include "vtpm/commands/forward_command.h"
#include "vtpm/commands/get_capability_command.h"
#include "vtpm/commands/nv_read_command.h"
#include "vtpm/commands/nv_read_public_command.h"
#include "vtpm/commands/unsupported_command.h"
namespace vtpm {
namespace {
// Handles and index from "TCG TPM v2.0 Provisioning Guidance" v1r1 Table 2 and
// "TCG EK Credential Profile For TPM Family 2.0; Level 0" v2.4r3.
//
// Note that since these are ECC objects they are at different locations than
// the RSA objects.
constexpr trunks::TPM_HANDLE kSrkHandle = 0x81000002;
constexpr trunks::TPM_HANDLE kEkHandle = 0x81010002;
constexpr trunks::TPM_NV_INDEX kVekCertIndex = 0x01C0000a;
// TODO(b/228789530): Virtualizer is not the best one that decides the layout of
// files. We should make sure that the path is managed in a more systematic way,
// and it should be revolved after all the persistent data is ready, and before
// the bug is resolved.
constexpr char kVsrkCachePath[] = "/var/lib/vtpm/vsrk.blob";
constexpr char kVekCachePath[] = "/var/lib/vtpm/vek.blob";
constexpr char kVekCertCachePath[] = "/var/lib/vtpm/vek_cert.blob";
constexpr char kVirtualEndorsementPassword[] = "";
constexpr trunks::TPM_CC kSupportedForwardCommands[] = {
trunks::TPM_CC_ReadPublic,
trunks::TPM_CC_Create,
trunks::TPM_CC_Load,
trunks::TPM_CC_FlushContext,
trunks::TPM_CC_StartAuthSession,
trunks::TPM_CC_PolicySecret,
trunks::TPM_CC_MakeCredential,
trunks::TPM_CC_ActivateCredential,
trunks::TPM_CC_Hash,
trunks::TPM_CC_Sign,
trunks::TPM_CC_VerifySignature,
trunks::TPM_CC_Certify,
trunks::TPM_CC_CertifyCreation,
trunks::TPM_CC_GetRandom,
};
} // namespace
std::unique_ptr<Virtualizer> Virtualizer::Create(Virtualizer::Profile profile) {
std::unique_ptr<Virtualizer> v =
std::unique_ptr<Virtualizer>(new Virtualizer());
if (profile == Virtualizer::Profile::kGLinux) {
CHECK(v->trunks_factory_.Initialize())
<< " Failed to initialize trunks factory.";
v->command_parser_ = &v->real_command_parser_;
v->response_serializer_ = &v->real_response_serializer_;
// Set up VSRK.
v->vsrk_cache_ =
std::make_unique<DiskCacheBlob>(base::FilePath(kVsrkCachePath));
v->cacheable_vsrk_ =
std::make_unique<CacheableBlob>(&v->vsrk_, v->vsrk_cache_.get());
// Set up attestation client.
scoped_refptr<dbus::Bus> bus = v->system_bus_connection_.Connect();
CHECK(bus) << "Failed to connect to system D-Bus";
v->attestation_proxy_ =
std::make_unique<org::chromium::AttestationProxy>(bus);
// Set up virtual endorsemnet.
v->attested_virtual_endorsement_ =
std::make_unique<AttestedVirtualEndorsement>(
v->attestation_proxy_.get());
// Set up tpm_manager proxy.
v->tpm_manager_proxy_ =
std::make_unique<org::chromium::TpmManagerProxy>(bus);
v->endorsement_password_changer_ =
std::make_unique<EndorsementPasswordChanger>(
v->tpm_manager_proxy_.get(), kVirtualEndorsementPassword);
// Set up VEK.
v->vek_cache_ =
std::make_unique<DiskCacheBlob>(base::FilePath(kVekCachePath));
v->vek_ = std::make_unique<Vek>(v->attested_virtual_endorsement_.get());
v->cacheable_vek_ =
std::make_unique<CacheableBlob>(v->vek_.get(), v->vek_cache_.get());
// Set up VEK cert.
v->vek_cert_cache_ =
std::make_unique<DiskCacheBlob>(base::FilePath(kVekCertCachePath));
v->vek_cert_ =
std::make_unique<VekCert>(v->attested_virtual_endorsement_.get());
v->cacheable_vek_cert_ = std::make_unique<CacheableBlob>(
v->vek_cert_.get(), v->vek_cert_cache_.get());
v->vek_cert_manager_ =
std::make_unique<VekCertManager>(kVekCertIndex, v->vek_cert_.get());
v->real_tpm_handle_manager_ = std::make_unique<RealTpmHandleManager>(
&v->trunks_factory_, v->vek_cert_manager_.get(),
std::map<trunks::TPM_HANDLE, Blob*>{
{kSrkHandle, v->cacheable_vsrk_.get()},
{kEkHandle, v->vek_.get()},
});
// add `GetCapabilityCommand`.
v->commands_.emplace_back(std::make_unique<GetCapabilityCommand>(
&v->real_command_parser_, &v->real_response_serializer_,
&v->direct_forwarder_, v->real_tpm_handle_manager_.get(),
&v->real_tpm_property_manager_));
v->AddCommandSupport(trunks::TPM_CC_GetCapability,
v->commands_.back().get());
// Add `NvReadCommand`.
// Since the only nv sapce is vEK certificate, and no known potential use of
// any other nv space, use `vek_cert_manager_` directly.
v->commands_.emplace_back(std::make_unique<NvReadCommand>(
&v->real_command_parser_, &v->real_response_serializer_,
v->vek_cert_manager_.get()));
v->AddCommandSupport(trunks::TPM_CC_NV_Read, v->commands_.back().get());
// Add `NvReadPublicCommand`.
v->commands_.emplace_back(std::make_unique<NvReadPublicCommand>(
&v->real_command_parser_, &v->real_response_serializer_,
v->vek_cert_manager_.get(), &v->real_static_analyzer_));
v->AddCommandSupport(trunks::TPM_CC_NV_ReadPublic,
v->commands_.back().get());
// Add forwarded command w/ handle translateion.
v->commands_.emplace_back(std::make_unique<ForwardCommand>(
&v->real_command_parser_, &v->real_response_serializer_,
&v->real_static_analyzer_, v->real_tpm_handle_manager_.get(),
v->endorsement_password_changer_.get(), &v->direct_forwarder_));
for (trunks::TPM_CC cc : kSupportedForwardCommands) {
v->AddCommandSupport(cc, v->commands_.back().get());
}
// Add `SelfTestCommand`.
v->AddCommandSupport(trunks::TPM_CC_SelfTest, &v->self_test_command_);
// Use an `UnsupportedCommand` as fallback.
v->commands_.emplace_back(
std::make_unique<UnsupportedCommand>(v->response_serializer_));
v->fallback_command_ = v->commands_.back().get();
// Others are not implemented yet.
}
return v;
}
void Virtualizer::AddCommandSupport(trunks::TPM_CC cc, Command* command) {
command_table_.emplace(cc, command);
real_tpm_property_manager_.AddCommand(cc);
}
Virtualizer::Virtualizer(trunks::CommandParser* parser,
trunks::ResponseSerializer* serializer,
std::unordered_map<trunks::TPM_CC, Command*> table,
Command* fallback_command)
: command_parser_(parser),
response_serializer_(serializer),
command_table_(std::move(table)),
fallback_command_(fallback_command) {}
void Virtualizer::Run(const std::string& command,
CommandResponseCallback callback) {
std::string buffer = command;
trunks::TPMI_ST_COMMAND_TAG tag;
trunks::UINT32 size;
trunks::TPM_CC cc;
const trunks::TPM_RC rc =
command_parser_->ParseHeader(&buffer, &tag, &size, &cc);
if (rc) {
std::string response;
response_serializer_->SerializeHeaderOnlyResponse(rc, &response);
std::move(callback).Run(response);
return;
}
if (command_table_.count(cc) == 0) {
fallback_command_->Run(command, std::move(callback));
return;
}
command_table_[cc]->Run(command, std::move(callback));
}
} // namespace vtpm