blob: 11a53657123ede958c822308bade3b410bb05de0 [file] [log] [blame]
// 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/optional.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 "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 signed redemption record (SRR) 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
// Signed 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_batch_size| must be the
// "batchsize" value, and |signed_Redemption_record_verification_key| the
// "srrkey" value, 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(
int issuer_configured_batch_size,
base::StringPiece signed_redemption_record_verification_key) = 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 base::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 signed redemption record (SRR) contained in
// the header. If successful, returns the SRR. Otherwise, returns nullopt.
//
// The Trust Tokens design doc is currently the normative source for the
// SRR's format.
virtual base::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
// SRR stored for the request's (issuer, top-level) origin pair. This is
// permitted to have value |kRefresh| only when the redemption
// request's initiator equals its issuer origin.
//
// - |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
// SRR 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;
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.
base::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.
base::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 SRR 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_