blob: da083bf02759baca49815a734539aa4508f8d72f [file]
/* Public domain, no copyright. Use at your own risk. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#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_SET_INT(&jval, "exp", TS_CONST + 480);
jwt_claim_set(jwt, &jval);
return 0;
}
START_TEST(gen_wcb)
{
const char exp[] = "eyJhbGciOiJub25lIn0.eyJleHAiOjE0NzU5ODEwMjV9.";
jwt_builder_auto_t *builder = NULL;
char_auto *out = NULL;
const char *ctx;
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_enable_iat(builder, 1);
ck_assert_int_eq(ret, 1);
ret = jwt_builder_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
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);
ctx = jwt_builder_getctx(builder);
ck_assert_str_eq(ctx, "testing");
}
END_TEST
static int __set_alg_cb(jwt_t *jwt, jwt_config_t *config)
{
jwt_value_t jval;
int ret;
ck_assert_ptr_nonnull(jwt);
ck_assert_ptr_nonnull(config);
/* Clear the whole header */
ret = jwt_header_del(jwt, NULL);
ck_assert_int_eq(ret, JWT_VALUE_ERR_NONE);
/* This will get overwritten */
jwt_set_SET_INT(&jval, "alg", JWT_ALG_HS256);
jwt_header_set(jwt, &jval);
/* This wont */
jwt_set_SET_STR(&jval, "typ", "NOTJWT");
jwt_header_set(jwt, &jval);
return 0;
}
START_TEST(set_alg)
{
jwt_builder_auto_t *builder = NULL;
const char *exp = "eyJhbGciOiJIUzI1NiIsInR5cCI6Ik5PVEpXVCJ9.e30.GsBNaD"
"rcrck5dXU9za1MrrOxpz8KQXjq-JHmeCyFhAA";
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
ret = jwt_builder_setcb(builder, __set_alg_cb, NULL);
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);
}
END_TEST
static int __just_fail_cb(jwt_t *jwt, jwt_config_t *config)
{
(void)jwt;
(void)config;
return 1;
}
START_TEST(just_fail_wcb)
{
jwt_builder_auto_t *builder = NULL;
char *out;
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_setcb(builder, __just_fail_cb, "testing");
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
free_key();
}
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_auto_t *builder = NULL;
jwt_value_t jval;
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);
jwt_set_GET_STR(&jval, "");
ret = jwt_builder_claim_get(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
jwt_set_GET_INT(&jval, "");
ret = jwt_builder_claim_get(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
jwt_set_GET_BOOL(&jval, "");
ret = jwt_builder_claim_get(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
jwt_set_GET_JSON(&jval, "");
jval.pretty = 1;
ret = jwt_builder_claim_get(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_NONE);
ck_assert_ptr_nonnull(jval.json_val);
free(jval.json_val);
jwt_set_SET_STR(&jval, "", "");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
jwt_set_SET_INT(&jval, "", 0);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
jwt_set_SET_BOOL(&jval, "", 0);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
jwt_set_SET_JSON(&jval, "", "{}");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_NONE);
jwt_set_SET_JSON(&jval, "", "");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_INVALID);
jwt_set_SET_JSON(&jval, "", "{}");
jval.replace = 1;
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_NONE);
/* 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);
/* Some alg mismatches */
read_json("eddsa_key_ed25519.json");
ret = jwt_builder_setkey(builder, JWT_ALG_NONE, g_item);
ck_assert_int_ne(ret, 0);
free_key();
jwt_builder_error_clear(builder);
read_json("oct_key_256.json");
ret = jwt_builder_setkey(builder, JWT_ALG_ES256, g_item);
ck_assert_int_ne(ret, 0);
jwt_builder_error_clear(builder);
ret = jwt_builder_setcb(builder, NULL, "test");
ck_assert_int_ne(ret, 0);
ret = jwt_builder_header_del(NULL, NULL);
ck_assert_int_ne(ret, 0);
ret = jwt_checker_claim_del(NULL, JWT_CLAIM_ISS);
ck_assert_int_ne(ret, 0);
ret = jwt_checker_claim_set(NULL, JWT_CLAIM_ISS, "goo");
ck_assert_int_ne(ret, 0);
out = jwt_checker_claim_get(NULL, JWT_CLAIM_ISS);
ck_assert_ptr_null(out);
/* Random */
ck_assert_int_eq(jwt_str_alg(NULL), JWT_ALG_INVAL);
out = jwt_alg_str(JWT_ALG_ES256K);
ck_assert_str_eq(out, "ES256K");
ck_assert_ptr_null(jwt_alg_str(JWT_ALG_INVAL));
ck_assert_int_eq(jwt_get_alg(NULL), JWT_ALG_INVAL);
ret = jwt_builder_setcb(NULL, NULL, NULL);
ck_assert_int_ne(ret, 0);
ck_assert_int_eq(jwt_header_del(NULL, NULL), JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jwt_claim_del(NULL, NULL), JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jwt_header_get(NULL, NULL), JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jwt_header_get(NULL, &jval), JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jval.error, JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jwt_builder_enable_iat(NULL, 1), -1);
ck_assert_ptr_null(jwt_builder_getctx(NULL));
ck_assert_int_eq(jwt_builder_claim_del(NULL, NULL), JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jwt_builder_claim_get(NULL, &jval), JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jwt_builder_claim_get(builder, NULL), JWT_VALUE_ERR_INVALID);
ck_assert_int_eq(jwt_builder_time_offset(NULL, JWT_CLAIM_NBF, 0), 1);
ck_assert_int_eq(jwt_builder_time_offset(builder, JWT_CLAIM_SUB, 0), 1);
ck_assert_int_eq(jwt_builder_time_offset(builder, JWT_CLAIM_NBF, 0), 0);
free_key();
}
END_TEST
START_TEST(gen_hs256)
{
jwt_builder_auto_t *builder = NULL;
char_auto *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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
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_hs256_bits)
{
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
read_json("oct_key_256.json");
ret = jwt_builder_setkey(builder, JWT_ALG_HS384, g_item);
ck_assert_int_ne(ret, 0);
free_key();
}
END_TEST
START_TEST(gen_es384_pub)
{
jwt_builder_auto_t *builder = NULL;
const unsigned char *buf = NULL;
jwk_key_type_t kty;
const char *crv;
size_t len = 0;
int ret, bits;
SET_OPS();
builder = jwt_builder_new();
ck_assert_ptr_nonnull(builder);
ck_assert_int_eq(jwt_builder_error(builder), 0);
ret = jwt_builder_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
/* Pub key */
read_json("ec_key_secp384r1_pub.json");
/* Check the curve */
crv = jwks_item_curve(g_item);
ck_assert_str_eq(crv, "P-384");
/* Check kty */
kty = jwks_item_kty(g_item);
ck_assert_int_eq(kty, JWK_KEY_TYPE_EC);
/* Check bits */
bits = jwks_item_key_bits(g_item);
ck_assert_int_eq(bits, 384);
/* Check that these aren't there */
ret = jwks_item_key_oct(g_item, &buf, &len);
ck_assert_int_ne(ret, 0);
ck_assert_ptr_null(buf);
ck_assert_int_eq(len, 0);
/* Pub key will fail to set */
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
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_ec_stress)
{
jwt_builder_auto_t *builder = NULL;
const char exp[] = "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.e30.";
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
read_json("ec_key_secp384r1.json");
ret = jwt_builder_setkey(builder, JWT_ALG_ES384, 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_mem_eq(out, exp, strlen(exp));
ck_assert_int_eq(strlen(out), 169);
}
free_key();
}
END_TEST
START_TEST(claim_str_setgetdel)
{
const char exp[] = "eyJhbGciOiJub25lIn0.eyJzdWIiOiJteS1mcmllbmQifQ.";
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_STR(&jval, "sub", "my-friend");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_STR(&jval, "aud", "public");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_STR(&jval, "aud", "private");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
jwt_set_SET_STR(&jval, "aud", "employees");
jval.replace = 1;
ret = jwt_builder_claim_set(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_setgetdel)
{
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_INT(&jval, "nbf", TS_CONST);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_INT(&jval, "exp", TS_CONST);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_INT(&jval, "exp", TS_CONST + 360);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
jwt_set_SET_INT(&jval, "exp", TS_CONST + 480);
jval.replace = 1;
ret = jwt_builder_claim_set(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_setgetdel)
{
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_BOOL(&jval, "admin", 1);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_BOOL(&jval, "sudo", 1);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_BOOL(&jval, "sudo", 0);
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
jwt_set_SET_BOOL(&jval, "sudo", 0);
jval.replace = 1;
ret = jwt_builder_claim_set(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_setgetdel)
{
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_JSON(&jval, "rooms",
"[\"office\",\"war-room\"]");
ret = jwt_builder_claim_set(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_SET_JSON(&jval, "buildings",
"{\"main\":\"dallas\",\"accounting\":\"houston\"}");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_JSON(&jval, "buildings", "{\"hq\": 0}");
ret = jwt_builder_claim_set(builder, &jval);
ck_assert_int_eq(ret, JWT_VALUE_ERR_EXIST);
jwt_set_SET_JSON(&jval, "buildings", "{\"hq\": 1}");
jval.replace = 1;
ret = jwt_builder_claim_set(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_setgetdel)
{
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_STR(&jval, "typ", "Custom");
ret = jwt_builder_header_set(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
START_TEST(sign_es256_bad_sig)
{
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);
/* Algorithm confusion: an OKP/EdDSA JWK must not be settable for
* an EC algorithm like ES256 (GHSA-q843-6q5f-w55g). setkey rejects
* up front before any signing is attempted. */
read_json("eddsa_key_ed25519_fake_es256.json");
ret = jwt_builder_setkey(builder, JWT_ALG_ES256, g_item);
ck_assert_int_ne(ret, 0);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"Key type does not match algorithm");
free_key();
}
END_TEST
/* @rfc{7515,4.1.11} "crit" header emission on the builder side. */
START_TEST(crit_gen)
{
/* {"alg":"none","crit":["foo"],"foo":"bar"} . {} . */
const char exp[] =
"eyJhbGciOiJub25lIiwiY3JpdCI6WyJmb28iXSwiZm9vIjoiYmFyIn0.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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_STR(&jval, "foo", "bar");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
ret = jwt_builder_setcrit(builder, "foo");
ck_assert_int_eq(ret, 0);
/* Duplicate registration is a no-op success. */
ret = jwt_builder_setcrit(builder, "foo");
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(crit_gen_two)
{
/* {"alg":"none","baz":2,"crit":["foo","baz"],"foo":"bar"} . {} . */
const char exp[] = "eyJhbGciOiJub25lIiwiYmF6IjoyLCJjcml0IjpbImZvbyIsImJh"
"eiJdLCJmb28iOiJiYXIifQ.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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_STR(&jval, "foo", "bar");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_INT(&jval, "baz", 2);
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
/* Array preserves registration order; object keys are sorted. */
ret = jwt_builder_setcrit(builder, "foo");
ck_assert_int_eq(ret, 0);
ret = jwt_builder_setcrit(builder, "baz");
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(crit_gen_not_in_header)
{
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);
/* Mark "foo" critical but never add it to the header. */
ret = jwt_builder_setcrit(builder, "foo");
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"\"crit\" lists \"foo\" which is not in the header");
}
END_TEST
START_TEST(crit_gen_registered)
{
/* Every RFC 7515 and JWA (RFC 7518) header name must be rejected. */
static const char * const names[] = {
"alg", "jku", "jwk", "kid", "x5u", "x5c", "x5t", "x5t#S256",
"typ", "cty", "crit",
"enc", "zip", "epk", "apu", "apv", "iv", "tag", "p2s", "p2c",
};
size_t n;
SET_OPS();
for (n = 0; n < sizeof(names) / sizeof(names[0]); n++) {
jwt_builder_auto_t *builder = NULL;
char_auto *out = NULL;
char expmsg[128];
int ret;
builder = jwt_builder_new();
ck_assert_ptr_nonnull(builder);
ck_assert_int_eq(jwt_builder_error(builder), 0);
ret = jwt_builder_setcrit(builder, names[n]);
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
snprintf(expmsg, sizeof(expmsg),
"\"crit\" cannot list registered header \"%s\"",
names[n]);
ck_assert_str_eq(jwt_builder_error_msg(builder), expmsg);
}
}
END_TEST
START_TEST(crit_gen_none)
{
/* No crit registered -> no "crit" header, baseline output. */
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
START_TEST(crit_gen_dup)
{
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);
/* App sets a "crit" array with a duplicate name directly. */
jwt_set_SET_JSON(&jval, "crit", "[\"foo\",\"foo\"]");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_STR(&jval, "foo", "bar");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"\"crit\" lists \"foo\" more than once");
}
END_TEST
/* An application can set "crit" directly in the header (bypassing
* jwt_builder_setcrit). It must still be validated, never emitted as-is. */
START_TEST(crit_appset_valid)
{
/* {"alg":"none","crit":["foo"],"foo":"bar"} . {} . */
const char exp[] =
"eyJhbGciOiJub25lIiwiY3JpdCI6WyJmb28iXSwiZm9vIjoiYmFyIn0.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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_JSON(&jval, "crit", "[\"foo\"]");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_STR(&jval, "foo", "bar");
ret = jwt_builder_header_set(builder, &jval);
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(crit_appset_not_array)
{
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);
jwt_set_SET_STR(&jval, "crit", "foo");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"\"crit\" header must be an array");
}
END_TEST
START_TEST(crit_appset_not_array_setcrit)
{
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);
/* App sets a non-array "crit" AND also registers a name; the
* non-array value cannot be appended to and is reported. */
jwt_set_SET_STR(&jval, "crit", "foo");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
ret = jwt_builder_setcrit(builder, "foo");
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"\"crit\" header must be an array");
}
END_TEST
START_TEST(crit_appset_empty)
{
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);
jwt_set_SET_JSON(&jval, "crit", "[]");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"\"crit\" header must not be empty");
}
END_TEST
START_TEST(crit_appset_non_string)
{
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);
jwt_set_SET_JSON(&jval, "crit", "[123]");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"\"crit\" header entries must be strings");
}
END_TEST
START_TEST(crit_merge)
{
/* App-set "crit":["foo"] merges with setcrit("baz"). Array keeps the
* app entry first then the registered one: ["foo","baz"]. */
const char exp[] = "eyJhbGciOiJub25lIiwiYmF6IjoyLCJjcml0IjpbImZvbyIsImJh"
"eiJdLCJmb28iOiJiYXIifQ.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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
jwt_set_SET_JSON(&jval, "crit", "[\"foo\"]");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_STR(&jval, "foo", "bar");
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
jwt_set_SET_INT(&jval, "baz", 2);
ret = jwt_builder_header_set(builder, &jval);
ck_assert_int_eq(ret, 0);
ret = jwt_builder_setcrit(builder, "baz");
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(crit_setcrit_null)
{
jwt_builder_auto_t *builder = NULL;
int ret;
builder = jwt_builder_new();
ck_assert_ptr_nonnull(builder);
ret = jwt_builder_setcrit(NULL, "foo");
ck_assert_int_ne(ret, 0);
ret = jwt_builder_setcrit(builder, NULL);
ck_assert_int_ne(ret, 0);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"Must pass a header name");
jwt_builder_error_clear(builder);
ret = jwt_builder_setcrit(builder, "");
ck_assert_int_ne(ret, 0);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"Must pass a header name");
}
END_TEST
/* @rfc{7519,4.1.7} jti generation callback. */
static char *__jti_gen(const jwt_t *jwt, jwt_config_t *config)
{
ck_assert_ptr_nonnull(jwt);
ck_assert_ptr_nonnull(config);
ck_assert_str_eq(config->ctx, "pool");
return strdup("abc-123");
}
START_TEST(jti_gen)
{
/* {"alg":"none"} . {"jti":"abc-123"} . */
const char exp[] = "eyJhbGciOiJub25lIn0.eyJqdGkiOiJhYmMtMTIzIn0.";
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_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
ret = jwt_builder_setjti(builder, __jti_gen, "pool");
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_nonnull(out);
ck_assert_str_eq(out, exp);
}
END_TEST
static char *__jti_gen_null(const jwt_t *jwt, jwt_config_t *config)
{
(void)jwt;
(void)config;
return NULL;
}
START_TEST(jti_gen_fail)
{
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_setjti(builder, __jti_gen_null, NULL);
ck_assert_int_eq(ret, 0);
out = jwt_builder_generate(builder);
ck_assert_ptr_null(out);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"jti callback returned no id");
}
END_TEST
START_TEST(jti_setjti_null)
{
/* {"alg":"none"} . {} . — cleared cb means no jti is generated. */
const char exp[] = "eyJhbGciOiJub25lIn0.e30.";
jwt_builder_auto_t *builder = NULL;
char_auto *out = NULL;
int ret;
SET_OPS();
builder = jwt_builder_new();
ck_assert_ptr_nonnull(builder);
ret = jwt_builder_setjti(NULL, __jti_gen, "pool");
ck_assert_int_ne(ret, 0);
/* Setting ctx without a cb is an error. */
ret = jwt_builder_setjti(builder, NULL, "pool");
ck_assert_int_ne(ret, 0);
ck_assert_str_eq(jwt_builder_error_msg(builder),
"Setting ctx without a cb won't work");
jwt_builder_error_clear(builder);
/* Set then update ctx (NULL cb, non-NULL ctx) then clear (both NULL). */
ret = jwt_builder_setjti(builder, __jti_gen, "old");
ck_assert_int_eq(ret, 0);
ret = jwt_builder_setjti(builder, NULL, "pool");
ck_assert_int_eq(ret, 0);
ret = jwt_builder_setjti(builder, NULL, NULL);
ck_assert_int_eq(ret, 0);
/* Cleared: no jti is generated. */
ret = jwt_builder_enable_iat(builder, 0);
ck_assert_int_eq(ret, 1);
out = jwt_builder_generate(builder);
ck_assert_ptr_nonnull(out);
ck_assert_str_eq(out, 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("New");
tcase_add_loop_test(tc_core, new, 0, i);
tcase_set_timeout(tc_core, 60);
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);
tcase_add_loop_test(tc_core, set_alg, 0, i);
tcase_add_loop_test(tc_core, gen_ec_stress, 0, i);
tcase_set_timeout(tc_core, 120);
suite_add_tcase(s, tc_core);
tc_core = tcase_create("Error Handling");
tcase_add_loop_test(tc_core, null_handling, 0, i);
tcase_add_loop_test(tc_core, just_fail_wcb, 0, i);
tcase_add_loop_test(tc_core, sign_es256_bad_sig, 0, i);
tcase_set_timeout(tc_core, 60);
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_bits, 0, i);
tcase_add_loop_test(tc_core, gen_hs256_wcb, 0, i);
tcase_set_timeout(tc_core, 60);
suite_add_tcase(s, tc_core);
tc_core = tcase_create("Claims SetGetDel");
tcase_add_loop_test(tc_core, claim_str_setgetdel, 0, i);
tcase_add_loop_test(tc_core, claim_int_setgetdel, 0, i);
tcase_add_loop_test(tc_core, claim_bool_setgetdel, 0, i);
tcase_add_loop_test(tc_core, claim_json_setgetdel, 0, i);
tcase_set_timeout(tc_core, 60);
suite_add_tcase(s, tc_core);
tc_core = tcase_create("Header SetGetDel");
/* All of the code paths for str/int/bool/json have been covered. We
* just run this to ensure set/get/del works on headers */
tcase_add_loop_test(tc_core, header_str_setgetdel, 0, i);
tcase_set_timeout(tc_core, 60);
suite_add_tcase(s, tc_core);
tc_core = tcase_create("Crit Header");
tcase_add_loop_test(tc_core, crit_gen, 0, i);
tcase_add_loop_test(tc_core, crit_gen_two, 0, i);
tcase_add_loop_test(tc_core, crit_gen_not_in_header, 0, i);
tcase_add_loop_test(tc_core, crit_gen_registered, 0, i);
tcase_add_loop_test(tc_core, crit_gen_none, 0, i);
tcase_add_loop_test(tc_core, crit_gen_dup, 0, i);
tcase_add_loop_test(tc_core, crit_appset_valid, 0, i);
tcase_add_loop_test(tc_core, crit_appset_not_array, 0, i);
tcase_add_loop_test(tc_core, crit_appset_not_array_setcrit, 0, i);
tcase_add_loop_test(tc_core, crit_appset_empty, 0, i);
tcase_add_loop_test(tc_core, crit_appset_non_string, 0, i);
tcase_add_loop_test(tc_core, crit_merge, 0, i);
tcase_add_loop_test(tc_core, crit_setcrit_null, 0, i);
tcase_set_timeout(tc_core, 60);
suite_add_tcase(s, tc_core);
tc_core = tcase_create("JTI");
tcase_add_loop_test(tc_core, jti_gen, 0, i);
tcase_add_loop_test(tc_core, jti_gen_fail, 0, i);
tcase_add_loop_test(tc_core, jti_setjti_null, 0, i);
tcase_set_timeout(tc_core, 60);
suite_add_tcase(s, tc_core);
return s;
}
int main(void)
{
JWT_TEST_MAIN("LibJWT Builder");
}