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