1861 lines
70 KiB
C++
1861 lines
70 KiB
C++
//
|
|
// Copyright (C) 2014 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#include "trunks/tpm_utility_impl.h"
|
|
|
|
#include <memory>
|
|
|
|
#include <base/logging.h>
|
|
#include <base/sha1.h>
|
|
#include <base/stl_util.h>
|
|
#include <crypto/openssl_util.h>
|
|
#include <crypto/secure_hash.h>
|
|
#include <crypto/sha2.h>
|
|
#include <openssl/aes.h>
|
|
#include <openssl/rand.h>
|
|
|
|
#include "trunks/authorization_delegate.h"
|
|
#include "trunks/blob_parser.h"
|
|
#include "trunks/error_codes.h"
|
|
#include "trunks/hmac_authorization_delegate.h"
|
|
#include "trunks/hmac_session.h"
|
|
#include "trunks/policy_session.h"
|
|
#include "trunks/scoped_key_handle.h"
|
|
#include "trunks/tpm_constants.h"
|
|
#include "trunks/tpm_state.h"
|
|
#include "trunks/trunks_factory.h"
|
|
|
|
namespace {
|
|
|
|
const char kPlatformPassword[] = "cros-platform";
|
|
const char kWellKnownPassword[] = "cros-password";
|
|
const size_t kMaxPasswordLength = 32;
|
|
// The below maximum is defined in TPM 2.0 Library Spec Part 2 Section 13.1
|
|
const uint32_t kMaxNVSpaceIndex = (1 << 24) - 1;
|
|
|
|
// Returns a serialized representation of the unmodified handle. This is useful
|
|
// for predefined handle values, like TPM_RH_OWNER. For details on what types of
|
|
// handles use this name formula see Table 3 in the TPM 2.0 Library Spec Part 1
|
|
// (Section 16 - Names).
|
|
std::string NameFromHandle(trunks::TPM_HANDLE handle) {
|
|
std::string name;
|
|
trunks::Serialize_TPM_HANDLE(handle, &name);
|
|
return name;
|
|
}
|
|
|
|
std::string HashString(const std::string& plaintext,
|
|
trunks::TPM_ALG_ID hash_alg) {
|
|
switch (hash_alg) {
|
|
case trunks::TPM_ALG_SHA1:
|
|
return base::SHA1HashString(plaintext);
|
|
case trunks::TPM_ALG_SHA256:
|
|
return crypto::SHA256HashString(plaintext);
|
|
}
|
|
NOTREACHED();
|
|
return std::string();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace trunks {
|
|
|
|
TpmUtilityImpl::TpmUtilityImpl(const TrunksFactory& factory)
|
|
: factory_(factory) {
|
|
crypto::EnsureOpenSSLInit();
|
|
}
|
|
|
|
TpmUtilityImpl::~TpmUtilityImpl() {}
|
|
|
|
TPM_RC TpmUtilityImpl::Startup() {
|
|
TPM_RC result = TPM_RC_SUCCESS;
|
|
Tpm* tpm = factory_.GetTpm();
|
|
result = tpm->StartupSync(TPM_SU_CLEAR, nullptr);
|
|
// Ignore TPM_RC_INITIALIZE, that means it was already started.
|
|
if (result && result != TPM_RC_INITIALIZE) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
result = tpm->SelfTestSync(YES /* Full test. */, nullptr);
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::Clear() {
|
|
TPM_RC result = TPM_RC_SUCCESS;
|
|
std::unique_ptr<AuthorizationDelegate> password_delegate(
|
|
factory_.GetPasswordAuthorization(""));
|
|
result = factory_.GetTpm()->ClearSync(TPM_RH_PLATFORM,
|
|
NameFromHandle(TPM_RH_PLATFORM),
|
|
password_delegate.get());
|
|
// If there was an error in the initialization, platform auth is in a bad
|
|
// state.
|
|
if (result == TPM_RC_AUTH_MISSING) {
|
|
std::unique_ptr<AuthorizationDelegate> authorization(
|
|
factory_.GetPasswordAuthorization(kPlatformPassword));
|
|
result = factory_.GetTpm()->ClearSync(
|
|
TPM_RH_PLATFORM, NameFromHandle(TPM_RH_PLATFORM), authorization.get());
|
|
}
|
|
if (GetFormatOneError(result) == TPM_RC_BAD_AUTH) {
|
|
LOG(INFO) << __func__
|
|
<< ": Clear failed because of BAD_AUTH. This probably means "
|
|
<< "that the TPM was already initialized.";
|
|
return result;
|
|
}
|
|
if (result) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Failed to clear the TPM: " << GetErrorString(result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void TpmUtilityImpl::Shutdown() {
|
|
TPM_RC return_code = factory_.GetTpm()->ShutdownSync(TPM_SU_CLEAR, nullptr);
|
|
if (return_code && return_code != TPM_RC_INITIALIZE) {
|
|
// This should not happen, but if it does, there is nothing we can do.
|
|
LOG(ERROR) << __func__
|
|
<< ": Error shutting down: " << GetErrorString(return_code);
|
|
}
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::InitializeTpm() {
|
|
TPM_RC result = TPM_RC_SUCCESS;
|
|
std::unique_ptr<TpmState> tpm_state(factory_.GetTpmState());
|
|
result = tpm_state->Initialize();
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
// Warn about various unexpected conditions.
|
|
if (!tpm_state->WasShutdownOrderly()) {
|
|
LOG(WARNING) << __func__
|
|
<< ": WARNING: The last TPM shutdown was not orderly.";
|
|
}
|
|
if (tpm_state->IsInLockout()) {
|
|
LOG(WARNING) << __func__ << ": WARNING: The TPM is currently in lockout.";
|
|
}
|
|
|
|
// We expect the firmware has already locked down the platform hierarchy. If
|
|
// it hasn't, do it now.
|
|
if (tpm_state->IsPlatformHierarchyEnabled()) {
|
|
std::unique_ptr<AuthorizationDelegate> empty_password(
|
|
factory_.GetPasswordAuthorization(""));
|
|
result = SetHierarchyAuthorization(TPM_RH_PLATFORM, kPlatformPassword,
|
|
empty_password.get());
|
|
if (GetFormatOneError(result) == TPM_RC_BAD_AUTH) {
|
|
// Most likely the platform password has already been set.
|
|
result = TPM_RC_SUCCESS;
|
|
}
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
result = AllocatePCR(kPlatformPassword);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::unique_ptr<AuthorizationDelegate> authorization(
|
|
factory_.GetPasswordAuthorization(kPlatformPassword));
|
|
result = DisablePlatformHierarchy(authorization.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::AllocatePCR(const std::string& platform_password) {
|
|
TPM_RC result;
|
|
TPMI_YES_NO more_data = YES;
|
|
TPMS_CAPABILITY_DATA capability_data;
|
|
result = factory_.GetTpm()->GetCapabilitySync(
|
|
TPM_CAP_PCRS, 0 /*property (not used)*/, 1 /*property_count*/, &more_data,
|
|
&capability_data, nullptr /*authorization_delegate*/);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error querying PCRs: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPML_PCR_SELECTION& existing_pcrs = capability_data.data.assigned_pcr;
|
|
bool sha256_needed = true;
|
|
std::vector<TPMI_ALG_HASH> pcr_banks_to_remove;
|
|
for (uint32_t i = 0; i < existing_pcrs.count; ++i) {
|
|
if (existing_pcrs.pcr_selections[i].hash == TPM_ALG_SHA256) {
|
|
sha256_needed = false;
|
|
} else {
|
|
pcr_banks_to_remove.push_back(existing_pcrs.pcr_selections[i].hash);
|
|
}
|
|
}
|
|
if (!sha256_needed && pcr_banks_to_remove.empty()) {
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
TPML_PCR_SELECTION pcr_allocation;
|
|
memset(&pcr_allocation, 0, sizeof(pcr_allocation));
|
|
if (sha256_needed) {
|
|
pcr_allocation.pcr_selections[pcr_allocation.count].hash = TPM_ALG_SHA256;
|
|
pcr_allocation.pcr_selections[pcr_allocation.count].sizeof_select =
|
|
PCR_SELECT_MIN;
|
|
for (int i = 0; i < PCR_SELECT_MIN; ++i) {
|
|
pcr_allocation.pcr_selections[pcr_allocation.count].pcr_select[i] = 0xff;
|
|
}
|
|
++pcr_allocation.count;
|
|
}
|
|
for (auto pcr_type : pcr_banks_to_remove) {
|
|
pcr_allocation.pcr_selections[pcr_allocation.count].hash = pcr_type;
|
|
pcr_allocation.pcr_selections[pcr_allocation.count].sizeof_select =
|
|
PCR_SELECT_MAX;
|
|
++pcr_allocation.count;
|
|
}
|
|
std::unique_ptr<AuthorizationDelegate> platform_delegate(
|
|
factory_.GetPasswordAuthorization(platform_password));
|
|
TPMI_YES_NO allocation_success;
|
|
uint32_t max_pcr;
|
|
uint32_t size_needed;
|
|
uint32_t size_available;
|
|
result = factory_.GetTpm()->PCR_AllocateSync(
|
|
TPM_RH_PLATFORM, NameFromHandle(TPM_RH_PLATFORM), pcr_allocation,
|
|
&allocation_success, &max_pcr, &size_needed, &size_available,
|
|
platform_delegate.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error allocating PCRs: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (allocation_success != YES) {
|
|
LOG(ERROR) << __func__ << ": PCR allocation unsuccessful.";
|
|
return TPM_RC_FAILURE;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::TakeOwnership(const std::string& owner_password,
|
|
const std::string& endorsement_password,
|
|
const std::string& lockout_password) {
|
|
// First we set the storage hierarchy authorization to the well know default
|
|
// password.
|
|
TPM_RC result = TPM_RC_SUCCESS;
|
|
result = SetKnownOwnerPassword(kWellKnownPassword);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error injecting known password: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
|
|
result = CreateStorageRootKeys(kWellKnownPassword);
|
|
if (result) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error creating SRKs: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
result = CreateSaltingKey(kWellKnownPassword);
|
|
if (result) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error creating salting key: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
|
|
std::unique_ptr<HmacSession> session = factory_.GetHmacSession();
|
|
result = session->StartUnboundSession(true);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error initializing AuthorizationSession: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::unique_ptr<TpmState> tpm_state(factory_.GetTpmState());
|
|
result = tpm_state->Initialize();
|
|
session->SetEntityAuthorizationValue("");
|
|
session->SetFutureAuthorizationValue(endorsement_password);
|
|
if (!tpm_state->IsEndorsementPasswordSet()) {
|
|
result = SetHierarchyAuthorization(TPM_RH_ENDORSEMENT, endorsement_password,
|
|
session->GetDelegate());
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
}
|
|
session->SetFutureAuthorizationValue(lockout_password);
|
|
if (!tpm_state->IsLockoutPasswordSet()) {
|
|
result = SetHierarchyAuthorization(TPM_RH_LOCKOUT, lockout_password,
|
|
session->GetDelegate());
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
}
|
|
// We take ownership of owner hierarchy last.
|
|
session->SetEntityAuthorizationValue(kWellKnownPassword);
|
|
session->SetFutureAuthorizationValue(owner_password);
|
|
result = SetHierarchyAuthorization(TPM_RH_OWNER, owner_password,
|
|
session->GetDelegate());
|
|
if ((GetFormatOneError(result) == TPM_RC_BAD_AUTH) &&
|
|
tpm_state->IsOwnerPasswordSet()) {
|
|
LOG(WARNING) << __func__
|
|
<< ": Error changing owner password. This probably because "
|
|
<< "ownership is already taken.";
|
|
return TPM_RC_SUCCESS;
|
|
} else if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error changing owner authorization: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::StirRandom(const std::string& entropy_data,
|
|
AuthorizationDelegate* delegate) {
|
|
std::string digest = crypto::SHA256HashString(entropy_data);
|
|
TPM2B_SENSITIVE_DATA random_bytes = Make_TPM2B_SENSITIVE_DATA(digest);
|
|
return factory_.GetTpm()->StirRandomSync(random_bytes, delegate);
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::GenerateRandom(size_t num_bytes,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* random_data) {
|
|
CHECK(random_data);
|
|
size_t bytes_left = num_bytes;
|
|
random_data->clear();
|
|
TPM_RC rc;
|
|
TPM2B_DIGEST digest;
|
|
while (bytes_left > 0) {
|
|
rc = factory_.GetTpm()->GetRandomSync(bytes_left, &digest, delegate);
|
|
if (rc) {
|
|
LOG(ERROR) << __func__ << ": Error getting random data from tpm.";
|
|
return rc;
|
|
}
|
|
random_data->append(StringFrom_TPM2B_DIGEST(digest));
|
|
bytes_left -= digest.size;
|
|
}
|
|
CHECK_EQ(random_data->size(), num_bytes);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ExtendPCR(int pcr_index,
|
|
const std::string& extend_data,
|
|
AuthorizationDelegate* delegate) {
|
|
if (pcr_index < 0 || pcr_index >= IMPLEMENTATION_PCR) {
|
|
LOG(ERROR) << __func__ << ": Using a PCR index that isn't implemented.";
|
|
return TPM_RC_FAILURE;
|
|
}
|
|
TPM_HANDLE pcr_handle = HR_PCR + pcr_index;
|
|
std::string pcr_name = NameFromHandle(pcr_handle);
|
|
TPML_DIGEST_VALUES digests;
|
|
digests.count = 1;
|
|
digests.digests[0].hash_alg = TPM_ALG_SHA256;
|
|
crypto::SHA256HashString(extend_data, digests.digests[0].digest.sha256,
|
|
crypto::kSHA256Length);
|
|
std::unique_ptr<AuthorizationDelegate> empty_password_delegate =
|
|
factory_.GetPasswordAuthorization("");
|
|
if (!delegate) {
|
|
delegate = empty_password_delegate.get();
|
|
}
|
|
return factory_.GetTpm()->PCR_ExtendSync(pcr_handle, pcr_name, digests,
|
|
delegate);
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ReadPCR(int pcr_index, std::string* pcr_value) {
|
|
TPML_PCR_SELECTION pcr_select_in;
|
|
uint32_t pcr_update_counter;
|
|
TPML_PCR_SELECTION pcr_select_out;
|
|
TPML_DIGEST pcr_values;
|
|
// This process of selecting pcrs is highlighted in TPM 2.0 Library Spec
|
|
// Part 2 (Section 10.5 - PCR structures).
|
|
uint8_t pcr_select_index = pcr_index / 8;
|
|
uint8_t pcr_select_byte = 1 << (pcr_index % 8);
|
|
pcr_select_in.count = 1;
|
|
pcr_select_in.pcr_selections[0].hash = TPM_ALG_SHA256;
|
|
pcr_select_in.pcr_selections[0].sizeof_select = PCR_SELECT_MIN;
|
|
pcr_select_in.pcr_selections[0].pcr_select[pcr_select_index] =
|
|
pcr_select_byte;
|
|
|
|
TPM_RC rc =
|
|
factory_.GetTpm()->PCR_ReadSync(pcr_select_in, &pcr_update_counter,
|
|
&pcr_select_out, &pcr_values, nullptr);
|
|
if (rc) {
|
|
LOG(INFO) << __func__
|
|
<< ": Error trying to read a pcr: " << GetErrorString(rc);
|
|
return rc;
|
|
}
|
|
if (pcr_select_out.count != 1 ||
|
|
pcr_select_out.pcr_selections[0].sizeof_select < (pcr_select_index + 1) ||
|
|
pcr_select_out.pcr_selections[0].pcr_select[pcr_select_index] !=
|
|
pcr_select_byte) {
|
|
LOG(ERROR) << __func__ << ": TPM did not return the requested PCR";
|
|
return TPM_RC_FAILURE;
|
|
}
|
|
CHECK_GE(pcr_values.count, 1U);
|
|
pcr_value->assign(StringFrom_TPM2B_DIGEST(pcr_values.digests[0]));
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::AsymmetricEncrypt(TPM_HANDLE key_handle,
|
|
TPM_ALG_ID scheme,
|
|
TPM_ALG_ID hash_alg,
|
|
const std::string& plaintext,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* ciphertext) {
|
|
TPMT_RSA_DECRYPT in_scheme;
|
|
if (hash_alg == TPM_ALG_NULL) {
|
|
hash_alg = TPM_ALG_SHA256;
|
|
}
|
|
if (scheme == TPM_ALG_RSAES) {
|
|
in_scheme.scheme = TPM_ALG_RSAES;
|
|
} else if (scheme == TPM_ALG_OAEP || scheme == TPM_ALG_NULL) {
|
|
in_scheme.scheme = TPM_ALG_OAEP;
|
|
in_scheme.details.oaep.hash_alg = hash_alg;
|
|
} else {
|
|
LOG(ERROR) << __func__ << ": Invalid Signing scheme used.";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
|
|
TPMT_PUBLIC public_area;
|
|
TPM_RC result = GetKeyPublicArea(key_handle, &public_area);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error finding public area for: " << key_handle;
|
|
return result;
|
|
} else if (public_area.type != TPM_ALG_RSA) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not an RSA key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
} else if ((public_area.object_attributes & kDecrypt) == 0) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not a decryption key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
if ((public_area.object_attributes & kRestricted) != 0) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot use RSAES for encryption with a restricted key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
std::string key_name;
|
|
result = ComputeKeyName(public_area, &key_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error computing key name for: " << key_handle;
|
|
return result;
|
|
}
|
|
|
|
TPM2B_DATA label;
|
|
label.size = 0;
|
|
TPM2B_PUBLIC_KEY_RSA in_message = Make_TPM2B_PUBLIC_KEY_RSA(plaintext);
|
|
TPM2B_PUBLIC_KEY_RSA out_message;
|
|
result = factory_.GetTpm()->RSA_EncryptSync(key_handle, key_name, in_message,
|
|
in_scheme, label, &out_message,
|
|
delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error performing RSA encrypt: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
ciphertext->assign(StringFrom_TPM2B_PUBLIC_KEY_RSA(out_message));
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::AsymmetricDecrypt(TPM_HANDLE key_handle,
|
|
TPM_ALG_ID scheme,
|
|
TPM_ALG_ID hash_alg,
|
|
const std::string& ciphertext,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* plaintext) {
|
|
TPMT_RSA_DECRYPT in_scheme;
|
|
if (hash_alg == TPM_ALG_NULL) {
|
|
hash_alg = TPM_ALG_SHA256;
|
|
}
|
|
if (scheme == TPM_ALG_RSAES) {
|
|
in_scheme.scheme = TPM_ALG_RSAES;
|
|
} else if (scheme == TPM_ALG_OAEP || scheme == TPM_ALG_NULL) {
|
|
in_scheme.scheme = TPM_ALG_OAEP;
|
|
in_scheme.details.oaep.hash_alg = hash_alg;
|
|
} else {
|
|
LOG(ERROR) << __func__ << ": Invalid Signing scheme used.";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPMT_PUBLIC public_area;
|
|
result = GetKeyPublicArea(key_handle, &public_area);
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": Error finding public area for: " << key_handle;
|
|
return result;
|
|
} else if (public_area.type != TPM_ALG_RSA) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not an RSA key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
} else if ((public_area.object_attributes & kDecrypt) == 0) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not a decryption key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
if ((public_area.object_attributes & kRestricted) != 0) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot use RSAES for encryption with a restricted key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
std::string key_name;
|
|
result = ComputeKeyName(public_area, &key_name);
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": Error computing key name for: " << key_handle;
|
|
return result;
|
|
}
|
|
|
|
TPM2B_DATA label;
|
|
label.size = 0;
|
|
TPM2B_PUBLIC_KEY_RSA in_message = Make_TPM2B_PUBLIC_KEY_RSA(ciphertext);
|
|
TPM2B_PUBLIC_KEY_RSA out_message;
|
|
result = factory_.GetTpm()->RSA_DecryptSync(key_handle, key_name, in_message,
|
|
in_scheme, label, &out_message,
|
|
delegate);
|
|
if (result) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error performing RSA decrypt: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
plaintext->assign(StringFrom_TPM2B_PUBLIC_KEY_RSA(out_message));
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::Sign(TPM_HANDLE key_handle,
|
|
TPM_ALG_ID scheme,
|
|
TPM_ALG_ID hash_alg,
|
|
const std::string& plaintext,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* signature) {
|
|
TPMT_SIG_SCHEME in_scheme;
|
|
if (hash_alg == TPM_ALG_NULL) {
|
|
hash_alg = TPM_ALG_SHA256;
|
|
}
|
|
if (scheme == TPM_ALG_RSAPSS) {
|
|
in_scheme.scheme = TPM_ALG_RSAPSS;
|
|
in_scheme.details.rsapss.hash_alg = hash_alg;
|
|
} else if (scheme == TPM_ALG_RSASSA || scheme == TPM_ALG_NULL) {
|
|
in_scheme.scheme = TPM_ALG_RSASSA;
|
|
in_scheme.details.rsassa.hash_alg = hash_alg;
|
|
} else {
|
|
LOG(ERROR) << __func__ << ": Invalid Signing scheme used.";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPMT_PUBLIC public_area;
|
|
result = GetKeyPublicArea(key_handle, &public_area);
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": Error finding public area for: " << key_handle;
|
|
return result;
|
|
} else if (public_area.type != TPM_ALG_RSA) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not an RSA key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
} else if ((public_area.object_attributes & kSign) == 0) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not a signging key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
} else if ((public_area.object_attributes & kRestricted) != 0) {
|
|
LOG(ERROR) << __func__ << ": Key handle references a restricted key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
|
|
std::string key_name;
|
|
result = ComputeKeyName(public_area, &key_name);
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": Error computing key name for: " << key_handle;
|
|
return result;
|
|
}
|
|
std::string digest = HashString(plaintext, hash_alg);
|
|
TPM2B_DIGEST tpm_digest = Make_TPM2B_DIGEST(digest);
|
|
TPMT_SIGNATURE signature_out;
|
|
TPMT_TK_HASHCHECK validation;
|
|
validation.tag = TPM_ST_HASHCHECK;
|
|
validation.hierarchy = TPM_RH_NULL;
|
|
validation.digest.size = 0;
|
|
result =
|
|
factory_.GetTpm()->SignSync(key_handle, key_name, tpm_digest, in_scheme,
|
|
validation, &signature_out, delegate);
|
|
if (result) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error signing digest: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (scheme == TPM_ALG_RSAPSS) {
|
|
signature->resize(signature_out.signature.rsapss.sig.size);
|
|
signature->assign(
|
|
StringFrom_TPM2B_PUBLIC_KEY_RSA(signature_out.signature.rsapss.sig));
|
|
} else {
|
|
signature->resize(signature_out.signature.rsassa.sig.size);
|
|
signature->assign(
|
|
StringFrom_TPM2B_PUBLIC_KEY_RSA(signature_out.signature.rsassa.sig));
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::Verify(TPM_HANDLE key_handle,
|
|
TPM_ALG_ID scheme,
|
|
TPM_ALG_ID hash_alg,
|
|
const std::string& plaintext,
|
|
const std::string& signature,
|
|
AuthorizationDelegate* delegate) {
|
|
TPMT_PUBLIC public_area;
|
|
TPM_RC return_code = GetKeyPublicArea(key_handle, &public_area);
|
|
if (return_code) {
|
|
LOG(ERROR) << __func__ << ": Error finding public area for: " << key_handle;
|
|
return return_code;
|
|
} else if (public_area.type != TPM_ALG_RSA) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not an RSA key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
} else if ((public_area.object_attributes & kSign) == 0) {
|
|
LOG(ERROR) << __func__ << ": Key handle given is not a signing key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
} else if ((public_area.object_attributes & kRestricted) != 0) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot use RSAPSS for signing with a restricted key";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
if (hash_alg == TPM_ALG_NULL) {
|
|
hash_alg = TPM_ALG_SHA256;
|
|
}
|
|
|
|
TPMT_SIGNATURE signature_in;
|
|
if (scheme == TPM_ALG_RSAPSS) {
|
|
signature_in.sig_alg = TPM_ALG_RSAPSS;
|
|
signature_in.signature.rsapss.hash = hash_alg;
|
|
signature_in.signature.rsapss.sig = Make_TPM2B_PUBLIC_KEY_RSA(signature);
|
|
} else if (scheme == TPM_ALG_NULL || scheme == TPM_ALG_RSASSA) {
|
|
signature_in.sig_alg = TPM_ALG_RSASSA;
|
|
signature_in.signature.rsassa.hash = hash_alg;
|
|
signature_in.signature.rsassa.sig = Make_TPM2B_PUBLIC_KEY_RSA(signature);
|
|
} else {
|
|
LOG(ERROR) << __func__ << ": Invalid scheme used to verify signature.";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
std::string key_name;
|
|
TPMT_TK_VERIFIED verified;
|
|
std::string digest = HashString(plaintext, hash_alg);
|
|
TPM2B_DIGEST tpm_digest = Make_TPM2B_DIGEST(digest);
|
|
return_code = factory_.GetTpm()->VerifySignatureSync(
|
|
key_handle, key_name, tpm_digest, signature_in, &verified, delegate);
|
|
if (return_code == TPM_RC_SIGNATURE) {
|
|
LOG(WARNING) << __func__ << ": Incorrect signature for given digest.";
|
|
return TPM_RC_SIGNATURE;
|
|
} else if (return_code && return_code != TPM_RC_SIGNATURE) {
|
|
LOG(ERROR) << __func__ << ": Error verifying signature: "
|
|
<< GetErrorString(return_code);
|
|
return return_code;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::CertifyCreation(TPM_HANDLE key_handle,
|
|
const std::string& creation_blob) {
|
|
TPM2B_CREATION_DATA creation_data;
|
|
TPM2B_DIGEST creation_hash;
|
|
TPMT_TK_CREATION creation_ticket;
|
|
if (!factory_.GetBlobParser()->ParseCreationBlob(
|
|
creation_blob, &creation_data, &creation_hash, &creation_ticket)) {
|
|
LOG(ERROR) << __func__ << ": Error parsing CreationBlob.";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
}
|
|
TPM2B_DATA qualifying_data;
|
|
qualifying_data.size = 0;
|
|
TPMT_SIG_SCHEME in_scheme;
|
|
in_scheme.scheme = TPM_ALG_NULL;
|
|
TPM2B_ATTEST certify_info;
|
|
TPMT_SIGNATURE signature;
|
|
std::unique_ptr<AuthorizationDelegate> delegate =
|
|
factory_.GetPasswordAuthorization("");
|
|
TPM_RC result = factory_.GetTpm()->CertifyCreationSync(
|
|
TPM_RH_NULL, "", key_handle, "", qualifying_data, creation_hash,
|
|
in_scheme, creation_ticket, &certify_info, &signature, delegate.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error certifying key creation: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ChangeKeyAuthorizationData(
|
|
TPM_HANDLE key_handle,
|
|
const std::string& new_password,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* key_blob) {
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string key_name;
|
|
std::string parent_name;
|
|
result = GetKeyName(key_handle, &key_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error getting Key name for key_handle: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
result = GetKeyName(kRSAStorageRootKey, &parent_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error getting Key name for RSA-SRK: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPM2B_AUTH new_auth = Make_TPM2B_DIGEST(new_password);
|
|
TPM2B_PRIVATE new_private_data;
|
|
new_private_data.size = 0;
|
|
result = factory_.GetTpm()->ObjectChangeAuthSync(
|
|
key_handle, key_name, kRSAStorageRootKey, parent_name, new_auth,
|
|
&new_private_data, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error changing object authorization data: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (key_blob) {
|
|
TPMT_PUBLIC public_data;
|
|
result = GetKeyPublicArea(key_handle, &public_data);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
if (!factory_.GetBlobParser()->SerializeKeyBlob(
|
|
Make_TPM2B_PUBLIC(public_data), new_private_data, key_blob)) {
|
|
return SAPI_RC_BAD_TCTI_STRUCTURE;
|
|
}
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ImportRSAKey(AsymmetricKeyUsage key_type,
|
|
const std::string& modulus,
|
|
uint32_t public_exponent,
|
|
const std::string& prime_factor,
|
|
const std::string& password,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* key_blob) {
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string parent_name;
|
|
result = GetKeyName(kRSAStorageRootKey, &parent_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error getting Key name for RSA-SRK: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA);
|
|
public_area.object_attributes = kUserWithAuth | kNoDA;
|
|
switch (key_type) {
|
|
case AsymmetricKeyUsage::kDecryptKey:
|
|
public_area.object_attributes |= kDecrypt;
|
|
break;
|
|
case AsymmetricKeyUsage::kSignKey:
|
|
public_area.object_attributes |= kSign;
|
|
break;
|
|
case AsymmetricKeyUsage::kDecryptAndSignKey:
|
|
public_area.object_attributes |= (kSign | kDecrypt);
|
|
break;
|
|
}
|
|
public_area.parameters.rsa_detail.key_bits = modulus.size() * 8;
|
|
public_area.parameters.rsa_detail.exponent = public_exponent;
|
|
public_area.unique.rsa = Make_TPM2B_PUBLIC_KEY_RSA(modulus);
|
|
TPM2B_DATA encryption_key;
|
|
encryption_key.size = kAesKeySize;
|
|
CHECK_EQ(RAND_bytes(encryption_key.buffer, encryption_key.size), 1)
|
|
<< "Error generating a cryptographically random Aes Key.";
|
|
TPM2B_PUBLIC public_data = Make_TPM2B_PUBLIC(public_area);
|
|
TPM2B_ENCRYPTED_SECRET in_sym_seed = Make_TPM2B_ENCRYPTED_SECRET("");
|
|
TPMT_SYM_DEF_OBJECT symmetric_alg;
|
|
symmetric_alg.algorithm = TPM_ALG_AES;
|
|
symmetric_alg.key_bits.aes = kAesKeySize * 8;
|
|
symmetric_alg.mode.aes = TPM_ALG_CFB;
|
|
TPMT_SENSITIVE in_sensitive;
|
|
in_sensitive.sensitive_type = TPM_ALG_RSA;
|
|
in_sensitive.auth_value = Make_TPM2B_DIGEST(password);
|
|
in_sensitive.seed_value = Make_TPM2B_DIGEST("");
|
|
in_sensitive.sensitive.rsa = Make_TPM2B_PRIVATE_KEY_RSA(prime_factor);
|
|
TPM2B_PRIVATE private_data;
|
|
result = EncryptPrivateData(in_sensitive, public_area, &private_data,
|
|
&encryption_key);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error creating encrypted private struct: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPM2B_PRIVATE tpm_private_data;
|
|
tpm_private_data.size = 0;
|
|
result = factory_.GetTpm()->ImportSync(
|
|
kRSAStorageRootKey, parent_name, encryption_key, public_data,
|
|
private_data, in_sym_seed, symmetric_alg, &tpm_private_data, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error importing key: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (key_blob) {
|
|
if (!factory_.GetBlobParser()->SerializeKeyBlob(
|
|
public_data, tpm_private_data, key_blob)) {
|
|
return SAPI_RC_BAD_TCTI_STRUCTURE;
|
|
}
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::CreateRSAKeyPair(AsymmetricKeyUsage key_type,
|
|
int modulus_bits,
|
|
uint32_t public_exponent,
|
|
const std::string& password,
|
|
const std::string& policy_digest,
|
|
bool use_only_policy_authorization,
|
|
int creation_pcr_index,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* key_blob,
|
|
std::string* creation_blob) {
|
|
CHECK(key_blob);
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string parent_name;
|
|
result = GetKeyName(kRSAStorageRootKey, &parent_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error getting Key name for RSA-SRK: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA);
|
|
public_area.auth_policy = Make_TPM2B_DIGEST(policy_digest);
|
|
public_area.object_attributes |=
|
|
(kSensitiveDataOrigin | kUserWithAuth | kNoDA);
|
|
switch (key_type) {
|
|
case AsymmetricKeyUsage::kDecryptKey:
|
|
public_area.object_attributes |= kDecrypt;
|
|
break;
|
|
case AsymmetricKeyUsage::kSignKey:
|
|
public_area.object_attributes |= kSign;
|
|
break;
|
|
case AsymmetricKeyUsage::kDecryptAndSignKey:
|
|
public_area.object_attributes |= (kSign | kDecrypt);
|
|
break;
|
|
}
|
|
if (use_only_policy_authorization && !policy_digest.empty()) {
|
|
public_area.object_attributes |= kAdminWithPolicy;
|
|
public_area.object_attributes &= (~kUserWithAuth);
|
|
}
|
|
public_area.parameters.rsa_detail.key_bits = modulus_bits;
|
|
public_area.parameters.rsa_detail.exponent = public_exponent;
|
|
TPML_PCR_SELECTION creation_pcrs = {};
|
|
if (creation_pcr_index == kNoCreationPCR) {
|
|
creation_pcrs.count = 0;
|
|
} else if (creation_pcr_index < 0 ||
|
|
creation_pcr_index > (PCR_SELECT_MIN * 8)) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Creation PCR index is not within the allocated bank.";
|
|
return SAPI_RC_BAD_PARAMETER;
|
|
} else {
|
|
creation_pcrs.count = 1;
|
|
creation_pcrs.pcr_selections[0].hash = TPM_ALG_SHA256;
|
|
creation_pcrs.pcr_selections[0].sizeof_select = PCR_SELECT_MIN;
|
|
creation_pcrs.pcr_selections[0].pcr_select[creation_pcr_index / 8] =
|
|
1 << (creation_pcr_index % 8);
|
|
}
|
|
TPMS_SENSITIVE_CREATE sensitive;
|
|
sensitive.user_auth = Make_TPM2B_DIGEST(password);
|
|
sensitive.data = Make_TPM2B_SENSITIVE_DATA("");
|
|
TPM2B_SENSITIVE_CREATE sensitive_create =
|
|
Make_TPM2B_SENSITIVE_CREATE(sensitive);
|
|
TPM2B_DATA outside_info = Make_TPM2B_DATA("");
|
|
TPM2B_PUBLIC out_public;
|
|
out_public.size = 0;
|
|
TPM2B_PRIVATE out_private;
|
|
out_private.size = 0;
|
|
TPM2B_CREATION_DATA creation_data;
|
|
TPM2B_DIGEST creation_hash;
|
|
TPMT_TK_CREATION creation_ticket;
|
|
result = factory_.GetTpm()->CreateSync(
|
|
kRSAStorageRootKey, parent_name, sensitive_create,
|
|
Make_TPM2B_PUBLIC(public_area), outside_info, creation_pcrs, &out_private,
|
|
&out_public, &creation_data, &creation_hash, &creation_ticket, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error creating RSA key: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (!factory_.GetBlobParser()->SerializeKeyBlob(out_public, out_private,
|
|
key_blob)) {
|
|
return SAPI_RC_BAD_TCTI_STRUCTURE;
|
|
}
|
|
if (creation_blob) {
|
|
if (!factory_.GetBlobParser()->SerializeCreationBlob(
|
|
creation_data, creation_hash, creation_ticket, creation_blob)) {
|
|
return SAPI_RC_BAD_TCTI_STRUCTURE;
|
|
}
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::LoadKey(const std::string& key_blob,
|
|
AuthorizationDelegate* delegate,
|
|
TPM_HANDLE* key_handle) {
|
|
CHECK(key_handle);
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string parent_name;
|
|
result = GetKeyName(kRSAStorageRootKey, &parent_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error getting parent key name: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPM2B_PUBLIC in_public;
|
|
TPM2B_PRIVATE in_private;
|
|
if (!factory_.GetBlobParser()->ParseKeyBlob(key_blob, &in_public,
|
|
&in_private)) {
|
|
return SAPI_RC_BAD_TCTI_STRUCTURE;
|
|
}
|
|
TPM2B_NAME key_name;
|
|
key_name.size = 0;
|
|
result =
|
|
factory_.GetTpm()->LoadSync(kRSAStorageRootKey, parent_name, in_private,
|
|
in_public, key_handle, &key_name, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error loading key: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::GetKeyName(TPM_HANDLE handle, std::string* name) {
|
|
CHECK(name);
|
|
TPM_RC result;
|
|
TPMT_PUBLIC public_data;
|
|
result = GetKeyPublicArea(handle, &public_data);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error fetching public info: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
result = ComputeKeyName(public_data, name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error computing key name: " << GetErrorString(result);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::GetKeyPublicArea(TPM_HANDLE handle,
|
|
TPMT_PUBLIC* public_data) {
|
|
CHECK(public_data);
|
|
TPM2B_NAME out_name;
|
|
TPM2B_PUBLIC public_area;
|
|
TPM2B_NAME qualified_name;
|
|
std::string handle_name; // Unused
|
|
TPM_RC return_code = factory_.GetTpm()->ReadPublicSync(
|
|
handle, handle_name, &public_area, &out_name, &qualified_name, nullptr);
|
|
if (return_code) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error getting public area for object: " << handle;
|
|
return return_code;
|
|
}
|
|
*public_data = public_area.public_area;
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::SealData(const std::string& data_to_seal,
|
|
const std::string& policy_digest,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* sealed_data) {
|
|
CHECK(sealed_data);
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string parent_name;
|
|
result = GetKeyName(kRSAStorageRootKey, &parent_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error getting Key name for RSA-SRK: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
// We seal data to the TPM by creating a KEYEDHASH object with sign and
|
|
// decrypt attributes disabled.
|
|
TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_KEYEDHASH);
|
|
public_area.auth_policy = Make_TPM2B_DIGEST(policy_digest);
|
|
public_area.object_attributes = kAdminWithPolicy | kNoDA;
|
|
public_area.unique.keyed_hash.size = 0;
|
|
TPML_PCR_SELECTION creation_pcrs = {};
|
|
TPMS_SENSITIVE_CREATE sensitive;
|
|
sensitive.user_auth = Make_TPM2B_DIGEST("");
|
|
sensitive.data = Make_TPM2B_SENSITIVE_DATA(data_to_seal);
|
|
TPM2B_SENSITIVE_CREATE sensitive_create =
|
|
Make_TPM2B_SENSITIVE_CREATE(sensitive);
|
|
TPM2B_DATA outside_info = Make_TPM2B_DATA("");
|
|
TPM2B_PUBLIC out_public;
|
|
out_public.size = 0;
|
|
TPM2B_PRIVATE out_private;
|
|
out_private.size = 0;
|
|
TPM2B_CREATION_DATA creation_data;
|
|
TPM2B_DIGEST creation_hash;
|
|
TPMT_TK_CREATION creation_ticket;
|
|
result = factory_.GetTpm()->CreateSync(
|
|
kRSAStorageRootKey, parent_name, sensitive_create,
|
|
Make_TPM2B_PUBLIC(public_area), outside_info, creation_pcrs, &out_private,
|
|
&out_public, &creation_data, &creation_hash, &creation_ticket, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error creating sealed object: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (!factory_.GetBlobParser()->SerializeKeyBlob(out_public, out_private,
|
|
sealed_data)) {
|
|
return SAPI_RC_BAD_TCTI_STRUCTURE;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::UnsealData(const std::string& sealed_data,
|
|
AuthorizationDelegate* delegate,
|
|
std::string* unsealed_data) {
|
|
CHECK(unsealed_data);
|
|
TPM_RC result;
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPM_HANDLE object_handle;
|
|
std::unique_ptr<AuthorizationDelegate> password_delegate =
|
|
factory_.GetPasswordAuthorization("");
|
|
result = LoadKey(sealed_data, password_delegate.get(), &object_handle);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error loading sealed object: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
ScopedKeyHandle sealed_object(factory_, object_handle);
|
|
std::string object_name;
|
|
result = GetKeyName(sealed_object.get(), &object_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error getting object name: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPM2B_SENSITIVE_DATA out_data;
|
|
result = factory_.GetTpm()->UnsealSync(sealed_object.get(), object_name,
|
|
&out_data, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error unsealing object: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
*unsealed_data = StringFrom_TPM2B_SENSITIVE_DATA(out_data);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::StartSession(HmacSession* session) {
|
|
TPM_RC result = session->StartUnboundSession(true /* enable_encryption */);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error starting unbound session: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
session->SetEntityAuthorizationValue("");
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::GetPolicyDigestForPcrValue(int pcr_index,
|
|
const std::string& pcr_value,
|
|
std::string* policy_digest) {
|
|
CHECK(policy_digest);
|
|
std::unique_ptr<PolicySession> session = factory_.GetTrialSession();
|
|
TPM_RC result = session->StartUnboundSession(false);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error starting unbound trial session: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string mutable_pcr_value;
|
|
if (pcr_value.empty()) {
|
|
result = ReadPCR(pcr_index, &mutable_pcr_value);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error reading pcr_value: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
} else {
|
|
mutable_pcr_value = pcr_value;
|
|
}
|
|
result = session->PolicyPCR(pcr_index, mutable_pcr_value);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error restricting policy to PCR value: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
result = session->GetDigest(policy_digest);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error getting policy digest: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::DefineNVSpace(uint32_t index,
|
|
size_t num_bytes,
|
|
TPMA_NV attributes,
|
|
const std::string& authorization_value,
|
|
const std::string& policy_digest,
|
|
AuthorizationDelegate* delegate) {
|
|
TPM_RC result;
|
|
if (num_bytes > MAX_NV_INDEX_SIZE) {
|
|
result = SAPI_RC_BAD_SIZE;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot define non-volatile space of given size: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (index > kMaxNVSpaceIndex) {
|
|
result = SAPI_RC_BAD_PARAMETER;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot define non-volatile space with the given index: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
uint32_t nv_index = NV_INDEX_FIRST + index;
|
|
TPMS_NV_PUBLIC public_data;
|
|
public_data.nv_index = nv_index;
|
|
public_data.name_alg = TPM_ALG_SHA256;
|
|
public_data.attributes = attributes;
|
|
public_data.auth_policy = Make_TPM2B_DIGEST(policy_digest);
|
|
public_data.data_size = num_bytes;
|
|
TPM2B_AUTH authorization = Make_TPM2B_DIGEST(authorization_value);
|
|
TPM2B_NV_PUBLIC public_area = Make_TPM2B_NV_PUBLIC(public_data);
|
|
result = factory_.GetTpm()->NV_DefineSpaceSync(
|
|
TPM_RH_OWNER, NameFromHandle(TPM_RH_OWNER), authorization, public_area,
|
|
delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error defining non-volatile space: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
nvram_public_area_map_[index] = public_data;
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::DestroyNVSpace(uint32_t index,
|
|
AuthorizationDelegate* delegate) {
|
|
TPM_RC result;
|
|
if (index > kMaxNVSpaceIndex) {
|
|
result = SAPI_RC_BAD_PARAMETER;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot undefine non-volatile space with the given index: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (delegate == nullptr) {
|
|
result = SAPI_RC_INVALID_SESSIONS;
|
|
LOG(ERROR) << __func__
|
|
<< ": This method needs a valid authorization delegate: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string nv_name;
|
|
result = GetNVSpaceName(index, &nv_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
uint32_t nv_index = NV_INDEX_FIRST + index;
|
|
result = factory_.GetTpm()->NV_UndefineSpaceSync(
|
|
TPM_RH_OWNER, NameFromHandle(TPM_RH_OWNER), nv_index, nv_name, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error undefining non-volatile space: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
nvram_public_area_map_.erase(index);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::LockNVSpace(uint32_t index,
|
|
bool lock_read,
|
|
bool lock_write,
|
|
bool using_owner_authorization,
|
|
AuthorizationDelegate* delegate) {
|
|
TPM_RC result;
|
|
if (index > kMaxNVSpaceIndex) {
|
|
result = SAPI_RC_BAD_PARAMETER;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot lock non-volatile space with the given index: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string nv_name;
|
|
result = GetNVSpaceName(index, &nv_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
uint32_t nv_index = NV_INDEX_FIRST + index;
|
|
TPMI_RH_NV_AUTH auth_target = nv_index;
|
|
std::string auth_target_name = nv_name;
|
|
if (using_owner_authorization) {
|
|
auth_target = TPM_RH_OWNER;
|
|
auth_target_name = NameFromHandle(TPM_RH_OWNER);
|
|
}
|
|
auto it = nvram_public_area_map_.find(index);
|
|
if (lock_read) {
|
|
result = factory_.GetTpm()->NV_ReadLockSync(auth_target, auth_target_name,
|
|
nv_index, nv_name, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error locking non-volatile space read: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (it != nvram_public_area_map_.end()) {
|
|
it->second.attributes |= TPMA_NV_READLOCKED;
|
|
}
|
|
}
|
|
if (lock_write) {
|
|
result = factory_.GetTpm()->NV_WriteLockSync(auth_target, auth_target_name,
|
|
nv_index, nv_name, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error locking non-volatile space write: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (it != nvram_public_area_map_.end()) {
|
|
it->second.attributes |= TPMA_NV_WRITELOCKED;
|
|
}
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::WriteNVSpace(uint32_t index,
|
|
uint32_t offset,
|
|
const std::string& nvram_data,
|
|
bool using_owner_authorization,
|
|
bool extend,
|
|
AuthorizationDelegate* delegate) {
|
|
TPM_RC result;
|
|
if (nvram_data.size() > MAX_NV_BUFFER_SIZE) {
|
|
result = SAPI_RC_BAD_SIZE;
|
|
LOG(ERROR) << __func__ << ": Insufficient buffer for non-volatile write: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (index > kMaxNVSpaceIndex) {
|
|
result = SAPI_RC_BAD_PARAMETER;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot write to non-volatile space with the given index: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string nv_name;
|
|
result = GetNVSpaceName(index, &nv_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
uint32_t nv_index = NV_INDEX_FIRST + index;
|
|
TPMI_RH_NV_AUTH auth_target = nv_index;
|
|
std::string auth_target_name = nv_name;
|
|
if (using_owner_authorization) {
|
|
auth_target = TPM_RH_OWNER;
|
|
auth_target_name = NameFromHandle(TPM_RH_OWNER);
|
|
}
|
|
if (extend) {
|
|
result = factory_.GetTpm()->NV_ExtendSync(
|
|
auth_target, auth_target_name, nv_index, nv_name,
|
|
Make_TPM2B_MAX_NV_BUFFER(nvram_data), delegate);
|
|
} else {
|
|
result = factory_.GetTpm()->NV_WriteSync(
|
|
auth_target, auth_target_name, nv_index, nv_name,
|
|
Make_TPM2B_MAX_NV_BUFFER(nvram_data), offset, delegate);
|
|
}
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error writing to non-volatile space: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
auto it = nvram_public_area_map_.find(index);
|
|
if (it != nvram_public_area_map_.end()) {
|
|
it->second.attributes |= TPMA_NV_WRITTEN;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ReadNVSpace(uint32_t index,
|
|
uint32_t offset,
|
|
size_t num_bytes,
|
|
bool using_owner_authorization,
|
|
std::string* nvram_data,
|
|
AuthorizationDelegate* delegate) {
|
|
TPM_RC result;
|
|
if (num_bytes > MAX_NV_BUFFER_SIZE) {
|
|
result = SAPI_RC_BAD_SIZE;
|
|
LOG(ERROR) << __func__ << ": Insufficient buffer for non-volatile read: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (index > kMaxNVSpaceIndex) {
|
|
result = SAPI_RC_BAD_PARAMETER;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot read from non-volatile space with the given index: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string nv_name;
|
|
result = GetNVSpaceName(index, &nv_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
uint32_t nv_index = NV_INDEX_FIRST + index;
|
|
TPMI_RH_NV_AUTH auth_target = nv_index;
|
|
std::string auth_target_name = nv_name;
|
|
if (using_owner_authorization) {
|
|
auth_target = TPM_RH_OWNER;
|
|
auth_target_name = NameFromHandle(TPM_RH_OWNER);
|
|
}
|
|
TPM2B_MAX_NV_BUFFER data_buffer;
|
|
data_buffer.size = 0;
|
|
result = factory_.GetTpm()->NV_ReadSync(auth_target, auth_target_name,
|
|
nv_index, nv_name, num_bytes, offset,
|
|
&data_buffer, delegate);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error reading from non-volatile space: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
nvram_data->assign(StringFrom_TPM2B_MAX_NV_BUFFER(data_buffer));
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::GetNVSpaceName(uint32_t index, std::string* name) {
|
|
TPM_RC result;
|
|
if (index > kMaxNVSpaceIndex) {
|
|
result = SAPI_RC_BAD_PARAMETER;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot read from non-volatile space with the given index: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPMS_NV_PUBLIC nv_public_data;
|
|
result = GetNVSpacePublicArea(index, &nv_public_data);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
result = ComputeNVSpaceName(nv_public_data, name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::GetNVSpacePublicArea(uint32_t index,
|
|
TPMS_NV_PUBLIC* public_data) {
|
|
TPM_RC result;
|
|
if (index > kMaxNVSpaceIndex) {
|
|
result = SAPI_RC_BAD_PARAMETER;
|
|
LOG(ERROR) << __func__
|
|
<< ": Cannot read from non-volatile space with the given index: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
auto it = nvram_public_area_map_.find(index);
|
|
if (it != nvram_public_area_map_.end()) {
|
|
*public_data = it->second;
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
TPM2B_NAME nvram_name;
|
|
TPM2B_NV_PUBLIC public_area;
|
|
public_area.nv_public.nv_index = 0;
|
|
uint32_t nv_index = NV_INDEX_FIRST + index;
|
|
result = factory_.GetTpm()->NV_ReadPublicSync(nv_index, "", &public_area,
|
|
&nvram_name, nullptr);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error reading non-volatile space public information: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
*public_data = public_area.nv_public;
|
|
nvram_public_area_map_[index] = public_area.nv_public;
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ListNVSpaces(std::vector<uint32_t>* index_list) {
|
|
TPM_RC result;
|
|
TPMI_YES_NO more_data = YES;
|
|
TPMS_CAPABILITY_DATA capability_data;
|
|
TPM_HANDLE handle_base = HR_NV_INDEX;
|
|
while (more_data == YES) {
|
|
result = factory_.GetTpm()->GetCapabilitySync(
|
|
TPM_CAP_HANDLES, handle_base, MAX_CAP_HANDLES, &more_data,
|
|
&capability_data, nullptr /*authorization_delegate*/);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error querying NV spaces: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
if (capability_data.capability != TPM_CAP_HANDLES) {
|
|
LOG(ERROR) << __func__ << ": Invalid capability type.";
|
|
return SAPI_RC_MALFORMED_RESPONSE;
|
|
}
|
|
TPML_HANDLE& handles = capability_data.data.handles;
|
|
for (uint32_t i = 0; i < handles.count; ++i) {
|
|
index_list->push_back(handles.handle[i] & HR_HANDLE_MASK);
|
|
handle_base = handles.handle[i] + 1;
|
|
}
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::SetDictionaryAttackParameters(
|
|
uint32_t max_tries,
|
|
uint32_t recovery_time,
|
|
uint32_t lockout_recovery,
|
|
AuthorizationDelegate* delegate) {
|
|
return factory_.GetTpm()->DictionaryAttackParametersSync(
|
|
TPM_RH_LOCKOUT, NameFromHandle(TPM_RH_LOCKOUT), max_tries, recovery_time,
|
|
lockout_recovery, delegate);
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ResetDictionaryAttackLock(
|
|
AuthorizationDelegate* delegate) {
|
|
return factory_.GetTpm()->DictionaryAttackLockResetSync(
|
|
TPM_RH_LOCKOUT, NameFromHandle(TPM_RH_LOCKOUT), delegate);
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::SetKnownOwnerPassword(
|
|
const std::string& known_owner_password) {
|
|
std::unique_ptr<TpmState> tpm_state(factory_.GetTpmState());
|
|
TPM_RC result = tpm_state->Initialize();
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::unique_ptr<AuthorizationDelegate> delegate =
|
|
factory_.GetPasswordAuthorization("");
|
|
if (tpm_state->IsOwnerPasswordSet()) {
|
|
LOG(INFO) << __func__ << ": Owner password is already set. "
|
|
<< "This is normal if ownership is already taken.";
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
result = SetHierarchyAuthorization(TPM_RH_OWNER, known_owner_password,
|
|
delegate.get());
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": Error setting storage hierarchy authorization "
|
|
<< "to its default value: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::CreateStorageRootKeys(
|
|
const std::string& owner_password) {
|
|
TPM_RC result = TPM_RC_SUCCESS;
|
|
std::unique_ptr<TpmState> tpm_state(factory_.GetTpmState());
|
|
result = tpm_state->Initialize();
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
Tpm* tpm = factory_.GetTpm();
|
|
TPML_PCR_SELECTION creation_pcrs;
|
|
creation_pcrs.count = 0;
|
|
TPMS_SENSITIVE_CREATE sensitive;
|
|
sensitive.user_auth = Make_TPM2B_DIGEST("");
|
|
sensitive.data = Make_TPM2B_SENSITIVE_DATA("");
|
|
TPM_HANDLE object_handle;
|
|
TPM2B_CREATION_DATA creation_data;
|
|
TPM2B_DIGEST creation_digest;
|
|
TPMT_TK_CREATION creation_ticket;
|
|
TPM2B_NAME object_name;
|
|
object_name.size = 0;
|
|
std::unique_ptr<AuthorizationDelegate> delegate =
|
|
factory_.GetPasswordAuthorization(owner_password);
|
|
if (tpm_state->IsRSASupported()) {
|
|
bool exists = false;
|
|
result = DoesPersistentKeyExist(kRSAStorageRootKey, &exists);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
if (!exists) {
|
|
TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA);
|
|
public_area.object_attributes |= (kSensitiveDataOrigin | kUserWithAuth |
|
|
kNoDA | kRestricted | kDecrypt);
|
|
public_area.parameters.rsa_detail.symmetric.algorithm = TPM_ALG_AES;
|
|
public_area.parameters.rsa_detail.symmetric.key_bits.aes = 128;
|
|
public_area.parameters.rsa_detail.symmetric.mode.aes = TPM_ALG_CFB;
|
|
TPM2B_PUBLIC rsa_public_area = Make_TPM2B_PUBLIC(public_area);
|
|
result = tpm->CreatePrimarySync(
|
|
TPM_RH_OWNER, NameFromHandle(TPM_RH_OWNER),
|
|
Make_TPM2B_SENSITIVE_CREATE(sensitive), rsa_public_area,
|
|
Make_TPM2B_DATA(""), creation_pcrs, &object_handle, &rsa_public_area,
|
|
&creation_data, &creation_digest, &creation_ticket, &object_name,
|
|
delegate.get());
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
ScopedKeyHandle rsa_key(factory_, object_handle);
|
|
// This will make the key persistent.
|
|
result = tpm->EvictControlSync(TPM_RH_OWNER, NameFromHandle(TPM_RH_OWNER),
|
|
object_handle,
|
|
StringFrom_TPM2B_NAME(object_name),
|
|
kRSAStorageRootKey, delegate.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
LOG(INFO) << __func__ << ": Created RSA SRK.";
|
|
} else {
|
|
LOG(INFO) << __func__ << ": Skip RSA SRK because it already exists.";
|
|
}
|
|
} else {
|
|
LOG(INFO) << __func__ << ": Skip RSA SRK because RSA is not supported.";
|
|
}
|
|
|
|
// Do it again for ECC.
|
|
if (tpm_state->IsRSASupported()) {
|
|
bool exists = false;
|
|
result = DoesPersistentKeyExist(kECCStorageRootKey, &exists);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
if (!exists) {
|
|
TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_ECC);
|
|
public_area.object_attributes |= (kSensitiveDataOrigin | kUserWithAuth |
|
|
kNoDA | kRestricted | kDecrypt);
|
|
public_area.parameters.ecc_detail.symmetric.algorithm = TPM_ALG_AES;
|
|
public_area.parameters.ecc_detail.symmetric.key_bits.aes = 128;
|
|
public_area.parameters.ecc_detail.symmetric.mode.aes = TPM_ALG_CFB;
|
|
TPM2B_PUBLIC ecc_public_area = Make_TPM2B_PUBLIC(public_area);
|
|
result = tpm->CreatePrimarySync(
|
|
TPM_RH_OWNER, NameFromHandle(TPM_RH_OWNER),
|
|
Make_TPM2B_SENSITIVE_CREATE(sensitive), ecc_public_area,
|
|
Make_TPM2B_DATA(""), creation_pcrs, &object_handle, &ecc_public_area,
|
|
&creation_data, &creation_digest, &creation_ticket, &object_name,
|
|
delegate.get());
|
|
if (result) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
ScopedKeyHandle ecc_key(factory_, object_handle);
|
|
// This will make the key persistent.
|
|
result = tpm->EvictControlSync(TPM_RH_OWNER, NameFromHandle(TPM_RH_OWNER),
|
|
object_handle,
|
|
StringFrom_TPM2B_NAME(object_name),
|
|
kECCStorageRootKey, delegate.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
LOG(INFO) << __func__ << ": Created ECC SRK.";
|
|
} else {
|
|
LOG(INFO) << __func__ << ": Skip ECC SRK because it already exists.";
|
|
}
|
|
} else {
|
|
LOG(INFO) << __func__ << ": Skip ECC SRK because ECC is not supported.";
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::CreateSaltingKey(const std::string& owner_password) {
|
|
bool exists = false;
|
|
TPM_RC result = DoesPersistentKeyExist(kSaltingKey, &exists);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
return result;
|
|
}
|
|
if (exists) {
|
|
LOG(INFO) << __func__ << ": Salting key already exists.";
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
std::string parent_name;
|
|
result = GetKeyName(kRSAStorageRootKey, &parent_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error getting Key name for RSA-SRK: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA);
|
|
public_area.name_alg = TPM_ALG_SHA256;
|
|
public_area.object_attributes |=
|
|
kSensitiveDataOrigin | kUserWithAuth | kNoDA | kDecrypt;
|
|
TPML_PCR_SELECTION creation_pcrs;
|
|
creation_pcrs.count = 0;
|
|
TPMS_SENSITIVE_CREATE sensitive;
|
|
sensitive.user_auth = Make_TPM2B_DIGEST("");
|
|
sensitive.data = Make_TPM2B_SENSITIVE_DATA("");
|
|
TPM2B_SENSITIVE_CREATE sensitive_create =
|
|
Make_TPM2B_SENSITIVE_CREATE(sensitive);
|
|
TPM2B_DATA outside_info = Make_TPM2B_DATA("");
|
|
|
|
TPM2B_PRIVATE out_private;
|
|
out_private.size = 0;
|
|
TPM2B_PUBLIC out_public;
|
|
out_public.size = 0;
|
|
TPM2B_CREATION_DATA creation_data;
|
|
TPM2B_DIGEST creation_hash;
|
|
TPMT_TK_CREATION creation_ticket;
|
|
// TODO(usanghi): MITM vulnerability with SaltingKey creation.
|
|
// Currently we cannot verify the key returned by the TPM.
|
|
// crbug.com/442331
|
|
std::unique_ptr<AuthorizationDelegate> delegate =
|
|
factory_.GetPasswordAuthorization("");
|
|
result = factory_.GetTpm()->CreateSync(
|
|
kRSAStorageRootKey, parent_name, sensitive_create,
|
|
Make_TPM2B_PUBLIC(public_area), outside_info, creation_pcrs, &out_private,
|
|
&out_public, &creation_data, &creation_hash, &creation_ticket,
|
|
delegate.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error creating salting key: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPM2B_NAME key_name;
|
|
key_name.size = 0;
|
|
TPM_HANDLE key_handle;
|
|
result = factory_.GetTpm()->LoadSync(kRSAStorageRootKey, parent_name,
|
|
out_private, out_public, &key_handle,
|
|
&key_name, delegate.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error loading salting key: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
ScopedKeyHandle key(factory_, key_handle);
|
|
std::unique_ptr<AuthorizationDelegate> owner_delegate =
|
|
factory_.GetPasswordAuthorization(owner_password);
|
|
result = factory_.GetTpm()->EvictControlSync(
|
|
TPM_RH_OWNER, NameFromHandle(TPM_RH_OWNER), key_handle,
|
|
StringFrom_TPM2B_NAME(key_name), kSaltingKey, owner_delegate.get());
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPMT_PUBLIC TpmUtilityImpl::CreateDefaultPublicArea(TPM_ALG_ID key_alg) {
|
|
TPMT_PUBLIC public_area;
|
|
public_area.name_alg = TPM_ALG_SHA256;
|
|
public_area.auth_policy = Make_TPM2B_DIGEST("");
|
|
public_area.object_attributes = kFixedTPM | kFixedParent;
|
|
if (key_alg == TPM_ALG_RSA) {
|
|
public_area.type = TPM_ALG_RSA;
|
|
public_area.parameters.rsa_detail.scheme.scheme = TPM_ALG_NULL;
|
|
public_area.parameters.rsa_detail.symmetric.algorithm = TPM_ALG_NULL;
|
|
public_area.parameters.rsa_detail.key_bits = 2048;
|
|
public_area.parameters.rsa_detail.exponent = 0;
|
|
public_area.unique.rsa = Make_TPM2B_PUBLIC_KEY_RSA("");
|
|
} else if (key_alg == TPM_ALG_ECC) {
|
|
public_area.type = TPM_ALG_ECC;
|
|
public_area.parameters.ecc_detail.curve_id = TPM_ECC_NIST_P256;
|
|
public_area.parameters.ecc_detail.kdf.scheme = TPM_ALG_NULL;
|
|
public_area.unique.ecc.x = Make_TPM2B_ECC_PARAMETER("");
|
|
public_area.unique.ecc.y = Make_TPM2B_ECC_PARAMETER("");
|
|
} else if (key_alg == TPM_ALG_KEYEDHASH) {
|
|
public_area.type = TPM_ALG_KEYEDHASH;
|
|
public_area.parameters.keyed_hash_detail.scheme.scheme = TPM_ALG_NULL;
|
|
} else {
|
|
LOG(WARNING) << __func__
|
|
<< ": Unrecognized key_type. Not filling parameters.";
|
|
}
|
|
return public_area;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::SetHierarchyAuthorization(
|
|
TPMI_RH_HIERARCHY_AUTH hierarchy,
|
|
const std::string& password,
|
|
AuthorizationDelegate* authorization) {
|
|
if (password.size() > kMaxPasswordLength) {
|
|
LOG(ERROR) << __func__ << ": Hierarchy passwords can be at most "
|
|
<< kMaxPasswordLength
|
|
<< " bytes. Current password length is: " << password.size();
|
|
return SAPI_RC_BAD_SIZE;
|
|
}
|
|
return factory_.GetTpm()->HierarchyChangeAuthSync(
|
|
hierarchy, NameFromHandle(hierarchy), Make_TPM2B_DIGEST(password),
|
|
authorization);
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::DisablePlatformHierarchy(
|
|
AuthorizationDelegate* authorization) {
|
|
return factory_.GetTpm()->HierarchyControlSync(
|
|
TPM_RH_PLATFORM, // The authorizing entity.
|
|
NameFromHandle(TPM_RH_PLATFORM),
|
|
TPM_RH_PLATFORM, // The target hierarchy.
|
|
0, // Disable.
|
|
authorization);
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ComputeKeyName(const TPMT_PUBLIC& public_area,
|
|
std::string* object_name) {
|
|
CHECK(object_name);
|
|
if (public_area.type == TPM_ALG_ERROR) {
|
|
// We do not compute a name for empty public area.
|
|
object_name->clear();
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
std::string serialized_public_area;
|
|
TPM_RC result = Serialize_TPMT_PUBLIC(public_area, &serialized_public_area);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error serializing public area: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string serialized_name_alg;
|
|
result = Serialize_TPM_ALG_ID(TPM_ALG_SHA256, &serialized_name_alg);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error serializing public area: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
object_name->assign(serialized_name_alg +
|
|
crypto::SHA256HashString(serialized_public_area));
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::ComputeNVSpaceName(const TPMS_NV_PUBLIC& nv_public_area,
|
|
std::string* nv_name) {
|
|
CHECK(nv_name);
|
|
if ((nv_public_area.nv_index & NV_INDEX_FIRST) == 0) {
|
|
// If the index is not an nvram index, we do not compute a name.
|
|
nv_name->clear();
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
std::string serialized_public_area;
|
|
TPM_RC result =
|
|
Serialize_TPMS_NV_PUBLIC(nv_public_area, &serialized_public_area);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error serializing public area: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string serialized_name_alg;
|
|
result = Serialize_TPM_ALG_ID(TPM_ALG_SHA256, &serialized_name_alg);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error serializing public area: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
nv_name->assign(serialized_name_alg +
|
|
crypto::SHA256HashString(serialized_public_area));
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::EncryptPrivateData(const TPMT_SENSITIVE& sensitive_area,
|
|
const TPMT_PUBLIC& public_area,
|
|
TPM2B_PRIVATE* encrypted_private_data,
|
|
TPM2B_DATA* encryption_key) {
|
|
TPM2B_SENSITIVE sensitive_data = Make_TPM2B_SENSITIVE(sensitive_area);
|
|
std::string serialized_sensitive_data;
|
|
TPM_RC result =
|
|
Serialize_TPM2B_SENSITIVE(sensitive_data, &serialized_sensitive_data);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error serializing sensitive data: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string object_name;
|
|
result = ComputeKeyName(public_area, &object_name);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error computing object name: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPM2B_DIGEST inner_integrity = Make_TPM2B_DIGEST(
|
|
crypto::SHA256HashString(serialized_sensitive_data + object_name));
|
|
std::string serialized_inner_integrity;
|
|
result = Serialize_TPM2B_DIGEST(inner_integrity, &serialized_inner_integrity);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__ << ": Error serializing inner integrity: "
|
|
<< GetErrorString(result);
|
|
return result;
|
|
}
|
|
std::string unencrypted_private_data =
|
|
serialized_inner_integrity + serialized_sensitive_data;
|
|
AES_KEY key;
|
|
AES_set_encrypt_key(encryption_key->buffer, kAesKeySize * 8, &key);
|
|
std::string private_data_string(unencrypted_private_data.size(), 0);
|
|
int iv_in = 0;
|
|
unsigned char iv[MAX_AES_BLOCK_SIZE_BYTES] = {0};
|
|
AES_cfb128_encrypt(
|
|
reinterpret_cast<const unsigned char*>(unencrypted_private_data.data()),
|
|
reinterpret_cast<unsigned char*>(string_as_array(&private_data_string)),
|
|
unencrypted_private_data.size(), &key, iv, &iv_in, AES_ENCRYPT);
|
|
*encrypted_private_data = Make_TPM2B_PRIVATE(private_data_string);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error making private area: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
TPM_RC TpmUtilityImpl::DoesPersistentKeyExist(TPMI_DH_PERSISTENT key_handle,
|
|
bool* exists) {
|
|
TPM_RC result;
|
|
TPMI_YES_NO more_data = YES;
|
|
TPMS_CAPABILITY_DATA capability_data;
|
|
result = factory_.GetTpm()->GetCapabilitySync(
|
|
TPM_CAP_HANDLES, key_handle, 1 /*property_count*/, &more_data,
|
|
&capability_data, nullptr /*authorization_delegate*/);
|
|
if (result != TPM_RC_SUCCESS) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error querying handles: " << GetErrorString(result);
|
|
return result;
|
|
}
|
|
TPML_HANDLE& handles = capability_data.data.handles;
|
|
*exists = (handles.count == 1 && handles.handle[0] == key_handle);
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
|
|
} // namespace trunks
|