| // Copyright 2019 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 "cryptohome/proxy/legacy_cryptohome_interface_adaptor.h" |
| |
| #include <attestation-client-test/attestation/dbus-proxy-mocks.h> |
| #include <base/files/file_util.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <brillo/dbus/mock_dbus_method_response.h> |
| #include <chromeos/constants/cryptohome.h> |
| #include <tpm_manager-client-test/tpm_manager/dbus-proxy-mocks.h> |
| |
| #include "cryptohome/mock_platform.h" |
| #include "user_data_auth/dbus-proxy-mocks.h" |
| |
| namespace cryptohome { |
| |
| namespace { |
| |
| using ::brillo::dbus_utils::MockDBusMethodResponse; |
| |
| using ::testing::_; |
| using ::testing::DoAll; |
| using ::testing::Invoke; |
| using ::testing::InvokeArgument; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| |
| // A mock adaptor that is used for testing. This is added so that we can capture |
| // the Send*() functions used for sending signals. |
| class LegacyCryptohomeInterfaceAdaptorForTesting |
| : public LegacyCryptohomeInterfaceAdaptor { |
| public: |
| LegacyCryptohomeInterfaceAdaptorForTesting( |
| org::chromium::AttestationProxyInterface* attestation_proxy, |
| org::chromium::TpmManagerProxyInterface* tpm_ownership_proxy, |
| org::chromium::TpmNvramProxyInterface* tpm_nvram_proxy, |
| org::chromium::UserDataAuthInterfaceProxyInterface* userdataauth_proxy, |
| org::chromium::ArcQuotaProxyInterface* arc_quota_proxy, |
| org::chromium::CryptohomePkcs11InterfaceProxyInterface* pkcs11_proxy, |
| org::chromium::InstallAttributesInterfaceProxyInterface* |
| install_attributes_proxy, |
| org::chromium::CryptohomeMiscInterfaceProxyInterface* misc_proxy, |
| cryptohome::Platform* platform) |
| : LegacyCryptohomeInterfaceAdaptor(attestation_proxy, |
| tpm_ownership_proxy, |
| tpm_nvram_proxy, |
| userdataauth_proxy, |
| arc_quota_proxy, |
| pkcs11_proxy, |
| install_attributes_proxy, |
| misc_proxy, |
| platform) {} |
| |
| MOCK_METHOD(void, |
| VirtualSendAsyncCallStatusSignal, |
| (int32_t, bool, int32_t), |
| (override)); |
| MOCK_METHOD(void, |
| VirtualSendAsyncCallStatusWithDataSignal, |
| (int32_t, bool, const std::vector<uint8_t>&), |
| (override)); |
| MOCK_METHOD(void, |
| VirtualSendDircryptoMigrationProgressSignal, |
| (int32_t, uint64_t, uint64_t), |
| (override)); |
| MOCK_METHOD(void, VirtualSendLowDiskSpaceSignal, (uint64_t), (override)); |
| }; |
| |
| // Some common constants used for testing. |
| constexpr char kUsername1[] = "foo@gmail.com"; |
| constexpr char kKeyLabel[] = "somelabel"; |
| constexpr char kSecret[] = "blah"; |
| constexpr char kSanitizedUsername1[] = "baadf00ddeadbeeffeedcafe"; |
| constexpr char kPCARequest[] = "PCA\0Request\xFFMay\x80Have\0None.ASCII"; |
| constexpr char kRequestOrigin[] = "SomeOrigin"; |
| |
| class LegacyCryptohomeInterfaceAdaptorTest : public ::testing::Test { |
| public: |
| LegacyCryptohomeInterfaceAdaptorTest() = default; |
| LegacyCryptohomeInterfaceAdaptorTest( |
| const LegacyCryptohomeInterfaceAdaptorTest&) = delete; |
| LegacyCryptohomeInterfaceAdaptorTest& operator=( |
| const LegacyCryptohomeInterfaceAdaptorTest&) = delete; |
| |
| ~LegacyCryptohomeInterfaceAdaptorTest() override = default; |
| |
| void SetUp() override { |
| adaptor_.reset(new LegacyCryptohomeInterfaceAdaptorForTesting( |
| &attestation_, &ownership_, &nvram_, &userdataauth_, &arc_quota_, |
| &pkcs11_, &install_attributes_, &misc_, &platform_)); |
| |
| account_.set_account_id(kUsername1); |
| auth_.mutable_key()->set_secret(kSecret); |
| } |
| |
| protected: |
| // Mocks that will be passed into |adaptor_| for its internal use. |
| NiceMock<org::chromium::AttestationProxyMock> attestation_; |
| NiceMock<org::chromium::TpmManagerProxyMock> ownership_; |
| NiceMock<org::chromium::TpmNvramProxyMock> nvram_; |
| NiceMock<org::chromium::UserDataAuthInterfaceProxyMock> userdataauth_; |
| NiceMock<org::chromium::ArcQuotaProxyMock> arc_quota_; |
| NiceMock<org::chromium::CryptohomePkcs11InterfaceProxyMock> pkcs11_; |
| NiceMock<org::chromium::InstallAttributesInterfaceProxyMock> |
| install_attributes_; |
| NiceMock<org::chromium::CryptohomeMiscInterfaceProxyMock> misc_; |
| NiceMock<MockPlatform> platform_; |
| |
| // The adaptor that we'll be testing. |
| std::unique_ptr<LegacyCryptohomeInterfaceAdaptorForTesting> adaptor_; |
| |
| // Default account identifier and authentication request set up with valid |
| // value to avoid repeating the same pattern in many test. |
| cryptohome::AccountIdentifier account_; |
| cryptohome::AuthorizationRequest auth_; |
| }; |
| |
| // -------------------------- MountEx Related Tests -------------------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, MountExSuccess) { |
| cryptohome::MountRequest req; |
| user_data_auth::MountRequest proxied_request; |
| |
| req.set_require_ephemeral(false); |
| req.set_force_dircrypto_if_available(true); |
| req.set_to_migrate_from_ecryptfs(false); |
| req.set_public_mount(false); |
| |
| EXPECT_CALL(userdataauth_, MountAsync(_, _, _, _)) |
| .WillOnce( |
| Invoke([&](const user_data_auth::MountRequest& in_request, |
| base::OnceCallback<void(const user_data_auth::MountReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| user_data_auth::MountReply proxied_reply; |
| proxied_reply.set_recreated(true); |
| proxied_reply.set_sanitized_username(kSanitizedUsername1); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->MountEx(std::move(response), account_, auth_, req); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(final_reply.has_value()); |
| |
| // Verify its content |
| EXPECT_EQ(cryptohome::CRYPTOHOME_ERROR_NOT_SET, final_reply->error()); |
| EXPECT_TRUE(final_reply->HasExtension(cryptohome::MountReply::reply)); |
| auto ext = final_reply->GetExtension(cryptohome::MountReply::reply); |
| EXPECT_TRUE(ext.recreated()); |
| EXPECT_EQ(ext.sanitized_username(), kSanitizedUsername1); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.account().account_id(), kUsername1); |
| EXPECT_EQ(proxied_request.authorization().key().secret(), kSecret); |
| EXPECT_FALSE(proxied_request.require_ephemeral()); |
| EXPECT_TRUE(proxied_request.force_dircrypto_if_available()); |
| EXPECT_FALSE(proxied_request.to_migrate_from_ecryptfs()); |
| EXPECT_FALSE(proxied_request.public_mount()); |
| EXPECT_FALSE(proxied_request.guest_mount()); |
| EXPECT_FALSE(proxied_request.has_create()); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, MountExSuccessWithCreate) { |
| cryptohome::MountRequest req; |
| user_data_auth::MountRequest proxied_request; |
| |
| req.set_require_ephemeral(false); |
| req.set_force_dircrypto_if_available(true); |
| req.set_to_migrate_from_ecryptfs(false); |
| req.set_public_mount(false); |
| req.mutable_create()->set_force_ecryptfs(true); |
| req.mutable_create()->set_copy_authorization_key(true); |
| auto key = req.mutable_create()->add_keys(); |
| key->set_secret(kSecret); |
| |
| EXPECT_CALL(userdataauth_, MountAsync(_, _, _, _)) |
| .WillOnce( |
| Invoke([&](const user_data_auth::MountRequest& in_request, |
| base::OnceCallback<void(const user_data_auth::MountReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| user_data_auth::MountReply proxied_reply; |
| proxied_reply.set_recreated(true); |
| proxied_reply.set_sanitized_username(kSanitizedUsername1); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| int respond_count = 0; |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| response->set_return_callback(base::BindRepeating( |
| [](int* respond_count_ptr, const cryptohome::BaseReply& reply) { |
| EXPECT_EQ(cryptohome::CRYPTOHOME_ERROR_NOT_SET, reply.error()); |
| EXPECT_TRUE(reply.HasExtension(cryptohome::MountReply::reply)); |
| auto ext = reply.GetExtension(cryptohome::MountReply::reply); |
| EXPECT_TRUE(ext.recreated()); |
| EXPECT_EQ(ext.sanitized_username(), kSanitizedUsername1); |
| (*respond_count_ptr)++; |
| }, |
| &respond_count)); |
| adaptor_->MountEx(std::move(response), account_, auth_, req); |
| |
| // Verify that Return() is indeed called. |
| EXPECT_EQ(respond_count, 1); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.account().account_id(), kUsername1); |
| EXPECT_EQ(proxied_request.authorization().key().secret(), kSecret); |
| EXPECT_FALSE(proxied_request.require_ephemeral()); |
| EXPECT_TRUE(proxied_request.force_dircrypto_if_available()); |
| EXPECT_FALSE(proxied_request.to_migrate_from_ecryptfs()); |
| EXPECT_FALSE(proxied_request.public_mount()); |
| EXPECT_FALSE(proxied_request.guest_mount()); |
| EXPECT_TRUE(proxied_request.has_create()); |
| EXPECT_TRUE(proxied_request.create().force_ecryptfs()); |
| EXPECT_TRUE(proxied_request.create().copy_authorization_key()); |
| EXPECT_EQ(proxied_request.create().keys_size(), 1); |
| EXPECT_EQ(proxied_request.create().keys(0).secret(), kSecret); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, MountExFail) { |
| cryptohome::MountRequest req; |
| user_data_auth::MountRequest proxied_request; |
| |
| req.set_require_ephemeral(true); |
| req.set_force_dircrypto_if_available(false); |
| req.set_to_migrate_from_ecryptfs(true); |
| req.set_public_mount(true); |
| |
| EXPECT_CALL(userdataauth_, MountAsync(_, _, _, _)) |
| .WillOnce( |
| Invoke([&](const user_data_auth::MountRequest& in_request, |
| base::OnceCallback<void(const user_data_auth::MountReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| user_data_auth::MountReply proxied_reply; |
| proxied_reply.set_error( |
| user_data_auth::CRYPTOHOME_ERROR_MOUNT_FATAL); |
| proxied_reply.set_recreated(false); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->MountEx(std::move(response), account_, auth_, req); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(final_reply.has_value()); |
| |
| // Verify its content |
| EXPECT_EQ(cryptohome::CRYPTOHOME_ERROR_MOUNT_FATAL, final_reply->error()); |
| EXPECT_TRUE(final_reply->HasExtension(cryptohome::MountReply::reply)); |
| auto ext = final_reply->GetExtension(cryptohome::MountReply::reply); |
| EXPECT_FALSE(ext.recreated()); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.account().account_id(), kUsername1); |
| EXPECT_EQ(proxied_request.authorization().key().secret(), kSecret); |
| EXPECT_TRUE(proxied_request.require_ephemeral()); |
| EXPECT_FALSE(proxied_request.force_dircrypto_if_available()); |
| EXPECT_TRUE(proxied_request.to_migrate_from_ecryptfs()); |
| EXPECT_TRUE(proxied_request.public_mount()); |
| EXPECT_FALSE(proxied_request.guest_mount()); |
| } |
| |
| // ------------- TpmIsAttestationPrepared Related Tests ------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmIsAttestationPreparedSuccessResultTrue) { |
| attestation::GetEnrollmentPreparationsRequest proxied_request; |
| EXPECT_CALL(attestation_, GetEnrollmentPreparationsAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::GetEnrollmentPreparationsRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::GetEnrollmentPreparationsReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::GetEnrollmentPreparationsReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| (*proxied_reply.mutable_enrollment_preparations())[0] = true; |
| (*proxied_reply.mutable_enrollment_preparations())[1] = false; |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<bool> result; |
| std::unique_ptr<MockDBusMethodResponse<bool>> response( |
| new MockDBusMethodResponse<bool>(nullptr)); |
| response->save_return_args(&result); |
| |
| adaptor_->TpmIsAttestationPrepared(std::move(response)); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result.has_value()); |
| |
| // Verify response content. |
| EXPECT_TRUE(result.value()); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmIsAttestationPreparedSuccessResultFalse) { |
| attestation::GetEnrollmentPreparationsRequest proxied_request; |
| EXPECT_CALL(attestation_, GetEnrollmentPreparationsAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::GetEnrollmentPreparationsRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::GetEnrollmentPreparationsReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::GetEnrollmentPreparationsReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| (*proxied_reply.mutable_enrollment_preparations())[0] = false; |
| (*proxied_reply.mutable_enrollment_preparations())[1] = false; |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<bool> result; |
| std::unique_ptr<MockDBusMethodResponse<bool>> response( |
| new MockDBusMethodResponse<bool>(nullptr)); |
| response->save_return_args(&result); |
| |
| adaptor_->TpmIsAttestationPrepared(std::move(response)); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result.has_value()); |
| |
| // Verify response content. |
| EXPECT_FALSE(result.value()); |
| } |
| |
| // --------- TpmAttestationGetEnrollmentPreparationsEx Related Tests --------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationGetEnrollmentPreparationsExSuccess) { |
| attestation::GetEnrollmentPreparationsRequest proxied_request; |
| EXPECT_CALL(attestation_, GetEnrollmentPreparationsAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::GetEnrollmentPreparationsRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::GetEnrollmentPreparationsReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::GetEnrollmentPreparationsReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| (*proxied_reply.mutable_enrollment_preparations())[0] = true; |
| (*proxied_reply.mutable_enrollment_preparations())[1] = false; |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<cryptohome::BaseReply> result; |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| response->save_return_args(&result); |
| |
| cryptohome::AttestationGetEnrollmentPreparationsRequest in_request; |
| in_request.set_pca_type(1); |
| adaptor_->TpmAttestationGetEnrollmentPreparationsEx(std::move(response), |
| in_request); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result.has_value()); |
| |
| // Verify response content. |
| EXPECT_EQ(result->error(), cryptohome::CRYPTOHOME_ERROR_NOT_SET); |
| EXPECT_TRUE( |
| result->HasExtension(AttestationGetEnrollmentPreparationsReply::reply)); |
| auto& ext = |
| result->GetExtension(AttestationGetEnrollmentPreparationsReply::reply); |
| EXPECT_EQ(ext.enrollment_preparations().size(), 2); |
| ASSERT_TRUE(ext.enrollment_preparations().contains(0)); |
| EXPECT_TRUE(ext.enrollment_preparations().at(0)); |
| ASSERT_TRUE(ext.enrollment_preparations().contains(1)); |
| EXPECT_FALSE(ext.enrollment_preparations().at(1)); |
| |
| // Check that the proxied request have the right ACA |
| EXPECT_EQ(proxied_request.aca_type(), attestation::ACAType::TEST_ACA); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationGetEnrollmentPreparationsExInvalidACA) { |
| // GetEnrollmentPreparationsAsync() shouldn't get called because the ACA |
| // specified is invalid. |
| EXPECT_CALL(attestation_, GetEnrollmentPreparationsAsync(_, _, _, _)) |
| .Times(0); |
| |
| base::Optional<cryptohome::BaseReply> result; |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| response->save_return_args(&result); |
| EXPECT_CALL( |
| *response, |
| ReplyWithError(_, brillo::errors::dbus::kDomain, DBUS_ERROR_NOT_SUPPORTED, |
| "Requested ACA type 99999 is not supported in " |
| "TpmAttestationGetEnrollmentPreparationsEx()")) |
| .WillOnce(Return()); |
| cryptohome::AttestationGetEnrollmentPreparationsRequest in_request; |
| in_request.set_pca_type(99999); |
| adaptor_->TpmAttestationGetEnrollmentPreparationsEx(std::move(response), |
| in_request); |
| |
| // Verify that Return() is not called |
| ASSERT_FALSE(result.has_value()); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationGetEnrollmentPreparationsExFailure) { |
| attestation::GetEnrollmentPreparationsRequest proxied_request; |
| EXPECT_CALL(attestation_, GetEnrollmentPreparationsAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::GetEnrollmentPreparationsRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::GetEnrollmentPreparationsReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::GetEnrollmentPreparationsReply proxied_reply; |
| proxied_reply.set_status( |
| attestation::STATUS_UNEXPECTED_DEVICE_ERROR); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<cryptohome::BaseReply> result; |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| response->save_return_args(&result); |
| |
| cryptohome::AttestationGetEnrollmentPreparationsRequest in_request; |
| in_request.set_pca_type(1); |
| adaptor_->TpmAttestationGetEnrollmentPreparationsEx(std::move(response), |
| in_request); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result.has_value()); |
| |
| // Verify response content. |
| EXPECT_EQ(result->error(), |
| cryptohome::CRYPTOHOME_ERROR_INTERNAL_ATTESTATION_ERROR); |
| |
| // Check that the proxied request have the right ACA |
| EXPECT_EQ(proxied_request.aca_type(), attestation::ACAType::TEST_ACA); |
| } |
| |
| // ------------- TpmAttestationCreateEnrollRequest Related Tests ------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationCreateEnrollRequestSuccess) { |
| attestation::CreateEnrollRequestRequest proxied_request; |
| EXPECT_CALL(attestation_, CreateEnrollRequestAsync(_, _, _, _)) |
| .WillOnce( |
| Invoke([&](const attestation::CreateEnrollRequestRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::CreateEnrollRequestReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::CreateEnrollRequestReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| proxied_reply.set_pca_request( |
| std::string(kPCARequest, sizeof(kPCARequest))); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<std::vector<uint8_t>> result_pca_request; |
| std::unique_ptr<MockDBusMethodResponse<std::vector<uint8_t>>> response( |
| new MockDBusMethodResponse<std::vector<uint8_t>>(nullptr)); |
| response->save_return_args(&result_pca_request); |
| |
| adaptor_->TpmAttestationCreateEnrollRequest( |
| std::move(response), static_cast<int>(attestation::TEST_ACA)); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result_pca_request.has_value()); |
| |
| // Verify response content. |
| EXPECT_EQ( |
| result_pca_request.value(), |
| std::vector<uint8_t>(kPCARequest, kPCARequest + sizeof(kPCARequest))); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.aca_type(), attestation::TEST_ACA); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationCreateEnrollRequestInvalidACA) { |
| std::unique_ptr<MockDBusMethodResponse<std::vector<uint8_t>>> response( |
| new MockDBusMethodResponse<std::vector<uint8_t>>(nullptr)); |
| EXPECT_CALL( |
| *response, |
| ReplyWithError(_, brillo::errors::dbus::kDomain, DBUS_ERROR_NOT_SUPPORTED, |
| "Requested ACA type 99999 is not supported")) |
| .WillOnce(Return()); |
| |
| // 99999 is an invalid ACA |
| adaptor_->TpmAttestationCreateEnrollRequest(std::move(response), 99999); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationCreateEnrollRequestFailed) { |
| attestation::CreateEnrollRequestRequest proxied_request; |
| EXPECT_CALL(attestation_, CreateEnrollRequestAsync(_, _, _, _)) |
| .WillOnce( |
| Invoke([&](const attestation::CreateEnrollRequestRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::CreateEnrollRequestReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::CreateEnrollRequestReply reply; |
| reply.set_status(attestation::STATUS_UNEXPECTED_DEVICE_ERROR); |
| std::move(success_callback).Run(reply); |
| })); |
| |
| std::unique_ptr<MockDBusMethodResponse<std::vector<uint8_t>>> response( |
| new MockDBusMethodResponse<std::vector<uint8_t>>(nullptr)); |
| EXPECT_CALL( |
| *response, |
| ReplyWithError(_, brillo::errors::dbus::kDomain, DBUS_ERROR_FAILED, |
| "Attestation daemon returned status " + |
| std::to_string(static_cast<int>( |
| attestation::STATUS_UNEXPECTED_DEVICE_ERROR)))) |
| .WillOnce(Return()); |
| adaptor_->TpmAttestationCreateEnrollRequest( |
| std::move(response), static_cast<int>(attestation::DEFAULT_ACA)); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.aca_type(), attestation::DEFAULT_ACA); |
| } |
| |
| // ------------------- TpmAttestationEnroll Related Tests ------------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, TpmAttestationEnrollSuccess) { |
| attestation::FinishEnrollRequest proxied_request; |
| EXPECT_CALL(attestation_, FinishEnrollAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::FinishEnrollRequest& in_request, |
| base::OnceCallback<void(const attestation::FinishEnrollReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) { |
| proxied_request = in_request; |
| attestation::FinishEnrollReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| base::Optional<bool> result_success; |
| std::unique_ptr<MockDBusMethodResponse<bool>> response( |
| new MockDBusMethodResponse<bool>(nullptr)); |
| response->save_return_args(&result_success); |
| |
| std::vector<uint8_t> pca_request(kPCARequest, |
| kPCARequest + sizeof(kPCARequest)); |
| adaptor_->TpmAttestationEnroll(std::move(response), |
| static_cast<int>(attestation::TEST_ACA), |
| pca_request); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result_success.has_value()); |
| |
| // Verify the response. |
| EXPECT_TRUE(result_success.value()); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.aca_type(), attestation::TEST_ACA); |
| EXPECT_EQ(proxied_request.pca_response(), |
| std::string(kPCARequest, kPCARequest + sizeof(kPCARequest))); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, TpmAttestationEnrollInvalidACA) { |
| std::unique_ptr<MockDBusMethodResponse<bool>> response( |
| new MockDBusMethodResponse<bool>(nullptr)); |
| EXPECT_CALL( |
| *response, |
| ReplyWithError(_, brillo::errors::dbus::kDomain, DBUS_ERROR_NOT_SUPPORTED, |
| "Requested ACA type 99999 is not supported")) |
| .WillOnce(Return()); |
| std::vector<uint8_t> pca_request(kPCARequest, |
| kPCARequest + sizeof(kPCARequest)); |
| |
| // 99999 is an invalid ACA |
| adaptor_->TpmAttestationEnroll(std::move(response), 99999, pca_request); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, TpmAttestationEnrollFailed) { |
| attestation::FinishEnrollRequest proxied_request; |
| EXPECT_CALL(attestation_, FinishEnrollAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::FinishEnrollRequest& in_request, |
| base::OnceCallback<void(const attestation::FinishEnrollReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) { |
| proxied_request = in_request; |
| attestation::FinishEnrollReply reply; |
| reply.set_status(attestation::STATUS_NOT_READY); |
| std::move(success_callback).Run(reply); |
| })); |
| base::Optional<bool> result_success; |
| std::unique_ptr<MockDBusMethodResponse<bool>> response( |
| new MockDBusMethodResponse<bool>(nullptr)); |
| response->save_return_args(&result_success); |
| |
| std::vector<uint8_t> pca_request(kPCARequest, |
| kPCARequest + sizeof(kPCARequest)); |
| adaptor_->TpmAttestationEnroll(std::move(response), |
| static_cast<int>(attestation::DEFAULT_ACA), |
| pca_request); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result_success.has_value()); |
| |
| // Verify the response. |
| EXPECT_FALSE(result_success.value()); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.aca_type(), attestation::DEFAULT_ACA); |
| EXPECT_EQ(proxied_request.pca_response(), |
| std::string(kPCARequest, kPCARequest + sizeof(kPCARequest))); |
| } |
| |
| // ------------- TpmAttestationCreateCertRequest Related Tests ------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationCreateCertRequestSuccess) { |
| attestation::CreateCertificateRequestRequest proxied_request; |
| EXPECT_CALL(attestation_, CreateCertificateRequestAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::CreateCertificateRequestRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::CreateCertificateRequestReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::CreateCertificateRequestReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| proxied_reply.set_pca_request( |
| std::string(kPCARequest, sizeof(kPCARequest))); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| base::Optional<std::vector<uint8_t>> result_pca_request; |
| std::unique_ptr<MockDBusMethodResponse<std::vector<uint8_t>>> response( |
| new MockDBusMethodResponse<std::vector<uint8_t>>(nullptr)); |
| response->save_return_args(&result_pca_request); |
| |
| adaptor_->TpmAttestationCreateCertRequest( |
| std::move(response), static_cast<int>(attestation::TEST_ACA), |
| static_cast<int>(attestation::CONTENT_PROTECTION_CERTIFICATE), kUsername1, |
| kRequestOrigin); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result_pca_request.has_value()); |
| |
| // Verify response content. |
| EXPECT_EQ( |
| result_pca_request.value(), |
| std::vector<uint8_t>(kPCARequest, kPCARequest + sizeof(kPCARequest))); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.aca_type(), attestation::TEST_ACA); |
| EXPECT_EQ(proxied_request.username(), kUsername1); |
| EXPECT_EQ(proxied_request.request_origin(), kRequestOrigin); |
| EXPECT_EQ(proxied_request.certificate_profile(), |
| attestation::CONTENT_PROTECTION_CERTIFICATE); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationCreateCertRequestInvalidACA) { |
| std::unique_ptr<MockDBusMethodResponse<std::vector<uint8_t>>> response( |
| new MockDBusMethodResponse<std::vector<uint8_t>>(nullptr)); |
| EXPECT_CALL( |
| *response, |
| ReplyWithError(_, brillo::errors::dbus::kDomain, DBUS_ERROR_NOT_SUPPORTED, |
| "Requested ACA type 99999 is not supported")) |
| .WillOnce(Return()); |
| |
| // 99999 is an invalid ACA |
| adaptor_->TpmAttestationCreateCertRequest(std::move(response), 99999, 2, |
| kUsername1, kRequestOrigin); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| TpmAttestationCreateCertRequestFailed) { |
| attestation::CreateCertificateRequestRequest proxied_request; |
| EXPECT_CALL(attestation_, CreateCertificateRequestAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::CreateCertificateRequestRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::CreateCertificateRequestReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::CreateCertificateRequestReply reply; |
| reply.set_status(attestation::STATUS_UNEXPECTED_DEVICE_ERROR); |
| std::move(success_callback).Run(reply); |
| })); |
| std::unique_ptr<MockDBusMethodResponse<std::vector<uint8_t>>> response( |
| new MockDBusMethodResponse<std::vector<uint8_t>>(nullptr)); |
| EXPECT_CALL( |
| *response, |
| ReplyWithError(_, brillo::errors::dbus::kDomain, DBUS_ERROR_FAILED, |
| "Attestation daemon returned status " + |
| std::to_string(static_cast<int>( |
| attestation::STATUS_UNEXPECTED_DEVICE_ERROR)))) |
| .WillOnce(Return()); |
| |
| // 12345 is an invalid certificate profile and should result in |
| // ENTERPRISE_USER_CERTIFICATE. |
| adaptor_->TpmAttestationCreateCertRequest( |
| std::move(response), static_cast<int>(attestation::DEFAULT_ACA), 12345, |
| kUsername1, kRequestOrigin); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_EQ(proxied_request.aca_type(), attestation::DEFAULT_ACA); |
| EXPECT_EQ(proxied_request.username(), kUsername1); |
| EXPECT_EQ(proxied_request.request_origin(), kRequestOrigin); |
| EXPECT_EQ(proxied_request.certificate_profile(), |
| attestation::ENTERPRISE_USER_CERTIFICATE); |
| } |
| |
| // ------------- TpmAttestationDeleteKey(s) Related Tests ------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, TpmAttestationDeleteKeysSuccess) { |
| attestation::DeleteKeysRequest proxied_request; |
| EXPECT_CALL(attestation_, DeleteKeysAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::DeleteKeysRequest& in_request, |
| base::OnceCallback<void(const attestation::DeleteKeysReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::DeleteKeysReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<bool> result; |
| std::unique_ptr<MockDBusMethodResponse<bool>> response( |
| new MockDBusMethodResponse<bool>(nullptr)); |
| response->save_return_args(&result); |
| |
| adaptor_->TpmAttestationDeleteKeys(std::move(response), |
| /*is_user_specific=*/true, kUsername1, |
| kKeyLabel); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result.has_value()); |
| |
| // Verify response content. |
| EXPECT_TRUE(result.value()); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) are |
| // correct. |
| EXPECT_EQ(proxied_request.username(), kUsername1); |
| EXPECT_EQ(proxied_request.key_label_match(), kKeyLabel); |
| EXPECT_EQ(proxied_request.match_behavior(), |
| attestation::DeleteKeysRequest::MATCH_BEHAVIOR_PREFIX); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, TpmAttestationDeleteKeySuccess) { |
| attestation::DeleteKeysRequest proxied_request; |
| EXPECT_CALL(attestation_, DeleteKeysAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const attestation::DeleteKeysRequest& in_request, |
| base::OnceCallback<void(const attestation::DeleteKeysReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| proxied_request = in_request; |
| attestation::DeleteKeysReply proxied_reply; |
| proxied_reply.set_status(attestation::STATUS_SUCCESS); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| base::Optional<bool> result; |
| std::unique_ptr<MockDBusMethodResponse<bool>> response( |
| new MockDBusMethodResponse<bool>(nullptr)); |
| response->save_return_args(&result); |
| |
| adaptor_->TpmAttestationDeleteKey(std::move(response), |
| /*is_user_specific=*/true, kUsername1, |
| kKeyLabel); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(result.has_value()); |
| |
| // Verify response content. |
| EXPECT_TRUE(result.value()); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) are |
| // correct. |
| EXPECT_EQ(proxied_request.username(), kUsername1); |
| EXPECT_EQ(proxied_request.key_label_match(), kKeyLabel); |
| EXPECT_EQ(proxied_request.match_behavior(), |
| attestation::DeleteKeysRequest::MATCH_BEHAVIOR_EXACT); |
| } |
| |
| // -------------------- MigrateToDircrypto Related Tests -------------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, MigrateToDircryptoSuccess) { |
| // Note that failure case is NOT tested because this method does not return |
| // anything so the failure case is no different from the success case. |
| |
| user_data_auth::StartMigrateToDircryptoRequest proxied_request; |
| EXPECT_CALL(userdataauth_, StartMigrateToDircryptoAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [&](const user_data_auth::StartMigrateToDircryptoRequest& in_request, |
| base::OnceCallback<void( |
| const user_data_auth::StartMigrateToDircryptoReply&)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) { |
| proxied_request = in_request; |
| user_data_auth::StartMigrateToDircryptoReply proxied_reply; |
| proxied_reply.set_error(user_data_auth::CRYPTOHOME_ERROR_NOT_SET); |
| std::move(success_callback).Run(proxied_reply); |
| })); |
| |
| bool called = false; |
| std::unique_ptr<MockDBusMethodResponse<>> response( |
| new MockDBusMethodResponse<>(nullptr)); |
| response->set_return_callback(base::BindRepeating( |
| [](bool* called_ptr) { |
| // Return can only be called once |
| ASSERT_FALSE(*called_ptr); |
| *called_ptr = true; |
| }, |
| &called)); |
| |
| MigrateToDircryptoRequest request; |
| request.set_minimal_migration(true); |
| adaptor_->MigrateToDircrypto(std::move(response), account_, request); |
| |
| // Verify that Return() is indeed called at least once. |
| ASSERT_TRUE(called); |
| |
| // Verify that the parameters passed to DBus Proxy (New interface) is correct. |
| EXPECT_TRUE(proxied_request.minimal_migration()); |
| EXPECT_EQ(proxied_request.account_id().account_id(), kUsername1); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, |
| DircryptoMigrationProgressSignalValidity) { |
| constexpr uint64_t kCurrentBytes = 1234567890123ULL; |
| constexpr uint64_t kTotalBytes = 9876543210987ULL; |
| static_assert(kTotalBytes > kCurrentBytes, |
| "Incorrect constant test values in " |
| "DircryptoMigrationProgressSignalValidity"); |
| |
| user_data_auth::DircryptoMigrationProgress progress; |
| progress.set_status(user_data_auth::DIRCRYPTO_MIGRATION_SUCCESS); |
| progress.set_current_bytes(kCurrentBytes); |
| progress.set_total_bytes(kTotalBytes); |
| |
| EXPECT_CALL(*adaptor_, |
| VirtualSendDircryptoMigrationProgressSignal( |
| DIRCRYPTO_MIGRATION_SUCCESS, kCurrentBytes, kTotalBytes)) |
| .WillOnce(Return()); |
| |
| adaptor_->OnDircryptoMigrationProgressSignalForTestingOnly(progress); |
| } |
| |
| // -------------------- LowDiskSpace Signal Related Tests -------------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, LowDiskSpaceSignalValidity) { |
| constexpr uint64_t kFreeDiskSpace = 998877665544ULL; |
| |
| user_data_auth::LowDiskSpace payload; |
| payload.set_disk_free_bytes(kFreeDiskSpace); |
| |
| EXPECT_CALL(*adaptor_, VirtualSendLowDiskSpaceSignal(kFreeDiskSpace)) |
| .WillOnce(Return()); |
| |
| adaptor_->OnLowDiskSpaceSignalForTestingOnly(payload); |
| } |
| |
| // --------------- TPM Ownership Interface Related Tests --------------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, GetVersionInfo) { |
| EXPECT_CALL(ownership_, GetVersionInfoAsync(_, _, _, _)) |
| .WillOnce( |
| Invoke([](const tpm_manager::GetVersionInfoRequest& in_request, |
| base::OnceCallback<void( |
| const tpm_manager::GetVersionInfoReply& /*reply*/)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> |
| /* error_callback */, |
| int /* timeout_ms */) { |
| tpm_manager::GetVersionInfoReply info; |
| info.set_family(1); |
| info.set_spec_level(2); |
| info.set_manufacturer(3); |
| info.set_tpm_model(4); |
| info.set_firmware_version(5); |
| info.set_vendor_specific("ab"); |
| std::move(success_callback).Run(info); |
| })); |
| |
| using VersionInfoResponse = |
| MockDBusMethodResponse<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, |
| std::string>; |
| std::unique_ptr<VersionInfoResponse> response = |
| std::make_unique<VersionInfoResponse>(nullptr); |
| |
| base::Optional<uint32_t> family; |
| base::Optional<uint64_t> spec_level; |
| base::Optional<uint32_t> manufacture; |
| base::Optional<uint32_t> tpm_model; |
| base::Optional<uint64_t> firmware_version; |
| base::Optional<std::string> vendor_specific; |
| response->save_return_args(&family, &spec_level, &manufacture, &tpm_model, |
| &firmware_version, &vendor_specific); |
| |
| adaptor_->TpmGetVersionStructured(std::move(response)); |
| |
| EXPECT_TRUE(family.has_value()); |
| EXPECT_EQ(*family, 1); |
| EXPECT_TRUE(spec_level.has_value()); |
| EXPECT_EQ(*spec_level, 2); |
| EXPECT_TRUE(manufacture.has_value()); |
| EXPECT_EQ(*manufacture, 3); |
| EXPECT_TRUE(tpm_model.has_value()); |
| EXPECT_EQ(*tpm_model, 4); |
| EXPECT_TRUE(firmware_version.has_value()); |
| EXPECT_EQ(*firmware_version, 5); |
| EXPECT_TRUE(vendor_specific.has_value()); |
| EXPECT_EQ(*vendor_specific, base::HexEncode("ab", 2)); |
| } |
| |
| // --------- CryptohomeMiscInterfaceProxyInterface Related Tests --------------- |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTest, GetLoginStatus) { |
| EXPECT_CALL(misc_, GetLoginStatusAsync(_, _, _, _)) |
| .WillOnce( |
| Invoke([](const user_data_auth::GetLoginStatusRequest& request, |
| base::OnceCallback<void( |
| const user_data_auth::GetLoginStatusReply& /*reply*/)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> |
| /* error_callback */, |
| int /* timeout_ms */) { |
| user_data_auth::GetLoginStatusReply reply; |
| reply.set_owner_user_exists(true); |
| reply.set_is_locked_to_single_user(true); |
| std::move(success_callback).Run(reply); |
| })); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| EXPECT_CALL(*response, ReplyWithError(_)).Times(0); |
| EXPECT_CALL(*response, ReplyWithError(_, _, _, _)).Times(0); |
| response->save_return_args(&final_reply); |
| |
| const cryptohome::GetLoginStatusRequest in_request; |
| adaptor_->GetLoginStatus(std::move(response), in_request); |
| |
| ASSERT_TRUE(final_reply.has_value()); |
| ASSERT_TRUE( |
| final_reply->HasExtension(cryptohome::GetLoginStatusReply::reply)); |
| const auto& ext = |
| final_reply->GetExtension(cryptohome::GetLoginStatusReply::reply); |
| |
| // These are the default values when call to retrieve attestation status |
| // failed. |
| EXPECT_TRUE(ext.owner_user_exists()); |
| EXPECT_TRUE(ext.is_locked_to_single_user()); |
| EXPECT_FALSE(ext.boot_lockbox_finalized()); |
| } |
| |
| // This class holds the various extra setups to facilitate testing GetTpmStatus |
| class LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus |
| : public LegacyCryptohomeInterfaceAdaptorTest { |
| public: |
| LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus() = default; |
| LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus( |
| const LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus&) = delete; |
| LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus& operator=( |
| const LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus&) = delete; |
| |
| ~LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus() override = default; |
| |
| protected: |
| void SetUp() override { |
| LegacyCryptohomeInterfaceAdaptorTest::SetUp(); |
| |
| status_reply_.set_enabled(true); |
| status_reply_.set_owned(true); |
| status_reply_.mutable_local_data()->set_owner_password(kPassword); |
| |
| da_reply_.set_dictionary_attack_counter(kDACounter); |
| da_reply_.set_dictionary_attack_threshold(kDAThreshold); |
| da_reply_.set_dictionary_attack_lockout_in_effect(false); |
| da_reply_.set_dictionary_attack_lockout_seconds_remaining(kDALockoutRem); |
| |
| install_attr_reply_.set_state( |
| user_data_auth::InstallAttributesState::VALID); |
| |
| attestation_reply_.set_prepared_for_enrollment(true); |
| attestation_reply_.set_enrolled(true); |
| attestation_reply_.set_verified_boot(true); |
| auto* identity1 = attestation_reply_.mutable_identities()->Add(); |
| identity1->set_features(kFeature1); |
| auto* identity2 = attestation_reply_.mutable_identities()->Add(); |
| identity2->set_features(kFeature2); |
| |
| attestation::GetStatusReply::IdentityCertificate identity_cert1; |
| identity_cert1.set_identity(kFeature1); |
| identity_cert1.set_aca(kACA1); |
| attestation_reply_.mutable_identity_certificates()->insert( |
| google::protobuf::Map< |
| int, attestation::GetStatusReply::IdentityCertificate>:: |
| value_type(kACA1, identity_cert1)); |
| |
| attestation::GetStatusReply::IdentityCertificate identity_cert2; |
| identity_cert2.set_identity(kFeature2); |
| identity_cert2.set_aca(kACA2); |
| attestation_reply_.mutable_identity_certificates()->insert( |
| google::protobuf::Map< |
| int, attestation::GetStatusReply::IdentityCertificate>:: |
| value_type(kACA2, identity_cert2)); |
| } |
| |
| void ExpectGetTpmStatus( |
| const base::Optional<tpm_manager::GetTpmStatusReply>& reply) { |
| EXPECT_CALL(ownership_, GetTpmStatusAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [reply](const tpm_manager::GetTpmStatusRequest& in_request, |
| base::OnceCallback<void( |
| const tpm_manager::GetTpmStatusReply& /*reply*/)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| if (reply.has_value()) { |
| // If |reply| has value, then the method will be successful and |
| // |reply| will be returned. |
| std::move(success_callback).Run(reply.value()); |
| } else { |
| // If not, the method will return an error. |
| std::move(error_callback) |
| .Run(CreateDefaultError(FROM_HERE).get()); |
| } |
| })); |
| } |
| |
| void ExpectGetDictionaryAttackInfo( |
| const base::Optional<tpm_manager::GetDictionaryAttackInfoReply>& reply) { |
| EXPECT_CALL(ownership_, GetDictionaryAttackInfoAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [reply]( |
| const tpm_manager::GetDictionaryAttackInfoRequest& in_request, |
| base::OnceCallback<void( |
| const tpm_manager::GetDictionaryAttackInfoReply& /*reply*/)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| if (reply.has_value()) { |
| std::move(success_callback).Run(reply.value()); |
| } else { |
| std::move(error_callback) |
| .Run(CreateDefaultError(FROM_HERE).get()); |
| } |
| })); |
| } |
| |
| void ExpectInstallAttributesGetStatus( |
| const base::Optional<user_data_auth::InstallAttributesGetStatusReply>& |
| reply) { |
| EXPECT_CALL(install_attributes_, |
| InstallAttributesGetStatusAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [reply](const user_data_auth::InstallAttributesGetStatusRequest& |
| in_request, |
| base::OnceCallback<void( |
| const user_data_auth:: |
| InstallAttributesGetStatusReply& /*reply*/)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| if (reply.has_value()) { |
| std::move(success_callback).Run(reply.value()); |
| } else { |
| std::move(error_callback) |
| .Run(CreateDefaultError(FROM_HERE).get()); |
| } |
| })); |
| } |
| |
| void ExpectAttestationGetStatus( |
| const base::Optional<attestation::GetStatusReply>& reply) { |
| EXPECT_CALL(attestation_, GetStatusAsync(_, _, _, _)) |
| .WillOnce(Invoke( |
| [reply](const attestation::GetStatusRequest& in_request, |
| base::OnceCallback<void( |
| const attestation::GetStatusReply& /*reply*/)> |
| success_callback, |
| base::OnceCallback<void(brillo::Error*)> error_callback, |
| int timeout_ms) { |
| if (reply.has_value()) { |
| std::move(success_callback).Run(reply.value()); |
| } else { |
| std::move(error_callback) |
| .Run(CreateDefaultError(FROM_HERE).get()); |
| } |
| })); |
| } |
| |
| // The reply we'll get from various proxies. |
| tpm_manager::GetTpmStatusReply status_reply_; |
| tpm_manager::GetDictionaryAttackInfoReply da_reply_; |
| user_data_auth::InstallAttributesGetStatusReply install_attr_reply_; |
| attestation::GetStatusReply attestation_reply_; |
| |
| // The request we send to GetTpmStatus() |
| cryptohome::GetTpmStatusRequest in_request_; |
| |
| // Constants used during testing |
| static constexpr char kPassword[] = "YetAnotherPassword"; |
| static constexpr int kDACounter = 42; // The answer |
| static constexpr int kDAThreshold = 4200; // 100x The answer!! |
| static constexpr int kDALockoutRem = 0; |
| static constexpr int kFeature1 = 0xDEADBEEF; |
| static constexpr int kFeature2 = 0xBAADF00D; |
| static constexpr int kACA1 = 1; |
| static constexpr int kACA2 = 2; |
| |
| private: |
| static brillo::ErrorPtr CreateDefaultError(const base::Location& from_here) { |
| brillo::ErrorPtr error; |
| brillo::Error::AddTo(&error, from_here, brillo::errors::dbus::kDomain, |
| DBUS_ERROR_FAILED, "Here's a fake error"); |
| return error; |
| } |
| }; |
| |
| constexpr char LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kPassword[]; |
| constexpr int LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kDACounter; |
| constexpr int LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kDAThreshold; |
| constexpr int |
| LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kDALockoutRem; |
| constexpr int LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kFeature1; |
| constexpr int LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kFeature2; |
| constexpr int LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kACA1; |
| constexpr int LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus::kACA2; |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus, |
| GetTpmStatusValidity) { |
| // Setup GetTpmStatus in tpm_manager to successfully return |status_reply_| |
| ExpectGetTpmStatus(status_reply_); |
| // Setup GetDictionaryAttackInfo in tpm_manager to successfully return |
| // |da_reply_| |
| ExpectGetDictionaryAttackInfo(da_reply_); |
| // Setup GetStatus in cryptohome/install attributes interface to sucessfully |
| // return |install_attr_reply_| |
| ExpectInstallAttributesGetStatus(install_attr_reply_); |
| // Setup GetStatus in attestation to successfully return |attestation_reply_| |
| ExpectAttestationGetStatus(attestation_reply_); |
| |
| EXPECT_CALL(platform_, |
| FileExists(base::FilePath(cryptohome::kLockedToSingleUserFile))) |
| .WillOnce(Return(true)); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| EXPECT_CALL(*response, ReplyWithError(_)).Times(0); |
| EXPECT_CALL(*response, ReplyWithError(_, _, _, _)).Times(0); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->GetTpmStatus(std::move(response), in_request_); |
| |
| ASSERT_TRUE(final_reply.has_value()); |
| ASSERT_TRUE(final_reply->HasExtension(cryptohome::GetTpmStatusReply::reply)); |
| const auto& ext = |
| final_reply->GetExtension(cryptohome::GetTpmStatusReply::reply); |
| |
| EXPECT_EQ(ext.enabled(), status_reply_.enabled()); |
| EXPECT_EQ(ext.owned(), status_reply_.owned()); |
| // |initialized| should be false because the owner password is supplied in |
| // |status_reply_|. |
| EXPECT_FALSE(ext.initialized()); |
| EXPECT_EQ(ext.owner_password(), status_reply_.local_data().owner_password()); |
| |
| EXPECT_EQ(ext.dictionary_attack_counter(), |
| da_reply_.dictionary_attack_counter()); |
| EXPECT_EQ(ext.dictionary_attack_threshold(), |
| da_reply_.dictionary_attack_threshold()); |
| EXPECT_EQ(ext.dictionary_attack_lockout_in_effect(), |
| da_reply_.dictionary_attack_lockout_in_effect()); |
| EXPECT_EQ(ext.dictionary_attack_lockout_seconds_remaining(), |
| da_reply_.dictionary_attack_lockout_seconds_remaining()); |
| |
| // |install_lockbox_finalized| is true because |install_attr_reply_.state()| |
| // is VALID. |
| EXPECT_TRUE(ext.install_lockbox_finalized()); |
| // |ext.boot_lockbox_finalized| is deprecated and always set to false. |
| EXPECT_FALSE(ext.boot_lockbox_finalized()); |
| // |ext.is_locked_to_single_user| is set according to the flag file specified |
| // in kLockedToSingleUserFile. |
| EXPECT_TRUE(ext.is_locked_to_single_user()); |
| |
| EXPECT_EQ(ext.attestation_prepared(), |
| attestation_reply_.prepared_for_enrollment()); |
| EXPECT_EQ(ext.attestation_enrolled(), attestation_reply_.enrolled()); |
| EXPECT_EQ(ext.verified_boot_measured(), attestation_reply_.verified_boot()); |
| |
| EXPECT_EQ(ext.identities().size(), attestation_reply_.identities().size()); |
| EXPECT_EQ(ext.identities().Get(0).features(), |
| attestation_reply_.identities().Get(0).features()); |
| EXPECT_EQ(ext.identities().Get(1).features(), |
| attestation_reply_.identities().Get(1).features()); |
| |
| EXPECT_EQ(ext.identity_certificates().size(), |
| attestation_reply_.identity_certificates().size()); |
| EXPECT_EQ(ext.identity_certificates().count(kACA1), 1); |
| EXPECT_EQ(ext.identity_certificates().at(kACA1).identity(), |
| attestation_reply_.identity_certificates().at(kACA1).identity()); |
| EXPECT_EQ(ext.identity_certificates().at(kACA1).aca(), |
| attestation_reply_.identity_certificates().at(kACA1).aca()); |
| EXPECT_EQ(ext.identity_certificates().count(kACA2), 1); |
| EXPECT_EQ(ext.identity_certificates().at(kACA2).identity(), |
| attestation_reply_.identity_certificates().at(kACA2).identity()); |
| EXPECT_EQ(ext.identity_certificates().at(kACA2).aca(), |
| attestation_reply_.identity_certificates().at(kACA2).aca()); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus, |
| GetTpmStatusInitialized) { |
| // If it's owned and no there's no owner_password, then it's initialized. |
| status_reply_.mutable_local_data()->clear_owner_password(); |
| |
| // Setup GetTpmStatus in tpm_manager to successfully return |status_reply_| |
| ExpectGetTpmStatus(status_reply_); |
| // Setup GetDictionaryAttackInfo in tpm_manager to successfully return |
| // |da_reply_| |
| ExpectGetDictionaryAttackInfo(da_reply_); |
| // Setup GetStatus in cryptohome/install attributes interface to sucessfully |
| // return |install_attr_reply_| |
| ExpectInstallAttributesGetStatus(install_attr_reply_); |
| // Setup GetStatus in attestation to successfully return |attestation_reply_| |
| ExpectAttestationGetStatus(attestation_reply_); |
| |
| EXPECT_CALL(platform_, |
| FileExists(base::FilePath(cryptohome::kLockedToSingleUserFile))) |
| .WillOnce(Return(false)); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| EXPECT_CALL(*response, ReplyWithError(_)).Times(0); |
| EXPECT_CALL(*response, ReplyWithError(_, _, _, _)).Times(0); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->GetTpmStatus(std::move(response), in_request_); |
| |
| ASSERT_TRUE(final_reply.has_value()); |
| ASSERT_TRUE(final_reply->HasExtension(cryptohome::GetTpmStatusReply::reply)); |
| const auto& ext = |
| final_reply->GetExtension(cryptohome::GetTpmStatusReply::reply); |
| |
| // |initialized| is set to true because owner_password is cleared but owned is |
| // true. |
| EXPECT_TRUE(ext.initialized()); |
| EXPECT_EQ(ext.owner_password(), status_reply_.local_data().owner_password()); |
| |
| EXPECT_FALSE(ext.is_locked_to_single_user()); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus, |
| GetTpmStatusStageOwnershipStatusFail) { |
| status_reply_.set_status(tpm_manager::STATUS_DEVICE_ERROR); |
| |
| // Setup GetTpmStatus in tpm_manager to successfully return |status_reply_| |
| ExpectGetTpmStatus(status_reply_); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| EXPECT_CALL(*response, ReplyWithError(_, _, _, _)).WillOnce(Return()); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->GetTpmStatus(std::move(response), in_request_); |
| |
| ASSERT_FALSE(final_reply.has_value()); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus, |
| GetTpmStatusStageDictionaryAttackFail) { |
| da_reply_.set_status(tpm_manager::STATUS_DEVICE_ERROR); |
| |
| // Setup GetTpmStatus in tpm_manager to successfully return |status_reply_| |
| ExpectGetTpmStatus(status_reply_); |
| // Setup GetDictionaryAttackInfo in tpm_manager to successfully return |
| // |da_reply_| |
| ExpectGetDictionaryAttackInfo(da_reply_); |
| // Setup GetStatus in cryptohome/install attributes interface to sucessfully |
| // return |install_attr_reply_| |
| ExpectInstallAttributesGetStatus(install_attr_reply_); |
| // Setup GetStatus in attestation to successfully return |attestation_reply_| |
| ExpectAttestationGetStatus(attestation_reply_); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| EXPECT_CALL(*response, ReplyWithError(_)).Times(0); |
| EXPECT_CALL(*response, ReplyWithError(_, _, _, _)).Times(0); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->GetTpmStatus(std::move(response), in_request_); |
| |
| ASSERT_TRUE(final_reply.has_value()); |
| ASSERT_TRUE(final_reply->HasExtension(cryptohome::GetTpmStatusReply::reply)); |
| const auto& ext = |
| final_reply->GetExtension(cryptohome::GetTpmStatusReply::reply); |
| |
| // These are the default values when call to retrieve DictionaryAttack info |
| // failed. |
| EXPECT_EQ(ext.dictionary_attack_counter(), 0); |
| EXPECT_EQ(ext.dictionary_attack_threshold(), 0); |
| EXPECT_FALSE(ext.dictionary_attack_lockout_in_effect()); |
| EXPECT_EQ(ext.dictionary_attack_lockout_seconds_remaining(), 0); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus, |
| GetTpmStatusStageInstallAttributesFail) { |
| install_attr_reply_.set_error( |
| user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT); |
| |
| // Setup GetTpmStatus in tpm_manager to successfully return |status_reply_| |
| ExpectGetTpmStatus(status_reply_); |
| // Setup GetDictionaryAttackInfo in tpm_manager to successfully return |
| // |da_reply_| |
| ExpectGetDictionaryAttackInfo(da_reply_); |
| // Setup GetStatus in cryptohome/install attributes interface to sucessfully |
| // return |install_attr_reply_| |
| ExpectInstallAttributesGetStatus(install_attr_reply_); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| EXPECT_CALL(*response, ReplyWithError(_, _, _, _)).WillOnce(Return()); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->GetTpmStatus(std::move(response), in_request_); |
| |
| ASSERT_FALSE(final_reply.has_value()); |
| } |
| |
| TEST_F(LegacyCryptohomeInterfaceAdaptorTestForGetTpmStatus, |
| GetTpmStatusStageAttestationFail) { |
| attestation_reply_.set_status(attestation::STATUS_NOT_AVAILABLE); |
| |
| // Setup GetTpmStatus in tpm_manager to successfully return |status_reply_| |
| ExpectGetTpmStatus(status_reply_); |
| // Setup GetDictionaryAttackInfo in tpm_manager to successfully return |
| // |da_reply_| |
| ExpectGetDictionaryAttackInfo(da_reply_); |
| // Setup GetStatus in cryptohome/install attributes interface to sucessfully |
| // return |install_attr_reply_| |
| ExpectInstallAttributesGetStatus(install_attr_reply_); |
| // Setup GetStatus in attestation to successfully return |attestation_reply_| |
| ExpectAttestationGetStatus(attestation_reply_); |
| |
| base::Optional<cryptohome::BaseReply> final_reply; |
| |
| std::unique_ptr<MockDBusMethodResponse<cryptohome::BaseReply>> response( |
| new MockDBusMethodResponse<cryptohome::BaseReply>(nullptr)); |
| EXPECT_CALL(*response, ReplyWithError(_)).Times(0); |
| EXPECT_CALL(*response, ReplyWithError(_, _, _, _)).Times(0); |
| response->save_return_args(&final_reply); |
| |
| adaptor_->GetTpmStatus(std::move(response), in_request_); |
| |
| ASSERT_TRUE(final_reply.has_value()); |
| ASSERT_TRUE(final_reply->HasExtension(cryptohome::GetTpmStatusReply::reply)); |
| const auto& ext = |
| final_reply->GetExtension(cryptohome::GetTpmStatusReply::reply); |
| |
| // These are the default values when call to retrieve attestation status |
| // failed. |
| EXPECT_FALSE(ext.attestation_prepared()); |
| EXPECT_FALSE(ext.attestation_enrolled()); |
| EXPECT_FALSE(ext.verified_boot_measured()); |
| } |
| |
| } // namespace |
| |
| } // namespace cryptohome |