| // 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 <set> |
| #include <sstream> |
| #include <string> |
| |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/logging.h> |
| #include <base/synchronization/lock.h> |
| #include <chromeos/secure_blob.h> |
| #include <openssl/rand.h> |
| #include <trousers/scoped_tss_type.h> |
| #include <trousers/tss.h> |
| |
| #include "chaps/chaps_utility.h" |
| |
| using base::AutoLock; |
| using chromeos::SecureBlob; |
| using trousers::ScopedTssContext; |
| using trousers::ScopedTssKey; |
| using trousers::ScopedTssObject; |
| using trousers::ScopedTssPolicy; |
| using std::hex; |
| using std::map; |
| using std::set; |
| using std::string; |
| using std::stringstream; |
| |
| 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) {} |
| 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_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TSSEncryptedData); |
| }; |
| |
| // 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) {} |
| 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_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TSSHash); |
| }; |
| |
| 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), |
| is_enabled_(false), |
| is_enabled_ready_(false) {} |
| |
| 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) { |
| Tspi_Key_UnloadKey(GetTssHandle(*it2)); |
| Tspi_Context_CloseObject(tsp_context_, GetTssHandle(*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() { |
| if (is_initialized_) |
| return true; |
| VLOG(1) << "TPMUtilityImpl::Init enter"; |
| AutoLock lock(lock_); |
| 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; |
| } |
| // Make sure we can communicate with the TPM. |
| TSS_HTPM tpm; |
| result = Tspi_Context_GetTpmObject(tsp_context_, &tpm); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Context_GetTpmObject - " << ResultToString(result); |
| return false; |
| } |
| BYTE *random_bytes = NULL; |
| result = Tspi_TPM_GetRandom(tpm, 4, &random_bytes); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_TPM_GetRandom - " << ResultToString(result); |
| return false; |
| } |
| Tspi_Context_FreeMemory(tsp_context_, random_bytes); |
| VLOG(1) << "TPMUtilityImpl::Init success"; |
| is_initialized_ = true; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::IsTPMAvailable() { |
| if (is_enabled_ready_) { |
| return is_enabled_; |
| } |
| // If the TPM works, clearly it's available. |
| if (is_initialized_) { |
| is_enabled_ready_ = true; |
| is_enabled_ = true; |
| return true; |
| } |
| // If the system says there is an enabled TPM, expect to use it. |
| const base::FilePath kTpmEnabledFile("/sys/class/misc/tpm0/device/enabled"); |
| string file_content; |
| if (base::ReadFileToString(kTpmEnabledFile, &file_content) && |
| !file_content.empty() && |
| file_content[0] == '1') { |
| is_enabled_ = true; |
| } |
| is_enabled_ready_ = true; |
| return is_enabled_; |
| } |
| |
| 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(int slot_id, |
| const SecureBlob& auth_data, |
| const string& auth_key_blob, |
| const string& encrypted_master_key, |
| SecureBlob* master_key) { |
| VLOG(1) << "TPMUtilityImpl::Authenticate enter"; |
| int key_handle = 0; |
| if (!LoadKey(slot_id, auth_key_blob, auth_data, &key_handle)) |
| return false; |
| string master_key_str; |
| if (!Unbind(key_handle, encrypted_master_key, &master_key_str)) |
| return false; |
| *master_key = SecureBlob(master_key_str.begin(), master_key_str.end()); |
| ClearString(&master_key_str); |
| VLOG(1) << "TPMUtilityImpl::Authenticate success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::ChangeAuthData(int slot_id, |
| 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 (!LoadKey(slot_id, old_auth_key_blob, old_auth_data, &key_handle)) |
| return false; |
| // Make sure the old auth data is ok. |
| string encrypted, decrypted; |
| if (!Bind(key_handle, "testdata", &encrypted)) |
| return false; |
| if (!Unbind(key_handle, encrypted, &decrypted)) |
| return false; |
| // Change the secret. |
| AutoLock lock(lock_); |
| 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) { |
| 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) { |
| LOG(ERROR) << "Tspi_Policy_SetSecret - " << ResultToString(result); |
| return false; |
| } |
| result = Tspi_ChangeAuth(GetTssHandle(key_handle), srk_, policy.release()); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_ChangeAuth - " << ResultToString(result); |
| return false; |
| } |
| if (!GetKeyBlob(GetTssHandle(key_handle), new_auth_key_blob)) |
| return false; |
| VLOG(1) << "TPMUtilityImpl::ChangeAuthData success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::GenerateRandom(int num_bytes, string* random_data) { |
| VLOG(1) << "TPMUtilityImpl::GenerateRandom enter"; |
| AutoLock lock(lock_); |
| 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"; |
| AutoLock lock(lock_); |
| 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::GenerateKey(int slot, |
| int modulus_bits, |
| const string& public_exponent, |
| const SecureBlob& auth_data, |
| string* key_blob, |
| int* key_handle) { |
| VLOG(1) << "TPMUtilityImpl::GenerateKey enter"; |
| AutoLock lock(lock_); |
| 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::GenerateKey success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::GetPublicKey(int key_handle, |
| string* public_exponent, |
| string* modulus) { |
| VLOG(1) << "TPMUtilityImpl::GetPublicKey enter"; |
| AutoLock lock(lock_); |
| 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::GetPublicKey success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::WrapKey(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::WrapKey enter"; |
| AutoLock lock(lock_); |
| 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::WrapKey success"; |
| return true; |
| } |
| |
| 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) { |
| AutoLock lock(lock_); |
| if (!InitSRK()) |
| return false; |
| if (IsAlreadyLoaded(slot, 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"; |
| AutoLock lock(lock_); |
| if (!InitSRK()) |
| return; |
| set<int>* handles = &slot_handles_[slot].handles_; |
| set<int>::iterator it; |
| for (it = handles->begin(); it != handles->end(); ++it) { |
| Tspi_Key_UnloadKey(GetTssHandle(*it)); |
| Tspi_Context_CloseObject(tsp_context_, GetTssHandle(*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"; |
| AutoLock lock(lock_); |
| 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"; |
| AutoLock lock(lock_); |
| 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, |
| const string& input, |
| string* signature) { |
| VLOG(1) << "TPMUtilityImpl::Sign enter"; |
| AutoLock lock(lock_); |
| if (!InitSRK()) |
| return false; |
| TSSHash hash(tsp_context_); |
| if (!hash.Create(input)) |
| 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::Verify(int key_handle, |
| const string& input, |
| const string& signature) { |
| VLOG(1) << "TPMUtilityImpl::Verify enter"; |
| AutoLock lock(lock_); |
| if (!InitSRK()) |
| return false; |
| TSSHash hash(tsp_context_); |
| if (!hash.Create(input)) |
| return false; |
| TSS_RESULT result = Tspi_Hash_VerifySignature( |
| hash, |
| GetTssHandle(key_handle), |
| signature.length(), |
| ConvertStringToByteBuffer(signature.data())); |
| if (result != TSS_SUCCESS) { |
| LOG(ERROR) << "Tspi_Hash_VerifySignature - " << ResultToString(result); |
| return false; |
| } |
| VLOG(1) << "TPMUtilityImpl::Verify success"; |
| return true; |
| } |
| |
| bool TPMUtilityImpl::IsSRKReady() { |
| VLOG(1) << "TPMUtilityImpl::IsSRKReady"; |
| AutoLock lock(lock_); |
| return InitSRK(); |
| } |
| |
| int TPMUtilityImpl::CreateHandle(int slot, |
| TSS_HKEY key, |
| const string& key_blob, |
| const SecureBlob& auth_data) { |
| int handle = ++last_handle_; |
| HandleInfo* handle_info = &slot_handles_[slot]; |
| 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; |
| } |
| |
| 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); |
| chromeos::SecureMemset(discard, 0, kSha1OutputBytes); |
| 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; |
| } |
| |
| 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 |