Hello community,

here is the log from the commit of package jwt_verify_lib for openSUSE:Factory 
checked in at 2020-01-17 16:07:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/jwt_verify_lib (Old)
 and      /work/SRC/openSUSE:Factory/.jwt_verify_lib.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "jwt_verify_lib"

Fri Jan 17 16:07:38 2020 rev:6 rq:765233 version:20191024

Changes:
--------
--- /work/SRC/openSUSE:Factory/jwt_verify_lib/jwt_verify_lib.changes    
2019-11-11 21:24:53.719856777 +0100
+++ /work/SRC/openSUSE:Factory/.jwt_verify_lib.new.26092/jwt_verify_lib.changes 
2020-01-17 16:07:59.420513935 +0100
@@ -1,0 +2,16 @@
+Tue Jan 14 10:43:14 UTC 2020 - [email protected]
+
+- Update to version 20191024:
+  * Add support for ES384 and ES512
+  * Add HS384 and HS512 support
+  * Clear openssl error queue if HMAC() fails
+  * Add HS256 support
+- Add source package, remove lib* and devel package - now it's not
+  possible to build jwt_verify_lib outside envoy-proxy's source
+  tree.
+- Remove Maistra sources:
+  * jwt-verify-lib-openssl-20190806.tar.xz
+- Add patch which adds compatibility with OpenSSL:
+  * jwt_verify-make-compatible-with-openssl.patch
+
+-------------------------------------------------------------------

Old:
----
  jwt-verify-lib-openssl-20190806.tar.xz
  jwt_verify_lib-20190909.tar.xz

New:
----
  jwt_verify-make-compatible-with-openssl.patch
  jwt_verify_lib-20191024.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ jwt_verify_lib.spec ++++++
--- /var/tmp/diff_new_pack.cmEtsx/_old  2020-01-17 16:07:59.928514175 +0100
+++ /var/tmp/diff_new_pack.cmEtsx/_new  2020-01-17 16:07:59.932514177 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package jwt_verify_lib
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,117 +16,47 @@
 #
 
 
-%define sover 0
-%define libname lib%{name}%{sover}
-%define maistra_name jwt-verify-lib-openssl
-%define maistra_version 20190806
+%define src_install_dir /usr/src/%{name}
 
 Name:           jwt_verify_lib
-Version:        20190909
+Version:        20191024
 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}
 Source0:        %{name}-%{version}.tar.xz
-Source1:        %{maistra_name}-%{maistra_version}.tar.xz
-BuildRequires:  abseil-cpp-source
-BuildRequires:  bazel-rules-cc-source
-BuildRequires:  bazel-rules-java-source
-BuildRequires:  bazel-rules-proto-source
-BuildRequires:  bazel-skylib-source
-BuildRequires:  bazel-workspaces
-BuildRequires:  bazel0.29
-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
+Patch0:         jwt_verify-make-compatible-with-openssl.patch
+BuildRequires:  fdupes
+BuildArch:      noarch
 
 %description
 jwt_verify_lib is a library which verifies JSON Web Tokens. It does not provide
 any other features like signing or advanced checks.
 
-%package -n %{libname}
-Summary:        JSON web token verification library for C++
-Group:          System/Libraries
+%package source
+Summary:        Source code of jwt_verify_lib
+Group:          Development/Sources
 
-%description -n %{libname}
+%description source
 jwt_verify_lib is a library which verifies JSON Web Tokens. It does not provide
 any other features like signing or advanced checks.
 
-This package contains shared library for jwt_verify_lib.
-
-%package devel
-Summary:        Development files for jwt_verify_lib
-Group:          Development/Libraries/C and C++
-Requires:       %{libname} = %{version}
-
-%description devel
-jwt_verify_lib is a library which verifies JSON Web Tokens. It does not provide
-any other features like signing or advanced checks.
-
-This package contains development files for jwt_verify_lib.
+This package contains source code of jwt_verify_lib.
 
 %prep
-%setup -q -D -b 1 -n %{maistra_name}-%{maistra_version}
-%setup -q
-pushd ../%{maistra_name}-%{maistra_version}
-sed -i "s|\"src/struct_utils.h\"|\"jwt_verify_lib/struct_utils.h\"|g" 
src/jwks.cc
-sed -i "s|\"src/struct_utils.h\"|\"jwt_verify_lib/struct_utils.h\"|g" 
src/jwt.cc
-./openssl.sh ../%{name}-%{version} SSL
-popd
+%autosetup -p1
 
 %build
-# TODO(mrostecki): Create a macro in bazel package.
-TARGETS=$(bazel query '//... except kind(.*test, //...)')
-bazel build \
-    -c dbg \
-    --color=no \
-    %(for opt in %{optflags}; do echo -e "--copt=${opt} \c"; done) \
-    --curses=no \
-    --distdir=%{_sourcedir} \
-    --genrule_strategy=standalone \
-    --host_javabase=@local_jdk//:jdk \
-    --linkopt="-Wl,-soname,libjwt_verify_lib.so.%{sover}" \
-    --override_repository="bazel_skylib=/usr/src/bazel-skylib" \
-    --override_repository="com_google_absl=/usr/src/abseil-cpp" \
-    --override_repository="com_google_protobuf=/usr/src/protobuf" \
-    
--override_repository="googletest_git=%{_datadir}/bazel-workspaces/googletest" \
-    --override_repository="rules_cc=/usr/src/bazel-rules-cc" \
-    --override_repository="rules_java=/usr/src/bazel-rules-java" \
-    --override_repository="rules_proto=/usr/src/bazel-rules-proto" \
-    --spawn_strategy=standalone \
-    --strip=never \
-    --verbose_failures \
-    ${TARGETS}
-bazel shutdown
 
 %install
-install -D -m755 bazel-bin/libjwt_verify_lib.so 
%{buildroot}%{_libdir}/libjwt_verify_lib.so.%{sover}
-ln -sf libjwt_verify_lib.so.%{sover} 
%{buildroot}%{_libdir}/libjwt_verify_lib.so
-find jwt_verify_lib -type f -execdir install -D -m0644 "{}" 
"%{buildroot}%{_includedir}/jwt_verify_lib/{}" \;
+mkdir -p %{buildroot}%{src_install_dir}
+cp -r * %{buildroot}%{src_install_dir}
+%fdupes %{buildroot}%{src_install_dir}
 
-%post -n %{libname} -p /sbin/ldconfig
-%postun -n %{libname} -p /sbin/ldconfig
-
-%files -n %{libname}
+%files source
 %license LICENSE
 %doc README.md
-%{_libdir}/libjwt_verify_lib.so.%{sover}
-
-%files devel
-%{_includedir}/jwt_verify_lib
-%{_includedir}/jwt_verify_lib/check_audience.h
-%{_includedir}/jwt_verify_lib/jwks.h
-%{_includedir}/jwt_verify_lib/jwt.h
-%{_includedir}/jwt_verify_lib/status.h
-%{_includedir}/jwt_verify_lib/verify.h
-%{_libdir}/libjwt_verify_lib.so
+%{src_install_dir}
 
 %changelog

++++++ _service ++++++
--- /var/tmp/diff_new_pack.cmEtsx/_old  2020-01-17 16:07:59.960514190 +0100
+++ /var/tmp/diff_new_pack.cmEtsx/_new  2020-01-17 16:07:59.960514190 +0100
@@ -5,15 +5,7 @@
     <param name="changesgenerate">enable</param>
     <param name="filename">jwt_verify_lib</param>
     <param name="versionformat">%cd</param>
-    <param name="revision">2866385faa2508a11071d075f788172b3f3bd27f</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">maistra-1.1</param>
+    <param name="revision">9f10e2d60d42edeb6662e185707a7d6a4ebc5604</param>
   </service>
   <service mode="disabled" name="recompress">
     <param name="file">*.tar</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.cmEtsx/_old  2020-01-17 16:07:59.976514197 +0100
+++ /var/tmp/diff_new_pack.cmEtsx/_new  2020-01-17 16:07:59.976514197 +0100
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/google/jwt_verify_lib</param>
-              <param 
name="changesrevision">5552dbc736a25da7e264b260d5ba3cedc33a71f8</param></service></servicedata>
\ No newline at end of file
+              <param 
name="changesrevision">4d9461344d9768c3cd05f8d90d4518b83d113f9d</param></service></servicedata>
\ No newline at end of file

++++++ jwt_verify-make-compatible-with-openssl.patch ++++++
>From b0e4badb4158934c8ec102dccc26adf3b478e6e5 Mon Sep 17 00:00:00 2001
From: Venil Noronha <[email protected]>
Date: Fri, 1 Nov 2019 10:10:10 -0700
Subject: [PATCH] make compatible with openssl

Signed-off-by: Venil Noronha <[email protected]>
---
 BUILD                 |  4 +++-
 jwt_verify_lib/jwks.h |  4 ++++
 src/jwks.cc           | 20 ++++++++++++++++----
 src/verify.cc         | 13 +++++++++++--
 4 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/BUILD b/BUILD
index 60331dc..bd55255 100644
--- a/BUILD
+++ b/BUILD
@@ -27,6 +27,8 @@ cc_library(
         "//external:abseil_time",
         "//external:protobuf",
         "//external:ssl",
+        "@envoy_openssl//boringssl_compat:bssl_compat_cbs_lib",
+        "@envoy_openssl//boringssl_compat:bssl_compat_lib",
     ],
 )
 
diff --git a/jwt_verify_lib/jwks.h b/jwt_verify_lib/jwks.h
index 24a18b7..80676da 100644
--- a/jwt_verify_lib/jwks.h
+++ b/jwt_verify_lib/jwks.h
@@ -22,6 +22,10 @@
 #include "openssl/ec.h"
 #include "openssl/evp.h"
 
+#ifndef OPENSSL_IS_BORINGSSL
+#include "boringssl_compat/bssl.h"
+#endif
+
 namespace google {
 namespace jwt_verify {
 
diff --git a/src/jwks.cc b/src/jwks.cc
index 97b1ae8..9723c82 100644
--- a/src/jwks.cc
+++ b/src/jwks.cc
@@ -27,6 +27,11 @@
 #include "openssl/rsa.h"
 #include "openssl/sha.h"
 
+#ifndef OPENSSL_IS_BORINGSSL
+#include "boringssl_compat/cbs.h"
+using namespace Envoy::Extensions::Common::Cbs;
+#endif
+
 namespace google {
 namespace jwt_verify {
 
@@ -118,18 +123,25 @@ class EvpPkeyGetter : public WithStatus {
   bssl::UniquePtr<RSA> createRsaFromJwk(const std::string& n,
                                         const std::string& e) {
     bssl::UniquePtr<RSA> rsa(RSA_new());
-    rsa->n = createBigNumFromBase64UrlString(n).release();
-    rsa->e = createBigNumFromBase64UrlString(e).release();
-    if (rsa->n == nullptr || rsa->e == nullptr) {
+    BIGNUM* n_bn;
+    BIGNUM* e_bn;
+    n_bn = createBigNumFromBase64UrlString(n).release();
+    e_bn = createBigNumFromBase64UrlString(e).release();
+    if (n_bn == nullptr || e_bn == nullptr) {
       // RSA public key field is missing or has parse error.
       updateStatus(Status::JwksRsaParseError);
       return nullptr;
     }
-    if (BN_cmp_word(rsa->e, 3) != 0 && BN_cmp_word(rsa->e, 65537) != 0) {
+    if (BN_cmp_word(e_bn, 3) != 0 && BN_cmp_word(e_bn, 65537) != 0) {
       // non-standard key; reject it early.
       updateStatus(Status::JwksRsaParseError);
       return nullptr;
     }
+    if (!RSA_set0_key(rsa.get(), n_bn, e_bn, NULL)) {
+      // can't set RSA key; reject it early.
+      updateStatus(Status::JwksRsaParseError);
+      return nullptr;
+    }
     return rsa;
   }
 };
diff --git a/src/verify.cc b/src/verify.cc
index 4d26c25..10fb175 100644
--- a/src/verify.cc
+++ b/src/verify.cc
@@ -22,7 +22,13 @@
 #include "openssl/err.h"
 #include "openssl/evp.h"
 #include "openssl/hmac.h"
+
+#ifdef OPENSSL_IS_BORINGSSL
 #include "openssl/mem.h"
+#else
+#include "openssl/crypto.h"
+#endif
+
 #include "openssl/rsa.h"
 #include "openssl/sha.h"
 
@@ -91,9 +97,12 @@ bool verifySignatureEC(EC_KEY* key, const EVP_MD* md, const 
uint8_t* signature,
     return false;
   }
 
-  if (BN_bin2bn(signature, signature_len / 2, ecdsa_sig->r) == nullptr ||
+  const BIGNUM* r_bn;
+  const BIGNUM* s_bn;
+  ECDSA_SIG_get0(ecdsa_sig.get(), &r_bn, &s_bn);
+  if (BN_bin2bn(signature, signature_len / 2, const_cast<BIGNUM *>(r_bn)) == 
nullptr ||
       BN_bin2bn(signature + (signature_len / 2), signature_len / 2,
-                ecdsa_sig->s) == nullptr) {
+                const_cast<BIGNUM *>(s_bn)) == nullptr) {
     return false;
   }
 
-- 
2.14.3 (Apple Git-98)

++++++ jwt_verify_lib-20190909.tar.xz -> jwt_verify_lib-20191024.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/BUILD 
new/jwt_verify_lib-20191024/BUILD
--- old/jwt_verify_lib-20190909/BUILD   2019-09-09 18:18:10.000000000 +0200
+++ new/jwt_verify_lib-20191024/BUILD   2019-10-24 19:42:38.000000000 +0200
@@ -162,3 +162,20 @@
         "//external:googletest_main",
     ],
 )
+
+cc_test(
+    name = "verify_jwk_hmac_test",
+    srcs = [
+        "src/test_common.h",
+        "src/verify_jwk_hmac_test.cc",
+    ],
+    linkopts = [
+        "-lm",
+        "-lpthread",
+    ],
+    linkstatic = 1,
+    deps = [
+        ":jwt_verify_lib",
+        "//external:googletest_main",
+    ],
+)
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/jwt_verify_lib/jwks.h 
new/jwt_verify_lib-20191024/jwt_verify_lib/jwks.h
--- old/jwt_verify_lib-20190909/jwt_verify_lib/jwks.h   2019-09-09 
18:18:10.000000000 +0200
+++ new/jwt_verify_lib-20191024/jwt_verify_lib/jwks.h   2019-10-24 
19:42:38.000000000 +0200
@@ -44,9 +44,11 @@
   struct Pubkey {
     bssl::UniquePtr<EVP_PKEY> evp_pkey_;
     bssl::UniquePtr<EC_KEY> ec_key_;
+    std::string hmac_key_;
     std::string kid_;
     std::string kty_;
     std::string alg_;
+    std::string crv_;
     bool alg_specified_ = false;
     bool kid_specified_ = false;
     bool pem_format_ = false;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/jwt_verify_lib/status.h 
new/jwt_verify_lib-20191024/jwt_verify_lib/status.h
--- old/jwt_verify_lib-20190909/jwt_verify_lib/status.h 2019-09-09 
18:18:10.000000000 +0200
+++ new/jwt_verify_lib-20191024/jwt_verify_lib/status.h 2019-10-24 
19:42:38.000000000 +0200
@@ -98,6 +98,9 @@
   // "x" or "y" field of a Jwk EC is missing or has a parse error.
   JwksEcParseError,
 
+  // Jwks Oct key is an invalid Base64.
+  JwksOctBadBase64,
+
   // Failed to fetch public key
   JwksFetchFail,
 
@@ -119,8 +122,12 @@
   // "e" field is not string for a RSA key
   JwksRSAKeyBadE,
 
-  // "alg" is not "ES256" for an EC key
+  // "alg" is not "ES256", "ES384" or "ES512" for an EC key
   JwksECKeyBadAlg,
+  // "crv" field is not string for an EC key
+  JwksECKeyBadCrv,
+  // "crv" is not compatible with "alg" for an EC key
+  JwksECKeyAlgNotCompatibleWithCrv,
   // "x" field is missing for an EC key
   JwksECKeyMissingX,
   // "x" field is not string for an EC key
@@ -129,6 +136,13 @@
   JwksECKeyMissingY,
   // "y" field is not string for an EC key
   JwksECKeyBadY,
+
+  // "alg" is not "HS256", "HS384" or "HS512" for an HMAC key
+  JwksHMACKeyBadAlg,
+  // "k" field is missing for an HMAC key
+  JwksHMACKeyMissingK,
+  // "k" field is not string for an HMAC key
+  JwksHMACKeyBadK,
 };
 
 /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/src/jwks.cc 
new/jwt_verify_lib-20191024/src/jwks.cc
--- old/jwt_verify_lib-20190909/src/jwks.cc     2019-09-09 18:18:10.000000000 
+0200
+++ new/jwt_verify_lib-20191024/src/jwks.cc     2019-10-24 19:42:38.000000000 
+0200
@@ -72,10 +72,9 @@
     return createEvpPkeyFromRsa(createRsaFromJwk(n, e).get());
   }
 
-  bssl::UniquePtr<EC_KEY> createEcKeyFromJwkEC(const std::string& x,
+  bssl::UniquePtr<EC_KEY> createEcKeyFromJwkEC(int nid, const std::string& x,
                                                const std::string& y) {
-    bssl::UniquePtr<EC_KEY> ec_key(
-        EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(nid));
     if (!ec_key) {
       updateStatus(Status::JwksEcCreateKeyFail);
       return nullptr;
@@ -168,13 +167,41 @@
 
 Status extractJwkFromJwkEC(const ::google::protobuf::Struct& jwk_pb,
                            Jwks::Pubkey* jwk) {
-  if (jwk->alg_specified_ && jwk->alg_ != "ES256") {
+  // since "alg" is optional, assume "ES256" if it was not specified
+  if (!jwk->alg_specified_) {
+    jwk->alg_ = "ES256";
+  } else if (jwk->alg_.size() < 2 || jwk->alg_.compare(0, 2, "ES") != 0) {
     return Status::JwksECKeyBadAlg;
   }
 
   StructUtils jwk_getter(jwk_pb);
+  std::string crv_str;
+  auto code = jwk_getter.GetString("crv", &crv_str);
+  if (code == StructUtils::MISSING) {
+    crv_str = "";
+  }
+  if (code == StructUtils::WRONG_TYPE) {
+    return Status::JwksECKeyBadCrv;
+  }
+  jwk->crv_ = crv_str;
+  int nid;
+  if (jwk->alg_ == "ES256" && (jwk->crv_ == "P-256" || jwk->crv_ == "")) {
+    nid = NID_X9_62_prime256v1;
+    jwk->crv_ = "P-256";
+  } else if (jwk->alg_ == "ES384" &&
+             (jwk->crv_ == "P-384" || jwk->crv_ == "")) {
+    nid = NID_secp384r1;
+    jwk->crv_ = "P-384";
+  } else if (jwk->alg_ == "ES512" &&
+             (jwk->crv_ == "P-521" || jwk->crv_ == "")) {
+    nid = NID_secp521r1;
+    jwk->crv_ = "P-521";
+  } else {
+    return Status::JwksECKeyAlgNotCompatibleWithCrv;
+  }
+
   std::string x_str;
-  auto code = jwk_getter.GetString("x", &x_str);
+  code = jwk_getter.GetString("x", &x_str);
   if (code == StructUtils::MISSING) {
     return Status::JwksECKeyMissingX;
   }
@@ -192,10 +219,36 @@
   }
 
   EvpPkeyGetter e;
-  jwk->ec_key_ = e.createEcKeyFromJwkEC(x_str, y_str);
+  jwk->ec_key_ = e.createEcKeyFromJwkEC(nid, x_str, y_str);
   return e.getStatus();
 }
 
+Status extractJwkFromJwkOct(const ::google::protobuf::Struct& jwk_pb,
+                            Jwks::Pubkey* jwk) {
+  if (jwk->alg_specified_ && jwk->alg_ != "HS256" && jwk->alg_ != "HS384" &&
+      jwk->alg_ != "HS512") {
+    return Status::JwksHMACKeyBadAlg;
+  }
+
+  StructUtils jwk_getter(jwk_pb);
+  std::string k_str;
+  auto code = jwk_getter.GetString("k", &k_str);
+  if (code == StructUtils::MISSING) {
+    return Status::JwksHMACKeyMissingK;
+  }
+  if (code == StructUtils::WRONG_TYPE) {
+    return Status::JwksHMACKeyBadK;
+  }
+
+  std::string key;
+  if (!absl::WebSafeBase64Unescape(k_str, &key) || key.empty()) {
+    return Status::JwksOctBadBase64;
+  }
+
+  jwk->hmac_key_ = key;
+  return Status::Ok;
+}
+
 Status extractJwk(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) 
{
   StructUtils jwk_getter(jwk_pb);
   // Check "kty" parameter, it should exist.
@@ -208,8 +261,8 @@
     return Status::JwksBadKty;
   }
 
-  // "kid" and "alg" are optional, if they do not exist, set them to empty.
-  // https://tools.ietf.org/html/rfc7517#page-8
+  // "kid", "alg" and "crv" are optional, if they do not exist, set them to
+  // empty. https://tools.ietf.org/html/rfc7517#page-8
   code = jwk_getter.GetString("kid", &jwk->kid_);
   if (code == StructUtils::OK) {
     jwk->kid_specified_ = true;
@@ -225,6 +278,8 @@
     return extractJwkFromJwkEC(jwk_pb, jwk);
   } else if (jwk->kty_ == "RSA") {
     return extractJwkFromJwkRSA(jwk_pb, jwk);
+  } else if (jwk->kty_ == "oct") {
+    return extractJwkFromJwkOct(jwk_pb, jwk);
   }
   return Status::JwksNotImplementedKty;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/src/jwks_test.cc 
new/jwt_verify_lib-20191024/src/jwks_test.cc
--- old/jwt_verify_lib-20190909/src/jwks_test.cc        2019-09-09 
18:18:10.000000000 +0200
+++ new/jwt_verify_lib-20191024/src/jwks_test.cc        2019-10-24 
19:42:38.000000000 +0200
@@ -112,17 +112,34 @@
              "y": "92bCBTvMFQ8lKbS2MbgjT3YfmYo6HnPEE2tsAqWUJw8",
              "alg": "ES256",
              "kid": "xyz"
+          },
+          {
+             "kty": "EC",
+             "crv": "P-384",
+             "x": 
"yY8DWcyWlrr93FTrscI5Ydz2NC7emfoKYHJLX2dr3cSgfw0GuxAkuQ5nBMJmVV5g",
+             "y": 
"An5wVxEfksDOa_zvSHHGkeYJUfl8y11wYkOlFjBt9pOCw5-RlfZgPOa3pbmUquxZ",
+             "alg": "ES384",
+             "kid": "es384"
+          },
+          {
+             "kty": "EC",
+             "crv": "P-521",
+             "x": 
"Abijiex7rz7t-_Zj_E6Oo0OXe9C_-MCSD-OWio15ATQGjH9WpbWjN62ZqrrU_nwJiqqwx6ZsYKhUc_J3PRaMbdVC",
+             "y": 
"FxaljCIuoVEA7PJIaDPJ5ePXtZ0hkinT1B_bQ91mShCiR_43Whsn1P7Gz30WEnLuJs1SGVz1oT4lIRUYni2OfIk",
+             "alg": "ES512",
+             "kid": "es512"
           }
       ]
      }
 )";
   auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
   EXPECT_EQ(jwks->getStatus(), Status::Ok);
-  EXPECT_EQ(jwks->keys().size(), 2);
+  EXPECT_EQ(jwks->keys().size(), 4);
 
   EXPECT_EQ(jwks->keys()[0]->alg_, "ES256");
   EXPECT_EQ(jwks->keys()[0]->kid_, "abc");
   EXPECT_EQ(jwks->keys()[0]->kty_, "EC");
+  EXPECT_EQ(jwks->keys()[0]->crv_, "P-256");
   EXPECT_TRUE(jwks->keys()[0]->alg_specified_);
   EXPECT_TRUE(jwks->keys()[0]->kid_specified_);
   EXPECT_FALSE(jwks->keys()[0]->pem_format_);
@@ -130,9 +147,26 @@
   EXPECT_EQ(jwks->keys()[1]->alg_, "ES256");
   EXPECT_EQ(jwks->keys()[1]->kid_, "xyz");
   EXPECT_EQ(jwks->keys()[1]->kty_, "EC");
+  EXPECT_EQ(jwks->keys()[1]->crv_, "P-256");
   EXPECT_TRUE(jwks->keys()[1]->alg_specified_);
   EXPECT_TRUE(jwks->keys()[1]->kid_specified_);
   EXPECT_FALSE(jwks->keys()[1]->pem_format_);
+
+  EXPECT_EQ(jwks->keys()[2]->alg_, "ES384");
+  EXPECT_EQ(jwks->keys()[2]->kid_, "es384");
+  EXPECT_EQ(jwks->keys()[2]->kty_, "EC");
+  EXPECT_EQ(jwks->keys()[2]->crv_, "P-384");
+  EXPECT_TRUE(jwks->keys()[2]->alg_specified_);
+  EXPECT_TRUE(jwks->keys()[2]->kid_specified_);
+  EXPECT_FALSE(jwks->keys()[2]->pem_format_);
+
+  EXPECT_EQ(jwks->keys()[3]->alg_, "ES512");
+  EXPECT_EQ(jwks->keys()[3]->kid_, "es512");
+  EXPECT_EQ(jwks->keys()[3]->kty_, "EC");
+  EXPECT_EQ(jwks->keys()[3]->crv_, "P-521");
+  EXPECT_TRUE(jwks->keys()[3]->alg_specified_);
+  EXPECT_TRUE(jwks->keys()[3]->kid_specified_);
+  EXPECT_FALSE(jwks->keys()[3]->pem_format_);
 }
 
 TEST(JwksParseTest, EmptyJwks) {
@@ -316,6 +350,158 @@
   EXPECT_EQ(jwks->getStatus(), Status::JwksRsaParseError);
 }
 
+TEST(JwksParseTest, JwksECMatchAlgES256CrvP256) {
+  // alg matches crv
+  const std::string jwks_text = R"(
+     {
+        "keys": [
+           {
+               "kty": "EC",
+               "alg": "ES256",
+               "crv": "P-256",
+               "x": "EB54wykhS7YJFD6RYJNnwbWEz3cI7CF5bCDTXlrwI5k",
+               "y": "92bCBTvMFQ8lKbS2MbgjT3YfmYo6HnPEE2tsAqWUJw8"
+           }
+        ]
+     }
+)";
+  auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
+  EXPECT_EQ(jwks->getStatus(), Status::Ok);
+}
+
+TEST(JwksParseTest, JwksECMatchAlgES384CrvP384) {
+  // alg matches crv
+  const std::string jwks_text = R"(
+     {
+        "keys": [
+           {
+               "kty": "EC",
+               "alg": "ES384",
+               "crv": "P-384",
+               "x": 
"yY8DWcyWlrr93FTrscI5Ydz2NC7emfoKYHJLX2dr3cSgfw0GuxAkuQ5nBMJmVV5g",
+               "y": 
"An5wVxEfksDOa_zvSHHGkeYJUfl8y11wYkOlFjBt9pOCw5-RlfZgPOa3pbmUquxZ"
+           }
+        ]
+     }
+)";
+  auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
+  EXPECT_EQ(jwks->getStatus(), Status::Ok);
+}
+
+TEST(JwksParseTest, JwksECMatchAlgES512CrvP521) {
+  // alg matches crv
+  const std::string jwks_text = R"(
+     {
+        "keys": [
+           {
+               "kty": "EC",
+               "alg": "ES512",
+               "crv": "P-521",
+               "x": 
"Abijiex7rz7t-_Zj_E6Oo0OXe9C_-MCSD-OWio15ATQGjH9WpbWjN62ZqrrU_nwJiqqwx6ZsYKhUc_J3PRaMbdVC",
+               "y": 
"FxaljCIuoVEA7PJIaDPJ5ePXtZ0hkinT1B_bQ91mShCiR_43Whsn1P7Gz30WEnLuJs1SGVz1oT4lIRUYni2OfIk"
+           }
+        ]
+     }
+)";
+  auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
+  EXPECT_EQ(jwks->getStatus(), Status::Ok);
+}
+
+TEST(JwksParseTest, JwksECMismatchAlgCrv1) {
+  // alg doesn't match with crv
+  const std::string jwks_text = R"(
+     {
+        "keys": [
+           {
+               "kty": "EC",
+               "alg": "ES256",
+               "crv": "P-384"
+           }
+        ]
+     }
+)";
+  auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
+  EXPECT_EQ(jwks->getStatus(), Status::JwksECKeyAlgNotCompatibleWithCrv);
+}
+
+TEST(JwksParseTest, JwksECMismatchAlgCrv2) {
+  // alg doesn't match with crv
+  const std::string jwks_text = R"(
+     {
+        "keys": [
+           {
+               "kty": "EC",
+               "alg": "ES384",
+               "crv": "P-521"
+           }
+        ]
+     }
+)";
+  auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
+  EXPECT_EQ(jwks->getStatus(), Status::JwksECKeyAlgNotCompatibleWithCrv);
+}
+
+TEST(JwksParseTest, JwksECMismatchAlgCrv3) {
+  // alg doesn't match with crv
+  const std::string jwks_text = R"(
+     {
+        "keys": [
+           {
+               "kty": "EC",
+               "alg": "ES512",
+               "crv": "P-256"
+           }
+        ]
+     }
+)";
+  auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
+  EXPECT_EQ(jwks->getStatus(), Status::JwksECKeyAlgNotCompatibleWithCrv);
+}
+
+TEST(JwksParseTest, JwksECUnspecifiedCrv) {
+  // crv determined from alg
+  const std::string jwks_text = R"(
+     {
+        "keys": [
+           {
+               "kty": "EC",
+               "alg": "ES256",
+               "x": "EB54wykhS7YJFD6RYJNnwbWEz3cI7CF5bCDTXlrwI5k",
+               "y": "92bCBTvMFQ8lKbS2MbgjT3YfmYo6HnPEE2tsAqWUJw8"
+           },
+           {
+               "kty": "EC",
+               "alg": "ES384",
+               "x": 
"yY8DWcyWlrr93FTrscI5Ydz2NC7emfoKYHJLX2dr3cSgfw0GuxAkuQ5nBMJmVV5g",
+               "y": 
"An5wVxEfksDOa_zvSHHGkeYJUfl8y11wYkOlFjBt9pOCw5-RlfZgPOa3pbmUquxZ"
+           },
+           {
+               "kty": "EC",
+               "alg": "ES512",
+               "x": 
"Abijiex7rz7t-_Zj_E6Oo0OXe9C_-MCSD-OWio15ATQGjH9WpbWjN62ZqrrU_nwJiqqwx6ZsYKhUc_J3PRaMbdVC",
+               "y": 
"FxaljCIuoVEA7PJIaDPJ5ePXtZ0hkinT1B_bQ91mShCiR_43Whsn1P7Gz30WEnLuJs1SGVz1oT4lIRUYni2OfIk"
+           }
+        ]
+     }
+)";
+
+  auto jwks = Jwks::createFrom(jwks_text, Jwks::JWKS);
+  EXPECT_EQ(jwks->getStatus(), Status::Ok);
+  EXPECT_EQ(jwks->keys().size(), 3);
+
+  EXPECT_EQ(jwks->keys()[0]->alg_, "ES256");
+  EXPECT_EQ(jwks->keys()[0]->crv_, "P-256");
+  EXPECT_TRUE(jwks->keys()[0]->alg_specified_);
+
+  EXPECT_EQ(jwks->keys()[1]->alg_, "ES384");
+  EXPECT_EQ(jwks->keys()[1]->crv_, "P-384");
+  EXPECT_TRUE(jwks->keys()[1]->alg_specified_);
+
+  EXPECT_EQ(jwks->keys()[2]->alg_, "ES512");
+  EXPECT_EQ(jwks->keys()[2]->crv_, "P-521");
+  EXPECT_TRUE(jwks->keys()[2]->alg_specified_);
+}
+
 }  // namespace
 }  // namespace jwt_verify
 }  // namespace google
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/src/jwt.cc 
new/jwt_verify_lib-20191024/src/jwt.cc
--- old/jwt_verify_lib-20190909/src/jwt.cc      2019-09-09 18:18:10.000000000 
+0200
+++ new/jwt_verify_lib-20191024/src/jwt.cc      2019-10-24 19:42:38.000000000 
+0200
@@ -61,8 +61,9 @@
     return Status::JwtHeaderBadAlg;
   }
 
-  if (alg_ != "RS256" && alg_ != "ES256" && alg_ != "RS384" &&
-      alg_ != "RS512") {
+  if (alg_ != "ES256" && alg_ != "ES384" && alg_ != "ES512" &&
+      alg_ != "HS256" && alg_ != "HS384" && alg_ != "HS512" &&
+      alg_ != "RS256" && alg_ != "RS384" && alg_ != "RS512") {
     return Status::JwtHeaderNotImplementedAlg;
   }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/src/status.cc 
new/jwt_verify_lib-20191024/src/status.cc
--- old/jwt_verify_lib-20190909/src/status.cc   2019-09-09 18:18:10.000000000 
+0200
+++ new/jwt_verify_lib-20191024/src/status.cc   2019-10-24 19:42:38.000000000 
+0200
@@ -70,6 +70,8 @@
       return "Jwks EC create key fail";
     case Status::JwksEcParseError:
       return "Jwks EC [x] or [y] field is missing or has a parse error.";
+    case Status::JwksOctBadBase64:
+      return "Jwks Oct key is an invalid Base64";
     case Status::JwksFetchFail:
       return "Jwks remote fetch is failed";
 
@@ -92,7 +94,11 @@
       return "[e] field is not string for a RSA key";
 
     case Status::JwksECKeyBadAlg:
-      return "[alg] is not [ES256] for an EC key";
+      return "[alg] is not started with [ES] for an EC key";
+    case Status::JwksECKeyBadCrv:
+      return "[crv] field is not string for an EC key";
+    case Status::JwksECKeyAlgNotCompatibleWithCrv:
+      return "[crv] field specified is not compatible with [alg] for an EC 
key";
     case Status::JwksECKeyMissingX:
       return "[x] field is missing for an EC key";
     case Status::JwksECKeyBadX:
@@ -101,6 +107,13 @@
       return "[y] field is missing for an EC key";
     case Status::JwksECKeyBadY:
       return "[y] field is not string for an EC key";
+
+    case Status::JwksHMACKeyBadAlg:
+      return "[alg] does not start with [HS] for an HMAC key";
+    case Status::JwksHMACKeyMissingK:
+      return "[k] field is missing for an HMAC key";
+    case Status::JwksHMACKeyBadK:
+      return "[k] field is not string for an HMAC key";
   };
   return "";
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/src/verify.cc 
new/jwt_verify_lib-20191024/src/verify.cc
--- old/jwt_verify_lib-20190909/src/verify.cc   2019-09-09 18:18:10.000000000 
+0200
+++ new/jwt_verify_lib-20191024/src/verify.cc   2019-10-24 19:42:38.000000000 
+0200
@@ -21,6 +21,8 @@
 #include "openssl/ecdsa.h"
 #include "openssl/err.h"
 #include "openssl/evp.h"
+#include "openssl/hmac.h"
+#include "openssl/mem.h"
 #include "openssl/rsa.h"
 #include "openssl/sha.h"
 
@@ -61,43 +63,91 @@
                             castToUChar(signed_data), signed_data.length());
 }
 
-bool verifySignatureEC(EC_KEY* key, const uint8_t* signature,
+bool verifySignatureEC(EC_KEY* key, const EVP_MD* md, const uint8_t* signature,
                        size_t signature_len, const uint8_t* signed_data,
                        size_t signed_data_len) {
-  if (key == nullptr || signature == nullptr || signed_data == nullptr) {
+  if (key == nullptr || md == nullptr || signature == nullptr ||
+      signed_data == nullptr) {
     return false;
   }
-  // ES256 signature should be 64 bytes.
-  if (signature_len != 2 * 32) {
+  bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_create());
+  std::vector<uint8_t> digest(EVP_MAX_MD_SIZE);
+  unsigned int digest_len = 0;
+
+  if (EVP_DigestInit(md_ctx.get(), md) == 0) {
     return false;
   }
 
-  uint8_t digest[SHA256_DIGEST_LENGTH];
-  SHA256(signed_data, signed_data_len, digest);
+  if (EVP_DigestUpdate(md_ctx.get(), signed_data, signed_data_len) == 0) {
+    return false;
+  }
+
+  if (EVP_DigestFinal(md_ctx.get(), digest.data(), &digest_len) == 0) {
+    return false;
+  }
 
   bssl::UniquePtr<ECDSA_SIG> ecdsa_sig(ECDSA_SIG_new());
   if (!ecdsa_sig) {
     return false;
   }
 
-  if (BN_bin2bn(signature, 32, ecdsa_sig->r) == nullptr ||
-      BN_bin2bn(signature + 32, 32, ecdsa_sig->s) == nullptr) {
+  if (BN_bin2bn(signature, signature_len / 2, ecdsa_sig->r) == nullptr ||
+      BN_bin2bn(signature + (signature_len / 2), signature_len / 2,
+                ecdsa_sig->s) == nullptr) {
     return false;
   }
-  if (ECDSA_do_verify(digest, SHA256_DIGEST_LENGTH, ecdsa_sig.get(), key) ==
-      1) {
+
+  if (ECDSA_do_verify(digest.data(), digest_len, ecdsa_sig.get(), key) == 1) {
     return true;
   }
+
   ERR_clear_error();
   return false;
 }
 
-bool verifySignatureEC(EC_KEY* key, absl::string_view signature,
+bool verifySignatureEC(EC_KEY* key, const EVP_MD* md,
+                       absl::string_view signature,
                        absl::string_view signed_data) {
-  return verifySignatureEC(key, castToUChar(signature), signature.length(),
+  return verifySignatureEC(key, md, castToUChar(signature), signature.length(),
                            castToUChar(signed_data), signed_data.length());
 }
 
+bool verifySignatureOct(const uint8_t* key, size_t key_len, const EVP_MD* md,
+                        const uint8_t* signature, size_t signature_len,
+                        const uint8_t* signed_data, size_t signed_data_len) {
+  if (key == nullptr || md == nullptr || signature == nullptr ||
+      signed_data == nullptr) {
+    return false;
+  }
+
+  std::vector<uint8_t> out(EVP_MAX_MD_SIZE);
+  unsigned int out_len = 0;
+  if (HMAC(md, key, key_len, signed_data, signed_data_len, out.data(),
+           &out_len) == nullptr) {
+    ERR_clear_error();
+    return false;
+  }
+
+  if (out_len != signature_len) {
+    return false;
+  }
+
+  if (CRYPTO_memcmp(out.data(), signature, signature_len) == 0) {
+    return true;
+  }
+
+  ERR_clear_error();
+  return false;
+}
+
+bool verifySignatureOct(absl::string_view key, const EVP_MD* md,
+                        absl::string_view signature,
+                        absl::string_view signed_data) {
+  return verifySignatureOct(castToUChar(key), key.length(), md,
+                            castToUChar(signature), signature.length(),
+                            castToUChar(signed_data), signed_data.length());
+}
+
 }  // namespace
 
 Status verifyJwt(const Jwt& jwt, const Jwks& jwks) {
@@ -131,10 +181,22 @@
     }
     kid_alg_matched = true;
 
-    if (jwk->kty_ == "EC" &&
-        verifySignatureEC(jwk->ec_key_.get(), jwt.signature_, signed_data)) {
-      // Verification succeeded.
-      return Status::Ok;
+    if (jwk->kty_ == "EC") {
+      const EVP_MD* md;
+      if (jwt.alg_ == "ES384") {
+        md = EVP_sha384();
+      } else if (jwt.alg_ == "ES512") {
+        md = EVP_sha512();
+      } else {
+        // default to SHA256
+        md = EVP_sha256();
+      }
+
+      if (verifySignatureEC(jwk->ec_key_.get(), md, 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") {
@@ -151,6 +213,21 @@
         // Verification succeeded.
         return Status::Ok;
       }
+    } else if (jwk->kty_ == "oct") {
+      const EVP_MD* md;
+      if (jwt.alg_ == "HS384") {
+        md = EVP_sha384();
+      } else if (jwt.alg_ == "HS512") {
+        md = EVP_sha512();
+      } else {
+        // default to SHA256
+        md = EVP_sha256();
+      }
+
+      if (verifySignatureOct(jwk->hmac_key_, md, jwt.signature_, signed_data)) 
{
+        // Verification succeeded.
+        return Status::Ok;
+      }
     }
   }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/src/verify_jwk_ec_test.cc 
new/jwt_verify_lib-20191024/src/verify_jwk_ec_test.cc
--- old/jwt_verify_lib-20190909/src/verify_jwk_ec_test.cc       2019-09-09 
18:18:10.000000000 +0200
+++ new/jwt_verify_lib-20191024/src/verify_jwk_ec_test.cc       2019-10-24 
19:42:38.000000000 +0200
@@ -20,14 +20,19 @@
 namespace jwt_verify {
 namespace {
 
-// Please see jwt_generator.py and jwk_generator.py under /tools/.
-// for ES256-signed jwt token and public jwk generation, respectively.
-// jwt_generator.py uses ES256 private key file to generate JWT token.
+// Please see jwt_generator.py and jwk_generator.py under
+// https://github.com/istio/proxy/tree/master/src/envoy/http/jwt_auth/tools
+// for ES{256,384,512}-signed jwt token and public jwk generation, 
respectively.
+// jwt_generator.py uses ES{256,384,512} private key file to generate JWT 
token.
 // ES256 private key file can be generated by:
 // $ openssl ecparam -genkey -name prime256v1 -noout -out private_key.pem
-// jwk_generator.py uses ES256 public key file to generate JWK. ES256
-// public key file can be generated by:
-// $ openssl ec -in private_key.pem -pubout -out public_key.pem.
+// ES384 private key file can be generated by:
+// $ openssl ecparam -genkey -name secp384r1 -noout -out private_key.pem
+// ES512 private key file can be generated by:
+// $ openssl ecparam -genkey -name secp521r1 -noout -out private_key.pem
+// jwk_generator.py uses ES{256.384,512} public key file to generate JWK.
+// ES256, ES384 and ES512 public key files can be generated by:
+// $ openssl ec -in private_key.pem -pubout -out public_key.pem
 
 // ES256 private key:
 // "-----BEGIN EC PRIVATE KEY-----"
@@ -42,6 +47,37 @@
 // "7CF5bCDTXlrwI5n3ZsIFO8wVDyUptLYxuCNPdh+Zijoec8QTa2wCpZQnDw=="
 // "-----END PUBLIC KEY-----"
 
+// ES384 private key:
+// "-----BEGIN EC PRIVATE KEY-----"
+// "MIGkAgEBBDDqSPe2gvdUVMQcCxpr60rScFgjEQZeCYvZRq3oyY9mECVMK7nuRjLx"
+// "blWjf6DH9E+gBwYFK4EEACKhZANiAATJjwNZzJaWuv3cVOuxwjlh3PY0Lt6Z+gpg"
+// "cktfZ2vdxKB/DQa7ECS5DmcEwmZVXmACfnBXER+SwM5r/O9IccaR5glR+XzLXXBi"
+// "Q6UWMG32k4LDn5GV9mA85reluZSq7Fk="
+// "-----END EC PRIVATE KEY-----"
+
+// ES384 public key:
+// "-----BEGIN PUBLIC KEY-----"
+// "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyY8DWcyWlrr93FTrscI5Ydz2NC7emfoK"
+// "YHJLX2dr3cSgfw0GuxAkuQ5nBMJmVV5gAn5wVxEfksDOa/zvSHHGkeYJUfl8y11w"
+// "YkOlFjBt9pOCw5+RlfZgPOa3pbmUquxZ"
+// "-----END PUBLIC KEY-----"
+
+// ES512 private key:
+// "-----BEGIN EC PRIVATE KEY-----"
+// "MIHcAgEBBEIBKlG7GPIoqQujJHwe21rnsZePySFyd45HPe3FeldgZQEHqcUiZgpb"
+// "BgiuYMPHytEaohj1yC5gyOOsOfgsWY2qSsWgBwYFK4EEACOhgYkDgYYABAG4o4ns"
+// "e68+7fv2Y/xOjqNDl3vQv/jAkg/jloqNeQE0Box/VqW1ozetmaq61P58CYqqsMem"
+// "bGCoVHPydz0WjG3VQgAXFqWMIi6hUQDs8khoM8nl49e1nSGSKdPUH9tD3WZKEKJH"
+// "/jdaGyfU/sbPfRYScu4mzVIZXPWhPiUhFRieLY58iQ=="
+// "-----END EC PRIVATE KEY-----"
+
+// ES512 public key:
+// "-----BEGIN PUBLIC KEY-----"
+// "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBuKOJ7HuvPu379mP8To6jQ5d70L/4"
+// "wJIP45aKjXkBNAaMf1altaM3rZmqutT+fAmKqrDHpmxgqFRz8nc9Foxt1UIAFxal"
+// "jCIuoVEA7PJIaDPJ5ePXtZ0hkinT1B/bQ91mShCiR/43Whsn1P7Gz30WEnLuJs1S"
+// "GVz1oT4lIRUYni2OfIk="
+// "-----END PUBLIC KEY-----"
 const std::string PublicKeyJwkEC = R"(
 {
   "keys": [
@@ -60,12 +96,37 @@
       "kid": "xyz",
       "x": "EB54wykhS7YJFD6RYJNnwbWEz3cI7CF5bCDTXlrwI5k",
       "y": "92bCBTvMFQ8lKbS2MbgjT3YfmYo6HnPEE2tsAqWUJw8"
+    },
+    {
+      "kty": "EC",
+      "crv": "P-384",
+      "alg": "ES384",
+      "kid": "es384",
+      "x": "yY8DWcyWlrr93FTrscI5Ydz2NC7emfoKYHJLX2dr3cSgfw0GuxAkuQ5nBMJmVV5g",
+      "y": "An5wVxEfksDOa_zvSHHGkeYJUfl8y11wYkOlFjBt9pOCw5-RlfZgPOa3pbmUquxZ"
+    },
+    {
+      "kty": "EC",
+      "crv": "P-521",
+      "alg": "ES512",
+      "kid": "es512",
+      "x": 
"Abijiex7rz7t-_Zj_E6Oo0OXe9C_-MCSD-OWio15ATQGjH9WpbWjN62ZqrrU_nwJiqqwx6ZsYKhUc_J3PRaMbdVC",
+      "y": 
"FxaljCIuoVEA7PJIaDPJ5ePXtZ0hkinT1B_bQ91mShCiR_43Whsn1P7Gz30WEnLuJs1SGVz1oT4lIRUYni2OfIk"
     }
   ]
 }
 )";
 
 // "{"kid":"abc"}"
+const std::string JwtES256Text =
+    "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFiYyJ9.eyJpc3MiOiI2Mj"
+    "g2NDU3NDE4ODEtbm9hYml1MjNmNWE4bThvdmQ4dWN2Njk4bGo3OHZ2MGxAZGV2ZWxvc"
+    "GVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzdWIiOiI2Mjg2NDU3NDE4ODEtbm9hYml1"
+    "MjNmNWE4bThvdmQ4dWN2Njk4bGo3OHZ2MGxAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3V"
+    "udC5jb20iLCJhdWQiOiJodHRwOi8vbXlzZXJ2aWNlLmNvbS9teWFwaSJ9.T2KAwChqg"
+    "o2ZSXyLh3IcMBQNSeRZRe5Z-MUDl-s-F99XGoyutqA6lq8bKZ6vmjZAlpVG8AGRZW9J"
+    "Gp9lq3cbEw";
+
 const std::string JwtTextEC =
     "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFiYyJ9.eyJpc3MiOiI2Mj"
     "g2NDU3NDE4ODEtbm9hYml1MjNmNWE4bThvdmQ4dWN2Njk4bGo3OHZ2MGxAZGV2ZWxvc"
@@ -75,6 +136,28 @@
     "o2ZSXyLh3IcMBQNSeRZRe5Z-MUDl-s-F99XGoyutqA6lq8bKZ6vmjZAlpVG8AGRZW9J"
     "Gp9lq3cbEw";
 
+// "{"kid":"es384"}"
+const std::string JwtES384Text =
+    "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCIsImtpZCI6ImVzMzg0In0.eyJpc3MiOi"
+    "I2Mjg2NDU3NDE4ODEtbm9hYml1MjNmNWE4bThvdmQ4dWN2Njk4bGo3OHZ2MGxAZ"
+    "GV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzdWIiOiI2Mjg2NDU3NDE4"
+    "ODEtbm9hYml1MjNmNWE4bThvdmQ4dWN2Njk4bGo3OHZ2MGxAZGV2ZWxvcGVyLmd"
+    "zZXJ2aWNlYWNjb3VudC5jb20iLCJhdWQiOiJodHRwOi8vbXlzZXJ2aWNlLmNvbS"
+    "9teWFwaSJ9.aKFxrqV4_rg1Zf2DamTU0D76hOq9-FYu-LNmpGPthjJKv31mOZ4t"
+    "J40x2FVVJx5d8lntg3bsy1IN0z9C7MD_k10Y7Gea1YB7Jyi-DR68U5krJzzwKmD"
+    "9ap1J7tb2UrzT";
+
+// "{"kid":"es512"}"
+const std::string JwtES512Text =
+    "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6ImVzNTEyIn0.eyJpc3MiOi"
+    "I2Mjg2NDU3NDE4ODEtbm9hYml1MjNmNWE4bThvdmQ4dWN2Njk4bGo3OHZ2MGxAZ"
+    "GV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzdWIiOiI2Mjg2NDU3NDE4"
+    "ODEtbm9hYml1MjNmNWE4bThvdmQ4dWN2Njk4bGo3OHZ2MGxAZGV2ZWxvcGVyLmd"
+    "zZXJ2aWNlYWNjb3VudC5jb20iLCJhdWQiOiJodHRwOi8vbXlzZXJ2aWNlLmNvbS"
+    "9teWFwaSJ9.ATSReP9zpba6PRJZmlIEA78Ft-FZS1m_SpFLqfiNQNexaDaTmmVr"
+    "IqD9X-krPxk0c8KSBeMlU-QLOsbh37coamruAPKoAODYWA-QKUN2a_xem8WrudK"
+    "VXWsmQlZDOJA0lQWI-YGMEPrDr17mljMhZwSGbVVST9l-nZiMXyMK0z8hR9Mn";
+
 // "{"kid":"abcdef"}"
 const std::string JwtTextWithNonExistKidEC =
     "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFiY2RlZiJ9.eyJpc3MiOi"
@@ -114,6 +197,26 @@
   });
 }
 
+TEST_F(VerifyJwkECTest, KidES384OK) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtES384Text), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_), Status::Ok);
+
+  fuzzJwtSignature(jwt, [this](const Jwt& jwt) {
+    EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwtVerificationFail);
+  });
+}
+
+TEST_F(VerifyJwkECTest, KidES512OK) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtES512Text), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_), Status::Ok);
+
+  fuzzJwtSignature(jwt, [this](const Jwt& jwt) {
+    EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwtVerificationFail);
+  });
+}
+
 TEST_F(VerifyJwkECTest, NoKidOK) {
   Jwt jwt;
   EXPECT_EQ(jwt.parseFromString(JwtTextECNoKid), Status::Ok);
@@ -144,7 +247,7 @@
   EXPECT_EQ(jwks_->getStatus(), Status::Ok);
 
   Jwt jwt;
-  EXPECT_EQ(jwt.parseFromString(JwtTextEC), Status::Ok);
+  EXPECT_EQ(jwt.parseFromString(JwtES256Text), Status::Ok);
   EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
 }
 
@@ -162,7 +265,7 @@
   EXPECT_EQ(jwks_->getStatus(), Status::Ok);
 
   Jwt jwt;
-  EXPECT_EQ(jwt.parseFromString(JwtTextEC), Status::Ok);
+  EXPECT_EQ(jwt.parseFromString(JwtES256Text), Status::Ok);
   EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jwt_verify_lib-20190909/src/verify_jwk_hmac_test.cc 
new/jwt_verify_lib-20191024/src/verify_jwk_hmac_test.cc
--- old/jwt_verify_lib-20190909/src/verify_jwk_hmac_test.cc     1970-01-01 
01:00:00.000000000 +0100
+++ new/jwt_verify_lib-20191024/src/verify_jwk_hmac_test.cc     2019-10-24 
19:42:38.000000000 +0200
@@ -0,0 +1,242 @@
+// 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.
+
+#include "gtest/gtest.h"
+#include "jwt_verify_lib/verify.h"
+#include "src/test_common.h"
+
+namespace google {
+namespace jwt_verify {
+namespace {
+
+const std::string SymmetricKeyHMAC = R"(
+{
+  "keys": [
+    {
+      "kty": "oct",
+      "alg": "HS256",
+      "use": "sig",
+      "kid": "62a93512c9ee4c7f8067b5a216dade2763d32a47",
+      "k": "LcHQCLETtc_QO4D69zCnQEIAYaZ6BsldibDzuRHE5bI"
+    },
+    {
+      "kty": "oct",
+      "alg": "HS256",
+      "use": "sig",
+      "kid": "b3319a147514df7ee5e4bcdee51350cc890cc89e",
+      "k": "nyeGXUHngW64dyg2EuDs_8x6VGa14Bkrv1SFQwOzKfI"
+    },
+    {
+      "kty": "oct",
+      "alg": "HS384",
+      "use": "sig",
+      "kid": "cda01077a6aa4b0088a6e959044977ef9e51c28b",
+      "k": "5xYkMHiMVnCBbFEt0Uh1LhIbFB6yakzp2Mh7ESBMUCDq4zMO6WgCMaQwP332FH47"
+    },
+    {
+      "kty": "oct",
+      "alg": "HS512",
+      "use": "sig",
+      "kid": "f6a7bd9ffd784388924f126280a746964ba61268",
+      "k": 
"ID3awf7bo607gitUDWylMMhUyVFr4ZAmnysPw4675A1YmOaYajbqLmMA7fohGLYZdZyaluaiugKvnnGLYTDoUA"
+    },
+
+  ]
+}
+)";
+
+// JWT without kid
+// Header:  {"alg":"HS256","typ":"JWT"}
+// Payload:
+// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058}
+const std::string JwtTextNoKid =
+    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
+    "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs"
+    "ImV4cCI6MTUwMTI4MTA1OH0."
+    "_LY8Zz3ssG82v5-T8L2Hg1TsqzCEEKnYOxzrQpDTjwU";
+
+// JWT without kid with long exp
+// Header:  {"alg":"HS256","typ":"JWT"}
+// Payload:
+// 
{"iss":"https://example.com","sub":"[email protected]","aud":"example_service","exp":2001001001}
+const std::string JwtTextNoKidLongExp =
+    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
+    "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs"
+    "ImF1ZCI6ImV4YW1wbGVfc2VydmljZSIsImV4cCI6MjAwMTAwMTAwMX0."
+    "4tc7M-gJizpbB69_sQi7E0ym0np6uon4V41hVjYV2ic";
+
+// JWT with correct kid
+// Header:
+// {"alg":"HS256","typ":"JWT","kid":"b3319a147514df7ee5e4bcdee51350cc890cc89e"}
+// Payload:
+// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058}
+const std::string JwtHS256TextWithCorrectKid =
+    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImIzMzE5YTE0NzUxNGRmN2VlNWU0"
+    "YmNkZWU1MTM1MGNjODkwY2M4OWUifQ."
+    "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs"
+    "ImV4cCI6MTUwMTI4MTA1OH0."
+    "QqSMCAY5UDBvySx0VQhGqIvomZaSRUJOCT6ktV3BhL8";
+
+// JWT with correct kid
+// Header:
+// {"alg":"HS384","typ":"JWT","kid":"cda01077a6aa4b0088a6e959044977ef9e51c28b"}
+// Payload:
+// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058}
+const std::string JwtHS384TextWithCorrectKid =
+    "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCIsImtpZCI6ImNkYTAxMDc3YTZhYTRiMDA4OGE2"
+    "ZTk1OTA0NDk3N2VmOWU1MWMyOGIifQ."
+    "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs"
+    "ImV4cCI6MTUwMTI4MTA1OH0."
+    "F69ivpIRbgrmy1j6_MHl10xDW8iPdzsHAIgln3Z9PEemH9heiQoDUOgG91kA44fL";
+
+// JWT with correct kid
+// Header:
+// {"alg":"HS512","typ":"JWT","kid":"f6a7bd9ffd784388924f126280a746964ba61268"}
+// Payload:
+// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058}
+const std::string JwtHS512TextWithCorrectKid =
+    "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6ImY2YTdiZDlmZmQ3ODQzODg5MjRm"
+    "MTI2MjgwYTc0Njk2NGJhNjEyNjgifQ."
+    "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs"
+    "ImV4cCI6MTUwMTI4MTA1OH0."
+    "YdILUM4zaeIRuxEMLV13qMX3d1sp63juPXwbpOp_HUjNdGGvocthipOxjQur6JtCLmIfvrI4"
+    "XNrkxVWd-qS_3g";
+
+// JWT with existing but incorrect kid
+// Header:
+// {"alg":"HS256","typ":"JWT","kid":"62a93512c9ee4c7f8067b5a216dade2763d32a47"}
+// Payload:
+// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058}
+const std::string JwtTextWithIncorrectKid =
+    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjYyYTkzNTEyYzllZTRjN2Y4MDY3"
+    "YjVhMjE2ZGFkZTI3NjNkMzJhNDcifQ."
+    "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs"
+    "ImV4cCI6MTUwMTI4MTA1OH0."
+    "GRLODq7HrBduwUJEoJ3alWlXvxhCZZpFgvd1hYRDXa4";
+
+// JWT with nonexist kid
+// Header:  {"alg":"HS256","typ":"JWT","kid":"blahblahblah"}
+// Payload:
+// {"iss":"https://example.com","sub":"[email protected]","exp":1501281058}
+const std::string JwtTextWithNonExistKid =
+    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJsYWhibGFoYmxhaCJ9."
+    "eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIs"
+    "ImV4cCI6MTUwMTI4MTA1OH0."
+    "WFHsFo29tA5_gT_rzm6WheQhCwwBPrRZWFEAWRF9Ym4";
+
+class VerifyJwkHmacTest : public testing::Test {
+ protected:
+  void SetUp() {
+    jwks_ = Jwks::createFrom(SymmetricKeyHMAC, Jwks::Type::JWKS);
+    EXPECT_EQ(jwks_->getStatus(), Status::Ok);
+  }
+
+  JwksPtr jwks_;
+};
+
+TEST_F(VerifyJwkHmacTest, NoKidOK) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtTextNoKid), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
+  fuzzJwtSignature(jwt, [this](const Jwt& jwt) {
+    EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwtVerificationFail);
+  });
+}
+
+TEST_F(VerifyJwkHmacTest, NoKidLongExpOK) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtTextNoKidLongExp), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_), Status::Ok);
+
+  fuzzJwtSignature(jwt, [this](const Jwt& jwt) {
+    EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwtVerificationFail);
+  });
+}
+
+TEST_F(VerifyJwkHmacTest, CorrectKidHS256OK) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtHS256TextWithCorrectKid), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
+
+  fuzzJwtSignature(jwt, [this](const Jwt& jwt) {
+    EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwtVerificationFail);
+  });
+}
+
+TEST_F(VerifyJwkHmacTest, CorrectKidHS384OK) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtHS384TextWithCorrectKid), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
+
+  fuzzJwtSignature(jwt, [this](const Jwt& jwt) {
+    EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwtVerificationFail);
+  });
+}
+
+TEST_F(VerifyJwkHmacTest, CorrectKidHS512OK) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtHS512TextWithCorrectKid), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
+
+  fuzzJwtSignature(jwt, [this](const Jwt& jwt) {
+    EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwtVerificationFail);
+  });
+}
+
+TEST_F(VerifyJwkHmacTest, NonExistKidFail) {
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtTextWithNonExistKid), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::JwksKidAlgMismatch);
+}
+
+TEST_F(VerifyJwkHmacTest, OkSymmetricKeyNotAlg) {
+  // Remove "alg" claim from symmetric key.
+  std::string alg_claim = R"("alg": "HS256",)";
+  std::string symmkey_no_alg = SymmetricKeyHMAC;
+  std::size_t alg_pos = symmkey_no_alg.find(alg_claim);
+  while (alg_pos != std::string::npos) {
+    symmkey_no_alg.erase(alg_pos, alg_claim.length());
+    alg_pos = symmkey_no_alg.find(alg_claim);
+  }
+
+  jwks_ = Jwks::createFrom(symmkey_no_alg, Jwks::Type::JWKS);
+  EXPECT_EQ(jwks_->getStatus(), Status::Ok);
+
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtTextNoKid), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
+}
+
+TEST_F(VerifyJwkHmacTest, OkSymmetricKeyNotKid) {
+  // Remove "kid" claim from symmetric key.
+  std::string kid_claim1 =
+      R"("kid": "62a93512c9ee4c7f8067b5a216dade2763d32a47",)";
+  std::string kid_claim2 =
+      R"("kid": "b3319a147514df7ee5e4bcdee51350cc890cc89e",)";
+  std::string symmkey_no_kid = SymmetricKeyHMAC;
+  std::size_t kid_pos = symmkey_no_kid.find(kid_claim1);
+  symmkey_no_kid.erase(kid_pos, kid_claim1.length());
+  kid_pos = symmkey_no_kid.find(kid_claim2);
+  symmkey_no_kid.erase(kid_pos, kid_claim2.length());
+  jwks_ = Jwks::createFrom(symmkey_no_kid, Jwks::Type::JWKS);
+  EXPECT_EQ(jwks_->getStatus(), Status::Ok);
+
+  Jwt jwt;
+  EXPECT_EQ(jwt.parseFromString(JwtTextNoKid), Status::Ok);
+  EXPECT_EQ(verifyJwt(jwt, *jwks_, 1), Status::Ok);
+}
+
+}  // namespace
+}  // namespace jwt_verify
+}  // namespace google


Reply via email to