Avi Drissman | 201a9a83 | 2022-09-13 19:39:25 | [diff] [blame] | 1 | // Copyright 2021 The Chromium Authors |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef CRYPTO_UNEXPORTABLE_KEY_H_ |
| 6 | #define CRYPTO_UNEXPORTABLE_KEY_H_ |
| 7 | |
| 8 | #include <memory> |
| 9 | |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 10 | #include <optional> |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 11 | #include "crypto/crypto_export.h" |
| 12 | #include "crypto/signature_verifier.h" |
| 13 | |
| 14 | namespace crypto { |
| 15 | |
| 16 | // UnexportableSigningKey provides a hardware-backed signing oracle on platforms |
| 17 | // that support it. Current support is: |
| 18 | // Windows: RSA_PKCS1_SHA256 via TPM 1.2+ and ECDSA_SHA256 via TPM 2.0. |
| 19 | // Tests: ECDSA_SHA256 via ScopedMockUnexportableSigningKeyForTesting. |
Alex Ilin | a06c3fa | 2023-01-09 11:39:50 | [diff] [blame] | 20 | // |
| 21 | // See also //components/unexportable_keys for a higher-level key management |
| 22 | // API. |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 23 | class CRYPTO_EXPORT UnexportableSigningKey { |
| 24 | public: |
| 25 | virtual ~UnexportableSigningKey(); |
| 26 | |
| 27 | // Algorithm returns the algorithm of the key in this object. |
| 28 | virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0; |
| 29 | |
| 30 | // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of |
| 31 | // this object. |
| 32 | virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0; |
| 33 | |
| 34 | // GetWrappedKey returns the encrypted private key of this object. It is |
| 35 | // encrypted to a key that is kept in hardware and the unencrypted private |
| 36 | // key never exists in the CPU's memory. |
| 37 | // |
| 38 | // A wrapped key may be used with a future instance of this code to recreate |
| 39 | // the key so long as it's running on the same computer. |
| 40 | // |
| 41 | // Note: it is possible to export this wrapped key off machine, but it must be |
| 42 | // sealed with an AEAD first. The wrapped key may contain machine identifiers |
| 43 | // and other values that you wouldn't want to export. Additionally |
| 44 | // |UnexportableKeyProvider::FromWrappedSigningKey| should not be presented |
| 45 | // attacked-controlled input and the AEAD would serve to authenticate the |
| 46 | // wrapped key. |
| 47 | virtual std::vector<uint8_t> GetWrappedKey() const = 0; |
| 48 | |
| 49 | // SignSlowly returns a signature of |data|, or |nullopt| if an error occurs |
| 50 | // during signing. |
| 51 | // |
| 52 | // Note: this may take a second or more to run. |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 53 | virtual std::optional<std::vector<uint8_t>> SignSlowly( |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 54 | base::span<const uint8_t> data) = 0; |
| 55 | }; |
| 56 | |
| 57 | // UnexportableKeyProvider creates |UnexportableSigningKey|s. |
| 58 | class CRYPTO_EXPORT UnexportableKeyProvider { |
| 59 | public: |
| 60 | virtual ~UnexportableKeyProvider(); |
| 61 | |
| 62 | // SelectAlgorithm returns which signature algorithm from |
| 63 | // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed |
| 64 | // to |GenerateSigningKeySlowly|. |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 65 | virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 66 | base::span<const SignatureVerifier::SignatureAlgorithm> |
| 67 | acceptable_algorithms) = 0; |
| 68 | |
| 69 | // GenerateSigningKeySlowly creates a new opaque signing key in hardware. The |
| 70 | // first supported value of |acceptable_algorithms| determines the type of the |
| 71 | // key. Returns nullptr if no supported hardware exists, if no value in |
| 72 | // |acceptable_algorithms| is supported, or if there was an error creating the |
| 73 | // key. |
| 74 | // |
| 75 | // Note: this may take one or two seconds to run. |
| 76 | virtual std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly( |
| 77 | base::span<const SignatureVerifier::SignatureAlgorithm> |
| 78 | acceptable_algorithms) = 0; |
| 79 | |
| 80 | // FromWrappedSigningKey creates an |UnexportableSigningKey| from |
| 81 | // |wrapped_key|, which must have resulted from calling |GetWrappedKey| on a |
| 82 | // previous instance of |UnexportableSigningKey|. Returns nullptr if |
| 83 | // |wrapped_key| cannot be imported. |
| 84 | // |
| 85 | // Note: this may take up to a second. |
| 86 | // |
| 87 | // Note: do not call this with attacker-controlled data. The underlying |
| 88 | // interfaces to the secure hardware may not be robust. See |GetWrappedKey|. |
| 89 | virtual std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly( |
| 90 | base::span<const uint8_t> wrapped_key) = 0; |
| 91 | }; |
| 92 | |
Kristian Monsen | 0578176f4 | 2023-03-08 20:44:51 | [diff] [blame] | 93 | // This is an experimental API as it uses an unofficial Windows API. |
| 94 | // The current implementation is here to gather metrics only. It should not be |
| 95 | // used outside of metrics gathering without knowledge of crypto OWNERS. |
| 96 | // |
| 97 | // UnexportableSigningKey provides a software-backed signing oracle based in a |
| 98 | // specialized virtual machine on platforms that support it. Current support is: |
| 99 | // Windows: RSA_PKCS1_SHA256 and ECDSA_SHA256. |
| 100 | // |
| 101 | // These keys differs from UnexportableSigningKey in several ways: |
| 102 | // - They are backed not by hardware, but by a specialized limited virtual |
| 103 | // machine resistant to attacks. |
| 104 | // - The latency of operations are expected to be about 100 times less, making |
| 105 | // them much more practical in cases that would otherwise disrupt the user |
| 106 | // experience. |
| 107 | // - The keys are stored in the virtual machine by name, this namespace is |
| 108 | // shared by all applications and there is a limited number of available keys |
| 109 | // (~65k from testing). |
| 110 | // |
| 111 | // For more info see: |
| 112 | // https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard |
| 113 | class CRYPTO_EXPORT VirtualUnexportableSigningKey { |
| 114 | public: |
| 115 | virtual ~VirtualUnexportableSigningKey(); |
| 116 | |
| 117 | // Algorithm returns the algorithm of the key in this object. |
| 118 | virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0; |
| 119 | |
| 120 | // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of |
| 121 | // this object. |
| 122 | virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0; |
| 123 | |
| 124 | // GetKeyName may be used with a future instance of this code to recreate |
| 125 | // the key so long as it's running on the same computer. |
| 126 | // |
| 127 | // Note: All local applications can enumerate all keys on device and |
| 128 | // recreate them. Private keys can also be exported with the first HANDLE |
| 129 | // after creation. |
| 130 | virtual std::string GetKeyName() const = 0; |
| 131 | |
| 132 | // Sign returns a signature of |data|, or |nullopt| if an error occurs |
| 133 | // during signing. |
| 134 | // |
| 135 | // Note: this is expected to be under 10ms. |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 136 | virtual std::optional<std::vector<uint8_t>> Sign( |
Kristian Monsen | 0578176f4 | 2023-03-08 20:44:51 | [diff] [blame] | 137 | base::span<const uint8_t> data) = 0; |
| 138 | |
| 139 | // Deletes the key from storage in the virtual machine. As the virtual machine |
| 140 | // has limited storage shared by all applications it is important to delete |
| 141 | // keys no longer in use. |
Rafael Cintron | fa079eb | 2023-05-18 20:48:37 | [diff] [blame] | 142 | virtual void DeleteKey() = 0; |
Kristian Monsen | 0578176f4 | 2023-03-08 20:44:51 | [diff] [blame] | 143 | }; |
| 144 | |
| 145 | // VirtualUnexportableKeyProvider creates |VirtualUnexportableSigningKey|s. |
| 146 | class CRYPTO_EXPORT VirtualUnexportableKeyProvider { |
| 147 | public: |
| 148 | virtual ~VirtualUnexportableKeyProvider(); |
| 149 | |
| 150 | // SelectAlgorithm returns which signature algorithm from |
| 151 | // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed |
| 152 | // to |GenerateSigningKeySlowly|. |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 153 | virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( |
Kristian Monsen | 0578176f4 | 2023-03-08 20:44:51 | [diff] [blame] | 154 | base::span<const SignatureVerifier::SignatureAlgorithm> |
| 155 | acceptable_algorithms) = 0; |
| 156 | |
| 157 | // GenerateSigningKey creates a new opaque signing key in a virtual machine. |
| 158 | // The first supported value of |acceptable_algorithms| determines the type of |
| 159 | // the key. Returns nullptr if it is not supported in the operating system, |
| 160 | // if no value in |acceptable_algorithms| is supported, or if there was an |
| 161 | // error creating the key. |
| 162 | // As the namespace is shared between all applications care should be taken to |
| 163 | // use a name that will not already be used by other applications. If a new |
| 164 | // key is created with the same name as a current key the creation will fail. |
| 165 | // Do not create a key with NULL or empty string as the name. |
| 166 | // |
| 167 | // Note: This may take milliseconds to run. |
| 168 | virtual std::unique_ptr<VirtualUnexportableSigningKey> GenerateSigningKey( |
| 169 | base::span<const SignatureVerifier::SignatureAlgorithm> |
| 170 | acceptable_algorithms, |
| 171 | std::string name) = 0; |
| 172 | |
| 173 | // FromKeyName creates an |UnexportableSigningKey| from |name|, which is the |
| 174 | // name used to create the key. Returns nullptr if |name| cannot be imported. |
| 175 | // |
| 176 | // Note: This may take milliseconds to run. |
| 177 | virtual std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName( |
| 178 | std::string name) = 0; |
| 179 | }; |
| 180 | |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 181 | // GetUnexportableKeyProvider returns an |UnexportableKeyProvider| |
| 182 | // for the current platform, or nullptr if there isn't one. This can be called |
| 183 | // from any thread but, in tests, but be sequenced with |
| 184 | // |SetUnexportableSigningKeyProvider|. |
| 185 | CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider> |
| 186 | GetUnexportableKeyProvider(); |
| 187 | |
Kristian Monsen | 0578176f4 | 2023-03-08 20:44:51 | [diff] [blame] | 188 | // GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY returns a |
| 189 | // |VirtualUnexportableKeyProvider| for the current platform, or nullptr if |
| 190 | // there isn't one. This should currently only be used for metrics gathering. |
| 191 | CRYPTO_EXPORT std::unique_ptr<VirtualUnexportableKeyProvider> |
| 192 | GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY(); |
| 193 | |
Alex Ilin | 869e421 | 2023-07-17 23:22:26 | [diff] [blame] | 194 | // `GetSoftwareUnsecureUnexportableKeyProvider()` returns a mock software |
| 195 | // implementation of `UnexportableKeyProvider` that can be used on platforms |
| 196 | // that do not have a native secure implementation. |
| 197 | // This should be used for development purposes only since these keys are not |
| 198 | // backed by hardware and are not stored securely. |
| 199 | CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider> |
| 200 | GetSoftwareUnsecureUnexportableKeyProvider(); |
| 201 | |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 202 | namespace internal { |
| 203 | |
| 204 | CRYPTO_EXPORT void SetUnexportableKeyProviderForTesting( |
| 205 | std::unique_ptr<UnexportableKeyProvider> (*func)()); |
| 206 | |
| 207 | } // namespace internal |
| 208 | |
| 209 | } // namespace crypto |
| 210 | |
| 211 | #endif // CRYPTO_UNEXPORTABLE_KEY_H_ |