| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "trunks/tpm_utility_impl.h" |
| |
| #include <base/logging.h> |
| #include <base/memory/scoped_ptr.h> |
| #include <base/stl_util.h> |
| #include <crypto/secure_hash.h> |
| #include <crypto/sha2.h> |
| #include <openssl/aes.h> |
| #include <openssl/rand.h> |
| |
| #include "trunks/authorization_delegate.h" |
| #include "trunks/authorization_session.h" |
| #include "trunks/error_codes.h" |
| #include "trunks/hmac_authorization_delegate.h" |
| #include "trunks/scoped_key_handle.h" |
| #include "trunks/tpm_state.h" |
| #include "trunks/trunks_factory.h" |
| |
| namespace { |
| |
| const char kPlatformPassword[] = "cros-platform"; |
| const char kWellKnownPassword[] = "cros-password"; |
| const trunks::TPMA_OBJECT kFixedTPM = 1U << 1; |
| const trunks::TPMA_OBJECT kFixedParent = 1U << 4; |
| const trunks::TPMA_OBJECT kSensitiveDataOrigin = 1U << 5; |
| const trunks::TPMA_OBJECT kUserWithAuth = 1U << 6; |
| const trunks::TPMA_OBJECT kNoDA = 1U << 10; |
| const trunks::TPMA_OBJECT kRestricted = 1U << 16; |
| const trunks::TPMA_OBJECT kDecrypt = 1U << 17; |
| const trunks::TPMA_OBJECT kSign = 1U << 18; |
| const size_t kMaxPasswordLength = 32; |
| |
| // Returns a serialized representation of the unmodified handle. This is useful |
| // for predefined handle values, like TPM_RH_OWNER. For details on what types of |
| // handles use this name formula see Table 3 in the TPM 2.0 Library Spec Part 1 |
| // (Section 16 - Names). |
| std::string NameFromHandle(trunks::TPM_HANDLE handle) { |
| std::string name; |
| trunks::Serialize_TPM_HANDLE(handle, &name); |
| return name; |
| } |
| |
| // Returns the digest size (in bytes) of the given TPM hash algorithm. |
| // Returns -1 when the algorithm is not recognized. |
| size_t GetDigestSize(trunks::TPM_ALG_ID hash_alg) { |
| switch (hash_alg) { |
| case trunks::TPM_ALG_SHA1: |
| return SHA1_DIGEST_SIZE; |
| case trunks::TPM_ALG_SHA256: |
| return SHA256_DIGEST_SIZE; |
| case trunks::TPM_ALG_SHA384: |
| return SHA384_DIGEST_SIZE; |
| case trunks::TPM_ALG_SHA512: |
| return SHA512_DIGEST_SIZE; |
| } |
| NOTREACHED(); |
| return -1; |
| } |
| |
| } // namespace |
| |
| namespace trunks { |
| |
| TpmUtilityImpl::TpmUtilityImpl(const TrunksFactory& factory) |
| : factory_(factory) {} |
| |
| TpmUtilityImpl::~TpmUtilityImpl() { |
| } |
| |
| TPM_RC TpmUtilityImpl::Startup() { |
| TPM_RC result = TPM_RC_SUCCESS; |
| Tpm* tpm = factory_.GetTpm(); |
| result = tpm->StartupSync(TPM_SU_CLEAR, NULL); |
| // Ignore TPM_RC_INITIALIZE, that means it was already started. |
| if (result && result != TPM_RC_INITIALIZE) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| result = tpm->SelfTestSync(YES /* Full test. */, NULL); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::Clear() { |
| TPM_RC result = TPM_RC_SUCCESS; |
| scoped_ptr<AuthorizationDelegate> password_delegate( |
| factory_.GetPasswordAuthorization("")); |
| result = factory_.GetTpm()->ClearSync(TPM_RH_PLATFORM, |
| NameFromHandle(TPM_RH_PLATFORM), |
| password_delegate.get()); |
| // If there was an error in the initialization, platform auth is in a bad |
| // state. |
| if (result == TPM_RC_AUTH_MISSING) { |
| scoped_ptr<AuthorizationDelegate> authorization( |
| factory_.GetPasswordAuthorization(kPlatformPassword)); |
| result = factory_.GetTpm()->ClearSync(TPM_RH_PLATFORM, |
| NameFromHandle(TPM_RH_PLATFORM), |
| authorization.get()); |
| } |
| if (GetFormatOneError(result) == TPM_RC_BAD_AUTH) { |
| LOG(INFO) << "Clear failed because of BAD_AUTH. This probably means " |
| << "that the TPM was already initialized."; |
| return result; |
| } |
| if (result) { |
| LOG(ERROR) << "Failed to clear the TPM: " << GetErrorString(result); |
| } |
| return result; |
| } |
| |
| void TpmUtilityImpl::Shutdown() { |
| TPM_RC return_code = factory_.GetTpm()->ShutdownSync(TPM_SU_CLEAR, |
| NULL); |
| if (return_code && return_code != TPM_RC_INITIALIZE) { |
| // This should not happen, but if it does, there is nothing we can do. |
| LOG(ERROR) << "Error shutting down: " << GetErrorString(return_code); |
| } |
| } |
| |
| TPM_RC TpmUtilityImpl::InitializeTpm() { |
| TPM_RC result = TPM_RC_SUCCESS; |
| scoped_ptr<TpmState> tpm_state(factory_.GetTpmState()); |
| result = tpm_state->Initialize(); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| // Warn about various unexpected conditions. |
| if (!tpm_state->WasShutdownOrderly()) { |
| LOG(WARNING) << "WARNING: The last TPM shutdown was not orderly."; |
| } |
| if (tpm_state->IsInLockout()) { |
| LOG(WARNING) << "WARNING: The TPM is currently in lockout."; |
| } |
| |
| // We expect the firmware has already locked down the platform hierarchy. If |
| // it hasn't, do it now. |
| if (tpm_state->IsPlatformHierarchyEnabled()) { |
| scoped_ptr<AuthorizationDelegate> empty_password( |
| factory_.GetPasswordAuthorization("")); |
| result = SetHierarchyAuthorization(TPM_RH_PLATFORM, |
| kPlatformPassword, |
| empty_password.get()); |
| if (GetFormatOneError(result) == TPM_RC_BAD_AUTH) { |
| // Most likely the platform password has already been set. |
| result = TPM_RC_SUCCESS; |
| } |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| scoped_ptr<AuthorizationDelegate> authorization( |
| factory_.GetPasswordAuthorization(kPlatformPassword)); |
| result = DisablePlatformHierarchy(authorization.get()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::TakeOwnership(const std::string& owner_password, |
| const std::string& endorsement_password, |
| const std::string& lockout_password) { |
| // First we set the storage hierarchy authorization to the well know default |
| // password. |
| scoped_ptr<TpmState> tpm_state(factory_.GetTpmState()); |
| TPM_RC result = tpm_state->Initialize(); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| scoped_ptr<AuthorizationDelegate> delegate = |
| factory_.GetPasswordAuthorization(""); |
| if (!tpm_state->IsOwnerPasswordSet()) { |
| result = SetHierarchyAuthorization(TPM_RH_OWNER, |
| kWellKnownPassword, |
| delegate.get()); |
| if (result) { |
| LOG(ERROR) << "Error setting storage hierarchy authorization " |
| << "to its default value: " << GetErrorString(result); |
| return result; |
| } |
| } |
| result = CreateStorageRootKeys(kWellKnownPassword); |
| if (result) { |
| LOG(ERROR) << "Error creating SRKs: " << GetErrorString(result); |
| return result; |
| } |
| result = CreateSaltingKey(kWellKnownPassword); |
| if (result) { |
| LOG(ERROR) << "Error creating salting key: " |
| << GetErrorString(result); |
| return result; |
| } |
| // At this point we have a session with parameter encryption securely |
| // enabled. We can now send actual passwords. |
| scoped_ptr<AuthorizationSession> session(factory_.GetAuthorizationSession()); |
| result = session->StartUnboundSession(true); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error initializing AuthorizationSession: " |
| << GetErrorString(result); |
| return result; |
| } |
| session->SetEntityAuthorizationValue(kWellKnownPassword); |
| session->SetFutureAuthorizationValue(owner_password); |
| result = SetHierarchyAuthorization(TPM_RH_OWNER, |
| owner_password, |
| session->GetDelegate()); |
| if (result) { |
| LOG(ERROR) << "Error changing owner authorization: " |
| << GetErrorString(result); |
| return result; |
| } |
| // We now set the endorsement and lockout authorizations. |
| result = tpm_state->Initialize(); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| session->SetEntityAuthorizationValue(""); |
| session->SetFutureAuthorizationValue(endorsement_password); |
| if (!tpm_state->IsEndorsementPasswordSet()) { |
| result = SetHierarchyAuthorization(TPM_RH_ENDORSEMENT, |
| endorsement_password, |
| session->GetDelegate()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| } |
| session->SetFutureAuthorizationValue(lockout_password); |
| if (!tpm_state->IsLockoutPasswordSet()) { |
| result = SetHierarchyAuthorization(TPM_RH_LOCKOUT, |
| lockout_password, |
| session->GetDelegate()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::StirRandom(const std::string& entropy_data) { |
| std::string digest = crypto::SHA256HashString(entropy_data); |
| TPM2B_SENSITIVE_DATA random_bytes = Make_TPM2B_SENSITIVE_DATA(digest); |
| return factory_.GetTpm()->StirRandomSync(random_bytes, NULL); |
| } |
| |
| TPM_RC TpmUtilityImpl::GenerateRandom(size_t num_bytes, |
| std::string* random_data) { |
| size_t bytes_left = num_bytes; |
| random_data->clear(); |
| TPM_RC rc; |
| TPM2B_DIGEST digest; |
| while (bytes_left > 0) { |
| rc = factory_.GetTpm()->GetRandomSync(bytes_left, |
| &digest, |
| NULL); |
| if (rc) { |
| LOG(ERROR) << "Error getting random data from tpm."; |
| return rc; |
| } |
| random_data->append(StringFrom_TPM2B_DIGEST(digest)); |
| bytes_left -= digest.size; |
| } |
| CHECK_EQ(random_data->size(), num_bytes); |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::ExtendPCR(int pcr_index, |
| const std::string& extend_data) { |
| if (pcr_index < 0 || pcr_index >= IMPLEMENTATION_PCR) { |
| LOG(ERROR) << "Using a PCR index that isnt implemented."; |
| return TPM_RC_FAILURE; |
| } |
| TPM_HANDLE pcr_handle = HR_PCR + pcr_index; |
| std::string pcr_name = NameFromHandle(pcr_handle); |
| TPML_DIGEST_VALUES digests; |
| digests.count = 1; |
| digests.digests[0].hash_alg = TPM_ALG_SHA256; |
| crypto::SHA256HashString(extend_data, |
| digests.digests[0].digest.sha256, |
| crypto::kSHA256Length); |
| return factory_.GetTpm()->PCR_ExtendSync(pcr_handle, |
| pcr_name, |
| digests, |
| NULL); |
| } |
| |
| TPM_RC TpmUtilityImpl::ReadPCR(int pcr_index, std::string* pcr_value) { |
| TPML_PCR_SELECTION pcr_select_in; |
| uint32_t pcr_update_counter; |
| TPML_PCR_SELECTION pcr_select_out; |
| TPML_DIGEST pcr_values; |
| // This process of selecting pcrs is highlighted in TPM 2.0 Library Spec |
| // Part 2 (Section 10.5 - PCR structures). |
| uint8_t pcr_select_index = pcr_index / 8; |
| uint8_t pcr_select_byte = 1 << (pcr_index % 8); |
| pcr_select_in.count = 1; |
| pcr_select_in.pcr_selections[0].hash = TPM_ALG_SHA256; |
| pcr_select_in.pcr_selections[0].sizeof_select = pcr_select_index + 1; |
| pcr_select_in.pcr_selections[0].pcr_select[pcr_select_index] = |
| pcr_select_byte; |
| |
| TPM_RC rc = factory_.GetTpm()->PCR_ReadSync(pcr_select_in, |
| &pcr_update_counter, |
| &pcr_select_out, |
| &pcr_values, |
| NULL); |
| if (rc) { |
| LOG(INFO) << "Error trying to read a pcr: " << rc; |
| return rc; |
| } |
| if (pcr_select_out.count != 1 || |
| pcr_select_out.pcr_selections[0].sizeof_select != |
| (pcr_select_index + 1) || |
| pcr_select_out.pcr_selections[0].pcr_select[pcr_select_index] != |
| pcr_select_byte) { |
| LOG(ERROR) << "TPM did not return the requested PCR"; |
| return TPM_RC_FAILURE; |
| } |
| CHECK_GE(pcr_values.count, 1U); |
| pcr_value->assign(StringFrom_TPM2B_DIGEST(pcr_values.digests[0])); |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::AsymmetricEncrypt(TPM_HANDLE key_handle, |
| TPM_ALG_ID scheme, |
| TPM_ALG_ID hash_alg, |
| const std::string& plaintext, |
| std::string* ciphertext) { |
| TPMT_RSA_DECRYPT in_scheme; |
| if (hash_alg == TPM_ALG_NULL) { |
| hash_alg = TPM_ALG_SHA256; |
| } |
| if (scheme == TPM_ALG_RSAES) { |
| in_scheme.scheme = TPM_ALG_RSAES; |
| } else if (scheme == TPM_ALG_OAEP || scheme == TPM_ALG_NULL) { |
| in_scheme.scheme = TPM_ALG_OAEP; |
| in_scheme.details.oaep.hash_alg = hash_alg; |
| } else { |
| LOG(ERROR) << "Invalid Signing scheme used."; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| |
| TPM2B_PUBLIC public_area; |
| TPM_RC return_code = GetKeyPublicArea(key_handle, &public_area); |
| if (return_code) { |
| LOG(ERROR) << "Error finding public area for: " << key_handle; |
| return return_code; |
| } else if (public_area.public_area.type != TPM_ALG_RSA) { |
| LOG(ERROR) << "Key handle given is not an RSA key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } else if ((public_area.public_area.object_attributes & kDecrypt) == 0) { |
| LOG(ERROR) << "Key handle given is not a decryption key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| if ((public_area.public_area.object_attributes & kRestricted) != 0) { |
| LOG(ERROR) << "Cannot use RSAES for encryption with a restricted key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| std::string key_name; |
| return_code = GetKeyName(key_handle, &key_name); |
| if (return_code) { |
| LOG(ERROR) << "Error finding key name for: " << key_handle; |
| return return_code; |
| } |
| |
| TPM2B_DATA label; |
| label.size = 0; |
| TPM2B_PUBLIC_KEY_RSA in_message = Make_TPM2B_PUBLIC_KEY_RSA(plaintext); |
| TPM2B_PUBLIC_KEY_RSA out_message; |
| return_code = factory_.GetTpm()->RSA_EncryptSync(key_handle, |
| key_name, |
| in_message, |
| in_scheme, |
| label, |
| &out_message, |
| NULL); |
| if (return_code) { |
| LOG(ERROR) << "Error performing RSA encrypt: " |
| << GetErrorString(return_code); |
| return return_code; |
| } |
| ciphertext->assign(StringFrom_TPM2B_PUBLIC_KEY_RSA(out_message)); |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::AsymmetricDecrypt(TPM_HANDLE key_handle, |
| TPM_ALG_ID scheme, |
| TPM_ALG_ID hash_alg, |
| const std::string& password, |
| const std::string& ciphertext, |
| AuthorizationSession* session, |
| std::string* plaintext) { |
| TPMT_RSA_DECRYPT in_scheme; |
| if (hash_alg == TPM_ALG_NULL) { |
| hash_alg = TPM_ALG_SHA256; |
| } |
| if (scheme == TPM_ALG_RSAES) { |
| in_scheme.scheme = TPM_ALG_RSAES; |
| } else if (scheme == TPM_ALG_OAEP || scheme == TPM_ALG_NULL) { |
| in_scheme.scheme = TPM_ALG_OAEP; |
| in_scheme.details.oaep.hash_alg = hash_alg; |
| } else { |
| LOG(ERROR) << "Invalid Signing scheme used."; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| |
| TPM2B_PUBLIC public_area; |
| TPM_RC return_code = GetKeyPublicArea(key_handle, &public_area); |
| if (return_code) { |
| LOG(ERROR) << "Error finding public area for: " << key_handle; |
| return return_code; |
| } else if (public_area.public_area.type != TPM_ALG_RSA) { |
| LOG(ERROR) << "Key handle given is not an RSA key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } else if ((public_area.public_area.object_attributes & kDecrypt) == 0) { |
| LOG(ERROR) << "Key handle given is not a decryption key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| if ((public_area.public_area.object_attributes & kRestricted) != 0) { |
| LOG(ERROR) << "Cannot use RSAES for encryption with a restricted key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| std::string key_name; |
| return_code = GetKeyName(key_handle, &key_name); |
| if (return_code) { |
| LOG(ERROR) << "Error finding key name for: " << key_handle; |
| return return_code; |
| } |
| |
| TPM2B_DATA label; |
| label.size = 0; |
| TPM2B_PUBLIC_KEY_RSA in_message = Make_TPM2B_PUBLIC_KEY_RSA(ciphertext); |
| TPM2B_PUBLIC_KEY_RSA out_message; |
| scoped_ptr<AuthorizationSession> local_session; |
| if (session == NULL) { |
| local_session = factory_.GetAuthorizationSession(); |
| return_code = local_session->StartUnboundSession(true); |
| if (return_code) { |
| LOG(ERROR) << "Error initializing Authorization Session: " |
| << GetErrorString(return_code); |
| return return_code; |
| } |
| session = local_session.get(); |
| } |
| session->SetEntityAuthorizationValue(password); |
| return_code = factory_.GetTpm()->RSA_DecryptSync(key_handle, |
| key_name, |
| in_message, |
| in_scheme, |
| label, |
| &out_message, |
| session->GetDelegate()); |
| if (return_code) { |
| LOG(ERROR) << "Error performing RSA decrypt: " |
| << GetErrorString(return_code); |
| return return_code; |
| } |
| plaintext->assign(StringFrom_TPM2B_PUBLIC_KEY_RSA(out_message)); |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::Sign(TPM_HANDLE key_handle, |
| TPM_ALG_ID scheme, |
| TPM_ALG_ID hash_alg, |
| const std::string& password, |
| const std::string& digest, |
| AuthorizationSession* session, |
| std::string* signature) { |
| TPMT_SIG_SCHEME in_scheme; |
| if (hash_alg == TPM_ALG_NULL) { |
| hash_alg = TPM_ALG_SHA256; |
| } |
| size_t hash_size = GetDigestSize(hash_alg); |
| if (digest.size() != hash_size) { |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| if (scheme == TPM_ALG_RSAPSS) { |
| in_scheme.scheme = TPM_ALG_RSAPSS; |
| in_scheme.details.rsapss.hash_alg = hash_alg; |
| } else if (scheme == TPM_ALG_RSASSA || scheme == TPM_ALG_NULL) { |
| in_scheme.scheme = TPM_ALG_RSASSA; |
| in_scheme.details.rsassa.hash_alg = hash_alg; |
| } else { |
| LOG(ERROR) << "Invalid Signing scheme used."; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| |
| TPM2B_PUBLIC public_area; |
| TPM_RC return_code = GetKeyPublicArea(key_handle, &public_area); |
| if (return_code) { |
| LOG(ERROR) << "Error finding public area for: " << key_handle; |
| return return_code; |
| } else if (public_area.public_area.type != TPM_ALG_RSA) { |
| LOG(ERROR) << "Key handle given is not an RSA key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } else if ((public_area.public_area.object_attributes & kSign) == 0) { |
| LOG(ERROR) << "Key handle given is not a signging key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } else if ((public_area.public_area.object_attributes & kRestricted) != 0) { |
| LOG(ERROR) << "Key handle references a restricted key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| |
| std::string key_name; |
| return_code = GetKeyName(key_handle, &key_name); |
| if (return_code) { |
| LOG(ERROR) << "Error finding key name for: " << key_handle; |
| return return_code; |
| } |
| TPM2B_DIGEST tpm_digest = Make_TPM2B_DIGEST(digest); |
| TPMT_SIGNATURE signature_out; |
| TPMT_TK_HASHCHECK validation; |
| validation.tag = TPM_ST_HASHCHECK; |
| validation.hierarchy = TPM_RH_NULL; |
| validation.digest.size = 0; |
| scoped_ptr<AuthorizationSession> local_session; |
| if (session == NULL) { |
| local_session = factory_.GetAuthorizationSession(); |
| return_code = local_session->StartUnboundSession(true); |
| if (return_code) { |
| LOG(ERROR) << "Error initializing Authorization Session: " |
| << GetErrorString(return_code); |
| return return_code; |
| } |
| session = local_session.get(); |
| } |
| session->SetEntityAuthorizationValue(password); |
| return_code = factory_.GetTpm()->SignSync(key_handle, |
| key_name, |
| tpm_digest, |
| in_scheme, |
| validation, |
| &signature_out, |
| session->GetDelegate()); |
| if (return_code) { |
| LOG(ERROR) << "Error signing digest: " << GetErrorString(return_code); |
| return return_code; |
| } |
| if (scheme == TPM_ALG_RSAPSS) { |
| signature->resize(signature_out.signature.rsapss.sig.size); |
| signature->assign(StringFrom_TPM2B_PUBLIC_KEY_RSA( |
| signature_out.signature.rsapss.sig)); |
| } else { |
| signature->resize(signature_out.signature.rsassa.sig.size); |
| signature->assign(StringFrom_TPM2B_PUBLIC_KEY_RSA( |
| signature_out.signature.rsassa.sig)); |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::Verify(TPM_HANDLE key_handle, |
| TPM_ALG_ID scheme, |
| TPM_ALG_ID hash_alg, |
| const std::string& digest, |
| const std::string& signature) { |
| TPM2B_PUBLIC public_area; |
| TPM_RC return_code = GetKeyPublicArea(key_handle, &public_area); |
| if (return_code) { |
| LOG(ERROR) << "Error finding public area for: " << key_handle; |
| return return_code; |
| } else if (public_area.public_area.type != TPM_ALG_RSA) { |
| LOG(ERROR) << "Key handle given is not an RSA key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } else if ((public_area.public_area.object_attributes & kSign) == 0) { |
| LOG(ERROR) << "Key handle given is not a signing key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } else if ((public_area.public_area.object_attributes & kRestricted) != 0) { |
| LOG(ERROR) << "Cannot use RSAPSS for signing with a restricted key"; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| if (hash_alg == TPM_ALG_NULL) { |
| hash_alg = TPM_ALG_SHA256; |
| } |
| size_t hash_size = GetDigestSize(hash_alg); |
| if (digest.size() != hash_size) { |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| |
| TPMT_SIGNATURE signature_in; |
| if (scheme == TPM_ALG_RSAPSS) { |
| signature_in.sig_alg = TPM_ALG_RSAPSS; |
| signature_in.signature.rsapss.hash = hash_alg; |
| signature_in.signature.rsapss.sig = Make_TPM2B_PUBLIC_KEY_RSA(signature); |
| } else if (scheme == TPM_ALG_NULL || scheme == TPM_ALG_RSASSA) { |
| signature_in.sig_alg = TPM_ALG_RSASSA; |
| signature_in.signature.rsassa.hash = hash_alg; |
| signature_in.signature.rsassa.sig = Make_TPM2B_PUBLIC_KEY_RSA(signature); |
| } else { |
| LOG(ERROR) << "Invalid scheme used to verify signature."; |
| return SAPI_RC_BAD_PARAMETER; |
| } |
| std::string key_name; |
| TPMT_TK_VERIFIED verified; |
| TPM2B_DIGEST tpm_digest = Make_TPM2B_DIGEST(digest); |
| return_code = factory_.GetTpm()->VerifySignatureSync(key_handle, |
| key_name, |
| tpm_digest, |
| signature_in, |
| &verified, |
| NULL); |
| if (return_code == TPM_RC_SIGNATURE) { |
| LOG(WARNING) << "Incorrect signature for given digest."; |
| return TPM_RC_SIGNATURE; |
| } else if (return_code && return_code != TPM_RC_SIGNATURE) { |
| LOG(ERROR) << "Error verifying signature: " << GetErrorString(return_code); |
| return return_code; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::ChangeKeyAuthorizationData( |
| TPM_HANDLE key_handle, |
| const std::string& old_password, |
| const std::string& new_password, |
| AuthorizationSession* session, |
| std::string* key_blob) { |
| std::string key_name; |
| std::string parent_name; |
| TPM_RC result = GetKeyName(key_handle, &key_name); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error getting Key name for key_handle: " |
| << GetErrorString(result); |
| return result; |
| } |
| result = GetKeyName(kRSAStorageRootKey, &parent_name); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error getting Key name for RSA-SRK: " |
| << GetErrorString(result); |
| return result; |
| } |
| TPM2B_AUTH new_auth = Make_TPM2B_DIGEST(new_password); |
| TPM2B_PRIVATE new_private_data; |
| new_private_data.size = 0; |
| scoped_ptr<AuthorizationSession> local_session; |
| if (session == NULL) { |
| local_session = factory_.GetAuthorizationSession(); |
| result = local_session->StartUnboundSession(true); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error initializing Authorization Session: " |
| << GetErrorString(result); |
| return result; |
| } |
| session = local_session.get(); |
| } |
| session->SetEntityAuthorizationValue(old_password); |
| result = factory_.GetTpm()->ObjectChangeAuthSync(key_handle, |
| key_name, |
| kRSAStorageRootKey, |
| parent_name, |
| new_auth, |
| &new_private_data, |
| session->GetDelegate()); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error changing object authorization data: " |
| << GetErrorString(result); |
| return result; |
| } |
| if (key_blob) { |
| TPM2B_PUBLIC public_data; |
| public_data.size = 0; |
| result = GetKeyPublicArea(key_handle, &public_data); |
| if (result != TPM_RC_SUCCESS) { |
| return result; |
| } |
| result = KeyDataToString(public_data, new_private_data, key_blob); |
| if (result != TPM_RC_SUCCESS) { |
| return result; |
| } |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::ImportRSAKey(AsymmetricKeyUsage key_type, |
| const std::string& modulus, |
| uint32_t public_exponent, |
| const std::string& prime_factor, |
| const std::string& password, |
| AuthorizationSession* session, |
| std::string* key_blob) { |
| std::string parent_name; |
| TPM_RC result = GetKeyName(kRSAStorageRootKey, &parent_name); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error getting Key name for RSA-SRK: " |
| << GetErrorString(result); |
| return result; |
| } |
| TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA); |
| public_area.object_attributes = kUserWithAuth | kNoDA; |
| switch (key_type) { |
| case AsymmetricKeyUsage::kDecryptKey: |
| public_area.object_attributes |= kDecrypt; |
| break; |
| case AsymmetricKeyUsage::kSignKey: |
| public_area.object_attributes |= kSign; |
| break; |
| case AsymmetricKeyUsage::kDecryptAndSignKey: |
| public_area.object_attributes |= (kSign | kDecrypt); |
| break; |
| } |
| public_area.parameters.rsa_detail.key_bits = modulus.size() * 8; |
| public_area.parameters.rsa_detail.exponent = public_exponent; |
| public_area.unique.rsa = Make_TPM2B_PUBLIC_KEY_RSA(modulus); |
| TPM2B_DATA encryption_key; |
| encryption_key.size = kAesKeySize; |
| CHECK_EQ(RAND_bytes(encryption_key.buffer, encryption_key.size), 1) << |
| "Error generating a cryptographically random Aes Key."; |
| TPM2B_PUBLIC public_data = Make_TPM2B_PUBLIC(public_area); |
| TPM2B_ENCRYPTED_SECRET in_sym_seed = Make_TPM2B_ENCRYPTED_SECRET(""); |
| TPMT_SYM_DEF_OBJECT symmetric_alg; |
| symmetric_alg.algorithm = TPM_ALG_AES; |
| symmetric_alg.key_bits.aes = kAesKeySize * 8; |
| symmetric_alg.mode.aes = TPM_ALG_CFB; |
| TPMT_SENSITIVE in_sensitive; |
| in_sensitive.sensitive_type = TPM_ALG_RSA; |
| in_sensitive.auth_value = Make_TPM2B_DIGEST(password); |
| in_sensitive.seed_value = Make_TPM2B_DIGEST(""); |
| in_sensitive.sensitive.rsa = Make_TPM2B_PRIVATE_KEY_RSA(prime_factor); |
| TPM2B_PRIVATE private_data; |
| result = EncryptPrivateData(in_sensitive, public_area, |
| &private_data, &encryption_key); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error creating encrypted private struct: " |
| << GetErrorString(result); |
| return result; |
| } |
| TPM2B_PRIVATE tpm_private_data; |
| tpm_private_data.size = 0; |
| scoped_ptr<AuthorizationSession> local_session; |
| if (session == NULL) { |
| local_session = factory_.GetAuthorizationSession(); |
| result = local_session->StartUnboundSession(true); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error initializing Authorization Session: " |
| << GetErrorString(result); |
| return result; |
| } |
| session = local_session.get(); |
| } |
| session->SetEntityAuthorizationValue(""); |
| result = factory_.GetTpm()->ImportSync(kRSAStorageRootKey, |
| parent_name, |
| encryption_key, |
| public_data, |
| private_data, |
| in_sym_seed, |
| symmetric_alg, |
| &tpm_private_data, |
| session->GetDelegate()); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error importing key: " << GetErrorString(result); |
| return result; |
| } |
| if (key_blob) { |
| result = KeyDataToString(public_data, tpm_private_data, key_blob); |
| if (result != TPM_RC_SUCCESS) { |
| return result; |
| } |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::CreateAndLoadRSAKey(AsymmetricKeyUsage key_type, |
| const std::string& password, |
| AuthorizationSession* session, |
| TPM_HANDLE* key_handle, |
| std::string* key_blob) { |
| std::string tmp_key_blob; |
| TPM_RC result = CreateRSAKeyPair(key_type, 2048, 0x10001, password, |
| session, &tmp_key_blob); |
| if (result != TPM_RC_SUCCESS) { |
| return result; |
| } |
| result = LoadKey(tmp_key_blob, session, key_handle); |
| if (result != TPM_RC_SUCCESS) { |
| return result; |
| } |
| if (key_blob) { |
| key_blob->assign(tmp_key_blob); |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::CreateRSAKeyPair(AsymmetricKeyUsage key_type, |
| int modulus_bits, |
| uint32_t public_exponent, |
| const std::string& password, |
| AuthorizationSession* session, |
| std::string* key_blob) { |
| CHECK(key_blob); |
| std::string parent_name; |
| TPM_RC result = GetKeyName(kRSAStorageRootKey, &parent_name); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error getting Key name for RSA-SRK: " |
| << GetErrorString(result); |
| return result; |
| } |
| TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA); |
| public_area.object_attributes |= |
| (kSensitiveDataOrigin | kUserWithAuth | kNoDA); |
| switch (key_type) { |
| case AsymmetricKeyUsage::kDecryptKey: |
| public_area.object_attributes |= kDecrypt; |
| break; |
| case AsymmetricKeyUsage::kSignKey: |
| public_area.object_attributes |= kSign; |
| break; |
| case AsymmetricKeyUsage::kDecryptAndSignKey: |
| public_area.object_attributes |= (kSign | kDecrypt); |
| break; |
| } |
| public_area.parameters.rsa_detail.key_bits = modulus_bits; |
| public_area.parameters.rsa_detail.exponent = public_exponent; |
| TPML_PCR_SELECTION creation_pcrs; |
| creation_pcrs.count = 0; |
| TPMS_SENSITIVE_CREATE sensitive; |
| sensitive.user_auth = Make_TPM2B_DIGEST(password); |
| sensitive.data = Make_TPM2B_SENSITIVE_DATA(""); |
| TPM2B_SENSITIVE_CREATE sensitive_create = Make_TPM2B_SENSITIVE_CREATE( |
| sensitive); |
| TPM2B_DATA outside_info = Make_TPM2B_DATA(""); |
| TPM2B_PUBLIC out_public; |
| out_public.size = 0; |
| TPM2B_PRIVATE out_private; |
| out_private.size = 0; |
| TPM2B_CREATION_DATA creation_data; |
| TPM2B_DIGEST creation_hash; |
| TPMT_TK_CREATION creation_ticket; |
| scoped_ptr<AuthorizationSession> local_session; |
| if (session == NULL) { |
| local_session = factory_.GetAuthorizationSession(); |
| result = local_session->StartUnboundSession(true); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error initializing Authorization Session: " |
| << GetErrorString(result); |
| return result; |
| } |
| session = local_session.get(); |
| } |
| session->SetEntityAuthorizationValue(""); |
| result = factory_.GetTpm()->CreateSync(kRSAStorageRootKey, |
| parent_name, |
| sensitive_create, |
| Make_TPM2B_PUBLIC(public_area), |
| outside_info, |
| creation_pcrs, |
| &out_private, |
| &out_public, |
| &creation_data, |
| &creation_hash, |
| &creation_ticket, |
| session->GetDelegate()); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error creating RSA key: " << GetErrorString(result); |
| return result; |
| } |
| result = KeyDataToString(out_public, out_private, key_blob); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error serializing key_blob: " << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::LoadKey(const std::string& key_blob, |
| AuthorizationSession* session, |
| TPM_HANDLE* key_handle) { |
| std::string parent_name; |
| TPM_RC result = GetKeyName(kRSAStorageRootKey, &parent_name); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error getting parent key name: " << GetErrorString(result); |
| return result; |
| } |
| TPM2B_PUBLIC in_public; |
| TPM2B_PRIVATE in_private; |
| result = StringToKeyData(key_blob, &in_public, &in_private); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error parsing key_blob: " << GetErrorString(result); |
| return result; |
| } |
| CHECK(key_handle); |
| TPM2B_NAME key_name; |
| key_name.size = 0; |
| scoped_ptr<AuthorizationSession> local_session; |
| if (session == NULL) { |
| local_session = factory_.GetAuthorizationSession(); |
| result = local_session->StartUnboundSession(true); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error initializing Authorization Session: " |
| << GetErrorString(result); |
| return result; |
| } |
| session = local_session.get(); |
| } |
| session->SetEntityAuthorizationValue(""); |
| result = factory_.GetTpm()->LoadSync(kRSAStorageRootKey, |
| parent_name, |
| in_private, |
| in_public, |
| key_handle, |
| &key_name, |
| session->GetDelegate()); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error loading key: " << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::GetKeyName(TPM_HANDLE handle, std::string* name) { |
| TPM2B_PUBLIC public_data; |
| TPM2B_NAME out_name; |
| out_name.size = 0; |
| TPM2B_NAME qualified_name; |
| std::string handle_name; // Unused |
| TPM_RC return_code = factory_.GetTpm()->ReadPublicSync(handle, |
| handle_name, |
| &public_data, |
| &out_name, |
| &qualified_name, |
| NULL); |
| if (return_code) { |
| LOG(ERROR) << "Error generating name for object: " << handle; |
| return return_code; |
| } |
| name->resize(out_name.size); |
| name->assign(StringFrom_TPM2B_NAME(out_name)); |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::GetKeyPublicArea(TPM_HANDLE handle, |
| TPM2B_PUBLIC* public_data) { |
| CHECK(public_data); |
| TPM2B_NAME out_name; |
| TPM2B_NAME qualified_name; |
| std::string handle_name; // Unused |
| TPM_RC return_code = factory_.GetTpm()->ReadPublicSync(handle, |
| handle_name, |
| public_data, |
| &out_name, |
| &qualified_name, |
| NULL); |
| if (return_code) { |
| LOG(ERROR) << "Error generating name for object: " << handle; |
| return return_code; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| bool TpmUtilityImpl::ParseHeader(const std::string& message, |
| bool* has_sessions, |
| uint32_t* size, |
| uint32_t* code) { |
| std::string buffer = message; |
| TPM_ST tag; |
| if (Parse_TPM_ST(&buffer, &tag, NULL) != TPM_RC_SUCCESS) { |
| return false; |
| } |
| uint32_t tmp_size; |
| if (Parse_UINT32(&buffer, &tmp_size, NULL) != TPM_RC_SUCCESS) { |
| return false; |
| } |
| if (tmp_size != message.size()) { |
| return false; |
| } |
| TPM_RC tmp_code; |
| if (Parse_TPM_RC(&buffer, &tmp_code, NULL) != TPM_RC_SUCCESS) { |
| return false; |
| } |
| if (has_sessions) { |
| *has_sessions = (tag == TPM_ST_SESSIONS); |
| } |
| if (size) { |
| *size = tmp_size; |
| } |
| if (code) { |
| *code = tmp_code; |
| } |
| return true; |
| } |
| |
| std::string TpmUtilityImpl::CreateErrorResponse(TPM_RC error_code) { |
| const uint32_t kErrorResponseSize = 10; |
| std::string response; |
| CHECK_EQ(Serialize_TPM_ST(TPM_ST_NO_SESSIONS, &response), TPM_RC_SUCCESS); |
| CHECK_EQ(Serialize_UINT32(kErrorResponseSize, &response), TPM_RC_SUCCESS); |
| CHECK_EQ(Serialize_TPM_RC(error_code, &response), TPM_RC_SUCCESS); |
| return response; |
| } |
| |
| TPM_RC TpmUtilityImpl::CreateStorageRootKeys( |
| const std::string& owner_password) { |
| TPM_RC result = TPM_RC_SUCCESS; |
| Tpm* tpm = factory_.GetTpm(); |
| TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA); |
| public_area.object_attributes |= |
| (kSensitiveDataOrigin | kUserWithAuth | kNoDA | |
| kRestricted | kDecrypt); |
| public_area.parameters.rsa_detail.symmetric.algorithm = TPM_ALG_AES; |
| public_area.parameters.rsa_detail.symmetric.key_bits.aes = 128; |
| public_area.parameters.rsa_detail.symmetric.mode.aes = TPM_ALG_CFB; |
| TPM2B_PUBLIC rsa_public_area = Make_TPM2B_PUBLIC(public_area); |
| TPML_PCR_SELECTION creation_pcrs; |
| creation_pcrs.count = 0; |
| TPMS_SENSITIVE_CREATE sensitive; |
| sensitive.user_auth = Make_TPM2B_DIGEST(""); |
| sensitive.data = Make_TPM2B_SENSITIVE_DATA(""); |
| TPM_HANDLE object_handle; |
| TPM2B_CREATION_DATA creation_data; |
| TPM2B_DIGEST creation_digest; |
| TPMT_TK_CREATION creation_ticket; |
| TPM2B_NAME object_name; |
| object_name.size = 0; |
| scoped_ptr<AuthorizationDelegate> delegate = |
| factory_.GetPasswordAuthorization(owner_password); |
| result = tpm->CreatePrimarySync(TPM_RH_OWNER, |
| NameFromHandle(TPM_RH_OWNER), |
| Make_TPM2B_SENSITIVE_CREATE(sensitive), |
| rsa_public_area, |
| Make_TPM2B_DATA(""), |
| creation_pcrs, |
| &object_handle, |
| &rsa_public_area, |
| &creation_data, |
| &creation_digest, |
| &creation_ticket, |
| &object_name, |
| delegate.get()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| ScopedKeyHandle rsa_key(factory_, object_handle); |
| // This will make the key persistent. |
| result = tpm->EvictControlSync(TPM_RH_OWNER, |
| NameFromHandle(TPM_RH_OWNER), |
| object_handle, |
| StringFrom_TPM2B_NAME(object_name), |
| kRSAStorageRootKey, |
| delegate.get()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| // Do it again for ECC. |
| public_area = CreateDefaultPublicArea(TPM_ALG_ECC); |
| public_area.object_attributes |= |
| (kSensitiveDataOrigin | kUserWithAuth | kNoDA | |
| kRestricted | kDecrypt); |
| public_area.parameters.ecc_detail.symmetric.algorithm = TPM_ALG_AES; |
| public_area.parameters.ecc_detail.symmetric.key_bits.aes = 128; |
| public_area.parameters.ecc_detail.symmetric.mode.aes = TPM_ALG_CFB; |
| TPM2B_PUBLIC ecc_public_area = Make_TPM2B_PUBLIC(public_area); |
| result = tpm->CreatePrimarySync(TPM_RH_OWNER, |
| NameFromHandle(TPM_RH_OWNER), |
| Make_TPM2B_SENSITIVE_CREATE(sensitive), |
| ecc_public_area, |
| Make_TPM2B_DATA(""), |
| creation_pcrs, |
| &object_handle, |
| &ecc_public_area, |
| &creation_data, |
| &creation_digest, |
| &creation_ticket, |
| &object_name, |
| delegate.get()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| ScopedKeyHandle ecc_key(factory_, object_handle); |
| // This will make the key persistent. |
| result = tpm->EvictControlSync(TPM_RH_OWNER, |
| NameFromHandle(TPM_RH_OWNER), |
| object_handle, |
| StringFrom_TPM2B_NAME(object_name), |
| kECCStorageRootKey, |
| delegate.get()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::CreateSaltingKey(const std::string& owner_password) { |
| std::string parent_name; |
| TPM_RC result = GetKeyName(kRSAStorageRootKey, &parent_name); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error getting Key name for RSA-SRK: " |
| << GetErrorString(result); |
| return result; |
| } |
| TPMT_PUBLIC public_area = CreateDefaultPublicArea(TPM_ALG_RSA); |
| // We are limited by openssl to using SHA1, because OAEP padding in openssl |
| // is limited to using SHA1. |
| // TODO(usanghi): Change this to SHA256 when that functionality is available |
| // in openssl. crbug.com/442823. |
| public_area.name_alg = TPM_ALG_SHA1; |
| public_area.object_attributes |= |
| kSensitiveDataOrigin | kUserWithAuth | kNoDA | kDecrypt; |
| TPML_PCR_SELECTION creation_pcrs; |
| creation_pcrs.count = 0; |
| TPMS_SENSITIVE_CREATE sensitive; |
| sensitive.user_auth = Make_TPM2B_DIGEST(""); |
| sensitive.data = Make_TPM2B_SENSITIVE_DATA(""); |
| TPM2B_SENSITIVE_CREATE sensitive_create = Make_TPM2B_SENSITIVE_CREATE( |
| sensitive); |
| TPM2B_DATA outside_info = Make_TPM2B_DATA(""); |
| |
| TPM2B_PRIVATE out_private; |
| out_private.size = 0; |
| TPM2B_PUBLIC out_public; |
| out_public.size = 0; |
| TPM2B_CREATION_DATA creation_data; |
| TPM2B_DIGEST creation_hash; |
| TPMT_TK_CREATION creation_ticket; |
| // TODO(usanghi): MITM vulnerability with SaltingKey creation. |
| // Currently we cannot verify the key returned by the TPM. |
| // crbug.com/442331 |
| scoped_ptr<AuthorizationDelegate> delegate = |
| factory_.GetPasswordAuthorization(""); |
| result = factory_.GetTpm()->CreateSync(kRSAStorageRootKey, |
| parent_name, |
| sensitive_create, |
| Make_TPM2B_PUBLIC(public_area), |
| outside_info, |
| creation_pcrs, |
| &out_private, |
| &out_public, |
| &creation_data, |
| &creation_hash, |
| &creation_ticket, |
| delegate.get()); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error creating salting key: " << GetErrorString(result); |
| return result; |
| } |
| TPM2B_NAME key_name; |
| key_name.size = 0; |
| TPM_HANDLE key_handle; |
| result = factory_.GetTpm()->LoadSync(kRSAStorageRootKey, |
| parent_name, |
| out_private, |
| out_public, |
| &key_handle, |
| &key_name, |
| delegate.get()); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error loading salting key: " << GetErrorString(result); |
| return result; |
| } |
| ScopedKeyHandle key(factory_, key_handle); |
| scoped_ptr<AuthorizationDelegate> owner_delegate = |
| factory_.GetPasswordAuthorization(owner_password); |
| result = factory_.GetTpm()->EvictControlSync(TPM_RH_OWNER, |
| NameFromHandle(TPM_RH_OWNER), |
| key_handle, |
| StringFrom_TPM2B_NAME(key_name), |
| kSaltingKey, |
| owner_delegate.get()); |
| if (result) { |
| LOG(ERROR) << __func__ << ": " << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPMT_PUBLIC TpmUtilityImpl::CreateDefaultPublicArea(TPM_ALG_ID key_alg) { |
| TPMT_PUBLIC public_area; |
| public_area.name_alg = TPM_ALG_SHA256; |
| public_area.auth_policy = Make_TPM2B_DIGEST(""); |
| public_area.object_attributes = kFixedTPM | kFixedParent; |
| if (key_alg == TPM_ALG_RSA) { |
| public_area.type = TPM_ALG_RSA; |
| public_area.parameters.rsa_detail.scheme.scheme = TPM_ALG_NULL; |
| public_area.parameters.rsa_detail.symmetric.algorithm = TPM_ALG_NULL; |
| public_area.parameters.rsa_detail.key_bits = 2048; |
| public_area.parameters.rsa_detail.exponent = 0; |
| public_area.unique.rsa = Make_TPM2B_PUBLIC_KEY_RSA(""); |
| } else if (key_alg == TPM_ALG_ECC) { |
| public_area.type = TPM_ALG_ECC; |
| public_area.parameters.ecc_detail.curve_id = TPM_ECC_NIST_P256; |
| public_area.parameters.ecc_detail.kdf.scheme = TPM_ALG_MGF1; |
| public_area.parameters.ecc_detail.kdf.details.mgf1.hash_alg = |
| TPM_ALG_SHA256; |
| public_area.unique.ecc.x = Make_TPM2B_ECC_PARAMETER(""); |
| public_area.unique.ecc.y = Make_TPM2B_ECC_PARAMETER(""); |
| } else { |
| LOG(WARNING) << "Unrecognized key_type. Not filling parameters."; |
| } |
| return public_area; |
| } |
| |
| TPM_RC TpmUtilityImpl::SetHierarchyAuthorization( |
| TPMI_RH_HIERARCHY_AUTH hierarchy, |
| const std::string& password, |
| AuthorizationDelegate* authorization) { |
| if (password.size() > kMaxPasswordLength) { |
| LOG(ERROR) << "Hierarchy passwords can be at most " << kMaxPasswordLength |
| << " bytes. Current password length is: " << password.size(); |
| return SAPI_RC_BAD_SIZE; |
| } |
| return factory_.GetTpm()->HierarchyChangeAuthSync( |
| hierarchy, |
| NameFromHandle(hierarchy), |
| Make_TPM2B_DIGEST(password), |
| authorization); |
| } |
| |
| TPM_RC TpmUtilityImpl::DisablePlatformHierarchy( |
| AuthorizationDelegate* authorization) { |
| return factory_.GetTpm()->HierarchyControlSync( |
| TPM_RH_PLATFORM, // The authorizing entity. |
| NameFromHandle(TPM_RH_PLATFORM), |
| TPM_RH_PLATFORM, // The target hierarchy. |
| 0, // Disable. |
| authorization); |
| } |
| |
| TPM_RC TpmUtilityImpl::StringToKeyData(const std::string& key_blob, |
| TPM2B_PUBLIC* public_info, |
| TPM2B_PRIVATE* private_info) { |
| if (!public_info || !private_info) { |
| LOG(WARNING) << "Output arguments not defined."; |
| return TPM_RC_SUCCESS; |
| } |
| if (key_blob.size() == 0) { |
| public_info->size = 0; |
| private_info->size = 0; |
| return TPM_RC_SUCCESS; |
| } |
| std::string mutable_key_blob = key_blob; |
| TPM_RC result = Parse_TPM2B_PUBLIC(&mutable_key_blob, public_info, NULL); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error parsing TPM2B_Public: " << GetErrorString(result); |
| return result; |
| } |
| result = Parse_TPM2B_PRIVATE(&mutable_key_blob, private_info, NULL); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error parsing TPM2B_Private: " << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::KeyDataToString(const TPM2B_PUBLIC& public_info, |
| const TPM2B_PRIVATE& private_info, |
| std::string* key_blob) { |
| if (!key_blob) { |
| LOG(WARNING) << "Output arguments not defined."; |
| return TPM_RC_SUCCESS; |
| } |
| if ((public_info.size == 0) && (private_info.size == 0)) { |
| key_blob->clear(); |
| return TPM_RC_SUCCESS; |
| } |
| TPM_RC result = Serialize_TPM2B_PUBLIC(public_info, key_blob); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error serializing TPM2B_Public: " << GetErrorString(result); |
| return result; |
| } |
| result = Serialize_TPM2B_PRIVATE(private_info, key_blob); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error serializing TPM2B_Private: " |
| << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::ComputeKeyName(const TPMT_PUBLIC& public_area, |
| std::string* object_name) { |
| std::string serialized_public_area; |
| TPM_RC result = Serialize_TPMT_PUBLIC(public_area, &serialized_public_area); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error serializing public area: " << GetErrorString(result); |
| return result; |
| } |
| std::string serialized_name_alg; |
| result = Serialize_TPM_ALG_ID(TPM_ALG_SHA256, &serialized_name_alg); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error serializing public area: " << GetErrorString(result); |
| return result; |
| } |
| object_name->assign(serialized_name_alg + |
| crypto::SHA256HashString(serialized_public_area)); |
| return TPM_RC_SUCCESS; |
| } |
| |
| TPM_RC TpmUtilityImpl::EncryptPrivateData(const TPMT_SENSITIVE& sensitive_area, |
| const TPMT_PUBLIC& public_area, |
| TPM2B_PRIVATE* encrypted_private_data, |
| TPM2B_DATA* encryption_key) { |
| TPM2B_SENSITIVE sensitive_data = Make_TPM2B_SENSITIVE(sensitive_area); |
| std::string serialized_sensitive_data; |
| TPM_RC result = Serialize_TPM2B_SENSITIVE(sensitive_data, |
| &serialized_sensitive_data); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error serializing sensitive data: " |
| << GetErrorString(result); |
| return result; |
| } |
| std::string object_name; |
| result = ComputeKeyName(public_area, &object_name); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error computing object name: " << GetErrorString(result); |
| return result; |
| } |
| TPM2B_DIGEST inner_integrity = Make_TPM2B_DIGEST(crypto::SHA256HashString( |
| serialized_sensitive_data + object_name)); |
| std::string serialized_inner_integrity; |
| result = Serialize_TPM2B_DIGEST(inner_integrity, &serialized_inner_integrity); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error serializing inner integrity: " |
| << GetErrorString(result); |
| return result; |
| } |
| std::string unencrypted_private_data = serialized_inner_integrity + |
| serialized_sensitive_data; |
| AES_KEY key; |
| AES_set_encrypt_key(encryption_key->buffer, kAesKeySize * 8, &key); |
| std::string private_data_string(unencrypted_private_data.size(), 0); |
| int iv_in = 0; |
| unsigned char iv[MAX_AES_BLOCK_SIZE_BYTES] = {0}; |
| AES_cfb128_encrypt( |
| reinterpret_cast<const unsigned char*>(unencrypted_private_data.data()), |
| reinterpret_cast<unsigned char*>(string_as_array(&private_data_string)), |
| unencrypted_private_data.size(), &key, iv, &iv_in, AES_ENCRYPT); |
| *encrypted_private_data = Make_TPM2B_PRIVATE(private_data_string); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error making private area: " |
| << GetErrorString(result); |
| return result; |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| } // namespace trunks |