| // Copyright 2022 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/encryption.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include <base/functional/callback_helpers.h> |
| #include <brillo/secure_blob.h> |
| #include <libhwsec-foundation/status/status_chain_macros.h> |
| #include <trunks/openssl_utility.h> |
| #include <trunks/tpm_utility.h> |
| |
| #include "libhwsec/error/tpm2_error.h" |
| #include "libhwsec/status.h" |
| #include "libhwsec/structures/no_default_init.h" |
| |
| using brillo::BlobFromString; |
| using brillo::BlobToString; |
| using hwsec_foundation::status::MakeStatus; |
| |
| namespace hwsec { |
| |
| namespace { |
| |
| struct SchemaDetail { |
| NoDefault<trunks::TPM_ALG_ID> schema; |
| NoDefault<trunks::TPM_ALG_ID> hash_alg; |
| }; |
| |
| StatusOr<SchemaDetail> GetSchemaDetail( |
| const EncryptionTpm2::EncryptionOptions& options) { |
| switch (options.schema) { |
| case EncryptionTpm2::EncryptionOptions::Schema::kDefault: |
| return SchemaDetail{ |
| .schema = trunks::TPM_ALG_OAEP, |
| .hash_alg = trunks::TPM_ALG_SHA256, |
| }; |
| case EncryptionTpm2::EncryptionOptions::Schema::kNull: |
| return SchemaDetail{ |
| .schema = trunks::TPM_ALG_NULL, |
| .hash_alg = trunks::TPM_ALG_NULL, |
| }; |
| case EncryptionTpm2::EncryptionOptions::Schema::kRsaesSha1: |
| return SchemaDetail{ |
| .schema = trunks::TPM_ALG_RSAES, |
| .hash_alg = trunks::TPM_ALG_SHA1, |
| }; |
| case EncryptionTpm2::EncryptionOptions::Schema::kOaepSha1: |
| return SchemaDetail{ |
| .schema = trunks::TPM_ALG_OAEP, |
| .hash_alg = trunks::TPM_ALG_SHA1, |
| }; |
| default: |
| return MakeStatus<TPMError>("Unknown options", TPMRetryAction::kNoRetry); |
| } |
| } |
| |
| } // namespace |
| |
| StatusOr<brillo::Blob> EncryptionTpm2::Encrypt( |
| Key key, const brillo::SecureBlob& plaintext, EncryptionOptions options) { |
| ASSIGN_OR_RETURN(const KeyTpm2& key_data, key_management_.GetKeyData(key)); |
| |
| ASSIGN_OR_RETURN(const SchemaDetail& schema, GetSchemaDetail(options)); |
| |
| if (plaintext.size() > MAX_RSA_KEY_BYTES) { |
| return MakeStatus<TPMError>("Plaintext too large", |
| TPMRetryAction::kNoRetry); |
| } |
| |
| std::string data = plaintext.to_string(); |
| |
| // Cleanup the data from secure blob. |
| base::ScopedClosureRunner cleanup_data(base::BindOnce( |
| brillo::SecureClearContainer<std::string>, std::ref(data))); |
| |
| ASSIGN_OR_RETURN( |
| ConfigTpm2::TrunksSession session, |
| config_.GetTrunksSession(key_data.cache.policy, |
| SessionSecuritySetting::kSaltAndEncrypted), |
| _.WithStatus<TPMError>("Failed to get session for policy")); |
| |
| std::string tpm_ciphertext; |
| |
| RETURN_IF_ERROR( |
| MakeStatus<TPM2Error>(context_.GetTpmUtility().AsymmetricEncrypt( |
| key_data.key_handle, schema.schema, schema.hash_alg, data, |
| session.delegate, &tpm_ciphertext))) |
| .WithStatus<TPMError>("Failed to encrypt plaintext"); |
| |
| return BlobFromString(tpm_ciphertext); |
| } |
| |
| StatusOr<brillo::SecureBlob> EncryptionTpm2::Decrypt( |
| Key key, const brillo::Blob& ciphertext, EncryptionOptions options) { |
| ASSIGN_OR_RETURN(const KeyTpm2& key_data, key_management_.GetKeyData(key)); |
| |
| ASSIGN_OR_RETURN(const SchemaDetail& schema, GetSchemaDetail(options)); |
| |
| if (ciphertext.size() > MAX_RSA_KEY_BYTES) { |
| return MakeStatus<TPMError>("Ciphertext too large", |
| TPMRetryAction::kNoRetry); |
| } |
| |
| ASSIGN_OR_RETURN( |
| ConfigTpm2::TrunksSession session, |
| config_.GetTrunksSession(key_data.cache.policy, |
| SessionSecuritySetting::kNoEncrypted), |
| _.WithStatus<TPMError>("Failed to get session for policy")); |
| |
| std::string tpm_plaintext; |
| |
| RETURN_IF_ERROR( |
| MakeStatus<TPM2Error>(context_.GetTpmUtility().AsymmetricDecrypt( |
| key_data.key_handle, schema.schema, schema.hash_alg, |
| BlobToString(ciphertext), session.delegate, &tpm_plaintext))) |
| .WithStatus<TPMError>("Failed to decrypt ciphertext"); |
| |
| brillo::SecureBlob result(tpm_plaintext.begin(), tpm_plaintext.end()); |
| return result; |
| } |
| |
| } // namespace hwsec |