diff --git a/README.md b/README.md index f356151..0ddc7b6 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,11 @@ int main( int argc, char *argv[] ) const char *hs_key = "hs256-secret"; - rv = cjwt_decode( hs_text, strlen(hs_text), 0, (uint8_t*) hs_key, strlen(hs_key), 0, 0, &jwt ); + rv = cjwt_decode( hs_text, + strlen(hs_text), + OPT_ALLOW_ONLY_HS_ALG, + (uint8_t*) hs_key, + strlen(hs_key), 0, 0, &jwt ); if( CJWTE_OK != rv ) { printf( "There was an error processing the text: %d\n", rv ); return -1; diff --git a/include/cjwt/cjwt.h b/include/cjwt/cjwt.h index cfc1c99..0baf61d 100644 --- a/include/cjwt/cjwt.h +++ b/include/cjwt/cjwt.h @@ -38,6 +38,15 @@ */ #define OPT_ALLOW_ANY_TYP (1 << 2) +/* If you specify OPT_ALLOW_ONLY_HS_ALG as part of the options bitmask you + * are allowing only the use of HMAC-SHA algorithms (HS256, HS384, HS512). + * Otherwise only public key algorithms are allowed. + * + * Symmetric algorithms and the unknown key type passed in pose a security + * risk since an attacker can treate the provided public key as the secret + * key and sign their own JWTs with the public key as a symmetric key. + */ +#define OPT_ALLOW_ONLY_HS_ALG (1 << 3) /*----------------------------------------------------------------------------*/ /* Data Structures */ @@ -167,12 +176,22 @@ typedef struct { * are accepted unless OPT_ALLOW_ANY_TIME is specified as an option. * * @note The key for HS signed JWTs is the plain text secret. + * + * @note To accept HS signed JWTs, OPT_ALLOW_ONLY_HS_ALG must be specified as + * an option. This option disables the use of public key algorithms. + * This is done to prevent an attacker from using a public key as a + * symmetric key and signing their own JWTs. * * @note The key for PS, RS and EC signed JWTs expect the text from the PEM * file including the -----BEGIN PUBLIC KEY----- and * -----END PUBLIC KEY----- lines. * * @note The 'time' parameter is seconds since Jan 1, 1970. + * + * @note It is strongly encouraged to validate the 'alg' header to ensure + * that the JWT is signed with the expected algorithm. This can be + * done by checking the 'alg' header against a known value in the cjwt_t + * object passed out via the jwt parameter. * * @param text [IN] the original JWT text * @param text_len [IN] length of the original text diff --git a/src/cjwt.c b/src/cjwt.c index 57fe4d8..066ee3a 100644 --- a/src/cjwt.c +++ b/src/cjwt.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include #include #include @@ -22,6 +23,7 @@ /*----------------------------------------------------------------------------*/ struct alg_map { cjwt_alg_t alg; + bool symmetric; const char *text; }; @@ -29,19 +31,19 @@ struct alg_map { /* File Scoped Variables */ /*----------------------------------------------------------------------------*/ const struct alg_map the_alg_map[] = { - { .alg = alg_none, .text = "none"}, - {.alg = alg_es256, .text = "ES256"}, - {.alg = alg_es384, .text = "ES384"}, - {.alg = alg_es512, .text = "ES512"}, - {.alg = alg_hs256, .text = "HS256"}, - {.alg = alg_hs384, .text = "HS384"}, - {.alg = alg_hs512, .text = "HS512"}, - {.alg = alg_ps256, .text = "PS256"}, - {.alg = alg_ps384, .text = "PS384"}, - {.alg = alg_ps512, .text = "PS512"}, - {.alg = alg_rs256, .text = "RS256"}, - {.alg = alg_rs384, .text = "RS384"}, - {.alg = alg_rs512, .text = "RS512"} + {.alg = alg_none, .symmetric = false, .text = "none" }, + {.alg = alg_es256, .symmetric = false, .text = "ES256"}, + {.alg = alg_es384, .symmetric = false, .text = "ES384"}, + {.alg = alg_es512, .symmetric = false, .text = "ES512"}, + {.alg = alg_hs256, .symmetric = true, .text = "HS256"}, + {.alg = alg_hs384, .symmetric = true, .text = "HS384"}, + {.alg = alg_hs512, .symmetric = true, .text = "HS512"}, + {.alg = alg_ps256, .symmetric = false, .text = "PS256"}, + {.alg = alg_ps384, .symmetric = false, .text = "PS384"}, + {.alg = alg_ps512, .symmetric = false, .text = "PS512"}, + {.alg = alg_rs256, .symmetric = false, .text = "RS256"}, + {.alg = alg_rs384, .symmetric = false, .text = "RS384"}, + {.alg = alg_rs512, .symmetric = false, .text = "RS512"} }; /*----------------------------------------------------------------------------*/ @@ -243,12 +245,21 @@ static cjwt_code_t process_header_json(cjwt_t *cjwt, uint32_t options, return CJWTE_HEADER_UNSUPPORTED_ALG; } - if ((alg_none == cjwt->header.alg) - && (0 == (OPT_ALLOW_ALG_NONE & options))) - { - return CJWTE_HEADER_UNSUPPORTED_ALG; + if (alg_none == cjwt->header.alg) { + if (0 == (OPT_ALLOW_ALG_NONE & options)) { + return CJWTE_HEADER_UNSUPPORTED_ALG; + } } + if (true == the_alg_map[cjwt->header.alg].symmetric) { + if (!(OPT_ALLOW_ONLY_HS_ALG & options)) { + return CJWTE_HEADER_UNSUPPORTED_ALG; + } + } else { + if (OPT_ALLOW_ONLY_HS_ALG & options) { + return CJWTE_HEADER_UNSUPPORTED_ALG; + } + } typ = cJSON_GetObjectItemCaseSensitive(json, "typ"); if (typ && (0 == (OPT_ALLOW_ANY_TYP & options))) { diff --git a/subprojects/trower-base64.wrap b/subprojects/trower-base64.wrap index 187d944..af95074 100644 --- a/subprojects/trower-base64.wrap +++ b/subprojects/trower-base64.wrap @@ -8,5 +8,5 @@ source_filename = trower-base64-1.2.7.tar.gz source_url = https://github.com/xmidt-org/trower-base64/releases/download/v1.2.7/trower-base64-1.2.7.tar.gz source_hash = 9921ea1eca2328c6cadc058df805e6ac58cca06c0737ac21b987ba13b8697ad9 -[provides] +[provide] libtrower_base64 = libtrower_base64_dep diff --git a/tests/test_cjwt.c b/tests/test_cjwt.c index 0b03c4e..830e203 100644 --- a/tests/test_cjwt.c +++ b/tests/test_cjwt.c @@ -17,77 +17,78 @@ typedef struct { int expected; const char *jwt_file_name; bool is_key_in_file; + bool expect_symmetric; const char *key; const char *decode_test_name; } test_case_t; test_case_t test_list[] = { - { 0, "jwtn.txt", false, "", "No Alg claims on on"}, - { 0, "jwtnx.txt", false, "", "No Alg claims off on"}, - { 0, "jwtny.txt", false, "", "No Alg claims off off"}, - { EINVAL, "jwtia.txt", false, "test_passwd1", "HS256 invalid jwt"}, - { EINVAL, "jwtib.txt", false, "test_passwd1", "HS256 invalid jwt"}, - // { EINVAL, "jwtic.txt", false, "test_passwd1", "HS256 invalid jwt"}, /*TBD */ //FAILED test after modifying verify_signature logic - { EINVAL, "jwtid.txt", false, "test_passwd1", "HS256 invalid jwt"}, - { EINVAL, "jwtie.txt", false, "test_passwd1", "HS256 invalid jwt"}, - { EINVAL, "jwtif.txt", false, "test_passwd1", "HS256 invalid jwt"}, - { 0, "jwt1.txt", false, "test_passwd1", "HS256 claims on on"}, - { EINVAL, "jwt1.txt", false, "test_passbad", "HS256 claims on on"}, - { 0, "jwt2.txt", false, "test_passwd2", "HS384 claims on on"}, - { EINVAL, "jwt2.txt", false, "test_passbad", "HS384 claims on on"}, - { 0, "jwt3.txt", false, "test_passwd3", "HS512 claims on on"}, - { EINVAL, "jwt3.txt", false, "test_passbad", "HS512 claims on on"}, - { 0, "jwt5.txt", true, "pubkey5.pem", "RS384 claims on on"}, - { EINVAL, "jwt5.txt", true, "badkey4.pem", "RS384 claims on on"}, - { 0, "jwt4.txt", true, "pubkey4.pem", "RS256 claims on on"}, - { EINVAL, "jwt4.txt", true, "badkey4.pem", "RS256 claims on on"}, - { 0, "jwt6.txt", true, "pubkey6.pem", "RS512 claims on on"}, - { EINVAL, "jwt6.txt", true, "badkey6.pem", "RS512 claims on on"}, - { 0, "jwt1x.txt", false, "test_passwd1", "HS256 claims off on"}, - { EINVAL, "jwt1x.txt", false, "test_prasswd1", "HS256 claims off on"}, - { 0, "jwt2x.txt", false, "test_passwd2", "HS384 claims off on"}, - { EINVAL, "jwt2x.txt", false, "twest_passwd2", "HS384 claims off on"}, - { 0, "jwt3x.txt", false, "test_passwd3", "HS512 claims off on"}, - { EINVAL, "jwt3x.txt", false, "test_passwd3...", "HS512 claims off on"}, - { 0, "jwt4x.txt", true, "pubkey4.pem", "RS256 claims off on"}, - { EINVAL, "jwt4x.txt", true, "pubkey5.pem", "RS256 claims off on"}, - { 0, "jwt5x.txt", true, "pubkey5.pem", "RS384 claims off on"}, - { EINVAL, "jwt5x.txt", true, "badkey5.pem", "RS384 claims off on"}, - { 0, "jwt6x.txt", true, "pubkey6.pem", "RS512 claims off on"}, - { EINVAL, "jwt6x.txt", true, "badkey6.pem", "RS512 claims off on"}, - { 0, "jwt1y.txt", false, "test_passwd1", "HS256 claims off off"}, - { EINVAL, "jwt1y.txt", false, "tast_passwd1", "HS256 claims off off"}, - { 0, "jwt2y.txt", false, "test_passwd2", "HS384 claims off off"}, - { EINVAL, "jwt2y.txt", false, "test..passwd2", "HS384 claims off off"}, - { 0, "jwt3y.txt", false, "test_passwd3", "HS512 claims off off"}, - { EINVAL, "jwt3y.txt", false, "tteesstt_passwd3", "HS512 claims off off"}, - { 0, "jwt4y.txt", true, "pubkey4.pem", "RS256 claims off off"}, - { EINVAL, "jwt4y.txt", true, "badkey4.pem", "RS256 claims off off"}, - { 0, "jwt5y.txt", true, "pubkey5.pem", "RS384 claims off off"}, - { EINVAL, "jwt5y.txt", true, "pubkey6.pem", "RS384 claims off off"}, - { 0, "jwt6y.txt", true, "pubkey6.pem", "RS512 claims off off"}, - { EINVAL, "jwt6y.txt", true, "pubkey5.pem", "RS512 claims off off"}, - { 0, "jwt1l.txt", false, "test_passwd1", "HS256 claims long"}, - { EINVAL, "jwt1l.txt", false, "test_keyword1", "HS256 claims long"}, - { 0, "jwt2l.txt", false, "test_passwd2", "HS384 claims long"}, - { EINVAL, "jwt2l.txt", false, "test_passwd1", "HS384 claims long"}, - { 0, "jwt3l.txt", false, "test_passwd3", "HS512 claims long"}, - { EINVAL, "jwt3l.txt", false, "passwd3", "HS512 claims long"}, - { 0, "jwt4l.txt", true, "pubkey4.pem", "RS256 claims long"}, - { EINVAL, "jwt4l.txt", true, "badkey4.pem", "RS256 claims long"}, - { 0, "jwt5l.txt", true, "pubkey5.pem", "RS384 claims long"}, - { EINVAL, "jwt5l.txt", true, "badkey5.pem", "RS384 claims long"}, - { 0, "jwt6l.txt", true, "pubkey6.pem", "RS512 claims long"}, - { EINVAL, "jwt6l.txt", true, "badkey6.pem", "RS512 claims long"}, - { 0, "jwt2.txt", false, "test_passwd2", "HS384 claims on on"}, - { 0, "jwt3.txt", false, "test_passwd3", "HS512 claims on on"}, - { 0, "jwt8_hs256.txt", true, "key8_hs256.pem", "HS256 claims on on"}, - { 0, "jwt9_hs384.txt", true, "key9_hs384.pem", "HS384 claims on on"}, - { 0, "jwt10_hs512.txt", true, "key10_hs512.pem", "HS512 claims on on"}, - { EINVAL, "jwt11.txt", false, "incorrect_key", "RS256 claims all"}, - { EINVAL, "jwt12.txt", false, "incorrect_key", "RS256 claims all"}, - { EINVAL, "jwt13.txt", false, "incorrect_key", "RS256 claims all"}, - {ENOTSUP, "jwtbadalg.txt", false, "incorrect_key", "Invalid/unsupported alg."} + { 0, "jwtn.txt", false, false, "", "No Alg claims on on"}, + { 0, "jwtnx.txt", false, false, "", "No Alg claims off on"}, + { 0, "jwtny.txt", false, false, "", "No Alg claims off off"}, + { EINVAL, "jwtia.txt", false, true, "test_passwd1", "HS256 invalid jwt"}, + { EINVAL, "jwtib.txt", false, true, "test_passwd1", "HS256 invalid jwt"}, + // { EINVAL, "jwtic.txt", false, true, "test_passwd1", "HS256 invalid jwt"}, /*TBD */ //FAILED test after modifying verify_signature logic + { EINVAL, "jwtid.txt", false, true, "test_passwd1", "HS256 invalid jwt"}, + { EINVAL, "jwtie.txt", false, true, "test_passwd1", "HS256 invalid jwt"}, + { EINVAL, "jwtif.txt", false, true, "test_passwd1", "HS256 invalid jwt"}, + { 0, "jwt1.txt", false, true, "test_passwd1", "HS256 claims on on"}, + { EINVAL, "jwt1.txt", false, true, "test_passbad", "HS256 claims on on"}, + { 0, "jwt2.txt", false, true, "test_passwd2", "HS384 claims on on"}, + { EINVAL, "jwt2.txt", false, true, "test_passbad", "HS384 claims on on"}, + { 0, "jwt3.txt", false, true, "test_passwd3", "HS512 claims on on"}, + { EINVAL, "jwt3.txt", false, true, "test_passbad", "HS512 claims on on"}, + { 0, "jwt5.txt", true, false, "pubkey5.pem", "RS384 claims on on"}, + { EINVAL, "jwt5.txt", true, false, "badkey4.pem", "RS384 claims on on"}, + { 0, "jwt4.txt", true, false, "pubkey4.pem", "RS256 claims on on"}, + { EINVAL, "jwt4.txt", true, false, "badkey4.pem", "RS256 claims on on"}, + { 0, "jwt6.txt", true, false, "pubkey6.pem", "RS512 claims on on"}, + { EINVAL, "jwt6.txt", true, false, "badkey6.pem", "RS512 claims on on"}, + { 0, "jwt1x.txt", false, true, "test_passwd1", "HS256 claims off on"}, + { EINVAL, "jwt1x.txt", false, true, "test_prasswd1", "HS256 claims off on"}, + { 0, "jwt2x.txt", false, true, "test_passwd2", "HS384 claims off on"}, + { EINVAL, "jwt2x.txt", false, true, "twest_passwd2", "HS384 claims off on"}, + { 0, "jwt3x.txt", false, true, "test_passwd3", "HS512 claims off on"}, + { EINVAL, "jwt3x.txt", false, true, "test_passwd3...", "HS512 claims off on"}, + { 0, "jwt4x.txt", true, false, "pubkey4.pem", "RS256 claims off on"}, + { EINVAL, "jwt4x.txt", true, false, "pubkey5.pem", "RS256 claims off on"}, + { 0, "jwt5x.txt", true, false, "pubkey5.pem", "RS384 claims off on"}, + { EINVAL, "jwt5x.txt", true, false, "badkey5.pem", "RS384 claims off on"}, + { 0, "jwt6x.txt", true, false, "pubkey6.pem", "RS512 claims off on"}, + { EINVAL, "jwt6x.txt", true, false, "badkey6.pem", "RS512 claims off on"}, + { 0, "jwt1y.txt", false, true, "test_passwd1", "HS256 claims off off"}, + { EINVAL, "jwt1y.txt", false, true, "tast_passwd1", "HS256 claims off off"}, + { 0, "jwt2y.txt", false, true, "test_passwd2", "HS384 claims off off"}, + { EINVAL, "jwt2y.txt", false, true, "test..passwd2", "HS384 claims off off"}, + { 0, "jwt3y.txt", false, true, "test_passwd3", "HS512 claims off off"}, + { EINVAL, "jwt3y.txt", false, true, "tteesstt_passwd3", "HS512 claims off off"}, + { 0, "jwt4y.txt", true, false, "pubkey4.pem", "RS256 claims off off"}, + { EINVAL, "jwt4y.txt", true, false, "badkey4.pem", "RS256 claims off off"}, + { 0, "jwt5y.txt", true, false, "pubkey5.pem", "RS384 claims off off"}, + { EINVAL, "jwt5y.txt", true, false, "pubkey6.pem", "RS384 claims off off"}, + { 0, "jwt6y.txt", true, false, "pubkey6.pem", "RS512 claims off off"}, + { EINVAL, "jwt6y.txt", true, false, "pubkey5.pem", "RS512 claims off off"}, + { 0, "jwt1l.txt", false, true, "test_passwd1", "HS256 claims long"}, + { EINVAL, "jwt1l.txt", false, true, "test_keyword1", "HS256 claims long"}, + { 0, "jwt2l.txt", false, true, "test_passwd2", "HS384 claims long"}, + { EINVAL, "jwt2l.txt", false, true, "test_passwd1", "HS384 claims long"}, + { 0, "jwt3l.txt", false, true, "test_passwd3", "HS512 claims long"}, + { EINVAL, "jwt3l.txt", false, true, "passwd3", "HS512 claims long"}, + { 0, "jwt4l.txt", true, false, "pubkey4.pem", "RS256 claims long"}, + { EINVAL, "jwt4l.txt", true, false, "badkey4.pem", "RS256 claims long"}, + { 0, "jwt5l.txt", true, false, "pubkey5.pem", "RS384 claims long"}, + { EINVAL, "jwt5l.txt", true, false, "badkey5.pem", "RS384 claims long"}, + { 0, "jwt6l.txt", true, false, "pubkey6.pem", "RS512 claims long"}, + { EINVAL, "jwt6l.txt", true, false, "badkey6.pem", "RS512 claims long"}, + { 0, "jwt2.txt", false, true, "test_passwd2", "HS384 claims on on"}, + { 0, "jwt3.txt", false, true, "test_passwd3", "HS512 claims on on"}, + { 0, "jwt8_hs256.txt", true, true, "key8_hs256.pem", "HS256 claims on on"}, + { 0, "jwt9_hs384.txt", true, true, "key9_hs384.pem", "HS384 claims on on"}, + { 0, "jwt10_hs512.txt", true, true, "key10_hs512.pem", "HS512 claims on on"}, + { EINVAL, "jwt11.txt", false, false, "incorrect_key", "RS256 claims all"}, + { EINVAL, "jwt12.txt", false, false, "incorrect_key", "RS256 claims all"}, + { EINVAL, "jwt13.txt", false, false, "incorrect_key", "RS256 claims all"}, + {ENOTSUP, "jwtbadalg.txt", false, false, "incorrect_key", "Invalid/unsupported alg."} }; #define _NUM_TEST_CASES (sizeof(test_list) / sizeof(test_case_t)) @@ -154,11 +155,13 @@ void test_case(unsigned _i) cjwt_t *jwt = NULL; char jwt_buf[65535]; char pem_buf[8192]; + int options; jwt_fname = test_list[_i].jwt_file_name; key_str = test_list[_i].key; key_len = strlen(key_str); expected = test_list[_i].expected; decode_test_name = test_list[_i].decode_test_name; + options = OPT_ALLOW_ALG_NONE | OPT_ALLOW_ANY_TIME; if (key_len == 0) { key_str = NULL; @@ -188,8 +191,11 @@ void test_case(unsigned _i) jwt_bytes = read_file(jwt_fname, jwt_buf, sizeof(jwt_buf)); if (jwt_bytes > 0) { + if (test_list[_i].expect_symmetric) { + options |= OPT_ALLOW_ONLY_HS_ALG; + } result = cjwt_decode(jwt_buf, strlen(jwt_buf), - OPT_ALLOW_ALG_NONE | OPT_ALLOW_ANY_TIME, + options, (const uint8_t *) key_str, key_len, 0, 0, &jwt); } else { diff --git a/tests/test_cjwt_new.c b/tests/test_cjwt_new.c index 9084ef9..a01f5a2 100644 --- a/tests/test_cjwt_new.c +++ b/tests/test_cjwt_new.c @@ -20,6 +20,7 @@ typedef struct { const char *filename; const char *key_fn; const char *key; + uint32_t options; cjwt_code_t expected; } test_case_t; @@ -37,75 +38,87 @@ typedef struct { test_case_t test_list[] = { /* Valid, positive tests */ /*------------------------------------------------------------------------*/ - { "HS256", "hs256.jwt", NULL, "hs256-secret", CJWTE_OK }, - { "HS384", "hs384.jwt", NULL, "hs384-secret", CJWTE_OK }, - { "HS512", "hs512.jwt", NULL, "hs512-secret", CJWTE_OK }, - { "RS256", "rs256.jwt", "rs.pub", NULL, CJWTE_OK }, - { "RS384", "rs384.jwt", "rs.pub", NULL, CJWTE_OK }, - { "RS512", "rs512.jwt", "rs.pub", NULL, CJWTE_OK }, - { "ES256", "es256.jwt", "es256.jwt.pub", NULL, CJWTE_OK }, - { "ES384", "es384.jwt", "es384.jwt.pub", NULL, CJWTE_OK }, - { "ES512", "es512.jwt", "es512.jwt.pub", NULL, CJWTE_OK }, - { "PS256", "ps256.jwt", "ps.pub", NULL, CJWTE_OK }, - { "PS384", "ps384.jwt", "ps.pub", NULL, CJWTE_OK }, - { "PS512", "ps512.jwt", "ps.pub", NULL, CJWTE_OK }, + { "HS256", "hs256.jwt", NULL, "hs256-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_OK }, + { "HS384", "hs384.jwt", NULL, "hs384-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_OK }, + { "HS512", "hs512.jwt", NULL, "hs512-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_OK }, + { "RS256", "rs256.jwt", "rs.pub", NULL, 0, CJWTE_OK }, + { "RS384", "rs384.jwt", "rs.pub", NULL, 0, CJWTE_OK }, + { "RS512", "rs512.jwt", "rs.pub", NULL, 0, CJWTE_OK }, + { "ES256", "es256.jwt", "es256.jwt.pub", NULL, 0, CJWTE_OK }, + { "ES384", "es384.jwt", "es384.jwt.pub", NULL, 0, CJWTE_OK }, + { "ES512", "es512.jwt", "es512.jwt.pub", NULL, 0, CJWTE_OK }, + { "PS256", "ps256.jwt", "ps.pub", NULL, 0, CJWTE_OK }, + { "PS384", "ps384.jwt", "ps.pub", NULL, 0, CJWTE_OK }, + { "PS512", "ps512.jwt", "ps.pub", NULL, 0, CJWTE_OK }, /* Negative tests around signature validation */ /*------------------------------------------------------------------------*/ - { "HS256 bad secret", "hs256.jwt", NULL, "hs000-secret", CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "HS384 bad secret", "hs384.jwt", NULL, "hs000-secret", CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "HS512 bad secret", "hs512.jwt", NULL, "hs000-secret", CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "HS256 NULL secret", "hs256.jwt", NULL, NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "HS384 NULL secret", "hs384.jwt", NULL, NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "HS512 NULL secret", "hs512.jwt", NULL, NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - - { "RS256 bad secret", "rs256.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "RS384 bad secret", "rs384.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "RS512 bad secret", "rs512.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "RS256 partial", "rs256.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "RS384 partial", "rs384.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "RS512 partial", "rs512.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "RS256 invalid", "rs256.jwt", "es256.jwt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "RS384 invalid", "rs384.jwt", "es256.jwt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "RS512 invalid", "rs512.jwt", "es256.jwt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "RS256 NULL secret", "rs256.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - { "RS384 NULL secret", "rs384.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - { "RS512 NULL secret", "rs512.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - - { "PS256 bad secret", "ps256.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "PS384 bad secret", "ps384.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "PS512 bad secret", "ps512.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "PS256 partial", "ps256.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "PS384 partial", "ps384.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "PS512 partial", "ps512.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "PS256 invalid", "ps256.jwt", "es256.jwt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "PS384 invalid", "ps384.jwt", "es256.jwt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "PS512 invalid", "ps512.jwt", "es256.jwt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "PS256 NULL secret", "ps256.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - { "PS384 NULL secret", "ps384.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - { "PS512 NULL secret", "ps512.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - - { "ES256 bad secret", "es256.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "ES384 bad secret", "es384.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "ES512 bad secret", "es512.jwt", "rs-alt.pub", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "ES256 partial", "es256.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "ES384 partial", "es384.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "ES512 partial", "es512.jwt", "rs.partial", NULL, CJWTE_SIGNATURE_INVALID_KEY }, - { "ES256 invalid", "es256.jwt", "es512.jwt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "ES384 invalid", "es384.jwt", "es512.jwt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "ES512 invalid", "es512.jwt", "es256.jwt.pub", NULL, CJWTE_SIGNATURE_VALIDATION_FAILED }, - { "ES256 NULL secret", "es256.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - { "ES384 NULL secret", "es384.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, - { "ES512 NULL secret", "es512.jwt", NULL, NULL, CJWTE_SIGNATURE_MISSING_KEY }, + { "HS256 bad secret", "hs256.jwt", NULL, "hs000-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "HS384 bad secret", "hs384.jwt", NULL, "hs000-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "HS512 bad secret", "hs512.jwt", NULL, "hs000-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "HS256 NULL secret", "hs256.jwt", NULL, NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "HS384 NULL secret", "hs384.jwt", NULL, NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "HS512 NULL secret", "hs512.jwt", NULL, NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "HS256 not allowed", "hs256.jwt", NULL, "hs256-secret", 0, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "HS384 not allowed", "hs384.jwt", NULL, "hs384-secret", 0, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "HS512 not allowed", "hs512.jwt", NULL, "hs512-secret", 0, CJWTE_HEADER_UNSUPPORTED_ALG }, + + { "RS256 bad secret", "rs256.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "RS384 bad secret", "rs384.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "RS512 bad secret", "rs512.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "RS256 partial", "rs256.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "RS384 partial", "rs384.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "RS512 partial", "rs512.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "RS256 invalid", "rs256.jwt", "es256.jwt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "RS384 invalid", "rs384.jwt", "es256.jwt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "RS512 invalid", "rs512.jwt", "es256.jwt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "RS256 NULL secret", "rs256.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "RS384 NULL secret", "rs384.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "RS512 NULL secret", "rs512.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "RS256 not allowed", "rs256.jwt", "rs.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "RS384 not allowed", "rs384.jwt", "rs.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "RS512 not allowed", "rs512.jwt", "rs.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + + { "PS256 bad secret", "ps256.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "PS384 bad secret", "ps384.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "PS512 bad secret", "ps512.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "PS256 partial", "ps256.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "PS384 partial", "ps384.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "PS512 partial", "ps512.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "PS256 invalid", "ps256.jwt", "es256.jwt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "PS384 invalid", "ps384.jwt", "es256.jwt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "PS512 invalid", "ps512.jwt", "es256.jwt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "PS256 NULL secret", "ps256.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "PS384 NULL secret", "ps384.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "PS512 NULL secret", "ps512.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "PS256 not allowed", "ps256.jwt", "ps.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "PS384 not allowed", "ps384.jwt", "ps.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "PS512 not allowed", "ps512.jwt", "ps.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + + { "ES256 bad secret", "es256.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "ES384 bad secret", "es384.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "ES512 bad secret", "es512.jwt", "rs-alt.pub", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "ES256 partial", "es256.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "ES384 partial", "es384.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "ES512 partial", "es512.jwt", "rs.partial", NULL, 0, CJWTE_SIGNATURE_INVALID_KEY }, + { "ES256 invalid", "es256.jwt", "es512.jwt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "ES384 invalid", "es384.jwt", "es512.jwt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "ES512 invalid", "es512.jwt", "es256.jwt.pub", NULL, 0, CJWTE_SIGNATURE_VALIDATION_FAILED }, + { "ES256 NULL secret", "es256.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "ES384 NULL secret", "es384.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "ES512 NULL secret", "es512.jwt", NULL, NULL, 0, CJWTE_SIGNATURE_MISSING_KEY }, + { "ES256 not allowed", "es256.jwt", "es256.jwt.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "ES384 not allowed", "es384.jwt", "es384.jwt.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, + { "ES512 not allowed", "es512.jwt", "es512.jwt.pub", NULL, OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_UNSUPPORTED_ALG }, /* These are some nefarious focused tests */ - { "Try 5 section", "try_5.inv", NULL, "hs256-secret", CJWTE_INVALID_SECTIONS }, - { "Try 4 section", "try_4.inv", NULL, "hs256-secret", CJWTE_INVALID_SECTIONS }, - { "Try 2 section", "try_2.inv", NULL, "hs256-secret", CJWTE_INVALID_SECTIONS }, - { "Try 1 section", "try_1.inv", NULL, "hs256-secret", CJWTE_HEADER_MISSING }, + { "Try 5 section", "try_5.inv", NULL, "hs256-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_INVALID_SECTIONS }, + { "Try 4 section", "try_4.inv", NULL, "hs256-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_INVALID_SECTIONS }, + { "Try 2 section", "try_2.inv", NULL, "hs256-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_INVALID_SECTIONS }, + { "Try 1 section", "try_1.inv", NULL, "hs256-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_MISSING }, - { "Invld b64 header", "hdr_b64.inv", NULL, "hs256-secret", CJWTE_HEADER_INVALID_BASE64 }, - { "Invld b64 sig", "sig_b64.inv", NULL, "hs256-secret", CJWTE_SIGNATURE_INVALID_BASE64 }, + { "Invld b64 header", "hdr_b64.inv", NULL, "hs256-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_HEADER_INVALID_BASE64 }, + { "Invld b64 sig", "sig_b64.inv", NULL, "hs256-secret", OPT_ALLOW_ONLY_HS_ALG, CJWTE_SIGNATURE_INVALID_BASE64 }, }; json_test_case_t json_test_list[] = { @@ -704,7 +717,7 @@ void test_case(const test_case_t *t) while (isspace(jwt_buf[jwt_bytes - 1])) { jwt_bytes--; } - result = cjwt_decode(jwt_buf, jwt_bytes, 0, key, key_len, 0, 0, &jwt); + result = cjwt_decode(jwt_buf, jwt_bytes, t->options, key, key_len, 0, 0, &jwt); } else { result = jwt_bytes; }