diff --git a/CMakeLists.txt b/CMakeLists.txt
index 286f43ff..88e65c59 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,7 +17,6 @@ project(${LIBJWT_PROJECT}
DESCRIPTION ${LIBJWT_DESCRIPTION}
HOMEPAGE_URL ${LIBJWT_HOMEPAGE_URL}
LANGUAGES C)
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
# Must be set after the above
include(GNUInstallDirs)
@@ -27,17 +26,11 @@ find_package(PkgConfig REQUIRED)
pkg_check_modules(JANSSON jansson>=2.0 REQUIRED IMPORTED_TARGET)
-if (NOT DEFINED WITH_OPENSSL)
- set(OPENSSL_AUTO TRUE)
-endif()
if (NOT DEFINED WITH_GNUTLS)
set(GNUTLS_AUTO TRUE)
endif()
-option(WITH_OPENSSL "Whether to use OpenSSL (default is auto detect)" ON)
-option(WITH_GNUTLS "Whether to use GnuTLS (default is auto detect)" ON)
-
-# option(WITH_MBEDTLS "Enable using MBedTLS (default is disabled)" ON)
+option(WITH_GNUTLS "Whether to use GnuTLS (default is auto detect)" ON)
option(WITH_EXAMPLES "Whether to build the example programs (default is OFF)" OFF)
option(WITH_TESTS "Whether to build and run the testsuite (default is ON)" ON)
@@ -50,13 +43,8 @@ if (WITH_GNUTLS)
${GNUTLS_REQUIRED})
endif()
-if (WITH_OPENSSL)
- #if (NOT OPENSSL_AUTO)
- set(OPENSSL_REQUIRED REQUIRED)
- #endif()
- pkg_check_modules(OPENSSL openssl>=3.0.0 IMPORTED_TARGET
- ${OPENSSL_REQUIRED})
-endif()
+pkg_check_modules(OPENSSL openssl>=3.0.0 IMPORTED_TARGET
+ REQUIRED)
add_library(jwt SHARED)
add_library(jwt_static STATIC)
@@ -65,14 +53,24 @@ set_target_properties(jwt_static PROPERTIES
COMPILE_FLAGS -DJWT_STATIC_DEFINE)
set(JWT_SOURCES libjwt/base64.c
- libjwt/jwt-memory.c
- libjwt/jwt.c
- libjwt/jwks.c
- libjwt/jwt-setget.c
- libjwt/jwt-crypto-ops.c
- libjwt/jwt-validate.c
- libjwt/jwt-encode.c
- libjwt/jwt-verify.c)
+ libjwt/jwt-memory.c
+ libjwt/jwt.c
+ libjwt/jwks.c
+ libjwt/jwt-setget.c
+ libjwt/jwt-crypto-ops.c
+ libjwt/jwt-encode.c
+ libjwt/jwt-verify.c)
+
+add_library(builder OBJECT)
+target_sources(builder PRIVATE libjwt/jwt-common.c)
+target_compile_definitions(builder PRIVATE JWT_BUILDER)
+
+add_library(checker OBJECT)
+target_sources(checker PRIVATE libjwt/jwt-common.c)
+target_compile_definitions(checker PRIVATE JWT_CHECKER)
+
+target_link_libraries(jwt PRIVATE builder checker)
+target_link_libraries(jwt_static PRIVATE builder checker)
# Allow building without deprecated functions (suggested)
option(EXCLUDE_DEPRECATED
@@ -88,6 +86,8 @@ include_directories(${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}
target_link_libraries(jwt PUBLIC PkgConfig::JANSSON)
target_link_libraries(jwt_static PUBLIC PkgConfig::JANSSON)
+target_link_libraries(builder PUBLIC PkgConfig::JANSSON)
+target_link_libraries(checker PUBLIC PkgConfig::JANSSON)
# Process the detected packages
set(HAVE_CRYPTO FALSE)
@@ -101,15 +101,13 @@ if (GNUTLS_FOUND)
# libjwt/gnutls/jwk-parse.c
endif()
-if (OPENSSL_FOUND)
- set(HAVE_CRYPTO TRUE)
- add_definitions(-DHAVE_OPENSSL)
- target_link_libraries(jwt PUBLIC PkgConfig::OPENSSL)
- target_link_libraries(jwt_static PUBLIC PkgConfig::OPENSSL)
- list(APPEND JWT_SOURCES
- libjwt/openssl/jwk-parse.c
- libjwt/openssl/sign-verify.c)
-endif()
+set(HAVE_CRYPTO TRUE)
+add_definitions(-DHAVE_OPENSSL)
+target_link_libraries(jwt PUBLIC PkgConfig::OPENSSL)
+target_link_libraries(jwt_static PUBLIC PkgConfig::OPENSSL)
+list(APPEND JWT_SOURCES
+ libjwt/openssl/jwk-parse.c
+ libjwt/openssl/sign-verify.c)
function(jwt_add_extra)
set(oneValueArgs NAME SRC DIR)
@@ -127,7 +125,7 @@ function(jwt_add_tool)
cmake_parse_arguments(Tool "" "${oneValueArgs}" "" ${ARGN})
add_executable(${Tool_NAME} ${Tool_SRC})
- target_link_libraries(${Tool_NAME} PRIVATE jwt_static PkgConfig::OPENSSL)
+ target_link_libraries(${Tool_NAME} PRIVATE jwt_static PkgConfig::OPENSSL)
# target_link_libraries(${Tool_NAME} PRIVATE jwt)
set_target_properties(${Tool_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY
@@ -169,7 +167,7 @@ set_target_properties(jwt PROPERTIES
SOVERSION ${LIBJWT_COMPATVERSION}
)
-add_definitions(-D_GNU_SOURCE -O3 -Wall -Werror)
+add_definitions(-D_GNU_SOURCE -O3 -Wall -Werror -Wextra)
add_definitions(-DKEYDIR=\"${CMAKE_SOURCE_DIR}/tests/keys\")
# Install header
@@ -256,15 +254,14 @@ endfunction()
if (CHECK_FOUND)
include(CTest)
- set (UNIT_TESTS jwt_dump jwt_ec jwt_encode jwt_grant jwt_header
- jwt_new jwt_rsa jwt_validate jwt_rsa_pss jwt_eddsa
- jwt_crypto jwt_es256k)
+ set (UNIT_TESTS jwt_crypto)
- if (OPENSSL_FOUND)
- # For now, only OpenSSL supports JWKS tests
- list (APPEND UNIT_TESTS jwt_jwks jwt_jwks_errors
- jwt_jwks_ec jwt_jwks_rsa)
- endif()
+ # JWKS Tests
+ list (APPEND UNIT_TESTS jwt_jwks jwt_jwks_errors
+ jwt_ec jwt_rsa jwt_hs)
+
+ # Checker and Builder
+ list (APPEND UNIT_TESTS jwt_builder jwt_checker jwt_flipflop)
foreach (TEST ${UNIT_TESTS})
jwt_add_test(NAME ${TEST})
diff --git a/cmake/LibJWTDoxyfile.cmake b/cmake/LibJWTDoxyfile.cmake
index e0a81ec8..bbc63cbf 100644
--- a/cmake/LibJWTDoxyfile.cmake
+++ b/cmake/LibJWTDoxyfile.cmake
@@ -50,6 +50,7 @@ set(DOXYGEN_GENERATE_TAGFILE "${DOXYGEN_OUTPUT_DIRECTORY}/LibJWT.tag")
set(DOXYGEN_DOT_IMAGE_FORMAT "svg")
set(DOXYGEN_INTERACTIVE_SVG "YES")
set(DOXYGEN_SEARCHENGINE "NO")
+set(DOXYGEN_LAYOUT_FILE "doxygen/DoxygenLayout.xml")
# List of extra files we need for a nice theme
set(DOXYGEN_HTML_EXTRA_FILES "doxygen/doxygen-awesome-paragraph-link.js")
diff --git a/doxygen/DoxygenLayout.xml b/doxygen/DoxygenLayout.xml
new file mode 100644
index 00000000..3d37df9b
--- /dev/null
+++ b/doxygen/DoxygenLayout.xml
@@ -0,0 +1,269 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/main-auth.c b/examples/main-auth.c
index bb2ad97e..a707b4c6 100644
--- a/examples/main-auth.c
+++ b/examples/main-auth.c
@@ -14,7 +14,7 @@
#include
#include
-void usage(const char *name)
+static void usage(const char *name)
{
printf("%s --key example.json --token eyJhb...\n", name);
printf("Options:\n"
@@ -24,19 +24,46 @@ void usage(const char *name)
exit(0);
}
+static int __verify_wcb(jwt_t *jwt, jwt_config_t *config)
+{
+ jwt_value_t jval;
+ int ret;
+
+ if (config == NULL)
+ return 1;
+
+ jwt_set_GET_JSON(&jval, NULL);
+ jval.pretty = 1;
+ ret = jwt_header_get(jwt, &jval);
+ if (!ret) {
+ fprintf(stderr, "HEADER:\n%s\n", jval.json_val);
+ free(jval.json_val);
+ }
+
+ jwt_set_GET_JSON(&jval, NULL);
+ jval.pretty = 1;
+ ret = jwt_grant_get(jwt, &jval);
+ if (!ret) {
+ fprintf(stderr, "PAYLOAD:\n%s\n", jval.json_val);
+ free(jval.json_val);
+ }
+ return 0;
+}
+
int main(int argc, char *argv[])
{
+ jwt_checker_auto_t *checker = NULL;
char *key_file = NULL, *token = NULL;
jwt_alg_t opt_alg = JWT_ALG_NONE;
- JWT_CONFIG_DECLARE(config);
- jwt_auto_t *jwt = NULL;
jwk_set_auto_t *jwk_set = NULL;
const jwk_item_t *item = NULL;
- FILE *key_fp = NULL;
- char key_data[BUFSIZ];
- jwt_value_t jval;
- int key_len;
- int oc, ret;
+ int oc;
+
+ checker = jwt_checker_new();
+ if (checker == NULL) {
+ fprintf(stderr, "Could not allocate checker context\n");
+ exit(EXIT_FAILURE);
+ }
char *optstr = "hk:t:a";
struct option opttbl[] = {
@@ -97,71 +124,41 @@ int main(int argc, char *argv[])
/* Load JWK key */
if (key_file) {
- key_fp = fopen(key_file, "r");
- if (key_fp == NULL) {
- perror(key_file);
- exit(EXIT_FAILURE);
- }
- key_len = fread(key_data, 1, sizeof(key_data), key_fp);
- fclose(key_fp);
- key_data[key_len] = '\0';
-
- /* Setup JWK Set */
- jwk_set = jwks_create(key_data);
- if (jwk_set == NULL || jwks_error(jwk_set)) {
- fprintf(stderr, "ERR: Could not read JWK: %s\n",
- jwks_error_msg(jwk_set));
- exit(EXIT_FAILURE);
- }
- /* Get the first key */
- item = jwks_item_get(jwk_set, 0);
- if (jwks_item_error(item)) {
- fprintf(stderr, "ERR: Could not read JWK: %s\n",
- jwks_item_error_msg(item));
- exit(EXIT_FAILURE);
- }
-
- if (jwks_item_alg(item) == JWT_ALG_NONE && opt_alg == JWT_ALG_NONE) {
- fprintf(stderr, "Cannot find a valid algorithm in the "
- " JWK. You need to set it with --alg\n");
- exit(EXIT_FAILURE);
- }
-
- if (jwks_item_alg(item) != JWT_ALG_NONE && opt_alg != JWT_ALG_NONE &&
- jwks_item_alg(item) != opt_alg) {
- fprintf(stderr, "Key algorithm does not match --alg argument\n");
- exit(EXIT_FAILURE);
- }
+ jwk_set = jwks_create_fromfile(key_file);
+ if (jwk_set == NULL || jwks_error(jwk_set)) {
+ fprintf(stderr, "ERR: Could not read JWK: %s\n",
+ jwks_error_msg(jwk_set));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Get the first key */
+ item = jwks_item_get(jwk_set, 0);
+ if (jwks_item_error(item)) {
+ fprintf(stderr, "ERR: Could not read JWK: %s\n",
+ jwks_item_error_msg(item));
+ exit(EXIT_FAILURE);
+ }
+
+ if (jwt_checker_setkey(checker, opt_alg, item)) {
+ fprintf(stderr, "ERR Loading key: %s\n",
+ jwt_checker_error_msg(checker));
+ exit(EXIT_FAILURE);
+ }
}
- /* Decode jwt */
- config.jw_key = item;
- config.alg = opt_alg;
- jwt = jwt_verify(token, &config);
- if (jwt == NULL || jwt_error(jwt)) {
- fprintf(stderr, "JWT could not be verified: %s\n",
- jwt ? jwt_error_msg(jwt) : "Unknown reason");
+ if (jwt_checker_setcb(checker, __verify_wcb, NULL)) {
+ fprintf(stderr, "ERR setting callback: %s\n",
+ jwt_checker_error_msg(checker));
exit(EXIT_FAILURE);
}
- fprintf(stderr, "JWT %s successfully!\n",
- token ? "verified" : "decoded");
-
- jwt_set_GET_JSON(&jval, NULL);
- jval.pretty = 1;
- ret = jwt_header_get(jwt, &jval);
- if (!ret) {
- fprintf(stderr, "HEADER:\n%s\n", jval.json_val);
- free(jval.json_val);
+ if (jwt_checker_verify(checker, token)) {
+ fprintf(stderr, "ERR verifyiung token: %s\n",
+ jwt_checker_error_msg(checker));
+ exit(EXIT_FAILURE);
}
- jwt_set_GET_JSON(&jval, NULL);
- jval.pretty = 1;
- ret = jwt_grant_get(jwt, &jval);
- if (!ret) {
- fprintf(stderr, "PAYLOAD:\n%s\n", jval.json_val);
- free(jval.json_val);
- }
+ fprintf(stderr, "JWT verfified successfully\n");
exit(EXIT_SUCCESS);
}
diff --git a/examples/main-gen.c b/examples/main-gen.c
index 8d2d6d5a..7378285e 100644
--- a/examples/main-gen.c
+++ b/examples/main-gen.c
@@ -18,9 +18,10 @@ void usage(const char *name)
{
printf("%s OPTIONS\n", name);
printf("Options:\n"
- " -k --key KEY The private JWK to use for signing (.json)\n"
+ " -k --key KEY The private key to use for signing (JWT json)\n"
" -a --alg ALG The algorithm to use for signing\n"
- " -c --claim KEY=VALUE A claim to add to JWT\n"
+ " -c --claim t:KEY=VALUE A claim to add to JWT\n"
+ " where t is i, s, or b for integer, string, or boolean\n"
" -j --json '{key1:value1}' A json to add to JWT\n"
);
exit(0);
@@ -43,24 +44,19 @@ int main(int argc, char *argv[])
{ NULL, 0, 0, 0 },
};
- char *k = NULL, *v = NULL;
- int claims_count = 0;
- int i = 0;
- char key[BUFSIZ];
- size_t key_len = 0;
- FILE *fp_priv_key;
- int ret = 0;
- jwt_auto_t *jwt = NULL;
+ char *t = NULL, *k = NULL, *v = NULL;
jwk_set_auto_t *jwk_set = NULL;
const jwk_item_t *item = NULL;
- jwt_value_t jval;
- struct kv {
- char *key;
- char *val;
- } opt_claims[100];
- memset(opt_claims, 0, sizeof(opt_claims));
char* opt_json = NULL;
- JWT_CONFIG_DECLARE(config);
+ jwt_builder_auto_t *builder = NULL;
+ jwt_value_t jval;
+ char *out;
+
+ builder = jwt_builder_new();
+ if (builder == NULL) {
+ fprintf(stderr, "Could not allocate builder context\n");
+ exit(EXIT_FAILURE);
+ }
while ((oc = getopt_long(argc, argv, optstr, opttbl, NULL)) != -1) {
switch (oc) {
@@ -71,24 +67,52 @@ int main(int argc, char *argv[])
case 'a':
opt_alg = jwt_str_alg(optarg);
if (opt_alg >= JWT_ALG_INVAL) {
- fprintf(stderr, "%s is not supported algorithm\n", optarg);
+ fprintf(stderr,
+ "%s is not supported algorithm\n",
+ optarg);
exit(EXIT_FAILURE);
}
break;
case 'c':
- k = strtok(optarg, "=");
- if (k) {
- v = strtok(NULL, "=");
- if (v) {
- opt_claims[claims_count].key = k;
- opt_claims[claims_count].val = v;
- claims_count++;
- }
+ t = strtok(optarg, ":");
+ if (t == NULL)
+ usage(basename(argv[0]));
+ k = strtok(NULL, "=");
+ if (k == NULL)
+ usage(basename(argv[0]));
+
+ v = strtok(NULL, "=");
+ if (v == NULL)
+ usage(basename(argv[0]));
+
+ switch (t[0]) {
+ case 's':
+ jwt_set_ADD_STR(&jval, k, v);
+ break;
+ case 'i':
+ jwt_set_ADD_INT(&jval, k, strtol(v, NULL, 10));
+ break;
+ case 'b':
+ if (v[0] == 'f' || v[0] == 'F' || v[0] == '0')
+ jwt_set_ADD_BOOL(&jval, k, 0);
+ else
+ jwt_set_ADD_BOOL(&jval, k, 1);
+ break;
+ default:
+ usage(basename(argv[0]));
}
+ if (jwt_builder_claim_add(builder, &jval)) {
+ fprintf(stderr, "Error adding %s:%s=%s\n",
+ t, k, v);
+ exit(EXIT_FAILURE);
+ }
+
break;
case 'j':
- opt_json = optarg;
+ if (optarg != NULL) {
+ opt_json = strdup(optarg);
+ }
break;
case 'h':
@@ -104,24 +128,17 @@ int main(int argc, char *argv[])
fprintf(stderr, "jwtgen: privkey %s algorithm %s\n",
opt_key_name, jwt_alg_str(opt_alg));
- if (opt_alg > JWT_ALG_NONE) {
- fp_priv_key = fopen(opt_key_name, "r");
- if (fp_priv_key == NULL) {
- perror("Failed to open key file");
- goto finish;
- }
- key_len = fread(key, 1, sizeof(key), fp_priv_key);
- fclose(fp_priv_key);
- key[key_len] = '\0';
- fprintf(stderr, "priv key loaded %s (%zu)!\n", opt_key_name, key_len);
+ if (opt_alg != JWT_ALG_NONE && opt_key_name == NULL)
+ usage(basename(argv[0]));
- /* Setup JWK Set */
- jwk_set = jwks_create(key);
+ if (opt_key_name) {
+ jwk_set = jwks_create_fromfile(opt_key_name);
if (jwk_set == NULL || jwks_error(jwk_set)) {
fprintf(stderr, "ERR: Could not read JWK: %s\n",
jwks_error_msg(jwk_set));
exit(EXIT_FAILURE);
}
+
/* Get the first key */
item = jwks_item_get(jwk_set, 0);
if (jwks_item_error(item)) {
@@ -130,67 +147,47 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- if (jwks_item_alg(item) == JWT_ALG_NONE && opt_alg == JWT_ALG_NONE) {
- fprintf(stderr, "Cannot find a valid algorithm in the "
- " JWK. You need to set it with --alg\n");
- exit(EXIT_FAILURE);
- }
-
- if (jwks_item_alg(item) != JWT_ALG_NONE && opt_alg != JWT_ALG_NONE &&
- jwks_item_alg(item) != opt_alg) {
- fprintf(stderr, "Key algorithm does not match --alg argument\n");
+ if (jwt_builder_setkey(builder, opt_alg, item)) {
+ fprintf(stderr, "ERR Loading key: %s\n",
+ jwt_builder_error_msg(builder));
exit(EXIT_FAILURE);
}
}
- config.jw_key = item;
- config.alg = opt_alg;
- jwt = jwt_create(&config);
- if (jwt == NULL) {
- fprintf(stderr, "invalid jwt\n");
- goto finish;
- }
-
jwt_set_ADD_INT(&jval, "iat", iat);
- jwt_grant_add(jwt, &jval);
- for (i = 0; i < claims_count; i++) {
- fprintf(stderr, "Adding claim %s with value %s\n",
- opt_claims[i].key, opt_claims[i].val);
-
- jwt_set_ADD_STR(&jval, opt_claims[i].key, opt_claims[i].val);
- jwt_grant_add(jwt, &jval);
+ if (jwt_builder_claim_add(builder, &jval)) {
+ fprintf(stderr, "Error adding iat\n");
+ exit(EXIT_FAILURE);
}
- if (opt_json != NULL) {
+ if (opt_json) {
jwt_set_ADD_JSON(&jval, NULL, opt_json);
- ret = jwt_grant_add(jwt, &jval);
- if (ret != 0) {
- fprintf(stderr, "Input json is invalid\n");
- goto finish;
+ if (jwt_builder_claim_add(builder, &jval)) {
+ fprintf(stderr, "Error adding iat\n");
+ exit(EXIT_FAILURE);
}
}
- char *out = jwt_encode_str(jwt);
- printf("Token: %s\n", out);
- free(out);
-
jwt_set_GET_JSON(&jval, NULL);
jval.pretty = 1;
- if (jwt_header_get(jwt, &jval) == JWT_VALUE_ERR_NONE) {
- fprintf(stderr, "HEADER: %s\n", jval.json_val);
+ if (jwt_builder_claim_get(builder, &jval) == JWT_VALUE_ERR_NONE) {
+ fprintf(stderr, "PAYLOAD: %s\n", jval.json_val);
free(jval.json_val);
}
- jwt_set_GET_JSON(&jval, NULL);
- jval.pretty = 1;
- if (jwt_grant_get(jwt, &jval) == JWT_VALUE_ERR_NONE) {
- fprintf(stderr, "PAYLOAD: %s\n", jval.json_val);
- free(jval.json_val);
+ out = jwt_builder_generate(builder);
+ if (out == NULL) {
+ fprintf(stderr, "ERR Generating Token: %s\n",
+ jwt_builder_error_msg(builder));
+ exit(EXIT_FAILURE);
}
fprintf(stderr, "jwt algo %s!\n", jwt_alg_str(opt_alg));
-finish:
+ printf("%s\n", out);
+
+ free(out);
+
return 0;
}
diff --git a/include/jwt.h b/include/jwt.h
index bc2aa0c6..698f1a64 100644
--- a/include/jwt.h
+++ b/include/jwt.h
@@ -24,34 +24,21 @@
extern "C" {
#endif
-/** @ingroup jwt_core_grp
+/** @ingroup jwt_grp
* @brief Opaque JWT object
*
- * This object is used throughout the JWT functions.
- *
- * @remark When creating a JWT object (encoding), this stores state until
- * you call one of the encoding functions. When dedcoding a JSON Web Token
- * this object is returned so you can inspect it further (e.g. retrieve
- * grants).
+ * Used in callbacks when generating or verifying a JWT
*/
typedef struct jwt jwt_t;
-/** @ingroup jwt_valid_grp
- * @brief Opaque JWT Validation object
- *
- * Used in the JWT validation functions.
- */
-typedef struct jwt_valid jwt_valid_t;
-
/** @ingroup jwks_core_grp
* @brief Opaque JWKS object
*
* Used for working with JSON Web Keys and JWK Sets (JWKS).
*
- * @remark All JWK operations require that you import your JWK into a
- * jwk_set_t first. Internal, LibJWT creates a jwk_set_t even for single
- * keys. This makes code pretty much the same whether working with one JWK
- * or a set of them.
+ * @remark All JWK operations require that you import your JWK into a jwk_set_t
+ * first. Internal, LibJWT creates a jwk_set_t even for single keys. This makes
+ * code pretty much the same whether working with one JWK or a set of them.
*/
typedef struct jwk_set jwk_set_t;
@@ -99,7 +86,7 @@ typedef enum {
JWT_CRYPTO_OPS_ANY, /**< Used internally for hmac keys */
} jwt_crypto_provider_t;
-/** @ingroup jwks_core_grp
+/** @ingroup jwks_item_grp
* @brief JWK Key Types
*
* Corresponds to the ``"kty"`` attribute of the JWK.
@@ -115,7 +102,7 @@ typedef enum {
JWK_KEY_TYPE_OCT, /**< Octet sequence (e.g. HS256) */
} jwk_key_type_t;
-/** @ingroup jwks_core_grp
+/** @ingroup jwks_item_grp
* @brief Usage types for JWK public keys
*
* Corresponds to the ``"use"`` attribute in a JWK the represents a public key.
@@ -124,16 +111,16 @@ typedef enum {
**/
typedef enum {
JWK_PUB_KEY_USE_NONE = 0, /**< No usable attribute was set */
- JWK_PUB_KEY_USE_SIG, /**< Signature validation (JWS) */
- JWK_PUB_KEY_USE_ENC, /**< Decryption key (JWE) */
+ JWK_PUB_KEY_USE_SIG, /**< Signature key (JWS) */
+ JWK_PUB_KEY_USE_ENC, /**< Encryption key (JWE) */
} jwk_pub_key_use_t;
-/** @ingroup jwks_core_grp
+/** @ingroup jwks_item_grp
* @brief Allowed key operations for JWK private keys
*
* Corresponds to the ``"key_ops"`` attribute in a JWK that represents a private
- * key. These can be bitwise compares to the key_ops attribute of a @ref
- * jwk_item_t. These flags are used internally to decide if a JWK can be used
+ * key. These can be bitwise compares to the key_ops attribute of a jwk_item_t.
+ * These flags are used internally to decide if a JWK can be used
* for cartain operations.
*
* @code
@@ -157,35 +144,62 @@ typedef enum {
JWK_KEY_OP_INVALID = 0xffff, /**< Invalid key_ops in JWK */
} jwk_key_op_t;
-/** @ingroup jwks_core_grp
- * @brief Object representation of a JWK
- *
- * This object is produced by importing a JWK or JWKS into a @ref jwk_set_t
- * object. It is passed functions that either producr or consume JWT.
+/** @ingroup jwt_setget_grp
+ * @brief Value types for grants and headers
*/
-typedef struct jwk_item jwk_item_t;
+typedef enum {
+ JWT_VALUE_NONE = 0, /**< No type (do not use this) */
+ JWT_VALUE_INT, /**< Integer */
+ JWT_VALUE_STR, /**< String */
+ JWT_VALUE_BOOL, /**< Boolean */
+ JWT_VALUE_JSON, /**< JSON String (object format ``{}``) */
+ JWT_VALUE_INVALID, /**< Invalid (used internally) */
+} jwt_value_type_t;
-/** @ingroup jwt_valid_grp
- * @brief Validation exception types for @ref jwt_t objects
+/** @ingroup jwt_setget_grp
+ * @brief Error values for header and grant requests
+ */
+typedef enum {
+ JWT_VALUE_ERR_NONE = 0, /**< No error, success */
+ JWT_VALUE_ERR_EXIST, /**< Item exists (when adding) */
+ JWT_VALUE_ERR_NOEXIST, /**< Item doesn't exist (when getting) */
+ JWT_VALUE_ERR_TYPE, /**< Item is not of the type requested */
+ JWT_VALUE_ERR_INVALID, /**< Invalid request (general error) */
+ JWT_VALUE_ERR_NOMEM, /**< Memory allocation error */
+} jwt_value_error_t;
+
+/** @ingroup jwt_setget_grp
+ * @brief Data type for get and add actions for JWT headers and grants
*
- * These are bitwise values that allow you to check for exceptions when using
- * the @ref jwt_valid_t
+ * This is used for both add and get requests. Specific rules for each type is
+ * described in more detail for the add and get requests.
*
- * @todo @rfc_t{7519,4.1.6} ``"iat"`` Issued At
- * @todo @rfc_t{7519,4.1.7} ``"jti"`` JWT ID
+ * @note There are helper macros to simplify settng this structure properly and
+ * reducing common mistakes. See the jwt_set_{ADD,GET}_{INT,STR,BOOL,JSON}
+ * definitions.
*/
-typedef enum {
-JWT_VALIDATION_SUCCESS = 0x0000, /**< Validation succeeded */
-JWT_VALIDATION_ERROR = 0x0001, /**< General failures */
-JWT_VALIDATION_ALG_MISMATCH = 0x0002, /**< @rfc_t{7518,3.1} ``"alg"`` Algorithm */
-JWT_VALIDATION_EXPIRED = 0x0004, /**< @rfc_t{7519,4.1.4} ``"exp"`` Expired */
-JWT_VALIDATION_TOO_NEW = 0x0008, /**< @rfc_t{7519,4.1.5} ``"nbf"`` Not Before */
-JWT_VALIDATION_ISS_MISMATCH = 0x0010, /**< @rfc_t{7519,4.1.1} ``"iss"`` Issuer */
-JWT_VALIDATION_SUB_MISMATCH = 0x0020, /**< @rfc_t{7519,4.1.2} ``"sub"`` Subject */
-JWT_VALIDATION_AUD_MISMATCH = 0x0040, /**< @rfc_t{7519,4.1.3} ``"aud"`` Audience */
-JWT_VALIDATION_GRANT_MISSING = 0x0080, /**< User-defined Grant missing */
-JWT_VALIDATION_GRANT_MISMATCH = 0x0100, /**< User-defined Grant mismatch */
-} jwt_valid_exception_t;
+typedef struct {
+ jwt_value_type_t type;
+ char *name;
+ union {
+ long int_val;
+ const char *str_val;
+ int bool_val;
+ char *json_val;
+ };
+ int replace;
+ int pretty;
+ jwt_value_error_t error;
+} jwt_value_t;
+
+/** @ingroup jwks_item_grp
+ * @brief Object representation of a JWK
+ *
+ * This object is produced by importing a JWK or JWKS into a @ref jwk_set_t
+ * object. It represents single key and is used when generating or verifying
+ * JWT.
+ */
+typedef struct jwk_item jwk_item_t;
/** @ingroup jwt_memory_grp
* @brief Prototype for malloc(3)
@@ -208,299 +222,442 @@ typedef void (*jwt_free_t)(void *);
*/
/**
- * @defgroup jwt_core_grp Utility functions
+ * Get the jwt_alg_t set for this JWT object.
*
- * Utility functions for JWT objects.
- * @{
+ * Returns the jwt_alg_t type for this JWT object.
+ *
+ * @param jwt Pointer to a JWT object.
+ * @returns Returns a jwt_alg_t type for this object.
*/
+JWT_EXPORT
+jwt_alg_t jwt_get_alg(const jwt_t *jwt);
/**
- * @brief Check JWT for error condition
- *
- * The relevance of this is dependent on whether this is a JWT being created,
- * or one being verified. See those functions for more information. Either way,
- * if a JWT has an error, it cannot be trusted.
+ * @brief Structure used to pass state with a user callback
+ */
+typedef struct {
+ const jwk_item_t *key; /**< A JWK to use for key */
+ jwt_alg_t alg; /**< For algorithm matching */
+ void *ctx; /**< User controlled context */
+} jwt_config_t;
+
+/**
+ * @brief General callback for generation and verification of JWT
+ */
+typedef int (*jwt_callback_t)(jwt_t *, jwt_config_t *);
+
+/**
+ * @brief WFC defined claims
+ */
+typedef enum {
+ JWT_CLAIM_DEFAULT = 0x0000, /**< Nothing set, default claims */
+ JWT_CLAIM_NONE = 0x0001, /**< No checks */
+ JWT_CLAIM_ISS = 0x0002, /**< @rfc_t{7519,4.1.1} ``"iss"`` */
+ JWT_CLAIM_SUB = 0x0004, /**< @rfc_t{7519,4.1.2} ``"sub"`` */
+ JWT_CLAIM_AUD = 0x0008, /**< @rfc_t{7519,4.1.3} ``"aud"`` */
+ JWT_CLAIM_EXP = 0x0010, /**< @rfc_t{7519,4.1.4} ``"exp"`` */
+ JWT_CLAIM_NBF = 0x0020, /**< @rfc_t{7519,4.1.5} ``"nbf"`` */
+ JWT_CLAIM_IAT = 0x0040, /**< @rfc_t{7519,4.1.6} ``"iat"`` */
+ JWT_CLAIM_JTI = 0x0080, /**< @rfc_t{7519,4.1.7} ``"nbf"`` */
+ JWT_CLAIMS_ENFORCE = 0x8000, /**< Fail if claim is missing */
+ JWT_CLAIMS_ALL = 0x80fe, /**< Mask of all claims */
+} jwt_claims_t;
+
+/**
+ * @brief Default validations
*
- * @param jwt Pointer to a jwt_t object
- * @return 0 if no error, 1 if there is
+ * Beyond the normal validations (e.g. algorithm, and signature checks) these
+ * are the ones that will be performed if the grants exist in the JWT. If the
+ * grants do not exist, they validation will be ignores.
*
- * @remark When creating a JWT and verifying one, you shoudl always check this
- * state.
+ * @note If you do not set any validation flags (JWT_VALIDATION_EMPTY), these
+ * will be used. If you do not want them used, them you must set
+ * JWT_VALIDATION_NONE to override it.
*/
-JWT_EXPORT
-int jwt_error(const jwt_t *jwt);
+#define JWT_CHECKER_CLAIMS (JWT_CLAIM_EXP|JWT_CLAIM_NBF)
+
+#define JWT_BUILDER_CLAIMS (JWT_CLAIM_IAT)
/**
- * @brief Print an error message from a JWT
+ * @defgroup jwt_builder_grp Builder
*
- * If jwt_error() shows an an error condition, this will give you a better idea
- * of the actual error being reported.
+ * Creating a JWT token involves several steps. First is creating a
+ * jwt_builder_t object, which can be thought of as a JWT factory. Once
+ * configured, you can use it to create tokens with pre-defined claims.
+ * @{
+ */
+
+/**
+ * @brief Opaque Builder
+ */
+typedef struct jwt_builder jwt_builder_t;
+
+/**
+ * @brief Function to create a new builder instance
*
- * @param jwt Pointer to a jwt_t object
- * @return A string message. The string may be empty.
+ * @return Pointer to a builder object on success, NULL on failure
*/
JWT_EXPORT
-const char *jwt_error_msg(const jwt_t *jwt);
+jwt_builder_t *jwt_builder_new(void);
/**
- * @brief Free a JWT object and any other resources it is using.
+ * @brief Frees a previously created builder object
*
- * After calling, the JWT object referenced will no longer be valid and
- * its memory will be freed.
- *
- * @param jwt Pointer to a JWT object previously created object
+ * @param builder Pointer to a builder object
*/
JWT_EXPORT
-void jwt_free(jwt_t *jwt);
+void jwt_builder_free(jwt_builder_t *builder);
#if defined(__GNUC__) || defined(__clang__)
/**
- * @brief Helper function to free a JWT and set the pointer to NULL
+ * @brief Helper function to free a builder and set the pointer to NULL
*
- * This is mainly to use with the jwt_auto_t type.
+ * This is mainly to use with the jwt_builder_auto_t type.
*
- * @param Pointer to a pointer for a jwt_t object
+ * @param Pointer to a pointer for a jwt_builder_t object
*/
-static inline void jwt_freep(jwt_t **jwt) {
- if (jwt) {
- jwt_free(*jwt);
- *jwt = NULL;
+static inline void jwt_builder_freep(jwt_builder_t **builder) {
+ if (builder) {
+ jwt_builder_free(*builder);
+ *builder = NULL;
}
}
+#define jwt_builder_auto_t jwt_builder_t \
+ __attribute__((cleanup(jwt_builder_freep)))
+#endif
+
/**
- * @brief Scoped cleanup type for jwt_t
- *
- * Declaring a jwt_t with jwt_auto_t will ensure that the memory used by it is
- * cleaned up when the variable goes our of scope (e.g. when a function
- * returns).
- *
- * @warning Make sure to initialize thsi to NULL when declaring with this type.
- *
- * @code
- * void my_app_check_token(const char *token)
- * {
- * jwt_auto_t *myjwt = NULL;
- *
- * // ...
+ * @brief Checks error state of builder object
*
- * myjwt = jwt_create(NULL);
- *
- * // ...
- * if (error_val)
- * return -1; // myjwt will be freed here automatically
+ * @param builder Pointer to a builder object
+ * @return 0 if no errors exist, non-zero otherwise
+ */
+JWT_EXPORT
+int jwt_builder_error(const jwt_builder_t *builder);
+
+/**
+ * @brief Get the error message contained in a builder object
*
- * return 0; // myjwt will be freed here automatically
- * }
- * @endcode
+ * @param builder Pointer to a builder object
+ * @return Pointer to a string with the error message. Can be an empty string
+ * if there is no error. Never returns NULL.
*/
-#define jwt_auto_t jwt_t __attribute__((cleanup(jwt_freep)))
-#endif
+JWT_EXPORT
+const char *jwt_builder_error_msg(const jwt_builder_t *builder);
/**
- * @brief Duplicate an existing JWT object.
+ * @brief Sets a key and algorithm for a builder
*
- * Copies all grants and algorithm specific bits to a new JWT object. This
- * includes the jw_key that is associated with it, if it exists. However, the
- * key is only copied by reference, and is not, itself, duplicated.
+ * The values here must make sense. This table shows what will or wont pass as
+ * far as algorithm matching between the alg param and the alg in jwk_item_t.
+ * Where ``alg-A`` means one specific algorithm (not none) and ``alg-B``
+ * represents another (also not none). The ``none`` is used to represent no
+ * algorithm being set. ``NULL`` represents that jwk_item_t pointer is NULL.
*
- * @note If the jwt_t has an error, that error state will also be copied.
+ * | alg | jwt_item_t | Result
+ * :-------: | :--------: | :-----------------------:
+ * ``alg-A`` | ``alg-A`` | \emoji :white_check_mark:
+ * ``none`` | ``alg-A`` | \emoji :white_check_mark:
+ * ``alg-A`` | ``none`` | \emoji :white_check_mark:
+ * ``none`` | ``NULL`` | \emoji :warning:
+ * ``alg-A`` | ``alg-B`` | \emoji :x:
+ * ``alg-A`` | ``NULL`` | \emoji :x:
*
- * @param jwt Pointer to a JWT object.
- * @return A new object on success, NULL on error
+ * @warning The warning represents an insecure token. Using insecure tokens is
+ * not very useful and strongly discouraged.
+ *
+ * @param builder Pointer to a builder object
+ * @param alg A valid jwt_alg_t type
+ * @param key A JWK key object
+ * @return 0 on success, non-zero otherwise with error set in the builder
*/
JWT_EXPORT
-jwt_t *jwt_dup(jwt_t *jwt);
+int jwt_builder_setkey(jwt_builder_t *builder, const jwt_alg_t alg,
+ const jwk_item_t *key);
/**
- * @}
- * @noop jwt_core_grp
+ * @brief Clear error state in a builder object
+ *
+ * @param builder Pointer to a builder object
*/
+JWT_EXPORT
+void jwt_builder_error_clear(jwt_builder_t *builder);
/**
- * @defgroup jwt_config_grp Configuration Type
+ * @brief Set claims for a builder object
*
- * The JWT configuration type is setup to allow an agnostic way to handle
- * state between different functions. The specific uses of the type varies
- * according to whether you are providing or consuming tokens. These aspects
- * are documented in the other sections.
+ * These only apply to the RFC defined claims. The ``iat`` claim is the
+ * only one that's automated, and will default to the time at which
+ * jwt_builder_generate() was called to create the token.
*
- * This section is a light intro of config type and common usage.
+ * The ``nbf`` and ``exp`` claims need to have the offsets set as well. The
+ * Others can be set, but will need values added with jwt_builder_claim_add()
+ * in order to be enforced.
*
- * @remark LibJWT does not internally modify or set information in the
- * @ref jwt_config_t object. Certain values will determine how LibJWT
- * handles various functions.
- * @{
- */
-
-/**
- * @brief Structure used to manage configuration state
+ * @param builder Pointer to a builder object
+ * @param grants A bitwise set of values in jwt_claims_t
+ * @return 0 on success, non-zero otherwise with error set in the builder
*/
-typedef struct {
- const jwk_item_t *jw_key; /**< A JWK to use for key */
- jwt_alg_t alg; /**< For algorithm matching */
- void *ctx; /**< User controlled context */
-} jwt_config_t;
+JWT_EXPORT
+int jwt_builder_setclaims(jwt_builder_t *builder, jwt_claims_t grants);
/**
- * @brief Intialize @ref jwt_config_t to a clean state.
+ * @brief Set a callback for generating tokens
+ *
+ * When generating a token, this callback will be run after jwt_t has been
+ * created, but before the token is encoded. During this, the callback can add,
+ * change, or remove claims and header attributes. It can also use the
+ * jwt_value_t structure to set a key and alg to use when signing the token.
*
- * To ensure a @ref jwt_config_t is at a known state, this will clear
- * values in the config. It will not free memory that might be associated
- * with internal pointers.
+ * The ctx value is also passed to the callback as part of the jwt_value_t
+ * struct.
*
- * @param config Pointer to config to be cleared
+ * @param builder Pointer to a builder object
+ * @param cb Pointer to a callback function
+ * @param ctx Pointer to data to pass to the callback function
+ * @return 0 on success, non-zero otherwise with error set in the builder
*/
JWT_EXPORT
-void jwt_config_init(jwt_config_t *config);
+int jwt_builder_setcb(jwt_builder_t *builder, jwt_callback_t cb, void *ctx);
/**
- * @brief Decleration of a @ref jwt_config_t
+ * @brief Generate a token
*
- * This is useful for scoped usage to avoid declaring it and running the
- * @ref jwt_config_init function.
+ * The result of this function is to generate a string containing a JWT. A
+ * token is represetned by 3 parts: ``header``.``payload``.``sig``. Each part is
+ * Base64url Encoded. An example would be:
*
* @code
- * void some_function(const char *token)
- * {
- * JWT_CONFIG_DECLARE(my_config);
- * jwt_auto_t *my_jwt;
- * int ret;
+ * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MzY0MzI0MzR9.iDn6N9JsAdUPF11ow0skIfc9eJc2wGRIq30RSRZ8_68
+ * @endcode
+ *
+ * When decoded, the header and payload woild look like this (excluding the
+ * signature block)::
*
- * // Setup my_config with key, alg type, etc
+ * @code
+ * {"alg":"HS256","typ":"JWT"}.{"iat":1736432434}
+ * @endcode
*
- * my_jwt = jwt_verify(token, &my_config);
- * if (my_jwt == NULL || jwt_error(my_jwt))
- * ...;
+ * If pretty printed:
*
- * // Success
+ * @code
+ * {
+ * "alg": "HS256",
+ * "typ": "JWT"
+ * }
+ * .
+ * {
+ * "iat": 1736432434
* }
* @endcode
- */
-#define JWT_CONFIG_DECLARE(__name) \
- jwt_config_t __name = { NULL, JWT_ALG_NONE, NULL}
-
-/**
- * @brief Callback for operations involving verification of tokens.
*
- * Further details can be found in @ref jwt_verify_grp, specifically
- * for @ref jwt_verify_wcb
+ * The signature block is a cryptographic has. It's length and format is
+ * dependent on the algorithm being used.
+ *
+ * @param builder Pointer to a builder object
+ * @return A string containing a JWT. Caller is respondible for freeing the
+ * memory for this string. On error, NULL is returned and error is set in
+ * the builder object.
*/
-typedef int (*jwt_callback_t)(const jwt_t *, jwt_config_t *);
+JWT_EXPORT
+char *jwt_builder_generate(jwt_builder_t *builder);
/**
* @}
- * @noop jwt_config_grp
+ * @noop jwt_builder_grp
*/
/**
- * @defgroup jwt_create_grp Creation
+ * @defgroup jwt_checker_grp Checker
*
- * Creating a JWT token involves several steps. First is creating the jwt_t
- * object. Next would be adding grants relevant to the usage and scope of this
- * token, and finally encoding (signing and generating).
+ * Creating a JWT token involves several steps. First is creating a
+ * jwt_builder_t object, which can be thought of as a JWT factory. Once
+ * configured, you can use it to create tokens with pre-defined claims.
* @{
*/
-/**
- * @brief Initial function to create a new JWT
- *
- * Create a new jwt_t object in preperation for encoding a new token. The
- * config passed should contain an alg and a key that will be used to sign the
- * token once done. If config.jw_key has an alg other than none, it must match
- * config.alg.
- *
- * The resulting jwt_t object would then be used to add grants and other
- * relevant information before finally passing it to one of the jwt_encode
- * functions.
- *
- * This function rarely returns NULL. Usually only when memory cannot be
- * allocated for the new jwt_t object. Callers are required to check for errors
- * with jwt_error() after calling this function.
- *
- * If you want to create an insecure key (not suggested), either pass NULL as
- * the config, or pass a config with just alg set as JWT_ALG_NONE, and jw_key
- * set as NULL.
- *
- * @warning Creating insecure tokens is not very useful and strongly
- * discouraged.
- *
- * @param config A jwt_config_t with settings for creating the token
- * @return A new jwt_t object, or NULL of there was an error allocating it
- */
+typedef struct jwt_checker jwt_checker_t;
+JWT_EXPORT
+jwt_checker_t *jwt_checker_new(void);
+
+JWT_EXPORT
+void jwt_checker_free(jwt_checker_t *checker);
+
+#if defined(__GNUC__) || defined(__clang__)
+static inline void jwt_checker_freep(jwt_checker_t **checker) {
+ if (checker) {
+ jwt_checker_free(*checker);
+ *checker = NULL;
+ }
+}
+#define jwt_checker_auto_t jwt_checker_t \
+ __attribute__((cleanup(jwt_checker_freep)))
+#endif
+
+JWT_EXPORT
+int jwt_checker_error(const jwt_checker_t *checker);
+JWT_EXPORT
+const char *jwt_checker_error_msg(const jwt_checker_t *checker);
JWT_EXPORT
-jwt_t *jwt_create(jwt_config_t *config);
+void jwt_checker_error_clear(jwt_checker_t *checker);
+
+JWT_EXPORT
+int jwt_checker_setkey(jwt_checker_t *checker, const jwt_alg_t alg, const
+ jwk_item_t *key);
+JWT_EXPORT
+int jwt_checker_setclaims(jwt_checker_t *checker, jwt_claims_t grants);
+JWT_EXPORT
+int jwt_checker_setcb(jwt_checker_t *checker, jwt_callback_t cb, void *ctx);
+JWT_EXPORT
+int jwt_checker_verify(jwt_checker_t *checker, const char *token);
/**
- * @brief Fully encode a JWT object and return as a string.
- *
- * Similar to jwt_encode_fp() except that a string is returned. The string
- * must be freed by the caller.
- *
- * @param jwt Pointer to a JWT object.
- * @return A null terminated string on success, NULL on error with errno
- * set appropriately.
+ * @}
+ * @noop jwt_checker_grp
*/
-JWT_EXPORT
-char *jwt_encode_str(jwt_t *jwt);
/**
- * @brief Fully encode a JWT object and write it to FILE.
- *
- * This will create and write the complete JWT object to FILE. All parts
- * will be Base64 encoded and signatures or encryption will be applied if
- * the algorithm specified requires it.
- *
- * @param jwt Pointer to a JWT object.
- * @param fp Valid FILE pointer to write data to.
- * @return Returns 0 on success, valid errno otherwise.
+ * @defgroup jwt_claims_grp Working with Claims
+ * @{
*/
+
+JWT_EXPORT
+jwt_value_error_t jwt_builder_header_add(jwt_builder_t *builder, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_builder_header_get(jwt_builder_t *builder, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_builder_header_del(jwt_builder_t *builder, const char
+ *header);
+JWT_EXPORT
+jwt_value_error_t jwt_builder_claim_add(jwt_builder_t *builder, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_builder_claim_get(jwt_builder_t *builder, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_builder_claim_del(jwt_builder_t *builder, const char
+ *header);
+
+JWT_EXPORT
+jwt_value_error_t jwt_checker_header_add(jwt_checker_t *checker, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_checker_header_get(jwt_checker_t *checker, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_checker_header_del(jwt_checker_t *checker, const char
+ *header);
JWT_EXPORT
-int jwt_encode_fp(jwt_t *jwt, FILE *fp);
+jwt_value_error_t jwt_checker_claim_add(jwt_checker_t *checker, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_checker_claim_get(jwt_checker_t *checker, jwt_value_t
+ *value);
+JWT_EXPORT
+jwt_value_error_t jwt_checker_claim_del(jwt_checker_t *checker, const char
+ *header);
/**
* @}
- * @noop jwt_create_grp
+ * @noop jwt_claims_grp
*/
/**
* @defgroup jwt_verify_grp Verification
*
- * LibJWT provides mechanisms to verify a JWT including the signature block.
+ * LibJWT provides mechanisms to verify a JWT, including the signature block.
* Many aspects of this verification are defined by the relevant RFCs.
*
- * @raisewarning Need more indepth information
+ * A ``token`` is a string that represents an encoded (and usually signed) JWT.
+ * It contains 3 parts: ``header``.``payload``.``sig``
+ *
+ * Each part is Base64url Encoded. An example would be:
+ *
+ * @code
+ * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MzY0MzI0MzR9.iDn6N9JsAdUPF11ow0skIfc9eJc2wGRIq30RSRZ8_68
+ * @endcode
+ *
+ * When decoded, the header and payload look like:
*
+ * @code
+ * {"alg":"HS256","typ":"JWT"}.{"iat":1736432434}
+ * @endcode
+ *
+ * Or with pretty printing:
+ *
+ * @code
+ * {
+ * "alg": "HS256",
+ * "typ": "JWT"
+ * }
+ * .
+ * {
+ * "iat": 1736432434
+ * }
+ * @endcode
+ *
+ * The signature block decodes into binary bytes that represent the
+ * cryptographic signature. The length and format depends on the algorithm
+ * used. In the above example this is ``HS256``, or HMAC with SHA-256 hashing.
+ *
+ * In order to verify a token, jwt_config_t.key MUST be supplied, and either
+ * jwt_config_t.alg or the alg in jwk_item_t must be set to something other than
+ * ``none``. On return from verification, you should inspect the resulting
+ * jwt_t for error using jwt_error(). You can retrieve the error message with
+ * jwt_error_msg().
+ *
+ * This table shows what will or wont pass as far as algorithm matching between
+ * jwt_config_t, jwt_t, and jwk_item_t, where ``alg-A`` means one specific
+ * algorithm (not none) and ``alg-B`` represents another (also not none). The
+ * ``none`` is used to represent no algorithm being set, and ``any`` represents
+ * any algorithm setting, ``none`` or otherwise. This table assumes that the
+ * JWT contains a signature block.
+ *
+ * jwt_config_t | jwk_item_t | jwt_t | Result
+ * :----------: | :--------: | :-------: | :-----------------------:
+ * ``alg-A`` | ``alg-A`` | ``alg-A`` | \emoji :white_check_mark:
+ * ``none`` | ``alg-A`` | ``alg-A`` | \emoji :white_check_mark:
+ * ``alg-A`` | ``none`` | ``alg-A`` | \emoji :white_check_mark:
+ * ``none`` | ``none`` | ``any`` | \emoji :x:
+ * ``any`` | ``any`` | ``none`` | \emoji :x:
+ * ``alg-A`` | ``alg-A`` | ``alg-B`` | \emoji :x:
+ * ``alg-A`` | ``none`` | ``alg-B`` | \emoji :x:
+ * ``none`` | ``alg-A`` | ``alg-B`` | \emoji :x:
+ * ``alg-A`` | ``alg-B`` | ``any`` | \emoji :x:
+ *
+ * @note For any JWT containing a signature block, jwt_config_t.key MUST
+ * point to a valid jwk_item_t key.
+ *
+ * For a JWT that does not contain a signature block, it will only pass
+ * verification if all of the following are true:
+ *
+ * jwt_config_t.alg | jwt_config_t.key | jwt_t alg | jwt_t sig | Result
+ * :-------- --: | :-----------------: | :-------: | :-------: | :-----------------------:
+ * ``none`` | ``NULL`` | ``none`` | ``empty`` | \emoji :white_check_mark:
+ *
+ * Anything else with an empty ``sig`` block will fail. This is to ensure
+ * security. Refer to the following links for security considerations:
+ *
+ * @rfc{7515,10} @rfc{7516,11} @rfc{7517,9} @rfc{7518,8}
+ *
+ * @warning Using insecure tokens is not very useful and strongly discouraged.
+ *
+ * @remark If you want to inspect a signed token, you MUST use jwt_verify_wcb()
+ * and supply a callback function.
* @{
*/
/**
* @brief Decode and verify a JWT
*
- * In order to verify a token, the config param MUST set jw_key and alg. Both
- * are required. On return, you should inspect the resulting jwt_t for error
- * using jwt_error(). You can print a message with jwt_error_msg().
- *
- * In order to verify, several things must be true:
- * - The value of config.alg MUST match the value of alg in the token.
- * - The value of config.jw_key.alg, if not "none" must also match the token
- * - The token MUST have a signature block.
- * - The key MUST be usable for the operation, either via the "use" attribute
- * being "sig" or the "key_ops" attribute have the "verify" bit set.
- * - The defined signature MUST pass.
- *
- * If you want to decode an unsigned JWT, these MUST be true:
- * - The config.alg and jwt.alg MUST be "none"
- * - The config.jw_key MUST be NULL
- * - The signature block in the token MUST be empty
- *
- * If you want to inspect a signed token, you should use jwt_verify_wcb() and
- * use a callback function.
- *
* @param token Pointer to a nil terminated JWT string
* @param config Pointer to a config structure to define how to verify the
- * token. This can be NULL, in which case the token is simply decoded.
- * @return Pointer to a jwt_t object or NULL. Generally a NULL is unlikely. The
- * object should be checked with jwt_error() to check for errors.
+ * token
+ * @return Pointer to a jwt_t object or NULL. Generally, a NULL is unlikely. The
+ * object should be checked with jwt_error() to check for errors. The jwt_t
+ * must be freed by the caller with jwt_free().
*/
JWT_EXPORT
jwt_t *jwt_verify(const char *token, jwt_config_t *config);
@@ -508,19 +665,20 @@ jwt_t *jwt_verify(const char *token, jwt_config_t *config);
/**
* @brief Decode and verify a JWT, with user callback
*
- * This operates the same as @ref jwt_verify, with the addition of calling
- * a user defined callback function between the decode and verification step.
- * This allows the user to perform some extra verification, and even provide a
- * key after decoding (e.g. to match a ``"kid"``).
+ * This operates the same as jwt_verify(), with the addition of calling a
+ * user-defined function between the parsing and verification step. This allows
+ * the user to perform some extra verification, and even provide a key after
+ * (e.g. to match a ``"kid"``).
*
* The callback function is performed after initial parsing of the head and
* body parts of the token, but before verification. The callback can then
* inspect portions of the JWT, update the config (e.g. to set an alg or a
- * jw_key).
+ * key). None of the rules in jwt_verify() apply until after this callback
+ * function has completed.
*
- * The callback function can return non-zero to stop processing immediately.
- * If the callback function returns zero, it does not mean that further
- * verification will succeed. All aspects of jwt_verify() must still be
+ * The callback function can return non-zero to stop processing immediately. If
+ * the callback function returns zero, it does not mean that further
+ * verification will succeed. All aspects of verification must still be
* followed.
*
* @param token Pointer to a nil terminated JWT string
@@ -540,60 +698,42 @@ jwt_t *jwt_verify_wcb(const char *token, jwt_config_t *config,
*/
/**
- * @defgroup jwt_head_grant_grp Grants and Headers
+ * @defgroup jwt_setget_grp Headers, Claims and Grants
*
- * These functions allow you to add, get, and delete items in the headers and
- * grants of a JWT that is being prepared for encoding.
- * @{
- */
-
-/**
- * @brief Value types for grants and headers
- */
-typedef enum {
- JWT_VALUE_NONE = 0, /**< No type (do not use this) */
- JWT_VALUE_INT, /**< Integer */
- JWT_VALUE_STR, /**< String */
- JWT_VALUE_BOOL, /**< Boolean */
- JWT_VALUE_JSON, /**< JSON String (object format ``{}``) */
- JWT_VALUE_INVALID, /**< Invalid (used internally) */
-} jwt_value_type_t;
-
-/**
- * @brief Error values for header and grant requests
- */
-typedef enum {
- JWT_VALUE_ERR_NONE = 0, /**< No error, success */
- JWT_VALUE_ERR_EXIST, /**< Item exists (when adding) */
- JWT_VALUE_ERR_NOEXIST, /**< Item doesn't exist (when getting) */
- JWT_VALUE_ERR_TYPE, /**< Item is not of the type requested */
- JWT_VALUE_ERR_INVALID, /**< Invalid request (general error) */
- JWT_VALUE_ERR_NOMEM, /**< Memory allocation error */
-} jwt_value_error_t;
-
-/**
- * @brief Data type for get and add actions for JWT headers and grants
+ * When dealing with JWT there are 3 main topics. Each has specific expectations
+ * depending if you are producing or consuming JWT.
*
- * This is used for both add and get requests. Specific rules for each type is
- * described in more detail for the add and get requests.
+ * @par Headers
+ * Generally, you do not need to worry about the header of a JWT, except in
+ * special (and usually custom) applications. For the most part, you will never
+ * access this part of a JWT. Internally, LibJWT is mostly concerned about the
+ * ``typ`` attribute being ``JWT`` and the ``alg`` attribute. LibJWT will add
+ * both of these when creating a token, and parse both when verifying them.
*
- * @note There are helper macros to simplify settng this structure properly and
- * reducing common mistakes. See the jwt_set_{ADD,GET}_{INT,STR,BOOL,JSON}
- * definitions.
+ * The functionality to get or add header values is mostly for convenience and
+ * special applications.
+ *
+ * @par Claims
+ * Claims are contained in the payload of a JWT. These are attributes that the
+ * JWT claims to have access to. It could be a hostname, access privileges, or
+ * even timestamps that ensure the token hasn't expired.
+ *
+ * Claims are verified by LibJWT for known types (e.g. ``nbf`` or ``exp``).
+ * Other claims can be enforced using the jwt_config_t structure. In this way, a
+ * single jwt_config_t can be created to repeat verification of tokens using a
+ * set of rules defined once.
+ *
+ * There is also a function to read the claims from the JWT after parsing. There
+ * is no method for modifying claims of a jwt_t.
+ *
+ * @par Grants
+ * Grants are defined as the attributes you give to a JWT you are creating. It
+ *
+ * Claims are set in the jwt_config_t structure and used to generate tokens. In
+ * this way, the jwt_config_t can be reused to create tokens on demand from a
+ * known source
+ * @{
*/
-typedef struct {
- jwt_value_type_t type;
- char *name;
- union {
- long int_val;
- const char *str_val;
- int bool_val;
- char *json_val;
- };
- int replace;
- int pretty;
- jwt_value_error_t error;
-} jwt_value_t;
/**
* @brief Add a value to the header of a JWT
@@ -814,31 +954,16 @@ jwt_value_error_t jwt_grant_del(jwt_t *jwt, const char *header);
/**
* @}
- * @noop jwt_head_grant_grp
+ * @noop jwt_setget_grp
*/
/**
* @defgroup jwt_alg_grp Algorithms
- * Set and check algorithms and algorithm specific values.
*
- * When working with functions that require a key, the underlying library
- * takes care to scrub memory when the key is no longer used (e.g. when
- * calling jwt_free() or when changing the algorithm, the old key, if it
- * exists, is scrubbed).
+ * Utility functions to convert between string and type for ``alg``
* @{
*/
-/**
- * Get the jwt_alg_t set for this JWT object.
- *
- * Returns the jwt_alg_t type for this JWT object.
- *
- * @param jwt Pointer to a JWT object.
- * @returns Returns a jwt_alg_t type for this object.
- */
-JWT_EXPORT
-jwt_alg_t jwt_get_alg(const jwt_t *jwt);
-
/**
* Convert alg type to it's string representation.
*
@@ -878,7 +1003,12 @@ jwt_alg_t jwt_str_alg(const char *alg);
*/
/**
- * @defgroup jwks_core_grp JSON Web Key Management
+ * @defgroup jwks_grp JSON Web Keys
+ * @{
+ */
+
+/**
+ * @defgroup jwks_core_grp JWK Management
*
* Functions to handle JSON that represents JWK and JWKS for use in validating
* or signing JWT objects.
@@ -1233,311 +1363,9 @@ int jwks_item_free_all(jwk_set_t *jwk_set);
* @noop jwks_item_grp
*/
-/** @ingroup jwt_grp
- * @defgroup jwt_valid_grp Validation Functions
- * These functions allow you to define requirements for JWT validation.
- *
- * The most basic validation is that the JWT uses the expected algorithm.
- *
- * When replicating claims in header (usually for encrypted JWT), validation
- * tests that they match claims in the body (iss, sub, aud).
- *
- * Time-based claims can also be validated (nbf, exp).
- *
- * Finally, validation can test that claims be present and have certain value.
- *
- * @{
- */
-
-/**
- * Validate a JWT object with a validation object.
- *
- * @param jwt Pointer to a JWT object.
- * @param jwt_valid Pointer to a JWT validation object.
- *
- * @return bitwide OR if possible validation errors or 0 on success
- */
-JWT_EXPORT
-jwt_valid_exception_t jwt_validate(jwt_t *jwt, jwt_valid_t *jwt_valid);
-
-/**
- * Allocate a new, JWT validation object.
- *
- * This is used to create a new object for a JWT validation. After you have
- * finished with the object, use jwt_valid_free() to clean up the memory used by
- * it.
- *
- * @param jwt_valid Pointer to a JWT validation object pointer. Will be allocated
- * on success.
- * @param alg A valid jwt_alg_t specifier.
- * @return 0 on success, valid errno otherwise.
- */
-JWT_EXPORT
-int jwt_valid_new(jwt_valid_t **jwt_valid, jwt_alg_t alg);
-
-/**
- * Free a JWT validation object and any other resources it is using.
- *
- * After calling, the JWT validation object referenced will no longer be valid
- * and its memory will be freed.
- *
- * @param jwt_valid Pointer to a JWT validation object previously created with
- * jwt_valid_new().
- */
-JWT_EXPORT
-void jwt_valid_free(jwt_valid_t *jwt_valid);
-
-/**
- * Return the status string for the validation object.
- *
- * The status of validation object is primarily for describing the reason
- * jwt_validate() failed.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @return Returns current validation status as a bitwise OR of possible
- * errors, or 0 if validation is currently successful.
- */
-JWT_EXPORT
-jwt_valid_exception_t jwt_valid_get_status(jwt_valid_t *jwt_valid);
-
-/**
- * Return the nbf_leeway value set.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @return Returns current nbf_leeway value
- */
-JWT_EXPORT
-time_t jwt_valid_get_nbf_leeway(jwt_valid_t *jwt_valid);
-
-/**
- * Return the exp_leeway value set.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @return Returns current exp_leeway value
- */
-JWT_EXPORT
-time_t jwt_valid_get_exp_leeway(jwt_valid_t *jwt_valid);
-
-/**
- * Add a new string grant requirement to this JWT validation object.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to add.
- * @param val String containing the value to be saved for grant. Can be
- * an empty string, but cannot be NULL.
- * @return Returns 0 on success, valid errno otherwise.
- *
- * Note, this only allows for string based grants. If you wish to add
- * integer grants, then use jwt_valid_add_grant_int(). If you wish to add more
- * complex grants (e.g. an array), then use jwt_valid_add_grants_json().
- */
-JWT_EXPORT
-int jwt_valid_add_grant(jwt_valid_t *jwt_valid, const char *grant, const char *val);
-
-/**
- * Return the value of a string required grant.
- *
- * Returns the string value for a grant (e.g. "iss"). If it does not exist,
- * NULL will be returned.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to return a value
- * for.
- * @return Returns a string for the value, or NULL when not found.
- *
- * Note, this will only return grants with JSON string values. Use
- * jwt_valid_get_grants_json() to get the JSON representation of more complex
- * values (e.g. arrays) or use jwt_valid_get_grant_int() to get simple integer
- * values.
- */
-JWT_EXPORT
-const char *jwt_valid_get_grant(jwt_valid_t *jwt_valid, const char *grant);
-
-/**
- * Add a new integer grant requirement to this JWT validation object.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to add.
- * @param val int containing the value to be saved for grant.
- * @return Returns 0 on success, valid errno otherwise.
- *
- * @remark This only allows for integer based grants. If you wish to add
- * string grants, then use jwt_valid_add_grant(). If you wish to add more
- * complex grants (e.g. an array), then use jwt_valid_add_grants_json().
- */
-JWT_EXPORT
-int jwt_valid_add_grant_int(jwt_valid_t *jwt_valid, const char *grant, long val);
-
-/**
- * Return the value of an integer required grant.
- *
- * Returns the int value for a grant (e.g. "exp"). If it does not exist,
- * 0 will be returned.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to return a value
- * for.
- * @return Returns an int for the value. Sets errno to ENOENT when not
- * found.
- *
- * @remark This will only return grants with JSON integer values. Use
- * jwt_valid_get_grants_json() to get the JSON representation of more complex
- * values (e.g. arrays) or use jwt_valid_get_grant() to get string values.
- */
-JWT_EXPORT
-long jwt_valid_get_grant_int(jwt_valid_t *jwt_valid, const char *grant);
-
-/**
- * Add a new boolean required grant to this JWT validation object.
- *
- * Creates a new grant for this object. The string for grant
- * is copied internally, so do not require that the pointer or string
- * remain valid for the lifetime of this object. It is an error if you
- * try to add a grant that already exists.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to add.
- * @param val boolean containing the value to be saved for grant.
- * @return Returns 0 on success, valid errno otherwise.
- *
- * @remark This only allows for boolean based grants. If you wish to add
- * string grants, then use jwt_valid_add_grant(). If you wish to add more
- * complex grants (e.g. an array), then use jwt_valid_add_grants_json().
- */
-JWT_EXPORT
-int jwt_valid_add_grant_bool(jwt_valid_t *jwt_valid, const char *grant, int val);
-
-/**
- * Return the value of an boolean required grant.
- *
- * Returns the int value for a grant (e.g. "exp"). If it does not exist,
- * 0 will be returned.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to return a value
- * for.
- * @return Returns a boolean for the value. Sets errno to ENOENT when not
- * found.
- *
- * @remark This will only return grants with JSON boolean values. Use
- * jwt_valid_get_grants_json() to get the JSON representation of more complex
- * values (e.g. arrays) or use jwt_valid_get_grant() to get string values.
- */
-JWT_EXPORT
-int jwt_valid_get_grant_bool(jwt_valid_t *jwt_valid, const char *grant);
-
-/**
- * Add required grants from a JSON encoded object string.
- *
- * Loads a grant from an existing JSON encoded object string. Overwrites
- * existing grant.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param json String containing a JSON encoded object of grants.
- * @return Returns 0 on success, valid errno otherwise.
- */
-JWT_EXPORT
-int jwt_valid_add_grants_json(jwt_valid_t *jwt_valid, const char *json);
-
-/**
- * Return the value of a grant as JSON encoded object string.
- *
- * Returns the JSON encoded string value for a grant (e.g. "iss"). If it
- * does not exist, NULL will be returned.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to return a value
- * for.
- * @return Returns a string for the value, or NULL when not found. The
- * returned string must be freed by the caller.
- */
-JWT_EXPORT
-char* jwt_valid_get_grants_json(jwt_valid_t *jwt_valid, const char *grant);
-
-/**
- * Delete a grant from this JWT object.
- *
- * Deletes the named grant from this object. It is not an error if there
- * is no grant matching the passed name. If grant is NULL, then all grants
- * are deleted from this JWT.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param grant String containing the name of the grant to delete. If this
- * is NULL, then all grants are deleted.
- * @return Returns 0 on success, valid errno otherwise.
- */
-JWT_EXPORT
-int jwt_valid_del_grants(jwt_valid_t *jwt_valid, const char *grant);
-
-/**
- * Set the time for which expires and not-before claims should be evaluated.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param now Time to use when considering nbf and exp claims.
- * @return Returns 0 on success, valid errno otherwise.
- *
- * @remark jwt_validate() will not fail based on time if no expires or
- * not-before claims exist in a JWT object.
- */
-JWT_EXPORT
-int jwt_valid_set_now(jwt_valid_t *jwt_valid, const time_t now);
-
-/**
- * Set the nbf_leeway value as defined in: https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param nbf_leeway leeway for nbf value.
- * @return Returns 0 on success, valid errno otherwise.
- *
- */
-JWT_EXPORT
-int jwt_valid_set_nbf_leeway(jwt_valid_t *jwt_valid, const time_t nbf_leeway);
-
-/**
- * Set the exp_leeway value as defined in: https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param exp_leeway leeway for exp value.
- * @return Returns 0 on success, valid errno otherwise.
- *
- */
-JWT_EXPORT
-int jwt_valid_set_exp_leeway(jwt_valid_t *jwt_valid, const time_t exp_leeway);
-
-/**
- * Set validation for replicated claims in headers.
- *
- * When set, validation tests for presence of iss, sub, aud in jwt headers and
- * tests match for same claims in body.
- *
- * @param jwt_valid Pointer to a JWT validation object.
- * @param hdr When true, test header claims
- * @return Returns 0 on success, valid errno otherwise.
- *
- * @remark jwt_validate() will not fail if iss, sub, aud are not present in JWT
- * header or body.
- */
-JWT_EXPORT
-int jwt_valid_set_headers(jwt_valid_t *jwt_valid, int hdr);
-
-/**
- * Parses exceptions and returns a comma delimited and human-readable string.
- *
- * The returned string must be freed by the caller.
- *
- * @remark This string is currently en-US ASCII only. Language support will come in the
- * future.
- *
- * @param exceptions Integer containing the exception flags.
- * @return A null terminated string on success, NULL on error with errno
- * set appropriately.
- */
-JWT_EXPORT
-char *jwt_exception_str(jwt_valid_exception_t exceptions);
-
/**
* @}
- * @noop jwt_valid_grp
+ * @noop jwks_grp
*/
/**
@@ -1596,7 +1424,7 @@ void jwt_get_alloc(jwt_malloc_t *pmalloc, jwt_realloc_t *prealloc,
*/
/**
- * @defgroup jwt_crypto_grp Cryptographic Operations
+ * @defgroup jwt_crypto_grp Cryptographic Ops
* Functions used to set and get which crypto operations are used
*
* LibJWT supports several crypto libraries, mainly "openssl" and "gnutls".
@@ -1669,7 +1497,7 @@ int jwt_crypto_ops_supports_jwk(void);
/**
* @}
- * @noop advanced_grp
+ * @noop jwt_advanced_grp
*/
#ifdef __cplusplus
diff --git a/libjwt/gnutls/sign-verify.c b/libjwt/gnutls/sign-verify.c
index de293890..4f1d25b8 100644
--- a/libjwt/gnutls/sign-verify.c
+++ b/libjwt/gnutls/sign-verify.c
@@ -31,11 +31,11 @@ static int gnutls_sign_sha_hmac(jwt_t *jwt, char **out, unsigned int *len,
void *key;
size_t key_len;
- if (!ops_compat(jwt->jw_key, JWT_CRYPTO_OPS_OPENSSL))
+ if (!ops_compat(jwt->key, JWT_CRYPTO_OPS_OPENSSL))
return 1; // LCOV_EXCL_LINE
- key = jwt->jw_key->oct.key;
- key_len = jwt->jw_key->oct.len;
+ key = jwt->key->oct.key;
+ key_len = jwt->key->oct.len;
switch (jwt->alg) {
case JWT_ALG_HS256:
@@ -102,13 +102,13 @@ static int gnutls_sign_sha_pem(jwt_t *jwt, char **out, unsigned int *len,
return 1;
}
- if (jwt->jw_key->pem == NULL)
+ if (jwt->key->pem == NULL)
return 1; // LCOV_EXCL_LINE
gnutls_privkey_t privkey;
gnutls_datum_t key_dat = {
- (unsigned char *)jwt->jw_key->pem,
- strlen(jwt->jw_key->pem)
+ (unsigned char *)jwt->key->pem,
+ strlen(jwt->key->pem)
};
gnutls_datum_t body_dat = {
(unsigned char *)str,
@@ -191,9 +191,6 @@ static int gnutls_sign_sha_pem(jwt_t *jwt, char **out, unsigned int *len,
if (pk_alg == GNUTLS_PK_EDDSA_ED25519)
alg = GNUTLS_DIG_SHA512;
else if (pk_alg == GNUTLS_PK_EDDSA_ED448) {
- /* Not implemented in GnuTLS yet, will fail XXX */
- jwt_write_error(jwt,
- "ED448 is not yet implemented in GnuTLS");
alg = GNUTLS_DIG_SHAKE_256;
} else {
jwt_write_error(jwt, "Unknown EdDSA key type");
@@ -211,15 +208,12 @@ static int gnutls_sign_sha_pem(jwt_t *jwt, char **out, unsigned int *len,
}
if (pk_alg != gnutls_privkey_get_pk_algorithm(privkey, NULL)) {
- jwt_write_error(jwt, "Alg mismatch with key during signing");
+ jwt_write_error(jwt, "Alg mismatch with key during signing: %d",
+ pk_alg);
ret = 1;
goto sign_clean_privkey;
}
- /* XXX Get curve name for ES256K case and make sure it's secp256k1 */
-
- /* XXX Get EC curve bits and make sure it matches ES* alg type */
-
/* Sign data */
if (gnutls_privkey_sign_data(privkey, alg, 0, &body_dat, &sig_dat)) {
// LCOV_EXCL_START
@@ -317,12 +311,12 @@ static int gnutls_verify_sha_pem(jwt_t *jwt, const char *head,
int alg, ret = 0, sig_len;
unsigned char *sig = NULL;
- if (jwt->jw_key->pem == NULL)
+ if (jwt->key->pem == NULL)
return 1;
gnutls_datum_t cert_dat = {
- (unsigned char *)jwt->jw_key->pem,
- strlen(jwt->jw_key->pem)
+ (unsigned char *)jwt->key->pem,
+ strlen(jwt->key->pem)
};
if (jwt->alg == JWT_ALG_ES256K) {
@@ -332,6 +326,48 @@ static int gnutls_verify_sha_pem(jwt_t *jwt, const char *head,
// LCOV_EXCL_STOP
}
+ if (gnutls_pubkey_init(&pubkey)) {
+ // LCOV_EXCL_START
+ ret = 1;
+ goto verify_clean_sig;
+ // LCOV_EXCL_STOP
+ }
+
+ ret = gnutls_pubkey_import(pubkey, &cert_dat, GNUTLS_X509_FMT_PEM);
+ if (ret) {
+ gnutls_privkey_t privkey;
+
+ /* Try loading as a private key, and extracting the pubkey. This is pefectly
+ * legit. A JWK can have a private key with key_ops of SIGN and VERIFY. */
+ if (gnutls_privkey_init(&privkey)) {
+ // LCOV_EXCL_START
+ ret = 1;
+ goto verify_clean_pubkey;
+ // LCOV_EXCL_STOP
+ }
+
+ /* Try loading as a private key, and extracting the pubkey */
+ if (gnutls_privkey_import_x509_raw(privkey, &cert_dat,
+ GNUTLS_X509_FMT_PEM,
+ NULL, 0)) {
+ // LCOV_EXCL_START
+ ret = 1;
+ gnutls_privkey_deinit(privkey);
+ goto verify_clean_pubkey;
+ // LCOV_EXCL_STOP
+ }
+
+ ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
+ gnutls_privkey_deinit(privkey);
+
+ if (ret) {
+ // LCOV_EXCL_START
+ ret = 1;
+ goto verify_clean_pubkey;
+ // LCOV_EXCL_STOP
+ }
+ }
+
switch (jwt->alg) {
/* RSA */
case JWT_ALG_RS256:
@@ -369,58 +405,28 @@ static int gnutls_verify_sha_pem(jwt_t *jwt, const char *head,
/* EdDSA */
case JWT_ALG_EDDSA:
- alg = GNUTLS_SIGN_EDDSA_ED25519;
+ alg = gnutls_pubkey_get_pk_algorithm(pubkey, NULL);
+ if (alg == GNUTLS_PK_EDDSA_ED25519)
+ alg = GNUTLS_SIGN_EDDSA_ED25519;
+ else if (alg == GNUTLS_PK_EDDSA_ED448) {
+ alg = GNUTLS_SIGN_EDDSA_ED448;
+ } else {
+ jwt_write_error(jwt, "Unknown EdDSA key type");
+ ret = 1;
+ goto verify_clean_pubkey;
+ }
break;
default:
- return 1; // LCOV_EXCL_LINE
+ ret = 1;
+ goto verify_clean_pubkey;
}
sig = (unsigned char *)jwt_base64uri_decode(sig_b64, &sig_len);
- if (sig == NULL)
- return 1;
-
- if (gnutls_pubkey_init(&pubkey)) {
- // LCOV_EXCL_START
+ if (sig == NULL) {
ret = 1;
- goto verify_clean_sig;
- // LCOV_EXCL_STOP
- }
-
- ret = gnutls_pubkey_import(pubkey, &cert_dat, GNUTLS_X509_FMT_PEM);
- if (ret) {
- gnutls_privkey_t privkey;
-
- /* Try loading as a private key, and extracting the pubkey. This is pefectly
- * legit. A JWK can have a private key with key_ops of SIGN and VERIFY. */
- if (gnutls_privkey_init(&privkey)) {
- // LCOV_EXCL_START
- ret = 1;
- goto verify_clean_pubkey;
- // LCOV_EXCL_STOP
- }
-
- /* Try loading as a private key, and extracting the pubkey */
- if (gnutls_privkey_import_x509_raw(privkey, &cert_dat,
- GNUTLS_X509_FMT_PEM,
- NULL, 0)) {
- // LCOV_EXCL_START
- ret = 1;
- gnutls_privkey_deinit(privkey);
- goto verify_clean_pubkey;
- // LCOV_EXCL_STOP
- }
-
- ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
- gnutls_privkey_deinit(privkey);
-
- if (ret) {
- // LCOV_EXCL_START
- ret = 1;
- goto verify_clean_pubkey;
- // LCOV_EXCL_STOP
- }
+ goto verify_clean_pubkey;
}
/* Rebuild signature using r and s extracted from sig when jwt->alg
diff --git a/libjwt/jwks.c b/libjwt/jwks.c
index 0b77b757..d0403566 100644
--- a/libjwt/jwks.c
+++ b/libjwt/jwks.c
@@ -225,7 +225,7 @@ const char *jwks_item_curve(const jwk_item_t *item)
const char *jwks_item_kid(const jwk_item_t *item)
{
- return item->kid[0] ? item->kid : NULL;
+ return item->kid;
}
jwt_alg_t jwks_item_alg(const jwk_item_t *item)
diff --git a/libjwt/jwt-common.c b/libjwt/jwt-common.c
new file mode 100644
index 00000000..d6029c1b
--- /dev/null
+++ b/libjwt/jwt-common.c
@@ -0,0 +1,359 @@
+/* Copyright (C) 2015-2025 maClara, LLC
+ This file is part of the JWT C Library
+
+ SPDX-License-Identifier: MPL-2.0
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include
+#include
+
+#include
+
+#include "base64.h"
+
+#include "jwt-private.h"
+
+#ifdef JWT_BUILDER
+#define jwt_common_t jwt_builder_t
+#define FUNC(__x) jwt_builder_##__x
+#define CLAIMS_DEF JWT_BUILDER_CLAIMS
+#endif
+#ifdef JWT_CHECKER
+#define jwt_common_t jwt_checker_t
+#define FUNC(__x) jwt_checker_##__x
+#define CLAIMS_DEF JWT_CHECKER_CLAIMS
+#endif
+
+#ifndef jwt_common_t
+#error Must have target defined
+#endif
+
+void FUNC(free)(jwt_common_t *__cmd)
+{
+ if (__cmd == NULL)
+ return;
+
+ json_decref(__cmd->c.payload);
+ json_decref(__cmd->c.headers);
+
+ memset(__cmd, 0, sizeof(*__cmd));
+
+ jwt_freemem(__cmd);
+}
+
+jwt_common_t *FUNC(new)(void)
+{
+ jwt_common_t *__cmd = jwt_malloc(sizeof(*__cmd));
+
+ if (__cmd == NULL)
+ return NULL;
+
+ memset(__cmd, 0, sizeof(*__cmd));
+
+ __cmd->c.payload = json_object();
+ __cmd->c.headers = json_object();
+ __cmd->c.claims = CLAIMS_DEF;
+
+ if (!__cmd->c.payload || !__cmd->c.headers)
+ jwt_freemem(__cmd);
+
+ return __cmd;
+}
+
+int FUNC(setkey_check)(jwt_common_t *__cmd, const jwt_alg_t alg,
+ const jwk_item_t *key)
+{
+ if (__cmd == NULL)
+ return 1;
+
+#ifdef JWT_BUILDER
+ if (key && !key->is_private_key) {
+ jwt_write_error(__cmd, "Signing requires a private key");
+ return 1;
+ }
+#endif
+ /* TODO: Check key_ops and use */
+
+ if (key == NULL) {
+ if (alg == JWT_ALG_NONE)
+ return 0;
+
+ jwt_write_error(__cmd, "Cannot set alg without a key");
+ } else if (key->alg == JWT_ALG_NONE) {
+ if (alg != JWT_ALG_NONE)
+ return 0;
+
+ jwt_write_error(__cmd, "Key provided, but could not find alg");
+ } else {
+ if (alg == JWT_ALG_NONE)
+ return 0;
+
+ if (alg == key->alg)
+ return 0;
+
+ jwt_write_error(__cmd, "Alg mismatch");
+ }
+
+ return 1;
+}
+
+int FUNC(setkey)(jwt_common_t *__cmd, const jwt_alg_t alg,
+ const jwk_item_t *key)
+{
+ if (FUNC(setkey_check)(__cmd, alg, key))
+ return 1;
+
+ __cmd->c.alg = alg;
+ __cmd->c.key = key;
+
+ return 0;
+}
+
+int FUNC(error)(const jwt_common_t *__cmd)
+{
+ if (__cmd == NULL)
+ return 1;
+
+ return __cmd->error ? 1 : 0;
+}
+
+const char *FUNC(error_msg)(const jwt_common_t *__cmd)
+{
+ if (__cmd == NULL)
+ return NULL;
+
+ return __cmd->error_msg;
+}
+
+void FUNC(error_clear)(jwt_common_t *__cmd)
+{
+ if (__cmd == NULL)
+ return;
+
+ __cmd->error = 0;
+ __cmd->error_msg[0] = '\0';
+}
+
+int FUNC(setclaims)(jwt_common_t *__cmd, jwt_claims_t claims)
+{
+ if (claims == JWT_CLAIM_DEFAULT) {
+ __cmd->c.claims = CLAIMS_DEF;
+ return 0;
+ }
+
+ if (claims == JWT_CLAIM_NONE) {
+ __cmd->c.claims = claims;
+ return 0;
+ }
+
+ if (claims & JWT_CLAIM_NONE) {
+ jwt_write_error(__cmd,
+ "NONE claim cannot be set with others");
+ return 1;
+ }
+
+ if (claims & ~JWT_CLAIMS_ALL) {
+ jwt_write_error(__cmd, "Unknown claim(s) in set");
+ return 1;
+ }
+
+ __cmd->c.claims = claims;
+
+ return 0;
+}
+
+int FUNC(setcb)(jwt_common_t *__cmd, jwt_callback_t cb, void *ctx)
+{
+ if (__cmd == NULL)
+ return 1;
+
+ if (cb == NULL && ctx != NULL) {
+ jwt_write_error(__cmd, "Setting ctx without a cb wont work");
+ return 1;
+ }
+
+ __cmd->c.cb = cb;
+ __cmd->c.cb_ctx = ctx;
+
+ return 0;
+}
+
+typedef enum {
+ __HEADER,
+ __CLAIM,
+} _setget_type_t;
+
+typedef jwt_value_error_t (*__doer_t)(json_t *, jwt_value_t *);
+
+static jwt_value_error_t __run_it(jwt_common_t *__cmd, _setget_type_t type,
+ jwt_value_t *value, __doer_t doer)
+{
+ json_t *which = NULL;
+
+ if (!__cmd || !value) {
+ if (value)
+ return value->error = JWT_VALUE_ERR_INVALID;
+ return JWT_VALUE_ERR_INVALID;
+ }
+
+ switch (type) {
+ case __HEADER:
+ which = __cmd->c.headers;
+ break;
+ case __CLAIM:
+ which = __cmd->c.payload;
+ break;
+ default:
+ return value->error = JWT_VALUE_ERR_INVALID;
+ }
+
+ return doer(which, value);
+}
+
+/* Claims */
+jwt_value_error_t FUNC(claim_get)(jwt_common_t *__cmd, jwt_value_t *value)
+{
+ return __run_it(__cmd, __CLAIM, value, __getter);
+}
+
+jwt_value_error_t FUNC(claim_add)(jwt_common_t *__cmd, jwt_value_t *value)
+{
+ return __run_it(__cmd, __CLAIM, value, __adder);
+}
+
+jwt_value_error_t FUNC(claim_del)(jwt_common_t *__cmd, const char *header)
+{
+ if (!__cmd)
+ return JWT_VALUE_ERR_INVALID;
+ return __deleter(__cmd->c.payload, header);
+}
+
+/* Headers */
+jwt_value_error_t FUNC(header_get)(jwt_common_t *__cmd, jwt_value_t *value)
+{
+ return __run_it(__cmd, __HEADER, value, __getter);
+}
+
+jwt_value_error_t FUNC(header_add)(jwt_common_t *__cmd, jwt_value_t *value)
+{
+ return __run_it(__cmd, __HEADER, value, __adder);
+}
+
+jwt_value_error_t FUNC(header_del)(jwt_common_t *__cmd, const char *header)
+{
+ if (!__cmd)
+ return JWT_VALUE_ERR_INVALID;
+ return __deleter(__cmd->c.headers, header);
+}
+
+#ifdef JWT_CHECKER
+int FUNC(verify)(jwt_common_t *__cmd, const char *token)
+{
+ JWT_CONFIG_DECLARE(config);
+ unsigned int payload_len;
+ jwt_auto_t *jwt = NULL;
+
+ if (__cmd == NULL)
+ return 1;
+
+ if (token == NULL || !strlen(token)) {
+ jwt_write_error(__cmd, "Must pass a token");
+ return 1;
+ }
+
+ jwt = jwt_new();
+ if (jwt == NULL) {
+ jwt_write_error(__cmd, "Could not allocate JWT object");
+ return 1;
+ }
+
+ /* First parsing pass, error will be set for us */
+ if (jwt_parse(jwt, token, &payload_len)) {
+ jwt_copy_error(__cmd, jwt);
+ return 1;
+ };
+
+ config.key = __cmd->c.key;
+ config.alg = __cmd->c.alg;
+ config.ctx = __cmd->c.cb_ctx;
+
+ /* Let the user handle this and update config */
+ if (__cmd->c.cb && __cmd->c.cb(jwt, &config)) {
+ jwt_write_error(__cmd, "User callback returned error");
+ return 1;
+ }
+
+ /* Callback may have changed this */
+ if (FUNC(setkey)(__cmd, config.alg, config.key))
+ return 1;
+
+ jwt->key = config.key;
+
+ /* Finish it up */
+ jwt = jwt_verify_complete(jwt, &config, token, payload_len);
+
+ /* Copy any errors back */
+ jwt_copy_error(__cmd, jwt);
+
+ return __cmd->error;
+}
+#endif
+
+#ifdef JWT_BUILDER
+char *FUNC(generate)(jwt_common_t *__cmd)
+{
+ JWT_CONFIG_DECLARE(config);
+ jwt_auto_t *jwt = NULL;
+ char *out = NULL;
+ jwt_value_t jval;
+
+ if (__cmd == NULL)
+ return NULL;
+
+ jwt = jwt_malloc(sizeof(*jwt));
+ if (jwt == NULL)
+ return NULL;
+
+ memset(jwt, 0, sizeof(*jwt));
+
+ jwt->headers = json_deep_copy(__cmd->c.headers);
+ jwt->grants = json_deep_copy(__cmd->c.payload);
+
+ /* Our internal work first */
+ if (__cmd->c.claims & JWT_CLAIM_IAT) {
+ jwt_set_ADD_INT(&jval, "iat", (long)time(NULL));
+ jval.replace = 1;
+ jwt_grant_add(jwt, &jval);
+ }
+
+ config.alg = __cmd->c.alg;
+ if (config.alg == JWT_ALG_NONE && __cmd->c.key)
+ config.alg = __cmd->c.key->alg;
+ config.key = __cmd->c.key;
+ config.ctx = __cmd->c.cb_ctx;
+
+ /* Let the callback do it's thing */
+ if (__cmd->c.cb && __cmd->c.cb(jwt, &config)) {
+ jwt_write_error(__cmd, "User callback returned error");
+ return NULL;
+ }
+
+ /* Callback may have changed this */
+ if (FUNC(setkey_check)(__cmd, config.alg, config.key)) {
+ jwt_write_error(__cmd, "Algorithm and key returned by callback invalid");
+ return NULL;
+ }
+
+ jwt->alg = config.alg;
+ jwt->key = config.key;
+
+ out = jwt_encode_str(jwt);
+ __cmd->error = jwt->error;
+ strcpy(__cmd->error_msg, jwt->error_msg);
+
+ return out;
+}
+#endif
diff --git a/libjwt/jwt-encode.c b/libjwt/jwt-encode.c
index 3ba553e0..eb9933fa 100644
--- a/libjwt/jwt-encode.c
+++ b/libjwt/jwt-encode.c
@@ -12,40 +12,18 @@
#include
-/* https://github.com/zhicheng/base64 */
#include "base64.h"
#include "jwt-private.h"
-#define APPEND_STR(__buf, __str) do { \
- if (__append_str(__buf, __str)) \
- return 1; \
-} while (0)
-
-static int write_js(const json_t *js, char **buf, int pretty)
+static int write_js(const json_t *js, char **buf)
{
- /* Sort keys for repeatability */
- size_t flags = JSON_SORT_KEYS;
- char_auto *serial = NULL;
-
- if (pretty) {
- APPEND_STR(buf, "\n");
- flags |= JSON_INDENT(4);
- } else {
- flags |= JSON_COMPACT;
- }
-
- serial = json_dumps(js, flags);
+ *buf = json_dumps(js, JSON_SORT_KEYS | JSON_COMPACT);
- APPEND_STR(buf, serial);
-
- if (pretty)
- APPEND_STR(buf, "\n");
-
- return 0;
+ return *buf == NULL ? 1 : 0;
}
-static int jwt_write_head(jwt_t *jwt, char **buf, int pretty)
+static int jwt_write_head(jwt_t *jwt, char **buf)
{
jwt_value_t jval;
@@ -72,12 +50,7 @@ static int jwt_write_head(jwt_t *jwt, char **buf, int pretty)
return 1;
}
- return write_js(jwt->headers, buf, pretty);
-}
-
-static int jwt_write_body(jwt_t *jwt, char **buf, int pretty)
-{
- return write_js(jwt->grants, buf, pretty);
+ return write_js(jwt->headers, buf);
}
static int jwt_encode(jwt_t *jwt, char **out)
@@ -94,7 +67,7 @@ static int jwt_encode(jwt_t *jwt, char **out)
*out = NULL;
/* First the header. */
- ret = jwt_write_head(jwt, &buf, 0);
+ ret = jwt_write_head(jwt, &buf);
if (ret)
return 1;
/* Encode it */
@@ -107,7 +80,7 @@ static int jwt_encode(jwt_t *jwt, char **out)
}
/* Now the body. */
- ret = jwt_write_body(jwt, &buf, 0);
+ ret = write_js(jwt->grants, &buf);
if (ret) {
jwt_write_error(jwt, "Error writing body");
return 1;
@@ -175,19 +148,6 @@ static int jwt_encode(jwt_t *jwt, char **out)
return ret;
}
-int jwt_encode_fp(jwt_t *jwt, FILE *fp)
-{
- char_auto *str = NULL;
-
- if (jwt_encode(jwt, &str))
- return 1;
-
- if (fputs(str, fp) == EOF)
- return 1;
-
- return 0;
-}
-
char *jwt_encode_str(jwt_t *jwt)
{
char *str = NULL;
diff --git a/libjwt/jwt-private.h b/libjwt/jwt-private.h
index 611663f2..69e9e68e 100644
--- a/libjwt/jwt-private.h
+++ b/libjwt/jwt-private.h
@@ -28,45 +28,69 @@
# endif
#endif
+#define JWT_CONFIG_DECLARE(__name) \
+ jwt_config_t __name = { NULL, JWT_ALG_NONE, NULL}
+
+#define JWT_ERR_LEN 256
+
JWT_NO_EXPORT
extern struct jwt_crypto_ops *jwt_ops;
-/* This can be used for jwt_t, jwk_set_t and jwk_item_t */
+/* This can be used on anything with an error and error_msg field */
#define jwt_write_error(__obj, __fmt, __args...) \
({ \
- if (!strlen(__obj->error_msg)) \
- snprintf(__obj->error_msg, \
- sizeof(__obj->error_msg), \
+ if (!strlen((__obj)->error_msg)) \
+ snprintf((__obj)->error_msg, \
+ sizeof((__obj)->error_msg), \
__fmt, ##__args); \
- __obj->error = 1; \
+ (__obj)->error = 1; \
})
-struct jwt {
- jwt_alg_t alg;
+#define jwt_copy_error(__dst, __src) \
+({ \
+ strcpy((__dst)->error_msg, (__src)->error_msg); \
+ (__dst)->error = (__src)->error; \
+})
- json_t *grants;
+/******************************/
+
+struct jwt_common {
+ jwt_alg_t alg;
+ const jwk_item_t *key;
+ json_t *payload;
json_t *headers;
+ jwt_claims_t claims;
+ jwt_callback_t cb;
+ void *cb_ctx;
+};
- const jwk_item_t *jw_key;
+struct jwt_builder {
+ struct jwt_common c;
+ int error;
+ char error_msg[JWT_ERR_LEN];
+};
+struct jwt_checker {
+ struct jwt_common c;
int error;
- char error_msg[256];
+ char error_msg[JWT_ERR_LEN];
};
-struct jwt_valid {
+/*****************************/
+
+struct jwt {
+ const jwk_item_t *key;
+ json_t *grants;
+ json_t *headers;
jwt_alg_t alg;
- time_t now;
- time_t nbf_leeway;
- time_t exp_leeway;
- int hdr;
- json_t *req_grants;
- jwt_valid_exception_t status;
+ int error;
+ char error_msg[JWT_ERR_LEN];
};
struct jwk_set {
ll_t head;
int error;
- char error_msg[256];
+ char error_msg[JWT_ERR_LEN];
};
/**
@@ -95,7 +119,7 @@ struct jwk_item {
char curve[256]; /**< Curve name of an ``"EC"`` or ``"OKP"`` key */
size_t bits; /**< The number of bits in the key (may be 0) */
int error; /**< There was an error parsing this key (unusable) */
- char error_msg[256]; /**< Descriptive message for @ref jwk_item_t.error */
+ char error_msg[JWT_ERR_LEN];/**< Descriptive message for @ref jwk_item_t.error */
jwk_key_type_t kty; /**< @rfc{7517,4.1} The key type of this key */
jwk_pub_key_use_t use; /**< @rfc{7517,4.2} How this key can be used */
jwk_key_op_t key_ops; /**< @rfc{7517,4.3} Key operations supported */
@@ -166,6 +190,16 @@ static inline void jwt_freememp(char **mem) {
}
#define char_auto char __attribute__((cleanup(jwt_freememp)))
+JWT_EXPORT
+void jwt_free(jwt_t *jwt);
+static inline void jwt_freep(jwt_t **jwt) {
+ if (jwt) {
+ jwt_free(*jwt);
+ *jwt = NULL;
+ }
+}
+#define jwt_auto_t jwt_t __attribute__((cleanup(jwt_freep)))
+
/* Helper routines to handle base64url encoding without percent padding
* as defined in RFC-4648. */
JWT_NO_EXPORT
@@ -191,7 +225,27 @@ int jwt_sign(jwt_t *jwt, char **out, unsigned int *len, const char *str,
unsigned int str_len);
JWT_NO_EXPORT
-int __append_str(char **buf, const char *str);
+jwt_value_error_t __deleter(json_t *which, const char *field);
+JWT_NO_EXPORT
+jwt_value_error_t __adder(json_t *which, jwt_value_t *value);
+JWT_NO_EXPORT
+jwt_value_error_t __getter(json_t *which, jwt_value_t *value);
+
+JWT_NO_EXPORT
+int jwt_parse(jwt_t *jwt, const char *token, unsigned int *len);
+JWT_NO_EXPORT
+jwt_t *jwt_verify_complete(jwt_t *jwt, const jwt_config_t *config,
+ const char *token, unsigned int payload_len);
+
+JWT_NO_EXPORT
+int jwt_builder_setkey_check(jwt_builder_t *builder, const jwt_alg_t alg,
+ const jwk_item_t *key);
+JWT_NO_EXPORT
+int jwt_checker_setkey_check(jwt_checker_t *checker, const jwt_alg_t alg,
+ const jwk_item_t *key);
+
+JWT_NO_EXPORT
+char *jwt_encode_str(jwt_t *jwt);
#define __trace() fprintf(stderr, "%s:%d\n", __func__, __LINE__)
diff --git a/libjwt/jwt-validate.c b/libjwt/jwt-validate.c
deleted file mode 100644
index a4a5fe9d..00000000
--- a/libjwt/jwt-validate.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/* Copyright (C) 2015-2025 maClara, LLC
- This file is part of the JWT C Library
-
- SPDX-License-Identifier: MPL-2.0
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include
-#include
-#include
-
-#include
-
-#include "jwt-private.h"
-
-static const char *get_js_string(const json_t *js, const char *key)
-{
- const char *val = NULL;
- json_t *js_val;
-
- js_val = json_object_get(js, key);
- if (js_val) {
- if (json_is_string(js_val))
- val = json_string_value(js_val);
- else
- errno = EINVAL;
- } else {
- errno = ENOENT;
- }
-
- return val;
-}
-
-static long get_js_int(const json_t *js, const char *key)
-{
- long val = -1;
- json_t *js_val;
-
- js_val = json_object_get(js, key);
- if (js_val) {
- if (json_is_integer(js_val))
- val = (long)json_integer_value(js_val);
- else
- errno = EINVAL;
- } else {
- errno = ENOENT;
- }
-
- return val;
-}
-
-static int get_js_bool(const json_t *js, const char *key)
-{
- int val = -1;
- json_t *js_val;
-
- js_val = json_object_get(js, key);
- if (js_val) {
- switch (json_typeof(js_val)) {
- case JSON_TRUE:
- val = 1;
- break;
- case JSON_FALSE:
- val = 0;
- break;
- default:
- errno = EINVAL;
- }
- } else {
- errno = ENOENT;
- }
- return val;
-}
-
-int jwt_valid_new(jwt_valid_t **jwt_valid, jwt_alg_t alg)
-{
- if (!jwt_valid)
- return EINVAL;
-
- *jwt_valid = jwt_malloc(sizeof(jwt_valid_t));
- if (!*jwt_valid)
- return ENOMEM; // LCOV_EXCL_LINE
-
- memset(*jwt_valid, 0, sizeof(jwt_valid_t));
- (*jwt_valid)->alg = alg;
-
- (*jwt_valid)->status = JWT_VALIDATION_ERROR;
-
- (*jwt_valid)->nbf_leeway = 0;
- (*jwt_valid)->exp_leeway = 0;
-
- (*jwt_valid)->req_grants = json_object();
- if (!(*jwt_valid)->req_grants) {
- jwt_freemem(*jwt_valid);
- return ENOMEM;
- }
-
- return 0;
-}
-
-void jwt_valid_free(jwt_valid_t *jwt_valid)
-{
- if (!jwt_valid)
- return;
-
- json_decref(jwt_valid->req_grants);
-
- jwt_freemem(jwt_valid);
-}
-
-jwt_valid_exception_t jwt_valid_get_status(jwt_valid_t *jwt_valid)
-{
- if (!jwt_valid)
- return JWT_VALIDATION_ERROR;
-
- return jwt_valid->status;
-}
-
-time_t jwt_valid_get_nbf_leeway(jwt_valid_t *jwt_valid)
-{
- if (!jwt_valid)
- return EINVAL;
-
- return jwt_valid->nbf_leeway;
-}
-
-time_t jwt_valid_get_exp_leeway(jwt_valid_t *jwt_valid)
-{
- if (!jwt_valid)
- return EINVAL;
-
- return jwt_valid->exp_leeway;
-}
-
-int jwt_valid_add_grant(jwt_valid_t *jwt_valid, const char *grant, const char *val)
-{
- if (!jwt_valid || !grant || !strlen(grant) || !val)
- return EINVAL;
-
- if (get_js_string(jwt_valid->req_grants, grant) != NULL)
- return EEXIST;
-
- if (json_object_set_new(jwt_valid->req_grants, grant, json_string(val)))
- return EINVAL;
-
- return 0;
-}
-
-int jwt_valid_add_grant_int(jwt_valid_t *jwt_valid, const char *grant, long val)
-{
- if (!jwt_valid || !grant || !strlen(grant))
- return EINVAL;
-
- if (get_js_int(jwt_valid->req_grants, grant) != -1)
- return EEXIST;
-
- if (json_object_set_new(jwt_valid->req_grants, grant, json_integer((json_int_t)val)))
- return EINVAL;
-
- return 0;
-}
-
-int jwt_valid_add_grant_bool(jwt_valid_t *jwt_valid, const char *grant, int val)
-{
- if (!jwt_valid || !grant || !strlen(grant))
- return EINVAL;
-
- if (get_js_bool(jwt_valid->req_grants, grant) != -1)
- return EEXIST;
-
- if (json_object_set_new(jwt_valid->req_grants, grant, json_boolean(val)))
- return EINVAL;
-
- return 0;
-}
-
-int jwt_valid_add_grants_json(jwt_valid_t *jwt_valid, const char *json)
-{
- json_auto_t *js_val = NULL;
- int ret = -1;
-
- if (!jwt_valid)
- return EINVAL;
-
- js_val = json_loads(json, JSON_REJECT_DUPLICATES, NULL);
-
- if (json_is_object(js_val))
- ret = json_object_update(jwt_valid->req_grants, js_val);
-
- return ret ? EINVAL : 0;
-}
-
-char *jwt_valid_get_grants_json(jwt_valid_t *jwt_valid, const char *grant)
-{
- json_t *js_val = NULL;
-
- errno = EINVAL;
-
- if (!jwt_valid)
- return NULL;
-
- if (grant && strlen(grant))
- js_val = json_object_get(jwt_valid->req_grants, grant);
- else
- js_val = jwt_valid->req_grants;
-
- if (js_val == NULL)
- return NULL;
-
- errno = 0;
-
- return json_dumps(js_val, JSON_SORT_KEYS | JSON_COMPACT | JSON_ENCODE_ANY);
-}
-
-const char *jwt_valid_get_grant(jwt_valid_t *jwt_valid, const char *grant)
-{
- if (!jwt_valid || !grant || !strlen(grant)) {
- errno = EINVAL;
- return NULL;
- }
-
- errno = 0;
-
- return get_js_string(jwt_valid->req_grants, grant);
-}
-
-long jwt_valid_get_grant_int(jwt_valid_t *jwt_valid, const char *grant)
-{
- if (!jwt_valid || !grant || !strlen(grant)) {
- errno = EINVAL;
- return 0;
- }
-
- errno = 0;
-
- return get_js_int(jwt_valid->req_grants, grant);
-}
-
-int jwt_valid_get_grant_bool(jwt_valid_t *jwt_valid, const char *grant)
-{
- if (!jwt_valid || !grant || !strlen(grant)) {
- errno = EINVAL;
- return 0;
- }
-
- errno = 0;
-
- return get_js_bool(jwt_valid->req_grants, grant);
-}
-
-int jwt_valid_set_now(jwt_valid_t *jwt_valid, const time_t now)
-{
- if (!jwt_valid)
- return EINVAL;
-
- jwt_valid->now = now;
-
- return 0;
-}
-
-int jwt_valid_set_nbf_leeway(jwt_valid_t *jwt_valid, const time_t nbf_leeway)
-{
- if (!jwt_valid)
- return EINVAL;
-
- jwt_valid->nbf_leeway = nbf_leeway;
-
- return 0;
-}
-
-int jwt_valid_set_exp_leeway(jwt_valid_t *jwt_valid, const time_t exp_leeway)
-{
- if (!jwt_valid)
- return EINVAL;
-
- jwt_valid->exp_leeway = exp_leeway;
-
- return 0;
-}
-
-int jwt_valid_set_headers(jwt_valid_t *jwt_valid, int hdr)
-{
- if (!jwt_valid)
- return EINVAL;
-
- jwt_valid->hdr = hdr;
-
- return 0;
-}
-
-int jwt_valid_del_grants(jwt_valid_t *jwt_valid, const char *grant)
-{
- if (!jwt_valid)
- return EINVAL;
-
- if (grant == NULL || !strlen(grant))
- json_object_clear(jwt_valid->req_grants);
- else
- json_object_del(jwt_valid->req_grants, grant);
-
- return 0;
-}
-
-#define _SET_AND_RET(__v, __e) do { \
- __v->status |= __e; \
- return __v->status; \
-} while (0)
-
-jwt_valid_exception_t jwt_validate(jwt_t *jwt, jwt_valid_t *jwt_valid)
-{
- const char *jwt_hdr_str, *jwt_body_str, *req_grant;
- json_t *js_val_1, *js_val_2;
- time_t t;
-
- if (!jwt_valid)
- return JWT_VALIDATION_ERROR;
-
- if (!jwt) {
- jwt_valid->status = JWT_VALIDATION_ERROR;
- return jwt_valid->status;
- }
-
- jwt_valid->status = JWT_VALIDATION_SUCCESS;
-
- /* Validate algorithm */
- if (jwt_valid->alg != jwt_get_alg(jwt))
- jwt_valid->status |= JWT_VALIDATION_ALG_MISMATCH;
-
- /* Validate expires */
- t = get_js_int(jwt->grants, "exp");
- if (jwt_valid->now && t != -1 && jwt_valid->now - jwt_valid->exp_leeway >= t)
- jwt_valid->status |= JWT_VALIDATION_EXPIRED;
-
- /* Validate not-before */
- t = get_js_int(jwt->grants, "nbf");
- if (jwt_valid->now && t != -1 && jwt_valid->now + jwt_valid->nbf_leeway < t)
- jwt_valid->status |= JWT_VALIDATION_TOO_NEW;
-
- /* Validate replicated issuer */
- jwt_hdr_str = get_js_string(jwt->headers, "iss");
- jwt_body_str = get_js_string(jwt->grants, "iss");
- if (jwt_hdr_str && jwt_body_str && jwt_strcmp(jwt_hdr_str, jwt_body_str))
- jwt_valid->status |= JWT_VALIDATION_ISS_MISMATCH;
-
- /* Validate replicated subject */
- jwt_hdr_str = get_js_string(jwt->headers, "sub");
- jwt_body_str = get_js_string(jwt->grants, "sub");
- if (jwt_hdr_str && jwt_body_str && jwt_strcmp(jwt_hdr_str, jwt_body_str))
- jwt_valid->status |= JWT_VALIDATION_SUB_MISMATCH;
-
- /* Validate replicated audience (might be array or string) */
- js_val_1 = json_object_get(jwt->headers, "aud");
- js_val_2 = json_object_get(jwt->grants, "aud");
- if (js_val_1 && js_val_2 && !json_equal(js_val_1, js_val_2))
- jwt_valid->status |= JWT_VALIDATION_AUD_MISMATCH;
-
- /* Validate required grants */
- json_object_foreach(jwt_valid->req_grants, req_grant, js_val_1) {
- json_t *act_js_val = json_object_get(jwt->grants, req_grant);
-
- if (act_js_val && json_equal(js_val_1, act_js_val))
- continue;
-
- if (act_js_val)
- jwt_valid->status |= JWT_VALIDATION_GRANT_MISMATCH;
- else
- jwt_valid->status |= JWT_VALIDATION_GRANT_MISSING;
- }
-
- return jwt_valid->status;
-}
-
-typedef struct {
- int error;
- char *str;
-} jwt_exception_dict_t;
-
-static jwt_exception_dict_t jwt_exceptions[] = {
- /* { JWT_VALIDATION_SUCCESS, "SUCCESS" }, */
- { JWT_VALIDATION_ERROR, "general failures" },
- { JWT_VALIDATION_ALG_MISMATCH, "algorithm mismatch" },
- { JWT_VALIDATION_EXPIRED, "token expired" },
- { JWT_VALIDATION_TOO_NEW, "token future dated" },
- { JWT_VALIDATION_ISS_MISMATCH, "issuer mismatch" },
- { JWT_VALIDATION_SUB_MISMATCH, "subject mismatch" },
- { JWT_VALIDATION_AUD_MISMATCH, "audience mismatch" },
- { JWT_VALIDATION_GRANT_MISSING, "grant missing" },
- { JWT_VALIDATION_GRANT_MISMATCH, "grant mismatch" },
-};
-
-char *jwt_exception_str(jwt_valid_exception_t exceptions)
-{
- size_t i;
- int rc;
- char *str = NULL;
-
- if (exceptions == JWT_VALIDATION_SUCCESS) {
- if ((rc = __append_str(&str, "success")))
- goto fail;
- return str;
- }
-
- for (i = 0; i < ARRAY_SIZE(jwt_exceptions); i++) {
- if (!(jwt_exceptions[i].error & exceptions))
- continue;
-
- if (str && (rc = __append_str(&str, ", ")))
- goto fail;
-
- if ((rc = __append_str(&str, jwt_exceptions[i].str)))
- goto fail;
- }
-
- /* check if none of the exceptions matched? */
- if (!str && (rc = __append_str(&str, "unknown exceptions")))
- goto fail;
-
- return str;
-fail:
- errno = rc;
- jwt_freemem(str);
- return NULL;
-}
diff --git a/libjwt/jwt-verify.c b/libjwt/jwt-verify.c
index a5d08629..f50edf47 100644
--- a/libjwt/jwt-verify.c
+++ b/libjwt/jwt-verify.c
@@ -78,7 +78,7 @@ static int jwt_parse_head(jwt_t *jwt, char *head)
return 0;
}
-static int jwt_parse(jwt_t *jwt, const char *token, unsigned int *len)
+int jwt_parse(jwt_t *jwt, const char *token, unsigned int *len)
{
char_auto *head = NULL;
char *body, *sig;
@@ -129,38 +129,44 @@ static int jwt_parse(jwt_t *jwt, const char *token, unsigned int *len)
static int __verify_config_post(jwt_t *jwt, const jwt_config_t *config,
unsigned int sig_len)
{
- /* The easy out; insecure JWT, and the caller expects it. */
- if (config->alg == JWT_ALG_NONE && config->jw_key == NULL && !sig_len &&
- jwt->alg == JWT_ALG_NONE)
- return 0;
+ if (!sig_len) {
+ if (config->key || config->alg != JWT_ALG_NONE) {
+ jwt_write_error(jwt,
+ "Expected a signature, but JWT has none");
+ return 1;
+ }
- /* The quick fail. The caller and JWT disagree. */
- if (config->alg != jwt->alg) {
- jwt_write_error(jwt, "JWT alg does not match expected value");
- return 1;
+ return 0;
}
- /* At this point, someone is expecting a sig and we also know the
- * caller and the JWT token agree on the alg. */
-
- /* We require a key and a signature. */
- if (config->jw_key == NULL || !sig_len) {
- jwt_write_error(jwt, "JWT does not contain a signature");
+ /* Signature is known to be present from this point */
+ if (config->key == NULL) {
+ jwt_write_error(jwt,
+ "JWT has signature, but no key was given");
return 1;
}
- /* If the key has an alg, it must match the caller. */
- if (config->jw_key->alg != JWT_ALG_NONE &&
- config->jw_key->alg != config->alg) {
- jwt_write_error(jwt, "JWT alg does not much the key being used");
+ /* Key is known to be given at this point */
+ if (config->alg == JWT_ALG_NONE) {
+ if (config->key->alg != jwt->alg) {
+ jwt_write_error(jwt, "Key alg does not match JWT");
+ return 1;
+ }
+ } else if (config->key->alg == JWT_ALG_NONE) {
+ if (config->alg != jwt->alg) {
+ jwt_write_error(jwt, "Config alg does not match JWT");
+ return 1;
+ }
+ } else if (config->alg != config->key->alg) {
+ jwt_write_error(jwt, "Config and key alg does not match");
return 1;
}
return 0;
}
-static jwt_t *jwt_verify_complete(jwt_t *jwt, const jwt_config_t *config,
- const char *token, unsigned int payload_len)
+jwt_t *jwt_verify_complete(jwt_t *jwt, const jwt_config_t *config,
+ const char *token, unsigned int payload_len)
{
const char *sig;
unsigned int sig_len;
@@ -177,42 +183,7 @@ static jwt_t *jwt_verify_complete(jwt_t *jwt, const jwt_config_t *config,
return jwt;
/* At this point, config is never NULL */
- jwt->jw_key = config->jw_key;
+ jwt->key = config->key;
return jwt_verify_sig(jwt, token, payload_len, sig);
}
-
-/*
- * If no callback then we act just like jwt_verify().
- */
-jwt_t *jwt_verify_wcb(const char *token, jwt_config_t *config,
- jwt_callback_t cb)
-{
- unsigned int payload_len;
- jwt_t *jwt = NULL;
-
- if (config == NULL)
- return NULL;
-
- jwt = jwt_new();
- if (jwt == NULL)
- return NULL;
-
- /* First parsing pass, error will be set for us */
- if (jwt_parse(jwt, token, &payload_len))
- return jwt;
-
- /* Let the user handle this and update config */
- if (cb && cb(jwt, config)) {
- jwt_write_error(jwt, "User callback returned error");
- return jwt;
- }
-
- /* Finish it up */
- return jwt_verify_complete(jwt, config, token, payload_len);
-}
-
-jwt_t *jwt_verify(const char *token, jwt_config_t *config)
-{
- return jwt_verify_wcb(token, config, NULL);
-}
diff --git a/libjwt/jwt.c b/libjwt/jwt.c
index cdc55485..5e69b387 100644
--- a/libjwt/jwt.c
+++ b/libjwt/jwt.c
@@ -17,33 +17,6 @@
#include "jwt-private.h"
-int __append_str(char **buf, const char *str)
-{
- char *new;
-
- if (str == NULL || str[0] == '\0')
- return 0;
-
- if (*buf == NULL) {
- new = jwt_malloc(strlen(str) + 1);
- if (new)
- new[0] = '\0';
- } else {
- new = jwt_realloc(*buf, strlen(*buf) + strlen(str) + 1);
- }
-
- if (new == NULL) {
- jwt_freemem(*buf);
- return 1;
- }
-
- strcat(new, str);
-
- *buf = new;
-
- return 0;
-}
-
const char *jwt_alg_str(jwt_alg_t alg)
{
switch (alg) {
@@ -121,23 +94,6 @@ jwt_alg_t jwt_str_alg(const char *alg)
return JWT_ALG_INVAL;
}
-int jwt_error(const jwt_t *jwt)
-{
- return jwt->error;
-}
-
-const char *jwt_error_msg(const jwt_t *jwt)
-{
- return jwt->error_msg;
-}
-
-JWT_NO_EXPORT
-void jwt_scrub_key(jwt_t *jwt)
-{
- jwt->jw_key = NULL;
- jwt->alg = JWT_ALG_NONE;
-}
-
JWT_NO_EXPORT
jwt_t *jwt_new(void)
{
@@ -157,43 +113,6 @@ jwt_t *jwt_new(void)
return jwt;
}
-jwt_t *jwt_create(jwt_config_t *config)
-{
- jwt_t *jwt = jwt_new();
-
- if (jwt == NULL)
- return NULL;
-
- /* An insecure JWT */
- if (config == NULL)
- return jwt;
-
- if (config->alg == JWT_ALG_NONE) {
- /* Also insecure */
- if (config->jw_key == NULL)
- return jwt;
-
- /* This is an error. */
- jwt_write_error(jwt, "Config alg must be set to other than "
- "none when supplying a key");
- return jwt;
- }
-
- /* At this point, we expect a key. */
-
- /* If the key has it set, it must match. */
- if (config->jw_key->alg != JWT_ALG_NONE &&
- config->alg != config->jw_key->alg) {
- jwt_write_error(jwt, "Config alg does not match key alg");
- return jwt;
- }
-
- jwt->jw_key = config->jw_key;
- jwt->alg = config->alg;
-
- return jwt;
-}
-
jwt_alg_t jwt_get_alg(const jwt_t *jwt)
{
if (jwt == NULL)
@@ -207,8 +126,6 @@ void jwt_free(jwt_t *jwt)
if (!jwt)
return;
- jwt_scrub_key(jwt);
-
json_decref(jwt->grants);
json_decref(jwt->headers);
@@ -217,35 +134,6 @@ void jwt_free(jwt_t *jwt)
jwt_freemem(jwt);
}
-jwt_t *jwt_dup(jwt_t *jwt)
-{
- jwt_t *new = NULL;
-
- if (jwt == NULL)
- return NULL;
-
- new = jwt_malloc(sizeof(*new));
- if (!new)
- return NULL;
-
- memset(new, 0, sizeof(jwt_t));
-
- new->jw_key = jwt->jw_key;
- new->alg = jwt->alg;
- new->error = jwt->error;
- strcpy(new->error_msg, jwt->error_msg);
-
- new->grants = json_deep_copy(jwt->grants);
- new->headers = json_deep_copy(jwt->headers);
- if (!new->headers || !new->grants) {
- json_decref(new->headers);
- json_decref(new->grants);
- jwt_freep(&new);
- }
-
- return new;
-}
-
void *jwt_base64uri_decode(const char *src, int *ret_len)
{
void *buf;
@@ -361,7 +249,7 @@ int jwt_base64uri_encode(char **_dst, const char *plain, int plain_len)
static int __check_hmac(jwt_t *jwt)
{
- int key_bits = jwt->jw_key->bits;
+ int key_bits = jwt->key->bits;
if (key_bits < 256) {
jwt_write_error(jwt, "Key too short for HS algs: %d bits",
@@ -400,7 +288,7 @@ static int __check_hmac(jwt_t *jwt)
static int __check_key_bits(jwt_t *jwt)
{
- int key_bits = jwt->jw_key->bits;
+ int key_bits = jwt->key->bits;
/* Ignore if we don't have it */
if (key_bits == 0)
@@ -542,8 +430,3 @@ jwt_t *jwt_verify_sig(jwt_t *jwt, const char *head, unsigned int head_len,
return jwt;
}
-
-void jwt_config_init(jwt_config_t *config)
-{
- memset(config, 0, sizeof(*config));
-}
diff --git a/libjwt/openssl/sign-verify.c b/libjwt/openssl/sign-verify.c
index cb18fec7..32940104 100644
--- a/libjwt/openssl/sign-verify.c
+++ b/libjwt/openssl/sign-verify.c
@@ -33,11 +33,11 @@ static int openssl_sign_sha_hmac(jwt_t *jwt, char **out, unsigned int *len,
void *key;
size_t key_len;
- if (!ops_compat(jwt->jw_key, JWT_CRYPTO_OPS_OPENSSL))
+ if (!ops_compat(jwt->key, JWT_CRYPTO_OPS_OPENSSL))
return 1; // LCOV_EXCL_LINE
- key = jwt->jw_key->oct.key;
- key_len = jwt->jw_key->oct.len;
+ key = jwt->key->oct.key;
+ key_len = jwt->key->oct.len;
*out = NULL;
@@ -102,26 +102,26 @@ static int openssl_verify_sha_hmac(jwt_t *jwt, const char *head,
static int __degree_and_check(jwt_t *jwt)
{
- int bits = jwt->jw_key->bits;
+ int bits = jwt->key->bits;
switch (jwt->alg) {
case JWT_ALG_ES256:
- if (bits != 256 ||jwt_strcmp(jwt->jw_key->curve, "P-256"))
+ if (bits != 256 ||jwt_strcmp(jwt->key->curve, "P-256"))
return 0;
break;
case JWT_ALG_ES384:
- if (bits != 384 ||jwt_strcmp(jwt->jw_key->curve, "P-384"))
+ if (bits != 384 ||jwt_strcmp(jwt->key->curve, "P-384"))
return 0;
break;
case JWT_ALG_ES512:
- if (bits != 521 ||jwt_strcmp(jwt->jw_key->curve, "P-521"))
+ if (bits != 521 ||jwt_strcmp(jwt->key->curve, "P-521"))
return 0;
break;
case JWT_ALG_ES256K:
- if (bits != 256 ||jwt_strcmp(jwt->jw_key->curve, "secp256k1"))
+ if (bits != 256 ||jwt_strcmp(jwt->key->curve, "secp256k1"))
return 0;
break;
@@ -200,10 +200,10 @@ static int openssl_sign_sha_pem(jwt_t *jwt, char **out, unsigned int *len,
int ret = 0;
size_t slen;
- if (!ops_compat(jwt->jw_key, JWT_CRYPTO_OPS_OPENSSL))
+ if (!ops_compat(jwt->key, JWT_CRYPTO_OPS_OPENSSL))
return 1; // LCOV_EXCL_LINE
- pkey = jwt->jw_key->provider_data;
+ pkey = jwt->key->provider_data;
switch (jwt->alg) {
/* RSA */
@@ -263,7 +263,11 @@ static int openssl_sign_sha_pem(jwt_t *jwt, char **out, unsigned int *len,
return 1; // LCOV_EXCL_LINE
}
- if (type != EVP_PKEY_id(pkey))
+ if (type == EVP_PKEY_RSA_PSS) {
+ if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA_PSS &&
+ EVP_PKEY_id(pkey) != EVP_PKEY_RSA)
+ SIGN_ERROR(); // LCOV_EXCL_LINE
+ } else if (type != EVP_PKEY_id(pkey))
SIGN_ERROR(); // LCOV_EXCL_LINE
mdctx = EVP_MD_CTX_create();
@@ -277,10 +281,10 @@ static int openssl_sign_sha_pem(jwt_t *jwt, char **out, unsigned int *len,
/* Required for RSA-PSS */
if (type == EVP_PKEY_RSA_PSS) {
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx,
- RSA_PKCS1_PSS_PADDING) < 0)
+ RSA_PKCS1_PSS_PADDING) < 0)
SIGN_ERROR(); // LCOV_EXCL_LINE
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx,
- RSA_PSS_SALTLEN_DIGEST) < 0)
+ RSA_PSS_SALTLEN_DIGEST) < 0)
SIGN_ERROR(); // LCOV_EXCL_LINE
}
@@ -341,9 +345,9 @@ static int openssl_verify_sha_pem(jwt_t *jwt, const char *head,
int ret = 0;
int slen;
- if (!ops_compat(jwt->jw_key, JWT_CRYPTO_OPS_OPENSSL))
+ if (!ops_compat(jwt->key, JWT_CRYPTO_OPS_OPENSSL))
return 1; // LCOV_EXCL_LINE
- pkey = jwt->jw_key->provider_data;
+ pkey = jwt->key->provider_data;
switch (jwt->alg) {
/* RSA */
@@ -407,11 +411,15 @@ static int openssl_verify_sha_pem(jwt_t *jwt, const char *head,
if (sig == NULL)
VERIFY_ERROR();
- if (type != EVP_PKEY_id(pkey))
+ if (type == EVP_PKEY_RSA_PSS) {
+ if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA_PSS &&
+ EVP_PKEY_id(pkey) != EVP_PKEY_RSA)
+ VERIFY_ERROR(); // LCOV_EXCL_LINE
+ } else if (type != EVP_PKEY_id(pkey))
VERIFY_ERROR();
- /* Convert EC sigs back to ASN1. */
- if (type == EVP_PKEY_EC) {
+ if (type == EVP_PKEY_EC) {
+ /* Convert EC sigs back to ASN1. */
unsigned int bn_len;
int degree;
unsigned char *p;
@@ -462,7 +470,7 @@ static int openssl_verify_sha_pem(jwt_t *jwt, const char *head,
RSA_PKCS1_PSS_PADDING) < 0)
VERIFY_ERROR(); // LCOV_EXCL_LINE
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx,
- RSA_PSS_SALTLEN_DIGEST) < 0)
+ RSA_PSS_SALTLEN_AUTO) < 0)
VERIFY_ERROR(); // LCOV_EXCL_LINE
}
diff --git a/tests/jwt_builder.c b/tests/jwt_builder.c
new file mode 100644
index 00000000..8985e380
--- /dev/null
+++ b/tests/jwt_builder.c
@@ -0,0 +1,638 @@
+/* Public domain, no copyright. Use at your own risk. */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "jwt_tests.h"
+
+START_TEST(new)
+{
+ jwt_builder_auto_t *builder = NULL;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+}
+END_TEST
+
+START_TEST(gen)
+{
+ const char exp[] = "eyJhbGciOiJub25lIn0.";
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_mem_eq(out, exp, strlen(exp));
+}
+END_TEST
+
+static int __gen_wcb(jwt_t *jwt, jwt_config_t *config)
+{
+ jwt_value_t jval;
+
+ ck_assert_ptr_nonnull(jwt);
+ ck_assert_ptr_nonnull(config);
+
+ ck_assert_str_eq(config->ctx, "testing");
+ jwt_set_ADD_INT(&jval, "exp", TS_CONST + 480);
+ jwt_grant_add(jwt, &jval);
+
+ return 0;
+}
+
+START_TEST(gen_wcb)
+{
+ const char exp[] = "eyJhbGciOiJub25lIn0.eyJleHAiOjE0NzU5ODEwMjV9.";
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_builder_setcb(builder, __gen_wcb, "testing");
+ ck_assert_int_eq(ret, 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+}
+END_TEST
+
+START_TEST(gen_stress)
+{
+ const char exp[] = "eyJhbGciOiJub25lIn0.";
+ jwt_builder_auto_t *builder = NULL;
+ int i;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ for (i = 0; i < 1000; i++) {
+ char_auto *out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_mem_eq(out, exp, strlen(exp));
+ }
+
+ ck_assert_int_eq(i, 1000);
+}
+END_TEST
+
+START_TEST(null_handling)
+{
+ jwt_builder_t *builder = NULL;
+ const char *out;
+ jwk_item_t *key = NULL;
+ int ret;
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ jwt_builder_free(NULL);
+
+ ret = jwt_builder_setkey(NULL, JWT_ALG_HS256, NULL);
+ ck_assert_int_ne(ret, 0);
+
+ /* Create and clear an error */
+ ret = jwt_builder_setkey(builder, JWT_ALG_HS256, NULL);
+ ck_assert_int_ne(ret, 0);
+ /* Check error exists */
+ ck_assert_int_ne(jwt_builder_error(builder), 0);
+ out = jwt_builder_error_msg(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_int_ne(strlen(out), 0);
+ /* Clear it */
+ jwt_builder_error_clear(builder);
+ /* Check that its cleared */
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+ out = jwt_builder_error_msg(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_int_eq(strlen(out), 0);
+
+ /* Fake it */
+ key = (void *)builder;
+ ret = jwt_builder_setkey(NULL, 0, key);
+ ck_assert_int_ne(ret, 0);
+
+ ret = jwt_builder_error(NULL);
+ ck_assert_int_ne(ret, 0);
+
+ out = jwt_builder_error_msg(NULL);
+ ck_assert_ptr_null(out);
+
+ out = jwt_builder_error_msg(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_int_eq(strlen(out), 0);
+
+ jwt_builder_error_clear(NULL);
+
+ out = jwt_builder_generate(NULL);
+ ck_assert_ptr_null(out);
+}
+END_TEST
+
+START_TEST(gen_hs256)
+{
+ jwt_builder_auto_t *builder = NULL;
+ char *out = NULL;
+ const char exp[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256.json");
+ ret = jwt_builder_setkey(builder, JWT_ALG_HS256, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+
+ free_key();
+}
+END_TEST
+
+START_TEST(gen_es384_pub)
+{
+ jwt_builder_auto_t *builder = NULL;
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ /* Pub key will fail to set */
+ read_json("ec_key_secp384r1_pub.json");
+ ret = jwt_builder_setkey(builder, JWT_ALG_ES384, g_item);
+ ck_assert_int_ne(ret, 0);
+ ck_assert_str_eq(jwt_builder_error_msg(builder),
+ "Signing requires a private key");
+
+ free_key();
+}
+END_TEST
+
+static int __gen_hs256_wcb(jwt_t *jwt, jwt_config_t *config)
+{
+ ck_assert_ptr_nonnull(jwt);
+ ck_assert_ptr_nonnull(config);
+ ck_assert_int_eq(jwt_get_alg(jwt), JWT_ALG_NONE);
+
+ if (config->ctx != NULL) {
+ ck_assert_int_eq(jwt_get_alg(jwt), JWT_ALG_NONE);
+ config->key = g_item;
+ config->alg = JWT_ALG_HS256;
+ } else {
+ config->key = NULL;
+ config->alg = JWT_ALG_HS256;
+ }
+
+ return 0;
+}
+
+START_TEST(gen_hs256_wcb)
+{
+ jwt_builder_auto_t *builder = NULL;
+ char *out = NULL;
+ const char exp[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256.json");
+
+ ret = jwt_builder_setcb(builder, __gen_hs256_wcb, "testing");
+ ck_assert_int_eq(ret, 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+ free(out);
+
+ ret = jwt_builder_setcb(builder, __gen_hs256_wcb, NULL);
+ ck_assert_int_eq(ret, 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_null(out);
+ ck_assert_int_eq(jwt_builder_error(builder), 1);
+
+ free_key();
+}
+END_TEST
+
+START_TEST(gen_hs256_stress)
+{
+ jwt_builder_auto_t *builder = NULL;
+ const char exp[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret, i;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256.json");
+ ret = jwt_builder_setkey(builder, JWT_ALG_HS256, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ for (i = 0; i < 1000; i++) {
+ char_auto *out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+ }
+
+ free_key();
+}
+END_TEST
+
+START_TEST(claim_str_addgetdel)
+{
+ const char exp[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJka"
+ "XNrLnN3aXNzZGlzay5jb20ifQ.";
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "iss", "disk.swissdisk.com");
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "aud", "public");
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "aud", "private");
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_STR(&jval, "aud", "employees");
+ jval.replace = 1;
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_STR(&jval, "aud");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.str_val, "employees");
+
+ jwt_set_GET_INT(&jval, "aud");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_BOOL(&jval, "aud");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_builder_claim_del(builder, "aud");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_STR(&jval, "aud");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+}
+END_TEST
+
+START_TEST(claim_int_addgetdel)
+{
+ const char exp[] = "eyJhbGciOiJub25lIn0.eyJuYmYiOjE0NzU5ODA1NDV9.";
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_INT(&jval, "nbf", TS_CONST);
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_INT(&jval, "exp", TS_CONST);
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_INT(&jval, "exp", TS_CONST + 360);
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_INT(&jval, "exp", TS_CONST + 480);
+ jval.replace = 1;
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_INT(&jval, "exp");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_int_eq(jval.int_val, TS_CONST + 480);
+
+ jwt_set_GET_STR(&jval, "exp");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_BOOL(&jval, "exp");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_builder_claim_del(builder, "exp");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_INT(&jval, "exp");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+}
+END_TEST
+
+START_TEST(claim_bool_addgetdel)
+{
+ const char exp[] = "eyJhbGciOiJub25lIn0.eyJhZG1pbiI6dHJ1ZX0.";
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_BOOL(&jval, "admin", 1);
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_BOOL(&jval, "sudo", 1);
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_BOOL(&jval, "sudo", 0);
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_BOOL(&jval, "sudo", 0);
+ jval.replace = 1;
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_BOOL(&jval, "sudo");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_int_eq(jval.bool_val, 0);
+
+ jwt_set_GET_STR(&jval, "sudo");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_INT(&jval, "sudo");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_builder_claim_del(builder, "sudo");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_BOOL(&jval, "sudo");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+}
+END_TEST
+
+START_TEST(claim_json_addgetdel)
+{
+ const char exp[] = "eyJhbGciOiJub25lIn0.eyJyb29tcyI6WyJvZ"
+ "mZpY2UiLCJ3YXItcm9vbSJdfQ.";
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_JSON(&jval, "rooms",
+ "[\"office\",\"war-room\"]");
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_JSON(&jval, "rooms");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.json_val);
+ ck_assert_str_eq(jval.json_val, "[\"office\",\"war-room\"]");
+ free(jval.json_val);
+
+ jwt_set_ADD_JSON(&jval, "buildings",
+ "{\"main\":\"dallas\",\"accounting\":\"houston\"}");
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_JSON(&jval, "buildings", "{\"hq\": 0}");
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_JSON(&jval, "buildings", "{\"hq\": 1}");
+ jval.replace = 1;
+ ret = jwt_builder_claim_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_JSON(&jval, "buildings");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.json_val);
+ ck_assert_str_eq(jval.json_val, "{\"hq\":1}");
+ free(jval.json_val);
+
+ jwt_set_GET_STR(&jval, "buildings");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_INT(&jval, "buildings");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_builder_claim_del(builder, "buildings");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_JSON(&jval, "buildings");
+ ret = jwt_builder_claim_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+}
+END_TEST
+
+START_TEST(header_str_addgetdel)
+{
+ const char exp[] = "eyJhbGciOiJub25lIiwidHlwIjoiQ3VzdG9tIn0.e30.";
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "typ", "Custom");
+ ret = jwt_builder_header_add(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, exp);
+
+ jwt_set_GET_STR(&jval, "typ");
+ ret = jwt_builder_header_get(builder, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.str_val, "Custom");
+
+ ret = jwt_builder_header_del(builder, "typ");
+
+ jwt_set_GET_STR(&jval, "typ");
+ ret = jwt_builder_header_get(builder, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+}
+END_TEST
+
+static Suite *libjwt_suite(const char *title)
+{
+ Suite *s;
+ TCase *tc_core;
+ int i = ARRAY_SIZE(jwt_test_ops);
+
+ s = suite_create(title);
+
+ tc_core = tcase_create("New");
+ tcase_add_loop_test(tc_core, new, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Gen");
+ tcase_add_loop_test(tc_core, gen, 0, i);
+ tcase_add_loop_test(tc_core, gen_stress, 0, i);
+ tcase_add_loop_test(tc_core, gen_wcb, 0, i);
+ tcase_add_loop_test(tc_core, gen_es384_pub, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Error Handling");
+ tcase_add_loop_test(tc_core, null_handling, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("HS256 Key Gen");
+ tcase_add_loop_test(tc_core, gen_hs256, 0, i);
+ tcase_add_loop_test(tc_core, gen_hs256_wcb, 0, i);
+ tcase_add_loop_test(tc_core, gen_hs256_stress, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Claims AddGetDel");
+ tcase_add_loop_test(tc_core, claim_str_addgetdel, 0, i);
+ tcase_add_loop_test(tc_core, claim_int_addgetdel, 0, i);
+ tcase_add_loop_test(tc_core, claim_bool_addgetdel, 0, i);
+ tcase_add_loop_test(tc_core, claim_json_addgetdel, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Header AddGetDel");
+ /* All of the code paths for str/int/bool/json have been covered. We
+ * just run this to ensure add/get/del works on headers */
+ tcase_add_loop_test(tc_core, header_str_addgetdel, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int main(void)
+{
+ JWT_TEST_MAIN("LibJWT Builder");
+}
diff --git a/tests/jwt_checker.c b/tests/jwt_checker.c
new file mode 100644
index 00000000..2918cae2
--- /dev/null
+++ b/tests/jwt_checker.c
@@ -0,0 +1,737 @@
+/* Public domain, no copyright. Use at your own risk. */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "jwt_tests.h"
+
+START_TEST(new)
+{
+ jwt_checker_auto_t *checker = NULL;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+}
+END_TEST
+
+START_TEST(verify)
+{
+ const char token[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJka"
+ "XNrLnN3aXNzZGlzay5jb20ifQ.";
+ jwt_checker_auto_t *checker = NULL;
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_eq(ret, 0);
+}
+END_TEST
+
+static int __verify_wcb(jwt_t *jwt, jwt_config_t *config)
+{
+ ck_assert_ptr_nonnull(jwt);
+ ck_assert_ptr_nonnull(config);
+
+ ck_assert_str_eq(config->ctx, "testing");
+
+ return 0;
+}
+
+START_TEST(verify_wcb)
+{
+ const char token[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJka"
+ "XNrLnN3aXNzZGlzay5jb20ifQ.";
+ jwt_checker_auto_t *checker = NULL;
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_setcb(checker, __verify_wcb, "testing");
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_eq(ret, 0);
+}
+END_TEST
+
+START_TEST(verify_stress)
+{
+ const char token[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJka"
+ "XNrLnN3aXNzZGlzay5jb20ifQ.";
+ jwt_checker_auto_t *checker = NULL;
+ int i;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ for (i = 0; i < 1000; i++) {
+ int ret = jwt_checker_verify(checker, token);
+ ck_assert_int_eq(ret, 0);
+ }
+}
+END_TEST
+
+START_TEST(null_handling)
+{
+ jwt_checker_t *checker = NULL;
+ const char *out;
+ jwk_item_t *key = NULL;
+ int ret;
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ jwt_checker_free(NULL);
+
+ ret = jwt_checker_setkey(NULL, JWT_ALG_HS256, NULL);
+ ck_assert_int_ne(ret, 0);
+
+ /* Create and clear an error */
+ ret = jwt_checker_setkey(checker, JWT_ALG_HS256, NULL);
+ ck_assert_int_ne(ret, 0);
+ /* Check error exists */
+ ck_assert_int_ne(jwt_checker_error(checker), 0);
+ out = jwt_checker_error_msg(checker);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_int_ne(strlen(out), 0);
+ /* Clear it */
+ jwt_checker_error_clear(checker);
+ /* Check that its cleared */
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+ out = jwt_checker_error_msg(checker);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_int_eq(strlen(out), 0);
+
+ /* Fake it */
+ key = (void *)checker;
+ ret = jwt_checker_setkey(NULL, 0, key);
+ ck_assert_int_ne(ret, 0);
+
+ ret = jwt_checker_error(NULL);
+ ck_assert_int_ne(ret, 0);
+
+ out = jwt_checker_error_msg(NULL);
+ ck_assert_ptr_null(out);
+
+ out = jwt_checker_error_msg(checker);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_int_eq(strlen(out), 0);
+
+ jwt_checker_error_clear(NULL);
+
+ ret = jwt_checker_verify(NULL, NULL);
+ ck_assert_int_ne(ret, 0);
+
+ ret = jwt_checker_verify(checker, NULL);
+ ck_assert_int_ne(ret, 0);
+ ck_assert_int_ne(jwt_checker_error(checker), 0);
+
+ /* Fake it */
+ out = (void *)checker;
+ ret = jwt_checker_verify(NULL, out);;
+ ck_assert_int_ne(ret, 0);
+ ck_assert_int_ne(jwt_checker_error(checker), 0);
+}
+END_TEST
+
+START_TEST(verify_hs256)
+{
+ jwt_checker_auto_t *checker = NULL;
+ const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256.json");
+ ret = jwt_checker_setkey(checker, JWT_ALG_HS256, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_eq(ret, 0);
+
+ free_key();
+}
+END_TEST
+
+START_TEST(verify_rsapss384)
+{
+ jwt_checker_auto_t *checker = NULL;
+ // GnuTLS created
+ const char *token1 = "eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.e30.g_OJbEk"
+ "tbb721dPDZ5hDZHnf8Uk6PiZ8IoatdEGxRc3GBW8xef1jRm_jZYfWh5cEz9Mg"
+ "mzN0xN3q9wYCjoBrB_UUV4sonbUX4QEmUW5B5M0JJ3KyFhzJtcVrl9pVGT6ZB"
+ "FLV-Pwmlus7cq73xDVNrdIX0CkZQ-3pkesiOuUsPK62cs6cQS_TrRQe58JWk0"
+ "CoLIIpaiwZ56uerdPK2uAyDaxRzlVQ_2uKkLjSRCnz4eDHRYJriGtR_bfqIWo"
+ "_gQHowDh_tTeGcWiMugtp9aU6_ES7VSuS7cQuH_-oYEKwnIcM4O8zV5J9EuYl"
+ "JDx0M3C2E13dyUxFEKw3nGEcdiZhcA";
+ // OpenSSL created
+ const char *token2 = "eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.e30.gNMKG8F"
+ "GbaYNmH5CHHfr-ApOoD5AdtCyasjGaIdphyTrfBXZEqMBet3-C3-Bw1N3hPta"
+ "eN-HpFj5XlDQAy3mmyO0oAiP--NHPKMo09pNNGU18BsAH5ht9SE5Y50AB8Wr1"
+ "vArRZnds3MDmAVwjcG-YBAy8q8jdUP1G9DyItd32bETq-5xlixCW1Jqk8n5Px"
+ "6jMalpbYIwGYYr1vcUUbwOSagVu8crtmRaXt_PSy4kUpI4sKtggIYTjoezwy5"
+ "_B0Tu_cO9xgBe-uOYvJ5rEQk5jen84pBcJ5G8OLorrefX81Vw-AKdD5kdbbqh"
+ "UXSooe803Mt5G2IpDHAXmOwvVBixjA";
+ // JWT.io created
+ const char *token3 = "eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.e30.XZN5m3p"
+ "HZnDsdRlR8bmZ1XuSqRBALy5Ikl12KtmtFSCYF22eeIJVwuk_DpKLyhZsiXF_"
+ "FIQqoKU8wOO984vK1r8nlQyv_6C0TbC-fH5bjdZ8w5esBOyihEjtG5AScbjpw"
+ "FYCPz_6kayusQqA_FUS_fsjHtg3gKb6viyotlMD6CCengg9aV6TyFMchBL-0_"
+ "S6u-gBZC_1IJ6-ibPy8ILSVKgi6D8ucI2ZcSP79z8BZv8-HWPSJU70Ef4CEVn"
+ "Owo3Grx7zAaAuzDEBELggZeW51bOypBCmmaTy3G2txeYhBE5TI88IeYOh-lrE"
+ "KVQ-ZwOB8dGr0g8wbPl_i9WPdaJV7Q";
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("rsa_pss_key_2048_384_pub.json");
+ ret = jwt_checker_setkey(checker, JWT_ALG_PS384, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token3);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token2);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token1);
+ ck_assert_int_eq(ret, 0);
+
+ free_key();
+}
+END_TEST
+
+static int __verify_hs256_wcb(jwt_t *jwt, jwt_config_t *config)
+{
+ ck_assert_ptr_nonnull(jwt);
+ ck_assert_ptr_nonnull(config);
+ ck_assert_int_eq(jwt_get_alg(jwt), JWT_ALG_HS256);
+
+ if (config->ctx != NULL) {
+ config->key = g_item;
+ config->alg = JWT_ALG_HS256;
+ } else {
+ config->key = NULL;
+ config->alg = JWT_ALG_HS256;
+ }
+
+ return 0;
+}
+
+START_TEST(verify_hs256_wcb)
+{
+ jwt_checker_auto_t *checker = NULL;
+ const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256.json");
+
+ ret = jwt_checker_setcb(checker, __verify_hs256_wcb, "testing");
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_setcb(checker, __verify_hs256_wcb, NULL);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_ne(ret, 0);
+
+ free_key();
+}
+END_TEST
+
+START_TEST(verify_hs256_stress)
+{
+ jwt_checker_auto_t *checker = NULL;
+ const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret, i;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256.json");
+ ret = jwt_checker_setkey(checker, JWT_ALG_HS256, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ for (i = 0; i < 1000; i++) {
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_eq(ret, 0);
+ }
+
+ free_key();
+}
+END_TEST
+
+START_TEST(verify_hs256_fail)
+{
+ jwt_checker_auto_t *checker = NULL;
+ const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256_issue1.json");
+ ret = jwt_checker_setkey(checker, JWT_ALG_HS256, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_ne(ret, 0);
+ ck_assert_str_eq(jwt_checker_error_msg(checker),
+ "Token failed verification");
+
+ free_key();
+}
+END_TEST
+
+START_TEST(verify_hs256_fail_stress)
+{
+ jwt_checker_auto_t *checker = NULL;
+ const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+ int ret, i;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json("oct_key_256_issue1.json");
+ ret = jwt_checker_setkey(checker, JWT_ALG_HS256, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ for (i = 0; i < 1000; i++) {
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_ne(ret, 0);
+ ck_assert_str_eq(jwt_checker_error_msg(checker),
+ "Token failed verification");
+ }
+
+ free_key();
+}
+END_TEST
+
+START_TEST(claim_str_addgetdel)
+{
+ const char exp[] = "{\"iss\":\"disk.swissdisk.com\"}";
+ jwt_checker_auto_t *checker = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "iss", "disk.swissdisk.com");
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "aud", "public");
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "aud", "private");
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_STR(&jval, "aud", "employees");
+ jval.replace = 1;
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_STR(&jval, "aud");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.str_val, "employees");
+
+ jwt_set_GET_INT(&jval, "aud");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_BOOL(&jval, "aud");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_checker_claim_del(checker, "aud");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_STR(&jval, "aud");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ jwt_set_GET_JSON(&jval, NULL);
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.json_val, exp);
+ free(jval.json_val);
+}
+END_TEST
+
+START_TEST(claim_int_addgetdel)
+{
+ const char exp[] = "{\"nbf\":1475980545}";
+ jwt_checker_auto_t *checker = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_INT(&jval, "nbf", TS_CONST);
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_INT(&jval, "exp", TS_CONST);
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_INT(&jval, "exp", TS_CONST + 360);
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_INT(&jval, "exp", TS_CONST + 480);
+ jval.replace = 1;
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_INT(&jval, "exp");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_int_eq(jval.int_val, TS_CONST + 480);
+
+ jwt_set_GET_STR(&jval, "exp");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_BOOL(&jval, "exp");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_checker_claim_del(checker, "exp");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_INT(&jval, "exp");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ jwt_set_GET_JSON(&jval, NULL);
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.json_val, exp);
+ free(jval.json_val);
+}
+END_TEST
+
+START_TEST(claim_bool_addgetdel)
+{
+ const char exp[] = "{\"admin\":true}";
+ jwt_checker_auto_t *checker = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_BOOL(&jval, "admin", 1);
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_BOOL(&jval, "sudo", 1);
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_BOOL(&jval, "sudo", 0);
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_BOOL(&jval, "sudo", 0);
+ jval.replace = 1;
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_BOOL(&jval, "sudo");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_int_eq(jval.bool_val, 0);
+
+ jwt_set_GET_STR(&jval, "sudo");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_INT(&jval, "sudo");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_checker_claim_del(checker, "sudo");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_BOOL(&jval, "sudo");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ jwt_set_GET_JSON(&jval, NULL);
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.json_val, exp);
+ free(jval.json_val);
+}
+END_TEST
+
+START_TEST(claim_json_addgetdel)
+{
+ const char exp[] = "{\"rooms\":[\"office\",\"war-room\"]}";
+ jwt_checker_auto_t *checker = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_JSON(&jval, "rooms",
+ "[\"office\",\"war-room\"]");
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_JSON(&jval, "rooms");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.json_val);
+ ck_assert_str_eq(jval.json_val, "[\"office\",\"war-room\"]");
+ free(jval.json_val);
+
+ jwt_set_ADD_JSON(&jval, "buildings",
+ "{\"main\":\"dallas\",\"accounting\":\"houston\"}");
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_JSON(&jval, "buildings", "{\"hq\": 0}");
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
+
+ jwt_set_ADD_JSON(&jval, "buildings", "{\"hq\": 1}");
+ jval.replace = 1;
+ ret = jwt_checker_claim_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_JSON(&jval, "buildings");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.json_val);
+ ck_assert_str_eq(jval.json_val, "{\"hq\":1}");
+ free(jval.json_val);
+
+ jwt_set_GET_STR(&jval, "buildings");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ jwt_set_GET_INT(&jval, "buildings");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_TYPE);
+
+ ret = jwt_checker_claim_del(checker, "buildings");
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_JSON(&jval, "buildings");
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+
+ jwt_set_GET_JSON(&jval, NULL);
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.json_val, exp);
+ free(jval.json_val);
+}
+
+START_TEST(header_str_addgetdel)
+{
+ const char exp[] = "{}";
+ jwt_checker_auto_t *checker = NULL;
+ char_auto *out = NULL;
+ jwt_value_t jval;
+ int ret;
+
+ SET_OPS();
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_ADD_STR(&jval, "typ", "Custom");
+ ret = jwt_checker_header_add(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+
+ jwt_set_GET_JSON(&jval, NULL);
+ ret = jwt_checker_claim_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.json_val, exp);
+ free(jval.json_val);
+
+ jwt_set_GET_STR(&jval, "typ");
+ ret = jwt_checker_header_get(checker, &jval);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_ptr_nonnull(jval.str_val);
+ ck_assert_str_eq(jval.str_val, "Custom");
+
+ ret = jwt_checker_header_del(checker, "typ");
+
+ jwt_set_GET_STR(&jval, "typ");
+ ret = jwt_checker_header_get(checker, &jval);
+ ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
+}
+END_TEST
+
+static Suite *libjwt_suite(const char *title)
+{
+ Suite *s;
+ TCase *tc_core;
+ int i = ARRAY_SIZE(jwt_test_ops);
+
+ s = suite_create(title);
+
+ tc_core = tcase_create("New");
+ tcase_add_loop_test(tc_core, new, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Verify");
+ tcase_add_loop_test(tc_core, verify, 0, i);
+ tcase_add_loop_test(tc_core, verify_rsapss384, 0, i);
+ tcase_add_loop_test(tc_core, verify_wcb, 0, i);
+ tcase_add_loop_test(tc_core, verify_stress, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Error Handling");
+ tcase_add_loop_test(tc_core, null_handling, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("HS256 Key Verify");
+ tcase_add_loop_test(tc_core, verify_hs256, 0, i);
+ tcase_add_loop_test(tc_core, verify_hs256_wcb, 0, i);
+ tcase_add_loop_test(tc_core, verify_hs256_stress, 0, i);
+ tcase_add_loop_test(tc_core, verify_hs256_fail, 0, i);
+ tcase_add_loop_test(tc_core, verify_hs256_fail_stress, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Claims AddGetDel");
+ tcase_add_loop_test(tc_core, claim_str_addgetdel, 0, i);
+ tcase_add_loop_test(tc_core, claim_int_addgetdel, 0, i);
+ tcase_add_loop_test(tc_core, claim_bool_addgetdel, 0, i);
+ tcase_add_loop_test(tc_core, claim_json_addgetdel, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ tc_core = tcase_create("Header AddGetDel");
+ /* All of the code paths for str/int/bool/json have been covered. We
+ * just run this to ensure add/get/del works on headers */
+ tcase_add_loop_test(tc_core, header_str_addgetdel, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int main(void)
+{
+ JWT_TEST_MAIN("LibJWT Checker");
+}
diff --git a/tests/jwt_dump.c b/tests/jwt_dump.c
deleted file mode 100644
index c7356eab..00000000
--- a/tests/jwt_dump.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-static void *test_malloc(size_t size)
-{
- return malloc(size);
-}
-
-static void test_free(void *ptr)
-{
- free(ptr);
-}
-
-static void *test_realloc(void *ptr, size_t size)
-{
- return realloc(ptr, size);
-}
-
-static int test_set_alloc(void)
-{
- return jwt_set_alloc(test_malloc, test_realloc, test_free);
-}
-
-#ifdef JWT_CONSTRUCTOR
-START_TEST(test_jwt_crypto_ops)
-{
- const char *msg = getenv("JWT_CRYPTO");
-
- ck_assert_str_eq(msg, "NONEXISTENT");
-}
-END_TEST
-#endif
-
-START_TEST(test_alloc_funcs)
-{
- jwt_malloc_t m = NULL;
- jwt_realloc_t r = NULL;
- jwt_free_t f = NULL;
- int ret;
-
- SET_OPS();
-
- jwt_get_alloc(&m, &r, &f);
- ck_assert_ptr_null(m);
- ck_assert_ptr_null(r);
- ck_assert_ptr_null(f);
-
- ret = test_set_alloc();
- ck_assert_int_eq(ret, 0);
-
- jwt_get_alloc(&m, &r, &f);
- ck_assert(m == test_malloc);
- ck_assert(r == test_realloc);
- ck_assert(f == test_free);
-}
-END_TEST
-
-START_TEST(test_jwt_dump_str)
-{
- jwt_value_t jval;
- jwt_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- ret = test_set_alloc();
- ck_assert_int_eq(ret, 0);
-
- jwt = jwt_create(NULL);
- ck_assert_ptr_nonnull(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", (long)time(NULL));
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- /* Test 'typ' header: should not be present, cause 'alg' is JWT_ALG_NONE. */
- jwt_set_GET_STR(&jval, "typ");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
- ck_assert_ptr_null(jval.str_val);
-
- /* Test 'typ' header: should not be present, cause 'alg' is JWT_ALG_NONE. */
- jwt_set_GET_STR(&jval, "typ");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
- ck_assert_ptr_null(jval.str_val);
-
- jwt_free(jwt);
-}
-END_TEST
-
-#define JSON_GRANTS_PRETTY "{\n" \
- " \"%s\": %ld,\n" \
- " \"%s\": \"%s\",\n" \
- " \"%s\": \"%s\",\n" \
- " \"%s\": \"%s\"\n" \
- "}"
-
-#define JSON_GRANTS_COMPACT "{\"%s\":%ld,\"%s\":\"%s\"," \
- "\"%s\":\"%s\",\"%s\":\"%s\"}"
-
-
-START_TEST(test_jwt_dump_grants_str)
-{
- jwt_value_t jval;
- jwt_t *jwt = NULL;
- int ret = 0;
- char *out;
- long timestamp = (long)time(NULL);
- char buf[1024];
-
- SET_OPS();
-
- ret = test_set_alloc();
- ck_assert_int_eq(ret, 0);
-
- jwt = jwt_create(NULL);
- ck_assert_ptr_nonnull(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", timestamp);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_JSON(&jval, NULL);
- jval.pretty = 1;
- ret = jwt_grant_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- out = jval.json_val;
- ck_assert_ptr_nonnull(out);
-
- /* Sorted Keys are expected */
- snprintf(buf, sizeof(buf), JSON_GRANTS_PRETTY,
- "iat", timestamp,
- "iss", "files.maclara-llc.com",
- "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC",
- "sub", "user0");
- ck_assert_str_eq(out, buf);
-
- free(out);
-
- jwt_set_GET_JSON(&jval, NULL);
- ret = jwt_grant_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- out = jval.json_val;
- ck_assert_ptr_nonnull(out);
-
- /* Sorted Keys are expected */
- snprintf(buf, sizeof(buf), JSON_GRANTS_COMPACT,
- "iat", timestamp,
- "iss", "files.maclara-llc.com",
- "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC",
- "sub", "user0");
- ck_assert_str_eq(out, buf);
-
- free(out);
-
- jwt_free(jwt);
-}
-END_TEST
-
-START_TEST(test_jwt_dump_str_alg_default_typ_header)
-{
- jwt_value_t jval;
- jwt_test_auto_t *jwt = NULL;
- char *out = NULL;
- int ret = 0;
-
- SET_OPS();
-
- ret = test_set_alloc();
- ck_assert_int_eq(ret, 0);
-
- CREATE_JWT(jwt, "oct_key_256.json", JWT_ALG_HS256);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", (long)time(NULL));
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- /*
- * Test 'typ' header: should not be present, cause jwt's header has
- * not been touched yet by jwt_write_head, this is only called as a
- * result of calling jwt_dump* methods.
- */
- jwt_set_GET_STR(&jval, "typ");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_ne(ret, 0);
- ck_assert_ptr_null(jval.str_val);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_nonnull(out);
-
- /*
- * Test 'typ' header: should be added with default value of 'JWT',
- * cause 'alg' is set explicitly and jwt's header has been processed
- * by jwt_write_head.
- */
- jwt_set_GET_STR(&jval, "typ");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.str_val);
- ck_assert_str_eq(jval.str_val, "JWT");
-}
-END_TEST
-
-START_TEST(test_jwt_dump_str_alg_custom_typ_header)
-{
- jwt_value_t jval;
- jwt_test_auto_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- ret = test_set_alloc();
- ck_assert_int_eq(ret, 0);
-
- CREATE_JWT(jwt, "oct_key_256.json", JWT_ALG_HS256);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", (long)time(NULL));
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "typ", "favourite");
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- /* Test that 'typ' header has been added. */
- jwt_set_GET_STR(&jval, "typ");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.str_val);
- ck_assert_str_eq(jval.str_val, "favourite");
-
- /* Test 'typ' header: should be left untouched. */
- jwt_set_GET_STR(&jval, "typ");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.str_val);
- ck_assert_str_eq(jval.str_val, "favourite");
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_dump");
-
-#ifdef JWT_CONSTRUCTOR
- tcase_add_test(tc_core, test_jwt_crypto_ops);
-#endif
- tcase_add_loop_test(tc_core, test_alloc_funcs, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_dump_str, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_dump_grants_str, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_dump_str_alg_default_typ_header, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_dump_str_alg_custom_typ_header, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT Dump");
-}
diff --git a/tests/jwt_ec.c b/tests/jwt_ec.c
index 64f00a85..9ffa1576 100644
--- a/tests/jwt_ec.c
+++ b/tests/jwt_ec.c
@@ -8,132 +8,99 @@
#include "jwt_tests.h"
-/* NOTE: ES signing will generate a different signature every time, so can't
- * be simply string compared for verification like we do with RS. */
-
-static const char jwt_es256[] = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQ"
- "iOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZiI6Ilh"
- "YWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.IONoUPo6QhHwcx1"
- "N1TD4DnrjvmB-9lSX6qrn_WPrh3DBum-qKP66MIF9tgymy7hCoU6dvUW8zKK0AyVH3iD"
- "1uA";
-
-static const char jwt_es384[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJpYXQ"
- "iOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLmN5cGhyZS5jb20iLCJyZWYiOiJYWFhYLVl"
- "ZWVktWlpaWi1BQUFBLUNDQ0MiLCJzdWIiOiJ1c2VyMCJ9.p6McjolhuIqel0DWaI2OrD"
- "oRYcxgSMnGFirdKT5jXpe9L801HBkouKBJSae8F7LLFUKiE2VVX_514WzkuExLQs2eB1"
- "L2Qahid5VFOK3hc7HcBL-rcCXa8d2tf_MudyrM";
-
-static const char jwt_es512[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJpYXQ"
- "iOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLmN5cGhyZS5jb20iLCJyZWYiOiJYWFhYLVl"
- "ZWVktWlpaWi1BQUFBLUNDQ0MiLCJzdWIiOiJ1c2VyMCJ9.Abs-SriTqd9NAO-bJb-B3U"
- "zF1W8JmoutfHQpMqJnkPHyasVVuKN-I-6RibSv-qxgTxuzlo0u5dCt4mOw7w8mgEnMAS"
- "zsjm-NlOPUBjIUD9T592lse9OOF6TjPOQbijqeMc6qFZ8q5YhxvxBXHO6PuImkJpEWj4"
- "Zda8lNTxqHol7vorg9";
-
-static const char jwt_es_invalid[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQ"
- "iOjE0NzU5ODA1IAmCornholio6ImZpbGVzLmN5cGhyZS5jb20iLCJyZWYiOiJYWFhYLVl"
- "PN9G9tV75ylfWvcwkF20bQA9m1vDbUIl8PIK8Q";
-
-START_TEST(test_jwt_encode_es256)
+START_TEST(test_jwks_ec_pub_missing)
{
- SET_OPS();
- __test_alg_key(JWT_ALG_ES256, "ec_key_prime256v1.json",
- "ec_key_prime256v1_pub.json");
-}
-END_TEST
+ const char *json = "{\"kty\":\"EC\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Missing or invalid type for one of crv, x, or y for pub key";
-START_TEST(test_jwt_verify_es256)
-{
SET_OPS();
- __verify_jwt(jwt_es256, JWT_ALG_ES256, "ec_key_prime256v1_pub.json");
-}
-END_TEST
-START_TEST(test_jwt_encode_es384)
-{
- SET_OPS();
- __test_alg_key(JWT_ALG_ES384, "ec_key_secp384r1.json", "ec_key_secp384r1_pub.json");
-}
-END_TEST
+ jwk_set = jwks_create(json);
-START_TEST(test_jwt_verify_es384)
-{
- SET_OPS();
- __verify_jwt(jwt_es384, JWT_ALG_ES384, "ec_key_secp384r1_pub.json");
-}
-END_TEST
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
-START_TEST(test_jwt_encode_es512)
-{
- SET_OPS();
- __test_alg_key(JWT_ALG_ES512, "ec_key_secp521r1.json", "ec_key_secp521r1_pub.json");
-}
-END_TEST
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
-START_TEST(test_jwt_verify_es512)
-{
- SET_OPS();
- __verify_jwt(jwt_es512, JWT_ALG_ES512, "ec_key_secp521r1_pub.json");
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
+
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_encode_ec_with_rsa)
+START_TEST(test_jwks_ec_pub_bad_type)
{
- JWT_CONFIG_DECLARE(config);
- jwt_test_auto_t *jwt = NULL;
+ const char *json = "{\"kty\":\"EC\",\"crv\":\"prime6v1\",\"x\":\"sd+#(@#($(ada\",\"y\":1}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Missing or invalid type for one of crv, x, or y for pub key";
SET_OPS();
- read_key("rsa_key_4096.json");
- config.alg = JWT_ALG_ES384;
- config.jw_key = g_item;
- jwt = jwt_create(&config);
- ck_assert_int_ne(jwt_error(jwt), 0);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_str_eq(jwt_error_msg(jwt),
- "Config alg does not match key alg");
-}
-END_TEST
+ jwk_set = jwks_create(json);
-START_TEST(test_jwt_verify_invalid_token)
-{
- jwt_t *jwt = NULL;
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
- SET_OPS();
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
+
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
- read_key("ec_key_secp384r1.json");
- jwt = jwt_verify(jwt_es_invalid, &t_config);
- free_key();
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_verify_invalid_alg)
+START_TEST(test_jwks_ec_pub_bad64)
{
- jwt_t *jwt = NULL;
+ const char *json = "{\"kty\":\"EC\",\"crv\":\"prime6v1\",\"x\":\"\",\"y\":\"asaad\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Error generating pub key from components";
SET_OPS();
- read_key("ec_key_secp384r1.json");
- jwt = jwt_verify(jwt_es256, &t_config);
- free_key();
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
+ jwk_set = jwks_create(json);
+
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
+
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
+
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
+
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_verify_invalid_cert)
+START_TEST(test_jwks_ec_pub_bad_points)
{
- jwt_t *jwt = NULL;
+ const char *json = "{\"kty\":\"EC\",\"crv\":\"prime256v1\",\"x\":\"YmFkdmFsdWUK\",\"y\":\"YmFkdmFsdWUK\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Error generating pub key from components";
SET_OPS();
- read_key("ec_key_secp521r1_pub.json");
- jwt = jwt_verify(jwt_es256, &t_config);
- free_key();
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
+ jwk_set = jwks_create(json);
+
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
+
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
+
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
+
+ jwks_free(jwk_set);
}
END_TEST
@@ -145,18 +112,13 @@ static Suite *libjwt_suite(const char *title)
s = suite_create(title);
- tc_core = tcase_create("jwt_ec");
+ tc_core = tcase_create("jwt_jwks_ec");
- tcase_add_loop_test(tc_core, test_jwt_encode_es256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_es256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_es384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_es384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_es512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_es512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_ec_with_rsa, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_token, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_alg, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_cert, 0, i);
+ /* EC specific error path tests */
+ tcase_add_loop_test(tc_core, test_jwks_ec_pub_missing, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_ec_pub_bad64, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_ec_pub_bad_type, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_ec_pub_bad_points, 0, i);
tcase_set_timeout(tc_core, 30);
@@ -167,5 +129,5 @@ static Suite *libjwt_suite(const char *title)
int main(void)
{
- JWT_TEST_MAIN("LibJWT EC Sign/Verify");
+ JWT_TEST_MAIN("LibJWT JWKS Error Path Testing EC");
}
diff --git a/tests/jwt_eddsa.c b/tests/jwt_eddsa.c
deleted file mode 100644
index 24487ad8..00000000
--- a/tests/jwt_eddsa.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-static const char jwt_eddsa[] = "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpY"
- "XQiOjE3MzYxMjA1OTIsImlzcyI6ImRpc2suc3dpc3NkaXNrLmNvbSIsInN1YiI6InV"
- "zZXIwIn0.m28yyGiulqE9CUbZ64oSlec7TglR6DvVWohayJvJsJzk65RLx99gycRig"
- "aYjKKNe0e0Fff3BsIAlh3A-ptkmAg";
-
-START_TEST(test_jwt_encode_eddsa)
-{
- SET_OPS();
- __test_alg_key(JWT_ALG_EDDSA, "eddsa_key_ed25519.json",
- "eddsa_key_ed25519_pub.json");
-}
-END_TEST
-
-START_TEST(test_jwt_verify_eddsa)
-{
- SET_OPS();
- __verify_jwt(jwt_eddsa, JWT_ALG_EDDSA, "eddsa_key_ed25519_pub.json");
-}
-END_TEST
-
-START_TEST(test_jwt_encode_eddsa_with_rsa)
-{
- JWT_CONFIG_DECLARE(config);
- jwt_test_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("rsa_key_4096.json");
- config.alg = JWT_ALG_EDDSA;
- config.jw_key = g_item;
- jwt = jwt_create(&config);
- ck_assert_int_ne(jwt_error(jwt), 0);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_str_eq(jwt_error_msg(jwt),
- "Config alg does not match key alg");
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_eddsa");
-
- tcase_add_loop_test(tc_core, test_jwt_encode_eddsa, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_eddsa, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_eddsa_with_rsa, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT EdDSA Sign/Verify");
-}
diff --git a/tests/jwt_encode.c b/tests/jwt_encode.c
deleted file mode 100644
index adba113a..00000000
--- a/tests/jwt_encode.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-START_TEST(test_jwt_encode_fp)
-{
- const char exp[] = "eyJhbGciOiJub25lIn0.eyJpYXQiOjE0NzU5ODA1NDUsIml"
- "zcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZiI6IlhYWFgtWVlZW"
- "S1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.";
- char read_back[BUFSIZ];
- jwt_value_t jval;
- FILE *out;
- jwt_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = fopen("test_outfile.txt", "w");
- ck_assert_ptr_nonnull(out);
-
- ret = jwt_encode_fp(jwt, out);
- ck_assert_int_eq(ret, 0);
- fclose(out);
-
- out = fopen("test_outfile.txt", "r");
- ck_assert_ptr_nonnull(out);
- ret = fread(read_back, 1, sizeof(read_back), out);
- ck_assert_int_gt(ret, 0);
- read_back[ret] = '\0';
- fclose(out);
- unlink("test_outfile.txt");
-
- ck_assert_str_eq(exp, read_back);
-
- jwt_free(jwt);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_str)
-{
- const char res[] = "eyJhbGciOiJub25lIn0.eyJpYXQiOjE0NzU5ODA1NDUsIml"
- "zcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZiI6IlhYWFgtWVlZW"
- "S1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.";
- jwt_value_t jval;
- jwt_t *jwt = NULL;
- int ret = 0;
- char *out;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_ne(out, NULL);
-
- ck_assert_str_eq(out, res);
-
- free(out);
-
- jwt_free(jwt);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_alg_none)
-{
- const char res[] = "eyJhbGciOiJub25lIn0.eyJhdWQiOiJ3d3cucGx1Z2dlcnM"
- "ubmwiLCJleHAiOjE0Nzc1MTQ4MTIsInN1YiI6IlBsdWdnZXJzIFNvZnR3Y"
- "XJlIn0.";
- jwt_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
- char *out;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "aud", "www.pluggers.nl");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "exp", 1477514812);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "Pluggers Software");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_ne(out, NULL);
-
- ck_assert_str_eq(out, res);
-
- free(out);
-
- jwt_free(jwt);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_hs256)
-{
- const char res[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOj"
- "E0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJl"
- "ZiI6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn"
- "0.JgSDx8Xwc6tjMDglRndhLeAbjPPrTNoK6uc_E_TDu_o";
- jwt_test_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
- char *out;
-
- SET_OPS();
-
- CREATE_JWT(jwt, "oct_key_256.json", JWT_ALG_HS256);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_ne(out, NULL);
-
- ck_assert_str_eq(out, res);
-
- free(out);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_hs384)
-{
- const char res[] = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJpYXQiOj"
- "E0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJl"
- "ZiI6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn"
- "0.sI0hzVmaMsnfKjEGsANdMNPUfe_Pk1JPY_aixKCxVvCy25B0ADUBQdKz"
- "6VIUPmG_";
- jwt_test_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
- char *out;
-
- SET_OPS();
-
- CREATE_JWT(jwt, "oct_key_384.json", JWT_ALG_HS384);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_ne(out, NULL);
-
- ck_assert_str_eq(out, res);
-
- free(out);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_hs512)
-{
- const char res[] = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQiOj"
- "E0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJl"
- "ZiI6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn"
- "0.qQ1ghQaPvzIRnzGgUPmvqEk0NlcMYjeZuna8xQLfKtZ52VHCaT-FS8T0"
- "O2O_O9NQyqnA3sNnDaSsTxq1fEuDLA";
- jwt_test_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
- char *out;
-
- SET_OPS();
-
- CREATE_JWT(jwt, "oct_key_512.json", JWT_ALG_HS512);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_ne(out, NULL);
-
- ck_assert_str_eq(out, res);
-
- free(out);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_change_alg)
-{
- const char res[] = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQiOj"
- "E0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJl"
- "ZiI6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn"
- "0.qQ1ghQaPvzIRnzGgUPmvqEk0NlcMYjeZuna8xQLfKtZ52VHCaT-FS8T0"
- "O2O_O9NQyqnA3sNnDaSsTxq1fEuDLA";
- jwt_test_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
- char *out;
-
- SET_OPS();
-
- CREATE_JWT(jwt, "oct_key_512.json", JWT_ALG_HS512);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_ne(out, NULL);
-
- ck_assert_str_eq(out, res);
-
- free(out);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_decode)
-{
- jwt_test_auto_t *mytoken = NULL;
- jwt_auto_t *ymtoken = NULL;
- jwt_value_t jval;
- char *encoded;
-
- SET_OPS();
-
- CREATE_JWT(mytoken, "oct_key_256.json", JWT_ALG_HS256);
- jwt_set_ADD_STR(&jval, "sub", "user0");
- jwt_grant_add(mytoken, &jval);
- jwt_set_ADD_INT(&jval, "iat", 1619130517);
- jwt_grant_add(mytoken, &jval);
- jwt_set_ADD_INT(&jval, "exp", 1619216917);
- jwt_grant_add(mytoken, &jval);
-
- encoded = jwt_encode_str(mytoken);
-
- t_config.alg = JWT_ALG_HS256;
- ymtoken = jwt_verify(encoded, &t_config);
- ck_assert_ptr_nonnull(ymtoken);
- ck_assert_int_eq(jwt_error(ymtoken), 0);
-
- free(encoded);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_too_short)
-{
- jwt_test_auto_t *mytoken;
- jwt_value_t jval;
- char *encoded;
-
- SET_OPS();
-
- CREATE_JWT(mytoken, "oct_key_512_bad.json", JWT_ALG_HS512);
- jwt_set_ADD_STR(&jval, "sub", "user0");
- jwt_grant_add(mytoken, &jval);
- jwt_set_ADD_INT(&jval, "iat", 1619130517);
- jwt_grant_add(mytoken, &jval);
- jwt_set_ADD_INT(&jval, "exp", 1619216917);
- jwt_grant_add(mytoken, &jval);
-
- encoded = jwt_encode_str(mytoken);
- ck_assert_ptr_null(encoded);
- ck_assert_int_ne(jwt_error(mytoken), 0);
- ck_assert_str_eq(jwt_error_msg(mytoken),
- "Key too short for HS512: 256 bits");
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_encode");
-
- tcase_add_loop_test(tc_core, test_jwt_encode_fp, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_str, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_alg_none, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_hs256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_hs384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_hs512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_change_alg, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_decode, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_too_short, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT Encode");
-}
diff --git a/tests/jwt_es256k.c b/tests/jwt_es256k.c
deleted file mode 100644
index 2983ef6b..00000000
--- a/tests/jwt_es256k.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-static const char jwt_es256k[] = "eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.e"
- "yJpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsIn"
- "JlZiI6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.u_E"
- "sClxS3Z8AFYude9vRupmOZ35646zAgc1xgTf_g1ImJV_1B6kqrg0IS1ckHimgUjd4"
- "-DBR1UMibSCdByZngw";
-
-#define SKIP_IF(opname) ({ \
- if (!strcmp(opname, jwt_get_crypto_ops())) \
- return; \
-})
-
-START_TEST(test_jwt_encode_es256k)
-{
- SET_OPS();
- SKIP_IF("gnutls");
- __test_alg_key(JWT_ALG_ES256K, "ec_key_secp256k1.json",
- "ec_key_secp256k1_pub.json");
-}
-END_TEST
-
-START_TEST(test_jwt_verify_es256k)
-{
- SET_OPS();
- SKIP_IF("gnutls");
- __verify_jwt(jwt_es256k, JWT_ALG_ES256K, "ec_key_secp256k1_pub.json");
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_es256k");
-
- tcase_add_loop_test(tc_core, test_jwt_encode_es256k, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_es256k, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT ES256K Sign/Verify");
-}
diff --git a/tests/jwt_flipflop.c b/tests/jwt_flipflop.c
new file mode 100644
index 00000000..d291fe77
--- /dev/null
+++ b/tests/jwt_flipflop.c
@@ -0,0 +1,257 @@
+/* Public domain, no copyright. Use at your own risk. */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "jwt_tests.h"
+
+
+static void *test_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static void test_free(void *ptr)
+{
+ free(ptr);
+}
+
+static void *test_realloc(void *ptr, size_t size)
+{
+ return realloc(ptr, size);
+}
+
+static int test_set_alloc(void)
+{
+ return jwt_set_alloc(test_malloc, test_realloc, test_free);
+}
+
+#ifdef JWT_CONSTRUCTOR
+START_TEST(test_jwt_crypto_ops)
+{
+ const char *msg = getenv("JWT_CRYPTO");
+
+ ck_assert_str_eq(msg, "NONEXISTENT");
+}
+END_TEST
+#endif
+
+START_TEST(test_alloc_funcs)
+{
+ jwt_malloc_t m = NULL;
+ jwt_realloc_t r = NULL;
+ jwt_free_t f = NULL;
+ int ret;
+
+ SET_OPS();
+
+ jwt_get_alloc(&m, &r, &f);
+ ck_assert_ptr_null(m);
+ ck_assert_ptr_null(r);
+ ck_assert_ptr_null(f);
+
+ ret = test_set_alloc();
+ ck_assert_int_eq(ret, 0);
+
+ jwt_get_alloc(&m, &r, &f);
+ ck_assert(m == test_malloc);
+ ck_assert(r == test_realloc);
+ ck_assert(f == test_free);
+
+ /* XXX Need to do a build/verify to excercise the functions */
+}
+END_TEST
+
+static char *__builder(const char *priv, jwt_alg_t alg)
+{
+ jwt_builder_auto_t *builder;
+ jwt_alg_t a_check = JWT_ALG_NONE;
+ char *out;
+ int ret;
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ read_json(priv);
+
+ if (jwks_item_alg(g_item) == JWT_ALG_NONE)
+ a_check = alg;
+
+ ret = jwt_builder_setkey(builder, a_check, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+
+ free_key();
+
+ return out;
+}
+
+static void __checker(const char *pub, jwt_alg_t alg, char *token)
+{
+ jwt_checker_auto_t *checker;
+ int ret;
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ read_json(pub);
+
+ ret = jwt_checker_setkey(checker, alg, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token);
+ if (ret)
+ fprintf(stderr, "E: %s\n", jwt_checker_error_msg(checker));
+ ck_assert_int_eq(ret, 0);
+ free(token);
+
+ free_key();
+}
+
+static void __flip_one(const char *priv, const char *pub, jwt_alg_t alg)
+{
+ char *out = NULL;
+ int ret;
+
+ /* If this doesn't work, we wont even bother */
+ ret = jwt_set_crypto_ops("gnutls");
+ if (ret)
+ return;
+
+ /* This one is mandated */
+ ret = jwt_set_crypto_ops("openssl");
+ ck_assert_int_eq(ret, 0);
+
+ /* Generate on OpenSSL */
+ out = __builder(priv, alg);
+
+ /* Switch to GnuTLS */
+ ret = jwt_set_crypto_ops("gnutls");
+ ck_assert_int_eq(ret, 0);
+
+ /* Verify the OpenSSL token on GnuTLS */
+ __checker(pub, alg, out);
+
+ /* Midway through, we switch memory ops */
+ test_set_alloc();
+
+ /* Generate on GnuTLS */
+ out = __builder(priv, alg);
+
+ /* Switch back to OpenSSL */
+ ret = jwt_set_crypto_ops("openssl");
+ ck_assert_int_eq(ret, 0);
+
+ /* And verify the GnuTLS token on OpenSSL */
+ __checker(pub, alg, out);
+
+ free_key();
+}
+
+#define FLIPFLOP_KEY(__name, __pub, __alg) \
+START_TEST(__name) \
+{ \
+ __flip_one(#__name ".json", \
+ #__pub ".json", __alg); \
+} \
+END_TEST
+
+FLIPFLOP_KEY(ec_key_prime256v1,
+ ec_key_prime256v1_pub,
+ JWT_ALG_ES256);
+FLIPFLOP_KEY(ec_key_secp384r1,
+ ec_key_secp384r1_pub,
+ JWT_ALG_ES384);
+FLIPFLOP_KEY(ec_key_secp521r1,
+ ec_key_secp521r1,
+ JWT_ALG_ES512);
+
+FLIPFLOP_KEY(eddsa_key_ed25519,
+ eddsa_key_ed25519,
+ JWT_ALG_EDDSA);
+FLIPFLOP_KEY(eddsa_key_ed448,
+ eddsa_key_ed448_pub,
+ JWT_ALG_EDDSA);
+
+FLIPFLOP_KEY(rsa_key_2048,
+ rsa_key_2048_pub,
+ JWT_ALG_RS256);
+FLIPFLOP_KEY(rsa_key_4096,
+ rsa_key_4096,
+ JWT_ALG_RS384);
+FLIPFLOP_KEY(rsa_key_8192,
+ rsa_key_8192_pub,
+ JWT_ALG_RS512);
+
+FLIPFLOP_KEY(rsa_pss_key_2048,
+ rsa_pss_key_2048,
+ JWT_ALG_PS256);
+FLIPFLOP_KEY(rsa_pss_key_2048_384,
+ rsa_pss_key_2048_384_pub,
+ JWT_ALG_PS384);
+FLIPFLOP_KEY(rsa_pss_key_2048_512,
+ rsa_pss_key_2048_512_pub,
+ JWT_ALG_PS512);
+
+FLIPFLOP_KEY(oct_key_256,
+ oct_key_256,
+ JWT_ALG_HS256);
+FLIPFLOP_KEY(oct_key_384,
+ oct_key_384,
+ JWT_ALG_HS384);
+FLIPFLOP_KEY(oct_key_512,
+ oct_key_512,
+ JWT_ALG_HS512);
+
+static Suite *libjwt_suite(const char *title)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create(title);
+
+ tc_core = tcase_create("Keys");
+
+ tcase_add_test(tc_core, ec_key_prime256v1);
+ tcase_add_test(tc_core, ec_key_secp384r1);
+ tcase_add_test(tc_core, ec_key_secp521r1);
+
+ tcase_add_test(tc_core, eddsa_key_ed25519);
+ tcase_add_test(tc_core, eddsa_key_ed448);
+
+ tcase_add_test(tc_core, rsa_key_2048);
+ tcase_add_test(tc_core, rsa_key_4096);
+ tcase_add_test(tc_core, rsa_key_8192);
+
+ tcase_add_test(tc_core, rsa_pss_key_2048);
+ tcase_add_test(tc_core, rsa_pss_key_2048_384);
+ tcase_add_test(tc_core, rsa_pss_key_2048_512);
+
+ tcase_add_test(tc_core, oct_key_256);
+ tcase_add_test(tc_core, oct_key_384);
+ tcase_add_test(tc_core, oct_key_512);
+
+ suite_add_tcase(s, tc_core);
+
+ /* We run this here so we get some usage out of it */
+ tc_core = tcase_create("Utility");
+#ifdef JWT_CONSTRUCTOR
+ tcase_add_test(tc_core, test_jwt_crypto_ops);
+#endif
+ tcase_add_test(tc_core, test_alloc_funcs);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int main(void)
+{
+ JWT_TEST_MAIN("OpenSSL / GnuTLS Cross Testing");
+}
diff --git a/tests/jwt_grant.c b/tests/jwt_grant.c
deleted file mode 100644
index e8797262..00000000
--- a/tests/jwt_grant.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-START_TEST(test_jwt_grant_add)
-{
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", "test");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- /* No duplicates */
- jwt_set_ADD_STR(&jval, "iss", "other");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
-
- /* No duplicates for int */
- jwt_set_ADD_INT(&jval, "iat", (long)time(NULL));
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", (long)time(NULL));
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
-}
-END_TEST
-
-START_TEST(test_jwt_grant_get)
-{
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- const char *val;
- const char testval[] = "testing";
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", testval);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "iss");
- ret = jwt_grant_get(jwt, &jval);
- val = jval.str_val;
- ck_assert_ptr_nonnull(val);
- ck_assert_str_eq(val, testval);
-}
-END_TEST
-
-START_TEST(test_jwt_grant_add_int)
-{
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_INT(&jval, "int", 1);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_INT(&jval, "int");
- ret = jwt_grant_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_int_eq(jval.int_val, 1);
-
- jwt_set_GET_INT(&jval, "not found");
- ret = jwt_grant_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
-}
-END_TEST
-
-START_TEST(test_jwt_grant_add_bool)
-{
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- int val;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_BOOL(&jval, "admin", 1);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_BOOL(&jval, "admin");
- ret = jwt_grant_get(jwt, &jval);
- val = jval.bool_val;
- ck_assert(val);
-
- jwt_set_ADD_BOOL(&jval, "test", 0);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_BOOL(&jval, "test");
- ret = jwt_grant_get(jwt, &jval);
- val = jval.bool_val;
- ck_assert(!val);
-
- jwt_set_GET_BOOL(&jval, "not found");
- ret = jwt_grant_get(jwt, &jval);
- val = jval.bool_val;
- ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
-}
-END_TEST
-
-START_TEST(test_jwt_grant_del)
-{
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- const char *val;
- const char testval[] = "testing";
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", testval);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "other", testval);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- ret = jwt_grant_del(jwt, "iss");
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "iss");
- ret = jwt_grant_get(jwt, &jval);
- val = jval.str_val;
- ck_assert_ptr_null(val);
-
- /* Delete non existent. */
- ret = jwt_grant_del(jwt, "iss");
- ck_assert_int_eq(ret, 0);
-
- /* Delete all grants. */
- ret = jwt_grant_del(jwt, NULL);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "other");
- ret = jwt_grant_get(jwt, &jval);
- val = jval.str_val;
- ck_assert_ptr_null(val);
-}
-END_TEST
-
-START_TEST(test_jwt_grant_invalid)
-{
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- const char *val;
- long valint = 0;
- int valbool = 0;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", NULL);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
-
- jwt_set_ADD_INT(&jval, "", (long)time(NULL));
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
-
- jwt_set_GET_STR(&jval, NULL);
- ret = jwt_grant_get(jwt, &jval);
- val = jval.str_val;
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
- ck_assert_ptr_null(val);
-
- jwt_set_GET_INT(&jval, NULL);
- ret = jwt_grant_get(jwt, &jval);
- valint = jval.int_val;
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
- ck_assert(valint == 0);
-
- jwt_set_GET_BOOL(&jval, NULL);
- ret = jwt_grant_get(jwt, &jval);
- valbool = jval.bool_val;
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
- ck_assert(valbool == 0);
-}
-END_TEST
-
-START_TEST(test_jwt_grants_json)
-{
- char *json = "{\"id\":\"FVvGYTr3FhiURCFebsBOpBqTbzHdX/DvImiA2yheXr8=\","
- "\"iss\":\"localhost\",\"other\":[\"foo\",\"bar\"],"
- "\"ref\":\"385d6518-fb73-45fc-b649-0527d8576130\","
- "\"scopes\":\"storage\",\"sub\":\"user0\"}";
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- const char *val;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_JSON(&jval, NULL, json);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "ref");
- ret = jwt_grant_get(jwt, &jval);
- val = jval.str_val;
- ck_assert_ptr_nonnull(val);
- ck_assert_str_eq(val, "385d6518-fb73-45fc-b649-0527d8576130");
-
- jwt_set_GET_JSON(&jval, "other");
- ret = jwt_grant_get(NULL, &jval);
- ck_assert_ptr_null(jval.json_val);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
-
- jwt_set_GET_JSON(&jval, "other");
- ret = jwt_grant_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.json_val);
- ck_assert_str_eq(jval.json_val, "[\"foo\",\"bar\"]");
-
- free(jval.json_val);
-
- jwt_set_GET_JSON(&jval, "other");
- ret = jwt_grant_get(jwt, NULL);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
-
- free(jval.json_val);
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_grant");
-
- tcase_add_loop_test(tc_core, test_jwt_grant_add, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_grant_add_int, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_grant_add_bool, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_grant_get, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_grant_del, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_grant_invalid, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_grants_json, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT Grant");
-}
diff --git a/tests/jwt_header.c b/tests/jwt_header.c
deleted file mode 100644
index b0119652..00000000
--- a/tests/jwt_header.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-START_TEST(test_jwt_header_add)
-{
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", "test");
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- /* No duplicates */
- jwt_set_ADD_STR(&jval, "iss", "other");
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_ne(ret, 0);
-
- /* No duplicates for int */
- jwt_set_ADD_INT(&jval, "iat", (long)time(NULL));
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_ne(ret, 0);
-}
-END_TEST
-
-START_TEST(test_jwt_header_get)
-{
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- const char testval[] = "testing";
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", testval);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "iss");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.str_val);
- ck_assert_str_eq(jval.str_val, testval);
-}
-END_TEST
-
-START_TEST(test_jwt_header_add_int)
-{
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_INT(&jval, "int", 1);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_INT(&jval, "int");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_int_eq(jval.int_val, 1);
-
- jwt_set_GET_STR(&jval, "not found");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
-}
-END_TEST
-
-START_TEST(test_jwt_header_add_bool)
-{
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_BOOL(&jval, "admin", 1);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_BOOL(&jval, "admin");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_int_ne(jval.bool_val, 0);
-
- jwt_set_ADD_BOOL(&jval, "test", 0);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_BOOL(&jval, "test");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_int_eq(jval.bool_val, 0);
-
- jwt_set_GET_BOOL(&jval, "not found");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
-}
-END_TEST
-
-START_TEST(test_jwt_header_del)
-{
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- const char testval[] = "testing";
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", testval);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "other", testval);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- ret = jwt_header_del(jwt, "iss");
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "iss");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_NOEXIST);
- ck_assert_ptr_null(jval.str_val);
-
- /* Delete non existent. */
- ret = jwt_header_del(jwt, "iss");
- ck_assert_int_eq(ret, 0);
-
- /* Delete all headers. */
- ret = jwt_header_del(jwt, NULL);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "other");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_ne(ret, 0);
- ck_assert_ptr_null(jval.str_val);
-}
-END_TEST
-
-START_TEST(test_jwt_header_invalid)
-{
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", NULL);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_ne(ret, 0);
-
- jwt_set_ADD_INT(&jval, "", 0);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_ne(ret, 0);
-
- jwt_set_GET_STR(&jval, NULL);
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
- ck_assert_ptr_null(jval.str_val);
-
- jwt_set_GET_INT(&jval, NULL);
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
-
- jwt_set_GET_BOOL(&jval, NULL);
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
-}
-END_TEST
-
-START_TEST(test_jwt_headers_json)
-{
- char *json = "{\"id\":\"FVvGYTr3FhiURCFebsBOpBqTbzHdX/DvImiA2yheXr8=\","
- "\"iss\":\"localhost\",\"other\":[\"foo\",\"bar\"],"
- "\"ref\":\"385d6518-fb73-45fc-b649-0527d8576130\","
- "\"scopes\":\"storage\",\"sub\":\"user0\"}";
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- int ret = 0;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_JSON(&jval, NULL, json);
- ret = jwt_header_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_STR(&jval, "ref");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.str_val);
- ck_assert_str_eq(jval.str_val, "385d6518-fb73-45fc-b649-0527d8576130");
-
- jwt_set_GET_STR(&jval, "other");
- ret = jwt_header_get(NULL, &jval);
- ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
-
- jwt_set_GET_JSON(&jval, "other");
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.json_val);
- ck_assert_str_eq(jval.json_val, "[\"foo\",\"bar\"]");
-
- free(jval.json_val);
-
- jwt_set_GET_JSON(&jval, NULL);
- ret = jwt_header_get(jwt, &jval);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jval.json_val);
- ck_assert_str_eq(jval.json_val, json);
-
- free(jval.json_val);
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_header");
-
- tcase_add_loop_test(tc_core, test_jwt_header_add, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_header_add_int, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_header_add_bool, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_header_get, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_header_del, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_header_invalid, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_headers_json, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT Header");
-}
diff --git a/tests/jwt_hs.c b/tests/jwt_hs.c
new file mode 100644
index 00000000..b961e2f7
--- /dev/null
+++ b/tests/jwt_hs.c
@@ -0,0 +1,112 @@
+/* Public domain, no copyright. Use at your own risk. */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "jwt_tests.h"
+
+static void __verify_token(const char *token, jwt_alg_t alg)
+{
+ jwt_checker_auto_t *checker = NULL;
+ int ret;
+
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
+
+ ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_setkey(checker, alg, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ ret = jwt_checker_verify(checker, token);
+ ck_assert_int_eq(ret, 0);
+}
+
+static void __test_alg(const char *key_file, jwt_alg_t alg, const char *expected)
+{
+ jwt_builder_auto_t *builder = NULL;
+ char *out = NULL;
+ int ret;
+
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
+ ck_assert_int_eq(jwt_builder_error(builder), 0);
+
+ ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
+ ck_assert_int_eq(ret, 0);
+
+ read_json(key_file);
+ ret = jwt_builder_setkey(builder, alg, g_item);
+ ck_assert_int_eq(ret, 0);
+
+ out = jwt_builder_generate(builder);
+ ck_assert_ptr_nonnull(out);
+ ck_assert_str_eq(out, expected);
+
+ __verify_token(out, alg);
+
+ free(out);
+
+ free_key();
+}
+
+START_TEST(hs256)
+{
+ const char exp[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CM4dD95Nj"
+ "0vSfMGtDas432AUW1HAo7feCiAbt5Yjuds";
+
+ SET_OPS();
+
+ __test_alg("oct_key_256.json", JWT_ALG_HS256, exp);
+}
+END_TEST
+
+START_TEST(hs384)
+{
+ const char exp[] = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.e30.GKapA5V0"
+ "PiRn-pNHK1Vj-E01pYv1Gx0VOkzzgp-SbfWQaOz6q6MiiCyVM0P69idm";
+
+ SET_OPS();
+
+ __test_alg("oct_key_384.json", JWT_ALG_HS384, exp);
+}
+END_TEST
+
+START_TEST(hs512)
+{
+ const char exp[] = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.e30.yeSPkrpAm"
+ "_6UGtg2SpdPUV0tsrhVosfxKLuUIqMRwhEEyg6jAWe4J-qKiPdJZfC1MVeMwk"
+ "zwB_k-o9RDi_gSbA";
+
+ SET_OPS();
+
+ __test_alg("oct_key_512.json", JWT_ALG_HS512, exp);
+}
+END_TEST
+
+static Suite *libjwt_suite(const char *title)
+{
+ Suite *s;
+ TCase *tc_core;
+ int i = ARRAY_SIZE(jwt_test_ops);
+
+ s = suite_create(title);
+
+ tc_core = tcase_create("HS Key Gen/Ver");
+ tcase_add_loop_test(tc_core, hs256, 0, i);
+ tcase_add_loop_test(tc_core, hs384, 0, i);
+ tcase_add_loop_test(tc_core, hs512, 0, i);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int main(void)
+{
+ JWT_TEST_MAIN("LibJWT HMAC Algorithms");
+}
diff --git a/tests/jwt_jwks.c b/tests/jwt_jwks.c
index d8254c5c..d6a8eca6 100644
--- a/tests/jwt_jwks.c
+++ b/tests/jwt_jwks.c
@@ -8,151 +8,47 @@
#include "jwt_tests.h"
-#define JWKS_KEY_TEST(__name) \
-START_TEST(test_jwks_##__name) \
-{ \
- SET_OPS(); \
- __jwks_check(#__name ".json", "pem-files/" \
- #__name ".pem"); \
-} \
-END_TEST
-
-static void __jwks_check(const char *json, const char *pem)
+START_TEST(test_jwks_keyring_load)
{
- JWT_CONFIG_DECLARE(config);
- jwk_set_auto_t *jwk_set = NULL;
- const jwk_item_t *item = NULL;
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- char *out = NULL;
- int ret;
-
- /* Load up the JWKS */
- read_key(json);
- jwk_set = jwks_create(test_data.key);
- free_key();
- ck_assert_ptr_nonnull(jwk_set);
+ const jwk_item_t *item;
+ int i, ret;
- ck_assert(!jwks_error(jwk_set));
+ SET_OPS();
- /* Make sure we have one item */
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
+ read_json("jwks_keyring.json");
- if (jwks_item_pem(item) != NULL) {
- read_key(pem);
- ret = strcmp(jwks_item_pem(item), test_data.key);
- free_key();
- ck_assert_int_eq(ret, 0);
+ for (i = 0; (item = jwks_item_get(g_jwk_set, i)); i++) {
+ jwt_builder_auto_t *builder = NULL;
+ char_auto *out = NULL;
+ jwt_alg_t alg;
- if (jwks_item_alg(item) == JWT_ALG_ES256) {
- ck_assert_str_eq(jwks_item_curve(item), "P-256");
- ck_assert_int_eq(jwks_item_kty(item), JWK_KEY_TYPE_EC);
- ck_assert_int_eq(jwks_item_key_bits(item), 256);
+ if (jwks_item_error(item)) {
+ fprintf(stderr, "Err KID: %s\n",
+ jwks_item_kid(item));
}
- }
+ ck_assert_int_eq(jwks_item_error(item), 0);
- /* Should only be one key in the set */
- item = jwks_item_get(jwk_set, 1);
- ck_assert_ptr_null(item);
+ alg = jwks_item_alg(item);
- /* Now create a token */
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
+ if (alg == JWT_ALG_ES256K)
+ continue;
- if (!jwks_item_is_private(item))
- return;
+ if (alg == JWT_ALG_NONE || !jwks_item_is_private(item))
+ continue;
- if (jwks_item_alg(item) == JWT_ALG_NONE &&
- jwks_item_kty(item) == JWK_KEY_TYPE_RSA) {
- /* "alg" is optional, and it's missing in a few keys */
- config.alg = JWT_ALG_RS256;
- } else {
- config.alg = jwks_item_alg(item);
- }
+ builder = jwt_builder_new();
+ ck_assert_ptr_nonnull(builder);
- /* Use our JWK */
- config.jw_key = item;
- jwt = jwt_create(&config);
- ck_assert_ptr_nonnull(jwt);
-
- /* Add some grants */
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- /* Encode it */
- out = jwt_encode_str(jwt);
- /* We allow this for now. */
- if (jwt_error(jwt)) {
- if (!strcmp(jwt_error_msg(jwt), "ES256K Not Supported on GnuTLS"))
- return;
- if (!strcmp(jwt_error_msg(jwt), "ED448 is not yet implemented in GnuTLS"))
- return;
- }
-
- ck_assert_int_eq(jwt_error(jwt), 0);
- ck_assert_ptr_nonnull(out);
-
- /* Verify it using our JWK */
- __verify_jwk(out, item);
-
- free(out);
-}
-
-JWKS_KEY_TEST(ec_key_prime256v1);
-JWKS_KEY_TEST(ec_key_prime256v1_pub);
-JWKS_KEY_TEST(ec_key_secp256k1);
-JWKS_KEY_TEST(ec_key_secp256k1_pub);
-JWKS_KEY_TEST(ec_key_secp384r1);
-JWKS_KEY_TEST(ec_key_secp384r1_pub);
-JWKS_KEY_TEST(ec_key_secp521r1);
-JWKS_KEY_TEST(ec_key_secp521r1_pub);
-
-JWKS_KEY_TEST(eddsa_key_ed25519);
-JWKS_KEY_TEST(eddsa_key_ed25519_pub);
-JWKS_KEY_TEST(eddsa_key_ed448);
-JWKS_KEY_TEST(eddsa_key_ed448_pub);
-
-JWKS_KEY_TEST(rsa_key_2048);
-JWKS_KEY_TEST(rsa_key_2048_pub);
-JWKS_KEY_TEST(rsa_key_4096);
-JWKS_KEY_TEST(rsa_key_4096_pub);
-JWKS_KEY_TEST(rsa_key_8192);
-JWKS_KEY_TEST(rsa_key_8192_pub);
-
-JWKS_KEY_TEST(rsa_key_i37_pub);
-
-JWKS_KEY_TEST(rsa_pss_key_2048);
-JWKS_KEY_TEST(rsa_pss_key_2048_pub);
-
-JWKS_KEY_TEST(oct_key_256);
-JWKS_KEY_TEST(oct_key_384);
-JWKS_KEY_TEST(oct_key_512);
-
-START_TEST(test_jwks_keyring_load)
-{
- const jwk_item_t *item;
- int i;
-
- SET_OPS();
-
- read_json("jwks_keyring.json");
+ ret = jwt_builder_setkey(builder, alg, item);
+ ck_assert_int_eq(ret, 0);
- for (i = 0; (item = jwks_item_get(g_jwk_set, i)); i++)
- ck_assert(!jwks_item_error(item));
+ out = jwt_builder_generate(builder);
+ if (out == NULL) {
+ fprintf(stderr, "Gen KID(%d/%d): %s\n", i, alg,
+ jwt_builder_error_msg(builder));
+ }
+ ck_assert_ptr_nonnull(out);
+ }
ck_assert_int_eq(i, 22);
@@ -215,7 +111,7 @@ START_TEST(test_jwks_key_op_bad_type)
SET_OPS();
- read_key("jwks_test-2.json");
+ read_json("jwks_test-2.json");
item = jwks_item_get(g_jwk_set, 0);
ck_assert_ptr_nonnull(item);
@@ -246,42 +142,11 @@ static Suite *libjwt_suite(const char *title)
tc_core = tcase_create("jwt_jwks");
- /* Testing individual keys */
- tcase_add_loop_test(tc_core, test_jwks_ec_key_prime256v1, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_key_prime256v1_pub, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_key_secp256k1, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_key_secp256k1_pub, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_key_secp384r1, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_key_secp384r1_pub, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_key_secp521r1, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_key_secp521r1_pub, 0, i);
-
- tcase_add_loop_test(tc_core, test_jwks_eddsa_key_ed25519, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_eddsa_key_ed25519_pub, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_eddsa_key_ed448, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_eddsa_key_ed448_pub, 0, i);
-
- tcase_add_loop_test(tc_core, test_jwks_rsa_key_2048, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_key_2048_pub, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_key_4096, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_key_4096_pub, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_key_8192, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_key_8192_pub, 0, i);
-
- tcase_add_loop_test(tc_core, test_jwks_rsa_key_i37_pub, 0, i);
-
- tcase_add_loop_test(tc_core, test_jwks_rsa_pss_key_2048, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_pss_key_2048_pub, 0, i);
-
- tcase_add_loop_test(tc_core, test_jwks_oct_key_256, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_oct_key_384, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_oct_key_512, 0, i);
-
- /* Load a whole keyring of all of the above. */
+ /* Load a whole keyring */
tcase_add_loop_test(tc_core, test_jwks_keyring_load, 0, i);
tcase_add_loop_test(tc_core, test_jwks_keyring_all_bad, 0, i);
- /* Some coverage attempts. */
+ /* Some coverage attempts */
tcase_add_loop_test(tc_core, test_jwks_key_op_all_types, 0, i);
tcase_add_loop_test(tc_core, test_jwks_key_op_bad_type, 0, i);
diff --git a/tests/jwt_jwks_ec.c b/tests/jwt_jwks_ec.c
deleted file mode 100644
index 9ffa1576..00000000
--- a/tests/jwt_jwks_ec.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-START_TEST(test_jwks_ec_pub_missing)
-{
- const char *json = "{\"kty\":\"EC\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Missing or invalid type for one of crv, x, or y for pub key";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_ec_pub_bad_type)
-{
- const char *json = "{\"kty\":\"EC\",\"crv\":\"prime6v1\",\"x\":\"sd+#(@#($(ada\",\"y\":1}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Missing or invalid type for one of crv, x, or y for pub key";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_ec_pub_bad64)
-{
- const char *json = "{\"kty\":\"EC\",\"crv\":\"prime6v1\",\"x\":\"\",\"y\":\"asaad\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Error generating pub key from components";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_ec_pub_bad_points)
-{
- const char *json = "{\"kty\":\"EC\",\"crv\":\"prime256v1\",\"x\":\"YmFkdmFsdWUK\",\"y\":\"YmFkdmFsdWUK\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Error generating pub key from components";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_jwks_ec");
-
- /* EC specific error path tests */
- tcase_add_loop_test(tc_core, test_jwks_ec_pub_missing, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_pub_bad64, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_pub_bad_type, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_ec_pub_bad_points, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT JWKS Error Path Testing EC");
-}
diff --git a/tests/jwt_jwks_rsa.c b/tests/jwt_jwks_rsa.c
deleted file mode 100644
index 72c3e4e0..00000000
--- a/tests/jwt_jwks_rsa.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-START_TEST(test_jwks_rsa_pub_missing)
-{
- const char *json = "{\"kty\":\"RSA\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Missing required RSA component: n or e";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_rsa_pub_bad_type)
-{
- const char *json = "{\"kty\":\"RSA\",\"n\":\"YmFkdmFsdWUK\",\"e\":1}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Error decoding pub components";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_rsa_pub_bad64)
-{
- const char *json = "{\"kty\":\"RSA\",\"n\":\"\",\"e\":\"asaadaaaaaa\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Error decoding pub components";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_rsa_pub_binary64)
-{
- const char *json = "{\"kty\":\"RSA\",\"n\":"
- "\"2fyxRFHaYP2a4pbdTK/s9x4YWV7qAWwJMXMkbRmy51w\","
- "\"e\":\"2fyxRFHaYP2a4pbdTK/s9x4YWV7qAWwJMXMkbRmy51w\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_ptr_nonnull(jwks_item_pem(item));
- ck_assert_int_eq(jwks_item_error(item), 0);
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_rsa_priv_missing)
-{
- const char *json = "{\"kty\":\"RSA\",\"n\":\"YmFkdmFsdWUK\","
- "\"e\":\"YmFkdmFsdWUK\",\"d\":\"YmFkdmFsdWUK\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Some priv key components exist, but some are missing";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-START_TEST(test_jwks_rsa_priv_bad64)
-{
- const char *json = "{\"kty\":\"RSA\",\"n\":\"YmFkdmFsdWUK\","
- "\"e\":\"YmFkdmFsdWUK\",\"d\":"
- "\"2fyxRFHaYP2a4pbdTK/s9x4YWV7qAWwJMXMkbRmy51w\","
- "\"p\":\"\",\"q\":\"=\",\"dp\":\"\",\"dq\":\"\",\"qi\":\"\"}";
- jwk_set_t *jwk_set = NULL;
- const jwk_item_t *item;
- const char exp[] = "Error decoding priv components";
-
- SET_OPS();
-
- jwk_set = jwks_create(json);
-
- ck_assert_ptr_nonnull(jwk_set);
- ck_assert(!jwks_error(jwk_set));
-
- item = jwks_item_get(jwk_set, 0);
- ck_assert_ptr_nonnull(item);
- ck_assert_int_ne(jwks_item_error(item), 0);
-
- ck_assert_str_eq(exp, jwks_item_error_msg(item));
-
- jwks_free(jwk_set);
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_jwks_rsa");
-
- /* RSA specific error path tests */
- tcase_add_loop_test(tc_core, test_jwks_rsa_pub_missing, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_pub_bad64, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_pub_bad_type, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_pub_binary64, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_priv_missing, 0, i);
- tcase_add_loop_test(tc_core, test_jwks_rsa_priv_bad64, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT JWKS Error Path Testing RSA");
-}
diff --git a/tests/jwt_new.c b/tests/jwt_new.c
deleted file mode 100644
index 17c6031f..00000000
--- a/tests/jwt_new.c
+++ /dev/null
@@ -1,603 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-#ifdef JWT_CONSTRUCTOR
-START_TEST(test_jwt_crypto_ops)
-{
- const char *msg = getenv("JWT_CRYPTO");
-
- ck_assert_str_eq(msg, "openssl");
-}
-END_TEST
-#endif
-
-/* The simplest of tests */
-START_TEST(test_jwt_new)
-{
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- EMPTY_JWT(jwt);
-}
-END_TEST
-
-START_TEST(test_jwt_dup)
-{
- jwt_auto_t *jwt = NULL, *new = NULL;
- jwt_value_t jval;
- int ret = 0;
- const char *val = NULL;
- time_t now;
- long valint;
-
- SET_OPS();
-
- new = jwt_dup(NULL);
- ck_assert_ptr_null(new);
-
- EMPTY_JWT(jwt);
-
- jwt_set_ADD_STR(&jval, "iss", "test");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- new = jwt_dup(jwt);
- ck_assert_ptr_nonnull(new);
-
- jwt_set_GET_STR(&jval, "iss");
- ret = jwt_grant_get(new, &jval);
- val = jval.str_val;
- ck_assert_ptr_nonnull(val);
- ck_assert_str_eq(val, "test");
-
- ck_assert_int_eq(jwt_get_alg(new), JWT_ALG_NONE);
-
- now = time(NULL);
- jwt_set_ADD_INT(&jval, "iat", (long)now);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_GET_INT(&jval, "iat");
- ret = jwt_grant_get(jwt, &jval);
- valint = jval.int_val;
- ck_assert(((long)now) == valint);
-}
-END_TEST
-
-START_TEST(test_jwt_dup_signed)
-{
- jwt_test_auto_t *jwt = NULL;
- jwt_auto_t *new = NULL;
- jwt_value_t jval;
- int ret = 0;
- const char *val = NULL;
-
- SET_OPS();
-
- CREATE_JWT(jwt, "oct_key_256.json", JWT_ALG_HS256);
-
- jwt_set_ADD_STR(&jval, "iss", "test");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- new = jwt_dup(jwt);
- ck_assert_ptr_nonnull(new);
-
- jwt_set_GET_STR(&jval, "iss");
- ret = jwt_grant_get(new, &jval);
- val = jval.str_val;
- ck_assert_ptr_nonnull(val);
- ck_assert_str_eq(val, "test");
-
- ck_assert_int_eq(jwt_get_alg(new), JWT_ALG_HS256);
-}
-END_TEST
-
-START_TEST(test_jwt_verify)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJmaWxlcy5jeXBo"
- "cmUuY29tIiwic3ViIjoidXNlcjAifQ.";
- jwt_alg_t alg;
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- alg = jwt_get_alg(jwt);
- ck_assert_int_eq(alg, JWT_ALG_NONE);
-}
-END_TEST
-
-static int test_jwt_verify_alg_none_cb(const jwt_t *jwt, jwt_config_t *config)
-{
- jwt_alg_t alg = jwt_get_alg(jwt);
- jwt_alg_t *test = config->ctx;
-
- ck_assert_ptr_nonnull(test);
- ck_assert_ptr_null(config->jw_key);
-
- /* Passed to us. */
- ck_assert_int_eq(*test, JWT_ALG_HS256);
-
- *test = JWT_ALG_NONE;
-
- return (alg == JWT_ALG_NONE) ? 0 : -1;
-}
-
-START_TEST(test_jwt_verify_wcb_alg_none)
-{
- const char token[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJmaWxlcy5jeXBo"
- "cmUuY29tIiwic3ViIjoidXNlcjAifQ.";
- JWT_CONFIG_DECLARE(config);
- jwt_alg_t alg = JWT_ALG_HS256;
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- config.ctx = &alg;
-
- jwt = jwt_verify_wcb(token, &config, test_jwt_verify_alg_none_cb);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- ck_assert_int_eq(alg, JWT_ALG_NONE);
-
- alg = jwt_get_alg(jwt);
- ck_assert_int_eq(alg, JWT_ALG_NONE);
-}
-
-START_TEST(test_jwt_verify_invalid_final_dot)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9."
- "eyJpc3MiOiJmaWxlcy5jeXBocmUuY29tIiwic"
- "3ViIjoidXNlcjAifQ";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_invalid_alg)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIQUhBSCJ9."
- "eyJpc3MiOiJmaWxlcy5jeXBocmUuY29tIiwic"
- "3ViIjoidXNlcjAifQ.";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-/* { "typ": "JWT", "alg": "none" } . . */
-START_TEST(test_jwt_verify_dot_dot)
-{
- JWT_CONFIG_DECLARE(config);
- char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0..";
- jwt_auto_t *jwt = NULL;
- int ret;
-
- SET_OPS();
-
- /* Two dots */
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-
- /* One dot */
- ret = strlen(token);
- token[ret - 1] = '\0';
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-
- /* No dot */
- ret = strlen(token);
- token[ret - 1] = '\0';
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-
-/* { "typ": "JWT", "alg": "none" } . {} . */
-START_TEST(test_jwt_verify_empty_body)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.e30.";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-}
-
-/* { "typ": "JWT", "alg": "HS256" } . { "test": 1 } . */
-START_TEST(test_jwt_verify_nokey_alg_hs256)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJBTEwiLCJhbGciOiJOT05FIn0.eyJ0ZXN0IjoxfQ.";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-/* { "typ": "ALL", "alg": "none" } . { "test": 1 } */
-START_TEST(test_jwt_verify_ignore_typ)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJBTEwiLCJhbGciOiJub25lIn0.eyJ0ZXN0IjoxfQ.";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_invalid_head)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "yJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9."
- "eyJpc3MiOiJmaWxlcy5jeXBocmUuY29tIiwic"
- "3ViIjoidXNlcjAifQ.";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_alg_none_with_key)
-{
- const char token[] = "eyJhbGciOiJub25lIn0."
- "eyJpc3MiOiJmaWxlcy5jeXBocmUuY29tIiwic"
- "3ViIjoidXNlcjAifQ.";
- JWT_CONFIG_DECLARE(config);
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_256.json");
- ck_assert_ptr_nonnull(g_item);
- config.jw_key = g_item;
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-
- free_key();
-}
-END_TEST
-
-START_TEST(test_jwt_verify_invalid_body)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9."
- "eyJpc3MiOiJmaWxlcy5jeBocmUuY29tIiwic"
- "3ViIjoidXNlcjAifQ.";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_hs256)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQi"
- "OjE3MzYxMTM5OTIsInN1YiI6InVzZXIwIn0.74dWICs1ezbHNBrPSmop3o"
- "zc4GQ8YdZISXCxZX8LAjk";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_256.json");
- config.jw_key = g_item;
- config.alg = JWT_ALG_HS256;
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- free_key();
-}
-END_TEST
-
-/* Fron issue #201. Adding tests for alg checks. */
-/* { "typ": "JWT", "alg": "HS256" } . { ... } . sig */
-START_TEST(test_jwt_verify_hs256_no_key_alg)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3Mi"
- "OiJmaWxlcy5jeXBocmUuY29tIiwic3ViIjoidXNlcjAif"
- "Q.dLFbrHVViu1e3VD1yeCd9aaLNed-bfXhSsF0Gh56fBg";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_hs256_issue_1)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIi"
- "OiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE"
- "5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3Ro"
- "ZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOT"
- "MzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAs"
- "ImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.t"
- "JoAl_pvq95hK7GKqsp5TU462pLTbmSYZc1fAHzcqWM";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_256_issue1.json");
-
- config.jw_key = g_item;
- config.alg = JWT_ALG_HS256;
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- free_key();
-}
-END_TEST
-
-START_TEST(test_jwt_verify_hs256_issue_2)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQi"
- "OjE3MzYxMTQyOTIsInN1YiI6InVzZXIwIn0.CjttUxGvPjKIh1Cz8RAOoB"
- "9i6xHKexJAsWzKwd6C7uM";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_256_issue2.json");
- config.jw_key = g_item;
- config.alg = JWT_ALG_HS256;
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- free_key();
-}
-END_TEST
-
-START_TEST(test_jwt_verify_hs384)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJpYXQi"
- "OjE3MzYxMTQxMTAsInN1YiI6InVzZXIwIn0.9bqi8aIAAS1L8uaOCFum-z"
- "oHC96tJOuDHW9GzE7uUQbXPyg6FmXQ9LS92D1aQi82";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_384.json");
- config.jw_key = g_item;
- config.alg = JWT_ALG_HS384;
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- free_key();
-}
-END_TEST
-
-START_TEST(test_jwt_verify_hs512)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQi"
- "OjE3MzYxMTQxNzAsInN1YiI6InVzZXIwIn0.WSD1YRRDD58uG-EeNGVhZt"
- "kDHgi_EVbJBHvCt72mE7oVFJ9qU8WCx5ACMbyIuWdgvOozTUVCSHL6RtDo"
- "JMq4JQ";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_512.json");
- config.jw_key = g_item;
- config.alg = JWT_ALG_HS512;
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- free_key();
-}
-END_TEST
-
-static int test_jwt_verify_wcb_hs512_kp(const jwt_t *jwt, jwt_config_t *config)
-{
- if (jwt_get_alg(jwt) != JWT_ALG_HS512)
- return EINVAL;
-
- config->jw_key = g_item;
-
- return 0;
-}
-
-START_TEST(test_jwt_verify_wcb_hs512)
-{
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3Mi"
- "OiJmaWxlcy5jeXBocmUuY29tIiwic3ViIjoidXNlcjAif"
- "Q.u-4XQB1xlYV8SgAnKBof8fOWOtfyNtc1ytTlc_vHo0U"
- "lh5uGT238te6kSacnVzBbC6qwzVMT1806oa1Y8_8EOg";
- JWT_CONFIG_DECLARE(config);
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_512_wcb.json");
-
- config.alg = JWT_ALG_HS512;
-
- jwt = jwt_verify_wcb(token, &config, &test_jwt_verify_wcb_hs512_kp);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- ck_assert_ptr_eq(config.jw_key, g_item);
-
- free_key();
-}
-END_TEST
-
-START_TEST(test_jwt_verify_wcb_invalid)
-{
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9."
- "eyJpc3MiOiJmaWxlcy5jeXBocmUuY29tIiwic"
- "3ViIjoidXNlcjAifQ.xqea3OVgPEMxsCgyikr"
- "R3gGv4H2yqMyXMm7xhOlQWpA-NpT6n2a1d7TD"
- "GgU6LOe4";
- JWT_CONFIG_DECLARE(config);
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- config.alg = JWT_ALG_HS512;
-
- jwt = jwt_verify_wcb(token, &config, &test_jwt_verify_wcb_hs512_kp);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
- ck_assert_str_eq(jwt_error_msg(jwt), "User callback returned error");
-}
-END_TEST
-
-START_TEST(test_jwt_verify_wcb_invalid_body)
-{
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9."
- "eyJpc3MiOiJmaWxlcy5jeBocmUuY29tIiwic"
- "3ViIjoidXNlcjAifQ.";
- JWT_CONFIG_DECLARE(config);
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- config.alg = JWT_ALG_HS512;
-
- jwt = jwt_verify_wcb(token, &config,
- &test_jwt_verify_wcb_hs512_kp);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
- ck_assert_str_eq(jwt_error_msg(jwt), "Error parsing body");
-}
-END_TEST
-
-START_TEST(test_jwt_verify_invalid_base64)
-{
- JWT_CONFIG_DECLARE(config);
- const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3Mi"
- "OiJmaWxlcy5jeXBocmUuY29tIiwic3ViIjoidXNlcjAif"
- "Q.dLFbrHVViu1e3VD1yeCd9aaLNed-bfXhSsF0Gh56fBga";
- jwt_auto_t *jwt = NULL;
-
- SET_OPS();
-
- read_key("oct_key_256_invalid_base64.json");
- config.jw_key = g_item;
- config.alg = JWT_ALG_HS256;
-
- jwt = jwt_verify(token, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_new");
-
-#ifdef JWT_CONSTRUCTOR
- tcase_add_test(tc_core, test_jwt_crypto_ops);
-#endif
-
- tcase_add_loop_test(tc_core, test_jwt_new, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_dup, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_dup_signed, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_wcb_alg_none, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_alg, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_ignore_typ, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_dot_dot, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_empty_body, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_nokey_alg_hs256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_head, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_alg_none_with_key, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_body, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_wcb_invalid_body, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_final_dot, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_hs256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_hs256_no_key_alg, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_hs384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_hs512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_wcb_hs512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_wcb_invalid, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_base64, 0, i);
-
- tcase_add_loop_test(tc_core, test_jwt_verify_hs256_issue_1, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_hs256_issue_2, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT New");
-}
diff --git a/tests/jwt_rsa.c b/tests/jwt_rsa.c
index 3a8ea77f..72c3e4e0 100644
--- a/tests/jwt_rsa.c
+++ b/tests/jwt_rsa.c
@@ -8,217 +8,151 @@
#include "jwt_tests.h"
-static const char jwt_rs256_2048[] = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.ey"
- "JpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZi"
- "I6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.RlJPQst_lp"
- "MJUsbnzlT2Mf3xzlHyUlVaQM_PJ1_vpBf1gHkhv-0hm3pa1_HRvpqg5UdDF3iOMLT0GU"
- "j3W8JveaSvXKFeZdRpQGqmC7MZ7NzaYtyaDT7asniIVDf0JomD8Cfq8IdOn2ZREpbuJ6"
- "moPwwvJ2zwL3vY-7w5A7ZQ3fxUedPuzn9n6tbEnuXcbDMyWQjen5poYmmvoIrDbzK0Zb"
- "KbAJ5VrJwME_fZnPHS4c3b8rZGdBJCPI8oT2On6a9LrVqY3riqqHeiSqewfjDsox4tL2"
- "G5KUpqK0oJmnZPGTnNY774PGabpcPBNbfMJqi8o8r0a7pa7sy6B59P7slUdw";
-
-static const char jwt_rs384_4096[] = "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.ey"
- "JpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZi"
- "I6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.E9e6Chv39H"
- "FQqhfUFcCxUzyS6yHQvBex_OaQNIPqeoPR_FDquiLhQUJj45IGd8_aVT8DvfzTFSHOP1"
- "cP_UbzCYtZ8VC0o-idxyjTnlnqMJy75xNBzPUy6OSpTeX9yVQCtIkT6kIom4j35ABibk"
- "_MdCVqnWG2fijDEeTlLD7uDRcCTGckqQhVOI3t4iIytiUVPnboFiaPLfei_mPcJ6CiOI"
- "QYF4VOWlDllgUFrQ0M0nKm4Pq6bVaBIMzF0hJrPn_7GCV3XmVLthcObljfydaNm_CcIY"
- "g7y_8OT_8yAvDlbKBe5jVeq-7_lLCinarkGUZ5ryA2lbC6yPBgtaAU3g6XxP60n6To7z"
- "akV_5dgcPJFDlTkoBI6pPH3Zf50UYsf-wR4D2J3fP4rcYco4HGtxZ89tfoNYCB8z5-GA"
- "ImSJRbVSsdadwSKKgldlG9XR13Cq-Ox8Hc7qCd1tTC-NeY31XMuWxd9981bQMeGhBkyJ"
- "fFnIksh8xyyO0uOPvgmchOtG8bSImfZZaeBI6TcPJ89Oo3iD6NmPdO5AUqv6NB7Y46zH"
- "GUXCeTuumVk7I_PJ9laICW4-cx1zHDvPY3TphVVTudSqWdUDMjwhrRI23569DByMJE9J"
- "XpTg7HV_17EPTDWExc6TQVkmmY4QbS0pVbKyJTwwKmnu2F9o2fl1N0NOw1SOM";
-
-static const char jwt_rs512_8192[] = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey"
- "JpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZi"
- "I6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.F3_fF6RGJy"
- "B_apyq_ljxLP7luYC78wT23pPKAyRSMiDi0g-7Yfohv5_p0rBOCsT1H-1_rImWiIcsdJ"
- "87oYfQw95G_pHcK56ag7_a1i-jQCV7ZyRAuesDcM1YRealKvdnof08Jw392h685XNK2l"
- "mqvZ436Hz4oCcQimwuKeR0ndAgm38y-_FswOlb3POwHBJcDtDR3UTvCONyqgcCD5hl5J"
- "edjA8GA0Mvlp4JV2-ctsNYaDOMQRw3S8hJOXvKySQsbckEj8pC_bCrcbSR8BUJBrjM5Q"
- "SLslcYGJopyCYAApGsq3t4-uY3Dx-QjWBMgSIgD9BONjv4VXvsfrllWUQmK88qJ4WQFO"
- "L0PUSJy57lZjpjXReafJcJgdrGI-tFHgqkcb1VxmqnnIFRqadgjJ1BkfFvdExJiOgnvN"
- "SEQ16AYy2FlxZeaabqyOjc8IlGi7Z9hYZgImL_qn0REJXgvxNtabA9-A4cEMWVDtYkCn"
- "F_VyYeMOMYKMuoFW5ubLfOhYhDnd_yvkrLzZ76BGXpHtg7cfpnN8dNWp8irwjSByBH4H"
- "lB0F9NFZydNB8wylFsKesNhmkQYcLnchhA4dBZV888NKVfqIBcM-GWXExtmON0SXg_HX"
- "YmbO6zTgQ4tGAk4HglRWJYlfgORdcBBtnlwUHXm5L7_0J8KHoyNUGbA2XU1krVhBN-A7"
- "sxtLof6MZP8c7p65Oc6DH8FulpmnBt8yVID2GnXPfcLs-RgM8QnlSGbNhn9WT2kmBTIV"
- "eniVfp_IJ40Kd4SROGa_XbXMTufympqyYSSxtqHblGgtolVGdpN05FDvInG0J0dojYxT"
- "_puZ-fvBAMXRPeoC_t_1ScfER4CjsUedbReQLZmE-9nJKhCZKqiba5qCbq8riZYiROGJ"
- "rtVryTywLzw7XX4D-s9oJsEk6ELSRI-buXuCqyCmbdRpFz-i2-VPmNQIalk_0Pq_dOZN"
- "y0GCvcezkhx1quGKPDmFskJnvKZmC70er0DvOQl1A909kFivxIXfTzlu8jUJt8PPi0gU"
- "-nnOGSYxC8tD16vwHvAP3KPYvUzmC2N0r6_yM2_Y-JH5Vypeecbuh66cx18Bqk1nQYfg"
- "BLjuJwQSIKRNNBLtgU7mcyI0Lj4-TWbE-22dYYvKcPMxSmfwAmJUm7ZFUAq_Ok-46AmV"
- "RYg-h7bZZlfutOiWuoBrmnqQ6dEDGjXiEgWhtAx5HG3qn1_vmA3JQxJAWEfuhHa3IWac"
- "MDRrJehImeyDE0H0rpOsxSXOjnDqiFBsf9d0-zJNFvo9tWlK_-d-N40BIy5eZm37FKG7"
- "g2rFmXtuicUs6jiwu0_tHSi1fPKO7YN2ezQc9HAoBvvrur1z_XGbDSmFTQNTv0Cg";
-
-static const char jwt_rs256_invalid[] = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
- ".eyJpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLmN5cGhyZS5jb20iLCJyZWYiOiJ"
- "YWFhYLVlZWVktWlpaWi1BQUFBLUNDQ0MiLCJzdWIiOiJ1c2VyMCJ9.IAmCornholio";
-
-START_TEST(test_jwt_encode_rs256)
+START_TEST(test_jwks_rsa_pub_missing)
{
- SET_OPS();
- __compare_alg_key("rsa_key_2048.json", jwt_rs256_2048, JWT_ALG_RS256);
-}
-END_TEST
+ const char *json = "{\"kty\":\"RSA\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Missing required RSA component: n or e";
-START_TEST(test_jwt_verify_rs256)
-{
SET_OPS();
- __verify_alg_key("rsa_key_2048_pub.json", jwt_rs256_2048, JWT_ALG_RS256);
+
+ jwk_set = jwks_create(json);
+
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
+
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
+
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
+
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_validate_rs256)
+START_TEST(test_jwks_rsa_pub_bad_type)
{
- jwt_t *jwt = NULL;
- jwt_valid_t *jwt_valid = NULL;
- int ret = 0;
+ const char *json = "{\"kty\":\"RSA\",\"n\":\"YmFkdmFsdWUK\",\"e\":1}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Error decoding pub components";
SET_OPS();
- t_config.alg = JWT_ALG_RS256;
-
- read_key("rsa_key_2048_pub.json");
- jwt = jwt_verify(jwt_rs256_2048, &t_config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
+ jwk_set = jwks_create(json);
- jwt_valid_new(&jwt_valid, JWT_ALG_RS256);
- ck_assert_ptr_nonnull(jwt_valid);
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
- ret = jwt_valid_add_grant(jwt_valid, "iss", "files.maclara-llc.com");
- ck_assert_int_eq(ret, 0);
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
- ret = jwt_valid_add_grant_int(jwt_valid, "iat", TS_CONST);
- ck_assert_int_eq(ret, 0);
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
- ck_assert_int_eq(JWT_VALIDATION_SUCCESS, jwt_validate(jwt, jwt_valid));
-
- jwt_valid_free(jwt_valid);
- jwt_free(jwt);
- free_key();
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_encode_rs384)
+START_TEST(test_jwks_rsa_pub_bad64)
{
- SET_OPS();
- __compare_alg_key("rsa_key_4096.json", jwt_rs384_4096, JWT_ALG_RS384);
-}
-END_TEST
+ const char *json = "{\"kty\":\"RSA\",\"n\":\"\",\"e\":\"asaadaaaaaa\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Error decoding pub components";
-START_TEST(test_jwt_verify_rs384)
-{
SET_OPS();
- __verify_alg_key("rsa_key_4096_pub.json", jwt_rs384_4096, JWT_ALG_RS384);
-}
-END_TEST
-START_TEST(test_jwt_encode_rs512)
-{
- SET_OPS();
- __compare_alg_key("rsa_key_8192.json", jwt_rs512_8192, JWT_ALG_RS512);
-}
-END_TEST
+ jwk_set = jwks_create(json);
-START_TEST(test_jwt_verify_rs512)
-{
- SET_OPS();
- __verify_alg_key("rsa_key_8192_pub.json", jwt_rs512_8192, JWT_ALG_RS512);
-}
-END_TEST
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
-static const char jwt_rsa_i37[] = "eyJraWQiOiJkWUoxTDVnbWd0eDlWVU9xbVpyd2F6cW"
- "NhK3B5c1lHNUl3N3RSUXB6a3Z3PSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJhMDQyZj"
- "Y4My0xODNiLTQ1ZWUtOTZiYy1lNDdlYjhiMzc2MTYiLCJ0b2tlbl91c2UiOiJhY2Nlc3"
- "MiLCJzY29wZSI6ImF3cy5jb2duaXRvLnNpZ25pbi51c2VyLmFkbWluIiwiaXNzIjoiaH"
- "R0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tXC91cy1lYX"
- "N0LTFfUWJvMXlMZ0ZIIiwiZXhwIjoxNDg1ODgyNDg5LCJpYXQiOjE0ODU4Nzg4ODksIm"
- "p0aSI6Ijg1MTBlMGVkLWU3N2UtNDJmZS1hMmI2LTgyMjAzMDcxZWQyOCIsImNsaWVudF"
- "9pZCI6IjdicTVhanV0czM1anVmamVnMGYwcmhzNnRpIiwidXNlcm5hbWUiOiJhZG1pbj"
- "MifQ.IZqzZEuwKCVT0acHk3p5DnzPSNxg1tLISt8wZCMAHJAnLSdtbtVibrCTZkTLP5z"
- "PD16MgzgsID_CFF2wZXPGBihhyihu1B5W8GimY4eQOKrt4qiLJgK-D8tG6MSZ2K_9DC3"
- "RwhMjrNL4lpu2YoSOgugRdKpJWy4zadtHKptFkKrkI8qjnDoDSkF0kt4I6S1xOcEPuVh"
- "EOrGsfKr5Bm1N3wX9OVQhcTiVugKrpU8x0Mv1AJYdaxKASOQ6fFlNquwfohgLDwy3By3"
- "xU6RoY6ZWhKm5dcGW7H9gqmr9X4aBmHDmYG5KQtodwf0LOYtprPAXCs9X7Ja-7ddJvko"
- "8mDObTA";
-
-START_TEST(test_jwt_verify_rsa_i37)
-{
- SET_OPS();
- __verify_alg_key("rsa_key_i37_pub.json", jwt_rsa_i37, JWT_ALG_RS256);
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
+
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
+
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_encode_rsa_with_ec)
+START_TEST(test_jwks_rsa_pub_binary64)
{
- JWT_CONFIG_DECLARE(config);
- jwt_test_auto_t *jwt = NULL;
+ const char *json = "{\"kty\":\"RSA\",\"n\":"
+ "\"2fyxRFHaYP2a4pbdTK/s9x4YWV7qAWwJMXMkbRmy51w\","
+ "\"e\":\"2fyxRFHaYP2a4pbdTK/s9x4YWV7qAWwJMXMkbRmy51w\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
SET_OPS();
- read_key("ec_key_secp384r1.json");
- config.alg = JWT_ALG_RS384;
- config.jw_key = g_item;
- jwt = jwt_create(&config);
- ck_assert_int_ne(jwt_error(jwt), 0);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_str_eq(jwt_error_msg(jwt),
- "Config alg does not match key alg");
+ jwk_set = jwks_create(json);
+
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
+
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_ptr_nonnull(jwks_item_pem(item));
+ ck_assert_int_eq(jwks_item_error(item), 0);
+
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_encode_rsa_1024)
+START_TEST(test_jwks_rsa_priv_missing)
{
- jwt_test_auto_t *jwt = NULL;
- jwt_value_t jval;
- char *out;
- int ret = 0;
+ const char *json = "{\"kty\":\"RSA\",\"n\":\"YmFkdmFsdWUK\","
+ "\"e\":\"YmFkdmFsdWUK\",\"d\":\"YmFkdmFsdWUK\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Some priv key components exist, but some are missing";
SET_OPS();
- CREATE_JWT(jwt, "rsa_key_1024.json", JWT_ALG_RS256);
+ jwk_set = jwks_create(json);
+
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
- /* Should fail from too few bits in key */
- out = jwt_encode_str(jwt);
- ck_assert_ptr_null(out);
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
+
+ jwks_free(jwk_set);
}
END_TEST
-START_TEST(test_jwt_verify_invalid_token)
+START_TEST(test_jwks_rsa_priv_bad64)
{
- jwt_t *jwt = NULL;
+ const char *json = "{\"kty\":\"RSA\",\"n\":\"YmFkdmFsdWUK\","
+ "\"e\":\"YmFkdmFsdWUK\",\"d\":"
+ "\"2fyxRFHaYP2a4pbdTK/s9x4YWV7qAWwJMXMkbRmy51w\","
+ "\"p\":\"\",\"q\":\"=\",\"dp\":\"\",\"dq\":\"\",\"qi\":\"\"}";
+ jwk_set_t *jwk_set = NULL;
+ const jwk_item_t *item;
+ const char exp[] = "Error decoding priv components";
SET_OPS();
- read_key("rsa_key_2048.json");
- jwt = jwt_verify(jwt_rs256_invalid, &t_config);
- free_key();
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
+ jwk_set = jwks_create(json);
-START_TEST(test_jwt_verify_invalid_cert)
-{
- jwt_t *jwt = NULL;
+ ck_assert_ptr_nonnull(jwk_set);
+ ck_assert(!jwks_error(jwk_set));
- SET_OPS();
+ item = jwks_item_get(jwk_set, 0);
+ ck_assert_ptr_nonnull(item);
+ ck_assert_int_ne(jwks_item_error(item), 0);
+
+ ck_assert_str_eq(exp, jwks_item_error_msg(item));
- read_key("rsa_key_8192_pub.json");
- jwt = jwt_verify(jwt_rs256_2048, &t_config);
- free_key();
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
+ jwks_free(jwk_set);
}
END_TEST
@@ -230,22 +164,17 @@ static Suite *libjwt_suite(const char *title)
s = suite_create(title);
- tc_core = tcase_create("jwt_rsa");
+ tc_core = tcase_create("jwt_jwks_rsa");
- tcase_add_loop_test(tc_core, test_jwt_encode_rs256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_rs256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_validate_rs256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_rs384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_rs384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_rs512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_rs512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_rsa_i37, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_rsa_with_ec, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_token, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_cert, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_rsa_1024, 0, i);
+ /* RSA specific error path tests */
+ tcase_add_loop_test(tc_core, test_jwks_rsa_pub_missing, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_rsa_pub_bad64, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_rsa_pub_bad_type, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_rsa_pub_binary64, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_rsa_priv_missing, 0, i);
+ tcase_add_loop_test(tc_core, test_jwks_rsa_priv_bad64, 0, i);
- tcase_set_timeout(tc_core, 120);
+ tcase_set_timeout(tc_core, 30);
suite_add_tcase(s, tc_core);
@@ -254,5 +183,5 @@ static Suite *libjwt_suite(const char *title)
int main(void)
{
- JWT_TEST_MAIN("LibJWT RSA Sign/Verify");
+ JWT_TEST_MAIN("LibJWT JWKS Error Path Testing RSA");
}
diff --git a/tests/jwt_rsa_pss.c b/tests/jwt_rsa_pss.c
deleted file mode 100644
index 5d581048..00000000
--- a/tests/jwt_rsa_pss.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-static const char jwt_ps256_2048[] = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.ey"
- "JpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZi"
- "I6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.B9gxqtbZae"
- "9PyGkjQaBMyBITOieALP39yCDSqmynmvnE2L8JJzNxOKjm5dy_ORhYjagghE18ti90v2"
- "whAwRFFvA7MlQC2rQm-4pXrHqAyhT7Dl1_lSeL98WGToZgJ646WLjr-SwbMNjp3RWwZz"
- "F-IwnB1D1f-RoA9yUoaNEFHUYVuL4okVj4ImnUE07pW-l2eal3bxUg6lzqGWSctbT46t"
- "y8qFlsOyrifev3y_z6-eKPHUruYEbWb1zw3-snBtcPfGMWAQ91PVoNkPLTO6G56I8FAF"
- "IufXyyp6k9VuKQ_WRzRQhwO8zBOto4RsTUjYbDJEY2FSFYVZUdPctwojNlCw";
-
-static const char jwt_ps384_2048[] = "eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.ey"
- "JpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZi"
- "I6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.GY8aZobXTy"
- "6DzooRUt6vwgBbWwWvTchFtDCVMto_NM68aqT_OI8_X1MAHwE7ppS1S-yxg1aEeGzZEG"
- "VEAdeIzswd7ilCpQrUQ2Qcym6SuK3NAKLtr6NyUZwdaEPTeEx3GWQbmvY66hVs7g2o4c"
- "luSfp3I4McgLCm-HS5Dl_xHoyV_1ympz_n3n7YDoe5l0EoHaX3-XPMtUvL4kxeMV5pLh"
- "72Yj2qNM5Dbbe9F_WSxoeQsyktg8MmPb22LWAAW7uafazr7TinJvPtBhPqT7hc2sUFbA"
- "Jui_TSM60Kjfqg15QQELifywNvgW0ZO6xKEI5GKgaIi2S9F2iqQehBBkjMrg";
-
-static const char jwt_ps512_2048[] = "eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9.ey"
- "JpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbSIsInJlZi"
- "I6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.OxnjxVNAEC"
- "xEnNVg6S6sx-JIxOq3sJimEefq4OONsYomWz1TAM8_42bmAnvda0bhC8LTmIogQwnYj3"
- "qIYrjef3s7nrs5USS3_ffqeMuog_Xp7cH1YhVwvkXEWzfeT-SLZiEdxGBrPvEASxwzv0"
- "CitQrfDGvFe20UXkhAvOKIc_1K5Fzv9IQiaKaPR2Jg8Ub0qQ6qZq1whnwDbjutWCFlW3"
- "62UOQbhA2WtE72Q60OFXMr2J0PYrScGgTRRrL6V2G7cNRend14FzDFG586dGUCwp9iKF"
- "nCrshFefpaFsOJYHG70Ka6CNIDG4LDiLatjjz1UCtAgbnHfy9qyJEpcJYPWg";
-
-static const char jwt_ps256_2048_invalid[] = "eyJhbGciOiJQUzI1NiIsInR5cCI6Ikp"
- "XVCJ9.eyJpYXQiOjE0NzU5ODA1NDUsImlzcyI6ImZpbGVzLm1hY2xhcmEtbGxjLmNvbS"
- "IsInJlZiI6IlhYWFgtWVlZWS1aWlpaLUFBQUEtQ0NDQyIsInN1YiI6InVzZXIwIn0.WX"
- "41yYTKxf6lDg7toDAAnwuLKCUSdEWUsJ-5neEbOPE4l09EEIDW2cjK4NZkAgySgCZHCa"
- "NUSn8XaOouoLoEMVua5f0g6U-_-c380KRfmiqFGe39vjHCqiw8j-WkdxHisi7eXw3fvL"
- "kp0VoyeWA6Fnp2x-shfHU5Br67Wagp7OgCk-SvVL08xyfvgZr6fzEqc486zdNhQE71Pv"
- "in5dRQ75Lg3rr1W8Xmx2zRrFKZALsEwGMhRL7e-x46mt6KF1UlwTYAW6FYoKTrrW62sH"
- "OgpgvsIwhE93RfCmJ_xvZNkKrqnB6RxfpHEbZYTS8iAI3va2S8IBEL_pH-2etsr1fqAg";
-
-#define RSA_PSS_KEY_PRE "rsa_pss_key_2048"
-
-#define PS_KEY_PRIV_256 RSA_PSS_KEY_PRE ".json"
-#define PS_KEY_PUB_256 RSA_PSS_KEY_PRE "_pub.json"
-
-#define PS_KEY_PRIV_384 RSA_PSS_KEY_PRE "-384.json"
-#define PS_KEY_PUB_384 RSA_PSS_KEY_PRE "-384_pub.json"
-
-#define PS_KEY_PRIV_512 RSA_PSS_KEY_PRE "-512.json"
-#define PS_KEY_PUB_512 RSA_PSS_KEY_PRE "-512_pub.json"
-
-static void __test_rsa_pss_encode(const char *priv_key_file,
- const char *pub_key_file,
- const jwt_alg_t alg)
-{
- jwt_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret;
- char *out;
-
- CREATE_JWT(jwt, priv_key_file, alg);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_ne(out, NULL);
-
- free_key();
-
- __verify_alg_key(pub_key_file, out, alg);
-
- free(out);
-}
-
-START_TEST(test_jwt_encode_ps256)
-{
- SET_OPS();
- __test_alg_key(JWT_ALG_PS256, PS_KEY_PRIV_256, PS_KEY_PUB_256);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_ps384)
-{
- SET_OPS();
- __test_rsa_pss_encode(PS_KEY_PRIV_384, PS_KEY_PUB_384, JWT_ALG_PS384);
-}
-END_TEST
-
-START_TEST(test_jwt_encode_ps512)
-{
- SET_OPS();
- __test_rsa_pss_encode(PS_KEY_PRIV_512, PS_KEY_PUB_512, JWT_ALG_PS512);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_ps256)
-{
- SET_OPS();
- __verify_alg_key(PS_KEY_PUB_256, jwt_ps256_2048, JWT_ALG_PS256);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_ps384)
-{
- SET_OPS();
- __verify_alg_key(PS_KEY_PUB_384, jwt_ps384_2048, JWT_ALG_PS384);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_ps512)
-{
- SET_OPS();
- __verify_alg_key(PS_KEY_PUB_512, jwt_ps512_2048, JWT_ALG_PS512);
-}
-END_TEST
-
-START_TEST(test_jwt_verify_invalid_rsa_pss)
-{
- jwt_t *jwt = NULL;
-
- SET_OPS();
-
- read_key(PS_KEY_PUB_256);
- t_config.alg = JWT_ALG_PS256;
- jwt = jwt_verify(jwt_ps256_2048_invalid, &t_config);
- free_key();
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_ne(jwt_error(jwt), 0);
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_rsa_pss");
-
- tcase_add_loop_test(tc_core, test_jwt_encode_ps256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_ps384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_encode_ps512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_ps256, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_ps384, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_ps512, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_verify_invalid_rsa_pss, 0, i);
-
- tcase_set_timeout(tc_core, 120);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT RSA-PSS Sign/Verify");
-}
diff --git a/tests/jwt_tests.h b/tests/jwt_tests.h
index b5175271..6d0f82a4 100644
--- a/tests/jwt_tests.h
+++ b/tests/jwt_tests.h
@@ -46,22 +46,6 @@ static jwt_test_op_t jwt_test_ops[] = {
#endif
};
-#define EMPTY_JWT(__jwt) do { \
- __jwt = jwt_create(NULL); \
- ck_assert_ptr_nonnull(__jwt); \
-} while(0)
-
-#define jwt_test_auto_t jwt_t __attribute__((cleanup(jwt_test_free)))
-
-#define CREATE_JWT(__j, __f, __a) do { \
- JWT_CONFIG_DECLARE(__c); \
- read_key(__f); \
- __c.alg = __a; \
- __c.jw_key = g_item; \
- __j = jwt_create(&__c); \
- ck_assert_ptr_nonnull(__j); \
-} while(0)
-
#define JWT_TEST_MAIN(__title) ({ \
int number_failed = 0; \
SRunner *sr; \
@@ -84,11 +68,21 @@ static jwt_test_op_t jwt_test_ops[] = {
ck_assert_str_eq(ops, jwt_test_ops[_i].name); \
})
+#define jwt_freemem(__ptr) ({ \
+ if (__ptr) { \
+ free(__ptr); \
+ __ptr = NULL; \
+ } \
+})
+
+static inline void jwt_freememp(char **mem) {
+ jwt_freemem(*mem);
+}
+#define char_auto char __attribute__((cleanup(jwt_freememp)))
+
__attribute__((unused)) static jwk_set_t *g_jwk_set;
__attribute__((unused)) static const jwk_item_t *g_item;
-__attribute__((unused)) static JWT_CONFIG_DECLARE(t_config);
-
__attribute__((unused))
static struct {
char *key;
@@ -173,25 +167,12 @@ static void read_key(const char *key_file)
ck_assert_int_eq(ferror(fp), 0);
fclose(fp);
-
- if (strstr(key_file, ".pem") != NULL)
- return;
-
- g_jwk_set = jwks_create_strn(test_data.key, test_data.key_len);
- ck_assert_ptr_nonnull(g_jwk_set);
- ck_assert(!jwks_error(g_jwk_set));
-
- g_item = jwks_item_get(g_jwk_set, 0);
- ck_assert_ptr_nonnull(g_item);
-
- t_config.jw_key = g_item;
}
__attribute__((unused))
static void free_key(void)
{
jwks_free(g_jwk_set);
- jwt_config_init(&t_config);
g_jwk_set = NULL;
g_item = NULL;
test_data.key_len = 0;
@@ -199,145 +180,22 @@ static void free_key(void)
test_data.key = NULL;
}
-__attribute__((unused))
-static void jwt_test_free(jwt_t **jwt)
-{
- free_key();
- jwt_freep(jwt);
-}
-
-__attribute__((unused))
-static void __verify_jwt(const char *jwt_str, const jwt_alg_t alg,
- const char *file)
-{
- jwt_auto_t *jwt = NULL;
-
- read_key(file);
-
- t_config.alg = alg;
-
- jwt = jwt_verify(jwt_str, &t_config);
- free_key();
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- ck_assert_int_eq(jwt_get_alg(jwt), alg);
-
- free_key();
-}
-
__attribute__((unused))
static void __verify_jwk(const char *jwt_str, const jwk_item_t *item)
{
- JWT_CONFIG_DECLARE(config);
- jwt_auto_t *jwt = NULL;
-
- config.jw_key = item;
- config.alg = jwks_item_alg(item);
- jwt = jwt_verify(jwt_str, &config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-}
-
-__attribute__((unused))
-static void __test_alg_key(const jwt_alg_t alg, const char *file, const char *pub)
-{
- jwt_value_t jval;
- jwt_auto_t *jwt = NULL;
- int ret = 0;
- char *out;
-
- CREATE_JWT(jwt, file, alg);
-
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_nonnull(out);
-
- free_key();
-
- __verify_jwt(out, alg, pub);
-
- free(out);
-
- /* auto free */
-}
-
-__attribute__((unused))
-static void __verify_alg_key(const char *key_file, const char *jwt_str,
- const jwt_alg_t alg)
-{
- jwt_valid_t *jwt_valid = NULL;
- jwt_auto_t *jwt = NULL;
- int ret = 0;
-
- read_key(key_file);
-
- t_config.alg = alg;
-
- jwt = jwt_verify(jwt_str, &t_config);
- ck_assert_ptr_nonnull(jwt);
- ck_assert_int_eq(jwt_error(jwt), 0);
-
- ck_assert_int_eq(alg, jwt_get_alg(jwt));
-
- jwt_valid_new(&jwt_valid, alg);
-
- ret = jwt_validate(jwt, jwt_valid);
- ck_assert_int_eq(JWT_VALIDATION_SUCCESS, ret);
-
- jwt_valid_free(jwt_valid);
-
- free_key();
-}
-
-__attribute__((unused))
-static void __compare_alg_key(const char *key_file, const char *jwt_str,
- const jwt_alg_t alg)
-{
- jwt_test_auto_t *jwt = NULL;
- jwt_value_t jval;
- int ret = 0;
- char *out;
+ jwt_checker_auto_t *checker = NULL;
+ jwt_alg_t alg = JWT_ALG_NONE; // jwks_item_alg(item);
+ int ret;
- CREATE_JWT(jwt, key_file, alg);
+ checker = jwt_checker_new();
+ ck_assert_ptr_nonnull(checker);
+ ck_assert_int_eq(jwt_checker_error(checker), 0);
- jwt_set_ADD_STR(&jval, "iss", "files.maclara-llc.com");
- ret = jwt_grant_add(jwt, &jval);
+ ret = jwt_checker_setkey(checker, alg, item);
ck_assert_int_eq(ret, 0);
- jwt_set_ADD_STR(&jval, "sub", "user0");
- ret = jwt_grant_add(jwt, &jval);
+ ret = jwt_checker_verify(checker, jwt_str);
ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_STR(&jval, "ref", "XXXX-YYYY-ZZZZ-AAAA-CCCC");
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- jwt_set_ADD_INT(&jval, "iat", TS_CONST);
- ret = jwt_grant_add(jwt, &jval);
- ck_assert_int_eq(ret, 0);
-
- out = jwt_encode_str(jwt);
- ck_assert_ptr_nonnull(out);
-
- ck_assert_str_eq(out, jwt_str);
-
- free(out);
}
#endif /* JWT_TESTS_H */
diff --git a/tests/jwt_validate.c b/tests/jwt_validate.c
deleted file mode 100644
index a9319631..00000000
--- a/tests/jwt_validate.c
+++ /dev/null
@@ -1,702 +0,0 @@
-/* Public domain, no copyright. Use at your own risk. */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "jwt_tests.h"
-
-static jwt_t *jwt;
-
-static const time_t iat = TS_CONST;
-static const time_t not_before = TS_CONST + 60L;
-static const time_t expires = TS_CONST + 600L;
-
-static void __setup_jwt()
-{
- jwt_value_t jval;
-
- EMPTY_JWT(jwt);
- jwt_set_ADD_STR(&jval, "iss", "test");
- jwt_grant_add(jwt, &jval);
-
- jwt_set_ADD_STR(&jval, "sub", "user0");
- jwt_grant_add(jwt, &jval);
-
- jwt_set_ADD_JSON(&jval, NULL, "{\"aud\": [\"svc1\",\"svc2\"]}");
- jwt_grant_add(jwt, &jval);
-
- jwt_set_ADD_INT(&jval, "iat", iat);
- jwt_grant_add(jwt, &jval);
-
- jwt_set_ADD_BOOL(&jval, "admin", 1);
- jwt_grant_add(jwt, &jval);
-}
-
-static void __teardown_jwt()
-{
- jwt_free(jwt);
- jwt = NULL;
-}
-
-#define __VAL_EQ(__v, __e, __str) do { \
- unsigned int __r = jwt_validate(jwt, __v); \
- char *__s; \
- ck_assert_int_eq(__r, __e); \
- __r = jwt_valid_get_status(__v); \
- ck_assert_int_eq(__e, __r); \
- __s = jwt_exception_str(__r); \
- ck_assert_str_eq(__str, __s); \
- free(__s); \
-} while(0);
-
-START_TEST(test_jwt_validate_errno)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
- char *exc;
-
- SET_OPS();
-
- ck_assert_ptr_nonnull(jwt);
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* Validate fails with NULL jwt */
- ret = jwt_validate(NULL, jwt_valid);
- ck_assert_int_eq(ret, JWT_VALIDATION_ERROR);
- ret = jwt_valid_get_status(jwt_valid);
- ck_assert_int_eq(ret, JWT_VALIDATION_ERROR);
- exc = jwt_exception_str(ret);
- ck_assert_str_eq(exc, "general failures");
- free(exc);
-
-
- /* Validate fails with NULL jwt_valid */
- ret = jwt_validate(jwt, NULL);
- ck_assert_int_eq(ret, JWT_VALIDATION_ERROR);
-
- /* Get status fails with NULL jwt_valid */
- ck_assert_int_eq(JWT_VALIDATION_ERROR, jwt_valid_get_status(NULL));
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_algorithm)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
-
- SET_OPS();
-
- /* Matching algorithm is valid */
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- jwt_valid_free(jwt_valid);
-
- /* Wrong algorithm is not valid */
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_HS256);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* Starts with invalid */
- ck_assert_int_eq(JWT_VALIDATION_ERROR, jwt_valid_get_status(jwt_valid));
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_ALG_MISMATCH, "algorithm mismatch");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_require_grant)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
- const char *valstr = NULL;
- int valnum = 0;
-
- SET_OPS();
-
- /* Valid when alg matches and all required grants match */
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- ret = jwt_valid_add_grant(jwt_valid, "iss", "test");
- ck_assert_int_eq(ret, 0);
-
- /* No duplicates */
- ret = jwt_valid_add_grant(jwt_valid, "iss", "other");
- ck_assert_int_eq(ret, EEXIST);
-
- /* Grant has expected value */
- valstr = jwt_valid_get_grant(jwt_valid, "iss");
- ck_assert_ptr_nonnull(valstr);
- ck_assert_str_eq(valstr, "test");
-
- ret = jwt_valid_add_grant_int(jwt_valid, "iat", (long)iat);
- ck_assert_int_eq(ret, 0);
-
- /* No duplicates for int */
- ret = jwt_valid_add_grant_int(jwt_valid, "iat", (long)time(NULL));
- ck_assert_int_eq(ret, EEXIST);
-
- /* Grant has expected value */
- valnum = jwt_valid_get_grant_int(jwt_valid, "iat");
- ck_assert_int_eq(valnum, (long)iat);
-
- ret = jwt_valid_add_grant_bool(jwt_valid, "admin", 1);
- ck_assert_int_eq(ret, 0);
-
- /* No duplicates for bool */
- ret = jwt_valid_add_grant_bool(jwt_valid, "admin", 0);
- ck_assert_int_eq(ret, EEXIST);
-
- /* Grant has expected value */
- valnum = jwt_valid_get_grant_bool(jwt_valid, "admin");
- ck_assert_int_eq(valnum, 1);
-
- ret = jwt_valid_add_grants_json(jwt_valid, "{\"aud\": [\"svc1\",\"svc2\"]}");
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_nonmatch_grant)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* Invalid when required grants don't match */
- ret = jwt_valid_add_grant(jwt_valid, "iss", "wrong");
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISMATCH, "grant mismatch");
-
- jwt_valid_del_grants(jwt_valid, NULL);
-
- /* Invalid when required grants don't match (int) */
- ret = jwt_valid_add_grant_int(jwt_valid, "iat", (long)time(NULL) + 1);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISMATCH, "grant mismatch");
-
- jwt_valid_del_grants(jwt_valid, NULL);
-
- /* Invalid when required grants don't match (bool) */
- ret = jwt_valid_add_grant_bool(jwt_valid, "admin", 0);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISMATCH, "grant mismatch");
-
- jwt_valid_del_grants(jwt_valid, NULL);
-
- /* Invalid when required grants don't match (json) */
- ret = jwt_valid_add_grants_json(jwt_valid, "{\"aud\": [\"svc3\",\"svc4\"]}");
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISMATCH, "grant mismatch");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_grant_bool)
-{
- jwt_valid_t *jwt_valid = NULL;
- int val;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- ret = jwt_valid_add_grant_bool(jwt_valid, "admin", 1);
- ck_assert_int_eq(ret, 0);
-
- val = jwt_valid_get_grant_bool(jwt_valid, "admin");
- ck_assert(val);
-
- ret = jwt_valid_add_grant_bool(jwt_valid, "test", 0);
- ck_assert_int_eq(ret, 0);
-
- val = jwt_valid_get_grant_bool(jwt_valid, "test");
- ck_assert(!val);
-
- val = jwt_valid_get_grant_bool(jwt_valid, "not found");
- ck_assert_int_eq(errno, ENOENT);
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_del_grants)
-{
- jwt_valid_t *jwt_valid = NULL;
- const char *val;
- const char testval[] = "testing";
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- ret = jwt_valid_add_grant(jwt_valid, "iss", testval);
- ck_assert_int_eq(ret, 0);
-
- ret = jwt_valid_add_grant(jwt_valid, "other", testval);
- ck_assert_int_eq(ret, 0);
-
- ret = jwt_valid_del_grants(jwt_valid, "iss");
- ck_assert_int_eq(ret, 0);
-
- val = jwt_valid_get_grant(jwt_valid, "iss");
- ck_assert_ptr_null(val);
-
- /* Delete non existent. */
- ret = jwt_valid_del_grants(jwt_valid, "iss");
- ck_assert_int_eq(ret, 0);
-
- /* Delete all grants. */
- ret = jwt_valid_del_grants(jwt_valid, NULL);
- ck_assert_int_eq(ret, 0);
-
- val = jwt_valid_get_grant(jwt_valid, "other");
- ck_assert_ptr_null(val);
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_invalid_grant)
-{
- jwt_valid_t *jwt_valid = NULL;
- const char *val;
- long valint = 0;
- long valbool = 0;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- ret = jwt_valid_add_grant(jwt_valid, "iss", NULL);
- ck_assert_int_eq(ret, EINVAL);
-
- ret = jwt_valid_add_grant_int(jwt_valid, "", (long)time(NULL));
- ck_assert_int_eq(ret, EINVAL);
-
- val = jwt_valid_get_grant(jwt_valid, NULL);
- ck_assert_int_eq(errno, EINVAL);
- ck_assert_ptr_null(val);
-
- valint = jwt_valid_get_grant_int(jwt_valid, NULL);
- ck_assert_int_eq(errno, EINVAL);
- ck_assert(valint == 0);
-
- valbool = jwt_valid_get_grant_bool(jwt_valid, NULL);
- ck_assert_int_eq(errno, EINVAL);
- ck_assert(valbool == 0);
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_missing_grant)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* JWT is invalid when required grants are not present */
- ret = jwt_valid_add_grant(jwt_valid, "np-str", "test");
- ck_assert_int_eq(ret, 0);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISSING, "grant missing");
-
- jwt_valid_del_grants(jwt_valid, NULL);
-
- /* JWT is invalid when required grants are not present (int) */
- ret = jwt_valid_add_grant_int(jwt_valid, "np-int", 7);
- ck_assert_int_eq(ret, 0);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISSING, "grant missing");
-
- jwt_valid_del_grants(jwt_valid, NULL);
-
- /* JWT is invalid when required grants are not present (bool) */
- ret = jwt_valid_add_grant_int(jwt_valid, "np-bool", 1);
- ck_assert_int_eq(ret, 0);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISSING, "grant missing");
-
- jwt_valid_del_grants(jwt_valid, NULL);
-
- /* JWT is invalid when required grants are not present (json) */
- ret = jwt_valid_add_grants_json(jwt_valid, "{\"np-other\": [\"foo\",\"bar\"]}");
- ck_assert_int_eq(ret, 0);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_GRANT_MISSING, "grant missing");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_not_before)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
- jwt_value_t jval;
-
- SET_OPS();
-
- jwt_set_ADD_INT(&jval, "nbf", not_before);
- jwt_grant_add(jwt, &jval);
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* JWT is invalid when now < not-before */
- ret = jwt_valid_set_now(jwt_valid, not_before - 1);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_TOO_NEW, "token future dated");
-
- /* JWT is valid when now >= not-before */
- ret = jwt_valid_set_now(jwt_valid, not_before);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_set_nbf_leeway)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* 0 by default */
- time_t init_nbf_leeway = jwt_valid_get_nbf_leeway(jwt_valid);
- ck_assert_int_eq(init_nbf_leeway, 0);
-
- /* Setting nbf_leeway */
- ret = jwt_valid_set_nbf_leeway(jwt_valid, 1);
- ck_assert_int_eq(ret, 0);
-
- time_t set_nbf_leeway = jwt_valid_get_nbf_leeway(jwt_valid);
- ck_assert_int_eq(set_nbf_leeway, 1);
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_not_before_leeway)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
- jwt_value_t jval;
-
- SET_OPS();
-
- jwt_set_ADD_INT(&jval, "nbf", not_before);
- jwt_grant_add(jwt, &jval);
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* Setting nbf_leeway */
- ret = jwt_valid_set_nbf_leeway(jwt_valid, 10);
- ck_assert_int_eq(ret, 0);
-
- /* JWT is invalid when now < not-before - nbf_leeway */
- ret = jwt_valid_set_now(jwt_valid, (long)not_before - 15);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_TOO_NEW, "token future dated");
-
- /* JWT is valid when now >= not-before - nbf_leeway */
- ret = jwt_valid_set_now(jwt_valid, (long)not_before - 5);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_expires)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
- jwt_value_t jval;
-
- SET_OPS();
-
- jwt_set_ADD_INT(&jval, "exp", expires);
- jwt_grant_add(jwt, &jval);
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* JWT is valid when now < expires */
- ret = jwt_valid_set_now(jwt_valid, (long)expires - 1);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- /* JWT is invalid when now >= expires */
- ret = jwt_valid_set_now(jwt_valid, (long)expires);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_EXPIRED, "token expired");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_set_exp_leeway)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* 0 by default */
- time_t init_exp_leeway = jwt_valid_get_exp_leeway(jwt_valid);
- ck_assert_int_eq(init_exp_leeway, 0);
-
- /* Setting exp_leeway */
- ret = jwt_valid_set_exp_leeway(jwt_valid, 1);
- ck_assert_int_eq(ret, 0);
-
- time_t set_exp_leeway = jwt_valid_get_exp_leeway(jwt_valid);
- ck_assert_int_eq(set_exp_leeway, 1);
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_expires_leeway)
-{
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
- jwt_value_t jval;
-
- SET_OPS();
-
- jwt_set_ADD_INT(&jval, "exp", expires);
- jwt_grant_add(jwt, &jval);
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- /* Setting exp_leeway */
- ret = jwt_valid_set_exp_leeway(jwt_valid, 10);
- ck_assert_int_eq(ret, 0);
-
- /* JWT is valid when now < expires + exp_leeway */
- ret = jwt_valid_set_now(jwt_valid, (long)expires + 5);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- /* JWT is invalid when now >= expires + exp_leeway */
- ret = jwt_valid_set_now(jwt_valid, (long)expires + 15);
- ck_assert_int_eq(ret, 0);
-
- __VAL_EQ(jwt_valid, JWT_VALIDATION_EXPIRED, "token expired");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_headers)
-{
- jwt_value_t jval;
- jwt_valid_t *jwt_valid = NULL;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- ret = jwt_valid_set_headers(jwt_valid, 1);
- ck_assert_int_eq(ret, 0);
-
- /* JWT is valid when iss in hdr matches iss in body */
- jwt_set_ADD_STR(&jval, "iss", "test");
- jwt_header_add(jwt, &jval);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- /* JWT is invalid when iss in hdr does not match iss in body */
- jwt_header_del(jwt, "iss");
- jwt_set_ADD_STR(&jval, "iss", "wrong");
- jwt_header_add(jwt, &jval);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_ISS_MISMATCH, "issuer mismatch");
-
- /* JWT is valid when checking hdr and iss not replicated */
- jwt_header_del(jwt, "iss");
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- /* JWT is valid when iss in hdr matches iss in body */
- jwt_set_ADD_STR(&jval, "sub", "user0");
- jwt_header_add(jwt, &jval);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- /* JWT is invalid when iss in hdr does not match iss in body */
- jwt_header_del(jwt, "sub");
- jwt_set_ADD_STR(&jval, "sub", "wrong");
- jwt_header_add(jwt, &jval);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUB_MISMATCH, "subject mismatch");
-
- /* JWT is valid when checking hdr and sub not replicated */
- jwt_header_del(jwt, "sub");
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- /* JWT is valid when checking hdr and aud matches */
- jwt_set_ADD_JSON(&jval, NULL, "{\"aud\": [\"svc1\",\"svc2\"]}");
- jwt_header_add(jwt, &jval);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- /* JWT is invalid when checking hdr and aud does not match */
- jwt_header_del(jwt, "aud");
- jwt_set_ADD_JSON(&jval, NULL, "{\"aud\": [\"svc1\",\"svc2\",\"svc3\"]}");
- jwt_header_add(jwt, &jval);
- __VAL_EQ(jwt_valid, JWT_VALIDATION_AUD_MISMATCH, "audience mismatch");
-
- /* JWT is invalid when checking hdr and aud does not match */
- jwt_header_del(jwt, "aud");
- __VAL_EQ(jwt_valid, JWT_VALIDATION_SUCCESS, "success");
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-START_TEST(test_jwt_valid_grants_json)
-{
- const char *json = "{\"id\":\"FVvGYTr3FhiURCFebsBOpBqTbzHdX/DvImiA2yheXr8=\","
- "\"iss\":\"localhost\",\"other\":[\"foo\",\"bar\"],"
- "\"ref\":\"385d6518-fb73-45fc-b649-0527d8576130\","
- "\"scopes\":\"storage\",\"sub\":\"user0\"}";
- jwt_valid_t *jwt_valid = NULL;
- const char *val;
- char *json_val;
- unsigned int ret = 0;
-
- SET_OPS();
-
- ret = jwt_valid_new(&jwt_valid, JWT_ALG_NONE);
- ck_assert_int_eq(ret, 0);
- ck_assert_ptr_nonnull(jwt_valid);
-
- ret = jwt_valid_add_grants_json(jwt_valid, json);
- ck_assert_int_eq(ret, 0);
-
- val = jwt_valid_get_grant(jwt_valid, "ref");
- ck_assert_ptr_nonnull(val);
- ck_assert_str_eq(val, "385d6518-fb73-45fc-b649-0527d8576130");
-
- json_val = jwt_valid_get_grants_json(NULL, "other");
- ck_assert_ptr_null(json_val);
- ck_assert_int_eq(errno, EINVAL);
-
- json_val = jwt_valid_get_grants_json(jwt_valid, "other");
- ck_assert_ptr_nonnull(json_val);
- ck_assert_str_eq(json_val, "[\"foo\",\"bar\"]");
-
- free(json_val);
-
- json_val = jwt_valid_get_grants_json(jwt_valid, NULL);
- ck_assert_ptr_nonnull(json_val);
- ck_assert_str_eq(json_val, json);
-
- free(json_val);
-
- jwt_valid_free(jwt_valid);
-}
-END_TEST
-
-static Suite *libjwt_suite(const char *title)
-{
- Suite *s;
- TCase *tc_core;
- int i = ARRAY_SIZE(jwt_test_ops);
-
- s = suite_create(title);
-
- tc_core = tcase_create("jwt_validate");
-
- /* Run before and after each unit test. */
- tcase_add_checked_fixture(tc_core, __setup_jwt, __teardown_jwt);
-
- tcase_add_loop_test(tc_core, test_jwt_validate_errno, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_algorithm, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_require_grant, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_nonmatch_grant, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_invalid_grant, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_missing_grant, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_grant_bool, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_grants_json, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_del_grants, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_not_before, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_set_nbf_leeway, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_not_before_leeway, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_expires, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_set_exp_leeway, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_expires_leeway, 0, i);
- tcase_add_loop_test(tc_core, test_jwt_valid_headers, 0, i);
-
- tcase_set_timeout(tc_core, 30);
-
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int main(void)
-{
- JWT_TEST_MAIN("LibJWT Validate");
-}
diff --git a/tests/keys/eddsa_key_ed25519.json b/tests/keys/eddsa_key_ed25519.json
index 983d10d1..5958cc2e 100644
--- a/tests/keys/eddsa_key_ed25519.json
+++ b/tests/keys/eddsa_key_ed25519.json
@@ -9,7 +9,6 @@
"kid": "7dc4a07e-51b6-47dd-ae8c-2da0ef921818",
"kty": "OKP",
"crv": "Ed25519",
- "alg": "EdDSA",
"x": "HUj-14kN6N4i5qNVkfEhwKiCf-tSrvRHstQdtV8a5QM",
"d": "XY5oUZqGWVZhX7J09hG-rRnAKXiw1g_aBh-Bc52KZ_Y"
}
diff --git a/tests/keys/eddsa_key_ed25519_pub.json b/tests/keys/eddsa_key_ed25519_pub.json
index b17b50f2..3f13c40c 100644
--- a/tests/keys/eddsa_key_ed25519_pub.json
+++ b/tests/keys/eddsa_key_ed25519_pub.json
@@ -8,7 +8,6 @@
"kid": "bf160513-a400-4bc9-ba52-bc90c5e55f60",
"kty": "OKP",
"crv": "Ed25519",
- "alg": "EdDSA",
"x": "HUj-14kN6N4i5qNVkfEhwKiCf-tSrvRHstQdtV8a5QM"
}
]
diff --git a/tests/keys/jwks_keyring.json b/tests/keys/jwks_keyring.json
index 518cf8ee..8089ac4d 100644
--- a/tests/keys/jwks_keyring.json
+++ b/tests/keys/jwks_keyring.json
@@ -250,7 +250,7 @@
{
"kty": "oct",
"alg": "HS512",
- "k": "5VQGqfFoKucG-LLYFmW500OiaKIJtedo_RHjOvt4d1qJoTVi_4k95CKc_iF8xNR3NSbyndUvCPSp"
+ "k": "vPnfAG10Y09YGh+DQQwQ-n1lye8hfaO1PYdh8qr5oOI5gxKaX1GNBgwtSWsFyt7txFpuMs4kf_3wPWIefC2rQg"
},
{
"kty": "oct",
diff --git a/tests/keys/oct_key_256_invalid_base64.json b/tests/keys/oct_key_256_invalid_base64.json
index c70b752e..2d184162 100644
--- a/tests/keys/oct_key_256_invalid_base64.json
+++ b/tests/keys/oct_key_256_invalid_base64.json
@@ -4,7 +4,7 @@
"key_ops": [
"sign"
],
- "kid": "8b5a52de-6449-4745-9712-64cd79a0b837",
+ "kid": "test:invalid-base64",
"kty": "oct",
"k": "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5WFk",
"alg": "HS256"
diff --git a/tests/keys/oct_key_512.json b/tests/keys/oct_key_512.json
index eef6b202..5f946f30 100644
--- a/tests/keys/oct_key_512.json
+++ b/tests/keys/oct_key_512.json
@@ -3,7 +3,7 @@
{
"kty": "oct",
"alg": "HS512",
- "k": "TVS/FVl4hPeR7OnxPKoMriFov2XeVrOBAJLdPf-Uq-9x5/HG6Z2nZkpDWp1Y6RYytSYfNE5nyLWxx8CDi5oAvw"
+ "k": "vPnfAG10Y09YGh+DQQwQ-n1lye8hfaO1PYdh8qr5oOI5gxKaX1GNBgwtSWsFyt7txFpuMs4kf_3wPWIefC2rQg"
}
]
}
diff --git a/tests/keys/rsa_pss_key_2048-384.json b/tests/keys/rsa_pss_key_2048_384.json
similarity index 100%
rename from tests/keys/rsa_pss_key_2048-384.json
rename to tests/keys/rsa_pss_key_2048_384.json
diff --git a/tests/keys/rsa_pss_key_2048-384_pub.json b/tests/keys/rsa_pss_key_2048_384_pub.json
similarity index 100%
rename from tests/keys/rsa_pss_key_2048-384_pub.json
rename to tests/keys/rsa_pss_key_2048_384_pub.json
diff --git a/tests/keys/rsa_pss_key_2048-512.json b/tests/keys/rsa_pss_key_2048_512.json
similarity index 100%
rename from tests/keys/rsa_pss_key_2048-512.json
rename to tests/keys/rsa_pss_key_2048_512.json
diff --git a/tests/keys/rsa_pss_key_2048-512_pub.json b/tests/keys/rsa_pss_key_2048_512_pub.json
similarity index 100%
rename from tests/keys/rsa_pss_key_2048-512_pub.json
rename to tests/keys/rsa_pss_key_2048_512_pub.json
diff --git a/tests/keys/rsa_pss_key_2048_noalg.json b/tests/keys/rsa_pss_key_2048_noalg.json
new file mode 100644
index 00000000..ebfe2fd2
--- /dev/null
+++ b/tests/keys/rsa_pss_key_2048_noalg.json
@@ -0,0 +1,18 @@
+ {
+ "use": "sig",
+ "key_ops": [
+ "verify",
+ "sign"
+ ],
+ "kid": "a9a0eb5b-67e9-4495-9030-a97d063d4bb4",
+ "kty": "RSA",
+ "alg": "PS384",
+ "n": "k2H-nc6pcHePEz7liCxy4sYXBbrks3jgmTyQo3nwfpEKecbPu8qraXg5Ogjm9LzfIapk3Jm_eFtY-zEhqgOTDipc_aXRhTZg71AHh-GgF7EtatrDwXs0Cs6M-dhF0MZpgqrUt2RgkjMD3CfgztfJVLi6KOeEcwfZ7zbjuvEGc7pvQrivNksvpxlOVVDYtF0o_kEWNGJB4djr5iJek2ZOO3Ij3iPw3bBx_nBO4p2NXb7j8mFcnbzyABNPGwr94SyXmWTNhtMYUrfYpjWcBp79H6FxXHRu0JZajYCIe95RrxQ23L1zBIZwhD1VJgYVGdhMfB9mfbo7FmxDwYaAmDoNYQ",
+ "e": "AQAB",
+ "d": "DHjrOhthnAdtWVF_mi9sxen0_wKkbqQiZniWIu3jhZdGCpOVEKbWxhuq-B4FvlAqr9r1vMENtfFBDZNIVO6gtL7hoYOCJu-Fpertxp8eh0xZDbH96_M-e1JxSR_dmwyxCoix0xbdbbHmHmzvg05s_TL1NuRbNJYSNUJXZLWxK2NKmlw-lPRb360n7H5KFSXECNWBsI9rkJuPvO_HmEYotiAotpxlC3N9cYmFc-G-W6JHTcF7CR2DZOauE3MI5jJpa-qzLXKKCphTq-PkbeM0jwgXciQ11RaC39KVy4YquWDTptilb4LgGQCMDqVIeW5VnBBmhtJvAJhPo_E5RK-MCw",
+ "p": "y6sKp6asFY-kv8hFEh_MPx-eTmZqr-g-CDEq7xgap9fI4LFGvemJv3isQcYJjPAFWreB0PF3uz6XlcK6x1CwjqWlNecQYUmDWq0kyJSvQ7Gn2txsIF6An5lkhSG_AQ-qLWay_WPmyjPXsxaF9aFM-QjTSW12wWcIKGCP0KSrhsM",
+ "q": "uUCYSXKi-4h0Z43Ol_jqy1mCD-yaICt4CtJeZTMbC7CI9qVPUaNHni3fUBxTDgOdH6xJGMZ1XuUFn68fjPB_mPmKUimYCrqlBzhRh7axT6tdD4WQc8rpEHvaucGjp2dBXrCDve_RPyMI8HYRS5kKGmvqhVpnwT0iVq5KRCERgQs",
+ "dp": "HFEzsguicXz_UwrtT4_MPhqPUCc9Pif0N_9eENAxJJUEAPmk9FK8LDsC-EIoocfddrd8_SgVlZsmSFRC0-OMKMkvJ0dxJ5WpBbp9GsZReAADbpKnFfkNuSMCrt_6RpN-_cEBselp9UMwAl5nUbeTlCx98_-cO1ev8q06UbATiTE",
+ "dq": "bmEPnAvDEs6OVTlIVILLG5jchzJ57xsXbpNEDVZzEfcA1L1Q0prQTG6WtXv6_MmocDvOXgW5323keO32hZqy3GorQaNo5VOqiu_CnHN9mLPJQjtaA7RuRBUYEUBQi6lZaNsR1DU1X0I3zFb9HSc1vuJ4HTbtxVTwxecZdxig_ls",
+ "qi": "RhNgmhA5ZNiHU0DoDoMzeaXVpwGxUZ_QkAmC1mc11SROp0khJmM-XfQBW5x6f8sYmX0zAj9EUh01dk1cKrg0dPX42c5nYItgo6ynFSJoSUkl_nu4tJysoCSh-3HtUtstooogDPQKUf4A9UAzgf1vrl95SRl-oL8MaVXlHm_o1KQ"
+ }
diff --git a/tests/test-env.sh b/tests/test-env.sh
index b9864ad9..d783cb21 100644
--- a/tests/test-env.sh
+++ b/tests/test-env.sh
@@ -1,5 +1,5 @@
if [ "$TEST" = "jwt_new" ]; then
export JWT_CRYPTO=openssl
-elif [ "$TEST" = "jwt_dump" ]; then
+elif [ "$TEST" = "jwt_flipflop" ]; then
export JWT_CRYPTO=NONEXISTENT
fi