• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // Returns true if the underlying key is stored in "hardware". Something like
65   // ARM TrustZone would count as hardware for these purposes. Ideally all
66   // implementations of this class would return true here, because software
67   // implementations aren't really "unexportable", but a software implementation
68   // does exist.
69   virtual bool IsHardwareBacked() const;
70 
71 #if BUILDFLAG(IS_MAC)
72   // Returns the underlying reference to a Keychain key owned by the current
73   // instance.
74   virtual SecKeyRef GetSecKeyRef() const = 0;
75 #endif  // BUILDFLAG(IS_MAC)
76 };
77 
78 // UnexportableKeyProvider creates |UnexportableSigningKey|s.
79 class CRYPTO_EXPORT UnexportableKeyProvider {
80  public:
81   virtual ~UnexportableKeyProvider();
82 
83   // Platform-specific configuration parameters for the provider.
84   struct Config {
85 #if BUILDFLAG(IS_MAC)
86     // Determines the level of user verification needed to sign with the key.
87     // https://developer.apple.com/documentation/security/secaccesscontrolcreateflags?language=objc
88     enum class AccessControl {
89       // No access control. User presence is not required to access this secret.
90       kNone,
91 
92       // Either biometry or the local account password are required to access
93       // this secret. This is equivalent to kSecAccessControlUserPresence.
94       // Note that if you set this and choose not to pass an authenticated
95       // LAContext when signing, macOS will prompt the user for biometrics and
96       // the thread will block until that resolves.
97       kUserPresence,
98     };
99 
100     // The keychain access group the key is shared with. The binary must be
101     // codesigned with the corresponding entitlement.
102     // https://developer.apple.com/documentation/bundleresources/entitlements/keychain-access-groups?language=objc
103     // This must be set to a non empty value when using unexportable keys on
104     // macOS.
105     std::string keychain_access_group;
106 
107     // An optional application tag that will be set for all keys created by this
108     // provider. If non empty, this should uniquely identify a group of related
109     // keys, and can be used to query or delete all credentials with the same
110     // tag.
111     // https://developer.apple.com/documentation/security/ksecattrapplicationtag?language=objc
112     std::string application_tag;
113 
114     // The access control set for keys created by the provider.
115     AccessControl access_control = AccessControl::kNone;
116 #endif  // BUILDFLAG(IS_MAC)
117   };
118 
119   // SelectAlgorithm returns which signature algorithm from
120   // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed
121   // to |GenerateSigningKeySlowly|.
122   virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
123       base::span<const SignatureVerifier::SignatureAlgorithm>
124           acceptable_algorithms) = 0;
125 
126   // GenerateSigningKeySlowly creates a new opaque signing key in hardware. The
127   // first supported value of |acceptable_algorithms| determines the type of the
128   // key. Returns nullptr if no supported hardware exists, if no value in
129   // |acceptable_algorithms| is supported, or if there was an error creating the
130   // key.
131   //
132   // Note: this may take one or two seconds to run.
133   virtual std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly(
134       base::span<const SignatureVerifier::SignatureAlgorithm>
135           acceptable_algorithms) = 0;
136 
137   // FromWrappedSigningKey creates an |UnexportableSigningKey| from
138   // |wrapped_key|, which must have resulted from calling |GetWrappedKey| on a
139   // previous instance of |UnexportableSigningKey|. Returns nullptr if
140   // |wrapped_key| cannot be imported.
141   //
142   // Note: this may take up to a second.
143   //
144   // Note: do not call this with attacker-controlled data. The underlying
145   // interfaces to the secure hardware may not be robust. See |GetWrappedKey|.
146   virtual std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly(
147       base::span<const uint8_t> wrapped_key) = 0;
148 
149   // Unexportable key implementations may be stateful. This is the case for
150   // macOS. |DeleteSigningKey| deletes all state associated with a given signing
151   // key on such implementations. For stateless implementations, this is a
152   // no-op.
153   // Returns true on successful deletion, false otherwise.
154   // This can sometimes block, and therefore must not be called from the UI
155   // thread.
156   virtual bool DeleteSigningKeySlowly(
157       base::span<const uint8_t> wrapped_key) = 0;
158 };
159 
160 // This is an experimental API as it uses an unofficial Windows API.
161 // The current implementation is here to gather metrics only. It should not be
162 // used outside of metrics gathering without knowledge of crypto OWNERS.
163 //
164 // UnexportableSigningKey provides a software-backed signing oracle based in a
165 // specialized virtual machine on platforms that support it. Current support is:
166 //   Windows: RSA_PKCS1_SHA256 and ECDSA_SHA256.
167 //
168 // These keys differs from UnexportableSigningKey in several ways:
169 // - They are backed not by hardware, but by a specialized limited virtual
170 // machine resistant to attacks.
171 // - The latency of operations are expected to be about 100 times less, making
172 // them much more practical in cases that would otherwise disrupt the user
173 // experience.
174 // - The keys are stored in the virtual machine by name, this namespace is
175 // shared by all applications and there is a limited number of available keys
176 // (~65k from testing).
177 //
178 // For more info see:
179 // https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard
180 class CRYPTO_EXPORT VirtualUnexportableSigningKey {
181  public:
182   virtual ~VirtualUnexportableSigningKey();
183 
184   // Algorithm returns the algorithm of the key in this object.
185   virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0;
186 
187   // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of
188   // this object.
189   virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0;
190 
191   // GetKeyName may be used with a future instance of this code to recreate
192   // the key so long as it's running on the same computer.
193   //
194   // Note: All local applications can enumerate all keys on device and
195   // recreate them. Private keys can also be exported with the first HANDLE
196   // after creation.
197   virtual std::string GetKeyName() const = 0;
198 
199   // Sign returns a signature of |data|, or |nullopt| if an error occurs
200   // during signing.
201   //
202   // Note: this is expected to be under 10ms.
203   virtual std::optional<std::vector<uint8_t>> Sign(
204       base::span<const uint8_t> data) = 0;
205 
206   // Deletes the key from storage in the virtual machine. As the virtual machine
207   // has limited storage shared by all applications it is important to delete
208   // keys no longer in use.
209   virtual void DeleteKey() = 0;
210 };
211 
212 // VirtualUnexportableKeyProvider creates |VirtualUnexportableSigningKey|s.
213 class CRYPTO_EXPORT VirtualUnexportableKeyProvider {
214  public:
215   virtual ~VirtualUnexportableKeyProvider();
216 
217   // SelectAlgorithm returns which signature algorithm from
218   // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed
219   // to |GenerateSigningKeySlowly|.
220   virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
221       base::span<const SignatureVerifier::SignatureAlgorithm>
222           acceptable_algorithms) = 0;
223 
224   // GenerateSigningKey creates a new opaque signing key in a virtual machine.
225   // The first supported value of |acceptable_algorithms| determines the type of
226   // the key. Returns nullptr if it is not supported in the operating system,
227   // if no value in |acceptable_algorithms| is supported, or if there was an
228   // error creating the key.
229   // As the namespace is shared between all applications care should be taken to
230   // use a name that will not already be used by other applications. If a new
231   // key is created with the same name as a current key the creation will fail.
232   // Do not create a key with NULL or empty string as the name.
233   //
234   // Note: This may take milliseconds to run.
235   virtual std::unique_ptr<VirtualUnexportableSigningKey> GenerateSigningKey(
236       base::span<const SignatureVerifier::SignatureAlgorithm>
237           acceptable_algorithms,
238       std::string name) = 0;
239 
240   // FromKeyName creates an |UnexportableSigningKey| from |name|, which is the
241   // name used to create the key. Returns nullptr if |name| cannot be imported.
242   //
243   // Note: This may take milliseconds to run.
244   virtual std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName(
245       std::string name) = 0;
246 };
247 
248 // GetUnexportableKeyProvider returns an |UnexportableKeyProvider|
249 // for the current platform, or nullptr if there isn't one. This can be called
250 // from any thread but, in tests, but be sequenced with
251 // |SetUnexportableSigningKeyProvider|.
252 CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider>
253 GetUnexportableKeyProvider(UnexportableKeyProvider::Config config);
254 
255 // GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY returns a
256 // |VirtualUnexportableKeyProvider| for the current platform, or nullptr if
257 // there isn't one. This should currently only be used for metrics gathering.
258 CRYPTO_EXPORT std::unique_ptr<VirtualUnexportableKeyProvider>
259 GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY();
260 
261 // `GetSoftwareUnsecureUnexportableKeyProvider()` returns a mock software
262 // implementation of `UnexportableKeyProvider` that can be used on platforms
263 // that do not have a native secure implementation.
264 // This should be used for development purposes only since these keys are not
265 // backed by hardware and are not stored securely.
266 CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider>
267 GetSoftwareUnsecureUnexportableKeyProvider();
268 
269 namespace internal {
270 
271 CRYPTO_EXPORT bool HasScopedUnexportableKeyProvider();
272 
273 CRYPTO_EXPORT void SetUnexportableKeyProviderForTesting(
274     std::unique_ptr<UnexportableKeyProvider> (*func)());
275 
276 }  // namespace internal
277 
278 }  // namespace crypto
279 
280 #endif  // CRYPTO_UNEXPORTABLE_KEY_H_
281