Skip to content
This repository has been archived by the owner on Apr 17, 2024. It is now read-only.

Commit

Permalink
Add C++ JWT HMAC key type.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 624174566
  • Loading branch information
willinois authored and copybara-github committed Apr 12, 2024
1 parent 52ab085 commit 3db8cd9
Show file tree
Hide file tree
Showing 5 changed files with 749 additions and 0 deletions.
37 changes: 37 additions & 0 deletions cc/jwt/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,27 @@ cc_library(
],
)

cc_library(
name = "jwt_hmac_key",
srcs = ["jwt_hmac_key.cc"],
hdrs = ["jwt_hmac_key.h"],
include_prefix = "tink/jwt",
deps = [
":jwt_hmac_parameters",
":jwt_mac_key",
"//:key",
"//:partial_key_access_token",
"//:restricted_data",
"//util:status",
"//util:statusor",
"@com_google_absl//absl/base:endian",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/types:optional",
],
)

# tests

cc_test(
Expand Down Expand Up @@ -390,3 +411,19 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "jwt_hmac_key_test",
srcs = ["jwt_hmac_key_test.cc"],
deps = [
":jwt_hmac_key",
":jwt_hmac_parameters",
"//:partial_key_access",
"//:restricted_data",
"//util:statusor",
"//util:test_matchers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/types:optional",
"@com_google_googletest//:gtest_main",
],
)
36 changes: 36 additions & 0 deletions cc/jwt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,26 @@ tink_cc_library(
tink::util::statusor
)

tink_cc_library(
NAME jwt_hmac_key
SRCS
jwt_hmac_key.cc
jwt_hmac_key.h
DEPS
tink::jwt::jwt_hmac_parameters
tink::jwt::jwt_mac_key
absl::endian
absl::status
absl::strings
absl::string_view
absl::optional
tink::core::key
tink::core::partial_key_access_token
tink::core::restricted_data
tink::util::status
tink::util::statusor
)

# tests

tink_cc_test(
Expand Down Expand Up @@ -364,3 +384,19 @@ tink_cc_test(
tink::util::statusor
tink::util::test_matchers
)

tink_cc_test(
NAME jwt_hmac_key_test
SRCS
jwt_hmac_key_test.cc
DEPS
tink::jwt::jwt_hmac_key
tink::jwt::jwt_hmac_parameters
gmock
absl::status
absl::optional
tink::core::partial_key_access
tink::core::restricted_data
tink::util::statusor
tink::util::test_matchers
)
151 changes: 151 additions & 0 deletions cc/jwt/jwt_hmac_key.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

#include "tink/jwt/jwt_hmac_key.h"

#include <string>

#include "absl/base/internal/endian.h"
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "tink/jwt/jwt_hmac_parameters.h"
#include "tink/key.h"
#include "tink/partial_key_access_token.h"
#include "tink/restricted_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"

namespace crypto {
namespace tink {

JwtHmacKey::Builder& JwtHmacKey::Builder::SetParameters(
const JwtHmacParameters& parameters) {
parameters_ = parameters;
return *this;
}

JwtHmacKey::Builder& JwtHmacKey::Builder::SetKeyBytes(
const RestrictedData& key_bytes) {
key_bytes_ = key_bytes;
return *this;
}

JwtHmacKey::Builder& JwtHmacKey::Builder::SetIdRequirement(int id_requirement) {
id_requirement_ = id_requirement;
return *this;
}

JwtHmacKey::Builder& JwtHmacKey::Builder::SetCustomKid(
absl::string_view custom_kid) {
custom_kid_ = custom_kid.data();
return *this;
}

util::StatusOr<absl::optional<std::string>> JwtHmacKey::Builder::ComputeKid() {
switch (parameters_->GetKidStrategy()) {
case JwtHmacParameters::KidStrategy::kBase64EncodedKeyId: {
if (custom_kid_.has_value()) {
return util::Status(
absl::StatusCode::kInvalidArgument,
"Custom kid must not be set for KidStrategy::kBase64EncodedKeyId.");
}
std::string base64_kid;
char buffer[4];
absl::big_endian::Store32(buffer, *id_requirement_);
absl::WebSafeBase64Escape(absl::string_view(buffer, 4), &base64_kid);
return base64_kid;
}
case JwtHmacParameters::KidStrategy::kCustom: {
if (!custom_kid_.has_value()) {
return util::Status(absl::StatusCode::kInvalidArgument,
"Custom kid must be set for KidStrategy::kCustom.");
}
return custom_kid_;
}
case JwtHmacParameters::KidStrategy::kIgnored: {
if (custom_kid_.has_value()) {
return util::Status(
absl::StatusCode::kInvalidArgument,
"Custom kid must not be set for KidStrategy::kIgnored.");
}
return absl::nullopt;
}
default:
// Should be unreachable if all valid kid strategies have been handled.
return util::Status(absl::StatusCode::kFailedPrecondition,
"Unknown kid strategy.");
}
}

util::StatusOr<JwtHmacKey> JwtHmacKey::Builder::Build(
PartialKeyAccessToken token) {
if (!parameters_.has_value()) {
return util::Status(absl::StatusCode::kInvalidArgument,
"JWT HMAC parameters must be specified.");
}
if (!key_bytes_.has_value()) {
return util::Status(absl::StatusCode::kInvalidArgument,
"JWT HMAC key bytes must be specified.");
}
if (parameters_->KeySizeInBytes() != key_bytes_->size()) {
return util::Status(
absl::StatusCode::kInvalidArgument,
"Actual JWT HMAC key size does not match size specified in "
"the parameters.");
}
if (parameters_->HasIdRequirement() && !id_requirement_.has_value()) {
return util::Status(
absl::StatusCode::kInvalidArgument,
"Cannot create key without ID requirement with parameters with ID "
"requirement");
}
if (!parameters_->HasIdRequirement() && id_requirement_.has_value()) {
return util::Status(
absl::StatusCode::kInvalidArgument,
"Cannot create key with ID requirement with parameters without ID "
"requirement");
}
util::StatusOr<absl::optional<std::string>> kid = ComputeKid();
if (!kid.ok()) {
return kid.status();
}
return JwtHmacKey(*parameters_, *key_bytes_, id_requirement_, *kid);
}

bool JwtHmacKey::operator==(const Key& other) const {
const JwtHmacKey* that = dynamic_cast<const JwtHmacKey*>(&other);
if (that == nullptr) {
return false;
}
if (parameters_ != that->parameters_) {
return false;
}
if (key_bytes_ != that->key_bytes_) {
return false;
}
if (id_requirement_ != that->id_requirement_) {
return false;
}
if (kid_ != that->kid_) {
return false;
}
return true;
}

} // namespace tink
} // namespace crypto
107 changes: 107 additions & 0 deletions cc/jwt/jwt_hmac_key.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

#ifndef TINK_JWT_JWT_HMAC_KEY_H_
#define TINK_JWT_JWT_HMAC_KEY_H_

#include <string>

#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "tink/jwt/jwt_hmac_parameters.h"
#include "tink/jwt/jwt_mac_key.h"
#include "tink/key.h"
#include "tink/partial_key_access_token.h"
#include "tink/restricted_data.h"
#include "tink/util/statusor.h"

namespace crypto {
namespace tink {

// Represents functions to authenticate and verify JWTs using HMAC.
class JwtHmacKey : public JwtMacKey {
public:
// Creates JWT HMAC key instances.
class Builder {
public:
// Copyable and movable.
Builder(const Builder& other) = default;
Builder& operator=(const Builder& other) = default;
Builder(Builder&& other) = default;
Builder& operator=(Builder&& other) = default;

// Creates initially empty parameters builder.
Builder() = default;

Builder& SetParameters(const JwtHmacParameters& parameters);
Builder& SetKeyBytes(const RestrictedData& key_bytes);
Builder& SetIdRequirement(int id_requirement);
Builder& SetCustomKid(absl::string_view custom_kid);

// Creates JWT HMAC key object from this builder.
util::StatusOr<JwtHmacKey> Build(PartialKeyAccessToken token);

private:
util::StatusOr<absl::optional<std::string>> ComputeKid();

absl::optional<JwtHmacParameters> parameters_;
absl::optional<RestrictedData> key_bytes_;
absl::optional<int> id_requirement_;
absl::optional<std::string> custom_kid_;
};

// Copyable and movable.
JwtHmacKey(const JwtHmacKey& other) = default;
JwtHmacKey& operator=(const JwtHmacKey& other) = default;
JwtHmacKey(JwtHmacKey&& other) = default;
JwtHmacKey& operator=(JwtHmacKey&& other) = default;

const RestrictedData& GetKeyBytes(PartialKeyAccessToken token) const {
return key_bytes_;
}

const JwtHmacParameters& GetParameters() const override {
return parameters_;
}

absl::optional<int> GetIdRequirement() const override {
return id_requirement_;
}

absl::optional<std::string> GetKid() const override { return kid_; }

bool operator==(const Key& other) const override;

private:
JwtHmacKey(const JwtHmacParameters& parameters,
const RestrictedData& key_bytes,
absl::optional<int> id_requirement,
absl::optional<std::string> kid)
: parameters_(parameters),
key_bytes_(key_bytes),
id_requirement_(id_requirement),
kid_(kid) {}

JwtHmacParameters parameters_;
RestrictedData key_bytes_;
absl::optional<int> id_requirement_;
absl::optional<std::string> kid_;
};

} // namespace tink
} // namespace crypto

#endif // TINK_JWT_JWT_HMAC_KEY_H_
Loading

0 comments on commit 3db8cd9

Please sign in to comment.