diff --git a/ChangeLog b/ChangeLog index 3d3c71ea..3720ca3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +07/12/2023 +- add a sanity alg/enc check on self-encrypted AES GCM JWTs +- bump to 2.4.14.3rc0 + 06/05/2023 - avoid using encryption keys as signing keys for request objects and private_key_jwt token endpoint auth - log the first Redis error as a warning before retrying diff --git a/configure.ac b/configure.ac index 39e7e6ec..f2af2ab3 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([mod_auth_openidc],[2.4.14.2],[hans.zandbelt@openidc.com]) +AC_INIT([mod_auth_openidc],[2.4.14.3rc0],[hans.zandbelt@openidc.com]) AC_SUBST(NAMEVER, AC_PACKAGE_TARNAME()-AC_PACKAGE_VERSION()) diff --git a/src/mod_auth_openidc.h b/src/mod_auth_openidc.h index d7c3189e..d421e23a 100644 --- a/src/mod_auth_openidc.h +++ b/src/mod_auth_openidc.h @@ -701,7 +701,7 @@ void oidc_proto_state_set_timestamp_now(oidc_proto_state_t *proto_state); apr_byte_t oidc_proto_token_endpoint_auth(request_rec *r, oidc_cfg *cfg, const char *token_endpoint_auth, const char *client_id, const char *client_secret, const apr_array_header_t *client_keys, const char *audience, apr_table_t *params, const char *bearer_access_token, char **basic_auth_str, char **bearer_auth_str); -char *oidc_proto_peek_jwt_header(request_rec *r, const char *jwt, char **alg); +char *oidc_proto_peek_jwt_header(request_rec *r, const char *jwt, char **alg, char **enc); int oidc_proto_authorization_request(request_rec *r, struct oidc_provider_t *provider, const char *login_hint, const char *redirect_uri, const char *state, oidc_proto_state_t *proto_state, const char *id_token_hint, const char *code_challenge, const char *auth_request_params, const char *path_scope); apr_byte_t oidc_proto_is_post_authorization_response(request_rec *r, oidc_cfg *cfg); apr_byte_t oidc_proto_is_redirect_authorization_response(request_rec *r, oidc_cfg *cfg); diff --git a/src/oauth.c b/src/oauth.c index f0f79322..087305a5 100644 --- a/src/oauth.c +++ b/src/oauth.c @@ -575,7 +575,7 @@ static apr_byte_t oidc_oauth_validate_jwt_access_token(request_rec *r, oidc_cfg *c, const char *access_token, json_t **token, char **response) { oidc_debug(r, "enter: JWT access_token header=%s", - oidc_proto_peek_jwt_header(r, access_token, NULL)); + oidc_proto_peek_jwt_header(r, access_token, NULL, NULL)); oidc_jose_error_t err; oidc_jwk_t *jwk = NULL; diff --git a/src/proto.c b/src/proto.c index d0ecd153..37e7917b 100644 --- a/src/proto.c +++ b/src/proto.c @@ -464,7 +464,7 @@ char* oidc_proto_create_request_object(request_rec *r, json_decref(request_object_config); oidc_debug(r, "serialized request object JWT header = \"%s\"", - oidc_proto_peek_jwt_header(r, serialized_request_object, NULL)); + oidc_proto_peek_jwt_header(r, serialized_request_object, NULL, NULL)); oidc_debug(r, "serialized request object = \"%s\"", serialized_request_object); @@ -1635,7 +1635,7 @@ apr_byte_t oidc_proto_jwt_verify(request_rec *r, oidc_cfg *cfg, oidc_jwt_t *jwt, * return the compact-encoded JWT header contents */ char* oidc_proto_peek_jwt_header(request_rec *r, - const char *compact_encoded_jwt, char **alg) { + const char *compact_encoded_jwt, char **alg, char **enc) { char *input = NULL, *result = NULL; char *p = strstr(compact_encoded_jwt ? compact_encoded_jwt : "", "."); if (p == NULL) { @@ -1649,12 +1649,19 @@ char* oidc_proto_peek_jwt_header(request_rec *r, oidc_warn(r, "oidc_base64url_decode returned an error"); return NULL; } - if (alg) { + if ((alg != NULL) || (enc != NULL)) { json_t *json = NULL; oidc_util_decode_json_object(r, result, &json); - if (json) - *alg = apr_pstrdup(r->pool, - json_string_value(json_object_get(json, CJOSE_HDR_ALG))); + if (json) { + if (alg) + *alg = apr_pstrdup(r->pool, + json_string_value( + json_object_get(json, CJOSE_HDR_ALG))); + if (enc) + *enc = apr_pstrdup(r->pool, + json_string_value( + json_object_get(json, CJOSE_HDR_ENC))); + } json_decref(json); } return result; @@ -1669,7 +1676,7 @@ apr_byte_t oidc_proto_parse_idtoken(request_rec *r, oidc_cfg *cfg, char *alg = NULL; oidc_debug(r, "enter: id_token header=%s", - oidc_proto_peek_jwt_header(r, id_token, &alg)); + oidc_proto_peek_jwt_header(r, id_token, &alg, NULL)); apr_hash_t *decryption_keys = NULL; char buf[APR_RFC822_DATE_LEN + 1]; @@ -2170,7 +2177,7 @@ static apr_byte_t oidc_user_info_response_validate(request_rec *r, || (provider->userinfo_encrypted_response_alg != NULL) || (provider->userinfo_encrypted_response_enc != NULL)) { oidc_debug(r, "JWT header=%s", - oidc_proto_peek_jwt_header(r, *response, &alg)); + oidc_proto_peek_jwt_header(r, *response, &alg, NULL)); } oidc_jose_error_t err; diff --git a/src/util.c b/src/util.c index bf3f26e8..91b330c5 100644 --- a/src/util.c +++ b/src/util.c @@ -268,9 +268,18 @@ apr_byte_t oidc_util_jwt_verify(request_rec *r, const char *secret, char *plaintext = NULL; int plaintext_len = 0; + char *alg = NULL; + char *enc = NULL; + oidc_proto_peek_jwt_header(r, compact_encoded_jwt, &alg, &enc); + if ((_oidc_strcmp(alg, CJOSE_HDR_ALG_DIR) != 0) + || (_oidc_strcmp(enc, CJOSE_HDR_ENC_A256GCM) != 0)) { + oidc_error(r, "corrupted JWE header, alg=\"%s\" enc=\"%s\"", alg, enc); + goto end; + } + if (oidc_jwe_decrypt(r->pool, compact_encoded_jwt, keys, &plaintext, &plaintext_len, &err, FALSE) == FALSE) { - oidc_error(r, "decrypting JWT failed: %s", oidc_jose_e2s(r->pool, err)); + oidc_error(r, "decrypting JWE failed: %s", oidc_jose_e2s(r->pool, err)); goto end; }