blob: eb9027bee0978b2b5ee6d0e5779c8264382ecc2b [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 "trunks/csme/pinweaver_provision_impl.h"
#include <memory>
#include <string>
#include <base/check.h>
#include <base/logging.h>
#include <crypto/sha2.h>
#include "trunks/csme/mei_client.h"
#include "trunks/csme/mei_client_factory.h"
#include "trunks/csme/pinweaver_provision_client.h"
#include "trunks/error_codes.h"
#include "trunks/tpm_state.h"
#include "trunks/tpm_utility.h"
#include "trunks/trunks_factory_impl.h"
namespace trunks {
namespace csme {
namespace {
enum class PinwWeaverSaltingKeyType {
kTpmKey,
kNullKey,
};
// Returns the corresponding `PinwWeaverSaltingKeyType` for the build time
// setting.
constexpr PinwWeaverSaltingKeyType GetPinwWeaverSaltingKeyType() {
return USE_PINWEAVER_CSME ? PinwWeaverSaltingKeyType::kTpmKey
: PinwWeaverSaltingKeyType::kNullKey;
}
} // namespace
PinWeaverProvisionImpl::PinWeaverProvisionImpl(const TrunksFactory& factory)
: factory_(factory) {}
bool PinWeaverProvisionImpl::Provision() {
std::string public_key_hash;
if (!GetProvisionKeyContent(public_key_hash)) {
LOG(ERROR) << "Failed to get provision key hash.";
return false;
}
if (!ProvisionSaltingKeyHash(public_key_hash)) {
LOG(ERROR) << "Failed to provision pinweaver-scme salting key.";
return false;
}
return true;
}
bool PinWeaverProvisionImpl::GetProvisionKeyContent(std::string& key_hash) {
switch (GetPinwWeaverSaltingKeyType()) {
case PinwWeaverSaltingKeyType::kTpmKey: {
std::unique_ptr<trunks::TpmUtility> tpm_utility =
factory_.GetTpmUtility();
// Persists the salting key in case it's not done yet.
trunks::TPM_RC result = tpm_utility->PrepareForPinWeaver();
if (result) {
LOG(ERROR) << ": Failed to prepare for pinweaver: "
<< trunks::GetErrorString(result);
return false;
}
trunks::TPMT_PUBLIC public_area;
result =
tpm_utility->GetKeyPublicArea(trunks::kCsmeSaltingKey, &public_area);
if (result) {
LOG(ERROR) << ": Failed to get public key info: "
<< trunks::GetErrorString(result);
return false;
}
if (public_area.type != trunks::TPM_ALG_ECC) {
LOG(ERROR) << "Unexpected key type (should be trunks::TPM_ALG_ECC): "
<< public_area.type;
return false;
}
const std::string public_key =
StringFrom_TPM2B_ECC_PARAMETER(public_area.unique.ecc.x) +
StringFrom_TPM2B_ECC_PARAMETER(public_area.unique.ecc.y);
key_hash = crypto::SHA256HashString(public_key);
} break;
case PinwWeaverSaltingKeyType::kNullKey:
key_hash = std::string(crypto::kSHA256Length, '\0');
break;
}
return true;
}
bool PinWeaverProvisionImpl::ProvisionSaltingKeyHash(
const std::string& public_key_hash) {
MeiClientFactory mei_client_factory;
// We don't need to provision salting key if the device doesn't support it.
if (GetPinwWeaverSaltingKeyType() == PinwWeaverSaltingKeyType::kNullKey &&
!mei_client_factory.CreateMeiClientForPinWeaverProvision()->IsSupport()) {
return true;
}
PinWeaverProvisionClient client(&mei_client_factory);
bool committed = false;
std::string salting_key_hash;
if (client.GetSaltingKeyHash(&salting_key_hash, &committed) && committed) {
if (salting_key_hash != public_key_hash) {
LOG(ERROR) << "Provisioned salting key hash mismatched.";
return false;
}
LOG(INFO) << "Already provisioned.";
return true;
}
LOG(INFO) << "Not provisioned yet; start provisioning.";
if (!client.SetSaltingKeyHash(public_key_hash)) {
LOG(ERROR) << "Failed to set key hash.";
return false;
}
if (!client.CommitSaltingKeyHash()) {
LOG(ERROR) << "Failed to commit salting key hash.";
return false;
}
return true;
}
bool PinWeaverProvisionImpl::InitOwner() {
std::unique_ptr<trunks::TpmState> tpm_state(factory_.GetTpmState());
trunks::TPM_RC result = tpm_state->Initialize();
if (result) {
LOG(ERROR) << "Failed to initialize `TpmState`.";
return false;
}
if (tpm_state->IsOwnerPasswordSet()) {
LOG(ERROR) << "Init owner requites empty owner password.";
return false;
}
return InitOwnerInternal();
}
bool PinWeaverProvisionImpl::InitOwnerInternal() {
MeiClientFactory mei_client_factory;
PinWeaverProvisionClient client(&mei_client_factory);
if (!client.InitOwner()) {
LOG(ERROR) << "Failed to init owner.";
return false;
}
return true;
}
} // namespace csme
} // namespace trunks