blob: 946be9bf57478391d39feb706c4f4b6ac920752e [file] [log] [blame]
Kristian Monsend39acd12022-09-15 17:42:311// 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 "base/feature_list.h"
8#include "base/metrics/histogram_functions.h"
9#include "base/task/task_traits.h"
10#include "base/task/thread_pool.h"
11#include "base/timer/elapsed_timer.h"
12#include "crypto/unexportable_key.h"
13
14namespace crypto {
15
16namespace {
17
18enum class TPMOperation {
19 kMessageSigning,
20 kMessageVerify,
21 kWrappedKeyCreation,
22 kNewKeyCreation,
23};
24
25std::string GetHistogramSuffixForOperation(TPMOperation operation) {
26 switch (operation) {
27 case TPMOperation::kMessageSigning:
28 return "MessageSigning";
29 case TPMOperation::kMessageVerify:
30 return "MessageVerify";
31 case TPMOperation::kNewKeyCreation:
32 return "NewKeyCreation";
33 case TPMOperation::kWrappedKeyCreation:
34 return "WrappedKeyCreation";
35 }
36 return "";
37}
38
39std::string GetHistogramSuffixForAlgo(internal::TPMSupport algo) {
40 switch (algo) {
41 case internal::TPMSupport::kECDSA:
42 return "ECDSA";
43 case internal::TPMSupport::kRSA:
44 return "RSA";
45 case internal::TPMSupport::kNone:
46 return "";
47 }
48 return "";
49}
50
51void ReportUmaLatency(TPMOperation operation,
52 internal::TPMSupport algo,
53 base::TimeDelta latency) {
54 std::string histogram_name = "Crypto.TPMDuration." +
55 GetHistogramSuffixForOperation(operation) +
56 GetHistogramSuffixForAlgo(algo);
57 base::UmaHistogramMediumTimes(histogram_name, latency);
58}
59
60void ReportUmaOperationSuccess(TPMOperation operation,
61 internal::TPMSupport algo,
62 bool status) {
63 std::string histogram_name = "Crypto.TPMOperation." +
64 GetHistogramSuffixForOperation(operation) +
65 GetHistogramSuffixForAlgo(algo);
66 base::UmaHistogramBoolean(histogram_name, status);
67}
68
69void ReportUmaTpmOperation(TPMOperation operation,
70 internal::TPMSupport algo,
71 base::TimeDelta latency,
72 bool status) {
73 ReportUmaOperationSuccess(operation, algo, status);
74 if (status && operation != TPMOperation::kMessageVerify) {
75 // Only report latency for successful operations
76 // No latency reported for verification that is done outside of TPM
77 ReportUmaLatency(operation, algo, latency);
78 }
79}
80
81void MeasureTpmOperationsInternal() {
82 internal::TPMSupport supported_algo = internal::TPMSupport::kNone;
83 std::unique_ptr<UnexportableKeyProvider> provider =
84 GetUnexportableKeyProvider();
85 if (!provider) {
86 return;
87 }
88
89 const SignatureVerifier::SignatureAlgorithm kAllAlgorithms[] = {
90 SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256,
91 SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256,
92 };
93
94 auto algo = provider->SelectAlgorithm(kAllAlgorithms);
95 if (algo) {
96 switch (*algo) {
97 case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
98 supported_algo = internal::TPMSupport::kECDSA;
99 break;
100 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
101 supported_algo = internal::TPMSupport::kRSA;
102 break;
103 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA1:
104 case SignatureVerifier::SignatureAlgorithm::RSA_PSS_SHA256:
105 // Not supported for this metric.
106 break;
107 }
108 }
109
110 // Report if TPM is supported and best algo
111 base::UmaHistogramEnumeration("Crypto.TPMSupport2", supported_algo);
112 if (supported_algo == internal::TPMSupport::kNone) {
113 return;
114 }
115
116 base::ElapsedTimer key_creation_timer;
117 std::unique_ptr<UnexportableSigningKey> current_key =
118 provider->GenerateSigningKeySlowly(kAllAlgorithms);
119 ReportUmaTpmOperation(TPMOperation::kNewKeyCreation, supported_algo,
120 key_creation_timer.Elapsed(), current_key != nullptr);
121 if (!current_key) {
122 return;
123 }
124
125 base::ElapsedTimer wrapped_key_creation_timer;
126 std::unique_ptr<UnexportableSigningKey> wrapped_key =
127 provider->FromWrappedSigningKeySlowly(current_key->GetWrappedKey());
128 ReportUmaTpmOperation(TPMOperation::kWrappedKeyCreation, supported_algo,
129 wrapped_key_creation_timer.Elapsed(),
130 wrapped_key != nullptr);
131
132 const uint8_t msg[] = {1, 2, 3, 4};
133 base::ElapsedTimer message_signing_timer;
134 absl::optional<std::vector<uint8_t>> signed_bytes =
135 current_key->SignSlowly(msg);
136 ReportUmaTpmOperation(TPMOperation::kMessageSigning, supported_algo,
137 message_signing_timer.Elapsed(),
138 signed_bytes.has_value());
139 if (!signed_bytes.has_value()) {
140 return;
141 }
142
143 crypto::SignatureVerifier verifier;
144 bool verify_init =
145 verifier.VerifyInit(current_key->Algorithm(), signed_bytes.value(),
146 current_key->GetSubjectPublicKeyInfo());
147 if (verify_init) {
148 verifier.VerifyUpdate(msg);
149 bool verify_final = verifier.VerifyFinal();
150 ReportUmaOperationSuccess(TPMOperation::kMessageVerify, supported_algo,
151 verify_final);
152 } else {
153 ReportUmaOperationSuccess(TPMOperation::kMessageVerify, supported_algo,
154 verify_init);
155 }
156}
157
158} // namespace
159
160namespace internal {
161
162void MeasureTpmOperationsInternalForTesting() {
163 MeasureTpmOperationsInternal();
164}
165
166} // namespace internal
167
168void MaybeMeasureTpmOperations() {
Daniel Chengedab3f872022-10-01 03:31:37169 static BASE_FEATURE(kTpmLatencyMetrics, "TpmLatencyMetrics",
170 base::FEATURE_ENABLED_BY_DEFAULT);
Kristian Monsend39acd12022-09-15 17:42:31171 if (base::FeatureList::IsEnabled(kTpmLatencyMetrics)) {
172 base::ThreadPool::PostTask(
173 FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
174 base::BindOnce(&MeasureTpmOperationsInternal));
175 }
176}
177
Daniel Chengedab3f872022-10-01 03:31:37178} // namespace crypto