xref: /aosp_15_r20/external/tink/testing/cc/jwt_impl.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 // Implementation of a JWT Service.
18 #include "jwt_impl.h"
19 
20 #include <memory>
21 #include <ostream>
22 #include <sstream>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 #include "absl/time/time.h"
28 #include "tink/binary_keyset_reader.h"
29 #include "tink/binary_keyset_writer.h"
30 #include "tink/cleartext_keyset_handle.h"
31 #include "tink/jwt/jwk_set_converter.h"
32 #include "tink/jwt/jwt_mac.h"
33 #include "tink/jwt/jwt_public_key_sign.h"
34 #include "tink/jwt/jwt_public_key_verify.h"
35 #include "tink/jwt/raw_jwt.h"
36 #include "tink/util/status.h"
37 #include "create.h"
38 
39 namespace tink_testing_api {
40 
41 using ::crypto::tink::BinaryKeysetReader;
42 using ::crypto::tink::BinaryKeysetWriter;
43 using ::crypto::tink::CleartextKeysetHandle;
44 using ::crypto::tink::JwtMac;
45 using ::crypto::tink::JwtPublicKeySign;
46 using ::crypto::tink::JwtPublicKeyVerify;
47 using ::crypto::tink::KeysetReader;
48 using ::crypto::tink::RawJwt;
49 using ::crypto::tink::VerifiedJwt;
50 using ::crypto::tink::util::StatusOr;
51 
52 using ::crypto::tink::JwkSetToPublicKeysetHandle;
53 
TimestampToTime(google::protobuf::Timestamp t)54 absl::Time TimestampToTime(google::protobuf::Timestamp t) {
55     return absl::FromUnixMillis(t.seconds() * 1000 + t.nanos() / 1000000);
56 }
57 
TimeToTimestamp(absl::Time time)58 google::protobuf::Timestamp TimeToTimestamp(absl::Time time) {
59   int64_t millis = absl::ToUnixMillis(time);
60   int64_t seconds = millis / 1000;
61   int32_t nanos = (millis - seconds * 1000) * 1000000;
62   google::protobuf::Timestamp timestamp;
63   timestamp.set_seconds(seconds);
64   timestamp.set_nanos(nanos);
65   return timestamp;
66 }
67 
RawJwtFromProto(const JwtToken & raw_jwt_proto)68 crypto::tink::util::StatusOr<crypto::tink::RawJwt> RawJwtFromProto(
69     const JwtToken& raw_jwt_proto) {
70   auto builder = crypto::tink::RawJwtBuilder();
71   if (raw_jwt_proto.has_type_header()) {
72     builder.SetTypeHeader(raw_jwt_proto.type_header().value());
73   }
74   if (raw_jwt_proto.has_issuer()) {
75     builder.SetIssuer(raw_jwt_proto.issuer().value());
76   }
77   if (raw_jwt_proto.has_subject()) {
78     builder.SetSubject(raw_jwt_proto.subject().value());
79   }
80   for (const std::string& audience : raw_jwt_proto.audiences()) {
81     builder.AddAudience(audience);
82   }
83   if (raw_jwt_proto.has_jwt_id()) {
84     builder.SetJwtId(raw_jwt_proto.jwt_id().value());
85   }
86   if (raw_jwt_proto.has_expiration()) {
87     builder.SetExpiration(TimestampToTime(raw_jwt_proto.expiration()));
88   } else {
89     builder.WithoutExpiration();
90   }
91   if (raw_jwt_proto.has_issued_at()) {
92     builder.SetIssuedAt(TimestampToTime(raw_jwt_proto.issued_at()));
93   }
94   if (raw_jwt_proto.has_not_before()) {
95     builder.SetNotBefore(TimestampToTime(raw_jwt_proto.not_before()));
96   }
97   auto claims = raw_jwt_proto.custom_claims();
98   for (auto it = claims.begin(); it != claims.end(); it++) {
99     const auto& name = it->first;
100     const auto& value = it->second;
101     if (value.kind_case() == JwtClaimValue::kNullValue) {
102       builder.AddNullClaim(name);
103     } else if (value.kind_case() == JwtClaimValue::kBoolValue) {
104       builder.AddBooleanClaim(name, value.bool_value());
105     } else if (value.kind_case() == JwtClaimValue::kNumberValue) {
106       builder.AddNumberClaim(name, value.number_value());
107     } else if (value.kind_case() == JwtClaimValue::kStringValue) {
108       builder.AddStringClaim(name, value.string_value());
109     } else if (value.kind_case() == JwtClaimValue::kJsonObjectValue) {
110       builder.AddJsonObjectClaim(name, value.json_object_value());
111     } else if (value.kind_case() == JwtClaimValue::kJsonArrayValue) {
112       builder.AddJsonArrayClaim(name, value.json_array_value());
113     }
114   }
115   return builder.Build();
116 }
117 
VerifiedJwtToProto(const crypto::tink::VerifiedJwt & verified_jwt)118 JwtToken VerifiedJwtToProto(const crypto::tink::VerifiedJwt& verified_jwt) {
119   JwtToken token;
120   if (verified_jwt.HasTypeHeader()) {
121     token.mutable_type_header()->set_value(
122         verified_jwt.GetTypeHeader().value());
123   }
124   if (verified_jwt.HasIssuer()) {
125     token.mutable_issuer()->set_value(verified_jwt.GetIssuer().value());
126   }
127   if (verified_jwt.HasSubject()) {
128     token.mutable_subject()->set_value(verified_jwt.GetSubject().value());
129   }
130   if (verified_jwt.HasAudiences()) {
131     std::vector<std::string> audiences = verified_jwt.GetAudiences().value();
132     for (const std::string& audience : audiences) {
133       token.add_audiences(audience);
134     }
135   }
136   if (verified_jwt.HasJwtId()) {
137     token.mutable_jwt_id()->set_value(verified_jwt.GetJwtId().value());
138   }
139   if (verified_jwt.HasExpiration()) {
140     *token.mutable_expiration() =
141         TimeToTimestamp(verified_jwt.GetExpiration().value());
142   }
143   if (verified_jwt.HasIssuedAt()) {
144     *token.mutable_issued_at() =
145         TimeToTimestamp(verified_jwt.GetIssuedAt().value());
146   }
147   if (verified_jwt.HasNotBefore()) {
148     *token.mutable_not_before() =
149         TimeToTimestamp(verified_jwt.GetNotBefore().value());
150   }
151   std::vector<std::string> names = verified_jwt.CustomClaimNames();
152   for (const std::string& name : names) {
153     if (verified_jwt.IsNullClaim(name)) {
154       (*token.mutable_custom_claims())[name].set_null_value(
155           NullValue::NULL_VALUE);
156     } else if (verified_jwt.HasBooleanClaim(name)) {
157       (*token.mutable_custom_claims())[name].set_bool_value(
158           verified_jwt.GetBooleanClaim(name).value());
159     } else if (verified_jwt.HasNumberClaim(name)) {
160       (*token.mutable_custom_claims())[name].set_number_value(
161           verified_jwt.GetNumberClaim(name).value());
162     } else if (verified_jwt.HasStringClaim(name)) {
163       (*token.mutable_custom_claims())[name].set_string_value(
164           verified_jwt.GetStringClaim(name).value());
165     } else if (verified_jwt.HasJsonObjectClaim(name)) {
166       (*token.mutable_custom_claims())[name].set_json_object_value(
167           verified_jwt.GetJsonObjectClaim(name).value());
168     } else if (verified_jwt.HasJsonArrayClaim(name)) {
169       (*token.mutable_custom_claims())[name].set_json_array_value(
170           verified_jwt.GetJsonArrayClaim(name).value());
171     }
172   }
173   return token;
174 }
175 
JwtValidatorFromProto(const JwtValidator & validator_proto)176 crypto::tink::util::StatusOr<crypto::tink::JwtValidator> JwtValidatorFromProto(
177     const JwtValidator& validator_proto) {
178   auto builder = crypto::tink::JwtValidatorBuilder();
179   if (validator_proto.has_expected_type_header()) {
180     builder.ExpectTypeHeader(validator_proto.expected_type_header().value());
181   }
182   if (validator_proto.has_expected_issuer()) {
183     builder.ExpectIssuer(validator_proto.expected_issuer().value());
184   }
185   if (validator_proto.has_expected_audience()) {
186     builder.ExpectAudience(validator_proto.expected_audience().value());
187   }
188   if (validator_proto.ignore_type_header()) {
189     builder.IgnoreTypeHeader();
190   }
191   if (validator_proto.ignore_issuer()) {
192     builder.IgnoreIssuer();
193   }
194   if (validator_proto.ignore_audience()) {
195     builder.IgnoreAudiences();
196   }
197   if (validator_proto.allow_missing_expiration()) {
198     builder.AllowMissingExpiration();
199   }
200   if (validator_proto.expect_issued_in_the_past()) {
201     builder.ExpectIssuedInThePast();
202   }
203   if (validator_proto.has_now()) {
204     builder.SetFixedNow(TimestampToTime(validator_proto.now()));
205   }
206   if (validator_proto.has_clock_skew()) {
207     builder.SetClockSkew(
208         absl::Seconds(validator_proto.clock_skew().seconds()));
209   }
210   return builder.Build();
211 }
212 
CreateJwtMac(grpc::ServerContext * context,const CreationRequest * request,CreationResponse * response)213 ::grpc::Status JwtImpl::CreateJwtMac(grpc::ServerContext* context,
214                                      const CreationRequest* request,
215                                      CreationResponse* response) {
216   return CreatePrimitiveForRpc<JwtMac>(request, response);
217 }
218 
CreateJwtPublicKeySign(grpc::ServerContext * context,const CreationRequest * request,CreationResponse * response)219 ::grpc::Status JwtImpl::CreateJwtPublicKeySign(grpc::ServerContext* context,
220                                                const CreationRequest* request,
221                                                CreationResponse* response) {
222   return CreatePrimitiveForRpc<JwtPublicKeySign>(request, response);
223 }
224 
CreateJwtPublicKeyVerify(grpc::ServerContext * context,const CreationRequest * request,CreationResponse * response)225 ::grpc::Status JwtImpl::CreateJwtPublicKeyVerify(grpc::ServerContext* context,
226                                                  const CreationRequest* request,
227                                                  CreationResponse* response) {
228   return CreatePrimitiveForRpc<JwtPublicKeyVerify>(request, response);
229 }
230 
231 // Computes a MAC and generates a signed compact JWT
ComputeMacAndEncode(grpc::ServerContext * context,const JwtSignRequest * request,JwtSignResponse * response)232 grpc::Status JwtImpl::ComputeMacAndEncode(grpc::ServerContext* context,
233                                             const JwtSignRequest* request,
234                                             JwtSignResponse* response) {
235   StatusOr<std::unique_ptr<JwtMac>> jwt_mac =
236       PrimitiveFromSerializedBinaryProtoKeyset<JwtMac>(
237           request->annotated_keyset());
238   if (!jwt_mac.ok()) {
239     response->set_err(std::string(jwt_mac.status().message()));
240     return grpc::Status::OK;
241   }
242   StatusOr<RawJwt> raw_jwt = RawJwtFromProto(request->raw_jwt());
243   if (!raw_jwt.ok()) {
244     response->set_err(std::string(raw_jwt.status().message()));
245     return grpc::Status::OK;
246   }
247   StatusOr<std::string> compact =
248       (*jwt_mac)->ComputeMacAndEncode(*raw_jwt);
249   if (!compact.ok()) {
250     response->set_err(std::string(compact.status().message()));
251     return grpc::Status::OK;
252   }
253   response->set_signed_compact_jwt(*compact);
254   return grpc::Status::OK;
255 }
256 
257 // Verifies a signed compact JWT
VerifyMacAndDecode(grpc::ServerContext * context,const JwtVerifyRequest * request,JwtVerifyResponse * response)258 grpc::Status JwtImpl::VerifyMacAndDecode(grpc::ServerContext* context,
259                                            const JwtVerifyRequest* request,
260                                            JwtVerifyResponse* response) {
261   StatusOr<std::unique_ptr<JwtMac>> jwt_mac =
262       PrimitiveFromSerializedBinaryProtoKeyset<JwtMac>(
263           request->annotated_keyset());
264   if (!jwt_mac.ok()) {
265     response->set_err(std::string(jwt_mac.status().message()));
266     return grpc::Status::OK;
267   }
268   StatusOr<crypto::tink::JwtValidator> validator =
269       JwtValidatorFromProto(request->validator());
270   StatusOr<VerifiedJwt> verified_jwt =
271       (*jwt_mac)->VerifyMacAndDecode(request->signed_compact_jwt(), *validator);
272   if (!verified_jwt.ok()) {
273     response->set_err(std::string(verified_jwt.status().message()));
274     return grpc::Status::OK;
275   }
276   *response->mutable_verified_jwt() = VerifiedJwtToProto(*verified_jwt);
277   return grpc::Status::OK;
278 }
279 
PublicKeySignAndEncode(grpc::ServerContext * context,const JwtSignRequest * request,JwtSignResponse * response)280 grpc::Status JwtImpl::PublicKeySignAndEncode(grpc::ServerContext* context,
281                                    const JwtSignRequest* request,
282                                    JwtSignResponse* response) {
283   StatusOr<std::unique_ptr<JwtPublicKeySign>> jwt_sign =
284       PrimitiveFromSerializedBinaryProtoKeyset<JwtPublicKeySign>(
285           request->annotated_keyset());
286   if (!jwt_sign.ok()) {
287     response->set_err(std::string(jwt_sign.status().message()));
288     return grpc::Status::OK;
289   }
290   StatusOr<RawJwt> raw_jwt = RawJwtFromProto(request->raw_jwt());
291   if (!raw_jwt.ok()) {
292     response->set_err(std::string(raw_jwt.status().message()));
293     return grpc::Status::OK;
294   }
295   StatusOr<std::string> compact = (*jwt_sign)->SignAndEncode(*raw_jwt);
296   if (!compact.ok()) {
297     response->set_err(std::string(compact.status().message()));
298     return grpc::Status::OK;
299   }
300   response->set_signed_compact_jwt(*compact);
301   return grpc::Status::OK;
302 }
303 
PublicKeyVerifyAndDecode(grpc::ServerContext * context,const JwtVerifyRequest * request,JwtVerifyResponse * response)304 grpc::Status JwtImpl::PublicKeyVerifyAndDecode(grpc::ServerContext* context,
305                                         const JwtVerifyRequest* request,
306                                         JwtVerifyResponse* response) {
307   StatusOr<std::unique_ptr<JwtPublicKeyVerify>> jwt_verify =
308       PrimitiveFromSerializedBinaryProtoKeyset<JwtPublicKeyVerify>(
309           request->annotated_keyset());
310   if (!jwt_verify.ok()) {
311     response->set_err(std::string(jwt_verify.status().message()));
312     return grpc::Status::OK;
313   }
314   StatusOr<crypto::tink::JwtValidator> validator =
315       JwtValidatorFromProto(request->validator());
316   StatusOr<VerifiedJwt> verified_jwt =
317       (*jwt_verify)->VerifyAndDecode(request->signed_compact_jwt(), *validator);
318   if (!verified_jwt.ok()) {
319     response->set_err(std::string(verified_jwt.status().message()));
320     return grpc::Status::OK;
321   }
322   *response->mutable_verified_jwt() = VerifiedJwtToProto(*verified_jwt);
323   return grpc::Status::OK;
324 }
325 
ToJwkSet(grpc::ServerContext * context,const JwtToJwkSetRequest * request,JwtToJwkSetResponse * response)326 ::grpc::Status JwtImpl::ToJwkSet(grpc::ServerContext* context,
327                                  const JwtToJwkSetRequest* request,
328                                  JwtToJwkSetResponse* response) {
329   StatusOr<std::unique_ptr<KeysetReader>> reader =
330       BinaryKeysetReader::New(request->keyset());
331   if (!reader.ok()) {
332     response->set_err(std::string(reader.status().message()));
333     return ::grpc::Status::OK;
334   }
335   StatusOr<std::unique_ptr<::crypto::tink::KeysetHandle>> handle =
336       CleartextKeysetHandle::Read(*std::move(reader));
337   if (!handle.ok()) {
338     response->set_err(std::string(handle.status().message()));
339     return ::grpc::Status::OK;
340   }
341   StatusOr<std::string> jwk_set = JwkSetFromPublicKeysetHandle(**handle);
342   if (!jwk_set.ok()) {
343     response->set_err(std::string(jwk_set.status().message()));
344     return ::grpc::Status::OK;
345   }
346   response->set_jwk_set(*jwk_set);
347   return ::grpc::Status::OK;
348 }
349 
FromJwkSet(grpc::ServerContext * context,const JwtFromJwkSetRequest * request,JwtFromJwkSetResponse * response)350 ::grpc::Status JwtImpl::FromJwkSet(grpc::ServerContext* context,
351                                    const JwtFromJwkSetRequest* request,
352                                    JwtFromJwkSetResponse* response) {
353   StatusOr<std::unique_ptr<::crypto::tink::KeysetHandle>> keyset_handle =
354       JwkSetToPublicKeysetHandle(request->jwk_set());
355   if (!keyset_handle.ok()) {
356     response->set_err(std::string(keyset_handle.status().message()));
357     return ::grpc::Status::OK;
358   }
359   std::stringbuf keyset;
360   StatusOr<std::unique_ptr<crypto::tink::BinaryKeysetWriter>> writer =
361       BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
362   if (!writer.ok()) {
363     response->set_err(std::string(writer.status().message()));
364     return ::grpc::Status::OK;
365   }
366   crypto::tink::util::Status status =
367       CleartextKeysetHandle::Write(writer->get(), **keyset_handle);
368   if (!status.ok()) {
369     response->set_err(std::string(status.message()));
370     return ::grpc::Status::OK;
371   }
372   response->set_keyset(keyset.str());
373   return ::grpc::Status::OK;
374 }
375 
376 }  // namespace tink_testing_api
377