| // Copyright (c) 2012 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 "chaps/tpm_utility_impl.h" |
| |
| #include <map> |
| #include <optional> |
| #include <set> |
| #include <sstream> |
| #include <string> |
| |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/logging.h> |
| #include <brillo/secure_blob.h> |
| #include <openssl/rand.h> |
| #include <trousers/scoped_tss_type.h> |
| #include <trousers/tss.h> |
| |
| #include "chaps/chaps_utility.h" |
| |
| using brillo::SecureBlob; |
| using std::hex; |
| using std::map; |
| using std::set; |
| using std::string; |
| using std::stringstream; |
| using trousers::ScopedTssContext; |
| using trousers::ScopedTssKey; |
| using trousers::ScopedTssObject; |
| using trousers::ScopedTssPolicy; |
| |
| namespace { |
| constexpr int kKeySizeForSealingData = 2048; |
| } // namespace |
| |
| namespace chaps { |
| |
| // TSSEncryptedData wraps a TSS encrypted data object. The underlying TSS object |
| // will be closed when this object falls out of scope. |
| typedef ScopedTssObject<TSS_HENCDATA> ScopedTssEncData; |
| class TSSEncryptedData { |
| public: |
| explicit TSSEncryptedData(TSS_HCONTEXT context) |
| : context_(context), handle_(context) {} |
| TSSEncryptedData(const TSSEncryptedData&) = delete; |
| TSSEncryptedData& operator=(const TSSEncryptedData&) = delete; |
| |
| bool Create() { |
| TSS_RESULT result = Tspi_Context_CreateObject( |
| context_, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, handle_.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_CreateObject - " |
| << TPMUtilityImpl::ResultToString(result); |
| return false; |
| } |
| |
| return true; |
| } |
| bool GetData(string* data) { |
| UINT32 length = 0; |
| BYTE* buffer = NULL; |
| TSS_RESULT result = |
| Tspi_GetAttribData(handle_, TSS_TSPATTRIB_ENCDATA_BLOB, |
| TSS_TSPATTRIB_ENCDATABLOB_BLOB, &length, &buffer); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_GetAttribData(ENCDATA_BLOB) - " |
| << TPMUtilityImpl::ResultToString(result); |
| return false; |
| } |
| *data = ConvertByteBufferToString(buffer, length); |
| Tspi_Context_FreeMemory(context_, buffer); |
| return true; |
| } |
| bool SetData(const string& data) { |
| TSS_RESULT result = Tspi_SetAttribData( |
| handle_, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB, |
| data.length(), ConvertStringToByteBuffer(data.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribData(ENCDATA_BLOB) - " |
| << TPMUtilityImpl::ResultToString(result); |
| return false; |
| } |
| return true; |
| } |
| operator TSS_HENCDATA() { return handle_; } |
| |
| private: |
| TSS_HCONTEXT context_; |
| ScopedTssObject<TSS_HENCDATA> handle_; |
| }; |
| |
| // TSSHash wraps a TSS hash object. The underlying TSS object will be closed |
| // when this object falls out of scope. |
| class TSSHash { |
| public: |
| explicit TSSHash(TSS_HCONTEXT context) |
| : context_(context), handle_(context) {} |
| TSSHash(const TSSHash&) = delete; |
| TSSHash& operator=(const TSSHash&) = delete; |
| |
| bool Create(const string& value) { |
| TSS_RESULT result = Tspi_Context_CreateObject( |
| context_, TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, handle_.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_CreateObject - " |
| << TPMUtilityImpl::ResultToString(result); |
| return false; |
| } |
| |
| result = Tspi_Hash_SetHashValue(handle_, value.length(), |
| ConvertStringToByteBuffer(value.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Hash_SetHashValue - " |
| << TPMUtilityImpl::ResultToString(result); |
| return false; |
| } |
| return true; |
| } |
| operator TSS_HHASH() { return handle_; } |
| |
| private: |
| TSS_HCONTEXT context_; |
| ScopedTssObject<TSS_HHASH> handle_; |
| }; |
| |
| TPMUtilityImpl::TPMUtilityImpl(const string& srk_auth_data) |
| : is_initialized_(false), |
| is_srk_ready_(false), |
| default_policy_(0), |
| srk_(0), |
| srk_auth_data_(srk_auth_data), |
| srk_public_loaded_(false), |
| default_exponent_("\x1\x0\x1", 3), |
| last_handle_(0), |
| tpm_manager_utility_(nullptr) {} |
| |
| TPMUtilityImpl::TPMUtilityImpl( |
| const string& srk_auth_data, |
| tpm_manager::TpmManagerUtility* tpm_manager_utility) |
| : is_initialized_(false), |
| is_srk_ready_(false), |
| default_policy_(0), |
| srk_(0), |
| srk_auth_data_(srk_auth_data), |
| srk_public_loaded_(false), |
| default_exponent_("\x1\x0\x1", 3), |
| last_handle_(0), |
| tpm_manager_utility_(tpm_manager_utility) {} |
| |
| TPMUtilityImpl::~TPMUtilityImpl() { |
| LOG(INFO) << "Unloading keys for all slots."; |
| map<int, HandleInfo>::iterator it; |
| set<int>::iterator it2; |
| for (it = slot_handles_.begin(); it != slot_handles_.end(); ++it) { |
| set<int>* slot_handles = &it->second.handles_; |
| for (it2 = slot_handles->begin(); it2 != slot_handles->end(); ++it2) { |
| FlushHandle(*it2); |
| } |
| } |
| // These can't use ScopedTssObject because they must be closed before the |
| // context (tsp_context_) closes. |
| if (srk_) |
| Tspi_Context_CloseObject(tsp_context_, srk_); |
| if (default_policy_) |
| Tspi_Context_CloseObject(tsp_context_, default_policy_); |
| } |
| |
| bool TPMUtilityImpl::Init() { |
| VLOG(1) << "TPMUtilityImpl::Init enter"; |
| |
| if (is_initialized_) |
| return true; |
| if (!IsTPMAvailable()) |
| return false; |
| |
| if (!tpm_manager_utility_) { |
| tpm_manager_utility_ = tpm_manager::TpmManagerUtility::GetSingleton(); |
| if (!tpm_manager_utility_) { |
| LOG(ERROR) << __func__ << ": Failed to get TpmManagerUtility singleton!"; |
| return false; |
| } |
| } |
| |
| TSS_RESULT result = TSS_SUCCESS; |
| result = Tspi_Context_Create(tsp_context_.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_Create - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_Context_Connect(tsp_context_, NULL); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_Connect - " << ResultToString(result); |
| return false; |
| } |
| // Get the default policy so we can compare against it later. |
| result = Tspi_Context_GetDefaultPolicy(tsp_context_, &default_policy_); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_GetDefaultPolicy - " << ResultToString(result); |
| return false; |
| } |
| is_initialized_ = true; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::IsTPMAvailable() { |
| if (is_enabled_) { |
| return true; |
| } |
| if (!tpm_manager_utility_) { |
| tpm_manager_utility_ = tpm_manager::TpmManagerUtility::GetSingleton(); |
| if (!tpm_manager_utility_) { |
| LOG(ERROR) << __func__ << ": Failed to get TpmManagerUtility singleton!"; |
| return false; |
| } |
| } |
| bool is_enabled = false; |
| bool is_owned = false; |
| bool is_owner_password_present = false; |
| bool has_reset_lock_permissions = false; |
| if (!tpm_manager_utility_->GetTpmNonsensitiveStatus( |
| &is_enabled, &is_owned, &is_owner_password_present, |
| &has_reset_lock_permissions)) { |
| LOG(ERROR) << ": failed to get TPM status from tpm_manager."; |
| return false; |
| } |
| return is_enabled_ = is_enabled; |
| } |
| |
| TPMVersion TPMUtilityImpl::GetTPMVersion() { |
| return TPMVersion::TPM1_2; |
| } |
| |
| bool TPMUtilityImpl::InitSRK() { |
| if (!is_initialized_) |
| return false; |
| if (is_srk_ready_) |
| return true; |
| VLOG(1) << "TPMUtilityImpl::InitSRK enter"; |
| // Load the SRK and assign it a usage policy with authorization data. |
| TSS_RESULT result = TSS_SUCCESS; |
| TSS_UUID uuid = TSS_UUID_SRK; |
| result = |
| Tspi_Context_LoadKeyByUUID(tsp_context_, TSS_PS_TYPE_SYSTEM, uuid, &srk_); |
| if (result != TSS_SUCCESS) { |
| if (result == (TSS_LAYER_TCS | TSS_E_PS_KEY_NOTFOUND)) { |
| LOG(WARNING) << "SRK does not exist - this is normal when the TPM is not " |
| << "yet owned."; |
| } else { |
| LOG(ERROR) << "Tspi_Context_LoadKeyByUUID - " << ResultToString(result); |
| } |
| return false; |
| } |
| ScopedTssPolicy srk_policy(tsp_context_); |
| result = Tspi_Context_CreateObject(tsp_context_, TSS_OBJECT_TYPE_POLICY, |
| TSS_POLICY_USAGE, srk_policy.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_CreateObject - " << ResultToString(result); |
| return false; |
| } |
| if (srk_auth_data_.empty()) { |
| result = Tspi_Policy_SetSecret(srk_policy, TSS_SECRET_MODE_PLAIN, 0, NULL); |
| } else { |
| LOG(INFO) << "Using non-empty secret for SRK policy."; |
| // If the authorization data is 20 null bytes, use SHA1 mode for |
| // compatibility with other tools that use this value. |
| result = Tspi_Policy_SetSecret( |
| srk_policy, |
| srk_auth_data_ == string(20, 0) ? TSS_SECRET_MODE_SHA1 |
| : TSS_SECRET_MODE_PLAIN, |
| srk_auth_data_.length(), |
| ConvertStringToByteBuffer(srk_auth_data_.data())); |
| } |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_SetSecret - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_Policy_AssignToObject(srk_policy.release(), srk_); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_AssignToObject - " << ResultToString(result); |
| return false; |
| } |
| VLOG(1) << "TPMUtilityImpl::InitSRK success"; |
| is_srk_ready_ = true; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::Authenticate(const SecureBlob& auth_data, |
| const string& auth_key_blob, |
| const string& encrypted_root_key, |
| SecureBlob* root_key) { |
| VLOG(1) << "TPMUtilityImpl::Authenticate enter"; |
| int key_handle = 0; |
| if (!LoadKeyWithParentInternal(std::nullopt, auth_key_blob, auth_data, srk_, |
| &key_handle)) |
| return false; |
| string root_key_str; |
| if (!Unbind(key_handle, encrypted_root_key, &root_key_str)) { |
| FlushHandle(key_handle); |
| return false; |
| } |
| *root_key = SecureBlob(root_key_str.begin(), root_key_str.end()); |
| brillo::SecureClearContainer(root_key_str); |
| |
| VLOG(1) << "TPMUtilityImpl::Authenticate success"; |
| FlushHandle(key_handle); |
| return true; |
| } |
| |
| bool TPMUtilityImpl::ChangeAuthData(const SecureBlob& old_auth_data, |
| const SecureBlob& new_auth_data, |
| const string& old_auth_key_blob, |
| string* new_auth_key_blob) { |
| VLOG(1) << "TPMUtilityImpl::ChangeAuthData enter"; |
| int key_handle = 0; |
| if (!LoadKeyWithParentInternal(std::nullopt, old_auth_key_blob, old_auth_data, |
| srk_, &key_handle)) |
| return false; |
| // Make sure the old auth data is ok. |
| string encrypted, decrypted; |
| if (!Bind(key_handle, "testdata", &encrypted)) { |
| FlushHandle(key_handle); |
| return false; |
| } |
| if (!Unbind(key_handle, encrypted, &decrypted)) { |
| FlushHandle(key_handle); |
| return false; |
| } |
| // Change the secret. |
| TSS_RESULT result = TSS_SUCCESS; |
| ScopedTssPolicy policy(tsp_context_); |
| result = Tspi_Context_CreateObject(tsp_context_, TSS_OBJECT_TYPE_POLICY, |
| TSS_POLICY_USAGE, policy.ptr()); |
| if (result != TSS_SUCCESS) { |
| FlushHandle(key_handle); |
| LOG(ERROR) << "Tspi_Context_CreateObject - " << ResultToString(result); |
| return false; |
| } |
| result = |
| Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_SHA1, new_auth_data.size(), |
| const_cast<BYTE*>(new_auth_data.data())); |
| if (result != TSS_SUCCESS) { |
| FlushHandle(key_handle); |
| LOG(ERROR) << "Tspi_Policy_SetSecret - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_ChangeAuth(GetTssHandle(key_handle), srk_, policy.release()); |
| if (result != TSS_SUCCESS) { |
| FlushHandle(key_handle); |
| LOG(ERROR) << "Tspi_ChangeAuth - " << ResultToString(result); |
| return false; |
| } |
| if (!GetKeyBlob(GetTssHandle(key_handle), new_auth_key_blob)) { |
| FlushHandle(key_handle); |
| return false; |
| } |
| VLOG(1) << "TPMUtilityImpl::ChangeAuthData success"; |
| FlushHandle(key_handle); |
| return true; |
| } |
| |
| bool TPMUtilityImpl::GenerateRandom(int num_bytes, string* random_data) { |
| VLOG(1) << "TPMUtilityImpl::GenerateRandom enter"; |
| if (!InitSRK()) |
| return false; |
| TSS_RESULT result = TSS_SUCCESS; |
| TSS_HTPM tpm; |
| BYTE* random_bytes = NULL; |
| result = Tspi_Context_GetTpmObject(tsp_context_, &tpm); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_GetTpmObject - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_TPM_GetRandom(tpm, num_bytes, &random_bytes); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_TPM_GetRandom - " << ResultToString(result); |
| return false; |
| } |
| *random_data = ConvertByteBufferToString(random_bytes, num_bytes); |
| Tspi_Context_FreeMemory(tsp_context_, random_bytes); |
| VLOG(1) << "TPMUtilityImpl::GenerateRandom success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::StirRandom(const string& entropy_data) { |
| VLOG(1) << "TPMUtilityImpl::StirRandom enter"; |
| if (!InitSRK()) |
| return false; |
| TSS_RESULT result = TSS_SUCCESS; |
| TSS_HTPM tpm; |
| result = Tspi_Context_GetTpmObject(tsp_context_, &tpm); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_GetTpmObject - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_TPM_StirRandom(tpm, entropy_data.length(), |
| ConvertStringToByteBuffer(entropy_data.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_TPM_StirRandom - " << ResultToString(result); |
| return false; |
| } |
| VLOG(1) << "TPMUtilityImpl::StirRandom success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::GenerateRSAKey(int slot, |
| int modulus_bits, |
| const string& public_exponent, |
| const SecureBlob& auth_data, |
| string* key_blob, |
| int* key_handle) { |
| // Call the internal function. |
| return GenerateRSAKeyInternal(slot, modulus_bits, public_exponent, auth_data, |
| key_blob, key_handle); |
| } |
| |
| bool TPMUtilityImpl::GenerateRSAKeyInternal(std::optional<int> slot, |
| int modulus_bits, |
| const string& public_exponent, |
| const SecureBlob& auth_data, |
| string* key_blob, |
| int* key_handle) { |
| VLOG(1) << "TPMUtilityImpl::GenerateRSAKey enter"; |
| if (!InitSRK()) |
| return false; |
| TSS_RESULT result = TSS_SUCCESS; |
| ScopedTssKey key(tsp_context_); |
| result = Tspi_Context_CreateObject(tsp_context_, TSS_OBJECT_TYPE_RSAKEY, |
| GetKeyFlags(modulus_bits), key.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_CreateObject - " << ResultToString(result); |
| return false; |
| } |
| if (public_exponent != default_exponent_) { |
| LOG(WARNING) << "Non-Default Public Exponent: " |
| << PrintIntVector(ConvertByteStringToVector(public_exponent)); |
| result = Tspi_SetAttribData( |
| key, TSS_TSPATTRIB_RSAKEY_INFO, TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT, |
| public_exponent.length(), |
| ConvertStringToByteBuffer(public_exponent.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribData(EXPONENT) - " << ResultToString(result); |
| return false; |
| } |
| } |
| if (!CreateKeyPolicy(key, auth_data, false)) |
| return false; |
| result = Tspi_Key_CreateKey(key, srk_, 0); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Key_CreateKey - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_Key_LoadKey(key, srk_); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Key_LoadKey - " << ResultToString(result); |
| return false; |
| } |
| if (!GetKeyBlob(key, key_blob)) |
| return false; |
| *key_handle = CreateHandle(slot, key.release(), *key_blob, auth_data); |
| VLOG(1) << "TPMUtilityImpl::GenerateRSAKey success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::GetRSAPublicKey(int key_handle, |
| string* public_exponent, |
| string* modulus) { |
| VLOG(1) << "TPMUtilityImpl::GetRSAPublicKey enter"; |
| if (!InitSRK()) |
| return false; |
| if (!GetKeyAttributeData(GetTssHandle(key_handle), TSS_TSPATTRIB_RSAKEY_INFO, |
| TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT, public_exponent)) |
| return false; |
| if (!GetKeyAttributeData(GetTssHandle(key_handle), TSS_TSPATTRIB_RSAKEY_INFO, |
| TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, modulus)) |
| return false; |
| VLOG(1) << "TPMUtilityImpl::GetRSAPublicKey success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::IsECCurveSupported(int curve_nid) { |
| return false; |
| } |
| |
| bool TPMUtilityImpl::GenerateECCKey(int slot, |
| int nid, |
| const brillo::SecureBlob& auth_data, |
| std::string* key_blob, |
| int* key_handle) { |
| LOG(ERROR) << __func__ << "TPM 1.2 doesn't support ECC."; |
| return false; |
| } |
| |
| bool TPMUtilityImpl::GetECCPublicKey(int key_handle, |
| std::string* public_point) { |
| LOG(ERROR) << __func__ << "TPM 1.2 doesn't support ECC."; |
| return false; |
| } |
| |
| bool TPMUtilityImpl::WrapRSAKey(int slot, |
| const string& public_exponent, |
| const string& modulus, |
| const string& prime_factor, |
| const SecureBlob& auth_data, |
| string* key_blob, |
| int* key_handle) { |
| VLOG(1) << "TPMUtilityImpl::WrapRSAKey enter"; |
| if (!InitSRK()) |
| return false; |
| if (!GetSRKPublicKey()) |
| return false; |
| ScopedTssKey key(tsp_context_); |
| TSS_RESULT result = |
| Tspi_Context_CreateObject(tsp_context_, TSS_OBJECT_TYPE_RSAKEY, |
| GetKeyFlags(modulus.length() * 8), key.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_CreateObject - " << ResultToString(result); |
| return false; |
| } |
| if (public_exponent != default_exponent_) { |
| LOG(WARNING) << "Non-Default Public Exponent: " |
| << PrintIntVector(ConvertByteStringToVector(public_exponent)); |
| result = Tspi_SetAttribData( |
| key, TSS_TSPATTRIB_RSAKEY_INFO, TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT, |
| public_exponent.length(), |
| ConvertStringToByteBuffer(public_exponent.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribData(EXPONENT) - " << ResultToString(result); |
| return false; |
| } |
| } |
| result = Tspi_SetAttribData( |
| key, TSS_TSPATTRIB_RSAKEY_INFO, TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, |
| modulus.length(), ConvertStringToByteBuffer(modulus.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribData(MODULUS) - " << ResultToString(result); |
| return false; |
| } |
| // The private parameter here is one of the prime factors (p or q). The reason |
| // is that they are half the size of the modulus and from one factor (and the |
| // modulus) the entire private key can be derived. The small size allows the |
| // key to be wrapped in a single operation by another key of the same size. |
| // See TPM_STORE_ASYMKEY in TPM Main Part 2 v1.2 r116 section 10.6 page 92. |
| result = Tspi_SetAttribData( |
| key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY, |
| prime_factor.length(), ConvertStringToByteBuffer(prime_factor.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribData(FACTOR) - " << ResultToString(result); |
| return false; |
| } |
| if (!CreateKeyPolicy(key, auth_data, false)) |
| return false; |
| result = Tspi_Key_WrapKey(key, srk_, 0); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Key_WrapKey - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_Key_LoadKey(key, srk_); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Key_LoadKey - " << ResultToString(result); |
| return false; |
| } |
| if (!GetKeyBlob(key, key_blob)) |
| return false; |
| *key_handle = CreateHandle(slot, key.release(), *key_blob, auth_data); |
| VLOG(1) << "TPMUtilityImpl::WrapRSAKey success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::WrapECCKey(int slot, |
| int curve_nid, |
| const std::string& public_point_x, |
| const std::string& public_point_y, |
| const std::string& private_value, |
| const brillo::SecureBlob& auth_data, |
| std::string* key_blob, |
| int* key_handle) { |
| LOG(ERROR) << __func__ << "TPM 1.2 doesn't support ECC."; |
| return false; |
| } |
| |
| bool TPMUtilityImpl::LoadKey(int slot, |
| const string& key_blob, |
| const SecureBlob& auth_data, |
| int* key_handle) { |
| // Use the SRK as the parent. This is the normal case. |
| return LoadKeyWithParent(slot, key_blob, auth_data, srk_, key_handle); |
| } |
| |
| bool TPMUtilityImpl::LoadKeyWithParent(int slot, |
| const string& key_blob, |
| const SecureBlob& auth_data, |
| int parent_key_handle, |
| int* key_handle) { |
| // Call the internal function. |
| return LoadKeyWithParentInternal(slot, key_blob, auth_data, parent_key_handle, |
| key_handle); |
| } |
| |
| bool TPMUtilityImpl::LoadKeyWithParentInternal(std::optional<int> slot, |
| const string& key_blob, |
| const SecureBlob& auth_data, |
| int parent_key_handle, |
| int* key_handle) { |
| if (!InitSRK()) |
| return false; |
| if (slot.has_value() && IsAlreadyLoaded(slot.value(), key_blob, key_handle)) |
| return true; |
| VLOG(1) << "TPMUtilityImpl::LoadKeyWithParent enter"; |
| ScopedTssKey key(tsp_context_); |
| if (!LoadKeyInternal(GetTssHandle(parent_key_handle), key_blob, auth_data, |
| key.ptr())) |
| return false; |
| *key_handle = CreateHandle(slot, key.release(), key_blob, auth_data); |
| VLOG(1) << "TPMUtilityImpl::LoadKeyWithParent success"; |
| return true; |
| } |
| |
| void TPMUtilityImpl::UnloadKeysForSlot(int slot) { |
| VLOG(1) << "TPMUtilityImpl::UnloadKeysForSlot enter"; |
| if (!InitSRK()) |
| return; |
| set<int>* handles = &slot_handles_[slot].handles_; |
| set<int>::iterator it; |
| for (it = handles->begin(); it != handles->end(); ++it) { |
| FlushHandle(*it); |
| } |
| slot_handles_.erase(slot); |
| LOG(INFO) << "Unloaded keys for slot " << slot; |
| VLOG(1) << "TPMUtilityImpl::UnloadKeysForSlot success"; |
| } |
| |
| bool TPMUtilityImpl::Bind(int key_handle, const string& input, string* output) { |
| VLOG(1) << "TPMUtilityImpl::Bind enter"; |
| if (!InitSRK()) |
| return false; |
| TSSEncryptedData encrypted(tsp_context_); |
| if (!encrypted.Create()) |
| return false; |
| TSS_RESULT result = |
| Tspi_Data_Bind(encrypted, GetTssHandle(key_handle), input.length(), |
| ConvertStringToByteBuffer(input.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Data_Bind - " << ResultToString(result); |
| return false; |
| } |
| if (!encrypted.GetData(output)) |
| return false; |
| VLOG(1) << "TPMUtilityImpl::Bind success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::Unbind(int key_handle, |
| const string& input, |
| string* output) { |
| VLOG(1) << "TPMUtilityImpl::Unbind enter"; |
| if (!InitSRK()) |
| return false; |
| TSSEncryptedData encrypted(tsp_context_); |
| if (!encrypted.Create()) |
| return false; |
| if (!encrypted.SetData(input)) |
| return false; |
| UINT32 length = 0; |
| BYTE* buffer = NULL; |
| TSS_RESULT result = |
| Tspi_Data_Unbind(encrypted, GetTssHandle(key_handle), &length, &buffer); |
| if (result == (TSS_LAYER_TCS | TCS_E_KM_LOADFAILED)) { |
| // On some TPMs, the TCS layer will fail to reload a key that has been |
| // evicted. If this occurs, we can attempt to reload the key manually and |
| // then try the operation again. |
| LOG(WARNING) << "TCS load failure: attempting to reload key."; |
| if (!ReloadKey(key_handle)) |
| return false; |
| result = |
| Tspi_Data_Unbind(encrypted, GetTssHandle(key_handle), &length, &buffer); |
| } |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Data_Unbind - " << ResultToString(result); |
| return false; |
| } |
| *output = ConvertByteBufferToString(buffer, length); |
| Tspi_Context_FreeMemory(tsp_context_, buffer); |
| VLOG(1) << "TPMUtilityImpl::Unbind success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::Sign(int key_handle, |
| CK_MECHANISM_TYPE signing_mechanism, |
| const std::string& mechanism_parameter, |
| const string& input, |
| string* signature) { |
| VLOG(1) << "TPMUtilityImpl::Sign enter"; |
| DigestAlgorithm digest_algorithm = GetDigestAlgorithm(signing_mechanism); |
| |
| // Using the TSS_SS_RSASSAPKCS1V15_DER scheme, we need to manually |
| // insert the hash OID. |
| std::string data_to_sign = |
| GetDigestAlgorithmEncoding(digest_algorithm) + input; |
| if (!InitSRK()) |
| return false; |
| TSSHash hash(tsp_context_); |
| if (!hash.Create(data_to_sign)) |
| return false; |
| |
| // Tspi_Hash_Sign only do PKCS#1 v1.5, and only the mechanisms below match. |
| if (GetSigningSchemeForMechanism(signing_mechanism) != |
| RsaPaddingScheme::RSASSA_PKCS1_V1_5) { |
| LOG(ERROR) << "Unsupported mechanism for tpm1.2 key " << signing_mechanism; |
| return false; |
| } |
| |
| UINT32 length = 0; |
| BYTE* buffer = NULL; |
| TSS_RESULT result = |
| Tspi_Hash_Sign(hash, GetTssHandle(key_handle), &length, &buffer); |
| if (result == (TSS_LAYER_TCS | TCS_E_KM_LOADFAILED)) { |
| // On some TPMs, the TCS layer will fail to reload a key that has been |
| // evicted. If this occurs, we can attempt to reload the key manually and |
| // then try the operation again. |
| LOG(WARNING) << "TCS load failure: attempting to reload key."; |
| if (!ReloadKey(key_handle)) |
| return false; |
| result = Tspi_Hash_Sign(hash, GetTssHandle(key_handle), &length, &buffer); |
| } |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Hash_Sign - " << ResultToString(result); |
| return false; |
| } |
| *signature = ConvertByteBufferToString(buffer, length); |
| Tspi_Context_FreeMemory(tsp_context_, buffer); |
| VLOG(1) << "TPMUtilityImpl::Sign success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::IsSRKReady() { |
| VLOG(1) << "TPMUtilityImpl::IsSRKReady"; |
| if (!tpm_manager_utility_) { |
| LOG(ERROR) << "Accessing invalid tpm_manager utility."; |
| return false; |
| } |
| bool is_enabled = false; |
| bool is_owned = false; |
| bool is_owner_password_present = false; |
| bool has_reset_lock_permissions = false; |
| if (!tpm_manager_utility_->GetTpmNonsensitiveStatus( |
| &is_enabled, &is_owned, &is_owner_password_present, |
| &has_reset_lock_permissions)) { |
| LOG(ERROR) << ": failed to get TPM status from tpm_manager."; |
| return false; |
| } |
| return is_enabled && is_owned && InitSRK(); |
| } |
| |
| int TPMUtilityImpl::CreateHandle(std::optional<int> slot, |
| TSS_HKEY key, |
| const string& key_blob, |
| const SecureBlob& auth_data) { |
| int handle = ++last_handle_; |
| if (slot.has_value()) { |
| HandleInfo* handle_info = &slot_handles_[slot.value()]; |
| handle_info->handles_.insert(handle); |
| handle_info->blob_handle_[key_blob] = handle; |
| } |
| KeyInfo* key_info = &handle_info_[handle]; |
| key_info->tss_handle = key; |
| key_info->blob = key_blob; |
| key_info->auth_data = auth_data; |
| return handle; |
| } |
| |
| void TPMUtilityImpl::FlushHandle(int handle) { |
| TSS_HKEY tss_handle = GetTssHandle(handle); |
| Tspi_Key_UnloadKey(tss_handle); |
| Tspi_Context_CloseObject(tsp_context_, tss_handle); |
| handle_info_.erase(handle); |
| } |
| |
| bool TPMUtilityImpl::CreateKeyPolicy(TSS_HKEY key, |
| const SecureBlob& auth_data, |
| bool auth_only) { |
| ScopedTssPolicy policy(tsp_context_); |
| TSS_RESULT result = Tspi_Context_CreateObject( |
| tsp_context_, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, policy.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_CreateObject - " << ResultToString(result); |
| return false; |
| } |
| if (auth_data.empty()) { |
| result = Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_NONE, 0, NULL); |
| } else { |
| result = |
| Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_SHA1, auth_data.size(), |
| const_cast<BYTE*>(auth_data.data())); |
| } |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_SetSecret - " << ResultToString(result); |
| return false; |
| } |
| if (!auth_only) { |
| result = Tspi_SetAttribUint32(key, TSS_TSPATTRIB_KEY_INFO, |
| TSS_TSPATTRIB_KEYINFO_ENCSCHEME, |
| TSS_ES_RSAESPKCSV15); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribUint(ENCSCHEME) - " |
| << ResultToString(result); |
| return false; |
| } |
| result = Tspi_SetAttribUint32(key, TSS_TSPATTRIB_KEY_INFO, |
| TSS_TSPATTRIB_KEYINFO_SIGSCHEME, |
| TSS_SS_RSASSAPKCS1V15_DER); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribUint(SIGSCHEME) - " |
| << ResultToString(result); |
| return false; |
| } |
| ScopedTssPolicy migration_policy(tsp_context_); |
| result = |
| Tspi_Context_CreateObject(tsp_context_, TSS_OBJECT_TYPE_POLICY, |
| TSS_POLICY_MIGRATION, migration_policy.ptr()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_SetAttribUint(SIGSCHEME) - " |
| << ResultToString(result); |
| return false; |
| } |
| // We need to set a migration policy but we don't want the key to be |
| // migratable. We'll set random authorization data and then discard it. |
| const int kSha1OutputBytes = 20; |
| unsigned char discard[kSha1OutputBytes]; |
| RAND_bytes(discard, kSha1OutputBytes); |
| result = Tspi_Policy_SetSecret(migration_policy, TSS_SECRET_MODE_SHA1, |
| kSha1OutputBytes, discard); |
| brillo::SecureClearContainer(discard); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_SetSecret - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_Policy_AssignToObject(migration_policy.release(), key); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_AssignToObject - " << ResultToString(result); |
| return false; |
| } |
| } |
| result = Tspi_Policy_AssignToObject(policy.release(), key); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_AssignToObject - " << ResultToString(result); |
| return false; |
| } |
| return true; |
| } |
| |
| bool TPMUtilityImpl::GetKeyAttributeData(TSS_HKEY key, |
| TSS_FLAG flag, |
| TSS_FLAG sub_flag, |
| string* data) { |
| UINT32 length = 0; |
| BYTE* buffer = NULL; |
| TSS_RESULT result = Tspi_GetAttribData(key, flag, sub_flag, &length, &buffer); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_GetAttribData(" << flag << ", " << sub_flag << ") - " |
| << ResultToString(result); |
| return false; |
| } |
| *data = ConvertByteBufferToString(buffer, length); |
| Tspi_Context_FreeMemory(tsp_context_, buffer); |
| return true; |
| } |
| |
| bool TPMUtilityImpl::GetKeyBlob(TSS_HKEY key, string* blob) { |
| return GetKeyAttributeData(key, TSS_TSPATTRIB_KEY_BLOB, |
| TSS_TSPATTRIB_KEYBLOB_BLOB, blob); |
| } |
| |
| TSS_FLAG TPMUtilityImpl::GetKeyFlags(int modulus_bits) { |
| // We want the keys we create / wrap to be capable of signing and binding. |
| // This means we need to use the 'legacy' key type. Keys of this type are |
| // migratable by definition. See TCG Architecture Overview 1.4: 4.2.7.2. |
| TSS_FLAG flags = |
| TSS_KEY_TYPE_LEGACY | TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE; |
| if (modulus_bits == TSS_KEY_SIZEVAL_512BIT) { |
| flags |= TSS_KEY_SIZE_512; |
| } else if (modulus_bits == TSS_KEY_SIZEVAL_1024BIT) { |
| flags |= TSS_KEY_SIZE_1024; |
| } else if (modulus_bits == TSS_KEY_SIZEVAL_2048BIT) { |
| flags |= TSS_KEY_SIZE_2048; |
| } else if (modulus_bits == TSS_KEY_SIZEVAL_4096BIT) { |
| flags |= TSS_KEY_SIZE_4096; |
| } else if (modulus_bits == TSS_KEY_SIZEVAL_8192BIT) { |
| flags |= TSS_KEY_SIZE_8192; |
| } else if (modulus_bits == TSS_KEY_SIZEVAL_16384BIT) { |
| flags |= TSS_KEY_SIZE_16384; |
| } else { |
| flags |= TSS_KEY_SIZE_DEFAULT; |
| } |
| return flags; |
| } |
| |
| bool TPMUtilityImpl::GetSRKPublicKey() { |
| // In order to wrap a key with the SRK we need access to the SRK public key |
| // and we need to get it manually. Once it's in the key object, we don't need |
| // to do this again. |
| if (!srk_public_loaded_) { |
| UINT32 length = 0; |
| BYTE* buffer = NULL; |
| TSS_RESULT result = Tspi_Key_GetPubKey(srk_, &length, &buffer); |
| if (result != TSS_SUCCESS) { |
| if (result == TPM_E_INVALID_KEYHANDLE) { |
| LOG(ERROR) << "The TPM is not configured to allow reading the public " |
| << "SRK. Use 'tpm_restrictsrk -a' to allow this."; |
| } else { |
| LOG(ERROR) << "Tspi_Key_GetPubKey - " << ResultToString(result); |
| } |
| return false; |
| } |
| Tspi_Context_FreeMemory(tsp_context_, buffer); |
| srk_public_loaded_ = true; |
| } |
| return true; |
| } |
| |
| TSS_HKEY TPMUtilityImpl::GetTssHandle(int key_handle) { |
| if (static_cast<TSS_HKEY>(key_handle) == srk_) |
| return srk_; |
| map<int, KeyInfo>::iterator it = handle_info_.find(key_handle); |
| if (it == handle_info_.end()) |
| return 0; |
| return it->second.tss_handle; |
| } |
| |
| bool TPMUtilityImpl::IsAlreadyLoaded(int slot, |
| const string& key_blob, |
| int* key_handle) { |
| HandleInfo* handle_info = &slot_handles_[slot]; |
| map<string, int>::iterator it = handle_info->blob_handle_.find(key_blob); |
| if (it == handle_info->blob_handle_.end()) |
| return false; |
| *key_handle = it->second; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::LoadKeyInternal(TSS_HKEY parent, |
| const string& key_blob, |
| const SecureBlob& auth_data, |
| TSS_HKEY* key) { |
| TSS_RESULT result = Tspi_Context_LoadKeyByBlob( |
| tsp_context_, parent, key_blob.length(), |
| ConvertStringToByteBuffer(key_blob.data()), key); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_LoadKeyByBlob - " << ResultToString(result); |
| return false; |
| } |
| TSS_HPOLICY policy; |
| result = Tspi_GetPolicyObject(*key, TSS_POLICY_USAGE, &policy); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_GetPolicyObject - " << ResultToString(result); |
| return false; |
| } |
| if (policy == default_policy_) { |
| if (!CreateKeyPolicy(*key, auth_data, true)) |
| return false; |
| } else if (auth_data.empty()) { |
| result = Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_NONE, 0, NULL); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_SetSecret - " << ResultToString(result); |
| return false; |
| } |
| } else { |
| result = |
| Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_SHA1, auth_data.size(), |
| const_cast<BYTE*>(auth_data.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Policy_SetSecret - " << ResultToString(result); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool TPMUtilityImpl::ReloadKey(int key_handle) { |
| KeyInfo* key_info = &handle_info_[key_handle]; |
| // Unload the current handle. |
| Tspi_Key_UnloadKey(key_info->tss_handle); |
| Tspi_Context_CloseObject(tsp_context_, key_info->tss_handle); |
| key_info->tss_handle = 0; |
| // Load the same key blob again. |
| ScopedTssKey scoped_key(tsp_context_); |
| if (!LoadKeyInternal(srk_, key_info->blob, key_info->auth_data, |
| scoped_key.ptr())) { |
| LOG(ERROR) << "Failed to reload key."; |
| return false; |
| } |
| key_info->tss_handle = scoped_key.release(); |
| return true; |
| } |
| |
| bool TPMUtilityImpl::SealData(const std::string& unsealed_data, |
| const brillo::SecureBlob& auth_value, |
| std::string* key_blob, |
| std::string* encrypted_data) { |
| // No need to lock here, because GenerateRSAKey & Bind would acquire the lock. |
| int auth_key_handle; |
| if (!GenerateRSAKeyInternal(std::nullopt, kKeySizeForSealingData, |
| default_exponent_, auth_value, key_blob, |
| &auth_key_handle)) { |
| LOG(ERROR) << "Failed to generate authentication key for sealing data."; |
| return false; |
| } |
| if (!Bind(auth_key_handle, unsealed_data, encrypted_data)) { |
| LOG(ERROR) << "Failed to bind encryption key for sealing data."; |
| FlushHandle(auth_key_handle); |
| return false; |
| } |
| FlushHandle(auth_key_handle); |
| return true; |
| } |
| |
| bool TPMUtilityImpl::UnsealData(const std::string& key_blob, |
| const std::string& encrypted_data, |
| const brillo::SecureBlob& auth_value, |
| brillo::SecureBlob* unsealed_data) { |
| if (!Authenticate(auth_value, key_blob, encrypted_data, unsealed_data)) { |
| LOG(ERROR) << "Authentication failed for unsealing data."; |
| return false; |
| } |
| return true; |
| } |
| |
| string TPMUtilityImpl::ResultToString(TSS_RESULT result) { |
| if (result == TSS_SUCCESS) |
| return "TSS_SUCCESS"; |
| TSS_RESULT layer = ERROR_LAYER(result); |
| TSS_RESULT code = ERROR_CODE(result); |
| if (layer == TSS_LAYER_TPM) { |
| switch (code) { |
| case TPM_E_AUTHFAIL: |
| return "TPM_E_AUTHFAIL"; |
| case TPM_E_BADINDEX: |
| return "TPM_E_BADINDEX"; |
| case TPM_E_BAD_PARAMETER: |
| return "TPM_E_BAD_PARAMETER"; |
| case TPM_E_AUDITFAILURE: |
| return "TPM_E_AUDITFAILURE"; |
| case TPM_E_CLEAR_DISABLED: |
| return "TPM_E_CLEAR_DISABLED"; |
| case TPM_E_DEACTIVATED: |
| return "TPM_E_DEACTIVATED"; |
| case TPM_E_DISABLED: |
| return "TPM_E_DISABLED"; |
| case TPM_E_DISABLED_CMD: |
| return "TPM_E_DISABLED_CMD"; |
| case TPM_E_FAIL: |
| return "TPM_E_FAIL"; |
| case TPM_E_BAD_ORDINAL: |
| return "TPM_E_BAD_ORDINAL"; |
| case TPM_E_INSTALL_DISABLED: |
| return "TPM_E_INSTALL_DISABLED"; |
| case TPM_E_INVALID_KEYHANDLE: |
| return "TPM_E_INVALID_KEYHANDLE"; |
| case TPM_E_KEYNOTFOUND: |
| return "TPM_E_KEYNOTFOUND"; |
| case TPM_E_INAPPROPRIATE_ENC: |
| return "TPM_E_INAPPROPRIATE_ENC"; |
| case TPM_E_MIGRATEFAIL: |
| return "TPM_E_MIGRATEFAIL"; |
| case TPM_E_INVALID_PCR_INFO: |
| return "TPM_E_INVALID_PCR_INFO"; |
| case TPM_E_NOSPACE: |
| return "TPM_E_NOSPACE"; |
| case TPM_E_NOSRK: |
| return "TPM_E_NOSRK"; |
| case TPM_E_NOTSEALED_BLOB: |
| return "TPM_E_NOTSEALED_BLOB"; |
| case TPM_E_OWNER_SET: |
| return "TPM_E_OWNER_SET"; |
| case TPM_E_RESOURCES: |
| return "TPM_E_RESOURCES"; |
| case TPM_E_SHORTRANDOM: |
| return "TPM_E_SHORTRANDOM"; |
| case TPM_E_SIZE: |
| return "TPM_E_SIZE"; |
| case TPM_E_WRONGPCRVAL: |
| return "TPM_E_WRONGPCRVAL"; |
| case TPM_E_BAD_PARAM_SIZE: |
| return "TPM_E_BAD_PARAM_SIZE"; |
| case TPM_E_SHA_THREAD: |
| return "TPM_E_SHA_THREAD"; |
| case TPM_E_SHA_ERROR: |
| return "TPM_E_SHA_ERROR"; |
| case TPM_E_FAILEDSELFTEST: |
| return "TPM_E_FAILEDSELFTEST"; |
| case TPM_E_AUTH2FAIL: |
| return "TPM_E_AUTH2FAIL"; |
| case TPM_E_BADTAG: |
| return "TPM_E_BADTAG"; |
| case TPM_E_IOERROR: |
| return "TPM_E_IOERROR"; |
| case TPM_E_ENCRYPT_ERROR: |
| return "TPM_E_ENCRYPT_ERROR"; |
| case TPM_E_DECRYPT_ERROR: |
| return "TPM_E_DECRYPT_ERROR"; |
| case TPM_E_INVALID_AUTHHANDLE: |
| return "TPM_E_INVALID_AUTHHANDLE"; |
| case TPM_E_NO_ENDORSEMENT: |
| return "TPM_E_NO_ENDORSEMENT"; |
| case TPM_E_INVALID_KEYUSAGE: |
| return "TPM_E_INVALID_KEYUSAGE"; |
| case TPM_E_WRONG_ENTITYTYPE: |
| return "TPM_E_WRONG_ENTITYTYPE"; |
| case TPM_E_INVALID_POSTINIT: |
| return "TPM_E_INVALID_POSTINIT"; |
| case TPM_E_INAPPROPRIATE_SIG: |
| return "TPM_E_INAPPROPRIATE_SIG"; |
| case TPM_E_BAD_KEY_PROPERTY: |
| return "TPM_E_BAD_KEY_PROPERTY"; |
| case TPM_E_BAD_MIGRATION: |
| return "TPM_E_BAD_MIGRATION"; |
| case TPM_E_BAD_SCHEME: |
| return "TPM_E_BAD_SCHEME"; |
| case TPM_E_BAD_DATASIZE: |
| return "TPM_E_BAD_DATASIZE"; |
| case TPM_E_BAD_MODE: |
| return "TPM_E_BAD_MODE"; |
| case TPM_E_BAD_PRESENCE: |
| return "TPM_E_BAD_PRESENCE"; |
| case TPM_E_BAD_VERSION: |
| return "TPM_E_BAD_VERSION"; |
| case TPM_E_NO_WRAP_TRANSPORT: |
| return "TPM_E_NO_WRAP_TRANSPORT"; |
| case TPM_E_AUDITFAIL_UNSUCCESSFUL: |
| return "TPM_E_AUDITFAIL_UNSUCCESSFUL"; |
| case TPM_E_AUDITFAIL_SUCCESSFUL: |
| return "TPM_E_AUDITFAIL_SUCCESSFUL"; |
| case TPM_E_NOTRESETABLE: |
| return "TPM_E_NOTRESETABLE"; |
| case TPM_E_NOTLOCAL: |
| return "TPM_E_NOTLOCAL"; |
| case TPM_E_BAD_TYPE: |
| return "TPM_E_BAD_TYPE"; |
| case TPM_E_INVALID_RESOURCE: |
| return "TPM_E_INVALID_RESOURCE"; |
| case TPM_E_NOTFIPS: |
| return "TPM_E_NOTFIPS"; |
| case TPM_E_INVALID_FAMILY: |
| return "TPM_E_INVALID_FAMILY"; |
| case TPM_E_NO_NV_PERMISSION: |
| return "TPM_E_NO_NV_PERMISSION"; |
| case TPM_E_REQUIRES_SIGN: |
| return "TPM_E_REQUIRES_SIGN"; |
| case TPM_E_KEY_NOTSUPPORTED: |
| return "TPM_E_KEY_NOTSUPPORTED"; |
| case TPM_E_AUTH_CONFLICT: |
| return "TPM_E_AUTH_CONFLICT"; |
| case TPM_E_AREA_LOCKED: |
| return "TPM_E_AREA_LOCKED"; |
| case TPM_E_BAD_LOCALITY: |
| return "TPM_E_BAD_LOCALITY"; |
| case TPM_E_READ_ONLY: |
| return "TPM_E_READ_ONLY"; |
| case TPM_E_PER_NOWRITE: |
| return "TPM_E_PER_NOWRITE"; |
| case TPM_E_FAMILYCOUNT: |
| return "TPM_E_FAMILYCOUNT"; |
| case TPM_E_WRITE_LOCKED: |
| return "TPM_E_WRITE_LOCKED"; |
| case TPM_E_BAD_ATTRIBUTES: |
| return "TPM_E_BAD_ATTRIBUTES"; |
| case TPM_E_INVALID_STRUCTURE: |
| return "TPM_E_INVALID_STRUCTURE"; |
| case TPM_E_KEY_OWNER_CONTROL: |
| return "TPM_E_KEY_OWNER_CONTROL"; |
| case TPM_E_BAD_COUNTER: |
| return "TPM_E_BAD_COUNTER"; |
| case TPM_E_NOT_FULLWRITE: |
| return "TPM_E_NOT_FULLWRITE"; |
| case TPM_E_CONTEXT_GAP: |
| return "TPM_E_CONTEXT_GAP"; |
| case TPM_E_MAXNVWRITES: |
| return "TPM_E_MAXNVWRITES"; |
| case TPM_E_NOOPERATOR: |
| return "TPM_E_NOOPERATOR"; |
| case TPM_E_RESOURCEMISSING: |
| return "TPM_E_RESOURCEMISSING"; |
| case TPM_E_DELEGATE_LOCK: |
| return "TPM_E_DELEGATE_LOCK"; |
| case TPM_E_DELEGATE_FAMILY: |
| return "TPM_E_DELEGATE_FAMILY"; |
| case TPM_E_DELEGATE_ADMIN: |
| return "TPM_E_DELEGATE_ADMIN"; |
| case TPM_E_TRANSPORT_NOTEXCLUSIVE: |
| return "TPM_E_TRANSPORT_NOTEXCLUSIVE"; |
| case TPM_E_OWNER_CONTROL: |
| return "TPM_E_OWNER_CONTROL"; |
| case TPM_E_DAA_RESOURCES: |
| return "TPM_E_DAA_RESOURCES"; |
| case TPM_E_DAA_INPUT_DATA0: |
| return "TPM_E_DAA_INPUT_DATA0"; |
| case TPM_E_DAA_INPUT_DATA1: |
| return "TPM_E_DAA_INPUT_DATA1"; |
| case TPM_E_DAA_ISSUER_SETTINGS: |
| return "TPM_E_DAA_ISSUER_SETTINGS"; |
| case TPM_E_DAA_TPM_SETTINGS: |
| return "TPM_E_DAA_TPM_SETTINGS"; |
| case TPM_E_DAA_STAGE: |
| return "TPM_E_DAA_STAGE"; |
| case TPM_E_DAA_ISSUER_VALIDITY: |
| return "TPM_E_DAA_ISSUER_VALIDITY"; |
| case TPM_E_DAA_WRONG_W: |
| return "TPM_E_DAA_WRONG_W"; |
| case TPM_E_BAD_HANDLE: |
| return "TPM_E_BAD_HANDLE"; |
| case TPM_E_BAD_DELEGATE: |
| return "TPM_E_BAD_DELEGATE"; |
| case TPM_E_BADCONTEXT: |
| return "TPM_E_BADCONTEXT"; |
| case TPM_E_TOOMANYCONTEXTS: |
| return "TPM_E_TOOMANYCONTEXTS"; |
| case TPM_E_MA_TICKET_SIGNATURE: |
| return "TPM_E_MA_TICKET_SIGNATURE"; |
| case TPM_E_MA_DESTINATION: |
| return "TPM_E_MA_DESTINATION"; |
| case TPM_E_MA_SOURCE: |
| return "TPM_E_MA_SOURCE"; |
| case TPM_E_MA_AUTHORITY: |
| return "TPM_E_MA_AUTHORITY"; |
| case TPM_E_PERMANENTEK: |
| return "TPM_E_PERMANENTEK"; |
| case TPM_E_BAD_SIGNATURE: |
| return "TPM_E_BAD_SIGNATURE"; |
| case TPM_E_NOCONTEXTSPACE: |
| return "TPM_E_NOCONTEXTSPACE"; |
| case TPM_E_RETRY: |
| return "TPM_E_RETRY"; |
| case TPM_E_NEEDS_SELFTEST: |
| return "TPM_E_NEEDS_SELFTEST"; |
| case TPM_E_DOING_SELFTEST: |
| return "TPM_E_DOING_SELFTEST"; |
| case TPM_E_DEFEND_LOCK_RUNNING: |
| return "TPM_E_DEFEND_LOCK_RUNNING"; |
| } |
| } else if (layer == TSS_LAYER_TDDL) { |
| switch (code) { |
| case TDDL_E_FAIL: |
| return "TDDL_E_FAIL"; |
| case TDDL_E_TIMEOUT: |
| return "TDDL_E_TIMEOUT"; |
| case TDDL_E_ALREADY_OPENED: |
| return "TDDL_E_ALREADY_OPENED"; |
| case TDDL_E_ALREADY_CLOSED: |
| return "TDDL_E_ALREADY_CLOSED"; |
| case TDDL_E_INSUFFICIENT_BUFFER: |
| return "TDDL_E_INSUFFICIENT_BUFFER"; |
| case TDDL_E_COMMAND_COMPLETED: |
| return "TDDL_E_COMMAND_COMPLETED"; |
| case TDDL_E_COMMAND_ABORTED: |
| return "TDDL_E_COMMAND_ABORTED"; |
| case TDDL_E_IOERROR: |
| return "TDDL_E_IOERROR"; |
| case TDDL_E_BADTAG: |
| return "TDDL_E_BADTAG"; |
| case TDDL_E_COMPONENT_NOT_FOUND: |
| return "TDDL_E_COMPONENT_NOT_FOUND"; |
| } |
| } else if (layer == TSS_LAYER_TCS) { |
| switch (code) { |
| case TCS_E_INVALID_CONTEXTHANDLE: |
| return "TCS_E_INVALID_CONTEXTHANDLE"; |
| case TCS_E_INVALID_KEYHANDLE: |
| return "TCS_E_INVALID_KEYHANDLE"; |
| case TCS_E_INVALID_AUTHHANDLE: |
| return "TCS_E_INVALID_AUTHHANDLE"; |
| case TCS_E_INVALID_AUTHSESSION: |
| return "TCS_E_INVALID_AUTHSESSION"; |
| case TCS_E_INVALID_KEY: |
| return "TCS_E_INVALID_KEY"; |
| case TCS_E_KEY_MISMATCH: |
| return "TCS_E_KEY_MISMATCH"; |
| case TCS_E_KM_LOADFAILED: |
| return "TCS_E_KM_LOADFAILED"; |
| case TCS_E_KEY_CONTEXT_RELOAD: |
| return "TCS_E_KEY_CONTEXT_RELOAD"; |
| case TCS_E_BAD_INDEX: |
| return "TCS_E_BAD_INDEX"; |
| case TCS_E_KEY_ALREADY_REGISTERED: |
| return "TCS_E_KEY_ALREADY_REGISTERED"; |
| case TCS_E_BAD_PARAMETER: |
| return "TCS_E_BAD_PARAMETER"; |
| case TCS_E_OUTOFMEMORY: |
| return "TCS_E_OUTOFMEMORY"; |
| case TCS_E_NOTIMPL: |
| return "TCS_E_NOTIMPL"; |
| case TCS_E_INTERNAL_ERROR: |
| return "TCS_E_INTERNAL_ERROR"; |
| } |
| } else if (layer == TSS_LAYER_TSP) { |
| switch (code) { |
| case TSS_E_FAIL: |
| return "TSS_E_FAIL"; |
| case TSS_E_BAD_PARAMETER: |
| return "TSS_E_BAD_PARAMETER"; |
| case TSS_E_INTERNAL_ERROR: |
| return "TSS_E_INTERNAL_ERROR"; |
| case TSS_E_OUTOFMEMORY: |
| return "TSS_E_OUTOFMEMORY"; |
| case TSS_E_NOTIMPL: |
| return "TSS_E_NOTIMPL"; |
| case TSS_E_KEY_ALREADY_REGISTERED: |
| return "TSS_E_KEY_ALREADY_REGISTERED"; |
| case TSS_E_TPM_UNEXPECTED: |
| return "TSS_E_TPM_UNEXPECTED"; |
| case TSS_E_COMM_FAILURE: |
| return "TSS_E_COMM_FAILURE"; |
| case TSS_E_TIMEOUT: |
| return "TSS_E_TIMEOUT"; |
| case TSS_E_TPM_UNSUPPORTED_FEATURE: |
| return "TSS_E_TPM_UNSUPPORTED_FEATURE"; |
| case TSS_E_CANCELED: |
| return "TSS_E_CANCELED"; |
| case TSS_E_PS_KEY_NOTFOUND: |
| return "TSS_E_PS_KEY_NOTFOUND"; |
| case TSS_E_PS_KEY_EXISTS: |
| return "TSS_E_PS_KEY_EXISTS"; |
| case TSS_E_PS_BAD_KEY_STATE: |
| return "TSS_E_PS_BAD_KEY_STATE"; |
| case TSS_E_INVALID_OBJECT_TYPE: |
| return "TSS_E_INVALID_OBJECT_TYPE"; |
| case TSS_E_NO_CONNECTION: |
| return "TSS_E_NO_CONNECTION"; |
| case TSS_E_CONNECTION_FAILED: |
| return "TSS_E_CONNECTION_FAILED"; |
| case TSS_E_CONNECTION_BROKEN: |
| return "TSS_E_CONNECTION_BROKEN"; |
| case TSS_E_HASH_INVALID_ALG: |
| return "TSS_E_HASH_INVALID_ALG"; |
| case TSS_E_HASH_INVALID_LENGTH: |
| return "TSS_E_HASH_INVALID_LENGTH"; |
| case TSS_E_HASH_NO_DATA: |
| return "TSS_E_HASH_NO_DATA"; |
| case TSS_E_INVALID_ATTRIB_FLAG: |
| return "TSS_E_INVALID_ATTRIB_FLAG"; |
| case TSS_E_INVALID_ATTRIB_SUBFLAG: |
| return "TSS_E_INVALID_ATTRIB_SUBFLAG"; |
| case TSS_E_INVALID_ATTRIB_DATA: |
| return "TSS_E_INVALID_ATTRIB_DATA"; |
| case TSS_E_INVALID_OBJECT_INITFLAG: |
| return "TSS_E_INVALID_OBJECT_INITFLAG"; |
| case TSS_E_NO_PCRS_SET: |
| return "TSS_E_NO_PCRS_SET"; |
| case TSS_E_KEY_NOT_LOADED: |
| return "TSS_E_KEY_NOT_LOADED"; |
| case TSS_E_KEY_NOT_SET: |
| return "TSS_E_KEY_NOT_SET"; |
| case TSS_E_VALIDATION_FAILED: |
| return "TSS_E_VALIDATION_FAILED"; |
| case TSS_E_TSP_AUTHREQUIRED: |
| return "TSS_E_TSP_AUTHREQUIRED"; |
| case TSS_E_TSP_AUTH2REQUIRED: |
| return "TSS_E_TSP_AUTH2REQUIRED"; |
| case TSS_E_TSP_AUTHFAIL: |
| return "TSS_E_TSP_AUTHFAIL"; |
| case TSS_E_TSP_AUTH2FAIL: |
| return "TSS_E_TSP_AUTH2FAIL"; |
| case TSS_E_KEY_NO_MIGRATION_POLICY: |
| return "TSS_E_KEY_NO_MIGRATION_POLICY"; |
| case TSS_E_POLICY_NO_SECRET: |
| return "TSS_E_POLICY_NO_SECRET"; |
| case TSS_E_INVALID_OBJ_ACCESS: |
| return "TSS_E_INVALID_OBJ_ACCESS"; |
| case TSS_E_INVALID_ENCSCHEME: |
| return "TSS_E_INVALID_ENCSCHEME"; |
| case TSS_E_INVALID_SIGSCHEME: |
| return "TSS_E_INVALID_SIGSCHEME"; |
| case TSS_E_ENC_INVALID_LENGTH: |
| return "TSS_E_ENC_INVALID_LENGTH"; |
| case TSS_E_ENC_NO_DATA: |
| return "TSS_E_ENC_NO_DATA"; |
| case TSS_E_ENC_INVALID_TYPE: |
| return "TSS_E_ENC_INVALID_TYPE"; |
| case TSS_E_INVALID_KEYUSAGE: |
| return "TSS_E_INVALID_KEYUSAGE"; |
| case TSS_E_VERIFICATION_FAILED: |
| return "TSS_E_VERIFICATION_FAILED"; |
| case TSS_E_HASH_NO_IDENTIFIER: |
| return "TSS_E_HASH_NO_IDENTIFIER"; |
| case TSS_E_INVALID_HANDLE: |
| return "TSS_E_INVALID_HANDLE"; |
| case TSS_E_SILENT_CONTEXT: |
| return "TSS_E_SILENT_CONTEXT"; |
| case TSS_E_EK_CHECKSUM: |
| return "TSS_E_EK_CHECKSUM"; |
| case TSS_E_DELEGATION_NOTSET: |
| return "TSS_E_DELEGATION_NOTSET"; |
| case TSS_E_DELFAMILY_NOTFOUND: |
| return "TSS_E_DELFAMILY_NOTFOUND"; |
| case TSS_E_DELFAMILY_ROWEXISTS: |
| return "TSS_E_DELFAMILY_ROWEXISTS"; |
| case TSS_E_VERSION_MISMATCH: |
| return "TSS_E_VERSION_MISMATCH"; |
| case TSS_E_DAA_AR_DECRYPTION_ERROR: |
| return "TSS_E_DAA_AR_DECRYPTION_ERROR"; |
| case TSS_E_DAA_AUTHENTICATION_ERROR: |
| return "TSS_E_DAA_AUTHENTICATION_ERROR"; |
| case TSS_E_DAA_CHALLENGE_RESPONSE_ERROR: |
| return "TSS_E_DAA_CHALLENGE_RESPONSE_ERROR"; |
| case TSS_E_DAA_CREDENTIAL_PROOF_ERROR: |
| return "TSS_E_DAA_CREDENTIAL_PROOF_ERROR"; |
| case TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR: |
| return "TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR"; |
| case TSS_E_DAA_ISSUER_KEY_ERROR: |
| return "TSS_E_DAA_ISSUER_KEY_ERROR"; |
| case TSS_E_DAA_PSEUDONYM_ERROR: |
| return "TSS_E_DAA_PSEUDONYM_ERROR"; |
| case TSS_E_INVALID_RESOURCE: |
| return "TSS_E_INVALID_RESOURCE"; |
| case TSS_E_NV_AREA_EXIST: |
| return "TSS_E_NV_AREA_EXIST"; |
| case TSS_E_NV_AREA_NOT_EXIST: |
| return "TSS_E_NV_AREA_NOT_EXIST"; |
| case TSS_E_TSP_TRANS_AUTHFAIL: |
| return "TSS_E_TSP_TRANS_AUTHFAIL"; |
| case TSS_E_TSP_TRANS_AUTHREQUIRED: |
| return "TSS_E_TSP_TRANS_AUTHREQUIRED"; |
| case TSS_E_TSP_TRANS_NOTEXCLUSIVE: |
| return "TSS_E_TSP_TRANS_NOTEXCLUSIVE"; |
| case TSS_E_TSP_TRANS_FAIL: |
| return "TSS_E_TSP_TRANS_FAIL"; |
| case TSS_E_TSP_TRANS_NO_PUBKEY: |
| return "TSS_E_TSP_TRANS_NO_PUBKEY"; |
| case TSS_E_NO_ACTIVE_COUNTER: |
| return "TSS_E_NO_ACTIVE_COUNTER"; |
| } |
| } |
| // Unknown value, just give the hex numeric value. |
| stringstream ss; |
| ss << "0x" << hex << result; |
| return ss.str(); |
| } |
| |
| } // namespace chaps |