1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crypto/unexportable_key_metrics.h"
6
7 #include <memory>
8
9 #include "base/test/metrics/histogram_tester.h"
10 #include "crypto/signature_verifier.h"
11 #include "crypto/unexportable_key.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace crypto {
15
16 namespace {
17
18 // Mock that wraps the stateless software unexportable key provider while
19 // tracking key creation and removal. CHECKs if there are keys left that have
20 // not been removed when destroyed.
21 class MockTrackingUnexportableKeyProvider : public UnexportableKeyProvider {
22 public:
MockTrackingUnexportableKeyProvider()23 MockTrackingUnexportableKeyProvider()
24 : key_provider_(GetSoftwareUnsecureUnexportableKeyProvider()) {}
25
~MockTrackingUnexportableKeyProvider()26 ~MockTrackingUnexportableKeyProvider() override {
27 CHECK(keys_.empty()) << keys_.size() << " key(s) not deleted.";
28 }
29
30 // UnexportableKeyProvider:
SelectAlgorithm(base::span<const SignatureVerifier::SignatureAlgorithm> acceptable_algorithms)31 std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
32 base::span<const SignatureVerifier::SignatureAlgorithm>
33 acceptable_algorithms) override {
34 return key_provider_->SelectAlgorithm(acceptable_algorithms);
35 }
GenerateSigningKeySlowly(base::span<const SignatureVerifier::SignatureAlgorithm> acceptable_algorithms)36 std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly(
37 base::span<const SignatureVerifier::SignatureAlgorithm>
38 acceptable_algorithms) override {
39 std::unique_ptr<UnexportableSigningKey> key =
40 key_provider_->GenerateSigningKeySlowly(acceptable_algorithms);
41 if (key) {
42 keys_.emplace(key->GetWrappedKey());
43 }
44 return key;
45 }
FromWrappedSigningKeySlowly(base::span<const uint8_t> wrapped_key)46 std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly(
47 base::span<const uint8_t> wrapped_key) override {
48 CHECK(keys_.contains(
49 std::vector<uint8_t>(wrapped_key.begin(), wrapped_key.end())))
50 << "Attempted to delete non existing key";
51 return key_provider_->FromWrappedSigningKeySlowly(wrapped_key);
52 }
DeleteSigningKey(base::span<const uint8_t> wrapped_key)53 bool DeleteSigningKey(base::span<const uint8_t> wrapped_key) override {
54 key_provider_->DeleteSigningKey(wrapped_key);
55 return keys_.erase(
56 std::vector<uint8_t>(wrapped_key.begin(), wrapped_key.end()));
57 }
58
59 private:
60 std::unique_ptr<UnexportableKeyProvider> key_provider_;
61 std::set<std::vector<uint8_t>> keys_;
62 };
63
GetUnexportableKeyProviderMock()64 std::unique_ptr<UnexportableKeyProvider> GetUnexportableKeyProviderMock() {
65 return std::make_unique<MockTrackingUnexportableKeyProvider>();
66 }
67
68 class UnexportableKeyMetricTest : public testing::Test {
SetUp()69 void SetUp() override {
70 internal::SetUnexportableKeyProviderForTesting(
71 GetUnexportableKeyProviderMock);
72 }
73
TearDown()74 void TearDown() override {
75 internal::SetUnexportableKeyProviderForTesting(nullptr);
76 }
77 };
78
79 // Note mock provider only supports ECDSA.
TEST_F(UnexportableKeyMetricTest,GatherAllMetrics)80 TEST_F(UnexportableKeyMetricTest, GatherAllMetrics) {
81 base::HistogramTester histogram_tester;
82 histogram_tester.ExpectTotalCount("Crypto.TPMSupport2", 0);
83 histogram_tester.ExpectTotalCount("Crypto.TPMDuration.NewKeyCreationECDSA",
84 0);
85 histogram_tester.ExpectTotalCount(
86 "Crypto.TPMDuration.WrappedKeyCreationECDSA", 0);
87 histogram_tester.ExpectTotalCount("Crypto.TPMDuration.MessageSigningECDSA",
88 0);
89 histogram_tester.ExpectTotalCount("Crypto.TPMOperation.NewKeyCreation", 0);
90 histogram_tester.ExpectTotalCount("Crypto.TPMOperation.WrappedKeyCreation",
91 0);
92 histogram_tester.ExpectTotalCount("Crypto.TPMOperation.MessageSigning", 0);
93 histogram_tester.ExpectTotalCount("Crypto.TPMOperation.MessageVerify", 0);
94
95 internal::MeasureTpmOperationsInternalForTesting();
96
97 EXPECT_THAT(histogram_tester.GetAllSamples("Crypto.TPMSupport2"),
98 BucketsAre(base::Bucket(internal::TPMSupport::kECDSA, 1)));
99 histogram_tester.ExpectTotalCount("Crypto.TPMDuration.NewKeyCreationECDSA",
100 1);
101 histogram_tester.ExpectTotalCount(
102 "Crypto.TPMDuration.WrappedKeyCreationECDSA", 1);
103 histogram_tester.ExpectTotalCount("Crypto.TPMDuration.MessageSigningECDSA",
104 1);
105 EXPECT_THAT(
106 histogram_tester.GetAllSamples("Crypto.TPMOperation.NewKeyCreationECDSA"),
107 BucketsAre(base::Bucket(true, 1)));
108 EXPECT_THAT(histogram_tester.GetAllSamples(
109 "Crypto.TPMOperation.WrappedKeyCreationECDSA"),
110 BucketsAre(base::Bucket(true, 1)));
111 EXPECT_THAT(
112 histogram_tester.GetAllSamples("Crypto.TPMOperation.MessageSigningECDSA"),
113 BucketsAre(base::Bucket(true, 1)));
114 EXPECT_THAT(
115 histogram_tester.GetAllSamples("Crypto.TPMOperation.MessageVerifyECDSA"),
116 BucketsAre(base::Bucket(true, 1)));
117 }
118
119 } // namespace
120
121 } // namespace crypto
122