| // 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 <cstdint> | |
| #include <memory> | |
| #include <utility> | |
| #include <base/strings/string_number_conversions.h> | |
| #include <gtest/gtest.h> | |
| #include <trunks/mock_tpm_utility.h> | |
| #include <libhwsec-foundation/crypto/sha.h> | |
| #include <libhwsec-foundation/error/testing_helper.h> | |
| #include "libhwsec/backend/tpm2/backend_test_base.h" | |
| // Prevent the conflict definition from tss.h | |
| #undef TPM_ALG_RSA | |
| using hwsec_foundation::Sha256; | |
| using hwsec_foundation::error::testing::IsOkAndHolds; | |
| using hwsec_foundation::error::testing::ReturnError; | |
| using hwsec_foundation::error::testing::ReturnValue; | |
| using testing::_; | |
| using testing::DoAll; | |
| using testing::NiceMock; | |
| using testing::Return; | |
| using testing::SaveArg; | |
| using testing::SetArgPointee; | |
| using tpm_manager::TpmManagerStatus; | |
| namespace hwsec { | |
| using BackendDeriveTpm2Test = BackendTpm2TestBase; | |
| TEST_F(BackendDeriveTpm2Test, DeriveSecureRsa) { | |
| const OperationPolicy kFakePolicy{}; | |
| const std::string kFakeKeyBlob = "fake_key_blob"; | |
| const uint32_t kFakeKeyHandle = 0x1337; | |
| const std::string kFakeBlob(256, 'X'); | |
| const std::string kFakeOutput = "fake_output"; | |
| const trunks::TPMT_PUBLIC kFakePublic = { | |
| .type = trunks::TPM_ALG_RSA, | |
| .name_alg = trunks::TPM_ALG_SHA256, | |
| .object_attributes = trunks::kFixedTPM | trunks::kFixedParent, | |
| .auth_policy = trunks::TPM2B_DIGEST{.size = 0}, | |
| .parameters = | |
| trunks::TPMU_PUBLIC_PARMS{ | |
| .rsa_detail = | |
| trunks::TPMS_RSA_PARMS{ | |
| .symmetric = | |
| trunks::TPMT_SYM_DEF_OBJECT{ | |
| .algorithm = trunks::TPM_ALG_NULL, | |
| }, | |
| .scheme = | |
| trunks::TPMT_RSA_SCHEME{ | |
| .scheme = trunks::TPM_ALG_NULL, | |
| }, | |
| .key_bits = 2048, | |
| .exponent = 0, | |
| }, | |
| }, | |
| .unique = | |
| trunks::TPMU_PUBLIC_ID{ | |
| .rsa = | |
| trunks::TPM2B_PUBLIC_KEY_RSA{ | |
| .size = 10, | |
| .buffer = "9876543210", | |
| }, | |
| }, | |
| }; | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), LoadKey(kFakeKeyBlob, _, _)) | |
| .WillOnce(DoAll(SetArgPointee<2>(kFakeKeyHandle), | |
| Return(trunks::TPM_RC_SUCCESS))); | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), GetKeyPublicArea(kFakeKeyHandle, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<1>(kFakePublic), Return(trunks::TPM_RC_SUCCESS))); | |
| auto key = backend_->GetKeyManagementTpm2().LoadKey( | |
| kFakePolicy, brillo::BlobFromString(kFakeKeyBlob), | |
| Backend::KeyManagement::LoadKeyOptions{}); | |
| ASSERT_OK(key); | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), | |
| AsymmetricDecrypt(kFakeKeyHandle, trunks::TPM_ALG_NULL, | |
| trunks::TPM_ALG_NULL, _, _, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<5>(kFakeOutput), Return(trunks::TPM_RC_SUCCESS))); | |
| EXPECT_THAT(backend_->GetDerivingTpm2().SecureDerive( | |
| key->GetKey(), brillo::SecureBlob(kFakeBlob)), | |
| IsOkAndHolds(Sha256(brillo::SecureBlob(kFakeOutput)))); | |
| } | |
| TEST_F(BackendDeriveTpm2Test, DeriveEcc) { | |
| const OperationPolicy kFakePolicy{}; | |
| const std::string kFakeKeyBlob = "fake_key_blob"; | |
| const uint32_t kFakeKeyHandle = 0x1337; | |
| const std::string kFakeBlob(256, 'X'); | |
| const trunks::TPMT_PUBLIC kFakePublic = { | |
| .type = trunks::TPM_ALG_ECC, | |
| .name_alg = trunks::TPM_ALG_SHA256, | |
| .object_attributes = trunks::kFixedTPM | trunks::kFixedParent, | |
| .auth_policy = trunks::TPM2B_DIGEST{.size = 0}, | |
| .parameters = | |
| trunks::TPMU_PUBLIC_PARMS{ | |
| .ecc_detail = | |
| trunks::TPMS_ECC_PARMS{ | |
| .symmetric = | |
| trunks::TPMT_SYM_DEF_OBJECT{ | |
| .algorithm = trunks::TPM_ALG_NULL, | |
| }, | |
| .scheme = | |
| trunks::TPMT_ECC_SCHEME{ | |
| .scheme = trunks::TPM_ALG_NULL, | |
| }, | |
| .curve_id = trunks::TPM_ECC_NIST_P256, | |
| .kdf = | |
| trunks::TPMT_KDF_SCHEME{ | |
| .scheme = trunks::TPM_ALG_NULL, | |
| }, | |
| }, | |
| }, | |
| .unique = | |
| trunks::TPMU_PUBLIC_ID{ | |
| .ecc = | |
| trunks::TPMS_ECC_POINT{ | |
| .x = | |
| trunks::TPM2B_ECC_PARAMETER{ | |
| .size = 10, | |
| .buffer = "0123456789", | |
| }, | |
| .y = trunks::TPM2B_ECC_PARAMETER{.size = 0}, | |
| }, | |
| }, | |
| }; | |
| const trunks::TPM2B_ECC_POINT kFakeZPoint{ | |
| .size = 2 + 10 + 2, | |
| .point = | |
| trunks::TPMS_ECC_POINT{ | |
| .x = | |
| trunks::TPM2B_ECC_PARAMETER{ | |
| .size = 10, | |
| .buffer = "9876543210", | |
| }, | |
| .y = trunks::TPM2B_ECC_PARAMETER{.size = 0}, | |
| }, | |
| }; | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), LoadKey(kFakeKeyBlob, _, _)) | |
| .WillOnce(DoAll(SetArgPointee<2>(kFakeKeyHandle), | |
| Return(trunks::TPM_RC_SUCCESS))); | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), GetKeyPublicArea(kFakeKeyHandle, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<1>(kFakePublic), Return(trunks::TPM_RC_SUCCESS))); | |
| auto key = backend_->GetKeyManagementTpm2().LoadKey( | |
| kFakePolicy, brillo::BlobFromString(kFakeKeyBlob), | |
| Backend::KeyManagement::LoadKeyOptions{}); | |
| ASSERT_OK(key); | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), ECDHZGen(kFakeKeyHandle, _, _, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<3>(kFakeZPoint), Return(trunks::TPM_RC_SUCCESS))); | |
| EXPECT_THAT(backend_->GetDerivingTpm2().Derive( | |
| key->GetKey(), brillo::BlobFromString(kFakeBlob)), | |
| IsOkAndHolds(Sha256(brillo::BlobFromString("9876543210")))); | |
| } | |
| TEST_F(BackendDeriveTpm2Test, DeriveEccOutOfRange) { | |
| const OperationPolicy kFakePolicy{}; | |
| const std::string kFakeKeyBlob = "fake_key_blob"; | |
| const uint32_t kFakeKeyHandle = 0x1337; | |
| const std::string kOorStr = | |
| "AD1FE60D4FF828511B829DA029F98A1A164C4C946776AC1A4DEF3D490371BB66"; | |
| const trunks::TPMT_PUBLIC kFakePublic = { | |
| .type = trunks::TPM_ALG_ECC, | |
| .name_alg = trunks::TPM_ALG_SHA256, | |
| .object_attributes = trunks::kFixedTPM | trunks::kFixedParent, | |
| .auth_policy = trunks::TPM2B_DIGEST{.size = 0}, | |
| .parameters = | |
| trunks::TPMU_PUBLIC_PARMS{ | |
| .ecc_detail = | |
| trunks::TPMS_ECC_PARMS{ | |
| .symmetric = | |
| trunks::TPMT_SYM_DEF_OBJECT{ | |
| .algorithm = trunks::TPM_ALG_NULL, | |
| }, | |
| .scheme = | |
| trunks::TPMT_ECC_SCHEME{ | |
| .scheme = trunks::TPM_ALG_NULL, | |
| }, | |
| .curve_id = trunks::TPM_ECC_NIST_P256, | |
| .kdf = | |
| trunks::TPMT_KDF_SCHEME{ | |
| .scheme = trunks::TPM_ALG_NULL, | |
| }, | |
| }, | |
| }, | |
| .unique = | |
| trunks::TPMU_PUBLIC_ID{ | |
| .ecc = | |
| trunks::TPMS_ECC_POINT{ | |
| .x = | |
| trunks::TPM2B_ECC_PARAMETER{ | |
| .size = 10, | |
| .buffer = "0123456789", | |
| }, | |
| .y = trunks::TPM2B_ECC_PARAMETER{.size = 0}, | |
| }, | |
| }, | |
| }; | |
| brillo::Blob fake_blob; | |
| base::HexStringToBytes(kOorStr, &fake_blob); | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), LoadKey(kFakeKeyBlob, _, _)) | |
| .WillOnce(DoAll(SetArgPointee<2>(kFakeKeyHandle), | |
| Return(trunks::TPM_RC_SUCCESS))); | |
| EXPECT_CALL(proxy_->GetMockTpmUtility(), GetKeyPublicArea(kFakeKeyHandle, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<1>(kFakePublic), Return(trunks::TPM_RC_SUCCESS))); | |
| auto key = backend_->GetKeyManagementTpm2().LoadKey( | |
| kFakePolicy, brillo::BlobFromString(kFakeKeyBlob), | |
| Backend::KeyManagement::LoadKeyOptions{}); | |
| ASSERT_OK(key); | |
| auto result = backend_->GetDerivingTpm2().Derive(key->GetKey(), fake_blob); | |
| ASSERT_NOT_OK(result); | |
| EXPECT_EQ(result.err_status()->ToTPMRetryAction(), | |
| TPMRetryAction::kEllipticCurveScalarOutOfRange); | |
| } | |
| } // namespace hwsec |