Skip to content

Commit 3c0d4fa

Browse files
committed
checker/claims: Enabled nbf, exp, iss, aud, sub verification
Signed-off-by: Ben Collins <bcollins@libjwt.io>
1 parent 6774682 commit 3c0d4fa

File tree

6 files changed

+107
-5
lines changed

6 files changed

+107
-5
lines changed

include/jwt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ typedef enum {
253253
JWT_CLAIM_EXP = 0x0010, /**< @rfc_t{7519,4.1.4} ``"exp"`` */
254254
JWT_CLAIM_NBF = 0x0020, /**< @rfc_t{7519,4.1.5} ``"nbf"`` */
255255
JWT_CLAIM_IAT = 0x0040, /**< @rfc_t{7519,4.1.6} ``"iat"`` */
256-
JWT_CLAIM_JTI = 0x0080, /**< @rfc_t{7519,4.1.7} ``"nbf"`` */
256+
JWT_CLAIM_JTI = 0x0080, /**< @rfc_t{7519,4.1.7} ``"jti"`` */
257257
JWT_CLAIMS_ENFORCE = 0x8000, /**< Fail if claim is missing */
258258
JWT_CLAIMS_ALL = 0x80fe, /**< Mask of all claims */
259259
} jwt_claims_t;

libjwt/jwt-common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ int FUNC(verify)(jwt_common_t *__cmd, const char *token)
291291
return 1;
292292

293293
jwt->key = config.key;
294+
jwt->checker = __cmd;
294295

295296
/* Finish it up */
296297
jwt = jwt_verify_complete(jwt, &config, token, payload_len);

libjwt/jwt-private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ struct jwt {
8585
jwt_alg_t alg;
8686
int error;
8787
char error_msg[JWT_ERR_LEN];
88+
union {
89+
struct jwt_checker *checker;
90+
struct jwt_builder *builder;
91+
};
8892
};
8993

9094
struct jwk_set {

libjwt/jwt-verify.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,94 @@ int jwt_parse(jwt_t *jwt, const char *token, unsigned int *len)
127127
return 0;
128128
}
129129

130+
static int __check_str_claim(jwt_t *jwt, jwt_claims_t claim, char *claim_str)
131+
{
132+
jwt_checker_t *checker = jwt->checker;
133+
jwt_value_t jval;
134+
const char *str;
135+
jwt_value_error_t err;
136+
int enforce = checker->c.claims & JWT_CLAIMS_ENFORCE;
137+
int ret = 0;
138+
139+
if (checker->c.claims & claim) {
140+
jwt_set_GET_STR(&jval, claim_str);
141+
err = jwt_checker_claim_get(checker, &jval);
142+
str = jval.str_val;
143+
144+
if (err == JWT_VALUE_ERR_NONE) {
145+
jwt_set_GET_STR(&jval, claim_str);
146+
err = jwt_claim_get(jwt, &jval);
147+
}
148+
149+
if (err == JWT_VALUE_ERR_NONE) {
150+
if (strcmp(str, jval.str_val))
151+
ret = 1;
152+
} else if (enforce)
153+
ret = 1;
154+
}
155+
156+
return ret;
157+
}
158+
159+
static jwt_claims_t __verify_claims(jwt_t *jwt)
160+
{
161+
jwt_checker_t *checker = jwt->checker;
162+
jwt_value_t jval;
163+
time_t now = time(NULL);
164+
jwt_value_error_t err;
165+
int enforce = checker->c.claims & JWT_CLAIMS_ENFORCE;
166+
jwt_claims_t failed = 0;
167+
168+
/* expiration in past */
169+
if (checker->c.claims & JWT_CLAIM_EXP) {
170+
jwt_set_GET_INT(&jval, "exp");
171+
err = jwt_claim_get(jwt, &jval);
172+
173+
if (err == JWT_VALUE_ERR_NONE) {
174+
if (jval.int_val < now)
175+
failed |= JWT_CLAIM_EXP;
176+
} else if (enforce)
177+
failed |= JWT_CLAIM_EXP;
178+
}
179+
180+
/* not valid before now */
181+
if (checker->c.claims & JWT_CLAIM_NBF) {
182+
jwt_set_GET_INT(&jval, "nbf");
183+
err = jwt_claim_get(jwt, &jval);
184+
185+
if (err == JWT_VALUE_ERR_NONE) {
186+
if (jval.int_val > now)
187+
failed |= JWT_CLAIM_NBF;
188+
} else if (enforce)
189+
failed |= JWT_CLAIM_NBF;
190+
}
191+
192+
/* issuer doesn't match */
193+
if (__check_str_claim(jwt, JWT_CLAIM_ISS, "iss"))
194+
failed |= JWT_CLAIM_ISS;
195+
196+
/* subject doesn't match */
197+
if (__check_str_claim(jwt, JWT_CLAIM_SUB, "sub"))
198+
failed |= JWT_CLAIM_SUB;
199+
200+
/* audience doesn't match */
201+
if (__check_str_claim(jwt, JWT_CLAIM_AUD, "aud"))
202+
failed |= JWT_CLAIM_AUD;
203+
204+
return failed;
205+
}
206+
130207
/* This is after parsing and possibly a user callback. */
131208
static int __verify_config_post(jwt_t *jwt, const jwt_config_t *config,
132209
unsigned int sig_len)
133210
{
211+
/* Yes, we do this before checking a signature. */
212+
if (__verify_claims(jwt)) {
213+
/* TODO Pass back the ORd list of claims failed. */
214+
jwt_write_error(jwt, "Failed one or more claims");
215+
return 1;
216+
}
217+
134218
if (!sig_len) {
135219
if (config->key || config->alg != JWT_ALG_NONE ||
136220
jwt->alg != JWT_ALG_NONE) {

tests/jwt_builder.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,7 @@ END_TEST
397397

398398
START_TEST(claim_str_addgetdel)
399399
{
400-
const char exp[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJka"
401-
"XNrLnN3aXNzZGlzay5jb20ifQ.";
400+
const char exp[] = "eyJhbGciOiJub25lIn0.eyJzdWIiOiJteS1mcmllbmQifQ.";
402401
jwt_builder_auto_t *builder = NULL;
403402
char_auto *out = NULL;
404403
jwt_value_t jval;
@@ -413,7 +412,7 @@ START_TEST(claim_str_addgetdel)
413412
ret = jwt_builder_setclaims(builder, JWT_CLAIM_NONE);
414413
ck_assert_int_eq(ret, 0);
415414

416-
jwt_set_ADD_STR(&jval, "iss", "disk.swissdisk.com");
415+
jwt_set_ADD_STR(&jval, "sub", "my-friend");
417416
ret = jwt_builder_claim_add(builder, &jval);
418417
ck_assert_int_eq(ret, 0);
419418

tests/jwt_checker.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ START_TEST(verify_wcb)
116116
const char token[] = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJka"
117117
"XNrLnN3aXNzZGlzay5jb20ifQ.";
118118
jwt_checker_auto_t *checker = NULL;
119+
jwt_value_t jval;
119120
int ret;
120121

121122
SET_OPS();
@@ -124,7 +125,20 @@ START_TEST(verify_wcb)
124125
ck_assert_ptr_nonnull(checker);
125126
ck_assert_int_eq(jwt_checker_error(checker), 0);
126127

127-
ret = jwt_checker_setclaims(checker, JWT_CLAIM_NONE);
128+
ret = jwt_checker_setclaims(checker, JWT_CLAIM_AUD | JWT_CLAIM_SUB |
129+
JWT_CLAIM_ISS | JWT_CLAIM_NBF | JWT_CLAIM_EXP);
130+
ck_assert_int_eq(ret, 0);
131+
132+
jwt_set_ADD_STR(&jval, "sub", "my-friend");
133+
ret = jwt_checker_claim_add(checker, &jval);
134+
ck_assert_int_eq(ret, 0);
135+
136+
jwt_set_ADD_STR(&jval, "aud", "public");
137+
ret = jwt_checker_claim_add(checker, &jval);
138+
ck_assert_int_eq(ret, 0);
139+
140+
jwt_set_ADD_STR(&jval, "iss", "disk.swissdisk.com");
141+
ret = jwt_checker_claim_add(checker, &jval);
128142
ck_assert_int_eq(ret, 0);
129143

130144
ret = jwt_checker_setcb(checker, __verify_wcb, "testing");

0 commit comments

Comments
 (0)