xref: /aosp_15_r20/external/tink/cc/jwt/internal/jwt_hmac_key_manager_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_hmac_key_manager.h"
18 
19 #include <memory>
20 #include <sstream>
21 #include <string>
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 "absl/time/time.h"
30 #include "tink/core/key_manager_impl.h"
31 #include "tink/jwt/internal/json_util.h"
32 #include "tink/jwt/internal/jwt_format.h"
33 #include "tink/mac.h"
34 #include "tink/util/istream_input_stream.h"
35 #include "tink/util/secret_data.h"
36 #include "tink/util/status.h"
37 #include "tink/util/statusor.h"
38 #include "tink/util/test_matchers.h"
39 #include "tink/util/test_util.h"
40 
41 namespace crypto {
42 namespace tink {
43 namespace jwt_internal {
44 
45 using ::crypto::tink::test::IsOk;
46 using ::crypto::tink::test::IsOkAndHolds;
47 using ::crypto::tink::test::StatusIs;
48 using ::crypto::tink::util::IstreamInputStream;
49 using ::crypto::tink::util::StatusOr;
50 using ::google::crypto::tink::JwtHmacAlgorithm;
51 using ::google::crypto::tink::JwtHmacKey;
52 using ::google::crypto::tink::JwtHmacKeyFormat;
53 using ::testing::Eq;
54 using ::testing::Not;
55 using ::testing::SizeIs;
56 
57 namespace {
58 
TEST(JwtHmacKeyManagerTest,Basics)59 TEST(JwtHmacKeyManagerTest, Basics) {
60   EXPECT_EQ(JwtHmacKeyManager().get_version(), 0);
61   EXPECT_EQ(JwtHmacKeyManager().get_key_type(),
62             "type.googleapis.com/google.crypto.tink.JwtHmacKey");
63   EXPECT_EQ(JwtHmacKeyManager().key_material_type(),
64             google::crypto::tink::KeyData::SYMMETRIC);
65 }
66 
TEST(JwtHmacKeyManagerTest,ValidateEmptyKey)67 TEST(JwtHmacKeyManagerTest, ValidateEmptyKey) {
68   EXPECT_THAT(JwtHmacKeyManager().ValidateKey(JwtHmacKey()), Not(IsOk()));
69 }
70 
TEST(JwtHmacKeyManagerTest,ValidateEmptyKeyFormat)71 TEST(JwtHmacKeyManagerTest, ValidateEmptyKeyFormat) {
72   EXPECT_THAT(JwtHmacKeyManager().ValidateKeyFormat(JwtHmacKeyFormat()),
73               Not(IsOk()));
74 }
75 
TEST(RawJwtHmacKeyManagerTest,ValidateHS256KeyFormat)76 TEST(RawJwtHmacKeyManagerTest, ValidateHS256KeyFormat) {
77   JwtHmacKeyFormat key_format;
78   key_format.set_algorithm(JwtHmacAlgorithm::HS256);
79   key_format.set_key_size(32);
80   EXPECT_THAT(JwtHmacKeyManager().ValidateKeyFormat(key_format), IsOk());
81   key_format.set_key_size(31);
82   EXPECT_THAT(JwtHmacKeyManager().ValidateKeyFormat(key_format), Not(IsOk()));
83 }
84 
TEST(RawJwtHmacKeyManagerTest,ValidateHS384KeyFormat)85 TEST(RawJwtHmacKeyManagerTest, ValidateHS384KeyFormat) {
86   JwtHmacKeyFormat key_format;
87   key_format.set_algorithm(JwtHmacAlgorithm::HS384);
88   key_format.set_key_size(48);
89   EXPECT_THAT(JwtHmacKeyManager().ValidateKeyFormat(key_format), IsOk());
90   key_format.set_key_size(47);
91   EXPECT_THAT(JwtHmacKeyManager().ValidateKeyFormat(key_format), Not(IsOk()));
92 }
93 
TEST(RawJwtHmacKeyManagerTest,ValidateHS512KeyFormat)94 TEST(RawJwtHmacKeyManagerTest, ValidateHS512KeyFormat) {
95   JwtHmacKeyFormat key_format;
96   key_format.set_algorithm(JwtHmacAlgorithm::HS512);
97   key_format.set_key_size(64);
98   EXPECT_THAT(JwtHmacKeyManager().ValidateKeyFormat(key_format), IsOk());
99   key_format.set_key_size(63);
100   EXPECT_THAT(JwtHmacKeyManager().ValidateKeyFormat(key_format), Not(IsOk()));
101 }
102 
TEST(JwtHmacKeyManagerTest,CreateKey)103 TEST(JwtHmacKeyManagerTest, CreateKey) {
104   JwtHmacKeyFormat key_format;
105   key_format.set_key_size(32);
106   key_format.set_algorithm(JwtHmacAlgorithm::HS256);
107   util::StatusOr<google::crypto::tink::JwtHmacKey> key =
108       JwtHmacKeyManager().CreateKey(key_format);
109   ASSERT_THAT(key, IsOk());
110   EXPECT_EQ(key->version(), 0);
111   EXPECT_EQ(key->algorithm(), key_format.algorithm());
112   EXPECT_THAT(key->key_value(), SizeIs(key_format.key_size()));
113 
114   EXPECT_THAT(JwtHmacKeyManager().ValidateKey(*key), IsOk());
115 }
116 
TEST(JwtHmacKeyManagerTest,ValidateKeyWithUnknownAlgorithm_fails)117 TEST(JwtHmacKeyManagerTest, ValidateKeyWithUnknownAlgorithm_fails) {
118   JwtHmacKey key;
119   key.set_version(0);
120   key.set_algorithm(JwtHmacAlgorithm::HS_UNKNOWN);
121   key.set_key_value("0123456789abcdef0123456789abcdef");
122 
123   EXPECT_FALSE(JwtHmacKeyManager().ValidateKey(key).ok());
124 }
125 
TEST(JwtHmacKeyManagerTest,ValidateHS256Key)126 TEST(JwtHmacKeyManagerTest, ValidateHS256Key) {
127   JwtHmacKey key;
128   key.set_version(0);
129   key.set_algorithm(JwtHmacAlgorithm::HS256);
130   key.set_key_value("0123456789abcdef0123456789abcdef");  // 32 bytes
131   EXPECT_THAT(JwtHmacKeyManager().ValidateKey(key), IsOk());
132   key.set_key_value("0123456789abcdef0123456789abcde");  // 31 bytes
133   EXPECT_THAT(JwtHmacKeyManager().ValidateKey(key), Not(IsOk()));
134 }
135 
TEST(JwtHmacKeyManagerTest,ValidateHS384Key)136 TEST(JwtHmacKeyManagerTest, ValidateHS384Key) {
137   JwtHmacKey key;
138   key.set_version(0);
139   key.set_algorithm(JwtHmacAlgorithm::HS384);
140   key.set_key_value(
141       "0123456789abcdef0123456789abcdef0123456789abcdef");  // 48 bytes
142   EXPECT_THAT(JwtHmacKeyManager().ValidateKey(key), IsOk());
143   key.set_key_value(
144       "0123456789abcdef0123456789abcdef0123456789abcde");  // 47 bytes
145   EXPECT_THAT(JwtHmacKeyManager().ValidateKey(key), Not(IsOk()));
146 }
147 
TEST(JwtHmacKeyManagerTest,ValidateHS512Key)148 TEST(JwtHmacKeyManagerTest, ValidateHS512Key) {
149   JwtHmacKey key;
150   key.set_version(0);
151   key.set_algorithm(JwtHmacAlgorithm::HS512);
152   key.set_key_value(  // 64 bytes
153       "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef");
154   key.set_key_value(  // 63 bytes
155       "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde");
156   EXPECT_THAT(JwtHmacKeyManager().ValidateKey(key), Not(IsOk()));
157 }
158 
159 
TEST(JwtHmacKeyManagerTest,DeriveKeyIsNotImplemented)160 TEST(JwtHmacKeyManagerTest, DeriveKeyIsNotImplemented) {
161   JwtHmacKeyFormat format;
162   format.set_version(0);
163   format.set_key_size(32);
164   format.set_algorithm(JwtHmacAlgorithm::HS256);
165 
166   IstreamInputStream input_stream{
167       absl::make_unique<std::stringstream>("0123456789abcdefghijklmnop")};
168 
169   ASSERT_THAT(JwtHmacKeyManager().DeriveKey(format, &input_stream).status(),
170               StatusIs(absl::StatusCode::kUnimplemented));
171 }
172 
TEST(JwtHmacKeyManagerTest,GetAndUsePrimitive)173 TEST(JwtHmacKeyManagerTest, GetAndUsePrimitive) {
174   JwtHmacKeyFormat key_format;
175   key_format.set_key_size(32);
176   key_format.set_algorithm(JwtHmacAlgorithm::HS256);
177   util::StatusOr<google::crypto::tink::JwtHmacKey> key =
178       JwtHmacKeyManager().CreateKey(key_format);
179   ASSERT_THAT(key, IsOk());
180 
181   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac =
182       JwtHmacKeyManager().GetPrimitive<JwtMacInternal>(*key);
183   ASSERT_THAT(jwt_mac, IsOk());
184 
185   util::StatusOr<RawJwt> raw_jwt =
186       RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
187   ASSERT_THAT(raw_jwt, IsOk());
188 
189   util::StatusOr<std::string> compact =
190       (*jwt_mac)->ComputeMacAndEncodeWithKid(*raw_jwt, /*kid=*/absl::nullopt);
191   ASSERT_THAT(compact, IsOk());
192   util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
193                                                .ExpectIssuer("issuer")
194                                                .AllowMissingExpiration()
195                                                .Build();
196   ASSERT_THAT(validator, IsOk());
197 
198   util::StatusOr<VerifiedJwt> verified_jwt =
199       (*jwt_mac)->VerifyMacAndDecodeWithKid(*compact, *validator,
200                                             /*kid=*/absl::nullopt);
201   ASSERT_THAT(verified_jwt, IsOk());
202   util::StatusOr<std::string> issuer = verified_jwt->GetIssuer();
203   EXPECT_THAT(issuer, IsOkAndHolds("issuer"));
204 }
205 
TEST(JwtHmacKeyManagerTest,GetAndUsePrimitiveWithKid)206 TEST(JwtHmacKeyManagerTest, GetAndUsePrimitiveWithKid) {
207   JwtHmacKeyFormat key_format;
208   key_format.set_key_size(32);
209   key_format.set_algorithm(JwtHmacAlgorithm::HS256);
210   util::StatusOr<google::crypto::tink::JwtHmacKey> key =
211       JwtHmacKeyManager().CreateKey(key_format);
212   ASSERT_THAT(key, IsOk());
213 
214   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac =
215       JwtHmacKeyManager().GetPrimitive<JwtMacInternal>(*key);
216   ASSERT_THAT(jwt_mac, IsOk());
217 
218   util::StatusOr<RawJwt> raw_jwt =
219       RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
220   ASSERT_THAT(raw_jwt, IsOk());
221 
222   util::StatusOr<std::string> token_with_kid =
223       (*jwt_mac)->ComputeMacAndEncodeWithKid(*raw_jwt, /*kid=*/"kid-123");
224   ASSERT_THAT(token_with_kid, IsOk());
225   util::StatusOr<std::string> token_without_kid =
226       (*jwt_mac)->ComputeMacAndEncodeWithKid(*raw_jwt, /*kid=*/absl::nullopt);
227   ASSERT_THAT(token_without_kid, IsOk());
228 
229   util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
230                                                .ExpectIssuer("issuer")
231                                                .AllowMissingExpiration()
232                                                .Build();
233   ASSERT_THAT(validator, IsOk());
234 
235   // A token with kid only fails if the wrong kid is passed.
236   ASSERT_THAT((*jwt_mac)
237                   ->VerifyMacAndDecodeWithKid(*token_with_kid, *validator,
238                                               /*kid=*/absl::nullopt)
239                   .status(),
240               IsOk());
241   ASSERT_THAT((*jwt_mac)
242                   ->VerifyMacAndDecodeWithKid(*token_with_kid, *validator,
243                                               /*kid=*/"kid-123")
244                   .status(),
245               IsOk());
246   ASSERT_THAT((*jwt_mac)
247                   ->VerifyMacAndDecodeWithKid(*token_with_kid, *validator,
248                                               /*kid=*/"wrong-kid")
249                   .status(),
250               Not(IsOk()));
251 
252   // A token without kid is only valid if no kid is passed.
253   ASSERT_THAT((*jwt_mac)
254                   ->VerifyMacAndDecodeWithKid(*token_without_kid, *validator,
255                                               /*kid=*/absl::nullopt)
256                   .status(),
257               IsOk());
258   ASSERT_THAT(
259       (*jwt_mac)
260           ->VerifyMacAndDecodeWithKid(*token_without_kid, *validator, "kid-123")
261           .status(),
262       Not(IsOk()));
263 }
264 
TEST(JwtHmacKeyManagerTest,GetAndUsePrimitiveWithCustomKid)265 TEST(JwtHmacKeyManagerTest, GetAndUsePrimitiveWithCustomKid) {
266   JwtHmacKeyFormat key_format;
267   key_format.set_key_size(32);
268   key_format.set_algorithm(JwtHmacAlgorithm::HS256);
269   util::StatusOr<JwtHmacKey> key = JwtHmacKeyManager().CreateKey(key_format);
270   ASSERT_THAT(key, IsOk());
271   key->mutable_custom_kid()->set_value(
272       "Lorem ipsum dolor sit amet, consectetur adipiscing elit");
273 
274   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac =
275       JwtHmacKeyManager().GetPrimitive<JwtMacInternal>(*key);
276   ASSERT_THAT(jwt_mac, IsOk());
277 
278   util::StatusOr<RawJwt> raw_jwt =
279       RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
280   ASSERT_THAT(raw_jwt, IsOk());
281 
282   util::StatusOr<std::string> compact =
283       (*jwt_mac)->ComputeMacAndEncodeWithKid(*raw_jwt, /*kid=*/absl::nullopt);
284   ASSERT_THAT(compact, IsOk());
285   util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
286                                                .ExpectIssuer("issuer")
287                                                .AllowMissingExpiration()
288                                                .Build();
289   ASSERT_THAT(validator, IsOk());
290   // parse header and check "kid"
291   std::vector<absl::string_view> parts = absl::StrSplit(*compact, '.');
292   ASSERT_THAT(parts.size(), Eq(3));
293   std::string json_header;
294   ASSERT_TRUE(DecodeHeader(parts[0], &json_header));
295   util::StatusOr<google::protobuf::Struct> header =
296       JsonStringToProtoStruct(json_header);
297   ASSERT_THAT(header, IsOk());
298   auto it = header->fields().find("kid");
299   ASSERT_FALSE(it == header->fields().end());
300   EXPECT_THAT(it->second.string_value(),
301               Eq("Lorem ipsum dolor sit amet, consectetur adipiscing elit"));
302 
303   // validate token
304   util::StatusOr<VerifiedJwt> verified_jwt =
305       (*jwt_mac)->VerifyMacAndDecodeWithKid(*compact, *validator,
306                                             /*kid=*/absl::nullopt);
307   ASSERT_THAT(verified_jwt, IsOk());
308   util::StatusOr<std::string> issuer = verified_jwt->GetIssuer();
309   ASSERT_THAT(issuer, IsOk());
310   EXPECT_THAT(*issuer, testing::Eq("issuer"));
311 
312   // passing a kid when custom_kid is set should fail
313   EXPECT_THAT((*jwt_mac)
314                   ->ComputeMacAndEncodeWithKid(*raw_jwt, /*kid=*/"kid123")
315                   .status(),
316               Not(IsOk()));
317 }
318 
TEST(JwtHmacKeyManagerTest,ValidateTokenWithFixedKey)319 TEST(JwtHmacKeyManagerTest, ValidateTokenWithFixedKey) {
320   JwtHmacKey key;
321   key.set_version(0);
322   key.set_algorithm(JwtHmacAlgorithm::HS256);
323 
324   std::string key_value;
325   ASSERT_TRUE(absl::WebSafeBase64Unescape(
326       "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1"
327       "qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
328       &key_value));
329   key.set_key_value(key_value);
330   util::StatusOr<std::unique_ptr<JwtMacInternal>> jwt_mac =
331       JwtHmacKeyManager().GetPrimitive<JwtMacInternal>(key);
332   ASSERT_THAT(jwt_mac, IsOk());
333 
334   std::string compact =
335       "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleH"
336       "AiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."
337       "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
338   util::StatusOr<JwtValidator> validator =
339       JwtValidatorBuilder()
340           .ExpectTypeHeader("JWT")
341           .ExpectIssuer("joe")
342           .SetFixedNow(absl::FromUnixSeconds(12345))
343           .Build();
344   ASSERT_THAT(validator, IsOk());
345 
346   util::StatusOr<VerifiedJwt> verified_jwt =
347       (*jwt_mac)->VerifyMacAndDecodeWithKid(compact, *validator,
348                                             /*kid=*/absl::nullopt);
349   ASSERT_THAT(verified_jwt, IsOk());
350   EXPECT_THAT(verified_jwt->GetIssuer(), IsOkAndHolds("joe"));
351   EXPECT_THAT(verified_jwt->GetBooleanClaim("http://example.com/is_root"),
352               IsOkAndHolds(true));
353 
354   util::StatusOr<JwtValidator> validator_now = JwtValidatorBuilder().Build();
355   ASSERT_THAT(validator_now, IsOk());
356   EXPECT_THAT((*jwt_mac)
357                   ->VerifyMacAndDecodeWithKid(compact, *validator_now,
358                                               /*kid=*/absl::nullopt)
359                   .status(),
360               Not(IsOk()));
361 
362   std::string modified_compact =
363       "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleH"
364       "AiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."
365       "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXi";
366   EXPECT_THAT((*jwt_mac)
367                   ->VerifyMacAndDecodeWithKid(modified_compact, *validator,
368                                               /*kid=*/absl::nullopt)
369                   .status(),
370               Not(IsOk()));
371 }
372 
373 }  // namespace
374 }  // namespace jwt_internal
375 }  // namespace tink
376 }  // namespace crypto
377