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 #include "net/device_bound_sessions/device_bound_session_registration_fetcher_param.h"
6 
7 #include <optional>
8 
9 #include "base/strings/strcat.h"
10 #include "base/test/bind.h"
11 #include "base/test/task_environment.h"
12 #include "crypto/signature_verifier.h"
13 #include "net/http/http_response_headers.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 #include "net/http/structured_headers.h"
18 
19 namespace net {
20 namespace {
21 
22 constexpr char kChallenge[] = ":Y2hhbGxlbmdl:";
23 constexpr char kDecodedChallenge[] = "challenge";
24 using crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
25 using crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
26 using ::testing::UnorderedElementsAre;
27 
CreateHeaders(std::optional<std::string> path,std::optional<std::string> algs,std::optional<std::string> challenge)28 scoped_refptr<net::HttpResponseHeaders> CreateHeaders(
29     std::optional<std::string> path,
30     std::optional<std::string> algs,
31     std::optional<std::string> challenge) {
32   std::string path_string = path ? base::StrCat({"\"", *path, "\"", "; "}) : "";
33   std::string algs_string =
34       (algs && !algs->empty()) ? base::StrCat({*algs, "; "}) : "";
35   std::string challenge_string =
36       challenge ? base::StrCat({"challenge=", *challenge}) : "";
37   std::string full_string =
38       base::StrCat({path_string, algs_string, challenge_string});
39   return HttpResponseHeaders::Builder({1, 1}, "200 OK")
40       .AddHeader("Sec-Session-Registration", full_string)
41       .Build();
42 }
43 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,BasicValid)44 TEST(DeviceBoundSessionRegistrationFetcherParamTest, BasicValid) {
45   GURL registration_request = GURL("https://www.example.com/registration");
46   scoped_refptr<net::HttpResponseHeaders> response_headers =
47       CreateHeaders("startsession", "es256;rs256", kChallenge);
48   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
49       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
50           registration_request, response_headers.get());
51   ASSERT_EQ(params.size(), 1U);
52   auto param = std::move(params[0]);
53   EXPECT_EQ(param.registration_endpoint(),
54             GURL("https://www.example.com/startsession"));
55   EXPECT_THAT(param.supported_algos(),
56               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
57   EXPECT_EQ(param.challenge(), kDecodedChallenge);
58 }
59 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,ExtraUnrecognizedAlgorithm)60 TEST(DeviceBoundSessionRegistrationFetcherParamTest,
61     ExtraUnrecognizedAlgorithm) {
62   GURL registration_request = GURL("https://www.example.com/registration");
63   scoped_refptr<net::HttpResponseHeaders> response_headers =
64       CreateHeaders("startsession", "es256;bf512", kChallenge);
65   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
66       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
67           registration_request, response_headers.get());
68   ASSERT_EQ(params.size(), 1U);
69   auto param = std::move(params[0]);
70   EXPECT_EQ(param.registration_endpoint(),
71             GURL("https://www.example.com/startsession"));
72   EXPECT_THAT(param.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
73   EXPECT_EQ(param.challenge(), kDecodedChallenge);
74 }
75 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,NoHeader)76 TEST(DeviceBoundSessionRegistrationFetcherParamTest, NoHeader) {
77   GURL registration_request = GURL("https://www.example.com/registration");
78   scoped_refptr<net::HttpResponseHeaders> response_headers =
79       base::MakeRefCounted<net::HttpResponseHeaders>("");
80   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
81       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
82           registration_request, response_headers.get());
83   ASSERT_TRUE(params.empty());
84 }
85 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,ChallengeFirst)86 TEST(DeviceBoundSessionRegistrationFetcherParamTest, ChallengeFirst) {
87   GURL registration_request = GURL("https://www.example.com/registration");
88   scoped_refptr<net::HttpResponseHeaders> response_headers =
89       base::MakeRefCounted<net::HttpResponseHeaders>("");
90   response_headers->SetHeader("Sec-Session-Registration",
91                               base::StrCat({"\"startsession\";", "challenge=",
92                                             kChallenge, "; ", "rs256;es256"}));
93   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
94       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
95           registration_request, response_headers.get());
96   ASSERT_EQ(params.size(), 1U);
97   auto param = std::move(params[0]);
98   EXPECT_EQ(param.registration_endpoint(),
99             GURL("https://www.example.com/startsession"));
100   EXPECT_THAT(param.supported_algos(),
101               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
102   EXPECT_EQ(param.challenge(), kDecodedChallenge);
103 }
104 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,NoSpaces)105 TEST(DeviceBoundSessionRegistrationFetcherParamTest, NoSpaces) {
106   GURL registration_request = GURL("https://www.example.com/registration");
107   scoped_refptr<net::HttpResponseHeaders> response_headers =
108       base::MakeRefCounted<net::HttpResponseHeaders>("");
109   response_headers->SetHeader("Sec-Session-Registration",
110                               base::StrCat({"\"startsession\";challenge=",
111                                             kChallenge, ";rs256;es256"}));
112   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
113       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
114           registration_request, response_headers.get());
115   ASSERT_EQ(params.size(), 1U);
116   auto param = std::move(params[0]);
117   EXPECT_EQ(param.registration_endpoint(),
118             GURL("https://www.example.com/startsession"));
119   EXPECT_THAT(param.supported_algos(),
120               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
121   EXPECT_EQ(param.challenge(), kDecodedChallenge);
122 }
123 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,TwoRegistrations)124 TEST(DeviceBoundSessionRegistrationFetcherParamTest, TwoRegistrations) {
125   GURL registration_request = GURL("https://www.example.com/registration");
126   scoped_refptr<net::HttpResponseHeaders> response_headers =
127       base::MakeRefCounted<net::HttpResponseHeaders>("");
128   response_headers->SetHeader("Sec-Session-Registration",
129                               base::StrCat({"\"startsession\";challenge=",
130                                             kChallenge, ";rs256;es256"}));
131   response_headers->AddHeader("Sec-Session-Registration",
132                               "\"new\";challenge=:Y29kZWQ=:;es256");
133   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
134       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
135           registration_request, response_headers.get());
136   ASSERT_EQ(params.size(), 2U);
137   auto p1 = std::move(params[0]);
138   EXPECT_EQ(p1.registration_endpoint(),
139             GURL("https://www.example.com/startsession"));
140   EXPECT_THAT(p1.supported_algos(),
141               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
142   EXPECT_EQ(p1.challenge(), kDecodedChallenge);
143 
144   auto p2 = std::move(params[1]);
145   EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/new"));
146   EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
147   EXPECT_EQ(p2.challenge(), "coded");
148 }
149 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,ValidInvalid)150 TEST(DeviceBoundSessionRegistrationFetcherParamTest, ValidInvalid) {
151   GURL registration_request = GURL("https://www.example.com/registration");
152   scoped_refptr<net::HttpResponseHeaders> response_headers =
153       base::MakeRefCounted<net::HttpResponseHeaders>("");
154   response_headers->SetHeader("Sec-Session-Registration",
155                               base::StrCat({"\"startsession\";challenge=",
156                                             kChallenge, ";rs256;es256"}));
157   response_headers->AddHeader("Sec-Session-Registration",
158                               "\"new\";challenge=:Y29kZWQ=:");
159   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
160       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
161           registration_request, response_headers.get());
162   ASSERT_EQ(params.size(), 1U);
163   auto p1 = std::move(params[0]);
164   EXPECT_EQ(p1.registration_endpoint(),
165             GURL("https://www.example.com/startsession"));
166   EXPECT_THAT(p1.supported_algos(),
167               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
168   EXPECT_EQ(p1.challenge(), kDecodedChallenge);
169 }
170 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,AddedNonsenseCharacters)171 TEST(DeviceBoundSessionRegistrationFetcherParamTest, AddedNonsenseCharacters) {
172   GURL registration_request = GURL("https://www.example.com/registration");
173   scoped_refptr<net::HttpResponseHeaders> response_headers =
174       base::MakeRefCounted<net::HttpResponseHeaders>("");
175   response_headers->AddHeader("Sec-Session-Registration",
176                               "\"new\";challenge=:Y29kZWQ=:;rs256;;=;");
177   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
178       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
179           registration_request, response_headers.get());
180   ASSERT_TRUE(params.empty());
181 }
182 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,AlgAsString)183 TEST(DeviceBoundSessionRegistrationFetcherParamTest, AlgAsString) {
184   GURL registration_request = GURL("https://www.example.com/registration");
185   scoped_refptr<net::HttpResponseHeaders> response_headers =
186       base::MakeRefCounted<net::HttpResponseHeaders>("");
187   response_headers->AddHeader("Sec-Session-Registration",
188                               "\"new\";challenge=:Y29kZWQ=:;\"rs256\"");
189   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
190       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
191           registration_request, response_headers.get());
192   ASSERT_TRUE(params.empty());
193 }
194 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,ChallengeAsString)195 TEST(DeviceBoundSessionRegistrationFetcherParamTest, ChallengeAsString) {
196   GURL registration_request = GURL("https://www.example.com/registration");
197   scoped_refptr<net::HttpResponseHeaders> response_headers =
198       base::MakeRefCounted<net::HttpResponseHeaders>("");
199   response_headers->AddHeader("Sec-Session-Registration",
200                               "\"new\";challenge=\"Y29kZWQ=\";rs256");
201   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
202       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
203           registration_request, response_headers.get());
204   ASSERT_TRUE(params.empty());
205 }
206 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,ValidInvalidValid)207 TEST(DeviceBoundSessionRegistrationFetcherParamTest, ValidInvalidValid) {
208   GURL registration_request = GURL("https://www.example.com/registration");
209   scoped_refptr<net::HttpResponseHeaders> response_headers =
210       base::MakeRefCounted<net::HttpResponseHeaders>("");
211   response_headers->SetHeader("Sec-Session-Registration",
212                               base::StrCat({"\"startsession\";challenge=",
213                                             kChallenge, ";rs256;es256"}));
214   response_headers->AddHeader("Sec-Session-Registration",
215                               "\"new\";challenge=:Y29kZWQ=:");
216   response_headers->AddHeader("Sec-Session-Registration",
217                               "\"new\";challenge=:Y29kZWQ=:;es256");
218   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
219       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
220           registration_request, response_headers.get());
221   ASSERT_EQ(params.size(), 2U);
222   auto p1 = std::move(params[0]);
223   EXPECT_EQ(p1.registration_endpoint(),
224             GURL("https://www.example.com/startsession"));
225   EXPECT_THAT(p1.supported_algos(),
226               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
227   EXPECT_EQ(p1.challenge(), kDecodedChallenge);
228 
229   auto p2 = std::move(params[1]);
230   EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/new"));
231   EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
232   EXPECT_EQ(p2.challenge(), "coded");
233 }
234 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,ThreeRegistrations)235 TEST(DeviceBoundSessionRegistrationFetcherParamTest, ThreeRegistrations) {
236   GURL registration_request = GURL("https://www.example.com/registration");
237   scoped_refptr<net::HttpResponseHeaders> response_headers =
238       base::MakeRefCounted<net::HttpResponseHeaders>("");
239   response_headers->SetHeader("Sec-Session-Registration",
240                               base::StrCat({"\"startsession\";challenge=",
241                                             kChallenge, ";rs256;es256"}));
242   response_headers->AddHeader("Sec-Session-Registration",
243                               "\"new\";challenge=:Y29kZWQ=:;es256");
244   response_headers->AddHeader("Sec-Session-Registration",
245                               "\"third\";challenge=:YW5vdGhlcg==:;es256");
246   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
247       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
248           registration_request, response_headers.get());
249   ASSERT_EQ(params.size(), 3U);
250   auto p1 = std::move(params[0]);
251   EXPECT_EQ(p1.registration_endpoint(),
252             GURL("https://www.example.com/startsession"));
253   EXPECT_THAT(p1.supported_algos(),
254               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
255   EXPECT_EQ(p1.challenge(), kDecodedChallenge);
256 
257   auto p2 = std::move(params[1]);
258   EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/new"));
259   EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
260   EXPECT_EQ(p2.challenge(), "coded");
261 
262   auto p3 = std::move(params[2]);
263   EXPECT_EQ(p3.registration_endpoint(), GURL("https://www.example.com/third"));
264   EXPECT_THAT(p3.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
265   EXPECT_EQ(p3.challenge(), "another");
266 }
267 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,ThreeRegistrationsList)268 TEST(DeviceBoundSessionRegistrationFetcherParamTest, ThreeRegistrationsList) {
269   GURL registration_request = GURL("https://www.example.com/registration");
270   scoped_refptr<net::HttpResponseHeaders> response_headers =
271       base::MakeRefCounted<net::HttpResponseHeaders>("");
272   response_headers->SetHeader("Sec-Session-Registration",
273                               base::StrCat({"\"startsession\";challenge=",
274                                             kChallenge, ";rs256;es256"}));
275   response_headers->AddHeader("Sec-Session-Registration",
276                               "\"new\";challenge=:Y29kZWQ=:;es256, "
277                               "\"third\";challenge=:YW5vdGhlcg==:;es256");
278   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
279       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
280           registration_request, response_headers.get());
281   ASSERT_EQ(params.size(), 3U);
282   auto p1 = std::move(params[0]);
283   EXPECT_EQ(p1.registration_endpoint(),
284             GURL("https://www.example.com/startsession"));
285   EXPECT_THAT(p1.supported_algos(),
286               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
287   EXPECT_EQ(p1.challenge(), kDecodedChallenge);
288 
289   auto p2 = std::move(params[1]);
290   EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/new"));
291   EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
292   EXPECT_EQ(p2.challenge(), "coded");
293 
294   auto p3 = std::move(params[2]);
295   EXPECT_EQ(p3.registration_endpoint(), GURL("https://www.example.com/third"));
296   EXPECT_THAT(p3.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
297   EXPECT_EQ(p3.challenge(), "another");
298 }
299 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,StartWithSlash)300 TEST(DeviceBoundSessionRegistrationFetcherParamTest, StartWithSlash) {
301   GURL registration_request = GURL("https://www.example.com/registration");
302   scoped_refptr<net::HttpResponseHeaders> response_headers =
303       CreateHeaders("/startsession", "es256;rs256", kChallenge);
304   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
305       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
306           registration_request, response_headers.get());
307   ASSERT_EQ(params.size(), 1U);
308   auto param = std::move(params[0]);
309   EXPECT_EQ(param.registration_endpoint(),
310             GURL("https://www.example.com/startsession"));
311   EXPECT_THAT(param.supported_algos(),
312               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
313   EXPECT_EQ(param.challenge(), kDecodedChallenge);
314 }
315 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,EscapeOnce)316 TEST(DeviceBoundSessionRegistrationFetcherParamTest, EscapeOnce) {
317   GURL registration_request = GURL("https://www.example.com/registration");
318   scoped_refptr<net::HttpResponseHeaders> response_headers =
319       CreateHeaders("/%2561", "es256;rs256", kChallenge);
320   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
321       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
322           registration_request, response_headers.get());
323   ASSERT_EQ(params.size(), 1U);
324   auto param = std::move(params[0]);
325   EXPECT_EQ(param.registration_endpoint(), GURL("https://www.example.com/%61"));
326   EXPECT_THAT(param.supported_algos(),
327               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
328   EXPECT_EQ(param.challenge(), kDecodedChallenge);
329 }
330 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,InvalidUrl)331 TEST(DeviceBoundSessionRegistrationFetcherParamTest, InvalidUrl) {
332   GURL registration_request = GURL("https://[/");
333   scoped_refptr<net::HttpResponseHeaders> response_headers =
334       CreateHeaders("[", "es256;rs256", kChallenge);
335   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
336       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
337           registration_request, response_headers.get());
338   ASSERT_EQ(params.size(), 0U);
339 }
340 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,HasUrlEncoded)341 TEST(DeviceBoundSessionRegistrationFetcherParamTest, HasUrlEncoded) {
342   GURL registration_request = GURL("https://www.example.com/registration");
343   scoped_refptr<net::HttpResponseHeaders> response_headers =
344       CreateHeaders("test%2Fstart", "es256;rs256", kChallenge);
345   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
346       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
347           registration_request, response_headers.get());
348   ASSERT_EQ(params.size(), 1U);
349   auto param = std::move(params[0]);
350   EXPECT_EQ(param.registration_endpoint(),
351             GURL("https://www.example.com/test/start"));
352   EXPECT_THAT(param.supported_algos(),
353               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
354   EXPECT_EQ(param.challenge(), kDecodedChallenge);
355 }
356 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,FullUrl)357 TEST(DeviceBoundSessionRegistrationFetcherParamTest, FullUrl) {
358   GURL registration_request = GURL("https://www.example.com/registration");
359   scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
360       "https://accounts.example.com/startsession", "es256;rs256", kChallenge);
361   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
362       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
363           registration_request, response_headers.get());
364   ASSERT_EQ(params.size(), 1U);
365   auto param = std::move(params[0]);
366   EXPECT_EQ(param.registration_endpoint(),
367             GURL("https://accounts.example.com/startsession"));
368   EXPECT_THAT(param.supported_algos(),
369               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
370   EXPECT_EQ(param.challenge(), kDecodedChallenge);
371 }
372 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,SwapAlgo)373 TEST(DeviceBoundSessionRegistrationFetcherParamTest, SwapAlgo) {
374   GURL registration_request = GURL("https://www.example.com/registration");
375   scoped_refptr<net::HttpResponseHeaders> response_headers =
376       CreateHeaders("startsession", "es256;rs256", kChallenge);
377   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
378       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
379           registration_request, response_headers.get());
380   ASSERT_EQ(params.size(), 1U);
381   auto param = std::move(params[0]);
382   EXPECT_EQ(param.registration_endpoint(),
383             GURL("https://www.example.com/startsession"));
384   EXPECT_THAT(param.supported_algos(),
385               UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
386   EXPECT_EQ(param.challenge(), kDecodedChallenge);
387 }
388 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,OneAlgo)389 TEST(DeviceBoundSessionRegistrationFetcherParamTest, OneAlgo) {
390   GURL registration_request = GURL("https://www.example.com/registration");
391   scoped_refptr<net::HttpResponseHeaders> response_headers =
392       CreateHeaders("startsession", "rs256", kChallenge);
393   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
394       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
395           registration_request, response_headers.get());
396   ASSERT_EQ(params.size(), 1U);
397   auto param = std::move(params[0]);
398   EXPECT_EQ(param.registration_endpoint(),
399             GURL("https://www.example.com/startsession"));
400   ASSERT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
401   EXPECT_EQ(param.challenge(), kDecodedChallenge);
402 }
403 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,AddedParameter)404 TEST(DeviceBoundSessionRegistrationFetcherParamTest, AddedParameter) {
405   GURL registration_request = GURL("https://www.example.com/registration");
406   scoped_refptr<net::HttpResponseHeaders> response_headers =
407       CreateHeaders("startsession", "rs256;lolcat", kChallenge);
408   std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
409       DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
410           registration_request, response_headers.get());
411   ASSERT_EQ(params.size(), 1U);
412   auto param = std::move(params[0]);
413   EXPECT_EQ(param.registration_endpoint(),
414             GURL("https://www.example.com/startsession"));
415   ASSERT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
416   EXPECT_EQ(param.challenge(), kDecodedChallenge);
417 }
418 
TEST(DeviceBoundSessionRegistrationFetcherParamTest,InvalidInputs)419 TEST(DeviceBoundSessionRegistrationFetcherParamTest, InvalidInputs) {
420   struct Input {
421     std::string request_url;
422     std::optional<std::string> path;
423     std::optional<std::string> algos;
424     std::optional<std::string> challenge;
425   };
426 
427   const Input kInvalidInputs[] = {
428       // All invalid
429       {"https://www.example.com/reg", "", "", ""},
430       // All missing
431       {"https://www.example.com/reg", std::nullopt, std::nullopt, std::nullopt},
432       // All valid different Url
433       {"https://www.example.com/registration",
434        "https://accounts.different.url/startsession", "rs256", kChallenge},
435       // Empty request Url
436       {"", "start", "rs256", kChallenge},
437       // Empty algo
438       {"https://www.example.com/reg", "start", "", kChallenge},
439       // Missing algo
440       {"https://www.example.com/reg", "start", std::nullopt, kChallenge},
441       // Missing registration
442       {"https://www.example.com/reg", std::nullopt, "es256;rs256", kChallenge},
443       // Missing challenge
444       {"https://www.example.com/reg", "start", "es256;rs256", std::nullopt},
445       // Empty challenge
446       {"https://www.example.com/reg", "start", "es256;rs256", ""},
447       // Challenge invalid utf8
448       {"https://www.example.com/reg", "start", "es256;rs256", "ab\xC0\x80"}};
449 
450   for (const auto& input : kInvalidInputs) {
451     GURL registration_request = GURL(input.request_url);
452     scoped_refptr<net::HttpResponseHeaders> response_headers =
453         CreateHeaders(input.path, input.algos, input.challenge);
454     SCOPED_TRACE(registration_request.spec() + "; " +
455                  response_headers->raw_headers());
456     std::vector<DeviceBoundSessionRegistrationFetcherParam> params =
457         DeviceBoundSessionRegistrationFetcherParam::CreateIfValid(
458             registration_request, response_headers.get());
459     EXPECT_TRUE(params.empty());
460   }
461 }
462 
463 }  // namespace
464 }  // namespace net
465