1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 SERVICES_NETWORK_TRUST_TOKENS_TRUST_TOKEN_KEY_COMMITMENT_CONTROLLER_H_
6 #define SERVICES_NETWORK_TRUST_TOKENS_TRUST_TOKEN_KEY_COMMITMENT_CONTROLLER_H_
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "base/callback.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/strings/string_piece_forward.h"
14 #include "services/network/public/cpp/simple_url_loader.h"
15 #include "services/network/public/mojom/trust_tokens.mojom-forward.h"
16 #include "url/gurl.h"
17 
18 namespace mojom {
19 class URLLoaderFactory;
20 class URLResponseHead;
21 }  // namespace mojom
22 
23 namespace net {
24 struct NetworkTrafficAnnotationTag;
25 struct RedirectInfo;
26 class URLRequest;
27 }  // namespace net
28 
29 namespace network {
30 
31 namespace internal {
32 
33 // Creates a key commitment request for the given issuance
34 // or redemption request:
35 // 1. sets the LOAD_BYPASS_CACHE and LOAD_DISABLE_CACHE flags,
36 // so that the result doesn't check the cache and isn't cached itself
37 // 2. sets the URL to kTrustTokenKeyCommitmentWellKnownPath, resolved
38 // relative to the issuance or redemption origin
39 // 3. sets the key commitment request to be uncredentialed
40 // 4. copies |request|'s initiator to the key commitment request
41 // 5. sets the key commitment request's Origin header to equal |request|'s
42 // top-level origin. (This is so servers can make a decision about whether to
43 // reject issuance or redemption early, by making a general decision about
44 // whether they want to issue/redeem on the provided top-level origin.)
45 std::unique_ptr<ResourceRequest> CreateTrustTokenKeyCommitmentRequest(
46     const net::URLRequest& request,
47     const url::Origin& top_level_origin);
48 
49 }  // namespace internal
50 
51 // TrustTokenKeyCommitmentController executes a single Trust Tokens key
52 // commitment request.
53 //
54 // This is an uncredentialed request to the above .well-known path
55 // relative to the origin of the Trust Tokens issuer involved in an issuance or
56 // redemption's origin; the request expects a key commitment response of the
57 // format defined in the Privacy Pass draft spec:
58 // https://github.com/alxdavids/draft-privacy-pass/blob/master/draft-privacy-pass.md.
59 //
60 // Lifetime: These are expected to be constructed when the client
61 // wishes to execute a request and destroyed immediately after the client
62 // receives its result.
63 class TrustTokenKeyCommitmentController final {
64  public:
65   // Class Parser parses HTTP response bodies obtained from key commitment
66   // registry queries.
67   class Parser {
68    public:
69     virtual ~Parser() = default;
70     virtual mojom::TrustTokenKeyCommitmentResultPtr Parse(
71         base::StringPiece response_body) = 0;
72   };
73 
74   // Constructor. Immediately starts a request:
75   // 1. builds a key commitment request using metadata from |request| (along
76   // with |top_level_origin|, which must be |request|'s initiating top level
77   // frame's origin);
78   // 2. uses |loader_factory| to send the key commitment request to
79   // |kTrustTokenKeyCommitmentWellKnownPath|, resolved relative to |request|'s
80   // origin;
81   // 3. uses |parser| to parse the result;
82   // 4. on completion or error, calls |completion_callback| with an error code
83   // and, if successful, a result.
84   struct Status {
85     enum class Value {
86       // There was an error parsing the key commitment endpoint's response. In
87       // particular, this occurs if servers deliberately return an empty or
88       // malformed response to short-circuit issuance or redemption.
89       kCouldntParse,
90       // The key commitment endpoint responded with a redirect, which is not
91       // permitted.
92       kGotRedirected,
93       // Success.
94       kOk,
95       // Connection error (|net_error| contains the specific error code).
96       kNetworkError,
97     } value;
98     int net_error;
99   };
100   TrustTokenKeyCommitmentController(
101       base::OnceCallback<void(Status status,
102                               mojom::TrustTokenKeyCommitmentResultPtr result)>
103           completion_callback,
104       const net::URLRequest& request,
105       const url::Origin& top_level_origin,
106       const net::NetworkTrafficAnnotationTag& traffic_annotation,
107       mojom::URLLoaderFactory* loader_factory,
108       std::unique_ptr<Parser> parser);
109 
110   TrustTokenKeyCommitmentController(const TrustTokenKeyCommitmentController&) =
111       delete;
112   TrustTokenKeyCommitmentController& operator=(
113       const TrustTokenKeyCommitmentController&) = delete;
114 
115   ~TrustTokenKeyCommitmentController();
116 
117  private:
118   void StartRequest(mojom::URLLoaderFactory* loader_factory);
119 
120   // Callbacks provided to |url_loader_|:
121 
122   // On redirect, fails (key commitment endpoints must not redirect
123   // their clients).
124   void HandleRedirect(const net::RedirectInfo& redirect_info,
125                       const mojom::URLResponseHead& response_head,
126                       std::vector<std::string>* to_be_removed_headers);
127 
128   // On completion, parses the given response (if the request was
129   // successful). Calls |completion_callback_| with an error
130   void HandleResponseBody(std::unique_ptr<std::string> response_body);
131 
132   // |url_loader_| performs the actual key commitment request.
133   std::unique_ptr<SimpleURLLoader> url_loader_;
134 
135   // Parses the key commitment response if one is received.
136   std::unique_ptr<Parser> parser_;
137 
138   base::OnceCallback<void(Status status,
139                           mojom::TrustTokenKeyCommitmentResultPtr result)>
140       completion_callback_;
141 };
142 
143 }  // namespace network
144 
145 #endif  // SERVICES_NETWORK_TRUST_TOKENS_TRUST_TOKEN_KEY_COMMITMENT_CONTROLLER_H_
146