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.
5 #include "crypto/unexportable_key_metrics.h"
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"
18 enum class TPMOperation {
30 const SignatureVerifier::SignatureAlgorithm kAllAlgorithms[] = {
31 SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256,
32 SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256,
35 constexpr char kTestKeyName[] = "ChromeMetricsTestKey";
37 // Leaving HW empty will keep the existing metric as is today.
38 std::string GetHistogramPrefixForKeyType(KeyType type) {
40 case KeyType::kHardwareKey:
42 case KeyType::kVirtualizedKey:
47 std::string GetHistogramSuffixForOperation(TPMOperation operation) {
49 case TPMOperation::kMessageSigning:
50 return "MessageSigning";
51 case TPMOperation::kMessageVerify:
52 return "MessageVerify";
53 case TPMOperation::kNewKeyCreation:
54 return "NewKeyCreation";
55 case TPMOperation::kWrappedKeyCreation:
56 return "WrappedKeyCreation";
61 std::string GetHistogramSuffixForAlgo(internal::TPMSupport algo) {
63 case internal::TPMSupport::kECDSA:
65 case internal::TPMSupport::kRSA:
67 case internal::TPMSupport::kNone:
73 internal::TPMType GetSupportedTpm(internal::TPMSupport hw,
74 internal::TPMSupport virt) {
75 if (hw != internal::TPMSupport::kNone &&
76 virt != internal::TPMSupport::kNone) {
77 return internal::TPMType::kBoth;
80 if (hw != internal::TPMSupport::kNone) {
81 return internal::TPMType::kHW;
84 // This is not expected
85 if (virt != internal::TPMSupport::kNone) {
86 return internal::TPMType::kVirtual;
89 return internal::TPMType::kNone;
92 void ReportUmaLatency(TPMOperation operation,
93 internal::TPMSupport algo,
94 base::TimeDelta latency,
95 KeyType type = KeyType::kHardwareKey) {
96 std::string histogram_name = "Crypto.TPMDuration." +
97 GetHistogramPrefixForKeyType(type) +
98 GetHistogramSuffixForOperation(operation) +
99 GetHistogramSuffixForAlgo(algo);
100 base::UmaHistogramMediumTimes(histogram_name, latency);
103 void ReportUmaOperationSuccess(TPMOperation operation,
104 internal::TPMSupport algo,
106 KeyType type = KeyType::kHardwareKey) {
107 std::string histogram_name = "Crypto.TPMOperation." +
108 GetHistogramPrefixForKeyType(type) +
109 GetHistogramSuffixForOperation(operation) +
110 GetHistogramSuffixForAlgo(algo);
111 base::UmaHistogramBoolean(histogram_name, status);
114 void ReportUmaTpmOperation(TPMOperation operation,
115 internal::TPMSupport algo,
116 base::TimeDelta latency,
118 KeyType type = KeyType::kHardwareKey) {
119 ReportUmaOperationSuccess(operation, algo, status, type);
120 if (status && operation != TPMOperation::kMessageVerify) {
121 // Only report latency for successful operations
122 // No latency reported for verification that is done outside of TPM
123 ReportUmaLatency(operation, algo, latency, type);
127 internal::TPMSupport MeasureVirtualTpmOperations() {
128 internal::TPMSupport supported_virtual_algo = internal::TPMSupport::kNone;
129 std::unique_ptr<VirtualUnexportableKeyProvider> virtual_provider =
130 GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY();
132 if (!virtual_provider) {
133 return supported_virtual_algo;
136 auto algo = virtual_provider->SelectAlgorithm(kAllAlgorithms);
139 case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
140 supported_virtual_algo = internal::TPMSupport::kECDSA;
142 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
143 supported_virtual_algo = internal::TPMSupport::kRSA;
145 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA1:
146 case SignatureVerifier::SignatureAlgorithm::RSA_PSS_SHA256:
147 // Not supported for this metric.
152 // Report if virtual TPM is supported and best algo
153 base::UmaHistogramEnumeration("Crypto.VirtualKeySupport",
154 supported_virtual_algo);
156 base::ElapsedTimer key_creation_timer;
157 std::unique_ptr<VirtualUnexportableSigningKey> current_key =
158 virtual_provider->GenerateSigningKey(kAllAlgorithms, kTestKeyName);
159 ReportUmaTpmOperation(TPMOperation::kNewKeyCreation, supported_virtual_algo,
160 key_creation_timer.Elapsed(), current_key != nullptr,
161 KeyType::kVirtualizedKey);
163 // Report no support if keys cannot be created, Windows appears to always
164 // mark the keys as available in SelectAlgorithm.
165 return internal::TPMSupport::kNone;
168 base::ElapsedTimer open_key_timer;
169 std::string key_name = current_key->GetKeyName();
170 std::unique_ptr<VirtualUnexportableSigningKey> opened_key =
171 virtual_provider->FromKeyName(key_name);
172 // Re-using TPMOperation::kWrappedKeyCreation for restoring keys even though
173 // there are no wrapped keys involved.
174 ReportUmaTpmOperation(TPMOperation::kWrappedKeyCreation,
175 supported_virtual_algo, open_key_timer.Elapsed(),
176 opened_key != nullptr, KeyType::kVirtualizedKey);
178 const uint8_t msg[] = {1, 2, 3, 4};
179 base::ElapsedTimer message_signing_timer;
180 absl::optional<std::vector<uint8_t>> signed_bytes = current_key->Sign(msg);
181 ReportUmaTpmOperation(TPMOperation::kMessageSigning, supported_virtual_algo,
182 message_signing_timer.Elapsed(),
183 signed_bytes.has_value(), KeyType::kVirtualizedKey);
185 if (signed_bytes.has_value()) {
186 crypto::SignatureVerifier verifier;
188 verifier.VerifyInit(current_key->Algorithm(), signed_bytes.value(),
189 current_key->GetSubjectPublicKeyInfo());
191 verifier.VerifyUpdate(msg);
192 bool verify_final = verifier.VerifyFinal();
193 ReportUmaOperationSuccess(TPMOperation::kMessageVerify,
194 supported_virtual_algo, verify_final,
195 KeyType::kVirtualizedKey);
197 ReportUmaOperationSuccess(TPMOperation::kMessageVerify,
198 supported_virtual_algo, verify_init,
199 KeyType::kVirtualizedKey);
203 current_key.get()->DeleteKey();
204 return supported_virtual_algo;
207 void MeasureTpmOperationsInternal() {
208 internal::TPMSupport supported_algo = internal::TPMSupport::kNone;
209 std::unique_ptr<UnexportableKeyProvider> provider =
210 GetUnexportableKeyProvider();
215 auto algo = provider->SelectAlgorithm(kAllAlgorithms);
218 case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
219 supported_algo = internal::TPMSupport::kECDSA;
221 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
222 supported_algo = internal::TPMSupport::kRSA;
224 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA1:
225 case SignatureVerifier::SignatureAlgorithm::RSA_PSS_SHA256:
226 // Not supported for this metric.
231 internal::TPMSupport supported_virtual_algo = MeasureVirtualTpmOperations();
232 base::UmaHistogramEnumeration(
233 "Crypto.TPMSupportType",
234 GetSupportedTpm(supported_algo, supported_virtual_algo));
236 // Report if TPM is supported and best algo
237 base::UmaHistogramEnumeration("Crypto.TPMSupport2", supported_algo);
238 if (supported_algo == internal::TPMSupport::kNone) {
242 base::ElapsedTimer key_creation_timer;
243 std::unique_ptr<UnexportableSigningKey> current_key =
244 provider->GenerateSigningKeySlowly(kAllAlgorithms);
245 ReportUmaTpmOperation(TPMOperation::kNewKeyCreation, supported_algo,
246 key_creation_timer.Elapsed(), current_key != nullptr);
251 base::ElapsedTimer wrapped_key_creation_timer;
252 std::unique_ptr<UnexportableSigningKey> wrapped_key =
253 provider->FromWrappedSigningKeySlowly(current_key->GetWrappedKey());
254 ReportUmaTpmOperation(TPMOperation::kWrappedKeyCreation, supported_algo,
255 wrapped_key_creation_timer.Elapsed(),
256 wrapped_key != nullptr);
258 const uint8_t msg[] = {1, 2, 3, 4};
259 base::ElapsedTimer message_signing_timer;
260 absl::optional<std::vector<uint8_t>> signed_bytes =
261 current_key->SignSlowly(msg);
262 ReportUmaTpmOperation(TPMOperation::kMessageSigning, supported_algo,
263 message_signing_timer.Elapsed(),
264 signed_bytes.has_value());
265 if (!signed_bytes.has_value()) {
269 crypto::SignatureVerifier verifier;
271 verifier.VerifyInit(current_key->Algorithm(), signed_bytes.value(),
272 current_key->GetSubjectPublicKeyInfo());
274 verifier.VerifyUpdate(msg);
275 bool verify_final = verifier.VerifyFinal();
276 ReportUmaOperationSuccess(TPMOperation::kMessageVerify, supported_algo,
279 ReportUmaOperationSuccess(TPMOperation::kMessageVerify, supported_algo,
288 void MeasureTpmOperationsInternalForTesting() {
289 MeasureTpmOperationsInternal();
292 } // namespace internal
294 void MaybeMeasureTpmOperations() {
295 static BASE_FEATURE(kTpmLatencyMetrics, "TpmLatencyMetrics",
296 base::FEATURE_ENABLED_BY_DEFAULT);
297 if (base::FeatureList::IsEnabled(kTpmLatencyMetrics)) {
298 base::ThreadPool::PostTask(
300 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
301 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
302 base::BindOnce(&MeasureTpmOperationsInternal));
306 } // namespace crypto