Coverage Report

Created: 2026-08-31 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cjose/src/jwk.c
Line
Count
Source
1
/*!
2
 * Copyrights
3
 *
4
 * Portions created or assigned to Cisco Systems, Inc. are
5
 * Copyright (c) 2014-2016 Cisco Systems, Inc.  All Rights Reserved.
6
 */
7
8
#define OPENSSL_API_COMPAT 0x10000000L
9
10
#include "include/jwk_int.h"
11
#include "include/util_int.h"
12
13
#include <cjose/base64.h>
14
#include <cjose/util.h>
15
16
#include <limits.h>
17
#include <stdlib.h>
18
#include <string.h>
19
#include <stdio.h>
20
21
#include <openssl/bn.h>
22
#include <openssl/obj_mac.h>
23
#include <openssl/rand.h>
24
#include <openssl/rsa.h>
25
#include <openssl/evp.h>
26
#include <openssl/hmac.h>
27
#include <openssl/evp.h>
28
29
// internal data structures
30
31
static const char CJOSE_JWK_EC_P_256_STR[] = "P-256";
32
static const char CJOSE_JWK_EC_P_384_STR[] = "P-384";
33
static const char CJOSE_JWK_EC_P_521_STR[] = "P-521";
34
static const char CJOSE_JWK_KTY_STR[] = "kty";
35
static const char CJOSE_JWK_KID_STR[] = "kid";
36
static const char CJOSE_JWK_KTY_EC_STR[] = "EC";
37
static const char CJOSE_JWK_KTY_RSA_STR[] = "RSA";
38
static const char CJOSE_JWK_KTY_OCT_STR[] = "oct";
39
static const char CJOSE_JWK_CRV_STR[] = "crv";
40
static const char CJOSE_JWK_X_STR[] = "x";
41
static const char CJOSE_JWK_Y_STR[] = "y";
42
static const char CJOSE_JWK_D_STR[] = "d";
43
static const char CJOSE_JWK_N_STR[] = "n";
44
static const char CJOSE_JWK_E_STR[] = "e";
45
static const char CJOSE_JWK_P_STR[] = "p";
46
static const char CJOSE_JWK_Q_STR[] = "q";
47
static const char CJOSE_JWK_DP_STR[] = "dp";
48
static const char CJOSE_JWK_DQ_STR[] = "dq";
49
static const char CJOSE_JWK_QI_STR[] = "qi";
50
static const char CJOSE_JWK_K_STR[] = "k";
51
52
static const char *JWK_KTY_NAMES[] = { CJOSE_JWK_KTY_RSA_STR, CJOSE_JWK_KTY_EC_STR, CJOSE_JWK_KTY_OCT_STR };
53
54
void _cjose_jwk_rsa_get(RSA *rsa, BIGNUM **rsa_n, BIGNUM **rsa_e, BIGNUM **rsa_d)
55
0
{
56
0
    if (rsa == NULL)
57
0
        return;
58
0
#if defined(CJOSE_OPENSSL_11X)
59
0
    RSA_get0_key(rsa, (const BIGNUM **)rsa_n, (const BIGNUM **)rsa_e, (const BIGNUM **)rsa_d);
60
#else
61
    *rsa_n = rsa->n;
62
    *rsa_e = rsa->e;
63
    *rsa_d = rsa->d;
64
#endif
65
0
}
66
67
bool _cjose_jwk_rsa_set(RSA *rsa, uint8_t *n, size_t n_len, uint8_t *e, size_t e_len, uint8_t *d, size_t d_len)
68
0
{
69
0
    BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
70
71
    // RSA_set0_key doesn't work without each of those on the first call!
72
0
    if ((n == NULL) || (n_len <= 0) || (e == NULL) || (e_len <= 0))
73
0
        return false;
74
75
0
    if (n && n_len > 0)
76
0
        rsa_n = BN_bin2bn(n, n_len, NULL);
77
0
    if (e && e_len > 0)
78
0
        rsa_e = BN_bin2bn(e, e_len, NULL);
79
0
    if (d && d_len > 0)
80
0
        rsa_d = BN_bin2bn(d, d_len, NULL);
81
82
0
#if defined(CJOSE_OPENSSL_11X)
83
0
    if (1 != RSA_set0_key(rsa, rsa_n, rsa_e, rsa_d))
84
0
    {
85
        // the setter takes ownership only on success; free the BIGNUMs it
86
        // refused (e.g. if a BN_bin2bn above failed) rather than leaking them
87
0
        BN_free(rsa_n);
88
0
        BN_free(rsa_e);
89
0
        BN_free(rsa_d);
90
0
        return false;
91
0
    }
92
0
    return true;
93
#else
94
    rsa->n = rsa_n;
95
    rsa->e = rsa_e;
96
    rsa->d = rsa_d;
97
    return true;
98
#endif
99
0
}
100
101
void _cjose_jwk_rsa_get_factors(RSA *rsa, BIGNUM **p, BIGNUM **q)
102
0
{
103
0
#if defined(CJOSE_OPENSSL_11X)
104
0
    RSA_get0_factors(rsa, (const BIGNUM **)p, (const BIGNUM **)q);
105
#else
106
    *p = rsa->p;
107
    *q = rsa->q;
108
#endif
109
0
}
110
111
bool _cjose_jwk_rsa_set_factors(RSA *rsa, uint8_t *p, size_t p_len, uint8_t *q, size_t q_len)
112
0
{
113
0
    BIGNUM *rsa_p = NULL, *rsa_q = NULL;
114
115
0
    if (p && p_len > 0)
116
0
        rsa_p = BN_bin2bn(p, p_len, NULL);
117
0
    if (q && q_len > 0)
118
0
        rsa_q = BN_bin2bn(q, q_len, NULL);
119
120
    // no factors supplied: a valid (n, e, d)-only private key
121
0
    if (NULL == rsa_p && NULL == rsa_q)
122
0
        return true;
123
124
    // p and q are required together; reject (and free) an incomplete pair
125
    // instead of leaking the BIGNUM the setter refuses to take ownership of
126
0
    if (NULL == rsa_p || NULL == rsa_q)
127
0
    {
128
0
        BN_free(rsa_p);
129
0
        BN_free(rsa_q);
130
0
        return false;
131
0
    }
132
133
0
#if defined(CJOSE_OPENSSL_11X)
134
0
    if (1 != RSA_set0_factors(rsa, rsa_p, rsa_q))
135
0
    {
136
0
        BN_free(rsa_p);
137
0
        BN_free(rsa_q);
138
0
        return false;
139
0
    }
140
#else
141
    rsa->p = rsa_p;
142
    rsa->q = rsa_q;
143
#endif
144
0
    return true;
145
0
}
146
147
void _cjose_jwk_rsa_get_crt(RSA *rsa, BIGNUM **dmp1, BIGNUM **dmq1, BIGNUM **iqmp)
148
0
{
149
0
#if defined(CJOSE_OPENSSL_11X)
150
0
    RSA_get0_crt_params(rsa, (const BIGNUM **)dmp1, (const BIGNUM **)dmq1, (const BIGNUM **)iqmp);
151
#else
152
    *dmp1 = rsa->dmp1;
153
    *dmq1 = rsa->dmq1;
154
    *iqmp = rsa->iqmp;
155
#endif
156
0
}
157
158
bool _cjose_jwk_rsa_set_crt(
159
    RSA *rsa, uint8_t *dmp1, size_t dmp1_len, uint8_t *dmq1, size_t dmq1_len, uint8_t *iqmp, size_t iqmp_len)
160
0
{
161
0
    BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL, *rsa_iqmp = NULL;
162
163
0
    if (dmp1 && dmp1_len > 0)
164
0
        rsa_dmp1 = BN_bin2bn(dmp1, dmp1_len, NULL);
165
0
    if (dmq1 && dmq1_len > 0)
166
0
        rsa_dmq1 = BN_bin2bn(dmq1, dmq1_len, NULL);
167
0
    if (iqmp && iqmp_len > 0)
168
0
        rsa_iqmp = BN_bin2bn(iqmp, iqmp_len, NULL);
169
170
    // no CRT params supplied: nothing to set
171
0
    if (NULL == rsa_dmp1 && NULL == rsa_dmq1 && NULL == rsa_iqmp)
172
0
        return true;
173
174
    // the CRT params are required together; reject (and free) an incomplete
175
    // set instead of leaking the BIGNUMs the setter refuses to take ownership of
176
0
    if (NULL == rsa_dmp1 || NULL == rsa_dmq1 || NULL == rsa_iqmp)
177
0
    {
178
0
        BN_free(rsa_dmp1);
179
0
        BN_free(rsa_dmq1);
180
0
        BN_free(rsa_iqmp);
181
0
        return false;
182
0
    }
183
184
0
#if defined(CJOSE_OPENSSL_11X)
185
0
    if (1 != RSA_set0_crt_params(rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp))
186
0
    {
187
0
        BN_free(rsa_dmp1);
188
0
        BN_free(rsa_dmq1);
189
0
        BN_free(rsa_iqmp);
190
0
        return false;
191
0
    }
192
#else
193
    rsa->dmp1 = rsa_dmp1;
194
    rsa->dmq1 = rsa_dmq1;
195
    rsa->iqmp = rsa_iqmp;
196
#endif
197
0
    return true;
198
0
}
199
200
// interface functions -- Generic
201
202
const char *cjose_jwk_name_for_kty(cjose_jwk_kty_t kty, cjose_err *err)
203
0
{
204
    // reject anything outside [CJOSE_JWK_KTY_RSA, CJOSE_JWK_KTY_OCT]; a value
205
    // below RSA (e.g. a negative sentinel, if the enum is signed) would index
206
    // JWK_KTY_NAMES out of bounds
207
0
    if (kty < CJOSE_JWK_KTY_RSA || CJOSE_JWK_KTY_OCT < kty)
208
0
    {
209
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
210
0
        return NULL;
211
0
    }
212
213
0
    return JWK_KTY_NAMES[kty - CJOSE_JWK_KTY_RSA];
214
0
}
215
216
cjose_jwk_t *cjose_jwk_retain(cjose_jwk_t *jwk, cjose_err *err)
217
0
{
218
0
    if (!jwk)
219
0
    {
220
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
221
0
        return NULL;
222
0
    }
223
224
0
    if (UINT_MAX == jwk->retained)
225
0
    {
226
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_STATE);
227
0
        return NULL;
228
0
    }
229
230
0
    ++(jwk->retained);
231
232
0
    return jwk;
233
0
}
234
235
bool cjose_jwk_release(cjose_jwk_t *jwk)
236
0
{
237
0
    if (!jwk)
238
0
    {
239
0
        return false;
240
0
    }
241
242
0
    --(jwk->retained);
243
0
    if (0 == jwk->retained)
244
0
    {
245
0
        cjose_get_dealloc()(jwk->kid);
246
0
        jwk->kid = NULL;
247
248
        // assumes freefunc is set
249
0
        if (NULL != jwk->fns->free_func)
250
0
        {
251
0
            jwk->fns->free_func(jwk);
252
0
        }
253
0
        jwk = NULL;
254
0
    }
255
256
0
    return (NULL != jwk);
257
0
}
258
259
cjose_jwk_kty_t cjose_jwk_get_kty(const cjose_jwk_t *jwk, cjose_err *err)
260
0
{
261
0
    if (!jwk)
262
0
    {
263
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
264
0
        return -1;
265
0
    }
266
267
0
    return jwk->kty;
268
0
}
269
size_t cjose_jwk_get_keysize(const cjose_jwk_t *jwk, cjose_err *err)
270
0
{
271
0
    if (!jwk)
272
0
    {
273
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
274
0
        return 0;
275
0
    }
276
0
    return jwk->keysize;
277
0
}
278
279
void *cjose_jwk_get_keydata(const cjose_jwk_t *jwk, cjose_err *err)
280
0
{
281
0
    if (!jwk)
282
0
    {
283
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
284
0
        return NULL;
285
0
    }
286
0
    return jwk->keydata;
287
0
}
288
289
const char *cjose_jwk_get_kid(const cjose_jwk_t *jwk, cjose_err *err)
290
0
{
291
0
    if (!jwk)
292
0
    {
293
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
294
0
        return NULL;
295
0
    }
296
297
0
    return jwk->kid;
298
0
}
299
300
bool cjose_jwk_set_kid(cjose_jwk_t *jwk, const char *kid, size_t len, cjose_err *err)
301
0
{
302
0
    if (!jwk || !kid)
303
0
    {
304
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
305
0
        return false;
306
0
    }
307
0
    if (jwk->kid)
308
0
    {
309
0
        cjose_get_dealloc()(jwk->kid);
310
0
    }
311
0
    jwk->kid = (char *)cjose_get_alloc()(len + 1);
312
0
    if (!jwk->kid)
313
0
    {
314
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
315
0
        return false;
316
0
    }
317
    // copy exactly len bytes from the caller-supplied (length-delimited, not
318
    // necessarily NUL-terminated) kid and terminate ourselves; strncpy(len + 1)
319
    // would read one byte past kid and could leave jwk->kid unterminated.
320
0
    memcpy(jwk->kid, kid, len);
321
0
    jwk->kid[len] = '\0';
322
0
    return true;
323
0
}
324
325
char *cjose_jwk_to_json(const cjose_jwk_t *jwk, bool priv, cjose_err *err)
326
0
{
327
0
    char *result = NULL;
328
329
0
    if (!jwk)
330
0
    {
331
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
332
0
        return NULL;
333
0
    }
334
335
0
    json_t *json = json_object(), *field = NULL;
336
0
    if (!json)
337
0
    {
338
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
339
0
        goto to_json_cleanup;
340
0
    }
341
342
    // set kty
343
0
    const char *kty = cjose_jwk_name_for_kty(jwk->kty, err);
344
0
    field = json_string(kty);
345
0
    if (!field)
346
0
    {
347
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
348
0
        goto to_json_cleanup;
349
0
    }
350
0
    json_object_set(json, "kty", field);
351
0
    json_decref(field);
352
0
    field = NULL;
353
354
    // set kid
355
0
    if (NULL != jwk->kid)
356
0
    {
357
0
        field = json_string(jwk->kid);
358
0
        if (!field)
359
0
        {
360
0
            CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
361
0
            goto to_json_cleanup;
362
0
        }
363
0
        json_object_set(json, CJOSE_JWK_KID_STR, field);
364
0
        json_decref(field);
365
0
        field = NULL;
366
0
    }
367
368
    // set public fields
369
0
    if (jwk->fns->public_json && !jwk->fns->public_json(jwk, json, err))
370
0
    {
371
0
        goto to_json_cleanup;
372
0
    }
373
374
    // set private fields
375
0
    if (priv && jwk->fns->private_json && !jwk->fns->private_json(jwk, json, err))
376
0
    {
377
0
        goto to_json_cleanup;
378
0
    }
379
380
    // generate the string ...
381
0
    char *str_jwk = json_dumps(json, JSON_ENCODE_ANY | JSON_COMPACT | JSON_PRESERVE_ORDER);
382
0
    if (!str_jwk)
383
0
    {
384
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
385
0
        goto to_json_cleanup;
386
0
    }
387
0
    result = _cjose_strndup(str_jwk, -1, err);
388
0
    if (!result)
389
0
    {
390
0
        cjose_get_dealloc()(str_jwk);
391
0
        goto to_json_cleanup;
392
0
    }
393
0
    cjose_get_dealloc()(str_jwk);
394
395
0
to_json_cleanup:
396
0
    if (json)
397
0
    {
398
0
        json_decref(json);
399
0
        json = NULL;
400
0
    }
401
0
    if (field)
402
0
    {
403
0
        json_decref(field);
404
0
        field = NULL;
405
0
    }
406
407
0
    return result;
408
0
}
409
410
//////////////// Octet String ////////////////
411
// internal data & functions -- Octet String
412
413
static void _oct_free(cjose_jwk_t *jwk);
414
static bool _oct_public_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err);
415
static bool _oct_private_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err);
416
417
static const key_fntable OCT_FNTABLE = { _oct_free, _oct_public_fields, _oct_private_fields };
418
419
static cjose_jwk_t *_oct_new(uint8_t *buffer, size_t keysize, cjose_err *err)
420
0
{
421
0
    cjose_jwk_t *jwk = (cjose_jwk_t *)cjose_get_alloc()(sizeof(cjose_jwk_t));
422
0
    if (NULL == jwk)
423
0
    {
424
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
425
0
    }
426
0
    else
427
0
    {
428
0
        memset(jwk, 0, sizeof(cjose_jwk_t));
429
0
        jwk->retained = 1;
430
0
        jwk->kty = CJOSE_JWK_KTY_OCT;
431
0
        jwk->keysize = keysize;
432
0
        jwk->keydata = buffer;
433
0
        jwk->fns = &OCT_FNTABLE;
434
0
    }
435
436
0
    return jwk;
437
0
}
438
439
static void _oct_free(cjose_jwk_t *jwk)
440
0
{
441
0
    uint8_t *buffer = (uint8_t *)jwk->keydata;
442
0
    jwk->keydata = NULL;
443
0
    if (buffer)
444
0
    {
445
0
        _cjose_cleanse_dealloc(buffer, jwk->keysize / 8);
446
0
    }
447
0
    cjose_get_dealloc()(jwk);
448
0
}
449
450
0
static bool _oct_public_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err) { return true; }
451
452
static bool _oct_private_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err)
453
0
{
454
0
    json_t *field = NULL;
455
0
    char *k = NULL;
456
0
    size_t klen = 0;
457
0
    uint8_t *keydata = (uint8_t *)jwk->keydata;
458
0
    size_t keysize = jwk->keysize / 8;
459
460
0
    if (!cjose_base64url_encode(keydata, keysize, &k, &klen, err))
461
0
    {
462
0
        return false;
463
0
    }
464
465
0
    field = _cjose_json_stringn(k, klen, err);
466
    // k holds the base64url-encoded symmetric key; wipe it before release
467
0
    _cjose_cleanse_dealloc(k, klen);
468
0
    k = NULL;
469
0
    if (!field)
470
0
    {
471
0
        return false;
472
0
    }
473
0
    json_object_set(json, "k", field);
474
0
    json_decref(field);
475
476
0
    return true;
477
0
}
478
479
// interface functions -- Octet String
480
481
cjose_jwk_t *cjose_jwk_create_oct_random(size_t keysize, cjose_err *err)
482
0
{
483
0
    cjose_jwk_t *jwk = NULL;
484
0
    uint8_t *buffer = NULL;
485
486
0
    if (0 == keysize)
487
0
    {
488
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
489
0
        goto create_oct_failed;
490
0
    }
491
492
    // resize to bytes
493
0
    size_t buffersize = sizeof(uint8_t) * (keysize / 8);
494
495
0
    buffer = (uint8_t *)cjose_get_alloc()(buffersize);
496
0
    if (NULL == buffer)
497
0
    {
498
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
499
0
        goto create_oct_failed;
500
0
    }
501
0
    if (1 != RAND_bytes(buffer, buffersize))
502
0
    {
503
0
        goto create_oct_failed;
504
0
    }
505
506
0
    jwk = _oct_new(buffer, keysize, err);
507
0
    if (NULL == jwk)
508
0
    {
509
0
        goto create_oct_failed;
510
0
    }
511
0
    return jwk;
512
513
0
create_oct_failed:
514
0
    if (buffer)
515
0
    {
516
0
        cjose_get_dealloc()(buffer);
517
0
        buffer = NULL;
518
0
    }
519
520
0
    return NULL;
521
0
}
522
523
cjose_jwk_t *cjose_jwk_create_oct_spec(const uint8_t *data, size_t len, cjose_err *err)
524
0
{
525
0
    cjose_jwk_t *jwk = NULL;
526
0
    uint8_t *buffer = NULL;
527
528
0
    if (NULL == data || 0 == len)
529
0
    {
530
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
531
0
        goto create_oct_failed;
532
0
    }
533
534
0
    buffer = (uint8_t *)cjose_get_alloc()(len);
535
0
    if (!buffer)
536
0
    {
537
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
538
0
        goto create_oct_failed;
539
0
    }
540
0
    memcpy(buffer, data, len);
541
542
0
    jwk = _oct_new(buffer, len * 8, err);
543
0
    if (NULL == jwk)
544
0
    {
545
0
        goto create_oct_failed;
546
0
    }
547
548
0
    return jwk;
549
550
0
create_oct_failed:
551
0
    if (buffer)
552
0
    {
553
0
        cjose_get_dealloc()(buffer);
554
0
        buffer = NULL;
555
0
    }
556
557
0
    return NULL;
558
0
}
559
560
//////////////// Elliptic Curve ////////////////
561
// internal data & functions -- Elliptic Curve
562
563
static void _EC_free(cjose_jwk_t *jwk);
564
static bool _EC_public_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err);
565
static bool _EC_private_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err);
566
567
static const key_fntable EC_FNTABLE = { _EC_free, _EC_public_fields, _EC_private_fields };
568
569
static inline uint8_t _ec_size_for_curve(cjose_jwk_ec_curve crv, cjose_err *err)
570
0
{
571
0
    switch (crv)
572
0
    {
573
0
    case CJOSE_JWK_EC_P_256:
574
0
        return 32;
575
0
    case CJOSE_JWK_EC_P_384:
576
0
        return 48;
577
0
    case CJOSE_JWK_EC_P_521:
578
0
        return 66;
579
0
    case CJOSE_JWK_EC_INVALID:
580
0
        return 0;
581
0
    }
582
583
0
    return 0;
584
0
}
585
586
static inline const char *_ec_name_for_curve(cjose_jwk_ec_curve crv, cjose_err *err)
587
0
{
588
0
    switch (crv)
589
0
    {
590
0
    case CJOSE_JWK_EC_P_256:
591
0
        return CJOSE_JWK_EC_P_256_STR;
592
0
    case CJOSE_JWK_EC_P_384:
593
0
        return CJOSE_JWK_EC_P_384_STR;
594
0
    case CJOSE_JWK_EC_P_521:
595
0
        return CJOSE_JWK_EC_P_521_STR;
596
0
    case CJOSE_JWK_EC_INVALID:
597
0
        return NULL;
598
0
    }
599
600
0
    return NULL;
601
0
}
602
603
static inline bool _ec_curve_from_name(const char *name, cjose_jwk_ec_curve *crv, cjose_err *err)
604
0
{
605
0
    bool retval = true;
606
0
    if (strncmp(name, CJOSE_JWK_EC_P_256_STR, sizeof(CJOSE_JWK_EC_P_256_STR)) == 0)
607
0
    {
608
0
        *crv = CJOSE_JWK_EC_P_256;
609
0
    }
610
0
    else if (strncmp(name, CJOSE_JWK_EC_P_384_STR, sizeof(CJOSE_JWK_EC_P_384_STR)) == 0)
611
0
    {
612
0
        *crv = CJOSE_JWK_EC_P_384;
613
0
    }
614
0
    else if (strncmp(name, CJOSE_JWK_EC_P_521_STR, sizeof(CJOSE_JWK_EC_P_521_STR)) == 0)
615
0
    {
616
0
        *crv = CJOSE_JWK_EC_P_521;
617
0
    }
618
0
    else
619
0
    {
620
0
        retval = false;
621
0
    }
622
0
    return retval;
623
0
}
624
625
static inline bool _kty_from_name(const char *name, cjose_jwk_kty_t *kty, cjose_err *err)
626
0
{
627
0
    bool retval = true;
628
0
    if (strncmp(name, CJOSE_JWK_KTY_EC_STR, sizeof(CJOSE_JWK_KTY_EC_STR)) == 0)
629
0
    {
630
0
        *kty = CJOSE_JWK_KTY_EC;
631
0
    }
632
0
    else if (strncmp(name, CJOSE_JWK_KTY_RSA_STR, sizeof(CJOSE_JWK_KTY_RSA_STR)) == 0)
633
0
    {
634
0
        *kty = CJOSE_JWK_KTY_RSA;
635
0
    }
636
0
    else if (strncmp(name, CJOSE_JWK_KTY_OCT_STR, sizeof(CJOSE_JWK_KTY_OCT_STR)) == 0)
637
0
    {
638
0
        *kty = CJOSE_JWK_KTY_OCT;
639
0
    }
640
0
    else
641
0
    {
642
0
        retval = false;
643
0
    }
644
0
    return retval;
645
0
}
646
647
static cjose_jwk_t *_EC_new(cjose_jwk_ec_curve crv, EC_KEY *ec, cjose_err *err)
648
0
{
649
0
    ec_keydata *keydata = cjose_get_alloc()(sizeof(ec_keydata));
650
0
    if (!keydata)
651
0
    {
652
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
653
0
        return NULL;
654
0
    }
655
0
    keydata->crv = crv;
656
0
    keydata->key = ec;
657
658
0
    cjose_jwk_t *jwk = cjose_get_alloc()(sizeof(cjose_jwk_t));
659
0
    if (!jwk)
660
0
    {
661
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
662
0
        cjose_get_dealloc()(keydata);
663
0
        return NULL;
664
0
    }
665
0
    memset(jwk, 0, sizeof(cjose_jwk_t));
666
0
    jwk->retained = 1;
667
0
    jwk->kty = CJOSE_JWK_KTY_EC;
668
0
    switch (crv)
669
0
    {
670
0
    case CJOSE_JWK_EC_P_256:
671
0
        jwk->keysize = 256;
672
0
        break;
673
0
    case CJOSE_JWK_EC_P_384:
674
0
        jwk->keysize = 384;
675
0
        break;
676
0
    case CJOSE_JWK_EC_P_521:
677
0
        jwk->keysize = 521;
678
0
        break;
679
0
    case CJOSE_JWK_EC_INVALID:
680
        // should never happen
681
0
        jwk->keysize = 0;
682
0
        break;
683
0
    }
684
0
    jwk->keydata = keydata;
685
0
    jwk->fns = &EC_FNTABLE;
686
687
0
    return jwk;
688
0
}
689
690
static void _EC_free(cjose_jwk_t *jwk)
691
0
{
692
0
    ec_keydata *keydata = (ec_keydata *)jwk->keydata;
693
0
    jwk->keydata = NULL;
694
695
0
    if (keydata)
696
0
    {
697
0
        EC_KEY *ec = keydata->key;
698
0
        keydata->key = NULL;
699
0
        if (ec)
700
0
        {
701
0
            EC_KEY_free(ec);
702
0
        }
703
0
        cjose_get_dealloc()(keydata);
704
0
    }
705
0
    cjose_get_dealloc()(jwk);
706
0
}
707
708
static bool _EC_public_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err)
709
0
{
710
0
    ec_keydata *keydata = (ec_keydata *)jwk->keydata;
711
0
    const EC_GROUP *params = NULL;
712
0
    const EC_POINT *pub = NULL;
713
0
    BIGNUM *bnX = NULL, *bnY = NULL;
714
0
    uint8_t *buffer = NULL;
715
0
    char *b64u = NULL;
716
0
    size_t len = 0, offset = 0;
717
0
    json_t *field = NULL;
718
0
    bool result = false;
719
720
    // track expected binary data size
721
0
    uint8_t numsize = _ec_size_for_curve(keydata->crv, err);
722
723
    // output the curve
724
0
    field = json_string(_ec_name_for_curve(keydata->crv, err));
725
0
    if (!field)
726
0
    {
727
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
728
0
        goto _ec_to_string_cleanup;
729
0
    }
730
0
    json_object_set(json, "crv", field);
731
0
    json_decref(field);
732
0
    field = NULL;
733
734
    // obtain the public key
735
0
    pub = EC_KEY_get0_public_key(keydata->key);
736
0
    params = EC_KEY_get0_group(keydata->key);
737
0
    if (!pub || !params)
738
0
    {
739
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
740
0
        goto _ec_to_string_cleanup;
741
0
    }
742
743
0
    buffer = cjose_get_alloc()(numsize);
744
0
    bnX = BN_new();
745
0
    bnY = BN_new();
746
0
    if (!buffer || !bnX || !bnY)
747
0
    {
748
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
749
0
        goto _ec_to_string_cleanup;
750
0
    }
751
0
    if (1 != EC_POINT_get_affine_coordinates_GFp(params, pub, bnX, bnY, NULL))
752
0
    {
753
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
754
0
        goto _ec_to_string_cleanup;
755
0
    }
756
757
    // output the x coordinate
758
0
    offset = numsize - BN_num_bytes(bnX);
759
0
    memset(buffer, 0, numsize);
760
0
    BN_bn2bin(bnX, (buffer + offset));
761
0
    if (!cjose_base64url_encode(buffer, numsize, &b64u, &len, err))
762
0
    {
763
0
        goto _ec_to_string_cleanup;
764
0
    }
765
0
    field = _cjose_json_stringn(b64u, len, err);
766
0
    if (!field)
767
0
    {
768
0
        goto _ec_to_string_cleanup;
769
0
    }
770
0
    json_object_set(json, "x", field);
771
0
    json_decref(field);
772
0
    field = NULL;
773
0
    cjose_get_dealloc()(b64u);
774
0
    b64u = NULL;
775
776
    // output the y coordinate
777
0
    offset = numsize - BN_num_bytes(bnY);
778
0
    memset(buffer, 0, numsize);
779
0
    BN_bn2bin(bnY, (buffer + offset));
780
0
    if (!cjose_base64url_encode(buffer, numsize, &b64u, &len, err))
781
0
    {
782
0
        goto _ec_to_string_cleanup;
783
0
    }
784
0
    field = _cjose_json_stringn(b64u, len, err);
785
0
    if (!field)
786
0
    {
787
0
        goto _ec_to_string_cleanup;
788
0
    }
789
0
    json_object_set(json, "y", field);
790
0
    json_decref(field);
791
0
    field = NULL;
792
0
    cjose_get_dealloc()(b64u);
793
0
    b64u = NULL;
794
795
0
    result = true;
796
797
0
_ec_to_string_cleanup:
798
0
    if (field)
799
0
    {
800
0
        json_decref(field);
801
0
    }
802
0
    if (bnX)
803
0
    {
804
0
        BN_free(bnX);
805
0
    }
806
0
    if (bnY)
807
0
    {
808
0
        BN_free(bnY);
809
0
    }
810
0
    if (buffer)
811
0
    {
812
0
        cjose_get_dealloc()(buffer);
813
0
    }
814
0
    if (b64u)
815
0
    {
816
0
        cjose_get_dealloc()(b64u);
817
0
    }
818
819
0
    return result;
820
0
}
821
822
static bool _EC_private_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err)
823
0
{
824
0
    ec_keydata *keydata = (ec_keydata *)jwk->keydata;
825
0
    const BIGNUM *bnD = EC_KEY_get0_private_key(keydata->key);
826
0
    uint8_t *buffer = NULL;
827
0
    char *b64u = NULL;
828
0
    size_t len = 0, offset = 0;
829
0
    json_t *field = NULL;
830
0
    bool result = false;
831
832
    // track expected binary data size
833
0
    uint8_t numsize = _ec_size_for_curve(keydata->crv, err);
834
835
    // short circuit if 'd' is NULL or 0
836
0
    if (!bnD || BN_is_zero(bnD))
837
0
    {
838
0
        return true;
839
0
    }
840
841
0
    buffer = cjose_get_alloc()(numsize);
842
0
    if (!buffer)
843
0
    {
844
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
845
0
        goto _ec_to_string_cleanup;
846
0
    }
847
848
0
    offset = numsize - BN_num_bytes(bnD);
849
0
    memset(buffer, 0, numsize);
850
0
    BN_bn2bin(bnD, (buffer + offset));
851
0
    if (!cjose_base64url_encode(buffer, numsize, &b64u, &len, err))
852
0
    {
853
0
        goto _ec_to_string_cleanup;
854
0
    }
855
0
    field = _cjose_json_stringn(b64u, len, err);
856
0
    if (!field)
857
0
    {
858
0
        goto _ec_to_string_cleanup;
859
0
    }
860
0
    json_object_set(json, "d", field);
861
0
    json_decref(field);
862
0
    field = NULL;
863
864
0
    result = true;
865
866
0
_ec_to_string_cleanup:
867
    // buffer and b64u hold the raw / base64url-encoded private key 'd';
868
    // wipe them before release on the success path as well as the
869
    // _cjose_json_stringn failure path (where b64u would otherwise leak)
870
0
    _cjose_cleanse_dealloc(buffer, numsize);
871
0
    _cjose_cleanse_dealloc(b64u, len);
872
873
0
    return result;
874
0
}
875
876
// interface functions -- Elliptic Curve
877
878
cjose_jwk_t *cjose_jwk_create_EC_random(cjose_jwk_ec_curve crv, cjose_err *err)
879
0
{
880
0
    cjose_jwk_t *jwk = NULL;
881
0
    EC_KEY *ec = NULL;
882
883
0
    ec = EC_KEY_new_by_curve_name(crv);
884
0
    if (!ec)
885
0
    {
886
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
887
0
        goto create_EC_failed;
888
0
    }
889
890
0
    if (1 != EC_KEY_generate_key(ec))
891
0
    {
892
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
893
0
        goto create_EC_failed;
894
0
    }
895
896
0
    jwk = _EC_new(crv, ec, err);
897
0
    if (!jwk)
898
0
    {
899
0
        goto create_EC_failed;
900
0
    }
901
902
0
    return jwk;
903
904
0
create_EC_failed:
905
0
    if (jwk)
906
0
    {
907
0
        cjose_get_dealloc()(jwk);
908
0
        jwk = NULL;
909
0
    }
910
0
    if (ec)
911
0
    {
912
0
        EC_KEY_free(ec);
913
0
        ec = NULL;
914
0
    }
915
916
0
    return NULL;
917
0
}
918
919
cjose_jwk_t *cjose_jwk_create_EC_spec(const cjose_jwk_ec_keyspec *spec, cjose_err *err)
920
0
{
921
0
    cjose_jwk_t *jwk = NULL;
922
0
    EC_KEY *ec = NULL;
923
0
    EC_GROUP *params = NULL;
924
0
    EC_POINT *Q = NULL;
925
0
    BIGNUM *bnD = NULL;
926
0
    BIGNUM *bnX = NULL;
927
0
    BIGNUM *bnY = NULL;
928
929
0
    if (!spec)
930
0
    {
931
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
932
0
        return NULL;
933
0
    }
934
935
0
    bool hasPriv = (NULL != spec->d && 0 < spec->dlen);
936
0
    bool hasPub = ((NULL != spec->x && 0 < spec->xlen) && (NULL != spec->y && 0 < spec->ylen));
937
0
    if (!hasPriv && !hasPub)
938
0
    {
939
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
940
0
        return NULL;
941
0
    }
942
943
0
    ec = EC_KEY_new_by_curve_name(spec->crv);
944
0
    if (NULL == ec)
945
0
    {
946
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
947
0
        goto create_EC_failed;
948
0
    }
949
950
0
    params = (EC_GROUP *)EC_KEY_get0_group(ec);
951
0
    if (NULL == params)
952
0
    {
953
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
954
0
        goto create_EC_failed;
955
0
    }
956
957
    // convert d from octet string to BIGNUM
958
0
    if (hasPriv)
959
0
    {
960
0
        bnD = BN_bin2bn(spec->d, spec->dlen, NULL);
961
0
        if (NULL == bnD)
962
0
        {
963
0
            CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
964
0
            goto create_EC_failed;
965
0
        }
966
0
        if (1 != EC_KEY_set_private_key(ec, bnD))
967
0
        {
968
0
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
969
0
            goto create_EC_failed;
970
0
        }
971
972
        // calculate public key from private
973
0
        Q = EC_POINT_new(params);
974
0
        if (NULL == Q)
975
0
        {
976
0
            CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
977
0
            goto create_EC_failed;
978
0
        }
979
0
        if (1 != EC_POINT_mul(params, Q, bnD, NULL, NULL, NULL))
980
0
        {
981
0
            CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
982
0
            goto create_EC_failed;
983
0
        }
984
985
        // public key is set below
986
        // ignore provided public key!
987
0
        hasPub = false;
988
0
    }
989
0
    if (hasPub)
990
0
    {
991
0
        Q = EC_POINT_new(params);
992
0
        if (NULL == Q)
993
0
        {
994
0
            CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
995
0
            goto create_EC_failed;
996
0
        }
997
998
0
        bnX = BN_bin2bn(spec->x, spec->xlen, NULL);
999
0
        bnY = BN_bin2bn(spec->y, spec->ylen, NULL);
1000
0
        if (!bnX || !bnY)
1001
0
        {
1002
0
            CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1003
0
            goto create_EC_failed;
1004
0
        }
1005
1006
0
        if (1 != EC_POINT_set_affine_coordinates_GFp(params, Q, bnX, bnY, NULL))
1007
0
        {
1008
0
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1009
0
            goto create_EC_failed;
1010
0
        }
1011
1012
0
        if (1 != EC_POINT_is_on_curve(params, Q, NULL))
1013
0
        {
1014
0
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1015
0
            goto create_EC_failed;
1016
0
        }
1017
0
    }
1018
1019
    // always set the public key
1020
0
    if (1 != EC_KEY_set_public_key(ec, Q))
1021
0
    {
1022
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1023
0
        goto create_EC_failed;
1024
0
    }
1025
1026
0
    if (1 != EC_KEY_check_key(ec))
1027
0
    {
1028
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1029
0
        goto create_EC_failed;
1030
0
    }
1031
1032
0
    jwk = _EC_new(spec->crv, ec, err);
1033
0
    if (!jwk)
1034
0
    {
1035
0
        goto create_EC_failed;
1036
0
    }
1037
1038
    // jump to cleanup
1039
0
    goto create_EC_cleanup;
1040
1041
0
create_EC_failed:
1042
0
    if (jwk)
1043
0
    {
1044
0
        cjose_get_dealloc()(jwk);
1045
0
        jwk = NULL;
1046
0
    }
1047
0
    if (ec)
1048
0
    {
1049
0
        EC_KEY_free(ec);
1050
0
        ec = NULL;
1051
0
    }
1052
1053
0
create_EC_cleanup:
1054
0
    if (Q)
1055
0
    {
1056
0
        EC_POINT_free(Q);
1057
0
        Q = NULL;
1058
0
    }
1059
0
    if (bnD)
1060
0
    {
1061
0
        BN_free(bnD);
1062
0
        bnD = NULL;
1063
0
    }
1064
0
    if (bnX)
1065
0
    {
1066
0
        BN_free(bnX);
1067
0
        bnX = NULL;
1068
0
    }
1069
0
    if (bnY)
1070
0
    {
1071
0
        BN_free(bnY);
1072
0
        bnY = NULL;
1073
0
    }
1074
1075
0
    return jwk;
1076
0
}
1077
1078
cjose_jwk_ec_curve cjose_jwk_EC_get_curve(const cjose_jwk_t *jwk, cjose_err *err)
1079
0
{
1080
0
    if (NULL == jwk || CJOSE_JWK_KTY_EC != cjose_jwk_get_kty(jwk, err))
1081
0
    {
1082
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1083
0
        return CJOSE_JWK_EC_INVALID;
1084
0
    }
1085
1086
0
    ec_keydata *keydata = jwk->keydata;
1087
0
    return keydata->crv;
1088
0
}
1089
1090
//////////////// RSA ////////////////
1091
// internal data & functions -- RSA
1092
1093
static void _RSA_free(cjose_jwk_t *jwk);
1094
static bool _RSA_public_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err);
1095
static bool _RSA_private_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err);
1096
1097
static const key_fntable RSA_FNTABLE = { _RSA_free, _RSA_public_fields, _RSA_private_fields };
1098
1099
static inline cjose_jwk_t *_RSA_new(RSA *rsa, cjose_err *err)
1100
0
{
1101
0
    cjose_jwk_t *jwk = cjose_get_alloc()(sizeof(cjose_jwk_t));
1102
0
    if (!jwk)
1103
0
    {
1104
        // _RSA_new owns rsa on every path; free it here so the callers that
1105
        // `return _RSA_new(rsa, err)` do not leak it on allocation failure
1106
0
        RSA_free(rsa);
1107
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1108
0
        return NULL;
1109
0
    }
1110
0
    memset(jwk, 0, sizeof(cjose_jwk_t));
1111
0
    jwk->retained = 1;
1112
0
    jwk->kty = CJOSE_JWK_KTY_RSA;
1113
0
    jwk->keysize = RSA_size(rsa) * 8;
1114
0
    jwk->keydata = rsa;
1115
0
    jwk->fns = &RSA_FNTABLE;
1116
1117
0
    return jwk;
1118
0
}
1119
1120
static void _RSA_free(cjose_jwk_t *jwk)
1121
0
{
1122
0
    RSA *rsa = (RSA *)jwk->keydata;
1123
0
    jwk->keydata = NULL;
1124
0
    if (rsa)
1125
0
    {
1126
0
        RSA_free(rsa);
1127
0
    }
1128
0
    cjose_get_dealloc()(jwk);
1129
0
}
1130
1131
static inline bool _RSA_json_field(BIGNUM *param, const char *name, json_t *json, cjose_err *err)
1132
0
{
1133
0
    json_t *field = NULL;
1134
0
    uint8_t *data = NULL;
1135
0
    char *b64u = NULL;
1136
0
    size_t datalen = 0, b64ulen = 0;
1137
0
    bool result = false;
1138
1139
0
    if (!param)
1140
0
    {
1141
0
        return true;
1142
0
    }
1143
1144
0
    datalen = BN_num_bytes(param);
1145
0
    data = cjose_get_alloc()(sizeof(uint8_t) * datalen);
1146
0
    if (!data)
1147
0
    {
1148
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1149
0
        goto RSA_json_field_cleanup;
1150
0
    }
1151
0
    BN_bn2bin(param, data);
1152
0
    if (!cjose_base64url_encode(data, datalen, &b64u, &b64ulen, err))
1153
0
    {
1154
0
        goto RSA_json_field_cleanup;
1155
0
    }
1156
0
    field = _cjose_json_stringn(b64u, b64ulen, err);
1157
0
    if (!field)
1158
0
    {
1159
0
        goto RSA_json_field_cleanup;
1160
0
    }
1161
0
    json_object_set(json, name, field);
1162
0
    json_decref(field);
1163
0
    field = NULL;
1164
0
    result = true;
1165
1166
0
RSA_json_field_cleanup:
1167
    // data / b64u may hold a private key component (d, p, q, dp, dq, qi);
1168
    // wipe them before release (harmless for the public n and e)
1169
0
    _cjose_cleanse_dealloc(b64u, b64ulen);
1170
0
    b64u = NULL;
1171
0
    _cjose_cleanse_dealloc(data, datalen);
1172
0
    data = NULL;
1173
1174
0
    return result;
1175
0
}
1176
1177
static bool _RSA_public_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err)
1178
0
{
1179
0
    RSA *rsa = (RSA *)jwk->keydata;
1180
1181
0
    BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
1182
0
    _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d);
1183
1184
0
    if (!_RSA_json_field(rsa_e, "e", json, err))
1185
0
    {
1186
0
        return false;
1187
0
    }
1188
0
    if (!_RSA_json_field(rsa_n, "n", json, err))
1189
0
    {
1190
0
        return false;
1191
0
    }
1192
1193
0
    return true;
1194
0
}
1195
1196
static bool _RSA_private_fields(const cjose_jwk_t *jwk, json_t *json, cjose_err *err)
1197
0
{
1198
0
    RSA *rsa = (RSA *)jwk->keydata;
1199
1200
0
    BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
1201
0
    _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d);
1202
1203
0
    BIGNUM *rsa_p = NULL, *rsa_q = NULL;
1204
0
    _cjose_jwk_rsa_get_factors(rsa, &rsa_p, &rsa_q);
1205
1206
0
    BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL, *rsa_iqmp = NULL;
1207
0
    _cjose_jwk_rsa_get_crt(rsa, &rsa_dmp1, &rsa_dmq1, &rsa_iqmp);
1208
1209
0
    if (!_RSA_json_field(rsa_d, "d", json, err))
1210
0
    {
1211
0
        return false;
1212
0
    }
1213
0
    if (!_RSA_json_field(rsa_p, "p", json, err))
1214
0
    {
1215
0
        return false;
1216
0
    }
1217
0
    if (!_RSA_json_field(rsa_q, "q", json, err))
1218
0
    {
1219
0
        return false;
1220
0
    }
1221
0
    if (!_RSA_json_field(rsa_dmp1, "dp", json, err))
1222
0
    {
1223
0
        return false;
1224
0
    }
1225
0
    if (!_RSA_json_field(rsa_dmq1, "dq", json, err))
1226
0
    {
1227
0
        return false;
1228
0
    }
1229
0
    if (!_RSA_json_field(rsa_iqmp, "qi", json, err))
1230
0
    {
1231
0
        return false;
1232
0
    }
1233
1234
0
    return true;
1235
0
}
1236
1237
// interface functions -- RSA
1238
static const uint8_t *DEFAULT_E_DAT = (const uint8_t *)"\x01\x00\x01";
1239
static const size_t DEFAULT_E_LEN = 3;
1240
1241
cjose_jwk_t *cjose_jwk_create_RSA_random(size_t keysize, const uint8_t *e, size_t elen, cjose_err *err)
1242
0
{
1243
    // RFC 7518 §3.3 requires minimum 2048-bit RSA modulus for RS*/PS*/RSA-OAEP/RSA1_5
1244
0
    if (keysize < 2048)
1245
0
    {
1246
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1247
0
        return NULL;
1248
0
    }
1249
0
    if (NULL == e || 0 >= elen)
1250
0
    {
1251
0
        e = DEFAULT_E_DAT;
1252
0
        elen = DEFAULT_E_LEN;
1253
0
    }
1254
1255
0
    RSA *rsa = NULL;
1256
0
    BIGNUM *bn = NULL;
1257
1258
0
    rsa = RSA_new();
1259
0
    if (!rsa)
1260
0
    {
1261
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1262
0
        goto create_RSA_random_failed;
1263
0
    }
1264
1265
0
    bn = BN_bin2bn(e, elen, NULL);
1266
0
    if (!bn)
1267
0
    {
1268
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1269
0
        goto create_RSA_random_failed;
1270
0
    }
1271
1272
0
    if (0 == RSA_generate_key_ex(rsa, keysize, bn, NULL))
1273
0
    {
1274
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1275
0
        goto create_RSA_random_failed;
1276
0
    }
1277
1278
0
    BN_free(bn);
1279
0
    return _RSA_new(rsa, err);
1280
1281
0
create_RSA_random_failed:
1282
0
    if (bn)
1283
0
    {
1284
0
        BN_free(bn);
1285
0
    }
1286
0
    if (rsa)
1287
0
    {
1288
0
        RSA_free(rsa);
1289
0
    }
1290
0
    return NULL;
1291
0
}
1292
1293
cjose_jwk_t *cjose_jwk_create_RSA_spec(const cjose_jwk_rsa_keyspec *spec, cjose_err *err)
1294
0
{
1295
0
    if (NULL == spec)
1296
0
    {
1297
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1298
0
        return NULL;
1299
0
    }
1300
1301
0
    bool hasPub = (NULL != spec->n && 0 < spec->nlen) && (NULL != spec->e && 0 < spec->elen);
1302
0
    bool hasPriv = (NULL != spec->n && 0 < spec->nlen) && (NULL != spec->d && 0 < spec->dlen);
1303
0
    if (!hasPub && !hasPriv)
1304
0
    {
1305
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1306
0
        return NULL;
1307
0
    }
1308
1309
    // RFC 7518 §3.3 requires minimum 2048-bit RSA modulus for RS*/PS*/RSA-OAEP/RSA1_5
1310
0
    BIGNUM *n_bn = BN_bin2bn(spec->n, spec->nlen, NULL);
1311
0
    if (NULL == n_bn)
1312
0
    {
1313
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1314
0
        return NULL;
1315
0
    }
1316
0
    if (BN_num_bits(n_bn) < 2048)
1317
0
    {
1318
0
        BN_free(n_bn);
1319
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1320
0
        return NULL;
1321
0
    }
1322
0
    BN_free(n_bn);
1323
1324
0
    RSA *rsa = NULL;
1325
0
    rsa = RSA_new();
1326
0
    if (!rsa)
1327
0
    {
1328
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1329
0
        return NULL;
1330
0
    }
1331
1332
0
    if (hasPriv)
1333
0
    {
1334
0
        if (!_cjose_jwk_rsa_set(rsa, spec->n, spec->nlen, spec->e, spec->elen, spec->d, spec->dlen))
1335
0
        {
1336
0
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1337
0
            goto create_RSA_spec_failed;
1338
0
        }
1339
0
        if (!_cjose_jwk_rsa_set_factors(rsa, spec->p, spec->plen, spec->q, spec->qlen)
1340
0
            || !_cjose_jwk_rsa_set_crt(rsa, spec->dp, spec->dplen, spec->dq, spec->dqlen, spec->qi, spec->qilen))
1341
0
        {
1342
0
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1343
0
            goto create_RSA_spec_failed;
1344
0
        }
1345
0
    }
1346
0
    else if (hasPub)
1347
0
    {
1348
0
        if (!_cjose_jwk_rsa_set(rsa, spec->n, spec->nlen, spec->e, spec->elen, NULL, 0))
1349
0
        {
1350
0
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1351
0
            goto create_RSA_spec_failed;
1352
0
        }
1353
0
    }
1354
1355
0
    return _RSA_new(rsa, err);
1356
1357
0
create_RSA_spec_failed:
1358
0
    if (rsa)
1359
0
    {
1360
0
        RSA_free(rsa);
1361
0
    }
1362
1363
0
    return NULL;
1364
0
}
1365
1366
//////////////// Import ////////////////
1367
// internal data & functions -- JWK key import
1368
1369
static const char *_get_json_object_string_attribute(json_t *json, const char *key, cjose_err *err)
1370
0
{
1371
0
    const char *attr_str = NULL;
1372
0
    json_t *attr_json = json_object_get(json, key);
1373
0
    if (NULL != attr_json)
1374
0
    {
1375
0
        attr_str = json_string_value(attr_json);
1376
0
    }
1377
0
    return attr_str;
1378
0
}
1379
1380
/**
1381
 * Internal helper function for extracing an octet string from a base64url
1382
 * encoded field.  Caller provides the json object, the attribute key,
1383
 * and an expected length for the octet string.  On successful decoding,
1384
 * this will return a newly allocated buffer with the decoded octet string
1385
 * of the expected length.
1386
 *
1387
 * Note: caller is responsible for freeing the buffer returned by this function.
1388
 *
1389
 * \param[in]     json the JSON object from which to read the attribute.
1390
 * \param[in]     key the name of the attribute to be decoded.
1391
 * \param[out]    pointer to buffer of octet string (if decoding succeeds).
1392
 * \param[in/out] in as the expected length of the attribute, out as the
1393
 *                actual decoded length.  Note, this method succeeds only
1394
 *                if the actual decoded length matches the expected length.
1395
 *                If the in-value is 0 this indicates there is no particular
1396
 *                expected length (i.e. any length is ok).
1397
 * \returns true  if attribute is either not present or successfully decoded.
1398
 *                false otherwise.
1399
 */
1400
static bool
1401
_decode_json_object_base64url_attribute(json_t *jwk_json, const char *key, uint8_t **buffer, size_t *buflen, cjose_err *err)
1402
0
{
1403
    // get the base64url encoded string value of the attribute (if any)
1404
0
    const char *str = _get_json_object_string_attribute(jwk_json, key, err);
1405
0
    if (str == NULL || strlen(str) == 0)
1406
0
    {
1407
0
        *buflen = 0;
1408
0
        *buffer = NULL;
1409
0
        return true;
1410
0
    }
1411
1412
    // if a particular decoded length is expected, check for that
1413
0
    if (*buflen != 0)
1414
0
    {
1415
0
        const char *end = NULL;
1416
0
        for (end = str + strlen(str) - 1; *end == '=' && end > str; --end)
1417
0
            ;
1418
0
        size_t unpadded_len = end + 1 - str - ((*end == '=') ? 1 : 0);
1419
        // number of unpadded base64url characters for *buflen bytes,
1420
        // i.e. ceil(4 * buflen / 3) computed with integer arithmetic
1421
0
        size_t expected_len = (4 * (*buflen) + 2) / 3;
1422
1423
0
        if (expected_len != unpadded_len)
1424
0
        {
1425
0
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1426
0
            *buflen = 0;
1427
0
            *buffer = NULL;
1428
0
            return false;
1429
0
        }
1430
0
    }
1431
1432
    // decode the base64url encoded string to the allocated buffer
1433
0
    if (!cjose_base64url_decode(str, strlen(str), buffer, buflen, err))
1434
0
    {
1435
0
        *buflen = 0;
1436
0
        *buffer = NULL;
1437
0
        return false;
1438
0
    }
1439
1440
0
    return true;
1441
0
}
1442
1443
static cjose_jwk_t *_cjose_jwk_import_EC(json_t *jwk_json, cjose_err *err)
1444
0
{
1445
0
    cjose_jwk_t *jwk = NULL;
1446
0
    uint8_t *x_buffer = NULL;
1447
0
    uint8_t *y_buffer = NULL;
1448
0
    uint8_t *d_buffer = NULL;
1449
0
    size_t x_buflen = 0;
1450
0
    size_t y_buflen = 0;
1451
0
    size_t d_buflen = 0;
1452
1453
    // get the value of the crv attribute
1454
0
    const char *crv_str = _get_json_object_string_attribute(jwk_json, CJOSE_JWK_CRV_STR, err);
1455
0
    if (crv_str == NULL)
1456
0
    {
1457
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1458
0
        goto import_EC_cleanup;
1459
0
    }
1460
1461
    // get the curve identifer for the curve named by crv
1462
0
    cjose_jwk_ec_curve crv;
1463
0
    if (!_ec_curve_from_name(crv_str, &crv, err))
1464
0
    {
1465
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1466
0
        goto import_EC_cleanup;
1467
0
    }
1468
1469
    // get the decoded value of the x coordinate
1470
0
    x_buflen = (size_t)_ec_size_for_curve(crv, err);
1471
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_X_STR, &x_buffer, &x_buflen, err))
1472
0
    {
1473
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1474
0
        goto import_EC_cleanup;
1475
0
    }
1476
1477
    // get the decoded value of the y coordinate
1478
0
    y_buflen = (size_t)_ec_size_for_curve(crv, err);
1479
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_Y_STR, &y_buffer, &y_buflen, err))
1480
0
    {
1481
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1482
0
        goto import_EC_cleanup;
1483
0
    }
1484
1485
    // get the decoded value of the private key d
1486
0
    d_buflen = (size_t)_ec_size_for_curve(crv, err);
1487
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_D_STR, &d_buffer, &d_buflen, err))
1488
0
    {
1489
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1490
0
        goto import_EC_cleanup;
1491
0
    }
1492
1493
    // create an ec keyspec
1494
0
    cjose_jwk_ec_keyspec ec_keyspec;
1495
0
    memset(&ec_keyspec, 0, sizeof(cjose_jwk_ec_keyspec));
1496
0
    ec_keyspec.crv = crv;
1497
0
    ec_keyspec.x = x_buffer;
1498
0
    ec_keyspec.xlen = x_buflen;
1499
0
    ec_keyspec.y = y_buffer;
1500
0
    ec_keyspec.ylen = y_buflen;
1501
0
    ec_keyspec.d = d_buffer;
1502
0
    ec_keyspec.dlen = d_buflen;
1503
1504
    // create the jwk
1505
0
    jwk = cjose_jwk_create_EC_spec(&ec_keyspec, err);
1506
1507
0
import_EC_cleanup:
1508
0
    if (NULL != x_buffer)
1509
0
    {
1510
0
        cjose_get_dealloc()(x_buffer);
1511
0
    }
1512
0
    if (NULL != y_buffer)
1513
0
    {
1514
0
        cjose_get_dealloc()(y_buffer);
1515
0
    }
1516
    // d is the private key -> wipe the decoded copy before release
1517
0
    if (NULL != d_buffer)
1518
0
    {
1519
0
        _cjose_cleanse_dealloc(d_buffer, d_buflen);
1520
0
    }
1521
1522
0
    return jwk;
1523
0
}
1524
1525
static cjose_jwk_t *_cjose_jwk_import_RSA(json_t *jwk_json, cjose_err *err)
1526
0
{
1527
0
    cjose_jwk_t *jwk = NULL;
1528
0
    uint8_t *n_buffer = NULL;
1529
0
    uint8_t *e_buffer = NULL;
1530
0
    uint8_t *d_buffer = NULL;
1531
0
    uint8_t *p_buffer = NULL;
1532
0
    uint8_t *q_buffer = NULL;
1533
0
    uint8_t *dp_buffer = NULL;
1534
0
    uint8_t *dq_buffer = NULL;
1535
0
    uint8_t *qi_buffer = NULL;
1536
0
    size_t n_buflen = 0;
1537
0
    size_t e_buflen = 0;
1538
0
    size_t d_buflen = 0;
1539
0
    size_t p_buflen = 0;
1540
0
    size_t q_buflen = 0;
1541
0
    size_t dp_buflen = 0;
1542
0
    size_t dq_buflen = 0;
1543
0
    size_t qi_buflen = 0;
1544
1545
    // get the decoded value of n (buflen = 0 means no particular expected len)
1546
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_N_STR, &n_buffer, &n_buflen, err))
1547
0
    {
1548
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1549
0
        goto import_RSA_cleanup;
1550
0
    }
1551
1552
    // get the decoded value of e
1553
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_E_STR, &e_buffer, &e_buflen, err))
1554
0
    {
1555
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1556
0
        goto import_RSA_cleanup;
1557
0
    }
1558
1559
    // get the decoded value of d
1560
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_D_STR, &d_buffer, &d_buflen, err))
1561
0
    {
1562
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1563
0
        goto import_RSA_cleanup;
1564
0
    }
1565
1566
    // get the decoded value of p
1567
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_P_STR, &p_buffer, &p_buflen, err))
1568
0
    {
1569
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1570
0
        goto import_RSA_cleanup;
1571
0
    }
1572
1573
    // get the decoded value of q
1574
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_Q_STR, &q_buffer, &q_buflen, err))
1575
0
    {
1576
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1577
0
        goto import_RSA_cleanup;
1578
0
    }
1579
1580
    // get the decoded value of dp
1581
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_DP_STR, &dp_buffer, &dp_buflen, err))
1582
0
    {
1583
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1584
0
        goto import_RSA_cleanup;
1585
0
    }
1586
1587
    // get the decoded value of dq
1588
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_DQ_STR, &dq_buffer, &dq_buflen, err))
1589
0
    {
1590
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1591
0
        goto import_RSA_cleanup;
1592
0
    }
1593
1594
    // get the decoded value of qi
1595
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_QI_STR, &qi_buffer, &qi_buflen, err))
1596
0
    {
1597
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1598
0
        goto import_RSA_cleanup;
1599
0
    }
1600
1601
    // create an rsa keyspec
1602
0
    cjose_jwk_rsa_keyspec rsa_keyspec;
1603
0
    memset(&rsa_keyspec, 0, sizeof(cjose_jwk_rsa_keyspec));
1604
0
    rsa_keyspec.n = n_buffer;
1605
0
    rsa_keyspec.nlen = n_buflen;
1606
0
    rsa_keyspec.e = e_buffer;
1607
0
    rsa_keyspec.elen = e_buflen;
1608
0
    rsa_keyspec.d = d_buffer;
1609
0
    rsa_keyspec.dlen = d_buflen;
1610
0
    rsa_keyspec.p = p_buffer;
1611
0
    rsa_keyspec.plen = p_buflen;
1612
0
    rsa_keyspec.q = q_buffer;
1613
0
    rsa_keyspec.qlen = q_buflen;
1614
0
    rsa_keyspec.dp = dp_buffer;
1615
0
    rsa_keyspec.dplen = dp_buflen;
1616
0
    rsa_keyspec.dq = dq_buffer;
1617
0
    rsa_keyspec.dqlen = dq_buflen;
1618
0
    rsa_keyspec.qi = qi_buffer;
1619
0
    rsa_keyspec.qilen = qi_buflen;
1620
1621
    // create the jwk
1622
0
    jwk = cjose_jwk_create_RSA_spec(&rsa_keyspec, err);
1623
1624
0
import_RSA_cleanup:
1625
    // n and e are public; the remaining decoded components are private -> wipe
1626
0
    cjose_get_dealloc()(n_buffer);
1627
0
    cjose_get_dealloc()(e_buffer);
1628
0
    _cjose_cleanse_dealloc(d_buffer, d_buflen);
1629
0
    _cjose_cleanse_dealloc(p_buffer, p_buflen);
1630
0
    _cjose_cleanse_dealloc(q_buffer, q_buflen);
1631
0
    _cjose_cleanse_dealloc(dp_buffer, dp_buflen);
1632
0
    _cjose_cleanse_dealloc(dq_buffer, dq_buflen);
1633
0
    _cjose_cleanse_dealloc(qi_buffer, qi_buflen);
1634
1635
0
    return jwk;
1636
0
}
1637
1638
static cjose_jwk_t *_cjose_jwk_import_oct(json_t *jwk_json, cjose_err *err)
1639
0
{
1640
0
    cjose_jwk_t *jwk = NULL;
1641
0
    uint8_t *k_buffer = NULL;
1642
1643
    // get the decoded value of k (buflen = 0 means no particular expected len)
1644
0
    size_t k_buflen = 0;
1645
0
    if (!_decode_json_object_base64url_attribute(jwk_json, CJOSE_JWK_K_STR, &k_buffer, &k_buflen, err))
1646
0
    {
1647
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1648
0
        goto import_oct_cleanup;
1649
0
    }
1650
1651
    // create the jwk
1652
0
    jwk = cjose_jwk_create_oct_spec(k_buffer, k_buflen, err);
1653
1654
0
import_oct_cleanup:
1655
    // k is secret symmetric key material -> wipe the decoded copy
1656
0
    _cjose_cleanse_dealloc(k_buffer, k_buflen);
1657
1658
0
    return jwk;
1659
0
}
1660
1661
cjose_jwk_t *cjose_jwk_import(const char *jwk_str, size_t len, cjose_err *err)
1662
0
{
1663
0
    cjose_jwk_t *jwk = NULL;
1664
1665
    // check params
1666
0
    if ((NULL == jwk_str) || (0 == len))
1667
0
    {
1668
0
        return NULL;
1669
0
    }
1670
1671
    // parse json content from the given string
1672
0
    json_t *jwk_json = json_loadb(jwk_str, len, 0, NULL);
1673
0
    if (NULL == jwk_json)
1674
0
    {
1675
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1676
0
        goto import_cleanup;
1677
0
    }
1678
1679
0
    jwk = cjose_jwk_import_json((cjose_header_t *)jwk_json, err);
1680
1681
// poor man's "finally"
1682
0
import_cleanup:
1683
0
    if (NULL != jwk_json)
1684
0
    {
1685
0
        json_decref(jwk_json);
1686
0
    }
1687
1688
0
    return jwk;
1689
0
}
1690
1691
cjose_jwk_t *cjose_jwk_import_json(cjose_header_t *json, cjose_err *err)
1692
0
{
1693
0
    cjose_jwk_t *jwk = NULL;
1694
1695
0
    json_t *jwk_json = (json_t *)json;
1696
1697
0
    if (NULL == jwk_json || JSON_OBJECT != json_typeof(jwk_json))
1698
0
    {
1699
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1700
0
        return NULL;
1701
0
    }
1702
1703
    // get the string value of the kty attribute of the jwk
1704
0
    const char *kty_str = _get_json_object_string_attribute(jwk_json, CJOSE_JWK_KTY_STR, err);
1705
0
    if (NULL == kty_str)
1706
0
    {
1707
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1708
0
        return NULL;
1709
0
    }
1710
1711
    // get kty corresponding to kty_str (kty is required)
1712
0
    cjose_jwk_kty_t kty;
1713
0
    if (!_kty_from_name(kty_str, &kty, err))
1714
0
    {
1715
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1716
0
        return NULL;
1717
0
    }
1718
1719
    // create a cjose_jwt_t based on the kty
1720
0
    switch (kty)
1721
0
    {
1722
0
    case CJOSE_JWK_KTY_EC:
1723
0
        jwk = _cjose_jwk_import_EC(jwk_json, err);
1724
0
        break;
1725
1726
0
    case CJOSE_JWK_KTY_RSA:
1727
0
        jwk = _cjose_jwk_import_RSA(jwk_json, err);
1728
0
        break;
1729
1730
0
    case CJOSE_JWK_KTY_OCT:
1731
0
        jwk = _cjose_jwk_import_oct(jwk_json, err);
1732
0
        break;
1733
1734
0
    default:
1735
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1736
0
        return NULL;
1737
0
    }
1738
0
    if (NULL == jwk)
1739
0
    {
1740
        // helper function will have already set err
1741
0
        return NULL;
1742
0
    }
1743
1744
    // get the value of the kid attribute (kid is optional)
1745
0
    const char *kid_str = _get_json_object_string_attribute(jwk_json, CJOSE_JWK_KID_STR, err);
1746
0
    if (kid_str != NULL)
1747
0
    {
1748
0
        jwk->kid = _cjose_strndup(kid_str, -1, err);
1749
0
        if (!jwk->kid)
1750
0
        {
1751
0
            cjose_jwk_release(jwk);
1752
0
            return NULL;
1753
0
        }
1754
0
    }
1755
1756
0
    return jwk;
1757
0
}
1758
1759
//////////////// ECDH ////////////////
1760
// internal data & functions -- ECDH derivation
1761
1762
static bool _cjose_jwk_evp_key_from_ec_key(const cjose_jwk_t *jwk, EVP_PKEY **key, cjose_err *err)
1763
0
{
1764
    // validate that the jwk is of type EC and we have a valid out-param
1765
0
    if (NULL == jwk || CJOSE_JWK_KTY_EC != jwk->kty || NULL == jwk->keydata || NULL == key || NULL != *key)
1766
0
    {
1767
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1768
0
        goto _cjose_jwk_evp_key_from_ec_key_fail;
1769
0
    }
1770
1771
    // create a blank EVP_PKEY
1772
0
    *key = EVP_PKEY_new();
1773
0
    if (NULL == *key)
1774
0
    {
1775
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1776
0
        goto _cjose_jwk_evp_key_from_ec_key_fail;
1777
0
    }
1778
1779
    // assign the EVP_PKEY to reference the jwk's internal EC_KEY structure
1780
0
    if (1 != EVP_PKEY_set1_EC_KEY(*key, ((struct _ec_keydata_int *)(jwk->keydata))->key))
1781
0
    {
1782
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1783
0
        goto _cjose_jwk_evp_key_from_ec_key_fail;
1784
0
    }
1785
1786
    // happy path
1787
0
    return true;
1788
1789
// fail path
1790
0
_cjose_jwk_evp_key_from_ec_key_fail:
1791
1792
0
    EVP_PKEY_free(*key);
1793
0
    *key = NULL;
1794
1795
0
    return false;
1796
0
}
1797
1798
cjose_jwk_t *cjose_jwk_derive_ecdh_secret(
1799
    const cjose_jwk_t *jwk_self, const cjose_jwk_t *jwk_peer, const uint8_t *salt, size_t salt_len, cjose_err *err)
1800
0
{
1801
0
    return cjose_jwk_derive_ecdh_ephemeral_key(jwk_self, jwk_peer, salt, salt_len, err);
1802
0
}
1803
1804
cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key(
1805
    const cjose_jwk_t *jwk_self, const cjose_jwk_t *jwk_peer, const uint8_t *salt, size_t salt_len, cjose_err *err)
1806
0
{
1807
0
    uint8_t *secret = NULL;
1808
0
    size_t secret_len = 0;
1809
0
    uint8_t *ephemeral_key = NULL;
1810
0
    size_t ephemeral_key_len = 0;
1811
0
    cjose_jwk_t *jwk_ephemeral_key = NULL;
1812
1813
0
    if (!cjose_jwk_derive_ecdh_bits(jwk_self, jwk_peer, &secret, &secret_len, err))
1814
0
    {
1815
0
        goto _cjose_jwk_derive_shared_secret_fail;
1816
0
    }
1817
1818
    // HKDF of the DH shared secret (SHA256, no info, 256 bit expand)
1819
0
    ephemeral_key_len = 32;
1820
0
    ephemeral_key = (uint8_t *)cjose_get_alloc()(ephemeral_key_len);
1821
0
    if (NULL == ephemeral_key)
1822
0
    {
1823
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1824
0
        goto _cjose_jwk_derive_shared_secret_fail;
1825
0
    }
1826
0
    if (!cjose_jwk_hkdf(EVP_sha256(), salt, salt_len, (uint8_t *)"", 0, secret, secret_len, ephemeral_key, ephemeral_key_len, err))
1827
0
    {
1828
0
        goto _cjose_jwk_derive_shared_secret_fail;
1829
0
    }
1830
1831
    // create a JWK of the shared secret
1832
0
    jwk_ephemeral_key = cjose_jwk_create_oct_spec(ephemeral_key, ephemeral_key_len, err);
1833
0
    if (NULL == jwk_ephemeral_key)
1834
0
    {
1835
0
        goto _cjose_jwk_derive_shared_secret_fail;
1836
0
    }
1837
1838
    // happy path
1839
0
    _cjose_cleanse_dealloc(secret, secret_len);
1840
0
    _cjose_cleanse_dealloc(ephemeral_key, ephemeral_key_len);
1841
1842
0
    return jwk_ephemeral_key;
1843
1844
// fail path
1845
0
_cjose_jwk_derive_shared_secret_fail:
1846
1847
0
    if (NULL != jwk_ephemeral_key)
1848
0
    {
1849
0
        cjose_jwk_release(jwk_ephemeral_key);
1850
0
    }
1851
0
    _cjose_cleanse_dealloc(secret, secret_len);
1852
0
    _cjose_cleanse_dealloc(ephemeral_key, ephemeral_key_len);
1853
0
    return NULL;
1854
0
}
1855
1856
bool cjose_jwk_derive_ecdh_bits(
1857
    const cjose_jwk_t *jwk_self, const cjose_jwk_t *jwk_peer, uint8_t **output, size_t *output_len, cjose_err *err)
1858
0
{
1859
0
    EVP_PKEY_CTX *ctx = NULL;
1860
0
    EVP_PKEY *pkey_self = NULL;
1861
0
    EVP_PKEY *pkey_peer = NULL;
1862
0
    uint8_t *secret = NULL;
1863
0
    size_t secret_len = 0;
1864
1865
    // get EVP_KEY from jwk_self
1866
0
    if (!_cjose_jwk_evp_key_from_ec_key(jwk_self, &pkey_self, err))
1867
0
    {
1868
0
        goto _cjose_jwk_derive_bits_fail;
1869
0
    }
1870
1871
    // get EVP_KEY from jwk_peer
1872
0
    if (!_cjose_jwk_evp_key_from_ec_key(jwk_peer, &pkey_peer, err))
1873
0
    {
1874
0
        goto _cjose_jwk_derive_bits_fail;
1875
0
    }
1876
1877
    // create derivation context based on local key pair
1878
0
    ctx = EVP_PKEY_CTX_new(pkey_self, NULL);
1879
0
    if (NULL == ctx)
1880
0
    {
1881
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1882
0
        goto _cjose_jwk_derive_bits_fail;
1883
0
    }
1884
1885
    // initialize derivation context
1886
0
    if (1 != EVP_PKEY_derive_init(ctx))
1887
0
    {
1888
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1889
0
        goto _cjose_jwk_derive_bits_fail;
1890
0
    }
1891
1892
    // provide the peer public key
1893
0
    if (1 != EVP_PKEY_derive_set_peer(ctx, pkey_peer))
1894
0
    {
1895
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1896
0
        goto _cjose_jwk_derive_bits_fail;
1897
0
    }
1898
1899
    // determine buffer length for shared secret
1900
0
    if (1 != EVP_PKEY_derive(ctx, NULL, &secret_len))
1901
0
    {
1902
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1903
0
        goto _cjose_jwk_derive_bits_fail;
1904
0
    }
1905
1906
    // allocate buffer for shared secret
1907
0
    secret = (uint8_t *)cjose_get_alloc()(secret_len);
1908
0
    if (NULL == secret)
1909
0
    {
1910
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1911
0
        goto _cjose_jwk_derive_bits_fail;
1912
0
    }
1913
0
    memset(secret, 0, secret_len);
1914
1915
    // derive the shared secret
1916
0
    if (1 != (EVP_PKEY_derive(ctx, secret, &secret_len)))
1917
0
    {
1918
0
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
1919
0
        goto _cjose_jwk_derive_bits_fail;
1920
0
    }
1921
1922
    // happy path
1923
0
    EVP_PKEY_CTX_free(ctx);
1924
0
    EVP_PKEY_free(pkey_self);
1925
0
    EVP_PKEY_free(pkey_peer);
1926
1927
0
    *output = secret;
1928
0
    *output_len = secret_len;
1929
0
    return true;
1930
1931
0
_cjose_jwk_derive_bits_fail:
1932
1933
0
    if (NULL != ctx)
1934
0
    {
1935
0
        EVP_PKEY_CTX_free(ctx);
1936
0
    }
1937
0
    if (NULL != pkey_self)
1938
0
    {
1939
0
        EVP_PKEY_free(pkey_self);
1940
0
    }
1941
0
    if (NULL != pkey_peer)
1942
0
    {
1943
0
        EVP_PKEY_free(pkey_peer);
1944
0
    }
1945
0
    _cjose_cleanse_dealloc(secret, secret_len);
1946
1947
0
    return false;
1948
0
}
1949
1950
bool cjose_jwk_hkdf(const EVP_MD *md,
1951
                    const uint8_t *salt,
1952
                    size_t salt_len,
1953
                    const uint8_t *info,
1954
                    size_t info_len,
1955
                    const uint8_t *ikm,
1956
                    size_t ikm_len,
1957
                    uint8_t *okm,
1958
                    unsigned int okm_len,
1959
                    cjose_err *err)
1960
0
{
1961
    // current impl. is very limited: SHA256, 256 bit output, and no info
1962
0
    if ((EVP_sha256() != md) || (0 != info_len) || (32 != okm_len))
1963
0
    {
1964
0
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
1965
0
        return false;
1966
0
    }
1967
1968
    // HKDF-Extract, HMAC-SHA256(salt, IKM) -> PRK
1969
0
    unsigned int prk_len;
1970
0
    unsigned char prk[EVP_MAX_MD_SIZE];
1971
0
    if (NULL == HMAC(md, salt, salt_len, ikm, ikm_len, prk, &prk_len))
1972
0
    {
1973
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1974
0
        return false;
1975
0
    }
1976
1977
    // HKDF-Expand, HMAC-SHA256(PRK,0x01) -> OKM
1978
0
    const unsigned char t[] = { 0x01 };
1979
0
    if (NULL == HMAC(md, prk, prk_len, t, sizeof(t), okm, NULL))
1980
0
    {
1981
0
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
1982
0
        _cjose_cleanse(prk, sizeof(prk));
1983
0
        return false;
1984
0
    }
1985
1986
0
    _cjose_cleanse(prk, sizeof(prk));
1987
    return true;
1988
0
}