1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "crypto/unexportable_key.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <optional>
8*6777b538SAndroid Build Coastguard Worker #include <tuple>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/test/scoped_feature_list.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
13*6777b538SAndroid Build Coastguard Worker #include "crypto/features.h"
14*6777b538SAndroid Build Coastguard Worker #include "crypto/scoped_mock_unexportable_key_provider.h"
15*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_MAC)
18*6777b538SAndroid Build Coastguard Worker #include "crypto/scoped_fake_apple_keychain_v2.h"
19*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_MAC)
20*6777b538SAndroid Build Coastguard Worker
21*6777b538SAndroid Build Coastguard Worker namespace {
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker const crypto::SignatureVerifier::SignatureAlgorithm kAllAlgorithms[] = {
24*6777b538SAndroid Build Coastguard Worker crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256,
25*6777b538SAndroid Build Coastguard Worker crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256,
26*6777b538SAndroid Build Coastguard Worker };
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_MAC)
29*6777b538SAndroid Build Coastguard Worker constexpr char kTestKeychainAccessGroup[] = "test-keychain-access-group";
30*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_MAC)
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker class UnexportableKeySigningTest
33*6777b538SAndroid Build Coastguard Worker : public testing::TestWithParam<
34*6777b538SAndroid Build Coastguard Worker std::tuple<crypto::SignatureVerifier::SignatureAlgorithm, bool>> {
35*6777b538SAndroid Build Coastguard Worker private:
36*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_MAC)
37*6777b538SAndroid Build Coastguard Worker crypto::ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
38*6777b538SAndroid Build Coastguard Worker kTestKeychainAccessGroup};
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker base::test::ScopedFeatureList scoped_feature_list_{
41*6777b538SAndroid Build Coastguard Worker crypto::kEnableMacUnexportableKeys};
42*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_MAC)
43*6777b538SAndroid Build Coastguard Worker };
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(All,
46*6777b538SAndroid Build Coastguard Worker UnexportableKeySigningTest,
47*6777b538SAndroid Build Coastguard Worker testing::Combine(testing::ValuesIn(kAllAlgorithms),
48*6777b538SAndroid Build Coastguard Worker testing::Bool()));
49*6777b538SAndroid Build Coastguard Worker
TEST_P(UnexportableKeySigningTest,RoundTrip)50*6777b538SAndroid Build Coastguard Worker TEST_P(UnexportableKeySigningTest, RoundTrip) {
51*6777b538SAndroid Build Coastguard Worker const crypto::SignatureVerifier::SignatureAlgorithm algo =
52*6777b538SAndroid Build Coastguard Worker std::get<0>(GetParam());
53*6777b538SAndroid Build Coastguard Worker const bool mock_enabled = std::get<1>(GetParam());
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Worker switch (algo) {
56*6777b538SAndroid Build Coastguard Worker case crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
57*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "ECDSA P-256, mock=" << mock_enabled;
58*6777b538SAndroid Build Coastguard Worker break;
59*6777b538SAndroid Build Coastguard Worker case crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
60*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "RSA, mock=" << mock_enabled;
61*6777b538SAndroid Build Coastguard Worker break;
62*6777b538SAndroid Build Coastguard Worker default:
63*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(false);
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(static_cast<int>(algo));
67*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(mock_enabled);
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker std::optional<crypto::ScopedMockUnexportableKeyProvider> mock;
70*6777b538SAndroid Build Coastguard Worker if (mock_enabled) {
71*6777b538SAndroid Build Coastguard Worker mock.emplace();
72*6777b538SAndroid Build Coastguard Worker }
73*6777b538SAndroid Build Coastguard Worker
74*6777b538SAndroid Build Coastguard Worker const crypto::SignatureVerifier::SignatureAlgorithm algorithms[] = {algo};
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker crypto::UnexportableKeyProvider::Config config{
77*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_MAC)
78*6777b538SAndroid Build Coastguard Worker .keychain_access_group = kTestKeychainAccessGroup
79*6777b538SAndroid Build Coastguard Worker #endif // BUILDLFAG(IS_MAC)
80*6777b538SAndroid Build Coastguard Worker };
81*6777b538SAndroid Build Coastguard Worker std::unique_ptr<crypto::UnexportableKeyProvider> provider =
82*6777b538SAndroid Build Coastguard Worker crypto::GetUnexportableKeyProvider(std::move(config));
83*6777b538SAndroid Build Coastguard Worker if (!provider) {
84*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "Skipping test because of lack of hardware support.";
85*6777b538SAndroid Build Coastguard Worker return;
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker if (!provider->SelectAlgorithm(algorithms)) {
89*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "Skipping test because of lack of support for this key type.";
90*6777b538SAndroid Build Coastguard Worker return;
91*6777b538SAndroid Build Coastguard Worker }
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker const base::TimeTicks generate_start = base::TimeTicks::Now();
94*6777b538SAndroid Build Coastguard Worker std::unique_ptr<crypto::UnexportableSigningKey> key =
95*6777b538SAndroid Build Coastguard Worker provider->GenerateSigningKeySlowly(algorithms);
96*6777b538SAndroid Build Coastguard Worker if (algo == crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256) {
97*6777b538SAndroid Build Coastguard Worker if (!key) {
98*6777b538SAndroid Build Coastguard Worker GTEST_SKIP()
99*6777b538SAndroid Build Coastguard Worker << "Workaround for https://issues.chromium.org/issues/41494935";
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker }
102*6777b538SAndroid Build Coastguard Worker
103*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(key);
104*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "Generation took " << (base::TimeTicks::Now() - generate_start);
105*6777b538SAndroid Build Coastguard Worker
106*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(key->Algorithm(), algo);
107*6777b538SAndroid Build Coastguard Worker const std::vector<uint8_t> wrapped = key->GetWrappedKey();
108*6777b538SAndroid Build Coastguard Worker const std::vector<uint8_t> spki = key->GetSubjectPublicKeyInfo();
109*6777b538SAndroid Build Coastguard Worker const uint8_t msg[] = {1, 2, 3, 4};
110*6777b538SAndroid Build Coastguard Worker
111*6777b538SAndroid Build Coastguard Worker const base::TimeTicks sign_start = base::TimeTicks::Now();
112*6777b538SAndroid Build Coastguard Worker const std::optional<std::vector<uint8_t>> sig = key->SignSlowly(msg);
113*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "Signing took " << (base::TimeTicks::Now() - sign_start);
114*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(sig);
115*6777b538SAndroid Build Coastguard Worker
116*6777b538SAndroid Build Coastguard Worker crypto::SignatureVerifier verifier;
117*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(verifier.VerifyInit(algo, *sig, spki));
118*6777b538SAndroid Build Coastguard Worker verifier.VerifyUpdate(msg);
119*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(verifier.VerifyFinal());
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker const base::TimeTicks import2_start = base::TimeTicks::Now();
122*6777b538SAndroid Build Coastguard Worker std::unique_ptr<crypto::UnexportableSigningKey> key2 =
123*6777b538SAndroid Build Coastguard Worker provider->FromWrappedSigningKeySlowly(wrapped);
124*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(key2);
125*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "Import took " << (base::TimeTicks::Now() - import2_start);
126*6777b538SAndroid Build Coastguard Worker
127*6777b538SAndroid Build Coastguard Worker const base::TimeTicks sign2_start = base::TimeTicks::Now();
128*6777b538SAndroid Build Coastguard Worker const std::optional<std::vector<uint8_t>> sig2 = key->SignSlowly(msg);
129*6777b538SAndroid Build Coastguard Worker LOG(INFO) << "Signing took " << (base::TimeTicks::Now() - sign2_start);
130*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(sig2);
131*6777b538SAndroid Build Coastguard Worker
132*6777b538SAndroid Build Coastguard Worker crypto::SignatureVerifier verifier2;
133*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(verifier2.VerifyInit(algo, *sig2, spki));
134*6777b538SAndroid Build Coastguard Worker verifier2.VerifyUpdate(msg);
135*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(verifier2.VerifyFinal());
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(provider->DeleteSigningKey(wrapped));
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker } // namespace
140