Kristian Monsen | d39acd1 | 2022-09-15 17:42:31 | [diff] [blame] | 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 "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 | |
| 14 | namespace crypto { |
| 15 | |
| 16 | namespace { |
| 17 | |
| 18 | enum class TPMOperation { |
| 19 | kMessageSigning, |
| 20 | kMessageVerify, |
| 21 | kWrappedKeyCreation, |
| 22 | kNewKeyCreation, |
| 23 | }; |
| 24 | |
| 25 | std::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 | |
| 39 | std::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 | |
| 51 | void 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 | |
| 60 | void 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 | |
| 69 | void 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 | |
| 81 | void 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 | |
| 160 | namespace internal { |
| 161 | |
| 162 | void MeasureTpmOperationsInternalForTesting() { |
| 163 | MeasureTpmOperationsInternal(); |
| 164 | } |
| 165 | |
| 166 | } // namespace internal |
| 167 | |
| 168 | void MaybeMeasureTpmOperations() { |
Daniel Cheng | edab3f87 | 2022-10-01 03:31:37 | [diff] [blame] | 169 | static BASE_FEATURE(kTpmLatencyMetrics, "TpmLatencyMetrics", |
| 170 | base::FEATURE_ENABLED_BY_DEFAULT); |
Kristian Monsen | d39acd1 | 2022-09-15 17:42:31 | [diff] [blame] | 171 | 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 Cheng | edab3f87 | 2022-10-01 03:31:37 | [diff] [blame] | 178 | } // namespace crypto |