xref: /aosp_15_r20/external/tink/cc/jwt/internal/jwt_mac_impl_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #include "tink/jwt/internal/jwt_mac_impl.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/escaping.h"
28 #include "absl/strings/str_split.h"
29 #include "tink/jwt/internal/json_util.h"
30 #include "tink/jwt/internal/jwt_format.h"
31 #include "tink/jwt/jwt_mac.h"
32 #include "tink/jwt/jwt_validator.h"
33 #include "tink/jwt/raw_jwt.h"
34 #include "tink/jwt/verified_jwt.h"
35 #include "tink/subtle/hmac_boringssl.h"
36 #include "tink/util/constants.h"
37 #include "tink/util/enums.h"
38 #include "tink/util/errors.h"
39 #include "tink/util/protobuf_helper.h"
40 #include "tink/util/secret_data.h"
41 #include "tink/util/test_matchers.h"
42 #include "tink/util/test_util.h"
43 
44 using ::crypto::tink::test::IsOk;
45 using ::crypto::tink::test::IsOkAndHolds;
46 using ::testing::Eq;
47 using ::testing::Not;
48 
49 namespace crypto {
50 namespace tink {
51 namespace jwt_internal {
52 
53 namespace {
54 
CreateJwtMac()55 util::StatusOr<std::unique_ptr<JwtMacInternal>> CreateJwtMac() {
56   std::string key_value;
57   if (!absl::WebSafeBase64Unescape(
58           "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1"
59           "qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
60           &key_value)) {
61     return util::Status(absl::StatusCode::kInvalidArgument,
62                         "failed to parse key");
63   }
64   crypto::tink::util::StatusOr<std::unique_ptr<Mac>> mac =
65       subtle::HmacBoringSsl::New(
66           util::Enums::ProtoToSubtle(google::crypto::tink::HashType::SHA256),
67           32, util::SecretDataFromStringView(key_value));
68   if (!mac.ok()) {
69     return mac.status();
70   }
71   std::unique_ptr<JwtMacInternal> jwt_mac = absl::make_unique<JwtMacImpl>(
72       *std::move(mac), "HS256", /*kid=*/absl::nullopt);
73   return std::move(jwt_mac);
74 }
75 
TEST(JwtMacImplTest,CreateAndValidateToken)76 TEST(JwtMacImplTest, CreateAndValidateToken) {
77   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac = CreateJwtMac();
78   ASSERT_THAT(jwt_mac, IsOk());
79 
80   absl::Time now = absl::Now();
81   util::StatusOr<RawJwt> raw_jwt = RawJwtBuilder()
82                                        .SetTypeHeader("typeHeader")
83                                        .SetJwtId("id123")
84                                        .SetNotBefore(now - absl::Seconds(300))
85                                        .SetIssuedAt(now)
86                                        .SetExpiration(now + absl::Seconds(300))
87                                        .Build();
88   ASSERT_THAT(raw_jwt, IsOk());
89   EXPECT_TRUE(raw_jwt->HasTypeHeader());
90   EXPECT_THAT(raw_jwt->GetTypeHeader(), IsOkAndHolds("typeHeader"));
91 
92   util::StatusOr<std::string> compact =
93       (*jwt_mac)->ComputeMacAndEncodeWithKid(*raw_jwt, /*kid=*/absl::nullopt);
94   ASSERT_THAT(compact, IsOk());
95 
96   util::StatusOr<JwtValidator> validator =
97       JwtValidatorBuilder().ExpectTypeHeader("typeHeader").Build();
98   ASSERT_THAT(validator, IsOk());
99 
100   util::StatusOr<VerifiedJwt> verified_jwt =
101       (*jwt_mac)->VerifyMacAndDecodeWithKid(*compact, *validator,
102                                             /*kid=*/absl::nullopt);
103   ASSERT_THAT(verified_jwt, IsOk());
104   EXPECT_THAT(verified_jwt->GetTypeHeader(), IsOkAndHolds("typeHeader"));
105   EXPECT_THAT(verified_jwt->GetJwtId(), IsOkAndHolds("id123"));
106 
107   util::StatusOr<JwtValidator> validator2 =
108       JwtValidatorBuilder().ExpectIssuer("unknown").Build();
109   ASSERT_THAT(validator2, IsOk());
110   EXPECT_FALSE((*jwt_mac)
111                    ->VerifyMacAndDecodeWithKid(*compact, *validator2,
112                                                /*kid=*/absl::nullopt)
113                    .ok());
114 }
115 
TEST(JwtMacImplTest,CreateAndValidateTokenWithKid)116 TEST(JwtMacImplTest, CreateAndValidateTokenWithKid) {
117   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac = CreateJwtMac();
118   ASSERT_THAT(jwt_mac, IsOk());
119 
120   absl::Time now = absl::Now();
121   util::StatusOr<RawJwt> raw_jwt = RawJwtBuilder()
122                                        .SetTypeHeader("typeHeader")
123                                        .SetJwtId("id123")
124                                        .SetNotBefore(now - absl::Seconds(300))
125                                        .SetIssuedAt(now)
126                                        .SetExpiration(now + absl::Seconds(300))
127                                        .Build();
128   ASSERT_THAT(raw_jwt, IsOk());
129   EXPECT_TRUE(raw_jwt->HasTypeHeader());
130   EXPECT_THAT(raw_jwt->GetTypeHeader(), IsOkAndHolds("typeHeader"));
131 
132   util::StatusOr<std::string> compact =
133       (*jwt_mac)->ComputeMacAndEncodeWithKid(*raw_jwt, "kid-123");
134   ASSERT_THAT(compact, IsOk());
135 
136   util::StatusOr<JwtValidator> validator =
137       JwtValidatorBuilder().ExpectTypeHeader("typeHeader").Build();
138   ASSERT_THAT(validator, IsOk());
139 
140   util::StatusOr<VerifiedJwt> verified_jwt =
141       (*jwt_mac)->VerifyMacAndDecodeWithKid(*compact, *validator,
142                                             /*kid=*/"kid-123");
143   ASSERT_THAT(verified_jwt, IsOk());
144   EXPECT_THAT(verified_jwt->GetTypeHeader(), IsOkAndHolds("typeHeader"));
145   EXPECT_THAT(verified_jwt->GetJwtId(), IsOkAndHolds("id123"));
146 
147   // with kid=absl::nullopt, the kid header in the token is ignored.
148   EXPECT_THAT((*jwt_mac)
149                   ->VerifyMacAndDecodeWithKid(*compact, *validator,
150                                               /*kid=*/absl::nullopt)
151                   .status(),
152               IsOk());
153 
154   // with a different kid, the verification fails.
155   EXPECT_THAT((*jwt_mac)
156                   ->VerifyMacAndDecodeWithKid(*compact, *validator,
157                                               /*kid=*/"other-kid")
158                   .status(),
159               Not(IsOk()));
160 
161   // parse header to make sure the kid value is set correctly.
162   std::vector<absl::string_view> parts = absl::StrSplit(*compact, '.');
163   ASSERT_THAT(parts.size(), Eq(3));
164   std::string json_header;
165   ASSERT_TRUE(DecodeHeader(parts[0], &json_header));
166   util::StatusOr<google::protobuf::Struct> header =
167       JsonStringToProtoStruct(json_header);
168   ASSERT_THAT(header, IsOk());
169   EXPECT_THAT(header->fields().find("kid")->second.string_value(),
170               Eq("kid-123"));
171 }
172 
TEST(JwtMacImplTest,ValidateFixedToken)173 TEST(JwtMacImplTest, ValidateFixedToken) {
174   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac = CreateJwtMac();
175   ASSERT_THAT(jwt_mac, IsOk());
176 
177   // token that expired in 2011
178   std::string compact =
179       "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleH"
180       "AiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."
181       "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
182   util::StatusOr<JwtValidator> validator_1970 =
183       JwtValidatorBuilder()
184           .ExpectTypeHeader("JWT")
185           .ExpectIssuer("joe")
186           .SetFixedNow(absl::FromUnixSeconds(12345))
187           .Build();
188   ASSERT_THAT(validator_1970, IsOk());
189 
190   // verification succeeds because token was valid 1970
191   util::StatusOr<VerifiedJwt> verified_jwt =
192       (*jwt_mac)->VerifyMacAndDecodeWithKid(compact, *validator_1970,
193                                             /*kid=*/absl::nullopt);
194   ASSERT_THAT(verified_jwt, IsOk());
195   EXPECT_THAT(verified_jwt->GetIssuer(), IsOkAndHolds("joe"));
196   EXPECT_THAT(verified_jwt->GetBooleanClaim("http://example.com/is_root"),
197               IsOkAndHolds(true));
198 
199   // verification fails because token is expired
200   util::StatusOr<JwtValidator> validator_now = JwtValidatorBuilder().Build();
201   ASSERT_THAT(validator_now, IsOk());
202   EXPECT_FALSE((*jwt_mac)
203                    ->VerifyMacAndDecodeWithKid(compact, *validator_now,
204                                                /*kid=*/absl::nullopt)
205                    .ok());
206 
207   // verification fails because token was modified
208   std::string modified_compact =
209       "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleH"
210       "AiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."
211       "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXi";
212   EXPECT_FALSE((*jwt_mac)
213                    ->VerifyMacAndDecodeWithKid(
214                        modified_compact, *validator_1970, /*kid=*/absl::nullopt)
215                    .ok());
216 }
217 
TEST(JwtMacImplTest,ValidateInvalidTokens)218 TEST(JwtMacImplTest, ValidateInvalidTokens) {
219   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac = CreateJwtMac();
220   ASSERT_THAT(jwt_mac, IsOk());
221 
222   util::StatusOr<JwtValidator> validator = JwtValidatorBuilder().Build();
223   ASSERT_THAT(validator, IsOk());
224 
225   EXPECT_FALSE((*jwt_mac)
226                    ->VerifyMacAndDecodeWithKid("eyJhbGciOiJIUzI1NiJ9.e30.abc.",
227                                                *validator,
228                                                /*kid=*/absl::nullopt)
229                    .ok());
230   EXPECT_FALSE((*jwt_mac)
231                    ->VerifyMacAndDecodeWithKid("eyJhbGciOiJIUzI1NiJ9?.e30.abc",
232                                                *validator,
233                                                /*kid=*/absl::nullopt)
234                    .ok());
235   EXPECT_FALSE((*jwt_mac)
236                    ->VerifyMacAndDecodeWithKid("eyJhbGciOiJIUzI1NiJ9.e30?.abc",
237                                                *validator,
238                                                /*kid=*/absl::nullopt)
239                    .ok());
240   EXPECT_FALSE((*jwt_mac)
241                    ->VerifyMacAndDecodeWithKid("eyJhbGciOiJIUzI1NiJ9.e30.abc?",
242                                                *validator,
243                                                /*kid=*/absl::nullopt)
244                    .ok());
245   EXPECT_FALSE((*jwt_mac)
246                    ->VerifyMacAndDecodeWithKid("eyJhbGciOiJIUzI1NiJ9.e30",
247                                                *validator,
248                                                /*kid=*/absl::nullopt)
249                    .ok());
250 }
251 
252 }  // namespace
253 }  // namespace jwt_internal
254 }  // namespace tink
255 }  // namespace crypto
256