• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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_USER_VERIFYING_KEY_H_
6 #define CRYPTO_USER_VERIFYING_KEY_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <variant>
12 #include <vector>
13 
14 #include "base/containers/span.h"
15 #include "base/functional/callback.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/types/expected.h"
18 #include "build/build_config.h"
19 #include "crypto/crypto_export.h"
20 #include "crypto/scoped_lacontext.h"
21 #include "crypto/signature_verifier.h"
22 #include "crypto/unexportable_key.h"
23 
24 namespace crypto {
25 
26 typedef std::string UserVerifyingKeyLabel;
27 
28 // Error values supplied to the callbacks for creating and retrieving
29 // user-verifying keys, upon failure.
30 enum class UserVerifyingKeyCreationError {
31   kPlatformApiError = 0,
32   kDuplicateCredential = 1,
33   kNotFound = 2,
34   kUserCancellation = 3,
35   kNoMatchingAlgorithm = 4,
36   kUnknownError = 5,
37 };
38 
39 // Error values supplied to the callback for signing with a user-verifying key,
40 // upon failure.
41 enum class UserVerifyingKeySigningError {
42   kPlatformApiError = 0,
43   kUserCancellation = 1,
44   kUnknownError = 2,
45 };
46 
47 // UserVerifyingSigningKey is a hardware-backed key that triggers a user
48 // verification by the platform before a signature will be provided.
49 //
50 // Notes:
51 // - This is currently only supported on Windows and Mac.
52 // - This does not export a wrapped key because the Windows implementation uses
53 //   the WinRT KeyCredentialManager which addresses stored keys by name.
54 // - The interface for this class will likely need to be generalized as support
55 //   for other platforms is added.
56 class CRYPTO_EXPORT UserVerifyingSigningKey {
57  public:
58   virtual ~UserVerifyingSigningKey();
59   using UserVerifyingKeySignatureCallback = base::OnceCallback<void(
60       base::expected<std::vector<uint8_t>, UserVerifyingKeySigningError>)>;
61 
62   // Sign invokes |callback| to provide a signature of |data|, or |nullopt| if
63   // an error occurs during signing.
64   virtual void Sign(base::span<const uint8_t> data,
65                     UserVerifyingKeySignatureCallback callback) = 0;
66 
67   // Provides the SPKI public key.
68   virtual std::vector<uint8_t> GetPublicKey() const = 0;
69 
70   // Get a reference to the label used to create or retrieve this key.
71   virtual const UserVerifyingKeyLabel& GetKeyLabel() const = 0;
72 
73   // Returns true if the underlying key is stored in "hardware". Something like
74   // ARM TrustZone would count as hardware for these purposes.
75   virtual bool IsHardwareBacked() const;
76 };
77 
78 // Reference-counted wrapper for UserVeriyingSigningKey.
79 class CRYPTO_EXPORT RefCountedUserVerifyingSigningKey
80     : public base::RefCountedThreadSafe<RefCountedUserVerifyingSigningKey> {
81  public:
82   explicit RefCountedUserVerifyingSigningKey(
83       std::unique_ptr<crypto::UserVerifyingSigningKey> key);
84 
85   RefCountedUserVerifyingSigningKey(const RefCountedUserVerifyingSigningKey&) =
86       delete;
87   RefCountedUserVerifyingSigningKey& operator=(
88       const RefCountedUserVerifyingSigningKey&) = delete;
89 
key()90   crypto::UserVerifyingSigningKey& key() const { return *key_; }
91 
92  private:
93   friend class base::RefCountedThreadSafe<RefCountedUserVerifyingSigningKey>;
94   ~RefCountedUserVerifyingSigningKey();
95 
96   const std::unique_ptr<crypto::UserVerifyingSigningKey> key_;
97 };
98 
99 // UserVerifyingKeyProvider creates |UserVerifyingSigningKey|s.
100 class CRYPTO_EXPORT UserVerifyingKeyProvider {
101  public:
102   struct CRYPTO_EXPORT Config {
103     Config();
104     Config(const Config& config) = delete;
105     Config& operator=(const Config& config) = delete;
106     Config(Config&& config);
107     Config& operator=(Config&& config);
108     ~Config();
109 
110 #if BUILDFLAG(IS_MAC)
111     // The keychain access group the key is shared with. The binary must be
112     // codesigned with the corresponding entitlement.
113     // https://developer.apple.com/documentation/bundleresources/entitlements/keychain-access-groups?language=objc
114     // This must be set to a non empty value when using user verifying keys on
115     // macOS.
116     std::string keychain_access_group;
117 
118     // Optional LAContext to be used when retrieving and storing keys. Passing
119     // an authenticated LAContext lets you call UserVerifyingSigningKey::Sign()
120     // without triggering a macOS local authentication prompt.
121     std::optional<ScopedLAContext> lacontext;
122 #endif  // BUILDFLAG(IS_MAC)
123   };
124 
125   using UserVerifyingKeyCreationCallback = base::OnceCallback<void(
126       base::expected<std::unique_ptr<UserVerifyingSigningKey>,
127                      UserVerifyingKeyCreationError>)>;
128 
129   virtual ~UserVerifyingKeyProvider();
130 
131   // Similar to |GenerateSigningKeySlowly| but the resulting signing key can
132   // only be used with a local user authentication by the platform. This can be
133   // called from any thread as the work is done asynchronously on a
134   // high-priority thread when the underlying platform is slow.
135   // Invokes |callback| with the resulting key, or nullptr on error.
136   virtual void GenerateUserVerifyingSigningKey(
137       base::span<const SignatureVerifier::SignatureAlgorithm>
138           acceptable_algorithms,
139       UserVerifyingKeyCreationCallback callback) = 0;
140 
141   // Similar to |FromWrappedSigningKey| but uses a wrapped key that was
142   // generated from |GenerateUserVerifyingSigningKey|. This can be called from
143   // any thread as the work is done asynchronously on a high-priority thread
144   // when the underlying platform is slow.
145   // Invokes |callback| with the resulting key, or nullptr on error.
146   virtual void GetUserVerifyingSigningKey(
147       UserVerifyingKeyLabel key_label,
148       UserVerifyingKeyCreationCallback callback) = 0;
149 
150   // Deletes a user verifying signing key. Work is be done asynchronously on a
151   // low-priority thread when the underlying platform is slow.
152   // Invokes |callback| with `true` if the key was found and deleted, `false`
153   // otherwise.
154   virtual void DeleteUserVerifyingKey(
155       UserVerifyingKeyLabel key_label,
156       base::OnceCallback<void(bool)> callback) = 0;
157 };
158 
159 // GetUserVerifyingKeyProvider returns |UserVerifyingKeyProvider| for the
160 // current platform, or nullptr if this is not implemented on the current
161 // platform.
162 // Note that this will return non null if keys are supported but not available,
163 // i.e. if |AreUserVerifyingKeysSupported| returns false. In that case,
164 // operations would fail.
165 CRYPTO_EXPORT std::unique_ptr<UserVerifyingKeyProvider>
166 GetUserVerifyingKeyProvider(UserVerifyingKeyProvider::Config config);
167 
168 // Invokes the callback with true if UV keys can be used on the current
169 // platform, and false otherwise. `callback` can be invoked synchronously or
170 // asynchronously.
171 CRYPTO_EXPORT void AreUserVerifyingKeysSupported(
172     UserVerifyingKeyProvider::Config config,
173     base::OnceCallback<void(bool)> callback);
174 
175 namespace internal {
176 
177 CRYPTO_EXPORT void SetUserVerifyingKeyProviderForTesting(
178     std::unique_ptr<UserVerifyingKeyProvider> (*func)());
179 
180 }  // namespace internal
181 
182 }  // namespace crypto
183 
184 #endif  // CRYPTO_USER_VERIFYING_KEY_H_
185