#include "chrome/browser/webauthn/enclave_manager.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/command_line.h"
#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/process/process.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "build/build_config.h"
#include "chrome/browser/webauthn/fake_magic_arch.h"
#include "chrome/browser/webauthn/fake_recovery_key_store.h"
#include "chrome/browser/webauthn/fake_security_domain_service.h"
#include "chrome/browser/webauthn/proto/enclave_local_state.pb.h"
#include "chrome/browser/webauthn/test_util.h"
#include "chrome/browser/webauthn/unexportable_key_utils.h"
#include "components/os_crypt/sync/os_crypt_mocker.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/sync/protocol/webauthn_credential_specifics.pb.h"
#include "components/trusted_vault/command_line_switches.h"
#include "components/trusted_vault/trusted_vault_connection.h"
#include "crypto/scoped_fake_user_verifying_key_provider.h"
#include "crypto/scoped_mock_unexportable_key_provider.h"
#include "crypto/user_verifying_key.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/enclave/constants.h"
#include "device/fido/enclave/enclave_authenticator.h"
#include "device/fido/enclave/types.h"
#include "device/fido/fido_authenticator.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_types.h"
#include "device/fido/json_request.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/public_key_credential_params.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/http/http_status_code.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/test/fake_test_cert_verifier_params_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_MAC)
#include "crypto/scoped_fake_apple_keychain_v2.h"
#include "device/fido/enclave/icloud_recovery_key_mac.h"
#include "device/fido/mac/scoped_touch_id_test_environment.h"
#include "third_party/boringssl/src/include/openssl/hmac.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
#endif
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#include "base/run_loop.h"
#include "components/trusted_vault/proto/recovery_key_store.pb.h"
#include "components/trusted_vault/proto/vault.pb.h"
#include "components/trusted_vault/proto_string_bytes_conversion.h"
#include "components/trusted_vault/securebox.h"
#include "crypto/signature_verifier.h"
#endif
#if !defined(MEMORY_SANITIZER)
enclave;
NoArgFuture;
BoolFuture;
namespace {
constexpr int32_t kSecretVersion = …;
constexpr std::array<uint8_t, 32> kTestKey = …;
constexpr uint8_t kTestProtobuf[] = …;
constexpr std::string_view kTestPINPublicKey = …;
#if BUILDFLAG(IS_MAC)
base::span<const uint8_t> ToSpan(std::string_view s) {
return base::as_bytes(base::make_span(s));
}
#endif
std::unique_ptr<sync_pb::WebauthnCredentialSpecifics> GetTestEntity() { … }
std::string StringOfZeros(size_t len) { … }
enclave::SigningCallback AlwaysFailsSigningCallback() { … }
webauthn_pb::EnclaveLocalState::WrappedPIN GetTestWrappedPIN() { … }
struct TempDir { … };
std::unique_ptr<network::NetworkService> CreateNetwork(
mojo::Remote<network::mojom::NetworkContext>* network_context) { … }
scoped_refptr<device::JSONRequest> JSONFromString(std::string_view json_str) { … }
class EnclaveManagerTest : public testing::Test, EnclaveManager::Observer { … };
TEST_F(EnclaveManagerTest, TestInfrastructure) { … }
TEST_F(EnclaveManagerTest, Basic) { … }
TEST_F(EnclaveManagerTest, SecretsArriveBeforeRegistrationRequested) { … }
TEST_F(EnclaveManagerTest, SecretsArriveBeforeRegistrationCompleted) { … }
TEST_F(EnclaveManagerTest, RegistrationFailureAndRetry) { … }
TEST_F(EnclaveManagerTest, PrimaryUserChange) { … }
TEST_F(EnclaveManagerTest, PrimaryUserChangeDiscardsActions) { … }
TEST_F(EnclaveManagerTest, AddWithExistingPIN) { … }
TEST_F(EnclaveManagerTest, InvalidWrappedPIN) { … }
TEST_F(EnclaveManagerTest, SetupWithPIN) { … }
TEST_F(EnclaveManagerTest, SetupWithPIN_SecurityDomainFailure) { … }
TEST_F(EnclaveManagerTest, SetupWithPIN_CertXMLFailure) { … }
TEST_F(EnclaveManagerTest, SetupWithPIN_SigXMLFailure) { … }
TEST_F(EnclaveManagerTest, AddDeviceAndPINToAccount) { … }
TEST_F(EnclaveManagerTest, ChangePIN) { … }
TEST_F(EnclaveManagerTest, ChangePINWithTwoDevices) { … }
TEST_F(EnclaveManagerTest, EnclaveForgetsClient_SetupWithPIN) { … }
TEST_F(EnclaveManagerTest, EnclaveForgetsClient_AddDeviceToAccount) { … }
TEST_F(EnclaveManagerTest, EnclaveForgetsClient_AddDeviceAndPINToAccount) { … }
TEST_F(EnclaveManagerTest, RenewPIN) { … }
TEST_F(EnclaveManagerTest, EpochChanged) { … }
TEST_F(EnclaveManagerTest, PINChanged) { … }
TEST_F(EnclaveManagerTest, SigningFails) { … }
#if BUILDFLAG(IS_MAC)
TEST_F(EnclaveManagerTest, AddICloudRecoveryKey) {
ASSERT_TRUE(Register());
BoolFuture setup_future;
manager_.SetupWithPIN("123456", setup_future.GetCallback());
EXPECT_TRUE(setup_future.Wait());
ASSERT_TRUE(manager_.is_ready());
std::unique_ptr<device::enclave::ICloudRecoveryKey> icloud_key =
device::enclave::ICloudRecoveryKey::CreateForTest();
std::unique_ptr<trusted_vault::SecureBoxKeyPair> key =
trusted_vault::SecureBoxKeyPair::CreateByPrivateKeyImport(
icloud_key->key()->private_key().ExportToBytes());
BoolFuture icloud_future;
manager_.AddICloudRecoveryKey(std::move(icloud_key),
icloud_future.GetCallback());
EXPECT_TRUE(icloud_future.Wait());
EXPECT_TRUE(icloud_future.Get());
EXPECT_EQ(security_domain_service_->num_physical_members(), 1u);
EXPECT_EQ(security_domain_service_->num_pin_members(), 1u);
const auto icloud_member = std::ranges::find_if(
security_domain_service_->members(),
[](const trusted_vault_pb::SecurityDomainMember& member) {
return member.member_type() == trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_ICLOUD_KEYCHAIN;
});
ASSERT_NE(icloud_member, security_domain_service_->members().end());
ASSERT_EQ(trusted_vault::ProtoStringToBytes(icloud_member->public_key()),
key->public_key().ExportToBytes());
const trusted_vault_pb::SharedMemberKey& shared_member_key =
icloud_member->memberships().at(0).keys().at(0);
const std::optional<std::vector<uint8_t>> security_domain_secret =
key->private_key().Decrypt(base::span<const uint8_t>(),
ToSpan("V1 shared_key"),
ToSpan(shared_member_key.wrapped_key()));
ASSERT_TRUE(security_domain_secret);
EXPECT_EQ(manager_.TakeSecret()->second, *security_domain_secret);
std::array<uint8_t, SHA256_DIGEST_LENGTH> expected_proof;
unsigned expected_proof_len;
HMAC(EVP_sha256(), security_domain_secret->data(),
security_domain_secret->size(),
reinterpret_cast<const uint8_t*>(icloud_member->public_key().data()),
icloud_member->public_key().size(), expected_proof.data(),
&expected_proof_len);
ASSERT_EQ(expected_proof_len, expected_proof.size());
EXPECT_EQ(base::span<const uint8_t>(expected_proof),
ToSpan(shared_member_key.member_proof()));
}
#endif
TEST_F(EnclaveManagerTest, Unenroll) { … }
TEST_F(EnclaveManagerTest, UnenrollRace) { … }
TEST_F(EnclaveManagerTest, UnenrollWithoutRegistering) { … }
TEST_F(EnclaveManagerTest, LockPINThenChange) { … }
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_HardwareKeyLost …
#else
#define MAYBE_HardwareKeyLost …
#endif
TEST_F(EnclaveManagerTest, MAYBE_HardwareKeyLost) { … }
class EnclaveManagerMockTimeTest : public EnclaveManagerTest { … };
TEST_F(EnclaveManagerMockTimeTest, AutomaticRenewal) { … }
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
std::string ToString(base::span<const uint8_t> v) {
return std::string(v.begin(), v.end());
}
class EnclaveUVTest : public EnclaveManagerTest {
protected:
void SetUp() override {
#if BUILDFLAG(IS_MAC)
scoped_fake_apple_keychain_.SetUVMethod(
crypto::ScopedFakeAppleKeychainV2::UVMethod::kPasswordOnly);
#endif
}
void TearDown() override {
#if BUILDFLAG(IS_CHROMEOS_ASH)
OverrideWebAuthnChromeosUserVerifyingKeyProviderForTesting(nullptr);
#endif
}
void DisableUVKeySupport() {
fake_provider_.emplace<crypto::ScopedNullUserVerifyingKeyProvider>();
#if BUILDFLAG(IS_CHROMEOS_ASH)
OverrideWebAuthnChromeosUserVerifyingKeyProviderForTesting([]() {
return std::unique_ptr<crypto::UserVerifyingKeyProvider>(nullptr);
});
#endif
}
void UseFailingUVKeySupport() {
fake_provider_.emplace<crypto::ScopedFailingUserVerifyingKeyProvider>();
#if BUILDFLAG(IS_CHROMEOS_ASH)
NOTIMPLEMENTED();
#endif
}
absl::variant<crypto::ScopedFakeUserVerifyingKeyProvider,
crypto::ScopedNullUserVerifyingKeyProvider,
crypto::ScopedFailingUserVerifyingKeyProvider>
fake_provider_;
#if BUILDFLAG(IS_MAC)
crypto::ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
"test-keychain-access-group"};
#endif
};
TEST_F(EnclaveUVTest, UserVerifyingKeyAvailable) {
security_domain_service_->pretend_there_are_members();
NoArgFuture loaded_future;
manager_.Load(loaded_future.GetCallback());
EXPECT_TRUE(loaded_future.Wait());
BoolFuture register_future;
manager_.RegisterIfNeeded(register_future.GetCallback());
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(register_future.Wait());
std::vector<uint8_t> key(kTestKey.begin(), kTestKey.end());
ASSERT_FALSE(manager_.has_pending_keys());
manager_.StoreKeys(gaia_id_, {std::move(key)},
kSecretVersion);
ASSERT_TRUE(manager_.is_idle());
ASSERT_TRUE(manager_.has_pending_keys());
BoolFuture add_future;
ASSERT_TRUE(manager_.AddDeviceToAccount(
std::nullopt, add_future.GetCallback()));
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(add_future.Wait());
#if BUILDFLAG(IS_WIN)
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUIDeferredCreation);
#else
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUI);
#endif
}
TEST_F(EnclaveUVTest, UserVerifyingKeyUnavailable) {
DisableUVKeySupport();
security_domain_service_->pretend_there_are_members();
NoArgFuture loaded_future;
manager_.Load(loaded_future.GetCallback());
EXPECT_TRUE(loaded_future.Wait());
BoolFuture register_future;
manager_.RegisterIfNeeded(register_future.GetCallback());
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(register_future.Wait());
std::vector<uint8_t> key(kTestKey.begin(), kTestKey.end());
ASSERT_FALSE(manager_.has_pending_keys());
manager_.StoreKeys(gaia_id_, {std::move(key)},
kSecretVersion);
ASSERT_TRUE(manager_.is_idle());
ASSERT_TRUE(manager_.has_pending_keys());
BoolFuture add_future;
ASSERT_TRUE(manager_.AddDeviceToAccount(
std::nullopt, add_future.GetCallback()));
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(add_future.Wait());
ASSERT_TRUE(manager_.is_registered());
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kNone);
}
TEST_F(EnclaveUVTest, UserVerifyingKeyLost) {
security_domain_service_->pretend_there_are_members();
NoArgFuture loaded_future;
manager_.Load(loaded_future.GetCallback());
EXPECT_TRUE(loaded_future.Wait());
BoolFuture register_future;
manager_.RegisterIfNeeded(register_future.GetCallback());
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(register_future.Wait());
std::vector<uint8_t> key(kTestKey.begin(), kTestKey.end());
ASSERT_FALSE(manager_.has_pending_keys());
manager_.StoreKeys(gaia_id_, {std::move(key)},
kSecretVersion);
ASSERT_TRUE(manager_.is_idle());
ASSERT_TRUE(manager_.has_pending_keys());
BoolFuture add_future;
ASSERT_TRUE(manager_.AddDeviceToAccount(
std::nullopt, add_future.GetCallback()));
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(add_future.Wait());
base::RepeatingClosure quit_closure;
#if BUILDFLAG(IS_WIN)
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUIDeferredCreation);
auto key_creation_callback = manager_.UserVerifyingKeyCreationCallback();
quit_closure = task_env_.QuitClosure();
std::move(key_creation_callback)
.Run(base::BindLambdaForTesting(
[&quit_closure](base::span<const uint8_t> uv_public_key) {
EXPECT_FALSE(uv_public_key.empty());
quit_closure.Run();
}));
task_env_.RunUntilQuit();
#else
ASSERT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUI);
#endif
manager_.ClearCachedKeysForTesting();
DisableUVKeySupport();
auto signing_callback =
manager_.UserVerifyingKeySigningCallback({});
quit_closure = task_env_.QuitClosure();
std::move(signing_callback)
.Run({1, 2, 3, 4},
base::BindLambdaForTesting(
[&quit_closure](
std::optional<enclave::ClientSignature> signature) {
EXPECT_EQ(signature, std::nullopt);
quit_closure.Run();
}));
task_env_.RunUntilQuit();
EXPECT_FALSE(manager_.is_registered());
}
TEST_F(EnclaveUVTest, UserVerifyingKeyUseExisting) {
security_domain_service_->pretend_there_are_members();
NoArgFuture loaded_future;
manager_.Load(loaded_future.GetCallback());
EXPECT_TRUE(loaded_future.Wait());
base::test::TestFuture<
base::expected<std::unique_ptr<crypto::UserVerifyingSigningKey>,
crypto::UserVerifyingKeyCreationError>>
key_future;
std::unique_ptr<crypto::UserVerifyingKeyProvider> key_provider =
crypto::GetUserVerifyingKeyProvider({});
key_provider->GenerateUserVerifyingSigningKey(
std::array{crypto::SignatureVerifier::ECDSA_SHA256},
key_future.GetCallback());
EXPECT_TRUE(key_future.Wait());
manager_.local_state_for_testing()
.mutable_users()
->begin()
->second.set_uv_public_key(
ToString(key_future.Get().value()->GetPublicKey()));
manager_.local_state_for_testing()
.mutable_users()
->begin()
->second.set_wrapped_uv_private_key(
key_future.Get().value()->GetKeyLabel());
BoolFuture register_future;
manager_.RegisterIfNeeded(register_future.GetCallback());
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(register_future.Wait());
std::vector<uint8_t> key(kTestKey.begin(), kTestKey.end());
ASSERT_FALSE(manager_.has_pending_keys());
manager_.StoreKeys(gaia_id_, {std::move(key)},
kSecretVersion);
ASSERT_TRUE(manager_.is_idle());
ASSERT_TRUE(manager_.has_pending_keys());
BoolFuture add_future;
ASSERT_TRUE(manager_.AddDeviceToAccount(
std::nullopt, add_future.GetCallback()));
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(add_future.Wait());
ASSERT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUI);
}
#if BUILDFLAG(IS_MAC)
TEST_F(EnclaveUVTest, ChromeHandlesBiometrics) {
security_domain_service_->pretend_there_are_members();
NoArgFuture loaded_future;
manager_.Load(loaded_future.GetCallback());
EXPECT_TRUE(loaded_future.Wait());
BoolFuture register_future;
manager_.RegisterIfNeeded(register_future.GetCallback());
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(register_future.Wait());
std::vector<uint8_t> key(kTestKey.begin(), kTestKey.end());
ASSERT_FALSE(manager_.has_pending_keys());
manager_.StoreKeys(gaia_id_, {std::move(key)},
kSecretVersion);
ASSERT_TRUE(manager_.is_idle());
ASSERT_TRUE(manager_.has_pending_keys());
BoolFuture add_future;
ASSERT_TRUE(manager_.AddDeviceToAccount(
std::nullopt, add_future.GetCallback()));
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(add_future.Wait());
scoped_fake_apple_keychain_.SetUVMethod(
crypto::ScopedFakeAppleKeychainV2::UVMethod::kBiometrics);
if (__builtin_available(macos 12, *)) {
EXPECT_EQ(manager_.uv_key_state(true),
EnclaveManager::UvKeyState::kUsesChromeUI);
} else {
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUI);
}
scoped_fake_apple_keychain_.SetUVMethod(
crypto::ScopedFakeAppleKeychainV2::UVMethod::kPasswordOnly);
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUI);
}
#endif
#if BUILDFLAG(IS_WIN)
TEST_F(EnclaveUVTest, DeferredUVKeyCreation) {
security_domain_service_->pretend_there_are_members();
NoArgFuture loaded_future;
manager_.Load(loaded_future.GetCallback());
EXPECT_TRUE(loaded_future.Wait());
BoolFuture register_future;
manager_.RegisterIfNeeded(register_future.GetCallback());
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(register_future.Wait());
std::vector<uint8_t> key(kTestKey.begin(), kTestKey.end());
ASSERT_FALSE(manager_.has_pending_keys());
manager_.StoreKeys(gaia_id_, {std::move(key)},
kSecretVersion);
ASSERT_TRUE(manager_.is_idle());
ASSERT_TRUE(manager_.has_pending_keys());
BoolFuture add_future;
ASSERT_TRUE(manager_.AddDeviceToAccount(
std::nullopt, add_future.GetCallback()));
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(add_future.Wait());
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUIDeferredCreation);
const auto& user_state =
manager_.local_state_for_testing().users().find(gaia_id_)->second;
EXPECT_TRUE(user_state.has_deferred_uv_key_creation() &&
user_state.deferred_uv_key_creation());
EXPECT_TRUE(user_state.wrapped_uv_private_key().empty());
auto key_creation_callback = manager_.UserVerifyingKeyCreationCallback();
auto quit_closure = task_env_.QuitClosure();
std::move(key_creation_callback)
.Run(base::BindLambdaForTesting(
[&quit_closure](base::span<const uint8_t> uv_public_key) {
EXPECT_FALSE(uv_public_key.empty());
quit_closure.Run();
}));
task_env_.RunUntilQuit();
EXPECT_FALSE(user_state.deferred_uv_key_creation());
EXPECT_FALSE(user_state.wrapped_uv_private_key().empty());
}
TEST_F(EnclaveUVTest, UnregisterOnFailedDeferredUVKeyCreation) {
security_domain_service_->pretend_there_are_members();
NoArgFuture loaded_future;
manager_.Load(loaded_future.GetCallback());
EXPECT_TRUE(loaded_future.Wait());
BoolFuture register_future;
manager_.RegisterIfNeeded(register_future.GetCallback());
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(register_future.Wait());
std::vector<uint8_t> key(kTestKey.begin(), kTestKey.end());
ASSERT_FALSE(manager_.has_pending_keys());
manager_.StoreKeys(gaia_id_, {std::move(key)},
kSecretVersion);
ASSERT_TRUE(manager_.is_idle());
ASSERT_TRUE(manager_.has_pending_keys());
BoolFuture add_future;
ASSERT_TRUE(manager_.AddDeviceToAccount(
std::nullopt, add_future.GetCallback()));
ASSERT_FALSE(manager_.is_idle());
EXPECT_TRUE(add_future.Wait());
EXPECT_EQ(manager_.uv_key_state(false),
EnclaveManager::UvKeyState::kUsesSystemUIDeferredCreation);
const auto& user_state =
manager_.local_state_for_testing().users().find(gaia_id_)->second;
EXPECT_TRUE(user_state.deferred_uv_key_creation());
EXPECT_TRUE(user_state.wrapped_uv_private_key().empty());
UseFailingUVKeySupport();
EnclaveManager::EnableInvariantChecksForTesting(false);
base::RunLoop run_loop;
auto ui_request = std::make_unique<enclave::CredentialRequest>();
ui_request->signing_callback = manager_.IdentityKeySigningCallback();
ui_request->wrapped_secret =
*manager_.GetWrappedSecret(kSecretVersion);
ui_request->entity = GetTestEntity();
ui_request->claimed_pin = nullptr;
ui_request->save_passkey_callback = base::BindOnce(
[](sync_pb::WebauthnCredentialSpecifics) { NOTREACHED(); });
ui_request->user_verified = true;
ui_request->uv_key_creation_callback =
manager_.UserVerifyingKeyCreationCallback();
ui_request->unregister_callback =
base::BindOnce(&EnclaveManager::Unenroll, manager_.GetWeakPtr(),
base::BindLambdaForTesting(
[&run_loop](bool) { run_loop.QuitWhenIdle(); }));
GetAssertionResponseExpectation expected_response;
expected_response.result = device::GetAssertionStatus::kEnclaveError;
expected_response.size = 0;
DoAssertion(GetTestEntity(), nullptr, expected_response,
std::move(ui_request));
run_loop.Run();
EXPECT_FALSE(manager_.is_registered());
}
#endif
#endif
}
#endif