/* * convert RSA key to JWK JSON string representation and kid */ apr_byte_t apr_jwk_to_json(apr_pool_t *pool, apr_jwk_t *jwk, char **s_json, apr_jwt_error_t *err) { if (jwk->type != APR_JWK_KEY_RSA) { apr_jwt_error(err, "non RSA keys (%d) not yet supported", jwk->type); return FALSE; } apr_jwk_key_rsa_t *key = jwk->key.rsa; unsigned char *n_enc = NULL; int n_len = apr_jwt_base64url_encode(pool, (char **) &n_enc, (const char *) key->modulus, key->modulus_len, 0); if (n_len <= 0) { apr_jwt_error(err, "apr_jwt_base64url_encode of modulus failed"); return FALSE; } unsigned char *e_enc = NULL; if (apr_jwt_base64url_encode(pool, (char **) &e_enc, (const char *) key->exponent, key->exponent_len, 0) <= 0) { apr_jwt_error(err, "apr_jwt_base64url_encode of public exponent failed"); return FALSE; } unsigned char *d_enc = NULL; if (key->private_exponent_len > 0) { if (apr_jwt_base64url_encode(pool, (char **) &d_enc, (const char *) key->private_exponent, key->private_exponent_len, 0) <= 0) { apr_jwt_error(err, "apr_jwt_base64url_encode of private exponent failed"); return FALSE; } } char *p = apr_psprintf(pool, "{ \"kty\" : \"RSA\""); p = apr_psprintf(pool, "%s, \"n\": \"%s\"", p, n_enc); p = apr_psprintf(pool, "%s, \"e\": \"%s\"", p, e_enc); if (d_enc != NULL) p = apr_psprintf(pool, "%s, \"d\": \"%s\"", p, d_enc); p = apr_psprintf(pool, "%s, \"kid\" : \"%s\"", p, jwk->kid); p = apr_psprintf(pool, "%s }", p); *s_json = p; return TRUE; }
/* * convert RSA key to JWK JSON string representation and kid */ static apr_byte_t apr_jwk_rsa_to_json(apr_pool_t *pool, apr_jwk_key_rsa_t *key, char **jwk, char**kid) { unsigned char *n_enc = NULL; int n_len = apr_jwt_base64url_encode(pool, (char **) &n_enc, (const char *) key->modulus, key->modulus_len, 0); unsigned char *e_enc = NULL; apr_jwt_base64url_encode(pool, (char **) &e_enc, (const char *) key->exponent, key->exponent_len, 0); unsigned char *d_enc = NULL; if (key->private_exponent_len > 0) apr_jwt_base64url_encode(pool, (char **) &d_enc, (const char *) key->private_exponent, key->private_exponent_len, 0); /* calculate a unique key identifier (kid) by fingerprinting the key params */ // TODO: based just on sha1 hash of baseurl-encoded "n" now... unsigned int fp_len = SHA_DIGEST_LENGTH; unsigned char fp[SHA_DIGEST_LENGTH]; if (!SHA1(n_enc, n_len, fp)) return FALSE; char *fp_enc = NULL; if (apr_jwt_base64url_encode(pool, &fp_enc, (const char *) fp, fp_len, 0) == FALSE) return FALSE; char *p = apr_psprintf(pool, "{ \"kty\" : \"RSA\""); p = apr_psprintf(pool, "%s, \"n\": \"%s\"", p, n_enc); p = apr_psprintf(pool, "%s, \"e\": \"%s\"", p, e_enc); if (d_enc != NULL) p = apr_psprintf(pool, "%s, \"d\": \"%s\"", p, d_enc); p = apr_psprintf(pool, "%s, \"kid\" : \"%s\"", p, fp_enc); p = apr_psprintf(pool, "%s }", p); *jwk = p; *kid = fp_enc; 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; }
/* * calculate a hash and base64url encode the result */ static apr_byte_t apr_jwk_hash_and_base64urlencode(apr_pool_t *pool, const unsigned char *input, const int input_len, char **output, apr_jwt_error_t *err) { unsigned int hash_len = SHA_DIGEST_LENGTH; unsigned char hash[SHA_DIGEST_LENGTH]; // TODO: upgrade to SHA2? /* hash it */ if (!SHA1(input, input_len, hash)) { apr_jwt_error_openssl(err, "SHA1"); return FALSE; } /* base64url encode the key fingerprint */ if (apr_jwt_base64url_encode(pool, output, (const char *) hash, hash_len, 0) <= 0) { apr_jwt_error(err, "apr_jwt_base64url_encode of hash failed"); return FALSE; } return TRUE; }