xref: /aosp_15_r20/external/cronet/crypto/unexportable_key.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 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 #ifndef CRYPTO_UNEXPORTABLE_KEY_H_
6 #define CRYPTO_UNEXPORTABLE_KEY_H_
7 
8 #include <memory>
9 #include <optional>
10 
11 #include "build/build_config.h"
12 #include "crypto/crypto_export.h"
13 #include "crypto/signature_verifier.h"
14 
15 #if BUILDFLAG(IS_MAC)
16 #import <Security/Security.h>
17 #endif  // BUILDFLAG(IS_MAC)
18 
19 namespace crypto {
20 
21 // UnexportableSigningKey provides a hardware-backed signing oracle on platforms
22 // that support it. Current support is:
23 //   Windows: RSA_PKCS1_SHA256 via TPM 1.2+ and ECDSA_SHA256 via TPM 2.0.
24 //   macOS: ECDSA_SHA256 via the Secure Enclave.
25 //   Tests: ECDSA_SHA256 via ScopedMockUnexportableSigningKeyForTesting.
26 //
27 // See also //components/unexportable_keys for a higher-level key management
28 // API.
29 class CRYPTO_EXPORT UnexportableSigningKey {
30  public:
31   virtual ~UnexportableSigningKey();
32 
33   // Algorithm returns the algorithm of the key in this object.
34   virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0;
35 
36   // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of
37   // this object.
38   virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0;
39 
40   // GetWrappedKey returns a handle to the private key of this object. Usually,
41   // it is the private key encrypted to a key that is kept in hardware and the
42   // unencrypted private key never exists in the CPU's memory, hence the name.
43   // On Mac, this is instead a hash of the public key and the wrapped key
44   // material is stored in the Keychain.
45   //
46   // A key handle may be used with a future instance of this code to recreate
47   // the key so long as it's running on the same computer.
48   //
49   // Note: on Windows it is possible to export this wrapped key off machine, but
50   // it must be sealed with an AEAD first. The wrapped key may contain machine
51   // identifiers and other values that you wouldn't want to export. Additionally
52   // |UnexportableKeyProvider::FromWrappedSigningKey| should not be presented
53   // attacked-controlled input and the AEAD would serve to authenticate the
54   // wrapped key.
55   virtual std::vector<uint8_t> GetWrappedKey() const = 0;
56 
57   // SignSlowly returns a signature of |data|, or |nullopt| if an error occurs
58   // during signing.
59   //
60   // Note: this may take a second or more to run.
61   virtual std::optional<std::vector<uint8_t>> SignSlowly(
62       base::span<const uint8_t> data) = 0;
63 
64 #if BUILDFLAG(IS_MAC)
65   // Returns the underlying reference to a Keychain key owned by the current
66   // instance.
67   virtual SecKeyRef GetSecKeyRef() const = 0;
68 #endif  // BUILDFLAG(IS_MAC)
69 };
70 
71 // UnexportableKeyProvider creates |UnexportableSigningKey|s.
72 class CRYPTO_EXPORT UnexportableKeyProvider {
73  public:
74   virtual ~UnexportableKeyProvider();
75 
76   // Platform-specific configuration parameters for the provider.
77   struct Config {
78 #if BUILDFLAG(IS_MAC)
79     // Determines the level of user verification needed to sign with the key.
80     // https://developer.apple.com/documentation/security/secaccesscontrolcreateflags?language=objc
81     enum class AccessControl {
82       // No access control. User presence is not required to access this secret.
83       kNone,
84 
85       // Either biometry or the local account password are required to access
86       // this secret. This is equivalent to kSecAccessControlUserPresence.
87       // Note that if you set this and choose not to pass an authenticated
88       // LAContext when signing, macOS will prompt the user for biometrics and
89       // the thread will block until that resolves.
90       kUserPresence,
91     };
92 
93     // The keychain access group the key is shared with. The binary must be
94     // codesigned with the corresponding entitlement.
95     // https://developer.apple.com/documentation/bundleresources/entitlements/keychain-access-groups?language=objc
96     // This must be set to a non empty value when using unexportable keys on
97     // macOS.
98     std::string keychain_access_group;
99 
100     // An optional application tag that will be set for all keys created by this
101     // provider. If non empty, this should uniquely identify a group of related
102     // keys, and can be used to query or delete all credentials with the same
103     // tag.
104     // https://developer.apple.com/documentation/security/ksecattrapplicationtag?language=objc
105     std::string application_tag;
106 
107     // The access control set for keys created by the provider.
108     AccessControl access_control = AccessControl::kNone;
109 #endif  // BUILDFLAG(IS_MAC)
110   };
111 
112   // SelectAlgorithm returns which signature algorithm from
113   // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed
114   // to |GenerateSigningKeySlowly|.
115   virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
116       base::span<const SignatureVerifier::SignatureAlgorithm>
117           acceptable_algorithms) = 0;
118 
119   // GenerateSigningKeySlowly creates a new opaque signing key in hardware. The
120   // first supported value of |acceptable_algorithms| determines the type of the
121   // key. Returns nullptr if no supported hardware exists, if no value in
122   // |acceptable_algorithms| is supported, or if there was an error creating the
123   // key.
124   //
125   // Note: this may take one or two seconds to run.
126   virtual std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly(
127       base::span<const SignatureVerifier::SignatureAlgorithm>
128           acceptable_algorithms) = 0;
129 
130   // FromWrappedSigningKey creates an |UnexportableSigningKey| from
131   // |wrapped_key|, which must have resulted from calling |GetWrappedKey| on a
132   // previous instance of |UnexportableSigningKey|. Returns nullptr if
133   // |wrapped_key| cannot be imported.
134   //
135   // Note: this may take up to a second.
136   //
137   // Note: do not call this with attacker-controlled data. The underlying
138   // interfaces to the secure hardware may not be robust. See |GetWrappedKey|.
139   virtual std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly(
140       base::span<const uint8_t> wrapped_key) = 0;
141 
142   // Unexportable key implementations may be stateful. This is the case for
143   // macOS. |DeleteSigningKey| deletes all state associated with a given signing
144   // key on such implementations. For stateless implementations, this is a
145   // no-op.
146   // Returns true on successful deletion, false otherwise.
147   virtual bool DeleteSigningKey(base::span<const uint8_t> wrapped_key) = 0;
148 };
149 
150 // This is an experimental API as it uses an unofficial Windows API.
151 // The current implementation is here to gather metrics only. It should not be
152 // used outside of metrics gathering without knowledge of crypto OWNERS.
153 //
154 // UnexportableSigningKey provides a software-backed signing oracle based in a
155 // specialized virtual machine on platforms that support it. Current support is:
156 //   Windows: RSA_PKCS1_SHA256 and ECDSA_SHA256.
157 //
158 // These keys differs from UnexportableSigningKey in several ways:
159 // - They are backed not by hardware, but by a specialized limited virtual
160 // machine resistant to attacks.
161 // - The latency of operations are expected to be about 100 times less, making
162 // them much more practical in cases that would otherwise disrupt the user
163 // experience.
164 // - The keys are stored in the virtual machine by name, this namespace is
165 // shared by all applications and there is a limited number of available keys
166 // (~65k from testing).
167 //
168 // For more info see:
169 // https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard
170 class CRYPTO_EXPORT VirtualUnexportableSigningKey {
171  public:
172   virtual ~VirtualUnexportableSigningKey();
173 
174   // Algorithm returns the algorithm of the key in this object.
175   virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0;
176 
177   // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of
178   // this object.
179   virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0;
180 
181   // GetKeyName may be used with a future instance of this code to recreate
182   // the key so long as it's running on the same computer.
183   //
184   // Note: All local applications can enumerate all keys on device and
185   // recreate them. Private keys can also be exported with the first HANDLE
186   // after creation.
187   virtual std::string GetKeyName() const = 0;
188 
189   // Sign returns a signature of |data|, or |nullopt| if an error occurs
190   // during signing.
191   //
192   // Note: this is expected to be under 10ms.
193   virtual std::optional<std::vector<uint8_t>> Sign(
194       base::span<const uint8_t> data) = 0;
195 
196   // Deletes the key from storage in the virtual machine. As the virtual machine
197   // has limited storage shared by all applications it is important to delete
198   // keys no longer in use.
199   virtual void DeleteKey() = 0;
200 };
201 
202 // VirtualUnexportableKeyProvider creates |VirtualUnexportableSigningKey|s.
203 class CRYPTO_EXPORT VirtualUnexportableKeyProvider {
204  public:
205   virtual ~VirtualUnexportableKeyProvider();
206 
207   // SelectAlgorithm returns which signature algorithm from
208   // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed
209   // to |GenerateSigningKeySlowly|.
210   virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
211       base::span<const SignatureVerifier::SignatureAlgorithm>
212           acceptable_algorithms) = 0;
213 
214   // GenerateSigningKey creates a new opaque signing key in a virtual machine.
215   // The first supported value of |acceptable_algorithms| determines the type of
216   // the key. Returns nullptr if it is not supported in the operating system,
217   // if no value in |acceptable_algorithms| is supported, or if there was an
218   // error creating the key.
219   // As the namespace is shared between all applications care should be taken to
220   // use a name that will not already be used by other applications. If a new
221   // key is created with the same name as a current key the creation will fail.
222   // Do not create a key with NULL or empty string as the name.
223   //
224   // Note: This may take milliseconds to run.
225   virtual std::unique_ptr<VirtualUnexportableSigningKey> GenerateSigningKey(
226       base::span<const SignatureVerifier::SignatureAlgorithm>
227           acceptable_algorithms,
228       std::string name) = 0;
229 
230   // FromKeyName creates an |UnexportableSigningKey| from |name|, which is the
231   // name used to create the key. Returns nullptr if |name| cannot be imported.
232   //
233   // Note: This may take milliseconds to run.
234   virtual std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName(
235       std::string name) = 0;
236 };
237 
238 // GetUnexportableKeyProvider returns an |UnexportableKeyProvider|
239 // for the current platform, or nullptr if there isn't one. This can be called
240 // from any thread but, in tests, but be sequenced with
241 // |SetUnexportableSigningKeyProvider|.
242 CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider>
243 GetUnexportableKeyProvider(UnexportableKeyProvider::Config config);
244 
245 // GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY returns a
246 // |VirtualUnexportableKeyProvider| for the current platform, or nullptr if
247 // there isn't one. This should currently only be used for metrics gathering.
248 CRYPTO_EXPORT std::unique_ptr<VirtualUnexportableKeyProvider>
249 GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY();
250 
251 // `GetSoftwareUnsecureUnexportableKeyProvider()` returns a mock software
252 // implementation of `UnexportableKeyProvider` that can be used on platforms
253 // that do not have a native secure implementation.
254 // This should be used for development purposes only since these keys are not
255 // backed by hardware and are not stored securely.
256 CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider>
257 GetSoftwareUnsecureUnexportableKeyProvider();
258 
259 namespace internal {
260 
261 CRYPTO_EXPORT void SetUnexportableKeyProviderForTesting(
262     std::unique_ptr<UnexportableKeyProvider> (*func)());
263 
264 }  // namespace internal
265 
266 }  // namespace crypto
267 
268 #endif  // CRYPTO_UNEXPORTABLE_KEY_H_
269