~ubuntu-branches/ubuntu/vivid/libapache2-mod-auth-openidc/vivid-proposed

« back to all changes in this revision

Viewing changes to src/jose/apr_jwk.c

  • Committer: Package Import Robot
  • Author(s): Hans Zandbelt
  • Date: 2014-10-13 12:23:35 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20141013122335-31wgnq50ascmubib
Tags: 1.6.0-1
new upstream release; add libssl-dev dependency

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
#include "apr_jose.h"
58
58
 
59
59
/*
60
 
 * parse an RSA JWK
 
60
 * parse an RSA JWK in raw format (n,e,d)
61
61
 */
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) {
63
64
 
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));
 
65
        /* allocate space */
 
66
        *jwk_key_rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t));
 
67
        apr_jwk_key_rsa_t *key = *jwk_key_rsa;
67
68
 
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)
72
73
                return FALSE;
73
74
 
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,
 
77
                        s_modulus, 1);
77
78
 
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)
82
83
                return FALSE;
83
84
 
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,
 
87
                        s_exponent, 1);
87
88
 
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,
95
 
                                1);
 
94
                key->private_exponent_len = apr_jwt_base64url_decode(pool,
 
95
                                (char **) &key->private_exponent, s_private_exponent, 1);
96
96
        }
97
97
 
98
98
        /* that went well */
100
100
}
101
101
 
102
102
/*
 
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
 
105
 */
 
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) {
 
108
 
 
109
        X509 *x509 = NULL;
 
110
        EVP_PKEY *pkey = NULL;
 
111
        apr_byte_t rv = FALSE;
 
112
 
 
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)
 
116
                        goto end;
 
117
        } else {
 
118
                /* read the X.509 struct */
 
119
                if ((x509 = PEM_read_bio_X509_AUX(input, NULL, NULL, NULL)) == NULL)
 
120
                        goto end;
 
121
                /* get the public key struct from the X.509 struct */
 
122
                if ((pkey = X509_get_pubkey(x509)) == NULL)
 
123
                        goto end;
 
124
        }
 
125
 
 
126
        /* allocate space */
 
127
        *jwk_key_rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t));
 
128
        apr_jwk_key_rsa_t *key = *jwk_key_rsa;
 
129
 
 
130
        /* get the RSA key from the public key struct */
 
131
        RSA *rsa = EVP_PKEY_get1_RSA(pkey);
 
132
        if (rsa == NULL)
 
133
                goto end;
 
134
 
 
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);
 
139
 
 
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);
 
144
 
 
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);
 
150
        }
 
151
 
 
152
        rv = TRUE;
 
153
 
 
154
end:
 
155
 
 
156
        if (pkey)
 
157
                EVP_PKEY_free(pkey);
 
158
        if (x509)
 
159
                X509_free(x509);
 
160
 
 
161
        return rv;
 
162
}
 
163
 
 
164
/*
 
165
 * parse an RSA JWK in X.509 format (x5c)
 
166
 */
 
167
static apr_byte_t apr_jwk_parse_rsa_x5c(apr_pool_t *pool, apr_jwk_t *jwk) {
 
168
 
 
169
        apr_byte_t rv = FALSE;
 
170
 
 
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)))
 
174
                return FALSE;
 
175
 
 
176
        /* take the first element of the array */
 
177
        v = json_array_get(v, 0);
 
178
        if ((v == NULL) || (!json_is_string(v)))
 
179
                return FALSE;
 
180
        const char *s_x5c = json_string_value(v);
 
181
 
 
182
        /* PEM-format it */
 
183
        const int len = 75;
 
184
        int i = 0;
 
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));
 
188
                i += len;
 
189
        }
 
190
        s = apr_psprintf(pool, "%s-----END CERTIFICATE-----\n", s);
 
191
 
 
192
        BIO *input = NULL;
 
193
 
 
194
        /* put it in BIO memory */
 
195
        if ((input = BIO_new(BIO_s_mem())) == NULL)
 
196
                return FALSE;
 
197
 
 
198
        if (BIO_puts(input, s) <= 0) {
 
199
                BIO_free(input);
 
200
                return FALSE;
 
201
        }
 
202
 
 
203
        /* do the actual parsing */
 
204
        rv = apr_jwk_rsa_bio_to_key(pool, input, &jwk->key.rsa, FALSE);
 
205
 
 
206
        BIO_free(input);
 
207
 
 
208
        return rv;
 
209
}
 
210
 
 
211
/*
 
212
 * parse an RSA JWK
 
213
 */
 
214
static apr_byte_t apr_jwk_parse_rsa(apr_pool_t *pool, apr_jwk_t *jwk) {
 
215
 
 
216
        jwk->type = APR_JWK_KEY_RSA;
 
217
 
 
218
        char *s_test = NULL;
 
219
        apr_jwt_get_string(pool, &jwk->value, "n", &s_test);
 
220
        if (s_test != NULL)
 
221
                return apr_jwk_parse_rsa_raw(pool, &jwk->value, &jwk->key.rsa);
 
222
 
 
223
        json_t *v = json_object_get(jwk->value.json, "x5c");
 
224
        if (v != NULL)
 
225
                return apr_jwk_parse_rsa_x5c(pool, jwk);
 
226
 
 
227
        return FALSE;
 
228
}
 
229
 
 
230
/*
103
231
 * parse an EC JWK
104
232
 */
105
233
static apr_byte_t apr_jwk_parse_ec(apr_pool_t *pool, apr_jwk_t *jwk) {
174
302
}
175
303
 
176
304
/*
177
 
 * convert OpenSSL BIGNUM type to base64url-encoded raw bytes value
178
 
 */
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);
186
 
}
187
 
 
188
 
/*
189
 
 * convert OpenSSL EVP public/private key to JWK JSON and kid
190
 
 */
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) {
193
 
 
194
 
        RSA *rsa = EVP_PKEY_get1_RSA(pkey);
 
305
 * convert RSA key to JWK JSON string representation and kid
 
306
 */
 
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) {
195
309
 
196
310
        unsigned char *n_enc = NULL;
197
 
        int n_len = 0;
198
 
        if (apr_jwk_bignum_base64enc(pool, rsa->n, &n_enc, &n_len) == FALSE)
199
 
                return FALSE;
 
311
        int n_len = apr_jwt_base64url_encode(pool, (char **) &n_enc,
 
312
                        (const char *) key->modulus, key->modulus_len, 0);
200
313
 
201
314
        unsigned char *e_enc = NULL;
202
 
        int e_len = 0;
203
 
        if (apr_jwk_bignum_base64enc(pool, rsa->e, &e_enc, &e_len) == FALSE)
204
 
                return FALSE;
 
315
        apr_jwt_base64url_encode(pool, (char **) &e_enc,
 
316
                        (const char *) key->exponent, key->exponent_len, 0);
205
317
 
206
318
        unsigned char *d_enc = NULL;
207
 
        int d_len = 0;
208
 
        if (rsa->d) {
209
 
                if (apr_jwk_bignum_base64enc(pool, rsa->d, &d_enc, &d_len) == FALSE)
210
 
                        return FALSE;
211
 
        }
 
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,
 
322
                                0);
212
323
 
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...
236
347
}
237
348
 
238
349
/*
 
350
 * convert PEM formatted public/private key file to JSON string representation
 
351
 */
 
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) {
 
354
        BIO *input = NULL;
 
355
        apr_jwk_key_rsa_t *key = NULL;
 
356
        apr_byte_t rv = FALSE;
 
357
 
 
358
        if ((input = BIO_new(BIO_s_file())) == NULL)
 
359
                goto end;
 
360
 
 
361
        if (BIO_read_filename(input, filename) <= 0)
 
362
                goto end;
 
363
 
 
364
        if (apr_jwk_rsa_bio_to_key(pool, input, &key, is_private_key) == FALSE)
 
365
                goto end;
 
366
 
 
367
        rv = apr_jwk_rsa_to_json(pool, key, s_jwk, s_kid);
 
368
 
 
369
end:
 
370
 
 
371
        if (input)
 
372
                BIO_free(input);
 
373
 
 
374
        return rv;
 
375
}
 
376
 
 
377
/*
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
241
380
 */
242
 
apr_byte_t apr_jwk_x509_to_rsa_jwk(apr_pool_t *pool, const char *filename,
243
 
                char **jwk, char**kid) {
244
 
 
245
 
        BIO *input = NULL;
246
 
        X509 *x509 = NULL;
247
 
        EVP_PKEY *pkey = NULL;
248
 
 
249
 
        apr_byte_t rv = FALSE;
250
 
 
251
 
        if ((input = BIO_new(BIO_s_file())) == NULL)
252
 
                goto end;
253
 
        if (BIO_read_filename(input, filename) <= 0)
254
 
                goto end;
255
 
        if ((x509 = PEM_read_bio_X509_AUX(input, NULL, NULL, NULL)) == NULL)
256
 
                goto end;
257
 
        if ((pkey = X509_get_pubkey(x509)) == NULL)
258
 
                goto end;
259
 
 
260
 
        rv = apr_jwk_openssl_evp_pkey_rsa_to_json(pool, pkey, jwk, kid);
261
 
 
262
 
end:
263
 
 
264
 
        if (pkey)
265
 
                EVP_PKEY_free(pkey);
266
 
        if (x509)
267
 
                X509_free(x509);
268
 
        if (input)
269
 
                BIO_free(input);
270
 
 
271
 
        return rv;
 
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);
272
384
}
273
385
 
274
386
/*
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
276
389
 */
277
390
apr_byte_t apr_jwk_private_key_to_rsa_jwk(apr_pool_t *pool,
278
 
                const char *filename, char **jwk, char**kid) {
279
 
 
280
 
        BIO *input = NULL;
281
 
        EVP_PKEY *pkey = NULL;
282
 
 
283
 
        apr_byte_t rv = FALSE;
284
 
 
285
 
        if ((input = BIO_new(BIO_s_file())) == NULL)
286
 
                goto end;
287
 
        if (BIO_read_filename(input, filename) <= 0)
288
 
                goto end;
289
 
        if ((pkey = PEM_read_bio_PrivateKey(input, NULL, NULL, NULL)) == NULL)
290
 
                goto end;
291
 
 
292
 
        rv = apr_jwk_openssl_evp_pkey_rsa_to_json(pool, pkey, jwk, kid);
293
 
 
294
 
end: if (pkey)
295
 
                EVP_PKEY_free(pkey);
296
 
        if (input)
297
 
                BIO_free(input);
298
 
 
299
 
        return rv;
 
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);
300
393
}