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 #include "services/network/trust_tokens/trust_token_request_canonicalizer.h"
6 
7 #include <memory>
8 
9 #include "components/cbor/values.h"
10 #include "components/cbor/writer.h"
11 #include "net/url_request/url_request.h"
12 #include "services/network/public/mojom/trust_tokens.mojom-shared.h"
13 #include "services/network/trust_tokens/test/trust_token_test_util.h"
14 #include "services/network/trust_tokens/trust_token_http_headers.h"
15 #include "services/network/trust_tokens/trust_token_request_canonicalizer.h"
16 #include "services/network/trust_tokens/trust_token_request_signing_helper.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace network {
20 
21 // Adopt the Trust Tokens fixture to create URLRequests without boilerplate
22 using TrustTokenRequestCanonicalizerTest = TrustTokenRequestHelperTest;
23 
24 // Check that an empty request with an empty public key (and no headers to sign)
25 // serializes correctly. Expected CBOR maps:
26 //
27 // SignRequestData::kHeadersOnly:
28 //   { "public_key": b"key" }
29 //
30 // SignRequestData::kInclude:
31 //   { "url": "", "public_key": b"key" }
TEST_F(TrustTokenRequestCanonicalizerTest,Empty)32 TEST_F(TrustTokenRequestCanonicalizerTest, Empty) {
33   TrustTokenRequestCanonicalizer canonicalizer;
34 
35   cbor::Value::MapValue expected_cbor;
36   expected_cbor[cbor::Value(
37       TrustTokenRequestSigningHelper::kCanonicalizedRequestDataPublicKeyKey)] =
38       cbor::Value("key", cbor::Value::Type::BYTE_STRING);
39 
40   std::unique_ptr<net::URLRequest> request = MakeURLRequest("");
41   EXPECT_EQ(canonicalizer.Canonicalize(
42                 request.get(), /*public_key=*/"key",
43                 mojom::TrustTokenSignRequestData::kHeadersOnly),
44             cbor::Writer::Write(cbor::Value(expected_cbor)));
45 
46   expected_cbor[cbor::Value(
47       TrustTokenRequestSigningHelper::kCanonicalizedRequestDataUrlKey)] =
48       cbor::Value("");
49   EXPECT_EQ(
50       canonicalizer.Canonicalize(request.get(), /*public_key=*/"key",
51                                  mojom::TrustTokenSignRequestData::kInclude),
52       cbor::Writer::Write(cbor::Value(expected_cbor)));
53 }
54 
55 // Canonicalize a request with a nonempty public key and a nonempty URL.
56 //
57 // SignRequestData::kHeadersOnly:
58 //   { "public_key": b"key" }
59 //
60 // SignRequestData::kInclude:
61 //   { "url": "https://issuer.com/", "public_key": b"key" }
TEST_F(TrustTokenRequestCanonicalizerTest,Simple)62 TEST_F(TrustTokenRequestCanonicalizerTest, Simple) {
63   TrustTokenRequestCanonicalizer canonicalizer;
64 
65   cbor::Value::MapValue expected_cbor;
66   expected_cbor[cbor::Value(
67       TrustTokenRequestSigningHelper::kCanonicalizedRequestDataPublicKeyKey)] =
68       cbor::Value("key", cbor::Value::Type::BYTE_STRING);
69 
70   std::unique_ptr<net::URLRequest> request =
71       MakeURLRequest("https://issuer.com/");
72   EXPECT_EQ(canonicalizer.Canonicalize(
73                 request.get(), /*public_key=*/"key",
74                 mojom::TrustTokenSignRequestData::kHeadersOnly),
75             cbor::Writer::Write(cbor::Value(expected_cbor)));
76 
77   expected_cbor[cbor::Value(
78       TrustTokenRequestSigningHelper::kCanonicalizedRequestDataUrlKey)] =
79       cbor::Value("https://issuer.com/");
80   EXPECT_EQ(
81       canonicalizer.Canonicalize(request.get(), /*public_key=*/"key",
82                                  mojom::TrustTokenSignRequestData::kInclude),
83       cbor::Writer::Write(cbor::Value(expected_cbor)));
84 }
85 
86 // Canonicalize a request with a nonempty public key, some signed headers, and a
87 // nonempty URL.
88 //
89 // Expected CBOR maps:
90 //
91 // SignRequestData::kHeadersOnly:
92 //   { "public_key": b"key", "first_header": "first_header_value",
93 //     "second_header": "second_header_value" }
94 //
95 // SignRequestData::kInclude:
96 //   { "url": "https://issuer.com/", "public_key": b"key",
97 //     "first_header": "first_header_value", "second_header":
98 //     "second_header_value" }
TEST_F(TrustTokenRequestCanonicalizerTest,WithSignedHeaders)99 TEST_F(TrustTokenRequestCanonicalizerTest, WithSignedHeaders) {
100   TrustTokenRequestCanonicalizer canonicalizer;
101 
102   cbor::Value::MapValue expected_cbor;
103   expected_cbor[cbor::Value(
104       TrustTokenRequestSigningHelper::kCanonicalizedRequestDataPublicKeyKey)] =
105       cbor::Value("key", cbor::Value::Type::BYTE_STRING);
106 
107   std::unique_ptr<net::URLRequest> request =
108       MakeURLRequest("https://issuer.com/");
109 
110   // Capitalization should be normalized.
111   request->SetExtraRequestHeaderByName("First_HeadER", "first_header_value",
112                                        /*overwrite=*/true);
113 
114   request->SetExtraRequestHeaderByName("second_header", "second_header_value",
115                                        /*overwrite=*/true);
116   request->SetExtraRequestHeaderByName(kTrustTokensRequestHeaderSignedHeaders,
117                                        "  first_header ,  second_header ",
118                                        /*overwrite=*/true);
119 
120   expected_cbor[cbor::Value("first_header")] =
121       cbor::Value("first_header_value");
122   expected_cbor[cbor::Value("second_header")] =
123       cbor::Value("second_header_value");
124 
125   EXPECT_EQ(canonicalizer.Canonicalize(
126                 request.get(), /*public_key=*/"key",
127                 mojom::TrustTokenSignRequestData::kHeadersOnly),
128             cbor::Writer::Write(cbor::Value(expected_cbor)));
129 
130   expected_cbor[cbor::Value(
131       TrustTokenRequestSigningHelper::kCanonicalizedRequestDataUrlKey)] =
132       cbor::Value("https://issuer.com/");
133   EXPECT_EQ(
134       canonicalizer.Canonicalize(request.get(), /*public_key=*/"key",
135                                  mojom::TrustTokenSignRequestData::kInclude),
136       cbor::Writer::Write(cbor::Value(expected_cbor)));
137 }
138 
139 // Canonicalizing a request with a malformed Signed-Headers header should fail.
TEST_F(TrustTokenRequestCanonicalizerTest,RejectsMalformedSignedHeaders)140 TEST_F(TrustTokenRequestCanonicalizerTest, RejectsMalformedSignedHeaders) {
141   TrustTokenRequestCanonicalizer canonicalizer;
142 
143   std::unique_ptr<net::URLRequest> request =
144       MakeURLRequest("https://issuer.com/");
145 
146   // Set the Signed-Headers header to something that is *not* the serialization
147   // of a Structured Headers token. (Tokens can't start with quotes.)
148   request->SetExtraRequestHeaderByName(kTrustTokensRequestHeaderSignedHeaders,
149                                        "\"", /*overwrite=*/true);
150 
151   EXPECT_FALSE(canonicalizer.Canonicalize(
152       request.get(), /*public_key=*/"key",
153       mojom::TrustTokenSignRequestData::kHeadersOnly));
154 }
155 
156 // Canonicalizing a request with an empty key should fail.
TEST_F(TrustTokenRequestCanonicalizerTest,RejectsEmptyKey)157 TEST_F(TrustTokenRequestCanonicalizerTest, RejectsEmptyKey) {
158   TrustTokenRequestCanonicalizer canonicalizer;
159 
160   std::unique_ptr<net::URLRequest> request =
161       MakeURLRequest("https://issuer.com/");
162 
163   EXPECT_FALSE(canonicalizer.Canonicalize(
164       request.get(), /*public_key=*/"",
165       mojom::TrustTokenSignRequestData::kHeadersOnly));
166 }
167 }  // namespace network
168