| // Copyright 2020 The Chromium 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 <memory> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/command_line.h" |
| #include "base/containers/span.h" |
| #include "base/location.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/optional.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/post_task.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "chrome/browser/chromeos/login/test/device_state_mixin.h" |
| #include "chrome/browser/chromeos/login/test/login_manager_mixin.h" |
| #include "chrome/browser/chromeos/login/test/scoped_policy_update.h" |
| #include "chrome/browser/chromeos/login/test/user_policy_mixin.h" |
| #include "chrome/browser/chromeos/platform_keys/platform_keys.h" |
| #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h" |
| #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h" |
| #include "chrome/browser/chromeos/platform_keys/platform_keys_service_test_util.h" |
| #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.h" |
| #include "chrome/browser/net/nss_context.h" |
| #include "chrome/browser/policy/policy_test_utils.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/test/base/mixin_based_in_process_browser_test.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chromeos/constants/chromeos_switches.h" |
| #include "chromeos/login/auth/user_context.h" |
| #include "components/policy/core/common/cloud/policy_builder.h" |
| #include "components/policy/core/common/policy_switches.h" |
| #include "components/signin/public/identity_manager/identity_test_utils.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/browser_test.h" |
| #include "crypto/nss_key_util.h" |
| #include "crypto/scoped_nss_types.h" |
| #include "crypto/signature_verifier.h" |
| #include "net/cert/nss_cert_database.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/cert/x509_util_nss.h" |
| #include "net/test/cert_test_util.h" |
| #include "net/test/test_data_directory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/cros_system_api/constants/pkcs11_custom_attributes.h" |
| |
| namespace chromeos { |
| namespace platform_keys { |
| namespace { |
| |
| constexpr char kTestUserEmail[] = "test@example.com"; |
| constexpr char kTestAffiliationId[] = "test_affiliation_id"; |
| |
| enum class ProfileToUse { |
| // A Profile that belongs to a user that is not affiliated with the device (no |
| // access to the system token). |
| kUnaffiliatedUserProfile, |
| // A Profile that belongs to a user that is affiliated with the device (access |
| // to the system token). |
| kAffiliatedUserProfile, |
| // The sign-in screen profile. |
| kSigninProfile |
| }; |
| |
| // Describes a test configuration for the test suite that runs one test per |
| // profile. |
| struct TestConfigPerProfile { |
| // The profile for which PlatformKeysService should be tested. |
| ProfileToUse profile_to_use; |
| |
| // The token IDs that are expected to be available for |profile_to_use|. |
| std::vector<TokenId> token_ids; |
| }; |
| |
| // Describes a test configuration for the test suite that runs one test per |
| // (profile, token) combination. |
| struct TestConfigPerToken { |
| // The profile for which PlatformKeysService should be tested. |
| ProfileToUse profile_to_use; |
| |
| // The token ID to perform the tests on. |
| TokenId token_id; |
| }; |
| |
| } // namespace |
| |
| class PlatformKeysServiceBrowserTestBase |
| : public MixinBasedInProcessBrowserTest { |
| public: |
| PlatformKeysServiceBrowserTestBase() = default; |
| PlatformKeysServiceBrowserTestBase( |
| const PlatformKeysServiceBrowserTestBase& other) = delete; |
| PlatformKeysServiceBrowserTestBase& operator=( |
| const PlatformKeysServiceBrowserTestBase& other) = delete; |
| ~PlatformKeysServiceBrowserTestBase() override = default; |
| |
| void SetUpInProcessBrowserTestFixture() override { |
| MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture(); |
| |
| // Call |Request*PolicyUpdate| even if not setting affiliation IDs so |
| // (empty) policy blobs are prepared in FakeSessionManagerClient. |
| auto user_policy_update = user_policy_mixin_.RequestPolicyUpdate(); |
| auto device_policy_update = device_state_mixin_.RequestDevicePolicyUpdate(); |
| if (GetProfileToUse() == ProfileToUse::kAffiliatedUserProfile) { |
| device_policy_update->policy_data()->add_device_affiliation_ids( |
| kTestAffiliationId); |
| user_policy_update->policy_data()->add_user_affiliation_ids( |
| kTestAffiliationId); |
| } |
| |
| PlatformKeysServiceFactory::GetInstance()->SetTestingMode(true); |
| } |
| |
| void SetUpOnMainThread() override { |
| MixinBasedInProcessBrowserTest::SetUpOnMainThread(); |
| |
| if (GetProfileToUse() == ProfileToUse::kSigninProfile) { |
| profile_ = ProfileHelper::GetSigninProfile(); |
| } else { |
| ASSERT_TRUE(login_manager_mixin_.LoginAndWaitForActiveSession( |
| LoginManagerMixin::CreateDefaultUserContext(test_user_info_))); |
| profile_ = ProfileManager::GetActiveUserProfile(); |
| |
| base::RunLoop loop; |
| GetNSSCertDatabaseForProfile( |
| profile_, |
| base::BindOnce(&PlatformKeysServiceBrowserTestBase::SetUserSlot, |
| base::Unretained(this), loop.QuitClosure())); |
| loop.Run(); |
| } |
| ASSERT_TRUE(profile_); |
| |
| platform_keys_service_ = |
| PlatformKeysServiceFactory::GetForBrowserContext(profile_); |
| ASSERT_TRUE(platform_keys_service_); |
| } |
| |
| void TearDownOnMainThread() override { |
| MixinBasedInProcessBrowserTest::TearDownOnMainThread(); |
| } |
| |
| protected: |
| virtual ProfileToUse GetProfileToUse() = 0; |
| |
| PlatformKeysService* platform_keys_service() { |
| return platform_keys_service_; |
| } |
| |
| // Returns the slot to be used depending on |token_id|. |
| PK11SlotInfo* GetSlot(TokenId token_id) { |
| switch (token_id) { |
| case TokenId::kSystem: |
| return system_nss_key_slot_mixin_.slot(); |
| case TokenId::kUser: |
| return user_slot_.get(); |
| } |
| } |
| |
| // Generates a key pair in the given |token_id| using platform keys service |
| // and returns the SubjectPublicKeyInfo string encoded in DER format. |
| std::string GenerateKeyPair(TokenId token_id) { |
| const unsigned int kKeySize = 2048; |
| |
| test_util::GenerateKeyExecutionWaiter generate_key_waiter; |
| platform_keys_service()->GenerateRSAKey(token_id, kKeySize, |
| generate_key_waiter.GetCallback()); |
| generate_key_waiter.Wait(); |
| |
| return generate_key_waiter.public_key_spki_der(); |
| } |
| |
| // Imports the certificate and key described by the |cert_filename| and |
| // |key_filename| files in |source_dir| into the Token |token_id|, then stores |
| // the resulting certificate in *|out_cert| and the SPKI of the public key in |
| // *|out_spki_der|. Should be wrapped in ASSERT_NO_FATAL_FAILURE. |
| void ImportCertAndKey(TokenId token_id, |
| const base::FilePath& source_dir, |
| const std::string& cert_filename, |
| const std::string& key_filename, |
| net::ScopedCERTCertificate* out_cert, |
| std::string* out_spki_der) { |
| // Import testing key pair and certificate. |
| { |
| base::ScopedAllowBlockingForTesting allow_io; |
| net::ImportClientCertAndKeyFromFile( |
| source_dir, cert_filename, key_filename, GetSlot(token_id), out_cert); |
| } |
| CERTCertificate* cert = out_cert->get(); |
| ASSERT_TRUE(cert); |
| ASSERT_GT(cert->derPublicKey.len, 0U); |
| *out_spki_der = |
| std::string(reinterpret_cast<const char*>(cert->derPublicKey.data), |
| cert->derPublicKey.len); |
| } |
| |
| private: |
| void SetUserSlot(const base::Closure& done_callback, |
| net::NSSCertDatabase* db) { |
| user_slot_ = db->GetPrivateSlot(); |
| done_callback.Run(); |
| } |
| |
| const AccountId test_user_account_id_ = AccountId::FromUserEmailGaiaId( |
| kTestUserEmail, |
| signin::GetTestGaiaIdForEmail(kTestUserEmail)); |
| const LoginManagerMixin::TestUserInfo test_user_info_{test_user_account_id_}; |
| |
| ScopedTestSystemNSSKeySlotMixin system_nss_key_slot_mixin_{&mixin_host_}; |
| LoginManagerMixin login_manager_mixin_{&mixin_host_, {test_user_info_}}; |
| |
| DeviceStateMixin device_state_mixin_{ |
| &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED}; |
| UserPolicyMixin user_policy_mixin_{&mixin_host_, test_user_account_id_}; |
| |
| // Unowned pointer to the profile selected by the current TestConfig. |
| // Valid after SetUpOnMainThread(). |
| Profile* profile_ = nullptr; |
| // Unowned pointer to the PlatformKeysService for |profile_|. Valid after |
| // SetUpOnMainThread(). |
| PlatformKeysService* platform_keys_service_ = nullptr; |
| // The private slot for the profile under test. This should be null if the |
| // test parameter mandates testing with the sign-in profile. |
| crypto::ScopedPK11Slot user_slot_; |
| }; |
| |
| class PlatformKeysServicePerProfileBrowserTest |
| : public PlatformKeysServiceBrowserTestBase, |
| public ::testing::WithParamInterface<TestConfigPerProfile> { |
| public: |
| PlatformKeysServicePerProfileBrowserTest() = default; |
| PlatformKeysServicePerProfileBrowserTest( |
| const PlatformKeysServicePerProfileBrowserTest& other) = delete; |
| PlatformKeysServicePerProfileBrowserTest& operator=( |
| const PlatformKeysServicePerProfileBrowserTest& other) = delete; |
| ~PlatformKeysServicePerProfileBrowserTest() override = default; |
| |
| protected: |
| ProfileToUse GetProfileToUse() override { return GetParam().profile_to_use; } |
| }; |
| |
| // Tests that GetTokens() is callable and returns the expected tokens. |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerProfileBrowserTest, GetTokens) { |
| test_util::GetTokensExecutionWaiter get_tokens_waiter; |
| platform_keys_service()->GetTokens(get_tokens_waiter.GetCallback()); |
| get_tokens_waiter.Wait(); |
| |
| EXPECT_EQ(get_tokens_waiter.status(), Status::kSuccess); |
| ASSERT_TRUE(get_tokens_waiter.token_ids()); |
| EXPECT_THAT(*get_tokens_waiter.token_ids(), |
| ::testing::UnorderedElementsAreArray(GetParam().token_ids)); |
| } |
| |
| // Generates a key pair in tokens accessible from the profile under test and |
| // retrieves them. |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerProfileBrowserTest, GetAllKeys) { |
| // Generate key pair in every token. |
| std::map<TokenId, std::string> token_key_map; |
| for (TokenId token_id : GetParam().token_ids) { |
| const std::string public_key_spki_der = GenerateKeyPair(token_id); |
| ASSERT_FALSE(public_key_spki_der.empty()); |
| token_key_map[token_id] = public_key_spki_der; |
| } |
| |
| // Only keys in the requested token should be retrieved. |
| for (TokenId token_id : GetParam().token_ids) { |
| test_util::GetAllKeysExecutionWaiter get_all_keys_waiter; |
| platform_keys_service()->GetAllKeys(token_id, |
| get_all_keys_waiter.GetCallback()); |
| get_all_keys_waiter.Wait(); |
| |
| EXPECT_EQ(get_all_keys_waiter.status(), Status::kSuccess); |
| std::vector<std::string> public_keys = get_all_keys_waiter.public_keys(); |
| ASSERT_EQ(public_keys.size(), 1U); |
| EXPECT_EQ(public_keys[0], token_key_map[token_id]); |
| } |
| } |
| |
| // Imports the same key into all tokens. Verifies that key attributes are stored |
| // per-token and don't leak between tokens. |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerProfileBrowserTest, |
| KeyAttributesPerToken) { |
| // Import the same key pair + cert in every token, remember its SPKI. |
| std::string spki_der; |
| for (TokenId token_id : GetParam().token_ids) { |
| net::ScopedCERTCertificate cert; |
| std::string current_spki_der; |
| ASSERT_NO_FATAL_FAILURE( |
| ImportCertAndKey(token_id, net::GetTestCertsDirectory(), "client_1.pem", |
| "client_1.pk8", &cert, ¤t_spki_der)); |
| // The SPKI must be the same on every slot, because the same key was |
| // imported. |
| if (!spki_der.empty()) { |
| EXPECT_EQ(current_spki_der, spki_der); |
| continue; |
| } |
| spki_der = current_spki_der; |
| } |
| |
| // Set an attribute for the key on each token. |
| const KeyAttributeType kAttributeType = |
| KeyAttributeType::kCertificateProvisioningId; |
| std::map<TokenId, std::string> token_to_value; |
| for (TokenId token_id : GetParam().token_ids) { |
| token_to_value[token_id] = |
| base::StringPrintf("test_value_%d", static_cast<int>(token_id)); |
| |
| // Set key attribute. |
| test_util::SetAttributeForKeyExecutionWaiter set_attr_waiter; |
| platform_keys_service()->SetAttributeForKey( |
| token_id, spki_der, kAttributeType, token_to_value[token_id], |
| set_attr_waiter.GetCallback()); |
| set_attr_waiter.Wait(); |
| EXPECT_EQ(set_attr_waiter.status(), Status::kSuccess); |
| } |
| |
| // Verify the token-specific attribute value for the key on each token. |
| for (TokenId token_id : GetParam().token_ids) { |
| // Get key attribute. |
| test_util::GetAttributeForKeyExecutionWaiter get_attr_waiter; |
| platform_keys_service()->GetAttributeForKey( |
| token_id, spki_der, kAttributeType, get_attr_waiter.GetCallback()); |
| get_attr_waiter.Wait(); |
| |
| EXPECT_EQ(get_attr_waiter.status(), Status::kSuccess); |
| ASSERT_TRUE(get_attr_waiter.attribute_value()); |
| EXPECT_EQ(get_attr_waiter.attribute_value().value(), |
| token_to_value[token_id]); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerProfileBrowserTest, |
| IsKeyOnTokenWhenNot) { |
| // More than one available token are needed to test this. |
| if (GetParam().token_ids.size() < 2) { |
| return; |
| } |
| |
| const TokenId token_id_1 = GetParam().token_ids[0]; |
| const TokenId token_id_2 = GetParam().token_ids[1]; |
| |
| const std::string public_key = GenerateKeyPair(token_id_1); |
| |
| test_util::IsKeyOnTokenExecutionWaiter is_key_on_token_waiter; |
| platform_keys_service()->IsKeyOnToken(token_id_2, public_key, |
| is_key_on_token_waiter.GetCallback()); |
| is_key_on_token_waiter.Wait(); |
| |
| EXPECT_EQ(is_key_on_token_waiter.status(), Status::kSuccess); |
| ASSERT_TRUE(is_key_on_token_waiter.on_slot().has_value()); |
| EXPECT_FALSE(is_key_on_token_waiter.on_slot().value()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AllSupportedProfileTypes, |
| PlatformKeysServicePerProfileBrowserTest, |
| ::testing::Values( |
| TestConfigPerProfile{ProfileToUse::kSigninProfile, {TokenId::kSystem}}, |
| TestConfigPerProfile{ProfileToUse::kUnaffiliatedUserProfile, |
| {TokenId::kUser}}, |
| TestConfigPerProfile{ProfileToUse::kAffiliatedUserProfile, |
| {TokenId::kUser, TokenId::kSystem}}, |
| TestConfigPerProfile{ProfileToUse::kAffiliatedUserProfile, |
| {TokenId::kSystem, TokenId::kUser}})); |
| |
| class PlatformKeysServicePerTokenBrowserTest |
| : public PlatformKeysServiceBrowserTestBase, |
| public ::testing::WithParamInterface<TestConfigPerToken> { |
| public: |
| PlatformKeysServicePerTokenBrowserTest() = default; |
| PlatformKeysServicePerTokenBrowserTest( |
| const PlatformKeysServicePerTokenBrowserTest& other) = delete; |
| PlatformKeysServicePerTokenBrowserTest& operator=( |
| const PlatformKeysServicePerTokenBrowserTest& other) = delete; |
| ~PlatformKeysServicePerTokenBrowserTest() override = default; |
| |
| protected: |
| ProfileToUse GetProfileToUse() override { return GetParam().profile_to_use; } |
| }; |
| |
| // Generates a Rsa key pair and tests signing using that key pair. |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| GenerateRsaAndSign) { |
| const std::string kDataToSign = "test"; |
| const unsigned int kKeySize = 2048; |
| const HashAlgorithm kHashAlgorithm = HASH_ALGORITHM_SHA256; |
| const crypto::SignatureVerifier::SignatureAlgorithm kSignatureAlgorithm = |
| crypto::SignatureVerifier::RSA_PKCS1_SHA256; |
| |
| const TokenId token_id = GetParam().token_id; |
| test_util::GenerateKeyExecutionWaiter generate_key_waiter; |
| platform_keys_service()->GenerateRSAKey(token_id, kKeySize, |
| generate_key_waiter.GetCallback()); |
| generate_key_waiter.Wait(); |
| EXPECT_EQ(generate_key_waiter.status(), Status::kSuccess); |
| |
| const std::string public_key_spki_der = |
| generate_key_waiter.public_key_spki_der(); |
| EXPECT_FALSE(public_key_spki_der.empty()); |
| |
| test_util::SignExecutionWaiter sign_waiter; |
| platform_keys_service()->SignRSAPKCS1Digest( |
| token_id, kDataToSign, public_key_spki_der, kHashAlgorithm, |
| sign_waiter.GetCallback()); |
| sign_waiter.Wait(); |
| EXPECT_EQ(sign_waiter.status(), Status::kSuccess); |
| |
| crypto::SignatureVerifier signature_verifier; |
| ASSERT_TRUE(signature_verifier.VerifyInit( |
| kSignatureAlgorithm, |
| base::as_bytes(base::make_span(sign_waiter.signature())), |
| base::as_bytes(base::make_span(public_key_spki_der)))); |
| signature_verifier.VerifyUpdate(base::as_bytes(base::make_span(kDataToSign))); |
| EXPECT_TRUE(signature_verifier.VerifyFinal()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| SetAndGetKeyAttribute) { |
| // The attribute type to be set and retrieved using platform keys service. |
| const KeyAttributeType kAttributeType = |
| KeyAttributeType::kCertificateProvisioningId; |
| const TokenId token_id = GetParam().token_id; |
| const std::string kAttributeValue = "test_attr_value"; |
| |
| // Generate key pair. |
| const std::string public_key_spki_der = GenerateKeyPair(token_id); |
| ASSERT_FALSE(public_key_spki_der.empty()); |
| |
| // Set key attribute. |
| test_util::SetAttributeForKeyExecutionWaiter |
| set_attribute_for_key_execution_waiter; |
| platform_keys_service()->SetAttributeForKey( |
| token_id, public_key_spki_der, kAttributeType, kAttributeValue, |
| set_attribute_for_key_execution_waiter.GetCallback()); |
| set_attribute_for_key_execution_waiter.Wait(); |
| |
| // Get key attribute. |
| test_util::GetAttributeForKeyExecutionWaiter |
| get_attribute_for_key_execution_waiter; |
| platform_keys_service()->GetAttributeForKey( |
| token_id, public_key_spki_der, kAttributeType, |
| get_attribute_for_key_execution_waiter.GetCallback()); |
| get_attribute_for_key_execution_waiter.Wait(); |
| |
| EXPECT_EQ(get_attribute_for_key_execution_waiter.status(), Status::kSuccess); |
| ASSERT_TRUE(get_attribute_for_key_execution_waiter.attribute_value()); |
| EXPECT_EQ(get_attribute_for_key_execution_waiter.attribute_value().value(), |
| kAttributeValue); |
| } |
| |
| // TODO(https://crbug.com/1073515): Add a test for an unset key attribute when |
| // simulating chaps behavior is possible. |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| GetKeyAttributeForNonExistingKey) { |
| const KeyAttributeType kAttributeType = |
| KeyAttributeType::kCertificateProvisioningId; |
| const TokenId token_id = GetParam().token_id; |
| const std::string kPublicKey = "Non Existing public key"; |
| |
| // Get key attribute. |
| test_util::GetAttributeForKeyExecutionWaiter |
| get_attribute_for_key_execution_waiter; |
| platform_keys_service()->GetAttributeForKey( |
| token_id, kPublicKey, kAttributeType, |
| get_attribute_for_key_execution_waiter.GetCallback()); |
| get_attribute_for_key_execution_waiter.Wait(); |
| |
| EXPECT_NE(get_attribute_for_key_execution_waiter.status(), Status::kSuccess); |
| EXPECT_FALSE(get_attribute_for_key_execution_waiter.attribute_value()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| SetKeyAttributeForNonExistingKey) { |
| const KeyAttributeType kAttributeType = |
| KeyAttributeType::kCertificateProvisioningId; |
| const TokenId token_id = GetParam().token_id; |
| const std::string kAttributeValue = "test"; |
| const std::string kPublicKey = "Non Existing public key"; |
| |
| // Set key attribute. |
| test_util::SetAttributeForKeyExecutionWaiter |
| set_attribute_for_key_execution_waiter; |
| platform_keys_service()->SetAttributeForKey( |
| token_id, kPublicKey, kAttributeType, kAttributeValue, |
| set_attribute_for_key_execution_waiter.GetCallback()); |
| set_attribute_for_key_execution_waiter.Wait(); |
| |
| EXPECT_NE(set_attribute_for_key_execution_waiter.status(), Status::kSuccess); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| RemoveKeyWithNoMatchingCertificates) { |
| const TokenId token_id = GetParam().token_id; |
| |
| // Generate first key pair. |
| const std::string public_key_1 = GenerateKeyPair(token_id); |
| ASSERT_FALSE(public_key_1.empty()); |
| |
| // Generate second key pair. |
| const std::string public_key_2 = GenerateKeyPair(token_id); |
| ASSERT_FALSE(public_key_2.empty()); |
| |
| auto public_key_bytes_1 = base::as_bytes(base::make_span(public_key_1)); |
| auto public_key_bytes_2 = base::as_bytes(base::make_span(public_key_2)); |
| EXPECT_TRUE(crypto::FindNSSKeyFromPublicKeyInfo(public_key_bytes_1)); |
| EXPECT_TRUE(crypto::FindNSSKeyFromPublicKeyInfo(public_key_bytes_2)); |
| |
| test_util::RemoveKeyExecutionWaiter remove_key_waiter; |
| platform_keys_service()->RemoveKey(token_id, public_key_1, |
| remove_key_waiter.GetCallback()); |
| remove_key_waiter.Wait(); |
| |
| EXPECT_EQ(remove_key_waiter.status(), Status::kSuccess); |
| EXPECT_FALSE(crypto::FindNSSKeyFromPublicKeyInfo(public_key_bytes_1)); |
| EXPECT_TRUE(crypto::FindNSSKeyFromPublicKeyInfo(public_key_bytes_2)); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| RemoveKeyWithMatchingCertificate) { |
| const TokenId token_id = GetParam().token_id; |
| |
| // Assert that there are no certificates before importing. |
| test_util::GetCertificatesExecutionWaiter get_certificates_waiter; |
| platform_keys_service()->GetCertificates( |
| token_id, get_certificates_waiter.GetCallback()); |
| get_certificates_waiter.Wait(); |
| ASSERT_EQ(get_certificates_waiter.matches().size(), 0U); |
| |
| net::ScopedCERTCertificate cert; |
| std::string public_key; |
| ASSERT_NO_FATAL_FAILURE( |
| ImportCertAndKey(token_id, net::GetTestCertsDirectory(), "client_1.pem", |
| "client_1.pk8", &cert, &public_key)); |
| |
| // Assert that the certificate is imported correctly. |
| ASSERT_TRUE(cert.get()); |
| test_util::GetCertificatesExecutionWaiter get_certificates_waiter_2; |
| platform_keys_service()->GetCertificates( |
| token_id, get_certificates_waiter_2.GetCallback()); |
| get_certificates_waiter_2.Wait(); |
| ASSERT_EQ(get_certificates_waiter_2.matches().size(), 1U); |
| |
| auto public_key_bytes = base::as_bytes(base::make_span(public_key)); |
| EXPECT_TRUE(crypto::FindNSSKeyFromPublicKeyInfo(public_key_bytes)); |
| |
| // Try Removing the key pair. |
| test_util::RemoveKeyExecutionWaiter remove_key_waiter; |
| platform_keys_service()->RemoveKey(token_id, public_key, |
| remove_key_waiter.GetCallback()); |
| remove_key_waiter.Wait(); |
| EXPECT_NE(remove_key_waiter.status(), Status::kSuccess); |
| |
| // Assert that the certificate is not removed. |
| test_util::GetCertificatesExecutionWaiter get_certificates_waiter_3; |
| platform_keys_service()->GetCertificates( |
| token_id, get_certificates_waiter_3.GetCallback()); |
| get_certificates_waiter_3.Wait(); |
| |
| net::CertificateList found_certs = get_certificates_waiter_3.matches(); |
| ASSERT_EQ(found_certs.size(), 1U); |
| EXPECT_TRUE( |
| net::x509_util::IsSameCertificate(found_certs[0].get(), cert.get())); |
| |
| // Assert that the key pair is not deleted. |
| EXPECT_TRUE(crypto::FindNSSKeyFromPublicKeyInfo(public_key_bytes)); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| GetAllKeysWhenNoKeysGenerated) { |
| const TokenId token_id = GetParam().token_id; |
| test_util::GetAllKeysExecutionWaiter get_all_keys_waiter; |
| platform_keys_service()->GetAllKeys(token_id, |
| get_all_keys_waiter.GetCallback()); |
| get_all_keys_waiter.Wait(); |
| |
| EXPECT_EQ(get_all_keys_waiter.status(), Status::kSuccess); |
| std::vector<std::string> public_keys = get_all_keys_waiter.public_keys(); |
| EXPECT_TRUE(public_keys.empty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, IsKeyOnToken) { |
| const TokenId token_id = GetParam().token_id; |
| const std::string public_key = GenerateKeyPair(token_id); |
| |
| test_util::IsKeyOnTokenExecutionWaiter is_key_on_token_waiter; |
| platform_keys_service()->IsKeyOnToken(token_id, public_key, |
| is_key_on_token_waiter.GetCallback()); |
| is_key_on_token_waiter.Wait(); |
| |
| EXPECT_EQ(is_key_on_token_waiter.status(), Status::kSuccess); |
| ASSERT_TRUE(is_key_on_token_waiter.on_slot().has_value()); |
| EXPECT_TRUE(is_key_on_token_waiter.on_slot().value()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerTokenBrowserTest, |
| IsKeyOnTokenWhenNoKeysGenerated) { |
| const TokenId token_id = GetParam().token_id; |
| |
| test_util::IsKeyOnTokenExecutionWaiter is_key_on_token_waiter; |
| platform_keys_service()->IsKeyOnToken(token_id, "test_public_key", |
| is_key_on_token_waiter.GetCallback()); |
| is_key_on_token_waiter.Wait(); |
| |
| EXPECT_EQ(is_key_on_token_waiter.status(), Status::kSuccess); |
| ASSERT_TRUE(is_key_on_token_waiter.on_slot().has_value()); |
| EXPECT_FALSE(is_key_on_token_waiter.on_slot().value()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AllSupportedProfilesAndTokensTypes, |
| PlatformKeysServicePerTokenBrowserTest, |
| ::testing::Values(TestConfigPerToken{ProfileToUse::kSigninProfile, |
| TokenId::kSystem}, |
| TestConfigPerToken{ProfileToUse::kUnaffiliatedUserProfile, |
| TokenId::kUser}, |
| TestConfigPerToken{ProfileToUse::kAffiliatedUserProfile, |
| TokenId::kSystem}, |
| TestConfigPerToken{ProfileToUse::kAffiliatedUserProfile, |
| TokenId::kUser})); |
| |
| // PlatformKeysServicePerUnavailableTokenBrowserTest is essentially the same as |
| // PlatformKeysServicePerTokenBrowserTest but contains different test cases |
| // (testing that the token is not available) and runs on a different set of |
| // (profile, token) pairs accordingly. |
| using PlatformKeysServicePerUnavailableTokenBrowserTest = |
| PlatformKeysServicePerTokenBrowserTest; |
| |
| // Uses GenerateRSAKey as an example operation that should fail because the |
| // token is not available. |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerUnavailableTokenBrowserTest, |
| GenerateRsa) { |
| const unsigned int kKeySize = 2048; |
| |
| const TokenId token_id = GetParam().token_id; |
| test_util::GenerateKeyExecutionWaiter generate_key_waiter; |
| platform_keys_service()->GenerateRSAKey(token_id, kKeySize, |
| generate_key_waiter.GetCallback()); |
| generate_key_waiter.Wait(); |
| EXPECT_NE(generate_key_waiter.status(), Status::kSuccess); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(PlatformKeysServicePerUnavailableTokenBrowserTest, |
| IsKeyOnToken) { |
| const TokenId token_id = GetParam().token_id; |
| |
| test_util::IsKeyOnTokenExecutionWaiter is_key_on_token_waiter; |
| platform_keys_service()->IsKeyOnToken(token_id, "test_public_key", |
| is_key_on_token_waiter.GetCallback()); |
| is_key_on_token_waiter.Wait(); |
| |
| EXPECT_NE(is_key_on_token_waiter.status(), Status::kSuccess); |
| EXPECT_FALSE(is_key_on_token_waiter.on_slot().has_value()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AllSupportedProfilesAndTokensTypes, |
| PlatformKeysServicePerUnavailableTokenBrowserTest, |
| ::testing::Values(TestConfigPerToken{ProfileToUse::kSigninProfile, |
| TokenId::kUser}, |
| TestConfigPerToken{ProfileToUse::kUnaffiliatedUserProfile, |
| TokenId::kSystem})); |
| } // namespace platform_keys |
| } // namespace chromeos |