/* * check the signature on a JWT against the provided keys */ static apr_byte_t apr_jws_verify_with_jwk(apr_pool_t *pool, apr_jwt_t *jwt, apr_jwk_t *jwk, apr_jwt_error_t *err) { apr_byte_t rc = FALSE; if (apr_jws_signature_is_hmac(pool, jwt)) { rc = (jwk->type == APR_JWK_KEY_OCT) && apr_jws_verify_hmac(pool, jwt, jwk, err); } else if (apr_jws_signature_is_rsa(pool, jwt)) { rc = (jwk->type == APR_JWK_KEY_RSA) && apr_jws_verify_rsa(pool, jwt, jwk, err); #if (OPENSSL_VERSION_NUMBER >= 0x01000000) } else if (apr_jws_signature_is_ec(pool, jwt)) { rc = (jwk->type == APR_JWK_KEY_EC) && apr_jws_verify_ec(pool, jwt, jwk, err); #endif } return rc; }
static char * test_jwt_parse(apr_pool_t *pool) { // from http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20 // 3.1. Example JWT char *s = apr_pstrdup(pool, "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9" \ ".eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ" \ ".dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"); apr_jwt_t *jwt = NULL; TST_ASSERT("apr_jwt_parse", apr_jwt_parse(pool, s, &jwt, NULL, NULL)); TST_ASSERT_STR("header.alg", jwt->header.alg, "HS256"); TST_ASSERT_STR("header.enc", jwt->header.enc, NULL); TST_ASSERT_STR("header.kid", jwt->header.kid, NULL); TST_ASSERT_STR("payload.iss", jwt->payload.iss, "joe"); TST_ASSERT_LONG("payload.exp", (long)apr_time_sec(jwt->payload.exp), 1300819380L); char *str_key = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"; char *raw_key = NULL; int raw_key_len = apr_jwt_base64url_decode(pool, &raw_key, str_key, 1); TST_ASSERT("apr_jws_verify_hmac", apr_jws_verify_hmac(pool, jwt, raw_key, raw_key_len)); s[5] = '.'; TST_ASSERT("corrupted header (1) apr_jwt_parse", apr_jwt_parse(pool, s, &jwt, NULL, NULL) == FALSE); s[0] = '\0'; TST_ASSERT("corrupted header (2) apr_jwt_parse", apr_jwt_parse(pool, s, &jwt, NULL, NULL) == FALSE); return 0; }
/* * verify the signature on an id_token */ apr_byte_t oidc_proto_idtoken_verify_signature(request_rec *r, oidc_cfg *cfg, oidc_provider_t *provider, apr_jwt_t *jwt, apr_byte_t *refresh) { apr_byte_t result = FALSE; if (apr_jws_signature_is_hmac(r->pool, jwt)) { oidc_debug(r, "verifying HMAC signature on id_token: header=%s, message=%s", jwt->header.value.str, jwt->message); result = apr_jws_verify_hmac(r->pool, jwt, provider->client_secret, strlen(provider->client_secret)); } else if (apr_jws_signature_is_rsa(r->pool, jwt) #if (OPENSSL_VERSION_NUMBER >= 0x01000000) || apr_jws_signature_is_ec(r->pool, jwt) #endif ) { /* get the key from the JWKs that corresponds with the key specified in the header */ apr_jwk_t *jwk = oidc_proto_get_key_from_jwk_uri(r, cfg, provider, &jwt->header, apr_jws_signature_is_rsa(r->pool, jwt) ? "RSA" : "EC", refresh); if (jwk != NULL) { oidc_debug(r, "verifying RSA/EC signature on id_token: header=%s, message=%s", jwt->header.value.str, jwt->message); result = apr_jws_signature_is_rsa(r->pool, jwt) ? apr_jws_verify_rsa(r->pool, jwt, jwk) : #if (OPENSSL_VERSION_NUMBER >= 0x01000000) apr_jws_verify_ec(r->pool, jwt, jwk); #else FALSE; #endif } else { oidc_warn(r, "could not find a key in the JSON Web Keys"); if (*refresh == FALSE) { oidc_debug(r, "force refresh of the JWKS"); /* do it again, forcing a JWKS refresh */ *refresh = TRUE; result = oidc_proto_idtoken_verify_signature(r, cfg, provider, jwt, refresh); } } } else { oidc_warn(r, "cannot verify id_token; unsupported algorithm \"%s\", must be RSA or HMAC", jwt->header.alg); } oidc_debug(r, "verification result of signature with algorithm \"%s\": %s", jwt->header.alg, (result == TRUE) ? "TRUE" : "FALSE"); return result; }