| // Copyright 2023 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "libhwsec/backend/tpm2/attestation.h" | |
| #include <memory> | |
| #include <optional> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <attestation/proto_bindings/attestation_ca.pb.h> | |
| #include <attestation/proto_bindings/database.pb.h> | |
| #include <base/strings/stringprintf.h> | |
| #include <crypto/scoped_openssl_types.h> | |
| #include <crypto/secure_util.h> | |
| #include <crypto/sha2.h> | |
| #include <tpm_manager-client/tpm_manager/dbus-constants.h> | |
| #include <trunks/mock_tpm_utility.h> | |
| #include <trunks/multiple_authorization_delegate.h> | |
| #include <libhwsec-foundation/crypto/aes.h> | |
| #include <libhwsec-foundation/crypto/hmac.h> | |
| #include <libhwsec-foundation/status/status_chain_macros.h> | |
| #include <trunks/tpm_generated.h> | |
| #include "libhwsec/backend/tpm2/static_utils.h" | |
| #include "libhwsec/error/tpm2_error.h" | |
| #include "libhwsec/error/tpm_manager_error.h" | |
| #include "libhwsec/status.h" | |
| #include "libhwsec/structures/key.h" | |
| #include "libhwsec/structures/operation_policy.h" | |
| using brillo::BlobFromString; | |
| using brillo::BlobToString; | |
| using hwsec_foundation::status::MakeStatus; | |
| using trunks::TPM_RC; | |
| using trunks::TPM_RC_SUCCESS; | |
| using Mode = hwsec::DeviceConfigSettings::BootModeSetting::Mode; | |
| namespace hwsec { | |
| namespace { | |
| constexpr size_t kRandomCertifiedKeyPasswordLength = 32; | |
| const char kHashHeaderForEncrypt[] = "ENCRYPT"; | |
| const char kHashHeaderForMac[] = "MAC"; | |
| std::string GetDescriptionForMode(const Mode& mode) { | |
| return base::StringPrintf( | |
| "(Developer Mode: %s, Recovery Mode: %s, Firmware Type: %s)", | |
| mode.developer_mode ? "On" : "Off", mode.recovery_mode ? "On" : "Off", | |
| mode.verified_firmware ? "Verified" : "Developer"); | |
| } | |
| StatusOr<brillo::SecureBlob> DecryptIdentityCertificate( | |
| const std::string& credential, const attestation::EncryptedData& input) { | |
| brillo::SecureBlob aes_key( | |
| crypto::SHA256HashString(kHashHeaderForEncrypt + credential)); | |
| brillo::SecureBlob hmac_key( | |
| crypto::SHA256HashString(kHashHeaderForMac + credential)); | |
| brillo::SecureBlob expected_mac = hwsec_foundation::HmacSha512( | |
| hmac_key, brillo::SecureBlob(input.iv() + input.encrypted_data())); | |
| if (expected_mac.size() != input.mac().size()) { | |
| return MakeStatus<TPMError>("MAC size mismatch", TPMRetryAction::kNoRetry); | |
| } | |
| if (!crypto::SecureMemEqual(expected_mac.data(), input.mac().data(), | |
| expected_mac.size())) { | |
| return MakeStatus<TPMError>("MAC mismatch", TPMRetryAction::kNoRetry); | |
| } | |
| brillo::SecureBlob decrypted; | |
| brillo::Blob encrypted = BlobFromString(input.encrypted_data()); | |
| brillo::Blob iv = BlobFromString(input.iv()); | |
| if (!hwsec_foundation::AesDecryptSpecifyBlockMode( | |
| encrypted, 0, encrypted.size(), brillo::SecureBlob(aes_key), iv, | |
| hwsec_foundation::PaddingScheme::kPaddingStandard, | |
| hwsec_foundation::BlockMode::kCbc, &decrypted)) { | |
| return MakeStatus<TPMError>("AES Decryption failed", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| return decrypted; | |
| } | |
| Status RemoveOwnerDependencyForAttestation( | |
| org::chromium::TpmManagerProxyInterface& tpm_manager) { | |
| tpm_manager::RemoveOwnerDependencyRequest request; | |
| request.set_owner_dependency(tpm_manager::kTpmOwnerDependency_Attestation); | |
| tpm_manager::RemoveOwnerDependencyReply reply; | |
| if (brillo::ErrorPtr err; !tpm_manager.RemoveOwnerDependency( | |
| request, &reply, &err, Proxy::kDefaultDBusTimeoutMs)) { | |
| return MakeStatus<TPMError>(TPMRetryAction::kCommunication) | |
| .Wrap(std::move(err)); | |
| } | |
| RETURN_IF_ERROR(MakeStatus<TPMManagerError>(reply.status())); | |
| return OkStatus(); | |
| } | |
| } // namespace | |
| StatusOr<attestation::TpmVersion> AttestationTpm2::GetTpmVersion() { | |
| return attestation::TpmVersion::TPM_2_0; | |
| } | |
| StatusOr<attestation::Quote> AttestationTpm2::Quote( | |
| DeviceConfigs device_configs, Key key) { | |
| if (device_configs.none()) { | |
| return MakeStatus<TPMError>("No device config specified", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| attestation::Quote quote; | |
| ASSIGN_OR_RETURN(const KeyTpm2& key_data, key_management_.GetKeyData(key)); | |
| ASSIGN_OR_RETURN(const ConfigTpm2::PcrMap& pcr_map, | |
| config_.ToPcrMap(device_configs), | |
| _.WithStatus<TPMError>("Failed to get PCR map")); | |
| if (pcr_map.size() == 1) { | |
| int pcr = pcr_map.begin()->first; | |
| ASSIGN_OR_RETURN(const std::string& value, config_.ReadPcr(pcr), | |
| _.WithStatus<TPMError>("Failed to read PCR")); | |
| quote.set_quoted_pcr_value(value); | |
| } | |
| std::unique_ptr<trunks::AuthorizationDelegate> delegate = | |
| context_.GetTrunksFactory().GetPasswordAuthorization(""); | |
| trunks::TPMT_SIG_SCHEME scheme; | |
| scheme.details.any.hash_alg = trunks::TPM_ALG_SHA256; | |
| ASSIGN_OR_RETURN(scheme.scheme, | |
| signing_.GetSignAlgorithm(key_data, SigningOptions{}), | |
| _.WithStatus<TPMError>("Failed to get signing algorithm")); | |
| trunks::TPML_PCR_SELECTION pcr_select; | |
| pcr_select.count = 1; | |
| ASSIGN_OR_RETURN(pcr_select.pcr_selections[0], | |
| config_.ToPcrSelection(device_configs), | |
| _.WithStatus<TPMError>( | |
| "Failed to convert device configs to PCR selection")); | |
| const trunks::TPM_HANDLE& key_handle = key_data.key_handle; | |
| std::string key_name; | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(context_.GetTpmUtility().GetKeyName( | |
| key_handle, &key_name))) | |
| .WithStatus<TPMError>("Failed to get key name"); | |
| trunks::TPM2B_ATTEST quoted_struct; | |
| trunks::TPMT_SIGNATURE signature; | |
| RETURN_IF_ERROR( | |
| MakeStatus<TPM2Error>(context_.GetTrunksFactory().GetTpm()->QuoteSync( | |
| key_handle, key_name, | |
| trunks::Make_TPM2B_DATA("") /* No qualifying data */, scheme, | |
| pcr_select, "ed_struct, &signature, delegate.get()))) | |
| .WithStatus<TPMError>("Failed to quote"); | |
| if (device_configs[DeviceConfig::kDeviceModel]) { | |
| if (StatusOr<std::string> hwid = config_.GetHardwareID(); !hwid.ok()) { | |
| LOG(WARNING) << "Failed to get Hardware ID: " << hwid.status(); | |
| } else { | |
| quote.set_pcr_source_hint(hwid.value()); | |
| } | |
| } | |
| ASSIGN_OR_RETURN(const std::string& sig, | |
| SerializeFromTpmSignature(signature)); | |
| quote.set_quote(sig); | |
| if (quoted_struct.size > sizeof(quoted_struct.attestation_data)) { | |
| return MakeStatus<TPMError>("Quoted struct overflow", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| quote.set_quoted_data(StringFrom_TPM2B_ATTEST(quoted_struct)); | |
| return quote; | |
| } | |
| // TODO(b/141520502): Verify the quote against expected output. | |
| StatusOr<bool> AttestationTpm2::IsQuoted(DeviceConfigs device_configs, | |
| const attestation::Quote& quote) { | |
| if (device_configs.none()) { | |
| return MakeStatus<TPMError>("No device config specified", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| if (!quote.has_quoted_data()) { | |
| return MakeStatus<TPMError>("Invalid attestation::Quote", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| if (device_configs[DeviceConfig::kBootMode]) { | |
| ASSIGN_OR_RETURN(Mode mode, config_.GetCurrentBootMode(), | |
| _.WithStatus<TPMError>("Failed to get current boot mode")); | |
| ASSIGN_OR_RETURN(Mode quoted_mode, | |
| config_.ToBootMode(quote.quoted_pcr_value()), | |
| _.WithStatus<TPMError>("Failed to get quoted boot mode")); | |
| if (mode != quoted_mode) { | |
| std::string err_msg = base::StringPrintf( | |
| "Quoted boot mode mismatched: current %s vs quoted %s", | |
| GetDescriptionForMode(mode).c_str(), | |
| GetDescriptionForMode(quoted_mode).c_str()); | |
| return MakeStatus<TPMError>(err_msg, TPMRetryAction::kNoRetry); | |
| } | |
| } | |
| std::string quoted_data = quote.quoted_data(); | |
| trunks::TPMS_ATTEST quoted_struct; | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(trunks::Parse_TPMS_ATTEST( | |
| "ed_data, "ed_struct, nullptr))) | |
| .WithStatus<TPMError>("Failed to parse TPMS_ATTEST"); | |
| if (quoted_struct.magic != trunks::TPM_GENERATED_VALUE) { | |
| return MakeStatus<TPMError>("Bad magic value", TPMRetryAction::kNoRetry); | |
| } | |
| if (quoted_struct.type != trunks::TPM_ST_ATTEST_QUOTE) { | |
| return MakeStatus<TPMError>("Not a quote", TPMRetryAction::kNoRetry); | |
| } | |
| const trunks::TPML_PCR_SELECTION& pcr_select = | |
| quoted_struct.attested.quote.pcr_select; | |
| if (pcr_select.count != 1) { | |
| return MakeStatus<TPMError>("Wrong number of PCR selection", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| const trunks::TPMS_PCR_SELECTION& pcr_selection = | |
| pcr_select.pcr_selections[0]; | |
| ASSIGN_OR_RETURN(trunks::TPMS_PCR_SELECTION expected_pcr_selection, | |
| config_.ToPcrSelection(device_configs), | |
| _.WithStatus<TPMError>( | |
| "Failed to convert device configs to PCR selection")); | |
| if (pcr_selection.sizeof_select != expected_pcr_selection.sizeof_select) { | |
| return MakeStatus<TPMError>("Size of pcr_selections mismatched", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| for (int i = 0; i < pcr_selection.sizeof_select; ++i) { | |
| if (pcr_selection.pcr_select[i] != expected_pcr_selection.pcr_select[i]) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| StatusOr<AttestationTpm2::CertifyKeyResult> AttestationTpm2::CertifyKey( | |
| Key key, Key identity_key, const std::string& external_data) { | |
| ASSIGN_OR_RETURN(const KeyTpm2& key_data, key_management_.GetKeyData(key), | |
| _.WithStatus<TPMError>("Failed to get key data")); | |
| ASSIGN_OR_RETURN(const KeyTpm2& identity_key_data, | |
| key_management_.GetKeyData(identity_key), | |
| _.WithStatus<TPMError>("Failed to get identity key data")); | |
| const trunks::TPM_HANDLE& key_handle = key_data.key_handle; | |
| const trunks::TPM_HANDLE& identity_key_handle = identity_key_data.key_handle; | |
| std::string key_name; | |
| std::string identity_key_name; | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(context_.GetTpmUtility().GetKeyName( | |
| key_handle, &key_name))) | |
| .WithStatus<TPMError>("Failed to get key name"); | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(context_.GetTpmUtility().GetKeyName( | |
| identity_key_handle, &identity_key_name))) | |
| .WithStatus<TPMError>("Failed to get key name"); | |
| trunks::TPMT_SIG_SCHEME scheme; | |
| scheme.details.any.hash_alg = trunks::TPM_ALG_SHA256; | |
| ASSIGN_OR_RETURN( | |
| scheme.scheme, | |
| signing_.GetSignAlgorithm(identity_key_data, SigningOptions{}), | |
| _.WithStatus<TPMError>("Failed to get signing algorithm")); | |
| std::string certified_key_password; | |
| if (key_data.cache.policy.permission.type == PermissionType::kAuthValue && | |
| key_data.cache.policy.permission.auth_value.has_value()) { | |
| certified_key_password = | |
| key_data.cache.policy.permission.auth_value.value().to_string(); | |
| } | |
| std::unique_ptr<trunks::AuthorizationDelegate> | |
| certified_key_password_authorization = | |
| context_.GetTrunksFactory().GetPasswordAuthorization( | |
| certified_key_password); | |
| std::unique_ptr<trunks::AuthorizationDelegate> empty_password_authorization = | |
| context_.GetTrunksFactory().GetPasswordAuthorization(""); | |
| trunks::MultipleAuthorizations authorization; | |
| authorization.AddAuthorizationDelegate( | |
| certified_key_password_authorization.get()); | |
| authorization.AddAuthorizationDelegate(empty_password_authorization.get()); | |
| trunks::TPM2B_ATTEST certify_info; | |
| trunks::TPMT_SIGNATURE signature; | |
| RETURN_IF_ERROR( | |
| MakeStatus<TPM2Error>(context_.GetTrunksFactory().GetTpm()->CertifySync( | |
| key_handle, key_name, identity_key_handle, identity_key_name, | |
| trunks::Make_TPM2B_DATA(external_data), scheme, &certify_info, | |
| &signature, &authorization))) | |
| .WithStatus<TPMError>("Failed to certify key"); | |
| ASSIGN_OR_RETURN(const std::string& sig, | |
| SerializeFromTpmSignature(signature)); | |
| return CertifyKeyResult{ | |
| .certify_info = StringFrom_TPM2B_ATTEST(certify_info), | |
| .signature = sig, | |
| }; | |
| } | |
| StatusOr<attestation::CertifiedKey> AttestationTpm2::CreateCertifiedKey( | |
| Key identity_key, | |
| attestation::KeyType key_type, | |
| attestation::KeyUsage key_usage, | |
| KeyRestriction restriction, | |
| EndorsementAuth endorsement_auth, | |
| const std::string& external_data) { | |
| KeyAlgoType key_algo; | |
| switch (key_type) { | |
| case attestation::KeyType::KEY_TYPE_RSA: | |
| key_algo = hwsec::KeyAlgoType::kRsa; | |
| break; | |
| case attestation::KeyType::KEY_TYPE_ECC: | |
| key_algo = hwsec::KeyAlgoType::kEcc; | |
| break; | |
| default: | |
| return MakeStatus<TPMError>("Unsuported key algorithm type", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| OperationPolicySetting policy; | |
| // When generating endorsement key (for vEK), we would create the key with | |
| // both policy and a temporary random password. | |
| if (endorsement_auth == EndorsementAuth::kEndorsement) { | |
| ASSIGN_OR_RETURN( | |
| const brillo::SecureBlob& random_password, | |
| random_.RandomSecureBlob(kRandomCertifiedKeyPasswordLength), | |
| _.WithStatus<TPMError>("Failed to create random password")); | |
| policy = OperationPolicySetting{ | |
| .device_config_settings = | |
| DeviceConfigSettings{ | |
| .use_endorsement_auth = true, | |
| }, | |
| .permission = | |
| Permission{ | |
| .auth_value = std::move(random_password), | |
| }, | |
| }; | |
| } | |
| ASSIGN_OR_RETURN( | |
| const KeyManagement::CreateKeyResult& create_key_result, | |
| key_management_.CreateKey( | |
| policy, key_algo, KeyManagement::LoadKeyOptions{.auto_reload = true}, | |
| KeyManagement::CreateKeyOptions{ | |
| .allow_software_gen = false, | |
| .allow_decrypt = | |
| key_usage == attestation::KeyUsage::KEY_USAGE_DECRYPT, | |
| .allow_sign = key_usage == attestation::KeyUsage::KEY_USAGE_SIGN, | |
| .restricted = restriction == KeyRestriction::kRestricted, | |
| }), | |
| _.WithStatus<TPMError>("Failed to create key")); | |
| const ScopedKey& key = create_key_result.key; | |
| const brillo::Blob& key_blob = create_key_result.key_blob; | |
| ASSIGN_OR_RETURN(const CertifyKeyResult& certify_key_result, | |
| CertifyKey(key.GetKey(), identity_key, external_data), | |
| _.WithStatus<TPMError>("Failed to certify key")); | |
| ASSIGN_OR_RETURN(const KeyTpm2& key_data, | |
| key_management_.GetKeyData(key.GetKey()), | |
| _.WithStatus<TPMError>("Failed to get key data")); | |
| const trunks::TPMT_PUBLIC& public_data = key_data.cache.public_area; | |
| std::string serialized_public_key; | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(trunks::Serialize_TPMT_PUBLIC( | |
| public_data, &serialized_public_key))) | |
| .WithStatus<TPMError>("Failed to serialized TPMT_PUBLIC"); | |
| ASSIGN_OR_RETURN( | |
| const brillo::Blob& public_key_der, | |
| key_management_.GetPublicKeyDer(key.GetKey(), | |
| /*use_rsa_subject_key_info=*/false), | |
| _.WithStatus<TPMError>("Failed to get public key in DER format")); | |
| attestation::CertifiedKey certified_key; | |
| certified_key.set_key_blob(BlobToString(key_blob)); | |
| certified_key.set_public_key(BlobToString(public_key_der)); | |
| certified_key.set_public_key_tpm_format(serialized_public_key); | |
| certified_key.set_certified_key_info(certify_key_result.certify_info); | |
| certified_key.set_certified_key_proof(certify_key_result.signature); | |
| certified_key.set_key_type(key_type); | |
| certified_key.set_key_usage(key_usage); | |
| return certified_key; | |
| } | |
| StatusOr<Attestation::CreateIdentityResult> AttestationTpm2::CreateIdentity( | |
| attestation::KeyType key_type) { | |
| trunks::TPM_ALG_ID algorithm; | |
| switch (key_type) { | |
| case attestation::KEY_TYPE_RSA: | |
| algorithm = trunks::TPM_ALG_RSA; | |
| break; | |
| case attestation::KEY_TYPE_ECC: | |
| algorithm = trunks::TPM_ALG_ECC; | |
| break; | |
| default: | |
| return MakeStatus<TPMError>("Unsupported key algorithm type", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| std::unique_ptr<trunks::AuthorizationDelegate> delegate = | |
| context_.GetTrunksFactory().GetPasswordAuthorization(""); | |
| std::string identity_key_blob; | |
| RETURN_IF_ERROR( | |
| MakeStatus<TPM2Error>(context_.GetTpmUtility().CreateIdentityKey( | |
| algorithm, delegate.get(), &identity_key_blob))) | |
| .WithStatus<TPMError>("Failed to call CreateIdentityKey"); | |
| std::unique_ptr<trunks::BlobParser> parser = | |
| context_.GetTrunksFactory().GetBlobParser(); | |
| trunks::TPM2B_PUBLIC public_info; | |
| trunks::TPM2B_PRIVATE not_used; | |
| if (!parser->ParseKeyBlob(identity_key_blob, &public_info, ¬_used)) { | |
| return MakeStatus<TPMError>("Failed to parse key blob", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| const trunks::TPMT_PUBLIC& public_data = public_info.public_area; | |
| std::string serialized_public_key; | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(trunks::Serialize_TPMT_PUBLIC( | |
| public_data, &serialized_public_key))) | |
| .WithStatus<TPMError>("Failed to serialized TPMT_PUBLIC"); | |
| ASSIGN_OR_RETURN( | |
| const brillo::Blob& public_key_der, | |
| key_management_.GetPublicKeyDerFromPublicData(public_data, false), | |
| _.WithStatus<TPMError>("Failed to get public key in DER format")); | |
| attestation::IdentityKey identity_key_info; | |
| identity_key_info.set_identity_key_type(key_type); | |
| identity_key_info.set_identity_public_key_der(BlobToString(public_key_der)); | |
| identity_key_info.set_identity_key_blob(identity_key_blob); | |
| attestation::IdentityBinding identity_binding_info; | |
| identity_binding_info.set_identity_public_key_tpm_format( | |
| serialized_public_key); | |
| identity_binding_info.set_identity_public_key_der( | |
| BlobToString(public_key_der)); | |
| return Attestation::CreateIdentityResult{ | |
| .identity_key = identity_key_info, | |
| .identity_binding = identity_binding_info, | |
| }; | |
| } | |
| StatusOr<brillo::SecureBlob> AttestationTpm2::ActivateIdentity( | |
| attestation::KeyType key_type, | |
| Key identity_key, | |
| const attestation::EncryptedIdentityCredential& encrypted_certificate) { | |
| KeyAlgoType key_algo; | |
| switch (key_type) { | |
| case attestation::KEY_TYPE_RSA: | |
| key_algo = hwsec::KeyAlgoType::kRsa; | |
| break; | |
| case attestation::KEY_TYPE_ECC: | |
| key_algo = hwsec::KeyAlgoType::kEcc; | |
| break; | |
| default: | |
| return MakeStatus<TPMError>("Unsupported key algorithm type", | |
| TPMRetryAction::kNoRetry); | |
| } | |
| std::unique_ptr<trunks::AuthorizationDelegate> delegate = | |
| context_.GetTrunksFactory().GetPasswordAuthorization(""); | |
| ASSIGN_OR_RETURN(ScopedKey endorsment_key, | |
| key_management_.GetEndorsementKey(key_algo)); | |
| ASSIGN_OR_RETURN( | |
| const KeyTpm2& endorsement_key_data, | |
| key_management_.GetKeyData(endorsment_key.GetKey()), | |
| _.WithStatus<TPMError>("Failed to get endorsement key data")); | |
| ASSIGN_OR_RETURN(const KeyTpm2& identity_key_data, | |
| key_management_.GetKeyData(identity_key), | |
| _.WithStatus<TPMError>("Failed to get identity key data")); | |
| const trunks::TPM_HANDLE& endorsement_key_handle = | |
| endorsement_key_data.key_handle; | |
| const trunks::TPM_HANDLE& identity_key_handle = identity_key_data.key_handle; | |
| std::string endorsement_key_name; | |
| std::string identity_key_name; | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(context_.GetTpmUtility().GetKeyName( | |
| endorsement_key_handle, &endorsement_key_name))) | |
| .WithStatus<TPMError>("Failed to get endorsement key name"); | |
| RETURN_IF_ERROR(MakeStatus<TPM2Error>(context_.GetTpmUtility().GetKeyName( | |
| identity_key_handle, &identity_key_name))) | |
| .WithStatus<TPMError>("Failed to get identity key name"); | |
| ASSIGN_OR_RETURN( | |
| const brillo::SecureBlob& endorsement_password, | |
| GetEndorsementPassword(tpm_manager_), | |
| _.WithStatus<TPMError>("Failed to get endorsement password")); | |
| std::unique_ptr<trunks::HmacSession> endorsement_session = | |
| context_.GetTrunksFactory().GetHmacSession(); | |
| RETURN_IF_ERROR( | |
| MakeStatus<TPM2Error>(endorsement_session->StartUnboundSession( | |
| true /* salted */, false /* enable_encryption */))) | |
| .WithStatus<TPMError>("Failed to start hmac session"); | |
| endorsement_session->SetEntityAuthorizationValue( | |
| endorsement_password.to_string()); | |
| ASSIGN_OR_RETURN(std::unique_ptr<trunks::PolicySession> session, | |
| config_.GetTrunksPolicySession(OperationPolicy{}, | |
| std::vector<std::string>(), | |
| /*salted=*/true, | |
| /*enable_encryption=*/false), | |
| _.WithStatus<TPMError>("Failed to get session for policy")); | |
| trunks::TPMI_DH_ENTITY auth_entity = trunks::TPM_RH_ENDORSEMENT; | |
| std::string auth_entity_name; | |
| trunks::Serialize_TPM_HANDLE(auth_entity, &auth_entity_name); | |
| RETURN_IF_ERROR( | |
| MakeStatus<TPM2Error>(session->PolicySecret( | |
| auth_entity, auth_entity_name, std::string(), std::string(), | |
| std::string(), 0, endorsement_session->GetDelegate()))) | |
| .WithStatus<TPMError>("Failed to set secrete"); | |
| trunks::MultipleAuthorizations authorization; | |
| authorization.AddAuthorizationDelegate(delegate.get()); | |
| authorization.AddAuthorizationDelegate(session->GetDelegate()); | |
| std::string identity_object_data; | |
| trunks::Serialize_TPM2B_DIGEST( | |
| trunks::Make_TPM2B_DIGEST(encrypted_certificate.credential_mac()), | |
| &identity_object_data); | |
| identity_object_data += | |
| encrypted_certificate.wrapped_certificate().wrapped_key(); | |
| trunks::TPM2B_DIGEST encoded_credential; | |
| RETURN_IF_ERROR( | |
| MakeStatus<TPM2Error>( | |
| context_.GetTrunksFactory().GetTpm()->ActivateCredentialSync( | |
| identity_key_handle, identity_key_name, endorsement_key_handle, | |
| endorsement_key_name, | |
| trunks::Make_TPM2B_ID_OBJECT(identity_object_data), | |
| trunks::Make_TPM2B_ENCRYPTED_SECRET( | |
| encrypted_certificate.encrypted_seed()), | |
| &encoded_credential, &authorization))) | |
| .WithStatus<TPMError>("Failed to activate credential"); | |
| std::string credential = trunks::StringFrom_TPM2B_DIGEST(encoded_credential); | |
| return DecryptIdentityCertificate( | |
| credential, encrypted_certificate.wrapped_certificate()); | |
| } | |
| Status AttestationTpm2::FinalizeEnrollmentPreparation() { | |
| return RemoveOwnerDependencyForAttestation(tpm_manager_); | |
| } | |
| } // namespace hwsec |