57
57
#include "apr_jose.h"
60
* parse an RSA JWK in raw format (n,e,d)
62
static apr_byte_t apr_jwk_parse_rsa(apr_pool_t *pool, apr_jwk_t *jwk) {
62
static apr_byte_t apr_jwk_parse_rsa_raw(apr_pool_t *pool, apr_jwt_value_t *jwk,
63
apr_jwk_key_rsa_t **jwk_key_rsa) {
64
/* allocated space and set key type */
65
jwk->type = APR_JWK_KEY_RSA;
66
jwk->key.rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t));
66
*jwk_key_rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t));
67
apr_jwk_key_rsa_t *key = *jwk_key_rsa;
68
69
/* parse the modulus */
69
70
char *s_modulus = NULL;
70
apr_jwt_get_string(pool, &jwk->value, "n", &s_modulus);
71
apr_jwt_get_string(pool, jwk, "n", &s_modulus);
71
72
if (s_modulus == NULL)
74
75
/* parse the modulus size */
75
jwk->key.rsa->modulus_len = apr_jwt_base64url_decode(pool,
76
(char **) &jwk->key.rsa->modulus, s_modulus, 1);
76
key->modulus_len = apr_jwt_base64url_decode(pool, (char **) &key->modulus,
78
79
/* parse the exponent */
79
80
char *s_exponent = NULL;
80
apr_jwt_get_string(pool, &jwk->value, "e", &s_exponent);
81
apr_jwt_get_string(pool, jwk, "e", &s_exponent);
81
82
if (s_exponent == NULL)
84
85
/* parse the exponent size */
85
jwk->key.rsa->exponent_len = apr_jwt_base64url_decode(pool,
86
(char **) &jwk->key.rsa->exponent, s_exponent, 1);
86
key->exponent_len = apr_jwt_base64url_decode(pool, (char **) &key->exponent,
88
89
/* parse the private exponent */
89
90
char *s_private_exponent = NULL;
90
apr_jwt_get_string(pool, &jwk->value, "d", &s_private_exponent);
91
apr_jwt_get_string(pool, jwk, "d", &s_private_exponent);
91
92
if (s_private_exponent != NULL) {
92
93
/* parse the private exponent size */
93
jwk->key.rsa->private_exponent_len = apr_jwt_base64url_decode(pool,
94
(char **) &jwk->key.rsa->private_exponent, s_private_exponent,
94
key->private_exponent_len = apr_jwt_base64url_decode(pool,
95
(char **) &key->private_exponent, s_private_exponent, 1);
98
98
/* that went well */
103
* convert the RSA public key in the X.509 certificate in the BIO pointed to
104
* by "input" to a JSON Web Key object
106
static apr_byte_t apr_jwk_rsa_bio_to_key(apr_pool_t *pool, BIO *input,
107
apr_jwk_key_rsa_t **jwk_key_rsa, int is_private_key) {
110
EVP_PKEY *pkey = NULL;
111
apr_byte_t rv = FALSE;
113
if (is_private_key) {
114
/* get the private key struct from the BIO */
115
if ((pkey = PEM_read_bio_PrivateKey(input, NULL, NULL, NULL)) == NULL)
118
/* read the X.509 struct */
119
if ((x509 = PEM_read_bio_X509_AUX(input, NULL, NULL, NULL)) == NULL)
121
/* get the public key struct from the X.509 struct */
122
if ((pkey = X509_get_pubkey(x509)) == NULL)
127
*jwk_key_rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t));
128
apr_jwk_key_rsa_t *key = *jwk_key_rsa;
130
/* get the RSA key from the public key struct */
131
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
135
/* convert the modulus bignum in to a key/len */
136
key->modulus_len = BN_num_bytes(rsa->n);
137
key->modulus = apr_pcalloc(pool, key->modulus_len);
138
BN_bn2bin(rsa->n, key->modulus);
140
/* convert the exponent bignum in to a key/len */
141
key->exponent_len = BN_num_bytes(rsa->e);
142
key->exponent = apr_pcalloc(pool, key->exponent_len);
143
BN_bn2bin(rsa->e, key->exponent);
145
/* convert the private exponent bignum in to a key/len */
146
if (rsa->d != NULL) {
147
key->private_exponent_len = BN_num_bytes(rsa->d);
148
key->private_exponent = apr_pcalloc(pool, key->private_exponent_len);
149
BN_bn2bin(rsa->d, key->private_exponent);
165
* parse an RSA JWK in X.509 format (x5c)
167
static apr_byte_t apr_jwk_parse_rsa_x5c(apr_pool_t *pool, apr_jwk_t *jwk) {
169
apr_byte_t rv = FALSE;
171
/* get the "x5c" array element from the JSON object */
172
json_t *v = json_object_get(jwk->value.json, "x5c");
173
if ((v == NULL) || (!json_is_array(v)))
176
/* take the first element of the array */
177
v = json_array_get(v, 0);
178
if ((v == NULL) || (!json_is_string(v)))
180
const char *s_x5c = json_string_value(v);
185
char *s = apr_psprintf(pool, "-----BEGIN CERTIFICATE-----\n");
186
while (i < strlen(s_x5c)) {
187
s = apr_psprintf(pool, "%s%s\n", s, apr_pstrndup(pool, s_x5c + i, len));
190
s = apr_psprintf(pool, "%s-----END CERTIFICATE-----\n", s);
194
/* put it in BIO memory */
195
if ((input = BIO_new(BIO_s_mem())) == NULL)
198
if (BIO_puts(input, s) <= 0) {
203
/* do the actual parsing */
204
rv = apr_jwk_rsa_bio_to_key(pool, input, &jwk->key.rsa, FALSE);
214
static apr_byte_t apr_jwk_parse_rsa(apr_pool_t *pool, apr_jwk_t *jwk) {
216
jwk->type = APR_JWK_KEY_RSA;
219
apr_jwt_get_string(pool, &jwk->value, "n", &s_test);
221
return apr_jwk_parse_rsa_raw(pool, &jwk->value, &jwk->key.rsa);
223
json_t *v = json_object_get(jwk->value.json, "x5c");
225
return apr_jwk_parse_rsa_x5c(pool, jwk);
103
231
* parse an EC JWK
105
233
static apr_byte_t apr_jwk_parse_ec(apr_pool_t *pool, apr_jwk_t *jwk) {
177
* convert OpenSSL BIGNUM type to base64url-encoded raw bytes value
179
static apr_byte_t apr_jwk_bignum_base64enc(apr_pool_t *pool, BIGNUM *v,
180
unsigned char **v_enc, int *v_len) {
181
*v_len = BN_num_bytes(v);
182
unsigned char *v_bytes = apr_pcalloc(pool, *v_len);
183
BN_bn2bin(v, v_bytes);
184
return apr_jwt_base64url_encode(pool, (char **) v_enc,
185
(const char *) v_bytes, *v_len, 0);
189
* convert OpenSSL EVP public/private key to JWK JSON and kid
191
static apr_byte_t apr_jwk_openssl_evp_pkey_rsa_to_json(apr_pool_t *pool,
192
EVP_PKEY *pkey, char **jwk, char**kid) {
194
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
305
* convert RSA key to JWK JSON string representation and kid
307
static apr_byte_t apr_jwk_rsa_to_json(apr_pool_t *pool, apr_jwk_key_rsa_t *key,
308
char **jwk, char**kid) {
196
310
unsigned char *n_enc = NULL;
198
if (apr_jwk_bignum_base64enc(pool, rsa->n, &n_enc, &n_len) == FALSE)
311
int n_len = apr_jwt_base64url_encode(pool, (char **) &n_enc,
312
(const char *) key->modulus, key->modulus_len, 0);
201
314
unsigned char *e_enc = NULL;
203
if (apr_jwk_bignum_base64enc(pool, rsa->e, &e_enc, &e_len) == FALSE)
315
apr_jwt_base64url_encode(pool, (char **) &e_enc,
316
(const char *) key->exponent, key->exponent_len, 0);
206
318
unsigned char *d_enc = NULL;
209
if (apr_jwk_bignum_base64enc(pool, rsa->d, &d_enc, &d_len) == FALSE)
319
if (key->private_exponent_len > 0)
320
apr_jwt_base64url_encode(pool, (char **) &d_enc,
321
(const char *) key->private_exponent, key->private_exponent_len,
213
324
/* calculate a unique key identifier (kid) by fingerprinting the key params */
214
325
// TODO: based just on sha1 hash of baseurl-encoded "n" now...
350
* convert PEM formatted public/private key file to JSON string representation
352
static apr_byte_t apr_jwk_pem_to_json_impl(apr_pool_t *pool,
353
const char *filename, char **s_jwk, char**s_kid, int is_private_key) {
355
apr_jwk_key_rsa_t *key = NULL;
356
apr_byte_t rv = FALSE;
358
if ((input = BIO_new(BIO_s_file())) == NULL)
361
if (BIO_read_filename(input, filename) <= 0)
364
if (apr_jwk_rsa_bio_to_key(pool, input, &key, is_private_key) == FALSE)
367
rv = apr_jwk_rsa_to_json(pool, key, s_jwk, s_kid);
239
378
* convert the RSA public key in the X.509 certificate in the file pointed to
240
* by "filename" to a JSON Web Key object
379
* by "filename" to a JSON Web Key string representation
242
apr_byte_t apr_jwk_x509_to_rsa_jwk(apr_pool_t *pool, const char *filename,
243
char **jwk, char**kid) {
247
EVP_PKEY *pkey = NULL;
249
apr_byte_t rv = FALSE;
251
if ((input = BIO_new(BIO_s_file())) == NULL)
253
if (BIO_read_filename(input, filename) <= 0)
255
if ((x509 = PEM_read_bio_X509_AUX(input, NULL, NULL, NULL)) == NULL)
257
if ((pkey = X509_get_pubkey(x509)) == NULL)
260
rv = apr_jwk_openssl_evp_pkey_rsa_to_json(pool, pkey, jwk, kid);
381
apr_byte_t apr_jwk_pem_to_json(apr_pool_t *pool, const char *filename,
382
char **s_jwk, char**s_kid) {
383
return apr_jwk_pem_to_json_impl(pool, filename, s_jwk, s_kid, FALSE);
275
* convert the RSA private key in the PEM file pointed to by "filename" to a JSON Web Key object
387
* convert the RSA private key in the PEM file pointed to by "filename"
388
* to a JSON Web Key string representation
277
390
apr_byte_t apr_jwk_private_key_to_rsa_jwk(apr_pool_t *pool,
278
const char *filename, char **jwk, char**kid) {
281
EVP_PKEY *pkey = NULL;
283
apr_byte_t rv = FALSE;
285
if ((input = BIO_new(BIO_s_file())) == NULL)
287
if (BIO_read_filename(input, filename) <= 0)
289
if ((pkey = PEM_read_bio_PrivateKey(input, NULL, NULL, NULL)) == NULL)
292
rv = apr_jwk_openssl_evp_pkey_rsa_to_json(pool, pkey, jwk, kid);
391
const char *filename, char **s_jwk, char**s_kid) {
392
return apr_jwk_pem_to_json_impl(pool, filename, s_jwk, s_kid, TRUE);