Hello community, here is the log from the commit of package jwt_verify_lib for openSUSE:Factory checked in at 2019-08-06 17:27:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/jwt_verify_lib (Old) and /work/SRC/openSUSE:Factory/.jwt_verify_lib.new.4126 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "jwt_verify_lib" Tue Aug 6 17:27:18 2019 rev:4 rq:721261 version:20190708 Changes: -------- --- /work/SRC/openSUSE:Factory/jwt_verify_lib/jwt_verify_lib.changes 2019-07-23 22:42:22.502796497 +0200 +++ /work/SRC/openSUSE:Factory/.jwt_verify_lib.new.4126/jwt_verify_lib.changes 2019-08-06 17:27:21.520687502 +0200 @@ -1,0 +2,24 @@ +Thu Aug 01 11:20:17 UTC 2019 - [email protected] + +- Use OpenSSL instead of BoringSSL. +- Update to version 20190708: + * Implement RS384/RS512 token verification + * Add tests for RS384 and RS512 tokens + * Harden JwkRSA verification code + * Reduce fuzz truncate case + * Fix verify_time_test + * one more uint64 + * one more uint64_t + * change to unsigned + * clean struct_utils + * clean protobuf binding + * remove rapidjson + * fix jwks + * 3rd draft + * second draft + * first draft + * Clear SSL errors for failed verification +- Remove patch: + * bazel-unbundle-dependencies.patch + +------------------------------------------------------------------- Old: ---- bazel-unbundle-dependencies.patch jwt_verify_lib-20181125.tar.xz New: ---- BUILD WORKSPACE abseil_strings.BUILD abseil_time.BUILD bsslwrapper.BUILD googletest.BUILD jwt-verify-lib-openssl-20190723.tar.xz jwt_verify_lib-20190708.tar.xz opensslcbs.BUILD zlib.BUILD ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ jwt_verify_lib.spec ++++++ --- /var/tmp/diff_new_pack.iuQUpj/_old 2019-08-06 17:27:22.404687310 +0200 +++ /var/tmp/diff_new_pack.iuQUpj/_new 2019-08-06 17:27:22.408687308 +0200 @@ -18,21 +18,37 @@ %define sover 0 %define libname lib%{name}%{sover} +%define maistra_name jwt-verify-lib-openssl +%define maistra_version 20190723 Name: jwt_verify_lib -Version: 20181125 +Version: 20190708 Release: 0 Summary: JSON Web Tokens verification library for C++ License: Apache-2.0 Group: Development/Libraries/C and C++ Url: https://github.com/google/%{name} -Source: %{name}-%{version}.tar.xz -Patch0: bazel-unbundle-dependencies.patch +Source0: %{name}-%{version}.tar.xz +Source1: %{maistra_name}-%{maistra_version}.tar.xz +Source100: WORKSPACE +Source101: BUILD +Source200: abseil_strings.BUILD +Source201: abseil_time.BUILD +Source202: bsslwrapper.BUILD +Source203: googletest.BUILD +Source204: opensslcbs.BUILD +Source205: zlib.BUILD BuildRequires: abseil-cpp-devel +BuildRequires: bazel-skylib-source BuildRequires: bazel0.19 -BuildRequires: boringssl-devel +BuildRequires: bssl_wrapper-devel BuildRequires: gcc-c++ +BuildRequires: gmock BuildRequires: gtest +BuildRequires: openssl-cbs-devel +BuildRequires: openssl-devel +BuildRequires: protobuf-devel +BuildRequires: protobuf-source BuildRequires: rapidjson-devel ExcludeArch: %ix86 @@ -62,11 +78,20 @@ This package contains development files for jwt_verify_lib. %prep +%setup -q -D -b 1 -n %{maistra_name}-%{maistra_version} + %setup -q -%patch0 -p1 -# BoringSSL headers are installed in /usr/include/boringssl directory to avoid -# conflict with openssl-devel. -find . -type f \( -name "*.h" -o -name "*.cc" \) -exec sed -i 's/openssl/boringssl/' "{}" + +pushd ../%{maistra_name}-%{maistra_version} +./openssl.sh ../%{name}-%{version} SSL +popd +cp %{SOURCE100} . +cp %{SOURCE101} . +cp %{SOURCE200} . +cp %{SOURCE201} . +cp %{SOURCE202} . +cp %{SOURCE203} . +cp %{SOURCE204} . +cp %{SOURCE205} . %build # TODO(mrostecki): Create a macro in bazel package. ++++++ BUILD ++++++ licenses(["notice"]) # Apache 2 package(default_visibility = ["//visibility:public"]) exports_files(["LICENSE"]) cc_library( name = "jwt_verify_lib", srcs = [ "src/check_audience.cc", "src/jwks.cc", "src/jwt.cc", "src/status.cc", "src/struct_utils.h", "src/verify.cc", ], hdrs = [ "jwt_verify_lib/check_audience.h", "jwt_verify_lib/jwks.h", "jwt_verify_lib/jwt.h", "jwt_verify_lib/status.h", "jwt_verify_lib/verify.h", ], deps = [ "@abseil_strings//:abseil_strings", "@abseil_time//:abseil_time", "@openssl//:openssl-lib", "//external:protobuf", ], ) ++++++ WORKSPACE ++++++ local_repository( name = "com_google_protobuf", path = "/usr/src/protobuf", ) bind( name = "protobuf", actual = "@com_google_protobuf//:protobuf", ) local_repository( name = "bazel_skylib", path = "/usr/src/bazel-skylib", ) new_local_repository( name = "openssl", path = "/usr/lib64/", build_file = "openssl.BUILD", ) new_local_repository( name = "abseil_strings", path = "/usr/lib64/", build_file = "abseil_strings.BUILD", ) new_local_repository( name = "abseil_time", path = "/usr/lib64/", build_file = "abseil_time.BUILD", ) new_local_repository( name = "bssl_wrapper_lib", path = "/usr/lib64/", build_file = "bsslwrapper.BUILD", ) new_local_repository( name = "googletest", path = "/usr/lib64/", build_file = "googletest.BUILD", ) new_local_repository( name = "opensslcbs", path = "/usr/lib64/", build_file = "opensslcbs.BUILD", ) new_local_repository( name = "zlib", path = "/usr/lib64", build_file = "zlib.BUILD", ) ++++++ _service ++++++ --- /var/tmp/diff_new_pack.iuQUpj/_old 2019-08-06 17:27:22.460687298 +0200 +++ /var/tmp/diff_new_pack.iuQUpj/_new 2019-08-06 17:27:22.460687298 +0200 @@ -5,7 +5,15 @@ <param name="changesgenerate">enable</param> <param name="filename">jwt_verify_lib</param> <param name="versionformat">%cd</param> - <param name="revision">a1298efde49c8f2329e8c124a2389c37845cacf5</param> + <param name="revision">0f14d43f20381cfae0469cb2309b2e220c0f0ea3</param> + </service> + <service mode="disabled" name="tar_scm"> + <param name="url">https://github.com/Maistra/jwt-verify-lib-openssl</param> + <param name="scm">git</param> + <param name="changesgenerate">disable</param> + <param name="filename">jwt-verify-lib-openssl</param> + <param name="versionformat">%cd</param> + <param name="revision">55dba200857b7c50d82336d38d556be5807d39b6</param> </service> <service mode="disabled" name="recompress"> <param name="file">*.tar</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.iuQUpj/_old 2019-08-06 17:27:22.476687294 +0200 +++ /var/tmp/diff_new_pack.iuQUpj/_new 2019-08-06 17:27:22.480687294 +0200 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/google/jwt_verify_lib</param> - <param name="changesrevision">0dd668acc4ebd8af9a83172464432ebe466ba5a1</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">c2a793f4c5c019199dbd7902a48fee07c252664b</param></service></servicedata> \ No newline at end of file ++++++ abseil_strings.BUILD ++++++ licenses(["notice"]) # Apache 2 cc_library( name = "abseil_strings", hdrs = glob(["thirdparty_build/include/absl/**/*.h"]), copts = ["-I/usr/include/absl"], linkopts = [ "-labsl_base_libbase", "-labsl_base_libthrow_delegate", "-labsl_strings_libinternal", "-labsl_strings_libstr_format_internal", "-labsl_strings_libstrings", ], visibility = ["//visibility:public"], linkstatic=False, ) ++++++ abseil_time.BUILD ++++++ licenses(["notice"]) # Apache 2 cc_library( name = "abseil_time", hdrs = glob(["thirdparty_build/include/absl/**/*.h"]), copts = ["-I/usr/include/absl"], linkopts = [ "-labsl_base_libbase", "-labsl_base_libspinlock_wait", "-labsl_numeric_libint128", "-labsl_time_internal_cctz_libcivil_time", "-labsl_time_internal_cctz_libtime_zone", "-labsl_time_libtest_util", "-labsl_time_libtime", ], visibility = ["//visibility:public"], linkstatic=False, ) ++++++ bsslwrapper.BUILD ++++++ licenses(["notice"]) # Apache 2 cc_library( name = "bssl_wrapper_lib", hdrs = glob(["thirdparty_build/include/bssl_wrapper/**/*.h"]), copts = ["-I/usr/include/bssl_wrapper"], linkopts = [ "-lbssl_wrapper_lib", ], visibility = ["//visibility:public"], linkstatic=False, ) ++++++ googletest.BUILD ++++++ licenses(["notice"]) # Apache 2 cc_library( name = "googletest", hdrs = glob([ "thirdparty_build/include/gmock/**/*.h", "thirdparty_build/include/gtest/**/*.h", ]), copts = ["-I/usr/include/gtest"], linkopts = [ "-lgmock", "-lgmock_main", "-lgtest", "-lgtest_main", ], visibility = ["//visibility:public"], linkstatic=False, ) ++++++ jwt_verify_lib-20181125.tar.xz -> jwt_verify_lib-20190708.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/BUILD new/jwt_verify_lib-20190708/BUILD --- old/jwt_verify_lib-20181125/BUILD 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/BUILD 2019-07-08 18:31:22.000000000 +0200 @@ -11,6 +11,7 @@ "src/jwks.cc", "src/jwt.cc", "src/status.cc", + "src/struct_utils.h", "src/verify.cc", ], hdrs = [ @@ -23,7 +24,7 @@ deps = [ "//external:abseil_strings", "//external:abseil_time", - "//external:rapidjson", + "//external:protobuf", "//external:ssl", ], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/WORKSPACE new/jwt_verify_lib-20190708/WORKSPACE --- old/jwt_verify_lib-20181125/WORKSPACE 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/WORKSPACE 2019-07-08 18:31:22.000000000 +0200 @@ -2,12 +2,12 @@ "//:repositories.bzl", "boringssl_repositories", "googletest_repositories", - "rapidjson_repositories", "abseil_repositories", + "protobuf_repositories", ) boringssl_repositories() googletest_repositories() -rapidjson_repositories() abseil_repositories() +protobuf_repositories() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/jwt_verify_lib/jwt.h new/jwt_verify_lib-20190708/jwt_verify_lib/jwt.h --- old/jwt_verify_lib-20181125/jwt_verify_lib/jwt.h 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/jwt_verify_lib/jwt.h 2019-07-08 18:31:22.000000000 +0200 @@ -17,7 +17,7 @@ #include <string> #include <vector> -#include "rapidjson/document.h" +#include "google/protobuf/struct.pb.h" #include "jwt_verify_lib/status.h" @@ -35,15 +35,15 @@ std::string header_str_; // header base64_url encoded std::string header_str_base64url_; - // header JSON object - rapidjson::Document header_json_; + // header in Struct protobuf + ::google::protobuf::Struct header_pb_; // payload string std::string payload_str_; // payload base64_url encoded std::string payload_str_base64url_; - // payload JSON object - rapidjson::Document payload_json_; + // payload in Struct protobuf + ::google::protobuf::Struct payload_pb_; // signature string std::string signature_; // alg @@ -57,11 +57,11 @@ // sub std::string sub_; // issued at - int64_t iat_ = 0; + uint64_t iat_ = 0; // not before - int64_t nbf_ = 0; + uint64_t nbf_ = 0; // expiration - int64_t exp_ = 0; + uint64_t exp_ = 0; // JWT ID std::string jti_; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/jwt_verify_lib/verify.h new/jwt_verify_lib-20190708/jwt_verify_lib/verify.h --- old/jwt_verify_lib-20181125/jwt_verify_lib/verify.h 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/jwt_verify_lib/verify.h 2019-07-08 18:31:22.000000000 +0200 @@ -42,7 +42,7 @@ * @param now is the number of seconds since the unix epoch * @return the verification status */ -Status verifyJwt(const Jwt& jwt, const Jwks& jwks, int64_t now); +Status verifyJwt(const Jwt& jwt, const Jwks& jwks, uint64_t now); /** * This function verifies JWT signature is valid, that it has not expired @@ -74,7 +74,7 @@ * @return the verification status */ Status verifyJwt(const Jwt& jwt, const Jwks& jwks, - const std::vector<std::string>& audiences, int64_t now); + const std::vector<std::string>& audiences, uint64_t now); } // namespace jwt_verify } // namespace google diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/repositories.bzl new/jwt_verify_lib-20190708/repositories.bzl --- old/jwt_verify_lib-20181125/repositories.bzl 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/repositories.bzl 2019-07-08 18:31:22.000000000 +0200 @@ -3,7 +3,7 @@ BORINGSSL_COMMIT = "9df0c47bc034d60d73d216cd0e090707b3fbea58" # same as Envoy BORINGSSL_SHA256 = "86d0614bb9e6cb4e6444b83bb1f031755eff4bbe52cd8f4cd5720bb84a7ea9f5" -def boringssl_repositories(bind=True): +def boringssl_repositories(bind = True): http_archive( name = "boringssl", strip_prefix = "boringssl-" + BORINGSSL_COMMIT, @@ -20,7 +20,7 @@ GOOGLETEST_COMMIT = "43863938377a9ea1399c0596269e0890b5c5515a" GOOGLETEST_SHA256 = "7c8ece456ad588c30160429498e108e2df6f42a30888b3ec0abf5d9792d9d3a0" -def googletest_repositories(bind=True): +def googletest_repositories(bind = True): http_archive( name = "googletest_git", build_file = "//:googletest.BUILD", @@ -45,28 +45,10 @@ actual = "@googletest_git//:googletest_prod", ) -RAPIDJSON_COMMIT = "f54b0e47a08782a6131cc3d60f94d038fa6e0a51" -RAPIDJSON_SHA256 = "4a76453d36770c9628d7d175a2e9baccbfbd2169ced44f0cb72e86c5f5f2f7cd" - -def rapidjson_repositories(bind=True): - http_archive( - name = "com_github_tencent_rapidjson", - build_file = "//:rapidjson.BUILD", - strip_prefix = "rapidjson-" + RAPIDJSON_COMMIT, - url = "https://github.com/tencent/rapidjson/archive/" + RAPIDJSON_COMMIT + ".tar.gz", - sha256 = RAPIDJSON_SHA256, - ) - - if bind: - native.bind( - name = "rapidjson", - actual = "@com_github_tencent_rapidjson//:rapidjson", - ) - ABSEIL_COMMIT = "cc8dcd307b76a575d2e3e0958a4fe4c7193c2f68" # same as Envoy ABSEIL_SHA256 = "e35082e88b9da04f4d68094c05ba112502a5063712f3021adfa465306d238c76" -def abseil_repositories(bind=True): +def abseil_repositories(bind = True): http_archive( name = "com_google_absl", strip_prefix = "abseil-cpp-" + ABSEIL_COMMIT, @@ -88,9 +70,38 @@ CCTZ_COMMIT = "e19879df3a14791b7d483c359c4acd6b2a1cd96b" CCTZ_SHA256 = "35d2c6cf7ddef1cf7c1bb054bdf2e8d7778242f6d199591a834c14d224b80c39" -def _cctz_repositories(bind=True): +def _cctz_repositories(bind = True): http_archive( name = "com_googlesource_code_cctz", url = "https://github.com/google/cctz/archive/" + CCTZ_COMMIT + ".tar.gz", sha256 = CCTZ_SHA256, - ) \ No newline at end of file + ) + +BAZEL_SKYLIB_RELEASE = "0.5.0" +BAZEL_SKYLIB_SHA256 = "b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f" + +def _bazel_skylib_repositories(): + http_archive( + name = "bazel_skylib", + sha256 = BAZEL_SKYLIB_SHA256, + strip_prefix = "bazel-skylib-" + BAZEL_SKYLIB_RELEASE, + url = "https://github.com/bazelbuild/bazel-skylib/archive/" + BAZEL_SKYLIB_RELEASE + ".tar.gz", + ) + +PROTOBUF_COMMIT = "fa252ec2a54acb24ddc87d48fed1ecfd458445fd" +PROTOBUF_SHA256 = "3d610ac90f8fa16e12490088605c248b85fdaf23114ce4b3605cdf81f7823604" + +def protobuf_repositories(bind = True): + _bazel_skylib_repositories() + http_archive( + name = "com_google_protobuf", + strip_prefix = "protobuf-" + PROTOBUF_COMMIT, + url = "https://github.com/protocolbuffers/protobuf/archive/" + PROTOBUF_COMMIT + ".tar.gz", + sha256 = PROTOBUF_SHA256, + ) + + if bind: + native.bind( + name = "protobuf", + actual = "@com_google_protobuf//:protobuf", + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/jwks.cc new/jwt_verify_lib-20190708/src/jwks.cc --- old/jwt_verify_lib-20181125/src/jwks.cc 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/jwks.cc 2019-07-08 18:31:22.000000000 +0200 @@ -15,10 +15,11 @@ #include <assert.h> #include <iostream> -#include "jwt_verify_lib/jwks.h" - #include "absl/strings/escaping.h" -#include "rapidjson/document.h" +#include "google/protobuf/struct.pb.h" +#include "google/protobuf/util/json_util.h" +#include "jwt_verify_lib/jwks.h" +#include "src/struct_utils.h" #include "openssl/bn.h" #include "openssl/ecdsa.h" @@ -134,100 +135,96 @@ } }; -Status extractJwkFromJwkRSA(const rapidjson::Value& jwk_json, +Status extractJwkFromJwkRSA(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) { if (jwk->alg_specified_ && (jwk->alg_.size() < 2 || jwk->alg_.compare(0, 2, "RS") != 0)) { return Status::JwksRSAKeyBadAlg; } - if (!jwk_json.HasMember("n")) { + StructUtils jwk_getter(jwk_pb); + std::string n_str; + auto code = jwk_getter.GetString("n", &n_str); + if (code == StructUtils::MISSING) { return Status::JwksRSAKeyMissingN; } - const auto& n_value = jwk_json["n"]; - if (!n_value.IsString()) { + if (code == StructUtils::WRONG_TYPE) { return Status::JwksRSAKeyBadN; } - std::string n_str = n_value.GetString(); - if (!jwk_json.HasMember("e")) { + std::string e_str; + code = jwk_getter.GetString("e", &e_str); + if (code == StructUtils::MISSING) { return Status::JwksRSAKeyMissingE; } - const auto& e_value = jwk_json["e"]; - if (!e_value.IsString()) { + if (code == StructUtils::WRONG_TYPE) { return Status::JwksRSAKeyBadE; } - std::string e_str = e_value.GetString(); EvpPkeyGetter e; jwk->evp_pkey_ = e.createEvpPkeyFromJwkRSA(n_str, e_str); return e.getStatus(); } -Status extractJwkFromJwkEC(const rapidjson::Value& jwk_json, +Status extractJwkFromJwkEC(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) { if (jwk->alg_specified_ && jwk->alg_ != "ES256") { return Status::JwksECKeyBadAlg; } - if (!jwk_json.HasMember("x")) { + StructUtils jwk_getter(jwk_pb); + std::string x_str; + auto code = jwk_getter.GetString("x", &x_str); + if (code == StructUtils::MISSING) { return Status::JwksECKeyMissingX; } - const auto& x_value = jwk_json["x"]; - if (!x_value.IsString()) { + if (code == StructUtils::WRONG_TYPE) { return Status::JwksECKeyBadX; } - std::string x_str = x_value.GetString(); - if (!jwk_json.HasMember("y")) { + std::string y_str; + code = jwk_getter.GetString("y", &y_str); + if (code == StructUtils::MISSING) { return Status::JwksECKeyMissingY; } - const auto& y_value = jwk_json["y"]; - if (!y_value.IsString()) { + if (code == StructUtils::WRONG_TYPE) { return Status::JwksECKeyBadY; } - std::string y_str = y_value.GetString(); EvpPkeyGetter e; jwk->ec_key_ = e.createEcKeyFromJwkEC(x_str, y_str); return e.getStatus(); } -Status extractJwk(const rapidjson::Value& jwk_json, Jwks::Pubkey* jwk) { +Status extractJwk(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) { + StructUtils jwk_getter(jwk_pb); // Check "kty" parameter, it should exist. // https://tools.ietf.org/html/rfc7517#section-4.1 - if (!jwk_json.HasMember("kty")) { + auto code = jwk_getter.GetString("kty", &jwk->kty_); + if (code == StructUtils::MISSING) { return Status::JwksMissingKty; } - const auto& kty_value = jwk_json["kty"]; - if (!kty_value.IsString()) { + if (code == StructUtils::WRONG_TYPE) { return Status::JwksBadKty; } - jwk->kty_ = kty_value.GetString(); // "kid" and "alg" are optional, if they do not exist, set them to empty. // https://tools.ietf.org/html/rfc7517#page-8 - if (jwk_json.HasMember("kid")) { - const auto& kid_value = jwk_json["kid"]; - if (kid_value.IsString()) { - jwk->kid_ = kid_value.GetString(); - jwk->kid_specified_ = true; - } - } - if (jwk_json.HasMember("alg")) { - const auto& alg_value = jwk_json["alg"]; - if (alg_value.IsString()) { - jwk->alg_ = alg_value.GetString(); - jwk->alg_specified_ = true; - } + code = jwk_getter.GetString("kid", &jwk->kid_); + if (code == StructUtils::OK) { + jwk->kid_specified_ = true; + } + code = jwk_getter.GetString("alg", &jwk->alg_); + if (code == StructUtils::OK) { + jwk->alg_specified_ = true; } // Extract public key according to "kty" value. // https://tools.ietf.org/html/rfc7518#section-6.1 if (jwk->kty_ == "EC") { - return extractJwkFromJwkEC(jwk_json, jwk); + return extractJwkFromJwkEC(jwk_pb, jwk); } else if (jwk->kty_ == "RSA") { - return extractJwkFromJwkRSA(jwk_json, jwk); + return extractJwkFromJwkRSA(jwk_pb, jwk); } return Status::JwksNotImplementedKty; } @@ -262,28 +259,35 @@ } } -void Jwks::createFromJwksCore(const std::string& pkey_jwks) { +void Jwks::createFromJwksCore(const std::string& jwks_json) { keys_.clear(); - rapidjson::Document jwks_json; - if (jwks_json.Parse(pkey_jwks.c_str()).HasParseError()) { + ::google::protobuf::util::JsonParseOptions options; + ::google::protobuf::Struct jwks_pb; + const auto status = ::google::protobuf::util::JsonStringToMessage( + jwks_json, &jwks_pb, options); + if (!status.ok()) { updateStatus(Status::JwksParseError); return; } - if (!jwks_json.HasMember("keys")) { + const auto& fields = jwks_pb.fields(); + const auto keys_it = fields.find("keys"); + if (keys_it == fields.end()) { updateStatus(Status::JwksNoKeys); return; } - const auto& keys_value = jwks_json["keys"]; - if (!keys_value.IsArray()) { + if (keys_it->second.kind_case() != google::protobuf::Value::kListValue) { updateStatus(Status::JwksBadKeys); return; } - for (auto key_it = keys_value.Begin(); key_it != keys_value.End(); ++key_it) { + for (const auto& key_value : keys_it->second.list_value().values()) { + if (key_value.kind_case() != ::google::protobuf::Value::kStructValue) { + continue; + } PubkeyPtr key_ptr(new Pubkey()); - Status status = extractJwk(*key_it, key_ptr.get()); + Status status = extractJwk(key_value.struct_value(), key_ptr.get()); if (status == Status::Ok) { keys_.push_back(std::move(key_ptr)); } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/jwks_test.cc new/jwt_verify_lib-20190708/src/jwks_test.cc --- old/jwt_verify_lib-20181125/src/jwks_test.cc 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/jwks_test.cc 2019-07-08 18:31:22.000000000 +0200 @@ -267,6 +267,55 @@ EXPECT_EQ(jwks->getStatus(), Status::JwksRsaParseError); } +TEST(JwksParseTest, JwksRSAInvalidN) { + const std::string BadPublicKeyRSA = + "{\n" + " \"keys\": [\n" + " {\n" + " \"alg\": \"RS256\",\n" + " \"kty\": \"RSA\",\n" + " \"use\": \"sig\",\n" + " \"x5c\": " + "[\"MIIDjjCCAnYCCQDM2dGMrJDL3TANBgkqhkiG9w0BAQUFADCBiDEVMBMGA1UEAwwMd3d3L" + "mRlbGwuY29tMQ0wCwYDVQQKDARkZWxsMQ0wCwYDVQQLDARkZWxsMRIwEAYDVQQHDAlCYW5nY" + "WxvcmUxEjAQBgNVBAgMCUthcm5hdGFrYTELMAkGA1UEBhMCSU4xHDAaBgkqhkiG9w0BCQEWD" + "WFiaGlAZGVsbC5jb20wHhcNMTkwNjI1MDcwNjM1WhcNMjAwNjI0MDcwNjM1WjCBiDEVMBMGA" + "1UEAwwMd3d3LmRlbGwuY29tMQ0wCwYDVQQKDARkZWxsMQ0wCwYDVQQLDARkZWxsMRIwEAYDV" + "QQHDAlCYW5nYWxvcmUxEjAQBgNVBAgMCUthcm5hdGFrYTELMAkGA1UEBhMCSU4xHDAaBgkqh" + "kiG9w0BCQEWDWFiaGlAZGVsbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBA" + "QDlE7W15NCXoIZX+" + "uE7HF0LTnfgBpaqoYyQFDmVUNEd0WWV9nX04c3iyxZSpoTsoUZktNd0CUyC8oVRg2xxdPxA2" + "aRVpNMwsDkuDnOZPNZZCS64QmMD7V5ebSAi4vQ7LH6zo9DCVwjzW10ZOZ3WHAyoKuNVGeb5w" + "2+xDQM1mFqApy6KB7M/b3KG7cqpZfPn9Ebd1Uyk+8WY/" + "IxJvb7EHt06Z+8b3F+LkRp7UI4ykkVkl3XaiBlG56ZyHfvH6R5Jy+" + "8P0vl4wtX86N6MS48TZPhGAoo2KwWsOEGxve005ZK6LkHwxMsOD98yvLM7AG0SBxVF8O8KeZ" + "/nbTP1oVSq6aEFAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAGEhT6xuZqyZb/" + "K6aI61RYy4tnR92d97H+zcL9t9/" + "8FyH3qIAjIM9+qdr7dLLnVcNMmwiKzZpsBywno72z5gG4l6/TicBIJfI2BaG9JVdU3/" + "wscPlqazwI/" + "d1LvIkWSzrFQ2VdTPSYactPzGWddlx9QKU9cIKcNPcWdg0S0q1Khu8kejpJ+" + "EUtSMc8OonFV99r1juFzVPtwGihuc6R7T/" + "GnWgYLmhoCCaQKdLWn7FIyQH2WZ10CI6as+" + "zKkylDkVnbsJYFabvbgRrNNl4RGXXm5D0lk9cwo1Srd28wEhi35b8zb1p0eTamS6qTpjHtc6" + "DpgZK3MavFVdaFfR9bEYpHc=\"],\n" + " \"n\": " + "\"5RO1teTQl6CGV/" + "rhOxxdC0534AaWqqGMkBQ5lVDRHdFllfZ19OHN4ssWUqaE7KFGZLTXdAlMgvKFUYNscXT8QN" + "mkVaTTMLA5Lg5zmTzWWQkuuEJjA+1eXm0gIuL0Oyx+s6PQwlcI81tdGTmd1hwMqCrjVRnm+" + "cNvsQ0DNZhagKcuigezP29yhu3KqWXz5/" + "RG3dVMpPvFmPyMSb2+xB7dOmfvG9xfi5Eae1COMpJFZJd12ogZRuemch37x+" + "keScvvD9L5eMLV/OjejEuPE2T4RgKKNisFrDhBsb3tNOWSui5B8MTLDg/" + "fMryzOwBtEgcVRfDvCnmf520z9aFUqumhBQ\",\n" + " \"e\": \"AQAB\",\n" + " \"kid\": \"F46BB2F600BF3BBB53A324F12B290846\",\n" + " \"x5t\": \"F46BB2F600BF3BBB53A324F12B290846\"\n" + " }\n" + " ]\n" + "}"; + auto jwks = Jwks::createFrom(BadPublicKeyRSA, Jwks::JWKS); + EXPECT_EQ(jwks->getStatus(), Status::JwksRsaParseError); +} + } // namespace } // namespace jwt_verify } // namespace google diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/jwt.cc new/jwt_verify_lib-20190708/src/jwt.cc --- old/jwt_verify_lib-20181125/src/jwt.cc 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/jwt.cc 2019-07-08 18:31:22.000000000 +0200 @@ -16,16 +16,13 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_split.h" +#include "google/protobuf/util/json_util.h" #include "jwt_verify_lib/jwt.h" +#include "src/struct_utils.h" namespace google { namespace jwt_verify { -// Maximum Jwt size to prevent JSON parser attack: -// stack overflow crash if a document contains heavily nested arrays. -// [[... repeat 100,000 times ... [[[0]]]]]]]]]]]]]]]]]]]]]]]]]]].. -const size_t kMaxJwtSize = 8096; - Jwt::Jwt(const Jwt& instance) { *this = instance; } Jwt& Jwt::operator=(const Jwt& rhs) { @@ -34,9 +31,6 @@ } Status Jwt::parseFromString(const std::string& jwt) { - if (jwt.size() >= kMaxJwtSize) { - return Status::JwtBadFormat; - } // jwt must have exactly 2 dots if (std::count(jwt.begin(), jwt.end(), '.') != 2) { return Status::JwtBadFormat; @@ -54,26 +48,27 @@ return Status::JwtHeaderParseError; } - if (header_json_.Parse(header_str_.c_str()).HasParseError()) { + ::google::protobuf::util::JsonParseOptions options; + const auto header_status = ::google::protobuf::util::JsonStringToMessage( + header_str_, &header_pb_, options); + if (!header_status.ok()) { return Status::JwtHeaderParseError; } + StructUtils header_getter(header_pb_); // Header should contain "alg" and should be a string. - if (!header_json_.HasMember("alg") || !header_json_["alg"].IsString()) { + if (header_getter.GetString("alg", &alg_) != StructUtils::OK) { return Status::JwtHeaderBadAlg; } - alg_ = header_json_["alg"].GetString(); - if (alg_ != "RS256" && alg_ != "ES256") { + if (alg_ != "RS256" && alg_ != "ES256" && alg_ != "RS384" && + alg_ != "RS512") { return Status::JwtHeaderNotImplementedAlg; } // Header may contain "kid", should be a string if exists. - if (header_json_.HasMember("kid")) { - if (!header_json_["kid"].IsString()) { - return Status::JwtHeaderBadKid; - } - kid_ = header_json_["kid"].GetString(); + if (header_getter.GetString("kid", &kid_) == StructUtils::WRONG_TYPE) { + return Status::JwtHeaderBadKid; } // Parse payload json @@ -82,76 +77,39 @@ return Status::JwtPayloadParseError; } - if (payload_json_.Parse(payload_str_.c_str()).HasParseError()) { + const auto payload_status = ::google::protobuf::util::JsonStringToMessage( + payload_str_, &payload_pb_, options); + if (!payload_status.ok()) { return Status::JwtPayloadParseError; } - if (payload_json_.HasMember("iss")) { - if (payload_json_["iss"].IsString()) { - iss_ = payload_json_["iss"].GetString(); - } else { - return Status::JwtPayloadParseError; - } - } - if (payload_json_.HasMember("sub")) { - if (payload_json_["sub"].IsString()) { - sub_ = payload_json_["sub"].GetString(); - } else { - return Status::JwtPayloadParseError; - } - } - if (payload_json_.HasMember("iat")) { - if (payload_json_["iat"].IsInt64()) { - iat_ = payload_json_["iat"].GetInt64(); - } else { - return Status::JwtPayloadParseError; - } - } else { - iat_ = 0; - } - if (payload_json_.HasMember("nbf")) { - if (payload_json_["nbf"].IsInt64()) { - nbf_ = payload_json_["nbf"].GetInt64(); - } else { - return Status::JwtPayloadParseError; - } - } else { - nbf_ = 0; - } - if (payload_json_.HasMember("exp")) { - if (payload_json_["exp"].IsInt64()) { - exp_ = payload_json_["exp"].GetInt64(); - } else { - return Status::JwtPayloadParseError; - } - } else { - exp_ = 0; - } - if (payload_json_.HasMember("jti")) { - if (payload_json_["jti"].IsString()) { - jti_ = payload_json_["jti"].GetString(); - } else { - return Status::JwtPayloadParseError; - } + StructUtils payload_getter(payload_pb_); + if (payload_getter.GetString("iss", &iss_) == StructUtils::WRONG_TYPE) { + return Status::JwtPayloadParseError; + } + if (payload_getter.GetString("sub", &sub_) == StructUtils::WRONG_TYPE) { + return Status::JwtPayloadParseError; + } + + if (payload_getter.GetInt64("iat", &iat_) == StructUtils::WRONG_TYPE) { + return Status::JwtPayloadParseError; + } + if (payload_getter.GetInt64("nbf", &nbf_) == StructUtils::WRONG_TYPE) { + return Status::JwtPayloadParseError; + } + if (payload_getter.GetInt64("exp", &exp_) == StructUtils::WRONG_TYPE) { + return Status::JwtPayloadParseError; + } + + if (payload_getter.GetString("jti", &jti_) == StructUtils::WRONG_TYPE) { + return Status::JwtPayloadParseError; } // "aud" can be either string array or string. // Try as string array, read it as empty array if doesn't exist. - if (payload_json_.HasMember("aud")) { - const auto& aud_value = payload_json_["aud"]; - if (aud_value.IsArray()) { - for (auto it = aud_value.Begin(); it != aud_value.End(); ++it) { - if (it->IsString()) { - audiences_.push_back(it->GetString()); - } else { - return Status::JwtPayloadParseError; - } - } - } else if (aud_value.IsString()) { - audiences_.push_back(aud_value.GetString()); - } else { - return Status::JwtPayloadParseError; - } + if (payload_getter.GetStringList("aud", &audiences_) == + StructUtils::WRONG_TYPE) { + return Status::JwtPayloadParseError; } // Set up signature diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/jwt_test.cc new/jwt_verify_lib-20190708/src/jwt_test.cc --- old/jwt_verify_lib-20181125/src/jwt_test.cc 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/jwt_test.cc 2019-07-08 18:31:22.000000000 +0200 @@ -13,7 +13,11 @@ // limitations under the License. #include "jwt_verify_lib/jwt.h" +#include "google/protobuf/util/message_differencer.h" #include "gtest/gtest.h" +#include "src/struct_utils.h" + +using google::protobuf::util::MessageDifferencer; #include <functional> #include <vector> @@ -43,19 +47,25 @@ EXPECT_EQ(jwt.alg_, "RS256"); EXPECT_EQ(jwt.kid_, ""); EXPECT_EQ(jwt.iss_, "https://example.com"); - EXPECT_TRUE(jwt.header_json_.HasMember("customheader")); - EXPECT_TRUE(jwt.header_json_["customheader"].IsString()); - EXPECT_EQ(jwt.header_json_["customheader"].GetString(), std::string("abc")); EXPECT_EQ(jwt.sub_, "[email protected]"); EXPECT_EQ(jwt.audiences_, std::vector<std::string>()); EXPECT_EQ(jwt.iat_, 1501281000); EXPECT_EQ(jwt.nbf_, 1501281000); EXPECT_EQ(jwt.exp_, 1501281058); EXPECT_EQ(jwt.jti_, std::string("identity")); - EXPECT_TRUE(jwt.payload_json_.HasMember("custompayload")); - EXPECT_TRUE(jwt.payload_json_["custompayload"].IsInt()); - EXPECT_EQ(jwt.payload_json_["custompayload"].GetInt(), 1234); EXPECT_EQ(jwt.signature_, "Signature"); + + StructUtils header_getter(jwt.header_pb_); + std::string str_value; + EXPECT_EQ(header_getter.GetString("customheader", &str_value), + StructUtils::OK); + EXPECT_EQ(str_value, std::string("abc")); + + StructUtils payload_getter(jwt.payload_pb_); + uint64_t int_value; + EXPECT_EQ(payload_getter.GetInt64("custompayload", &int_value), + StructUtils::OK); + EXPECT_EQ(int_value, 1234); } TEST(JwtParseTest, Copy) { @@ -81,8 +91,10 @@ EXPECT_EQ(ref.exp_, original.exp_); EXPECT_EQ(ref.jti_, original.jti_); EXPECT_EQ(ref.signature_, original.signature_); - EXPECT_EQ(ref.header_json_, original.header_json_); - EXPECT_EQ(ref.payload_json_, original.payload_json_); + EXPECT_TRUE( + MessageDifferencer::Equals(ref.header_pb_, original.header_pb_)); + EXPECT_TRUE( + MessageDifferencer::Equals(ref.payload_pb_, original.payload_pb_)); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/struct_utils.h new/jwt_verify_lib-20190708/src/struct_utils.h --- old/jwt_verify_lib-20181125/src/struct_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/struct_utils.h 2019-07-08 18:31:22.000000000 +0200 @@ -0,0 +1,90 @@ +// Copyright 2018 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 +// +// https://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.#pragma once + +#pragma once + +#include "google/protobuf/struct.pb.h" + +namespace google { +namespace jwt_verify { + +class StructUtils { + public: + StructUtils(const ::google::protobuf::Struct& struct_pb) + : struct_pb_(struct_pb) {} + + enum FindResult { + OK = 0, + MISSING, + WRONG_TYPE, + }; + + FindResult GetString(const std::string& name, std::string* value) { + const auto& fields = struct_pb_.fields(); + const auto it = fields.find(name); + if (it == fields.end()) { + return MISSING; + } + if (it->second.kind_case() != google::protobuf::Value::kStringValue) { + return WRONG_TYPE; + } + *value = it->second.string_value(); + return OK; + } + + FindResult GetInt64(const std::string& name, uint64_t* value) { + const auto& fields = struct_pb_.fields(); + const auto it = fields.find(name); + if (it == fields.end()) { + return MISSING; + } + if (it->second.kind_case() != google::protobuf::Value::kNumberValue) { + return WRONG_TYPE; + } + *value = static_cast<uint64_t>(it->second.number_value()); + return OK; + } + + // Get string or list of string, designed to get "aud" field + // "aud" can be either string array or string. + // Try as string array, read it as empty array if doesn't exist. + FindResult GetStringList(const std::string& name, + std::vector<std::string>* list) { + const auto& fields = struct_pb_.fields(); + const auto it = fields.find(name); + if (it == fields.end()) { + return MISSING; + } + if (it->second.kind_case() == google::protobuf::Value::kStringValue) { + list->push_back(it->second.string_value()); + return OK; + } + if (it->second.kind_case() == google::protobuf::Value::kListValue) { + for (const auto& v : it->second.list_value().values()) { + if (v.kind_case() != google::protobuf::Value::kStringValue) { + return WRONG_TYPE; + } + list->push_back(v.string_value()); + } + return OK; + } + return WRONG_TYPE; + } + + private: + const ::google::protobuf::Struct& struct_pb_; +}; + +} // namespace jwt_verify +} // namespace google diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/test_common.h new/jwt_verify_lib-20190708/src/test_common.h --- old/jwt_verify_lib-20181125/src/test_common.h 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/test_common.h 2019-07-08 18:31:22.000000000 +0200 @@ -37,12 +37,10 @@ } // truncate bytes - for (size_t pos = 0; pos < jwt.signature_.size(); ++pos) { - for (size_t count = 1; count < jwt.signature_.size() - pos; ++count) { - Jwt fuzz_jwt(jwt); - fuzz_jwt.signature_ = jwt.signature_.substr(pos, count); - test_fn(fuzz_jwt); - } + for (size_t count = 1; count < jwt.signature_.size(); ++count) { + Jwt fuzz_jwt(jwt); + fuzz_jwt.signature_ = jwt.signature_.substr(0, count); + test_fn(fuzz_jwt); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/verify.cc new/jwt_verify_lib-20190708/src/verify.cc --- old/jwt_verify_lib-20181125/src/verify.cc 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/verify.cc 2019-07-08 18:31:22.000000000 +0200 @@ -19,6 +19,7 @@ #include "openssl/bn.h" #include "openssl/ecdsa.h" +#include "openssl/err.h" #include "openssl/evp.h" #include "openssl/rsa.h" #include "openssl/sha.h" @@ -41,9 +42,16 @@ } bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_create()); - EVP_DigestVerifyInit(md_ctx.get(), nullptr, md, nullptr, key); - EVP_DigestVerifyUpdate(md_ctx.get(), signed_data, signed_data_len); - return (EVP_DigestVerifyFinal(md_ctx.get(), signature, signature_len) == 1); + if (EVP_DigestVerifyInit(md_ctx.get(), nullptr, md, nullptr, key) == 1) { + if (EVP_DigestVerifyUpdate(md_ctx.get(), signed_data, signed_data_len) == + 1) { + if (EVP_DigestVerifyFinal(md_ctx.get(), signature, signature_len) == 1) { + return true; + } + } + } + ERR_clear_error(); + return false; } bool verifySignatureRSA(EVP_PKEY* key, const EVP_MD* md, @@ -76,8 +84,12 @@ BN_bin2bn(signature + 32, 32, ecdsa_sig->s) == nullptr) { return false; } - return (ECDSA_do_verify(digest, SHA256_DIGEST_LENGTH, ecdsa_sig.get(), key) == - 1); + if (ECDSA_do_verify(digest, SHA256_DIGEST_LENGTH, ecdsa_sig.get(), key) == + 1) { + return true; + } + ERR_clear_error(); + return false; } bool verifySignatureEC(EC_KEY* key, absl::string_view signature, @@ -92,7 +104,7 @@ return verifyJwt(jwt, jwks, absl::ToUnixSeconds(absl::Now())); } -Status verifyJwt(const Jwt& jwt, const Jwks& jwks, int64_t now) { +Status verifyJwt(const Jwt& jwt, const Jwks& jwks, uint64_t now) { // First check that the JWT has not expired (exp) and is active (nbf). if (now < jwt.nbf_) { return Status::JwtNotYetValid; @@ -123,11 +135,22 @@ verifySignatureEC(jwk->ec_key_.get(), jwt.signature_, signed_data)) { // Verification succeeded. return Status::Ok; - } else if ((jwk->pem_format_ || jwk->kty_ == "RSA") && - verifySignatureRSA(jwk->evp_pkey_.get(), EVP_sha256(), - jwt.signature_, signed_data)) { - // Verification succeeded. - return Status::Ok; + } else if (jwk->pem_format_ || jwk->kty_ == "RSA") { + const EVP_MD* md; + if (jwt.alg_ == "RS384") { + md = EVP_sha384(); + } else if (jwt.alg_ == "RS512") { + md = EVP_sha512(); + } else { + // default to SHA256 + md = EVP_sha256(); + } + + if (verifySignatureRSA(jwk->evp_pkey_.get(), md, jwt.signature_, + signed_data)) { + // Verification succeeded. + return Status::Ok; + } } } @@ -142,7 +165,7 @@ } Status verifyJwt(const Jwt& jwt, const Jwks& jwks, - const std::vector<std::string>& audiences, int64_t now) { + const std::vector<std::string>& audiences, uint64_t now) { CheckAudience checker(audiences); if (!checker.areAudiencesAllowed(jwt.audiences_)) { return Status::JwtAudienceNotAllowed; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/verify_pem_test.cc new/jwt_verify_lib-20190708/src/verify_pem_test.cc --- old/jwt_verify_lib-20181125/src/verify_pem_test.cc 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/verify_pem_test.cc 2019-07-08 18:31:22.000000000 +0200 @@ -24,7 +24,7 @@ // Header: {"alg":"RS256","typ":"JWT"} // Payload: // {"iss":"https://example.com","sub":"[email protected]","exp":1501281058} -const std::string JwtPem = +const std::string JwtPemRs256 = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9." "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs" "ImV4cCI6MTUwMTI4MTA1OH0.FxT92eaBr9thDpeWaQh0YFhblVggn86DBpnTa_" @@ -34,6 +34,34 @@ "N09hdvlCtAF87Fu1qqfwEQ93A-J7m08bZJoyIPcNmTcYGHwfMR4-lcI5cC_93C_" "5BGE1FHPLOHpNghLuM6-rhOtgwZc9ywupn_bBK3QzuAoDnYwpqQhgQL_CdUD_bSHcmWFkw"; +// JWT with +// Header: {"alg":"RS384","typ":"JWT"} +// Payload: +// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058} +const std::string JwtPemRs384 = + "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9." + "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs" + "ImV4cCI6MTUwMTI4MTA1OH0.NvinWcCVmBAmbK5FnAPt8gMBSWOU9kjTEIxcDqJBzjB6nKGj" + "sUYF05RC69F4POrJKLl3ak9LQUFPAwn732xEavbQunl-MreZCtRKrTX2xdwod0_u3gvSakcc" + "N9kEkbXMqJ5DhFUH0Viv7oVQtbRzwB7hr0ip-Yi8RAbrKfk8qDX0bT2TOlqzbLDnIp3M5btX" + "vO1GfOirIiz0YDfzEmSbkhZAnz4D062LWwyfIfM1ZhFusSyYBaNjib1vBfjIGsiYW-ot9dRY" + "X0YZP1YF-XxalyUGalD6pn-5nOkd86KL8ch0OkxBpHc1XqBrrsw0Pjax6Sv-nYYUb9qN6p69" + "q9YstA"; + +// JWT with +// Header: {"alg":"RS512","typ":"JWT"} +// Payload: +// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058} +const std::string JwtPemRs512 = + "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9." + "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs" + "ImV4cCI6MTUwMTI4MTA1OH0.BaBGWBS5ZhOX7o0LlAYqnnS-rME0E_eAjnCzPolSY5oh-Mic" + "WFN3B1AW-iCeAW3fHf7GhlbshKoybLaj7Cj87m9T-w015WGyIBIwWKQVjfT62RJ1hrKzoyM5" + "flVbwMPG70vqV9xfOTpZ4iZ9QomAut4yMDSBTINeeQLRVckYUN-IQVLU-bMnnvabsIQeNxhs" + "sG6S61cOD234mGdgkxoaZhHDprvEtAaYAuuKsIlaNIbp8r5hYFv09SMjAELlneObiMI3m5IG" + "yx3cF3odgb8PPLRBEOxD6HwJzmvbYmkjmgLuE5vb5lLEacyn2I1ko7e-Hlzvp_ezST0wknz5" + "wadrCQ"; + const std::string PublicKeyPem = "MIIBCgKCAQEAtw7MNxUTxmzWROCD5BqJxmzT7xqc9KsnAjbXCoqEEHDx4WBlfcwk" "XHt9e/2+Uwi3Arz3FOMNKwGGlbr7clBY3utsjUs8BTF0kO/poAmSTdSuGeh2mSbc" @@ -42,9 +70,37 @@ "+hHYL6nqwOR3ej0VqCTLS0OloC0LuCpLV7CnSpwbp2Qg/c+MDzQ0TH8g8drIzR5h" "Fe9a3NlNRMXgUU5RqbLnR9zfXr7b9oEszQIDAQAB"; -TEST(VerifyPemTest, OKPem) { +TEST(VerifyPemTestRs256, OKPem) { + Jwt jwt; + EXPECT_EQ(jwt.parseFromString(JwtPemRs256), Status::Ok); + + auto jwks = Jwks::createFrom(PublicKeyPem, Jwks::Type::PEM); + EXPECT_EQ(jwks->getStatus(), Status::Ok); + + EXPECT_EQ(verifyJwt(jwt, *jwks, 1), Status::Ok); + + fuzzJwtSignature(jwt, [&jwks](const Jwt& jwt) { + EXPECT_EQ(verifyJwt(jwt, *jwks, 1), Status::JwtVerificationFail); + }); +} + +TEST(VerifyPemTestRs384, OKPem) { + Jwt jwt; + EXPECT_EQ(jwt.parseFromString(JwtPemRs384), Status::Ok); + + auto jwks = Jwks::createFrom(PublicKeyPem, Jwks::Type::PEM); + EXPECT_EQ(jwks->getStatus(), Status::Ok); + + EXPECT_EQ(verifyJwt(jwt, *jwks, 1), Status::Ok); + + fuzzJwtSignature(jwt, [&jwks](const Jwt& jwt) { + EXPECT_EQ(verifyJwt(jwt, *jwks, 1), Status::JwtVerificationFail); + }); +} + +TEST(VerifyPemTestRs512, OKPem) { Jwt jwt; - EXPECT_EQ(jwt.parseFromString(JwtPem), Status::Ok); + EXPECT_EQ(jwt.parseFromString(JwtPemRs512), Status::Ok); auto jwks = Jwks::createFrom(PublicKeyPem, Jwks::Type::PEM); EXPECT_EQ(jwks->getStatus(), Status::Ok); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwt_verify_lib-20181125/src/verify_time_test.cc new/jwt_verify_lib-20190708/src/verify_time_test.cc --- old/jwt_verify_lib-20181125/src/verify_time_test.cc 2018-11-25 02:41:06.000000000 +0100 +++ new/jwt_verify_lib-20190708/src/verify_time_test.cc 2019-07-08 18:31:22.000000000 +0200 @@ -41,7 +41,11 @@ Jwt jwt; Jwks jwks; EXPECT_EQ(jwt.parseFromString(JwtText), Status::Ok); - EXPECT_EQ(verifyJwt(jwt, jwks, 9223372036854775807), Status::JwtExpired); + // proto.Struct is using "double" for number_value. A big integer has been + // casted to double and back may not be the same. + // In this case, 9223372036854775806 become 9223372036854775808 + // so using 9223372036854775807 for the test will not work. + EXPECT_EQ(verifyJwt(jwt, jwks, 9223372036854775810U), Status::JwtExpired); } TEST(VerifyExpTest, NotBefore) { ++++++ opensslcbs.BUILD ++++++ licenses(["notice"]) # Apache 2 cc_library( name = "bssl_wrapper_lib", hdrs = glob(["thirdparty_build/include/opensslcbs/**/*.h"]), copts = ["-I/usr/include/opensslcbs"], linkopts = [ "-lopenssl_cbs_lib", ], visibility = ["//visibility:public"], linkstatic=False, ) ++++++ zlib.BUILD ++++++ licenses(["notice"]) # Apache 2 cc_library( name = "zlib", hdrs = glob([ "thirdparty_build/include/zconf.h", "thirdparty_build/include/zlib.h", ]), copts = [], linkopts = ["-lz"], visibility = ["//visibility:public"], linkstatic=False, )
