| // Copyright 2015 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 "tpm_manager/server/tpm_initializer_impl.h" |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include <base/logging.h> |
| #include <base/stl_util.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <libhwsec/overalls/overalls_api.h> |
| #include <tpm_manager-client/tpm_manager/dbus-constants.h> |
| #include <trousers/scoped_tss_type.h> |
| #include <trousers/trousers.h> |
| #include <trousers/tss.h> |
| |
| #include "tpm_manager/server/local_data_store.h" |
| #include "tpm_manager/server/tpm_connection.h" |
| #include "tpm_manager/server/tpm_status.h" |
| #include "tpm_manager/server/tpm_util.h" |
| |
| using ::hwsec::overalls::GetOveralls; |
| |
| namespace { |
| |
| constexpr int kMaxOwnershipTimeoutRetries = 5; |
| constexpr char kWellKnownSrkSecret[] = "well_known_srk_secret"; |
| constexpr int kDelegateSecretSize = 20; |
| constexpr uint8_t kDefaultDelegateLabel = 2; |
| constexpr uint8_t kDefaultDelegateFamilyLabel = 1; |
| |
| } // namespace |
| |
| namespace tpm_manager { |
| |
| TpmInitializerImpl::TpmInitializerImpl(LocalDataStore* local_data_store, |
| TpmStatus* tpm_status) |
| : local_data_store_(local_data_store), tpm_status_(tpm_status) {} |
| |
| bool TpmInitializerImpl::PreInitializeTpm() { |
| // No pre-initialization steps are performed for 1.2. |
| return true; |
| } |
| |
| bool TpmInitializerImpl::InitializeTpm() { |
| TpmStatus::TpmOwnershipStatus ownership_status; |
| if (!tpm_status_->GetTpmOwned(&ownership_status)) { |
| LOG(ERROR) << __func__ << ": failed to get tpm ownership status"; |
| return false; |
| } |
| if (ownership_status == TpmStatus::kTpmOwned) { |
| // Tpm is already owned, so we do not need to do anything. |
| VLOG(1) << "Tpm already owned."; |
| return true; |
| } |
| // Makes sure EK is there when unowned. |
| if (ownership_status != TpmStatus::kTpmUnowned) { |
| LOG(INFO) << __func__ |
| << ": TPM ownership is taken already; skip initializing EK."; |
| } else if (!InitializeEndorsementKey()) { |
| LOG(ERROR) << __func__ << ": failed to initialize endorsement key"; |
| return false; |
| } |
| TpmConnection connection(GetDefaultOwnerPassword()); |
| if (ownership_status != TpmStatus::kTpmUnowned) { |
| LOG(INFO) << __func__ |
| << ": TPM ownership is taken already; skip taking ownership."; |
| } else if (!TakeOwnership(&connection)) { |
| LOG(ERROR) << __func__ << ": failed to take TPM ownership"; |
| return false; |
| } |
| // TPM ownership is taken; now the status is pre-owned. |
| if (!InitializeSrk(&connection)) { |
| LOG(ERROR) << __func__ << ": failed to initialize SRK"; |
| return false; |
| } |
| std::string owner_password; |
| std::string random_bytes; |
| if (!openssl_util_.GetRandomBytes(kOwnerPasswordRandomBytes, &random_bytes)) { |
| return false; |
| } |
| owner_password = base::HexEncode(random_bytes.data(), random_bytes.size()); |
| LocalData local_data; |
| local_data.clear_owner_dependency(); |
| for (auto value : kInitialTpmOwnerDependencies) { |
| local_data.add_owner_dependency(value); |
| } |
| local_data.set_owner_password(owner_password); |
| if (!local_data_store_->Write(local_data)) { |
| LOG(ERROR) << ": Error saving local data after |set_owner_password|."; |
| return false; |
| } |
| if (!ChangeOwnerPassword(&connection, owner_password)) { |
| return false; |
| } |
| tpm_status_->MarkRandomOwnerPasswordSet(); |
| |
| // for performance sake, continue using the same |local_data| so we don't need |
| // to read the data from file once again. |
| AuthDelegate owner_delegate; |
| if (CreateDelegateWithDefaultLabel(&owner_delegate)) { |
| local_data.mutable_owner_delegate()->Swap(&owner_delegate); |
| if (!local_data_store_->Write(local_data)) { |
| LOG(ERROR) << ": Cannot persist delegate."; |
| return false; |
| } |
| } else { |
| LOG(ERROR) << __func__ << ": Cannot create delegate."; |
| return false; |
| } |
| |
| reset_da_lock_auth_failed_ = false; |
| return true; |
| } |
| |
| void TpmInitializerImpl::VerifiedBootHelper() { |
| // Nothing to do. |
| } |
| |
| DictionaryAttackResetStatus TpmInitializerImpl::ResetDictionaryAttackLock() { |
| if (reset_da_lock_auth_failed_) { |
| // An auth error was encountered in a previous attempt, and there was no |
| // auth update after the attempt. Skips the request to avoid further |
| // increasing the counter. |
| LOG(ERROR) << __func__ |
| << ": skipped the request to avoid repeating a " |
| "previous auth error."; |
| return DictionaryAttackResetStatus::kResetAttemptFailed; |
| } |
| |
| TpmStatus::TpmOwnershipStatus ownership_status; |
| if (!tpm_status_->GetTpmOwned(&ownership_status)) { |
| // Can't tell if we really can't get tpm ownership status or lockout is in |
| // our way, so let's still go ahead. |
| LOG(WARNING) << __func__ |
| << ": failed to get tpm ownership status, but that could be " |
| "caused by a locked out TPM, so proceeding anyway."; |
| } else { |
| if (ownership_status != TpmStatus::kTpmOwned) { |
| LOG(ERROR) << __func__ << ": TPM is not initialized yet."; |
| return DictionaryAttackResetStatus::kResetAttemptFailed; |
| } |
| } |
| |
| std::string owner_password; |
| AuthDelegate owner_delegate; |
| if (!ReadOwnerAuthFromLocalData(&owner_password, &owner_delegate)) { |
| // Note that if it failed here, it could be because the TPM is not owned, |
| // but we tried anyway because we can't get the TPM status. See comments |
| // above on GetTpmOwned(). |
| LOG(ERROR) << __func__ << ": failed to get owner auth."; |
| return DictionaryAttackResetStatus::kResetAttemptFailed; |
| } |
| |
| std::unique_ptr<TpmConnection> connection; |
| if (!owner_password.empty()) { |
| connection = std::make_unique<TpmConnection>(owner_password); |
| } else if (!owner_delegate.blob().empty() && |
| !owner_delegate.secret().empty()) { |
| if (!owner_delegate.has_reset_lock_permissions()) { |
| return DictionaryAttackResetStatus::kDelegateNotAllowed; |
| } |
| connection = std::make_unique<TpmConnection>(owner_delegate); |
| } else { |
| LOG(ERROR) << __func__ << ": available owner auth not found."; |
| return DictionaryAttackResetStatus::kDelegateNotAvailable; |
| } |
| |
| TSS_HTPM tpm_handle = connection->GetTpm(); |
| if (!tpm_handle) { |
| LOG(ERROR) << __func__ << ": Error getting a TPM handle."; |
| return DictionaryAttackResetStatus::kResetAttemptFailed; |
| } |
| |
| TSS_RESULT result = GetOveralls()->Ospi_TPM_SetStatus( |
| tpm_handle, TSS_TPMSTATUS_RESETLOCK, true /* value will be ignored */); |
| if (result != TSS_SUCCESS) { |
| TPM_LOG(ERROR, result) << __func__ << ": failed to reset DA lock."; |
| if (TPM_ERROR(TPM_E_AUTHFAIL) == result || |
| TPM_ERROR(TPM_E_AUTH2FAIL) == result) { |
| reset_da_lock_auth_failed_ = true; |
| } |
| |
| return result == TPM_ERROR(TPM_E_WRONGPCRVAL) |
| ? DictionaryAttackResetStatus::kInvalidPcr0State |
| : DictionaryAttackResetStatus::kResetAttemptFailed; |
| } |
| |
| LOG(INFO) << __func__ << ": dictionary attack counter has been reset."; |
| return DictionaryAttackResetStatus::kResetAttemptSucceeded; |
| } |
| |
| void TpmInitializerImpl::PruneStoredPasswords() { |
| TpmStatus::TpmOwnershipStatus ownership_status; |
| if (!tpm_status_->GetTpmOwned(&ownership_status)) { |
| LOG(ERROR) << __func__ << ": failed to get tpm ownership status"; |
| return; |
| } |
| |
| if (ownership_status == TpmStatus::kTpmOwned) { |
| LOG(WARNING) << __func__ |
| << ": TPM is already owned. Local data won't be touched."; |
| return; |
| } |
| |
| LocalData local_data; |
| if (!local_data_store_->Read(&local_data)) { |
| LOG(ERROR) << __func__ << ": failed to read local data."; |
| return; |
| } |
| |
| local_data.clear_owner_password(); |
| local_data.clear_owner_delegate(); |
| local_data.clear_owner_dependency(); |
| |
| if (!local_data_store_->Write(local_data)) { |
| LOG(ERROR) << __func__ << ": failed to write local data."; |
| } |
| } |
| |
| bool TpmInitializerImpl::InitializeEndorsementKey() { |
| TpmConnection connection; |
| trousers::ScopedTssKey local_key_handle(connection.GetContext()); |
| TSS_RESULT result = Tspi_TPM_GetPubEndorsementKey( |
| connection.GetTpm(), false, nullptr, local_key_handle.ptr()); |
| if (TPM_ERROR(result) == TPM_SUCCESS) { |
| // In this case the EK already exists, so we can return true here. |
| VLOG(1) << "EK already exists."; |
| return true; |
| } else if (TPM_ERROR(result) != TPM_E_NO_ENDORSEMENT) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetPubEndorsementKey"; |
| return false; |
| } |
| TPM_LOG(INFO, result) << "No EK is present; creating it."; |
| TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_SIZE_2048; |
| if (TPM_ERROR(result = Tspi_Context_CreateObject( |
| connection.GetContext(), TSS_OBJECT_TYPE_RSAKEY, init_flags, |
| local_key_handle.ptr()))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
| return false; |
| } |
| if (TPM_ERROR(result = Tspi_TPM_CreateEndorsementKey( |
| connection.GetTpm(), local_key_handle, NULL))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_CreateEndorsementKey"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool TpmInitializerImpl::TakeOwnership(TpmConnection* connection) { |
| TSS_RESULT result; |
| trousers::ScopedTssKey srk_handle(connection->GetContext()); |
| TSS_FLAG init_flags = TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION; |
| if (TPM_ERROR(result = Tspi_Context_CreateObject( |
| connection->GetContext(), TSS_OBJECT_TYPE_RSAKEY, |
| init_flags, srk_handle.ptr()))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
| return false; |
| } |
| TSS_HPOLICY srk_usage_policy; |
| if (TPM_ERROR(result = Tspi_GetPolicyObject(srk_handle, TSS_POLICY_USAGE, |
| &srk_usage_policy))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject"; |
| return false; |
| } |
| if (TPM_ERROR(result = Tspi_Policy_SetSecret( |
| srk_usage_policy, TSS_SECRET_MODE_PLAIN, |
| strlen(kWellKnownSrkSecret), |
| const_cast<BYTE*>( |
| reinterpret_cast<const BYTE*>(kWellKnownSrkSecret))))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; |
| return false; |
| } |
| // Tspi_TPM_TakeOwnership can potentially take a long time to complete, |
| // so we retry if there is a timeout in any layer. I chose 5, because the |
| // longest TakeOwnership call that I have seen took ~2min, and the default |
| // TSS timeout is 30s. This means that after 5 calls, it is quite likely that |
| // this call will succeed. |
| int retry_count = 0; |
| do { |
| result = Tspi_TPM_TakeOwnership(connection->GetTpm(), srk_handle, 0); |
| retry_count++; |
| } while (((result == TDDL_E_TIMEOUT) || |
| (result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) || |
| (result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) && |
| (retry_count < kMaxOwnershipTimeoutRetries)); |
| if (result) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_TakeOwnership, attempts: " |
| << retry_count; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool TpmInitializerImpl::InitializeSrk(TpmConnection* connection) { |
| TSS_RESULT result; |
| trousers::ScopedTssKey srk_handle(connection->GetContext()); |
| TSS_UUID SRK_UUID = TSS_UUID_SRK; |
| if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID( |
| connection->GetContext(), TSS_PS_TYPE_SYSTEM, SRK_UUID, |
| srk_handle.ptr()))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Context_LoadKeyByUUID"; |
| return false; |
| } |
| |
| trousers::ScopedTssPolicy policy_handle(connection->GetContext()); |
| if (TPM_ERROR(result = Tspi_Context_CreateObject( |
| connection->GetContext(), TSS_OBJECT_TYPE_POLICY, |
| TSS_POLICY_USAGE, policy_handle.ptr()))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
| return false; |
| } |
| BYTE new_password[0]; |
| if (TPM_ERROR(result = Tspi_Policy_SetSecret( |
| policy_handle, TSS_SECRET_MODE_PLAIN, 0, new_password))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; |
| return false; |
| } |
| |
| if (TPM_ERROR(result = Tspi_ChangeAuth(srk_handle, connection->GetTpm(), |
| policy_handle))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth"; |
| return false; |
| } |
| TSS_BOOL is_srk_restricted = false; |
| if (TPM_ERROR(result = Tspi_TPM_GetStatus(connection->GetTpm(), |
| TSS_TPMSTATUS_DISABLEPUBSRKREAD, |
| &is_srk_restricted))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetStatus"; |
| return false; |
| } |
| // If the SRK is restricted, we unrestrict it. |
| if (is_srk_restricted) { |
| if (TPM_ERROR(result = Tspi_TPM_SetStatus(connection->GetTpm(), |
| TSS_TPMSTATUS_DISABLEPUBSRKREAD, |
| false))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_SetStatus"; |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool TpmInitializerImpl::ChangeOwnerPassword( |
| TpmConnection* connection, const std::string& owner_password) { |
| TSS_RESULT result; |
| trousers::ScopedTssPolicy policy_handle(connection->GetContext()); |
| if (TPM_ERROR(result = Tspi_Context_CreateObject( |
| connection->GetContext(), TSS_OBJECT_TYPE_POLICY, |
| TSS_POLICY_USAGE, policy_handle.ptr()))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
| return false; |
| } |
| std::string mutable_owner_password(owner_password); |
| if (TPM_ERROR( |
| result = Tspi_Policy_SetSecret( |
| policy_handle, TSS_SECRET_MODE_PLAIN, owner_password.size(), |
| reinterpret_cast<BYTE*>(base::data(mutable_owner_password))))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; |
| return false; |
| } |
| |
| if (TPM_ERROR(result = |
| Tspi_ChangeAuth(connection->GetTpm(), 0, policy_handle))) { |
| TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth"; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool TpmInitializerImpl::ReadOwnerAuthFromLocalData( |
| std::string* owner_password, AuthDelegate* owner_delegate) { |
| LocalData local_data; |
| if (!local_data_store_->Read(&local_data)) { |
| LOG(ERROR) << __func__ << ": Failed to read local data."; |
| return false; |
| } |
| |
| if (owner_password) { |
| *owner_password = local_data.owner_password(); |
| } |
| |
| if (owner_delegate) { |
| *owner_delegate = local_data.owner_delegate(); |
| } |
| |
| return true; |
| } |
| |
| bool TpmInitializerImpl::CreateDelegateWithDefaultLabel( |
| AuthDelegate* delegate) { |
| std::string delegate_blob; |
| std::string delegate_secret; |
| // No PCR value bound to the delegate by default (crbug/990322, b/139099154). |
| if (!CreateAuthDelegate(/*bound_pcrs=*/{}, kDefaultDelegateFamilyLabel, |
| kDefaultDelegateLabel, &delegate_blob, |
| &delegate_secret)) { |
| LOG(ERROR) << __func__ << ": Failed to create delegate."; |
| return false; |
| } |
| delegate->set_blob(delegate_blob); |
| delegate->set_secret(delegate_secret); |
| delegate->set_has_reset_lock_permissions(true); |
| return true; |
| } |
| |
| bool TpmInitializerImpl::EnsurePersistentOwnerDelegate() { |
| LocalData local_data; |
| if (!local_data_store_->Read(&local_data)) { |
| LOG(ERROR) << __func__ << ": Failed to read local data."; |
| return false; |
| } |
| auto owner_delegate = local_data.mutable_owner_delegate(); |
| if (!owner_delegate->blob().empty() && !owner_delegate->secret().empty()) { |
| return true; |
| } |
| LOG(WARNING) << __func__ << ": Owner delegate is missing; re-creating."; |
| if (!CreateDelegateWithDefaultLabel(owner_delegate)) { |
| LOG(ERROR) << __func__ << ": Failed to create owner delegate."; |
| return false; |
| } |
| if (!local_data_store_->Write(local_data)) { |
| LOG(ERROR) << __func__ << ": Failed to write local data change."; |
| return false; |
| } |
| return true; |
| } |
| |
| bool TpmInitializerImpl::CreateAuthDelegate( |
| const std::vector<uint32_t>& bound_pcrs, |
| uint8_t delegate_family_label, |
| uint8_t delegate_label, |
| std::string* delegate_blob, |
| std::string* delegate_secret) { |
| CHECK(delegate_blob && delegate_secret); |
| |
| // Connects to the TPM as the owner. |
| |
| // read the owner password. |
| // TODO(cylai): provide a clean way to retrieve owner password for this class. |
| std::string owner_password; |
| if (!ReadOwnerAuthFromLocalData(&owner_password, nullptr) || |
| owner_password.empty()) { |
| LOG(ERROR) << __func__ << ": couldn't get owner password."; |
| return false; |
| } |
| |
| TpmConnection connection(owner_password); |
| TSS_HCONTEXT context_handle = connection.GetContext(); |
| TSS_HTPM tpm_handle = connection.GetTpm(); |
| if (!context_handle || !tpm_handle) { |
| LOG(ERROR) << __func__ << "TPM connection error."; |
| return false; |
| } |
| |
| // Generate a delegate secret. |
| if (!openssl_util_.GetRandomBytes(kDelegateSecretSize, delegate_secret)) { |
| return false; |
| } |
| |
| // Create an owner delegation policy. |
| trousers::ScopedTssPolicy policy(context_handle); |
| TSS_RESULT result; |
| result = Tspi_Context_CreateObject(context_handle, TSS_OBJECT_TYPE_POLICY, |
| TSS_POLICY_USAGE, policy.ptr()); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to create policy."; |
| return false; |
| } |
| result = Tspi_Policy_SetSecret( |
| policy, TSS_SECRET_MODE_PLAIN, delegate_secret->size(), |
| reinterpret_cast<BYTE*>(const_cast<char*>(delegate_secret->data()))); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to set policy secret."; |
| return false; |
| } |
| result = |
| Tspi_SetAttribUint32(policy, TSS_TSPATTRIB_POLICY_DELEGATION_INFO, |
| TSS_TSPATTRIB_POLDEL_TYPE, TSS_DELEGATIONTYPE_OWNER); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to set delegation type."; |
| return false; |
| } |
| // These are the privileged operations we will allow the delegate to perform. |
| constexpr UINT32 permissions = |
| TPM_DELEGATE_ActivateIdentity | TPM_DELEGATE_DAA_Join | |
| TPM_DELEGATE_DAA_Sign | TPM_DELEGATE_ResetLockValue | |
| TPM_DELEGATE_OwnerReadInternalPub | TPM_DELEGATE_CMK_ApproveMA | |
| TPM_DELEGATE_CMK_CreateTicket | TPM_DELEGATE_AuthorizeMigrationKey; |
| result = Tspi_SetAttribUint32(policy, TSS_TSPATTRIB_POLICY_DELEGATION_INFO, |
| TSS_TSPATTRIB_POLDEL_PER1, permissions); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to set permissions."; |
| return false; |
| } |
| result = Tspi_SetAttribUint32(policy, TSS_TSPATTRIB_POLICY_DELEGATION_INFO, |
| TSS_TSPATTRIB_POLDEL_PER2, 0); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to set permissions."; |
| return false; |
| } |
| |
| // Bind the delegate to the specified PCRs. Note: it's crucial to pass a null |
| // TSS_HPCRS to Tspi_TPM_Delegate_CreateDelegation() when no PCR is selected, |
| // otherwise it will fail with TPM_E_BAD_PARAM_SIZE. |
| trousers::ScopedTssPcrs pcrs_handle(context_handle); |
| if (!bound_pcrs.empty()) { |
| result = Tspi_Context_CreateObject(context_handle, TSS_OBJECT_TYPE_PCRS, |
| TSS_PCRS_STRUCT_INFO_SHORT, |
| pcrs_handle.ptr()); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to create PCRS object."; |
| return false; |
| } |
| for (auto bound_pcr : bound_pcrs) { |
| UINT32 pcr_len = 0; |
| trousers::ScopedTssMemory pcr_value(context_handle); |
| if (TPM_ERROR(result = Tspi_TPM_PcrRead(tpm_handle, bound_pcr, &pcr_len, |
| pcr_value.ptr()))) { |
| TPM_LOG(ERROR, result) << "Could not read PCR value"; |
| return false; |
| } |
| result = Tspi_PcrComposite_SetPcrValue(pcrs_handle, bound_pcr, pcr_len, |
| pcr_value.value()); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "Could not set value for PCR in PCRS handle"; |
| return false; |
| } |
| } |
| constexpr unsigned int kTpmPCRLocality = 1; |
| result = Tspi_PcrComposite_SetPcrLocality(pcrs_handle, kTpmPCRLocality); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) |
| << "Could not set locality for PCRs in PCRS handle"; |
| return false; |
| } |
| } |
| |
| // Create a delegation family. |
| trousers::ScopedTssObject<TSS_HDELFAMILY> family(context_handle); |
| result = Tspi_TPM_Delegate_AddFamily(tpm_handle, delegate_family_label, |
| family.ptr()); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to create family."; |
| return false; |
| } |
| |
| // Create the delegation. |
| result = Tspi_TPM_Delegate_CreateDelegation(tpm_handle, delegate_label, 0, |
| pcrs_handle, family, policy); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to create delegation."; |
| return false; |
| } |
| |
| // Enable the delegation family. |
| result = Tspi_SetAttribUint32(family, TSS_TSPATTRIB_DELFAMILY_STATE, |
| TSS_TSPATTRIB_DELFAMILYSTATE_ENABLED, TRUE); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << "CreateDelegate: Failed to enable family."; |
| return false; |
| } |
| |
| // Save the delegation blob for later. |
| if (!GetDataAttribute(context_handle, policy, |
| TSS_TSPATTRIB_POLICY_DELEGATION_INFO, |
| TSS_TSPATTRIB_POLDEL_OWNERBLOB, delegate_blob)) { |
| LOG(ERROR) << "CreateDelegate: Failed to get delegate blob."; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool TpmInitializerImpl::GetDataAttribute(TSS_HCONTEXT context, |
| TSS_HOBJECT object, |
| TSS_FLAG flag, |
| TSS_FLAG sub_flag, |
| std::string* data) { |
| UINT32 length = 0; |
| trousers::ScopedTssMemory buffer(context); |
| TSS_RESULT result = |
| Tspi_GetAttribData(object, flag, sub_flag, &length, buffer.ptr()); |
| if (TPM_ERROR(result)) { |
| TPM_LOG(ERROR, result) << __func__ << "Failed to read object attribute."; |
| return false; |
| } |
| data->assign(buffer.value(), buffer.value() + length); |
| return true; |
| } |
| |
| } // namespace tpm_manager |