summaryrefslogtreecommitdiff
path: root/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.h
blob: 67ea906059d220b987413748d5a7b5512baf8710 (plain)
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
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SERVICES_NETWORK_TRUST_TOKENS_TRUST_TOKEN_REQUEST_REDEMPTION_HELPER_H_
#define SERVICES_NETWORK_TRUST_TOKENS_TRUST_TOKEN_REQUEST_REDEMPTION_HELPER_H_

#include <memory>
#include <string>

#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece_forward.h"
#include "net/log/net_log_with_source.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/trust_tokens/proto/public.pb.h"
#include "services/network/trust_tokens/suitable_trust_token_origin.h"
#include "services/network/trust_tokens/trust_token_key_commitment_getter.h"
#include "services/network/trust_tokens/trust_token_request_helper.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/origin.h"

namespace net {
class URLRequest;
}  // namespace net

namespace network {
class TrustTokenStore;

namespace mojom {
class URLResponseHead;
}  // namespace mojom

// Class TrustTokenRequestRedemptionHelper performs a single trust token
// redemption operation (https://github.com/wicg/trust-token-api): it attaches a
// single signed, unblinded token to an outgoing request, hands it to the
// token's issuer, and expects a redemption record (RR) in response. The normal
// case involves a total of two network requests: one to get an up-to-date view
// of a key set the issuer provides for verifying that it's safe to perform the
// redemption, and another to send the token to the issuer.
class TrustTokenRequestRedemptionHelper : public TrustTokenRequestHelper {
 public:
  // Class KeyPairGenerator generates a signing and verification key pair.
  // These are not used for any cryptographic operations during redemption
  // itself. Instead, a digest of the verification key goes into the redemption
  // request and, on redemption success, we store the key pair alongside the
  // Redemption Record obtained from the server; the key pair can subsequently
  // be used to sign outgoing requests as part of the Trust Tokens
  // "request signing" operation.
  class KeyPairGenerator {
   public:
    virtual ~KeyPairGenerator() = default;
    // Generates a key pair, returning true on success and false on failure (for
    // instance, the underlying cryptographic code could fail unexpectedly).
    virtual bool Generate(std::string* signing_key_out,
                          std::string* verification_key_out) = 0;
  };

  // Class Cryptographer executes the underlying cryptographic operations
  // required for redemption. The API is intended to correspond closely to the
  // BoringSSL API.
  //
  // Usage:
  //   1x Initialize; then, if it succeeds,
  //   1x BeginRedemption; then, if it succeeds,
  //   1x ConfirmRedemption
  class Cryptographer {
   public:
    virtual ~Cryptographer() = default;

    // Initializes the delegate. |issuer_configured_version| and
    // |issuer_configured_batch_size| must be the "protocol_version" and
    // "batchsize" values, from an issuer-provided key commitment result.
    //
    // Returns true on success and false if the batch size or key is
    // unacceptable or an internal error occurred in the underlying
    // cryptographic library.
    virtual bool Initialize(
        mojom::TrustTokenProtocolVersion issuer_configured_version,
        int issuer_configured_batch_size) = 0;

    // Given a trust token to redeem and parameters to encode in the redemption
    // request, returns a base64-encoded string suitable for attachment in the
    // Sec-Trust-Token header, or nullopt on error. The exact format of the
    // redemption request is currently considered an implementation detail of
    // the underlying cryptographic code.
    //
    // Some representation of each of |verification_key_to_bind| and
    // |top_level_origin| is embedded in the redemption request so that a token
    // redemption can be bound to a particular top-level origin and client-owned
    // key pair; see the design doc for more details.
    virtual absl::optional<std::string> BeginRedemption(
        TrustToken token,
        base::StringPiece verification_key_to_bind,
        const url::Origin& top_level_origin) = 0;

    // Given a base64-encoded Sec-Trust-Token redemption response header,
    // validates and extracts the redemption record (RR) contained in the
    // header. If successful, returns the RR. Otherwise, returns nullopt.
    //
    // The Trust Tokens design doc is currently the normative source for the
    // RR's format.
    virtual absl::optional<std::string> ConfirmRedemption(
        base::StringPiece response_header) = 0;
  };

  // Creates a new redemption helper.
  //
  // - |top_level_origin| is the top-level origin
  // of the request subsequently passed to Begin; |top_level_origin|'s scheme
  // must be both (1) HTTP or HTTPS and (2) "potentially trustworthy". This
  // precondition is slightly involved because there are two needs:
  //   1. HTTP or HTTPS so that the scheme serializes in a sensible manner in
  //   order to serve as a key for persisting state.
  //   2. potentially trustworthy origin to satisfy Web security requirements.
  //
  // - |refresh_policy| controls whether to attempt to overwrite the cached
  // RR stored for the request's (issuer, top-level) origin pair.
  //
  // - |token_store| will be responsible for storing underlying Trust Tokens
  // state. It must outlive this object.
  //
  // - |key_commitment_getter|, |key_pair_generator|, and
  // |cryptographer| are delegates that help execute the protocol; see
  // their class comments.
  TrustTokenRequestRedemptionHelper(
      SuitableTrustTokenOrigin top_level_origin,
      mojom::TrustTokenRefreshPolicy refresh_policy,
      TrustTokenStore* token_store,
      const TrustTokenKeyCommitmentGetter* key_commitment_getter,
      std::unique_ptr<KeyPairGenerator> key_pair_generator,
      std::unique_ptr<Cryptographer> cryptographer,
      net::NetLogWithSource net_log = net::NetLogWithSource());
  ~TrustTokenRequestRedemptionHelper() override;

  // Executes the outbound part of a Trust Tokens redemption operation,
  // interpreting |request|'s URL's origin as the token issuance origin;
  // 1. Checks preconditions (see "Returns" below); if unsuccessful, fails.
  // 2. Executes a Trust Tokens key commitment request against the issuer; if
  //    unsuccessful, fails.
  // 3. In a request header, adds a signed, unblinded token along with
  //    associated metadata provided by |cryptographer_|.
  //
  // Returns:
  // * kOk on success
  // * kResourceExhausted if the top-level origin provided to this
  //   object's constructor has already reached its number-of-issuers limit,
  //   or if the (issuer, top-level) pair has no tokens to redeem
  // * kAlreadyExists if the (issuer, top-level) pair already has a current
  //   RR and this helper was not parameterized with |kRefresh|.
  // * kFailedPrecondition if preconditions fail, including receiving a
  //   malformed or otherwise invalid key commitment record from the issuer,
  //   or if |kRefresh| was provided and the request was not initiated
  //   from an issuer context.
  //
  // |request|'s initiator, and its destination URL's origin, must be both (1)
  // HTTP or HTTPS and (2) "potentially trustworthy" in the sense of
  // network::IsOriginPotentiallyTrustworthy. (See the justification in the
  // constructor's comment.)
  void Begin(
      net::URLRequest* request,
      base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) override;

  // Performs the second half of Trust Token issuance's client side:
  // 1. Checks |response| for an issuance response header.
  // 2. If the header is present, strips it from the response and passes its
  // value to an underlying cryptographic library, which parses and validates
  // the response and splits it into a number of signed, unblinded tokens.
  //
  // If both of these steps are successful, stores the tokens in |token_store_|
  // and returns kOk. Otherwise, returns kBadResponse.
  void Finalize(
      mojom::URLResponseHead* response,
      base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) override;

  mojom::TrustTokenOperationResultPtr CollectOperationResultWithStatus(
      mojom::TrustTokenOperationStatus status) override;

 private:
  // Continuation of |Begin| after asynchronous key commitment fetching
  // concludes.
  void OnGotKeyCommitment(
      net::URLRequest* request,
      base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done,
      mojom::TrustTokenKeyCommitmentResultPtr commitment_result);

  // Helper method: searches |token_store_| for a single trust token and returns
  // it, returning nullopt if the store contains no tokens for |issuer_|.
  //
  // Warning: This does NOT remove the token from the store.
  absl::optional<TrustToken> RetrieveSingleToken();

  // |issuer_|, |top_level_origin_|, and |refresh_policy_| are parameters
  // determining the scope and control flow of the redemption operation.
  //
  // |issuer_| needs to be a nullable type because it is initialized in |Begin|,
  // but, once initialized, it will never be empty over the course of the
  // operation's execution.
  absl::optional<SuitableTrustTokenOrigin> issuer_;
  const SuitableTrustTokenOrigin top_level_origin_;
  const mojom::TrustTokenRefreshPolicy refresh_policy_;

  // |bound_signing_key_| and |bound_verification_key_| form the key pair
  // "bound" to the redemption; they are generated speculatively near the
  // beginning of redemption and committed to storage if the operation succeeds.
  std::string bound_signing_key_;
  std::string bound_verification_key_;
  // |token_verification_key_| is the token issuance verification key
  // corresponding to the token being redeemed. It's stored here speculatively
  // when beginning redemption so that it can be placed in persistent storage
  // alongside the RR if redemption succeeds.
  std::string token_verification_key_;

  TrustTokenStore* const token_store_;
  const TrustTokenKeyCommitmentGetter* const key_commitment_getter_;
  const std::unique_ptr<KeyPairGenerator> key_pair_generator_;
  const std::unique_ptr<Cryptographer> cryptographer_;
  net::NetLogWithSource net_log_;

  base::WeakPtrFactory<TrustTokenRequestRedemptionHelper> weak_factory_{this};
};
}  // namespace network

#endif  // SERVICES_NETWORK_TRUST_TOKENS_TRUST_TOKEN_REQUEST_REDEMPTION_HELPER_H_