/* * parse an EC JWK */ static apr_byte_t apr_jwk_parse_ec(apr_pool_t *pool, apr_jwk_t *jwk) { /* allocated space and set key type */ jwk->type = APR_JWK_KEY_EC; jwk->key.ec = apr_pcalloc(pool, sizeof(apr_jwk_key_ec_t)); /* parse x */ char *s_x = NULL; apr_jwt_get_string(pool, &jwk->value, "x", &s_x); if (s_x == NULL) return FALSE; /* parse x size */ jwk->key.ec->x_len = apr_jwt_base64url_decode(pool, (char **) &jwk->key.ec->x, s_x, 1); /* parse y */ char *s_y = NULL; apr_jwt_get_string(pool, &jwk->value, "y", &s_y); if (s_y == NULL) return FALSE; /* parse y size */ jwk->key.ec->y_len = apr_jwt_base64url_decode(pool, (char **) &jwk->key.ec->y, s_y, 1); /* that went well */ return TRUE; }
/* * parse an RSA JWK in raw format (n,e,d) */ static apr_byte_t apr_jwk_parse_rsa_raw(apr_pool_t *pool, json_t *json, apr_jwk_key_rsa_t **jwk_key_rsa, apr_jwt_error_t *err) { /* allocate space */ *jwk_key_rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t)); apr_jwk_key_rsa_t *key = *jwk_key_rsa; /* parse the mandatory modulus */ char *s_modulus = NULL; if (apr_jwt_get_string(pool, json, "n", TRUE, &s_modulus, err) == FALSE) return FALSE; /* base64url decode the modulus and get its size */ key->modulus_len = apr_jwt_base64url_decode(pool, (char **) &key->modulus, s_modulus, 1); if (key->modulus_len <= 0) { apr_jwt_error(err, "apr_jwt_base64url_decode of modulus failed"); return FALSE; } /* parse the mandatory exponent */ char *s_exponent = NULL; if (apr_jwt_get_string(pool, json, "e", TRUE, &s_exponent, err) == FALSE) return FALSE; /* base64url decode the exponent and get its size */ key->exponent_len = apr_jwt_base64url_decode(pool, (char **) &key->exponent, s_exponent, 1); if (key->exponent_len <= 0) { apr_jwt_error(err, "apr_jwt_base64url_decode of exponent failed"); return FALSE; } /* parse the optional private exponent */ char *s_private_exponent = NULL; apr_jwt_get_string(pool, json, "d", FALSE, &s_private_exponent, NULL); if (s_private_exponent != NULL) { /* base64url decode the private exponent and get its size */ key->private_exponent_len = apr_jwt_base64url_decode(pool, (char **) &key->private_exponent, s_private_exponent, 1); if (key->private_exponent_len <= 0) { apr_jwt_error(err, "apr_jwt_base64url_decode of private exponent failed"); return FALSE; } } /* that went well */ return TRUE; }
/* * parse JSON object from string in to JWT value */ static apr_byte_t apr_jwt_base64url_decode_object(apr_pool_t *pool, const char *str, apr_jwt_value_t *value, apr_jwt_error_t *err) { /* base64url-decode the string representation into value->str */ if (apr_jwt_base64url_decode(pool, &value->str, str, 1) <= 0) { apr_jwt_error(err, "apr_jwt_base64url_decode of (%s) failed", str); return FALSE; } /* decode the string in to a JSON structure into value->json */ json_error_t json_error; value->json = json_loads(value->str, 0, &json_error); /* check that we've actually got a JSON value back */ if (value->json == NULL) { apr_jwt_error(err, "JSON parsing (json_loads) failed: %s (%s)", json_error.text, value->str); return FALSE; } /* check that the value is a JSON object */ if (!json_is_object(value->json)) { apr_jwt_error(err, "JSON value is not an object"); return FALSE; } return TRUE; }
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; }
/* * parse JWT signature */ static apr_byte_t apr_jwt_parse_signature(apr_pool_t *pool, const char *s_signature, apr_jwt_signature_t *signature) { signature->length = apr_jwt_base64url_decode(pool, (char **) &signature->bytes, s_signature, 1); return (signature->length > 0); }
/* * parse an RSA JWK in raw format (n,e,d) */ static apr_byte_t apr_jwk_parse_rsa_raw(apr_pool_t *pool, apr_jwt_value_t *jwk, apr_jwk_key_rsa_t **jwk_key_rsa) { /* allocate space */ *jwk_key_rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t)); apr_jwk_key_rsa_t *key = *jwk_key_rsa; /* parse the modulus */ char *s_modulus = NULL; apr_jwt_get_string(pool, jwk, "n", &s_modulus); if (s_modulus == NULL) return FALSE; /* parse the modulus size */ key->modulus_len = apr_jwt_base64url_decode(pool, (char **) &key->modulus, s_modulus, 1); /* parse the exponent */ char *s_exponent = NULL; apr_jwt_get_string(pool, jwk, "e", &s_exponent); if (s_exponent == NULL) return FALSE; /* parse the exponent size */ key->exponent_len = apr_jwt_base64url_decode(pool, (char **) &key->exponent, s_exponent, 1); /* parse the private exponent */ char *s_private_exponent = NULL; apr_jwt_get_string(pool, jwk, "d", &s_private_exponent); if (s_private_exponent != NULL) { /* parse the private exponent size */ key->private_exponent_len = apr_jwt_base64url_decode(pool, (char **) &key->private_exponent, s_private_exponent, 1); } /* that went well */ return TRUE; }
/* * parse an EC JWK */ static apr_byte_t apr_jwk_parse_ec(apr_pool_t *pool, json_t *json, apr_jwk_t *jwk, apr_jwt_error_t *err) { /* allocated space and set key type */ jwk->type = APR_JWK_KEY_EC; jwk->key.ec = apr_pcalloc(pool, sizeof(apr_jwk_key_ec_t)); /* parse x */ char *s_x = NULL; if (apr_jwt_get_string(pool, json, "x", TRUE, &s_x, err) == FALSE) return FALSE; /* base64url decode x and get its size */ jwk->key.ec->x_len = apr_jwt_base64url_decode(pool, (char **) &jwk->key.ec->x, s_x, 1); if (jwk->key.ec->x_len <= 0) { apr_jwt_error(err, "apr_jwt_base64url_decode of x length failed"); return FALSE; } /* parse y */ char *s_y = NULL; if (apr_jwt_get_string(pool, json, "y", TRUE, &s_y, err) == FALSE) return FALSE; /* base64url decode y and get its size */ jwk->key.ec->y_len = apr_jwt_base64url_decode(pool, (char **) &jwk->key.ec->y, s_y, 1); if (jwk->key.ec->y_len <= 0) { apr_jwt_error(err, "apr_jwt_base64url_decode of y length failed"); return FALSE; } /* that went well */ return TRUE; }
static char *test_jwt_url_encode_decode(apr_pool_t *pool) { char *dst = NULL; char *src = "abcd"; TST_ASSERT("apr_jwt_base64url_encode (1)", apr_jwt_base64url_encode(pool, &dst, src, strlen(src), 0)); TST_ASSERT_STR("apr_jwt_base64url_encode (2)", dst, "YWJjZA"); src = dst; TST_ASSERT("apr_jwt_base64url_decode (1)", apr_jwt_base64url_decode(pool, &dst, src, 1)); TST_ASSERT_STR("apr_jwt_base64url_decode (2)", dst, "abcd"); return 0; }
/* * parse a an octet sequence used to represent a symmetric key */ static apr_byte_t apr_jwk_parse_oct(apr_pool_t *pool, json_t *json, apr_jwk_t *jwk, apr_jwt_error_t *err) { /* allocated space and set key type */ jwk->type = APR_JWK_KEY_OCT; jwk->key.oct = apr_pcalloc(pool, sizeof(apr_jwk_key_oct_t)); /* parse k */ char *s_k = NULL; if (apr_jwt_get_string(pool, json, "k", TRUE, &s_k, err) == FALSE) return FALSE; /* base64url decode k and get its size */ jwk->key.oct->k_len = apr_jwt_base64url_decode(pool, (char **) &jwk->key.oct->k, s_k, 1); if (jwk->key.oct->k_len <= 0) { apr_jwt_error(err, "apr_jwt_base64url_decode of k length failed"); return FALSE; } /* that went well */ return TRUE; }
/* * parse JSON object from string in to JWT value */ static apr_byte_t apr_jwt_base64url_decode_object(apr_pool_t *pool, const char *str, apr_jwt_value_t *value) { /* base64url-decode the string representation into value->str */ if (apr_jwt_base64url_decode(pool, &value->str, str, 1) < 0) return FALSE; /* decode the string in to a JSON structure into value->json */ json_error_t json_error; value->json = json_loads(value->str, 0, &json_error); if (value->json == NULL) return FALSE; /* check that we've actually got a JSON value back */ if (value->json == NULL) return FALSE; /* check that the value is a JSON object */ if (!json_is_object(value->json)) return FALSE; return TRUE; }