xref: /aosp_15_r20/external/tink/cc/jwt/internal/jwt_public_key_verify_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 #include "tink/jwt/internal/jwt_public_key_verify_impl.h"
18 
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "absl/status/status.h"
24 #include "absl/strings/escaping.h"
25 #include "absl/strings/str_split.h"
26 #include "tink/jwt/internal/json_util.h"
27 #include "tink/jwt/internal/jwt_format.h"
28 
29 namespace crypto {
30 namespace tink {
31 namespace jwt_internal {
32 
VerifyAndDecodeWithKid(absl::string_view compact,const JwtValidator & validator,absl::optional<absl::string_view> kid) const33 util::StatusOr<VerifiedJwt> JwtPublicKeyVerifyImpl::VerifyAndDecodeWithKid(
34     absl::string_view compact, const JwtValidator& validator,
35     absl::optional<absl::string_view> kid) const {
36   // TODO(juerg): Refactor this code into a util function.
37   std::size_t signature_pos = compact.find_last_of('.');
38   if (signature_pos == absl::string_view::npos) {
39     return util::Status(absl::StatusCode::kInvalidArgument, "invalid token");
40   }
41   absl::string_view unsigned_token = compact.substr(0, signature_pos);
42   std::string signature;
43   if (!DecodeSignature(compact.substr(signature_pos + 1), &signature)) {
44     return util::Status(absl::StatusCode::kInvalidArgument,
45                         "invalid JWT signature");
46   }
47   util::Status verify_result = verify_->Verify(signature, unsigned_token);
48   if (!verify_result.ok()) {
49     // Use a different error code so that we can distinguish it.
50     return util::Status(absl::StatusCode::kUnauthenticated,
51                         verify_result.message());
52   }
53   std::vector<absl::string_view> parts = absl::StrSplit(unsigned_token, '.');
54   if (parts.size() != 2) {
55     return util::Status(
56         absl::StatusCode::kInvalidArgument,
57         "only tokens in JWS compact serialization format are supported");
58   }
59   std::string json_header;
60   if (!DecodeHeader(parts[0], &json_header)) {
61     return util::Status(absl::StatusCode::kInvalidArgument, "invalid header");
62   }
63   util::StatusOr<google::protobuf::Struct> header =
64       JsonStringToProtoStruct(json_header);
65   if (!header.ok()) {
66     return header.status();
67   }
68   util::Status validate_header_result =
69       ValidateHeader(*header, algorithm_, kid, custom_kid_);
70   if (!validate_header_result.ok()) {
71     return validate_header_result;
72   }
73   std::string json_payload;
74   if (!DecodePayload(parts[1], &json_payload)) {
75     return util::Status(absl::StatusCode::kInvalidArgument,
76                         "invalid JWT payload");
77   }
78   util::StatusOr<RawJwt> raw_jwt = RawJwtParser::FromJson(
79       GetTypeHeader(*header), json_payload);
80   if (!raw_jwt.ok()) {
81     return raw_jwt.status();
82   }
83   util::Status validate_result = validator.Validate(*raw_jwt);
84   if (!validate_result.ok()) {
85     return validate_result;
86   }
87   return VerifiedJwt(*std::move(raw_jwt));
88 }
89 
90 }  // namespace jwt_internal
91 }  // namespace tink
92 }  // namespace crypto
93