From: Marco Bettini Date: Mon, 21 Feb 2022 11:48:26 +0000 (+0100) Subject: lib-oauth2: get_time_field() - Fix accepting JWT tokens containing decimal parts... X-Git-Tag: 2.4.0~4303 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bb76d60849c5b0c32c3a06cf471962d4948926bb;p=thirdparty%2Fdovecot%2Fcore.git lib-oauth2: get_time_field() - Fix accepting JWT tokens containing decimal parts in NumericDate fields --- diff --git a/src/lib-oauth2/oauth2-jwt.c b/src/lib-oauth2/oauth2-jwt.c index ec7ad46d4a..8444aa6122 100644 --- a/src/lib-oauth2/oauth2-jwt.c +++ b/src/lib-oauth2/oauth2-jwt.c @@ -20,13 +20,16 @@ #include -static const char *get_field(const struct json_tree *tree, const char *key) +static const char *get_field(const struct json_tree *tree, const char *key, + enum json_type *type_r) { const struct json_tree_node *root = json_tree_root(tree); const struct json_tree_node *value_node = json_tree_find_key(root, key); if (value_node == NULL || value_node->value_type == JSON_TYPE_OBJECT || value_node->value_type == JSON_TYPE_ARRAY) return NULL; + if (type_r != NULL) + *type_r = value_node->value_type; return json_tree_get_value_str(value_node); } @@ -34,11 +37,22 @@ static int get_time_field(const struct json_tree *tree, const char *key, int64_t *value_r) { time_t tvalue; - const char *value = get_field(tree, key); + enum json_type value_type; + const char *value = get_field(tree, key, &value_type); + int tz_offset ATTR_UNUSED; if (value == NULL) return 0; - if (str_to_int64(value, value_r) == 0) { + if (value_type == JSON_TYPE_NUMBER) { + /* Parse with atof() to handle the json valid exponential formats, + but discard the decimal part of the fields as we are not + interested in them. + + The worst case of x.99999 would appear as almost a second older + than the actual x which is same as saying we processed it a + second later for the purpose of JWT tokens */ + double v = atof(value); + *value_r = (int64_t) v; if (*value_r < 0) return -1; return 1; @@ -322,9 +336,9 @@ static int oauth2_jwt_header_process(struct json_tree *tree, const char **alg_r, const char **kid_r, const char **error_r) { - const char *typ = get_field(tree, "typ"); - const char *alg = get_field(tree, "alg"); - const char *kid = get_field(tree, "kid"); + const char *typ = get_field(tree, "typ", NULL); + const char *alg = get_field(tree, "alg", NULL); + const char *kid = get_field(tree, "kid", NULL); if (null_strcmp(typ, "JWT") != 0) { *error_r = "Cannot find 'typ' field"; @@ -349,7 +363,7 @@ oauth2_jwt_body_process(const struct oauth2_settings *set, const char *alg, struct json_tree *tree, const char *const *blobs, const char **error_r) { - const char *sub = get_field(tree, "sub"); + const char *sub = get_field(tree, "sub", NULL); int ret; int64_t t0 = time(NULL); @@ -400,7 +414,7 @@ oauth2_jwt_body_process(const struct oauth2_settings *set, const char *alg, return -1; } - const char *iss = get_field(tree, "iss"); + const char *iss = get_field(tree, "iss", NULL); if (set->issuers != NULL && *set->issuers != NULL) { if (iss == NULL) { *error_r = "Token is missing 'iss' field"; @@ -414,7 +428,7 @@ oauth2_jwt_body_process(const struct oauth2_settings *set, const char *alg, } /* see if there is azp */ - const char *azp = get_field(tree, "azp"); + const char *azp = get_field(tree, "azp", NULL); if (azp == NULL) azp = "default"; else diff --git a/src/lib-oauth2/test-oauth2-jwt.c b/src/lib-oauth2/test-oauth2-jwt.c index 890712e48d..0f17593c84 100644 --- a/src/lib-oauth2/test-oauth2-jwt.c +++ b/src/lib-oauth2/test-oauth2-jwt.c @@ -138,9 +138,10 @@ static buffer_t *create_jwt_token_kid(const char *algo, const char *kid) /* body */ base64url_encode_str( + /* decimals injected to excercise the JSON number parser */ t_strdup_printf("{\"sub\":\"testuser\","\ "\"iat\":%"PRIdTIME_T"," - "\"exp\":%"PRIdTIME_T"}", + "\"exp\":%"PRIdTIME_T".000E+0}", time(NULL), time(NULL)+600), tokenbuf); return tokenbuf; @@ -159,9 +160,10 @@ static buffer_t *create_jwt_token(const char *algo) /* body */ base64url_encode_str( + /* decimals injected to excercise the JSON number parser */ t_strdup_printf("{\"sub\":\"testuser\","\ "\"iat\":%"PRIdTIME_T"," - "\"exp\":%"PRIdTIME_T"}", + "\"exp\":%"PRIdTIME_T".000E+0}", time(NULL), time(NULL)+600), tokenbuf); return tokenbuf; @@ -662,8 +664,9 @@ static void test_jwt_dates(void) base64url_encode_str("{\"alg\":\"HS256\",\"typ\":\"JWT\"}", tokenbuf); str_append_c(tokenbuf, '.'); base64url_encode_str(t_strdup_printf("{\"sub\":\"testuser\"," + "\"nbf\":0," "\"exp\":%"PRIdTIME_T"," - "\"nbf\":0,\"iat\":%"PRIdTIME_T"}", + "\"iat\":%"PRIdTIME_T".000E+0}", exp, iat), tokenbuf); sign_jwt_token_hs256(tokenbuf, hs_sign_key);