Coverage Report

Created: 2025-11-09 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/openpace/src/pace_mappings.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2010-2012 Frank Morgner and Dominik Oepen
3
 *
4
 * This file is part of OpenPACE.
5
 *
6
 * OpenPACE is free software: you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free
8
 * Software Foundation, either version 3 of the License, or (at your option)
9
 * any later version.
10
 *
11
 * OpenPACE is distributed in the hope that it will be useful, but WITHOUT ANY
12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * OpenPACE.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * Additional permission under GNU GPL version 3 section 7
20
 *
21
 * If you modify this Program, or any covered work, by linking or combining it
22
 * with OpenSSL (or a modified version of that library), containing
23
 * parts covered by the terms of OpenSSL's license, the licensors of
24
 * this Program grant you additional permission to convey the resulting work.
25
 * Corresponding Source for a non-source form of such a combination shall include
26
 * the source code for the parts of OpenSSL used as well as that of the
27
 * covered work.
28
 *
29
 * If you modify this Program, or any covered work, by linking or combining it
30
 * with OpenSC (or a modified version of that library), containing
31
 * parts covered by the terms of OpenSC's license, the licensors of
32
 * this Program grant you additional permission to convey the resulting work. 
33
 * Corresponding Source for a non-source form of such a combination shall include
34
 * the source code for the parts of OpenSC used as well as that of the
35
 * covered work.
36
 */
37
38
/**
39
 * @file pace_mappings.c
40
 * @brief Functions for domain parameter mappings
41
 *
42
 * @author Frank Morgner <frankmorgner@gmail.com>
43
 * @author Dominik Oepen <oepen@informatik.hu-berlin.de>
44
 */
45
46
#ifdef HAVE_CONFIG_H
47
#include "config.h"
48
#endif
49
50
#include "eac_dh.h"
51
#include "eac_ecdh.h"
52
#include "eac_err.h"
53
#include "eac_util.h"
54
#include "misc.h"
55
#include "pace_mappings.h"
56
#include "ssl_compat.h"
57
#include <openssl/bn.h>
58
#include <openssl/crypto.h>
59
#include <openssl/ec.h>
60
#include <openssl/ecdh.h>
61
62
BUF_MEM *
63
dh_gm_generate_key(const PACE_CTX * ctx, BN_CTX *bn_ctx)
64
0
{
65
0
    check_return(ctx, "Invalid arguments");
66
67
0
    return dh_generate_key(ctx->static_key, bn_ctx);
68
0
}
69
70
int
71
dh_gm_compute_key(PACE_CTX * ctx, const BUF_MEM * s, const BUF_MEM * in,
72
        BN_CTX *bn_ctx)
73
0
{
74
0
    int ret = 0;
75
0
    BUF_MEM * mem_h = NULL;
76
0
    BIGNUM * bn_s = NULL, *bn_h = NULL, *bn_g = NULL, *new_g = NULL;
77
0
    DH *static_key = NULL, *ephemeral_key = NULL;
78
0
    const BIGNUM *p, *q, *g;
79
80
0
    check(ctx && ctx->static_key && s && ctx->ka_ctx, "Invalid arguments");
81
82
0
    BN_CTX_start(bn_ctx);
83
84
0
    static_key = EVP_PKEY_get1_DH(ctx->static_key);
85
0
    if (!static_key)
86
0
        goto err;
87
88
    /* Convert nonce to BIGNUM */
89
0
    bn_s = BN_bin2bn((unsigned char *) s->data, s->length, bn_s);
90
0
    if (!bn_s)
91
0
        goto err;
92
93
    /* complete the DH and convert the result to a BIGNUM */
94
0
    mem_h = dh_compute_key(ctx->static_key, in, bn_ctx);
95
0
    if (!mem_h)
96
0
        goto err;
97
0
    bn_h = BN_bin2bn((unsigned char *) mem_h->data, mem_h->length, bn_h);
98
0
    if (!bn_h)
99
0
        goto err;
100
101
    /* Initialize ephemeral parameters with parameters from the static key */
102
0
    ephemeral_key = DHparams_dup(static_key);
103
0
    if (!ephemeral_key)
104
0
        goto err;
105
106
0
    DH_get0_pqg(static_key, &p, &q, &g);
107
108
    /* map to new generator */
109
0
    bn_g = BN_CTX_get(bn_ctx);
110
0
    new_g = BN_new();
111
0
    if (!bn_g || !new_g ||
112
        /* bn_g = g^s mod p */
113
0
        !BN_mod_exp(bn_g, g, bn_s, p, bn_ctx) ||
114
        /* ephemeral_key->g = bn_g * h mod p = g^s * h mod p */
115
0
        !BN_mod_mul(new_g, bn_g, bn_h, p, bn_ctx))
116
0
        goto err;
117
118
0
    if (!DH_set0_pqg(ephemeral_key, BN_dup(p), BN_dup(q), new_g))
119
0
        goto err;
120
0
    new_g = NULL;
121
122
    /* Copy ephemeral key to context structure */
123
0
    if (!EVP_PKEY_set1_DH(ctx->ka_ctx->key, ephemeral_key))
124
0
        goto err;
125
126
0
    ret = 1;
127
128
0
err:
129
0
    if (mem_h) {
130
0
        OPENSSL_cleanse(mem_h->data, mem_h->max);
131
0
        BUF_MEM_free(mem_h);
132
0
    }
133
0
    if (bn_h)
134
0
        BN_clear_free(bn_h);
135
0
    if (bn_s)
136
0
        BN_clear_free(bn_s);
137
    /* Decrement reference count, keys are still available via PACE_CTX */
138
0
    if (static_key)
139
0
        DH_free(static_key);
140
0
    if (ephemeral_key)
141
0
        DH_free(ephemeral_key);
142
0
    BN_CTX_end(bn_ctx);
143
0
    if (new_g)
144
0
        BN_clear_free(new_g);
145
146
0
    return ret;
147
0
}
148
149
BUF_MEM *
150
dh_im_generate_key(const PACE_CTX * ctx, BN_CTX *bn_ctx)
151
0
{
152
0
    check_return((ctx && ctx->ka_ctx), "Invalid arguments");
153
154
0
    return randb(EVP_CIPHER_key_length(ctx->ka_ctx->cipher));
155
0
}
156
157
int
158
dh_im_compute_key(PACE_CTX * ctx, const BUF_MEM * s, const BUF_MEM * in,
159
        BN_CTX *bn_ctx)
160
0
{
161
0
    int ret = 0;
162
0
    BUF_MEM * x_mem = NULL;
163
0
    BIGNUM * x_bn = NULL, *a = NULL, *p_1 = NULL, *q = NULL, *g_new = NULL;
164
0
    const BIGNUM *p, *g;
165
0
    DH *static_key = NULL, *ephemeral_key = NULL;
166
167
0
    check((ctx && in && ctx->ka_ctx), "Invalid arguments");
168
0
    if (in->length < (size_t) EVP_CIPHER_key_length(ctx->ka_ctx->cipher)
169
0
            || !ctx->static_key)
170
0
        goto err;
171
172
0
    BN_CTX_start(bn_ctx);
173
174
0
    static_key = EVP_PKEY_get1_DH(ctx->static_key);
175
0
    if (!static_key)
176
0
        goto err;
177
178
    /* Initialize ephemeral parameters with parameters from the static key */
179
0
    ephemeral_key = DHparams_dup_with_q(static_key);
180
0
    if (!ephemeral_key)
181
0
        goto err;
182
0
    DH_get0_pqg(ephemeral_key, &p, NULL, &g);
183
184
    /* Perform the actual mapping */
185
0
    x_mem = cipher_no_pad(ctx->ka_ctx, NULL, in, s, 1);
186
0
    if (!x_mem)
187
0
        goto err;
188
0
    x_bn = BN_bin2bn((unsigned char *) x_mem->data, x_mem->length, x_bn);
189
0
    a = BN_CTX_get(bn_ctx);
190
0
    q = DH_get_q(static_key, bn_ctx);
191
0
    p_1 = BN_dup(p);
192
0
    g_new = BN_dup(g);
193
0
    if (!x_bn || !a || !q || !p_1 || !g_new ||
194
            /* p_1 = p-1 */
195
0
            !BN_sub_word(p_1, 1) ||
196
            /* a = p-1 / q */
197
0
            !BN_div(a, NULL, p_1, q, bn_ctx) ||
198
            /* g~ = x^a mod p */
199
0
            !BN_mod_exp(g_new, x_bn, a, p, bn_ctx))
200
0
        goto err;
201
202
    /* check if g~ != 1 */
203
0
    check((!BN_is_one(g_new)), "Bad DH generator");
204
205
0
    DH_set0_pqg(ephemeral_key, BN_dup(p), q, g_new);
206
0
    g_new = NULL;
207
0
    q = NULL;
208
209
    /* Copy ephemeral key to context structure */
210
0
    if (!EVP_PKEY_set1_DH(ctx->ka_ctx->key, ephemeral_key))
211
0
        goto err;
212
213
0
    ret = 1;
214
215
0
err:
216
0
    if (q)
217
0
        BN_clear_free(q);
218
0
    if (g_new)
219
0
        BN_clear_free(g_new);
220
0
    if (p_1)
221
0
        BN_clear_free(p_1);
222
0
    if (x_bn)
223
0
        BN_clear_free(x_bn);
224
0
    if (x_mem)
225
0
        BUF_MEM_free(x_mem);
226
    /* Decrement reference count, keys are still available via PACE_CTX */
227
0
    if (static_key)
228
0
        DH_free(static_key);
229
0
    if (ephemeral_key)
230
0
        DH_free(ephemeral_key);
231
0
    BN_CTX_end(bn_ctx);
232
233
0
    return ret;
234
0
}
235
236
BUF_MEM *
237
ecdh_gm_generate_key(const PACE_CTX * ctx, BN_CTX *bn_ctx)
238
0
{
239
0
    check_return(ctx, "Invalid arguments");
240
241
0
    return ecdh_generate_key(ctx->static_key, bn_ctx);
242
0
}
243
244
int
245
ecdh_gm_compute_key(PACE_CTX * ctx, const BUF_MEM * s, const BUF_MEM * in,
246
        BN_CTX *bn_ctx)
247
0
{
248
0
    int ret = 0;
249
0
    BUF_MEM * mem_h = NULL;
250
0
    BIGNUM * bn_s = NULL, *order = NULL, *cofactor = NULL;
251
0
    EC_POINT * ecp_h = NULL, *ecp_g = NULL;
252
0
    EC_GROUP *group = NULL;
253
0
    EC_KEY *static_key = NULL, *ephemeral_key = NULL;
254
0
#ifdef HAVE_EC_KEY_METHOD
255
0
    const EC_KEY_METHOD *default_method;
256
#else
257
    const ECDH_METHOD *default_method;
258
#endif
259
260
0
    BN_CTX_start(bn_ctx);
261
262
0
    check((ctx && ctx->static_key && s && ctx->ka_ctx), "Invalid arguments");
263
264
0
    static_key = EVP_PKEY_get1_EC_KEY(ctx->static_key);
265
0
    check(static_key, "could not get key object");
266
267
    /* Extract group parameters */
268
0
    group = EC_GROUP_dup(EC_KEY_get0_group(static_key));
269
0
    order = BN_CTX_get(bn_ctx);
270
0
    cofactor = BN_CTX_get(bn_ctx);
271
0
    check(group && cofactor, "internal error");
272
0
    if (!EC_GROUP_get_order(group, order, bn_ctx)
273
0
            || !EC_GROUP_get_cofactor(group, cofactor, bn_ctx))
274
0
        goto err;
275
276
    /* Convert nonce to BIGNUM */
277
0
    bn_s = BN_bin2bn((unsigned char *) s->data, s->length, bn_s);
278
0
    if (!bn_s)
279
0
        goto err;
280
281
0
#ifdef HAVE_EC_KEY_METHOD
282
0
    default_method = EC_KEY_get_method(static_key);
283
0
    if (!EC_KEY_set_method(static_key, EC_KEY_OpenSSL_Point()))
284
0
        goto err;
285
    /* complete the ECDH and get the resulting point h */
286
0
    mem_h = ecdh_compute_key(ctx->static_key, in, bn_ctx);
287
0
    EC_KEY_set_method(static_key, default_method);
288
#else
289
    default_method = ECDH_get_default_method();
290
    ECDH_set_default_method(ECDH_OpenSSL_Point());
291
    /* complete the ECDH and get the resulting point h */
292
    mem_h = ecdh_compute_key(ctx->static_key, in, bn_ctx);
293
    ECDH_set_default_method(default_method);
294
#endif
295
0
    ecp_h = EC_POINT_new(group);
296
0
    if (!mem_h || !ecp_h || !EC_POINT_oct2point(group, ecp_h,
297
0
            (unsigned char *) mem_h->data, mem_h->length, bn_ctx))
298
0
        goto err;
299
300
    /* map to new generator */
301
0
    ecp_g = EC_POINT_new(group);
302
    /* g' = g*s + h*1 */
303
0
    if (!EC_POINT_mul(group, ecp_g, bn_s, ecp_h, BN_value_one(), bn_ctx))
304
0
        goto err;
305
306
    /* Initialize ephemeral parameters with parameters from the static key */
307
0
    ephemeral_key = EC_KEY_dup(static_key);
308
0
    if (!ephemeral_key)
309
0
        goto err;
310
0
    EVP_PKEY_set1_EC_KEY(ctx->ka_ctx->key, ephemeral_key);
311
312
    /* configure the new EC_KEY */
313
0
    if (!EC_GROUP_set_generator(group, ecp_g, order, cofactor)
314
0
            || !EC_GROUP_check(group, bn_ctx)
315
0
            || !EC_KEY_set_group(ephemeral_key, group))
316
0
        goto err;
317
318
0
    ret = 1;
319
320
0
err:
321
0
    if (ecp_g)
322
0
        EC_POINT_clear_free(ecp_g);
323
0
    if (ecp_h)
324
0
        EC_POINT_clear_free(ecp_h);
325
0
    if (mem_h)
326
0
        BUF_MEM_free(mem_h);
327
0
    if (bn_s)
328
0
        BN_clear_free(bn_s);
329
0
    BN_CTX_end(bn_ctx);
330
    /* Decrement reference count, keys are still available via PACE_CTX */
331
0
    if (static_key)
332
0
        EC_KEY_free(static_key);
333
0
    if (ephemeral_key)
334
0
        EC_KEY_free(ephemeral_key);
335
0
    if (group)
336
0
        EC_GROUP_clear_free(group);
337
338
0
    return ret;
339
0
}
340
341
BUF_MEM *
342
ecdh_im_generate_key(const PACE_CTX * ctx, BN_CTX *bn_ctx)
343
0
{
344
0
    check_return((ctx && ctx->ka_ctx), "Invalid arguments");
345
346
0
    return randb(EVP_CIPHER_key_length(ctx->ka_ctx->cipher));
347
0
}
348
349
int
350
ecdh_im_compute_key(PACE_CTX * ctx, const BUF_MEM * s, const BUF_MEM * in,
351
        BN_CTX *bn_ctx)
352
0
{
353
0
    int ret = 0;
354
0
    BUF_MEM * x_mem = NULL;
355
0
    BIGNUM * a = NULL, *b = NULL, *p = NULL;
356
0
    BIGNUM * x = NULL, *y = NULL, *v = NULL, *u = NULL;
357
0
    BIGNUM * tmp = NULL, *tmp2 = NULL, *bn_inv = NULL;
358
0
    BIGNUM * two = NULL, *three = NULL, *four = NULL, *six = NULL;
359
0
    BIGNUM * twentyseven = NULL;
360
0
    EC_KEY *static_key = NULL, *ephemeral_key = NULL;
361
0
    EC_POINT *g = NULL;
362
363
0
    BN_CTX_start(bn_ctx);
364
365
0
    check((ctx && ctx->static_key && s && ctx->ka_ctx), "Invalid arguments"); 
366
367
0
    static_key = EVP_PKEY_get1_EC_KEY(ctx->static_key);
368
0
    if (!static_key)
369
0
        goto err;
370
371
    /* Setup all the variables*/
372
0
    a = BN_CTX_get(bn_ctx);
373
0
    b = BN_CTX_get(bn_ctx);
374
0
    p = BN_CTX_get(bn_ctx);
375
0
    x = BN_CTX_get(bn_ctx);
376
0
    y = BN_CTX_get(bn_ctx);
377
0
    v = BN_CTX_get(bn_ctx);
378
0
    two = BN_CTX_get(bn_ctx);
379
0
    three = BN_CTX_get(bn_ctx);
380
0
    four = BN_CTX_get(bn_ctx);
381
0
    six = BN_CTX_get(bn_ctx);
382
0
    twentyseven = BN_CTX_get(bn_ctx);
383
0
    tmp = BN_CTX_get(bn_ctx);
384
0
    tmp2 = BN_CTX_get(bn_ctx);
385
0
    bn_inv = BN_CTX_get(bn_ctx);
386
0
    if (!bn_inv)
387
0
        goto err;
388
389
    /* Encrypt the Nonce using the symmetric key in */
390
0
    x_mem = cipher_no_pad(ctx->ka_ctx, NULL, in, s, 1);
391
0
    if (!x_mem)
392
0
        goto err;
393
394
    /* Fetch the curve parameters */
395
0
    if (!EC_GROUP_get_curve_GFp(EC_KEY_get0_group(static_key), p, a, b, bn_ctx))
396
0
        goto err;
397
398
    /* Assign constants */
399
0
    if (    !BN_set_word(two,2)||
400
0
            !BN_set_word(three,3)||
401
0
            !BN_set_word(four,4)||
402
0
            !BN_set_word(six,6)||
403
0
            !BN_set_word(twentyseven,27)
404
0
            ) goto err;
405
406
    /* Check prerequisites for curve parameters */
407
0
    check(
408
            /* p > 3;*/
409
0
           (BN_cmp(p, three) == 1) &&
410
           /* p mod 3 = 2; (p has the form p=q^n, q prime) */
411
0
           BN_nnmod(tmp, p, three, bn_ctx) &&
412
0
           (BN_cmp(tmp, two) == 0),
413
0
        "Unsuited curve");
414
415
    /* Convert encrypted nonce to BIGNUM */
416
0
    u = BN_bin2bn((unsigned char *) x_mem->data, x_mem->length, u);
417
0
    if (!u)
418
0
        goto err;
419
420
0
    if ( /* v = (3a - u^4) / 6u mod p */
421
0
            !BN_mod_mul(tmp, three, a, p, bn_ctx) ||
422
0
            !BN_mod_exp(tmp2, u, four, p, bn_ctx) ||
423
0
            !BN_mod_sub(v, tmp, tmp2, p, bn_ctx) ||
424
0
            !BN_mod_mul(tmp, u, six, p, bn_ctx) ||
425
            /* For division within a galois field we need to compute
426
             * the multiplicative inverse of a number */
427
0
            !BN_mod_inverse(bn_inv, tmp, p, bn_ctx) ||
428
0
            !BN_mod_mul(v, v, bn_inv, p, bn_ctx) ||
429
430
            /* x = (v^2 - b - ((u^6)/27)) */
431
0
            !BN_mod_sqr(tmp, v, p, bn_ctx) ||
432
0
            !BN_mod_sub(tmp2, tmp, b, p, bn_ctx) ||
433
0
            !BN_mod_exp(tmp, u, six, p, bn_ctx) ||
434
0
            !BN_mod_inverse(bn_inv, twentyseven, p, bn_ctx) ||
435
0
            !BN_mod_mul(tmp, tmp, bn_inv, p, bn_ctx) ||
436
0
            !BN_mod_sub(x, tmp2, tmp, p, bn_ctx) ||
437
438
            /* x -> x^(1/3) = x^((2p^n -1)/3) */
439
0
            !BN_mul(tmp, two, p, bn_ctx) ||
440
0
            !BN_sub(tmp, tmp, BN_value_one()) ||
441
442
            /* Division is defined, because p^n = 2 mod 3 */
443
0
            !BN_div(tmp, y, tmp, three, bn_ctx) ||
444
0
            !BN_mod_exp(tmp2, x, tmp, p, bn_ctx) ||
445
0
            !BN_copy(x, tmp2) ||
446
447
            /* x += (u^2)/3 */
448
0
            !BN_mod_sqr(tmp, u, p, bn_ctx) ||
449
0
            !BN_mod_inverse(bn_inv, three, p, bn_ctx) ||
450
0
            !BN_mod_mul(tmp2, tmp, bn_inv, p, bn_ctx) ||
451
0
            !BN_mod_add(tmp, x, tmp2, p, bn_ctx) ||
452
0
            !BN_copy(x, tmp) ||
453
454
            /* y = ux + v */
455
0
            !BN_mod_mul(y, u, x, p, bn_ctx) ||
456
0
            !BN_mod_add(tmp, y, v, p, bn_ctx) ||
457
0
            !BN_copy(y, tmp)
458
0
            )
459
0
        goto err;
460
461
    /* Initialize ephemeral parameters with parameters from the static key */
462
0
    ephemeral_key = EC_KEY_dup(static_key);
463
0
    if (!ephemeral_key)
464
0
        goto err;
465
0
    EVP_PKEY_set1_EC_KEY(ctx->ka_ctx->key, ephemeral_key);
466
467
    /* configure the new EC_KEY */
468
0
    g = EC_POINT_new(EC_KEY_get0_group(ephemeral_key));
469
0
    if (!g)
470
0
        goto err;
471
0
    if (!EC_POINT_set_affine_coordinates(EC_KEY_get0_group(ephemeral_key), g,
472
0
            x, y, bn_ctx))
473
0
        goto err;
474
475
0
    ret = 1;
476
477
0
err:
478
0
    if (x_mem)
479
0
        BUF_MEM_free(x_mem);
480
0
    if (u)
481
0
        BN_free(u);
482
0
    BN_CTX_end(bn_ctx);
483
0
    if (g)
484
0
        EC_POINT_clear_free(g);
485
    /* Decrement reference count, keys are still available via PACE_CTX */
486
0
    if (static_key)
487
0
        EC_KEY_free(static_key);
488
0
    if (ephemeral_key)
489
0
        EC_KEY_free(ephemeral_key);
490
491
0
    return ret;
492
0
}