File: passkey_browser_binder.h

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (233 lines) | stat: -rw-r--r-- 9,964 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_PAYMENTS_CONTENT_BROWSER_BINDING_PASSKEY_BROWSER_BINDER_H_
#define COMPONENTS_PAYMENTS_CONTENT_BROWSER_BINDING_PASSKEY_BROWSER_BINDER_H_

#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "components/payments/content/browser_binding/browser_bound_key_store.h"
#include "components/payments/content/payment_manifest_web_data_service.h"
#include "components/webdata/common/web_data_service_consumer.h"

namespace payments {

class BrowserBoundKey;
struct BrowserBoundKeyMetadata;

// Facilitates binding browser bound keys to passkeys.
//
// Browser bound keys (BBK) are temporarily not bound to passkeys while creating
// the passkey. The BBK needs to be created before the passkey since the BBK's
// public key will be set in the client data json and itself is an input to
// creating the passkey. Once the passkey has been created then its credential
// id becomes known and the BBK can be bound to the passkey.
//
// Example passkey creation usage:
//
// auto binder = PasskeyBrowserBinder(
//     std::move(key_store), payment_manifest_web_data_service);
//
// // Create an unbound key.
// PasskeyBrowserBinder::UnboundKey unbound_key =
//     binder.CreateUnboundKey(std::move(allowed_algorithms));
//
// // Get the public key and include it in some authenticator creation request.
// auto passkey = CreatePasskey(...,
//     unbound_key.Get()->GetPublicKeyAsCoseKey());
//
// // Finally bind the key given the passkey's credential identifier.
// binder.BindKey(
//     std::move(unbound_key), passkey.GetCredentialId(), relying_party_id);
//
//
// Example retrieval usage:
//
// auto passkey = ...; // After retrieving the passkey.
//
// binder_ = std::make_unique<PasskeyBrowserBinder>(
//     std::move(key_store), payment_manifest_web_data_service);
//
// binder_->GetOrCreateBoundKeyForPasskey(
//     passkey.GetCredentialId(),
//     passkey.GetRelyingPartyId(),
//     allowed_algorithms,
//     [](std::unique_ptr<BrowserBoundKey> key) {
//       if (!key) {
//         // Handle the browser bound key could not be found nor created.
//       }
//       // Use the browser bound key to sign something.
//       key->Sign(client_data_json);
//     });
//
// This class depends on an implementation of BrowserBoundKeyStore and the
// payment manifest web data service for storing the BBK and passkey
// identifiers.
class PasskeyBrowserBinder : public WebDataServiceConsumer {
 public:
  // `key_store` and `web_data_service` are required and must be set.
  PasskeyBrowserBinder(
      scoped_refptr<BrowserBoundKeyStore> key_store,
      scoped_refptr<PaymentManifestWebDataService> web_data_service);
  PasskeyBrowserBinder(const PasskeyBrowserBinder&) = delete;
  PasskeyBrowserBinder& operator=(const PasskeyBrowserBinder&) = delete;
  ~PasskeyBrowserBinder() override;

  // Represents a browser bound key that has not yet been associated. If
  // BindKey() is not called when this class goes out of scope, the wrapped
  // BrowserBoundKey will be deleted.
  class UnboundKey {
   public:
    // Creates an UnboundKey. `browser_bound_key_id` will be used to delete the
    // key from `key_store` when UnboundKey goes out of scope without having
    // been bound. UnboundKey takes ownership of `browser_bound_key` which can
    // be accessed via Get() while the key has not yet been bound.
    UnboundKey(std::vector<uint8_t> browser_bound_key_id,
               std::unique_ptr<BrowserBoundKey> browser_bound_key,
               scoped_refptr<BrowserBoundKeyStore> key_store);
    UnboundKey(const UnboundKey&) = delete;
    UnboundKey& operator=(const UnboundKey&) = delete;
    UnboundKey(UnboundKey&&);
    UnboundKey& operator=(UnboundKey&&);
    ~UnboundKey();

    // Returns a reference to the underlying browser bound key, this is the only
    // way by which the browser bound key can be accessed before having been
    // associated.
    BrowserBoundKey& Get();

   private:
    friend PasskeyBrowserBinder;

    // Marks the BrowserBoundKey as bound. After calling, destruction of this
    // UnboundKey will not delete the browser bound key.
    //
    // Do not call other methods on UnboundKey after calling
    // MarkKeyBoundAndReset().
    void MarkKeyBoundAndReset();

    // The browser bound key id. This is passed to the key store if the BBK
    // needs to be deleted.
    std::vector<uint8_t> browser_bound_key_id_;

    // An owned reference to the browser bound key. This member may be `nullptr`
    // in some PasskeyBrowserBinder internal usages of UnboundKey.
    std::unique_ptr<BrowserBoundKey> browser_bound_key_;

    // A reference to the key store. This key store is invoked if the browser
    // bound key needs to be deleted.
    scoped_refptr<BrowserBoundKeyStore> key_store_;
  };

  // Creates a browser bound key that is not yet associated to a passkey. The
  // UnboundKey should be bound using BindKey() after the credential id has
  // been created.
  std::optional<UnboundKey> CreateUnboundKey(
      const BrowserBoundKeyStore::CredentialInfoList& allowed_algorithms);

  // Gets a browser bound key for the given `credential_id` and `relying_party`
  // only if a browser bound key already exists for the credential.
  void GetBoundKeyForPasskey(
      std::vector<uint8_t> credential_id,
      std::string relying_party,
      base::OnceCallback<void(std::unique_ptr<BrowserBoundKey>)> callback);

  // Gets or creates a browser bound key for the given `credential_id`,
  // `relying_party` and `allowed_algorithms` returning the browser bound key
  // by running `callback`.
  void GetOrCreateBoundKeyForPasskey(
      std::vector<uint8_t> credential_id,
      std::string relying_party,
      const BrowserBoundKeyStore::CredentialInfoList& allowed_algorithms,
      base::OnceCallback<void(bool is_new, std::unique_ptr<BrowserBoundKey>)>
          callback);

  // Stores the association of the `key` to a `credential_id` and
  // `relying_party`. The UnboundKey must be std::moved and is thus
  // intentionally no longer available to the caller. If the BrowserBoundKey is
  // needed thereafter, then retrieve it using BoundKeyForPasskey().
  void BindKey(UnboundKey key,
               const std::vector<uint8_t>& credential_id,
               const std::string& relying_party);

  // Deletes all unknown browser bound keys, querying using the provided
  // `get_matching_credential_ids_callback` to find credentials matching each
  // relying party in the BBK storage. The
  // `get_matching_credential_ids_callback` must be valid until `callback` is
  // invoked. `callback` may hold and release the reference to this
  // PasskeyBrowserBinder object (DeleteAllUnknownBrowserBoundKeys will run
  // `callback` as its last action).
  void DeleteAllUnknownBrowserBoundKeys(
      base::RepeatingCallback<
          void(const std::string& relying_party_id,
               const std::vector<std::vector<uint8_t>>& credential_ids,
               bool require_third_party_payment_bit_set,
               base::OnceCallback<void(std::vector<std::vector<uint8_t>>)>)>
          get_matching_credential_ids_callback,
      base::OnceClosure callback);

  // WebDataServiceConsumer:
  void OnWebDataServiceRequestDone(
      WebDataServiceBase::Handle h,
      std::unique_ptr<WDTypedResult> result) override;

  // Injects the random bytes function for testing.
  void SetRandomBytesAsVectorCallbackForTesting(
      base::RepeatingCallback<std::vector<uint8_t>(size_t length)>);

  BrowserBoundKeyStore* GetBrowserBoundKeyStoreForTesting();
  PaymentManifestWebDataService* GetWebDataServiceForTesting();

 private:
  // Called after retrieving the possibly empty `existing_browser_bound_key_id`
  // to retrieve the matching browser bound key. Runs `callback` with nullptr if
  // there is no matching browser bound key.
  void GetBrowserBoundKey(
      base::OnceCallback<void(std::unique_ptr<BrowserBoundKey>)> callback,
      std::vector<uint8_t> existing_browser_bound_key_id);

  // Called after retrieving the possibly empty `existing_browser_bound_key_id`
  // to retrieve the matching browser bound key. Otherwise creates a new browser
  // bound key and saves its id. The browser bound key is returned by running
  // `callback` with a boolean indicating whether the browser bound key is new.
  void GetOrCreateBrowserBoundKey(
      std::vector<uint8_t> credential_id,
      std::string relying_party,
      BrowserBoundKeyStore::CredentialInfoList allowed_algorithms,
      base::OnceCallback<void(bool is_new, std::unique_ptr<BrowserBoundKey>)>
          callback,
      std::vector<uint8_t> existing_browser_bound_key_id);

  // Called after internal authenticator was called to find stale BBKs.
  // `callback` is Run once the database operation completes.
  void DeleteBrowserBoundKeys(
      base::OnceClosure callback,
      std::vector<BrowserBoundKeyMetadata> stale_bbk_metas);

  // Records a creation or retrieval metric.
  void RecordCreationOrRetrieval(bool is_creation, bool did_succeed);

  scoped_refptr<BrowserBoundKeyStore> key_store_;
  scoped_refptr<PaymentManifestWebDataService> web_data_service_;
  std::map<WebDataServiceBase::Handle, base::OnceCallback<void(bool)>>
      set_browser_bound_key_handlers_;
  std::map<WebDataServiceBase::Handle,
           base::OnceCallback<void(std::vector<uint8_t>)>>
      get_browser_bound_key_handlers_;
  base::RepeatingCallback<std::vector<uint8_t>(size_t)>
      random_bytes_as_vector_callback_;
  base::WeakPtrFactory<PasskeyBrowserBinder> weak_ptr_factory_{this};
};

}  // namespace payments

#endif  // COMPONENTS_PAYMENTS_CONTENT_BROWSER_BINDING_PASSKEY_BROWSER_BINDER_H_