Coverage Report

Created: 2026-06-18 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/providers/implementations/exchange/dh_exch.c
Line
Count
Source
1
/*
2
 * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
/*
11
 * DH low level APIs are deprecated for public use, but still ok for
12
 * internal use.
13
 */
14
#include "internal/deprecated.h"
15
16
#include <string.h>
17
#include <openssl/crypto.h>
18
#include <openssl/core_dispatch.h>
19
#include <openssl/core_names.h>
20
#include <openssl/dh.h>
21
#include <openssl/err.h>
22
#include <openssl/proverr.h>
23
#include <openssl/params.h>
24
#include "internal/cryptlib.h"
25
#include "internal/fips.h"
26
#include "prov/providercommon.h"
27
#include "prov/implementations.h"
28
#include "prov/provider_ctx.h"
29
#include "prov/securitycheck.h"
30
#include "crypto/dh.h"
31
#include "providers/implementations/exchange/dh_exch.inc"
32
33
static OSSL_FUNC_keyexch_newctx_fn dh_newctx;
34
static OSSL_FUNC_keyexch_init_fn dh_init;
35
static OSSL_FUNC_keyexch_set_peer_fn dh_set_peer;
36
static OSSL_FUNC_keyexch_derive_fn dh_derive;
37
static OSSL_FUNC_keyexch_freectx_fn dh_freectx;
38
static OSSL_FUNC_keyexch_dupctx_fn dh_dupctx;
39
static OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params;
40
static OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params;
41
static OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params;
42
static OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params;
43
44
/*
45
 * This type is only really used to handle some legacy related functionality.
46
 * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE
47
 * here and then create and run a KDF after the key is derived.
48
 * Note that X942 has 2 variants of key derivation:
49
 *   (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has
50
 *   the counter embedded in it.
51
 *   (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be
52
 *       done by creating a "X963KDF".
53
 */
54
enum kdf_type {
55
    PROV_DH_KDF_NONE = 0,
56
    PROV_DH_KDF_X9_42_ASN1
57
};
58
59
/*
60
 * What's passed as an actual key is defined by the KEYMGMT interface.
61
 * We happen to know that our KEYMGMT simply passes DH structures, so
62
 * we use that here too.
63
 */
64
65
typedef struct {
66
    OSSL_LIB_CTX *libctx;
67
    DH *dh;
68
    DH *dhpeer;
69
    unsigned int pad : 1;
70
71
    /* DH KDF */
72
    /* KDF (if any) to use for DH */
73
    enum kdf_type kdf_type;
74
    /* Message digest to use for key derivation */
75
    EVP_MD *kdf_md;
76
    /* User key material */
77
    unsigned char *kdf_ukm;
78
    size_t kdf_ukmlen;
79
    /* KDF output length */
80
    size_t kdf_outlen;
81
    char *kdf_cekalg;
82
    OSSL_FIPS_IND_DECLARE
83
} PROV_DH_CTX;
84
85
static void *dh_newctx(void *provctx)
86
0
{
87
0
    PROV_DH_CTX *pdhctx;
88
89
0
    if (!ossl_prov_is_running())
90
0
        return NULL;
91
92
#ifdef FIPS_MODULE
93
    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
94
            ST_ID_KA_DH))
95
        return NULL;
96
#endif
97
98
0
    pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX));
99
0
    if (pdhctx == NULL)
100
0
        return NULL;
101
0
    OSSL_FIPS_IND_INIT(pdhctx)
102
0
    pdhctx->libctx = PROV_LIBCTX_OF(provctx);
103
0
    pdhctx->kdf_type = PROV_DH_KDF_NONE;
104
0
    return pdhctx;
105
0
}
106
107
#ifdef FIPS_MODULE
108
static int dh_check_key(PROV_DH_CTX *ctx)
109
{
110
    int key_approved = ossl_dh_check_key(ctx->dh);
111
112
    if (!key_approved) {
113
        if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0,
114
                ctx->libctx, "DH Init", "DH Key",
115
                FIPS_CONFIG_SECURITY_CHECKS)) {
116
            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
117
            return 0;
118
        }
119
    }
120
    return 1;
121
}
122
123
static int digest_check(PROV_DH_CTX *ctx, const EVP_MD *md)
124
{
125
    return ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(ctx),
126
        OSSL_FIPS_IND_SETTABLE1, ctx->libctx,
127
        md, "DH Set Ctx");
128
}
129
#endif
130
131
static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[])
132
0
{
133
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
134
135
0
    if (!ossl_prov_is_running()
136
0
        || pdhctx == NULL
137
0
        || vdh == NULL
138
0
        || !DH_up_ref(vdh))
139
0
        return 0;
140
0
    DH_free(pdhctx->dh);
141
0
    pdhctx->dh = vdh;
142
0
    pdhctx->kdf_type = PROV_DH_KDF_NONE;
143
144
0
    OSSL_FIPS_IND_SET_APPROVED(pdhctx)
145
0
    if (!dh_set_ctx_params(pdhctx, params))
146
0
        return 0;
147
#ifdef FIPS_MODULE
148
    if (!dh_check_key(pdhctx))
149
        return 0;
150
#endif
151
0
    return 1;
152
0
}
153
154
/* The 2 parties must share the same domain parameters */
155
static int dh_match_params(DH *priv, DH *peer)
156
0
{
157
0
    int ret;
158
0
    int ignore_q = 1;
159
0
    FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv);
160
0
    FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer);
161
162
0
    if (dhparams_priv != NULL && dhparams_priv->q != NULL)
163
0
        ignore_q = 0;
164
0
    ret = dhparams_priv != NULL
165
0
        && dhparams_peer != NULL
166
0
        && ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, ignore_q);
167
0
    if (!ret)
168
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
169
0
    return ret;
170
0
}
171
172
static int dh_set_peer(void *vpdhctx, void *vdh)
173
0
{
174
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
175
176
0
    if (!ossl_prov_is_running()
177
0
        || pdhctx == NULL
178
0
        || vdh == NULL
179
0
        || !dh_match_params(vdh, pdhctx->dh)
180
0
        || !DH_up_ref(vdh))
181
0
        return 0;
182
0
    DH_free(pdhctx->dhpeer);
183
0
    pdhctx->dhpeer = vdh;
184
0
    return 1;
185
0
}
186
187
static int dh_plain_derive(void *vpdhctx,
188
    unsigned char *secret, size_t *secretlen,
189
    size_t outlen, unsigned int pad)
190
0
{
191
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
192
0
    int ret;
193
0
    size_t dhsize;
194
0
    const BIGNUM *pub_key = NULL;
195
196
0
    if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) {
197
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
198
0
        return 0;
199
0
    }
200
201
0
    dhsize = (size_t)DH_size(pdhctx->dh);
202
0
    if (secret == NULL) {
203
0
        *secretlen = dhsize;
204
0
        return 1;
205
0
    }
206
0
    if (outlen < dhsize) {
207
0
        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
208
0
        return 0;
209
0
    }
210
211
0
    DH_get0_key(pdhctx->dhpeer, &pub_key, NULL);
212
0
    if (pad)
213
0
        ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh);
214
0
    else
215
0
        ret = DH_compute_key(secret, pub_key, pdhctx->dh);
216
0
    if (ret <= 0)
217
0
        return 0;
218
219
0
    *secretlen = ret;
220
0
    return 1;
221
0
}
222
223
static int dh_X9_42_kdf_derive(void *vpdhctx, unsigned char *secret,
224
    size_t *secretlen, size_t outlen)
225
0
{
226
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
227
0
    unsigned char *stmp = NULL;
228
0
    size_t stmplen;
229
0
    int ret = 0;
230
231
0
    if (secret == NULL) {
232
0
        *secretlen = pdhctx->kdf_outlen;
233
0
        return 1;
234
0
    }
235
236
0
    if (pdhctx->kdf_outlen > outlen) {
237
0
        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
238
0
        return 0;
239
0
    }
240
0
    if (!dh_plain_derive(pdhctx, NULL, &stmplen, 0, 1))
241
0
        return 0;
242
0
    if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL)
243
0
        return 0;
244
0
    if (!dh_plain_derive(pdhctx, stmp, &stmplen, stmplen, 1))
245
0
        goto err;
246
247
    /* Do KDF stuff */
248
0
    if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) {
249
0
        if (!ossl_dh_kdf_X9_42_asn1(secret, pdhctx->kdf_outlen,
250
0
                stmp, stmplen,
251
0
                pdhctx->kdf_cekalg,
252
0
                pdhctx->kdf_ukm,
253
0
                pdhctx->kdf_ukmlen,
254
0
                pdhctx->kdf_md,
255
0
                pdhctx->libctx, NULL))
256
0
            goto err;
257
0
    }
258
0
    *secretlen = pdhctx->kdf_outlen;
259
0
    ret = 1;
260
0
err:
261
0
    OPENSSL_secure_clear_free(stmp, stmplen);
262
0
    return ret;
263
0
}
264
265
static int dh_derive(void *vpdhctx, unsigned char *secret,
266
    size_t *psecretlen, size_t outlen)
267
0
{
268
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
269
270
0
    if (!ossl_prov_is_running())
271
0
        return 0;
272
273
0
    switch (pdhctx->kdf_type) {
274
0
    case PROV_DH_KDF_NONE:
275
0
        return dh_plain_derive(pdhctx, secret, psecretlen, outlen,
276
0
            pdhctx->pad);
277
0
    case PROV_DH_KDF_X9_42_ASN1:
278
0
        return dh_X9_42_kdf_derive(pdhctx, secret, psecretlen, outlen);
279
0
    default:
280
0
        break;
281
0
    }
282
0
    return 0;
283
0
}
284
285
static void dh_freectx(void *vpdhctx)
286
0
{
287
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
288
289
0
    OPENSSL_free(pdhctx->kdf_cekalg);
290
0
    DH_free(pdhctx->dh);
291
0
    DH_free(pdhctx->dhpeer);
292
0
    EVP_MD_free(pdhctx->kdf_md);
293
0
    OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen);
294
295
0
    OPENSSL_free(pdhctx);
296
0
}
297
298
static void *dh_dupctx(void *vpdhctx)
299
0
{
300
0
    PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx;
301
0
    PROV_DH_CTX *dstctx;
302
303
0
    if (!ossl_prov_is_running())
304
0
        return NULL;
305
306
0
    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
307
0
    if (dstctx == NULL)
308
0
        return NULL;
309
310
0
    *dstctx = *srcctx;
311
0
    dstctx->dh = NULL;
312
0
    dstctx->dhpeer = NULL;
313
0
    dstctx->kdf_md = NULL;
314
0
    dstctx->kdf_ukm = NULL;
315
0
    dstctx->kdf_cekalg = NULL;
316
317
0
    if (srcctx->dh != NULL && !DH_up_ref(srcctx->dh))
318
0
        goto err;
319
0
    else
320
0
        dstctx->dh = srcctx->dh;
321
322
0
    if (srcctx->dhpeer != NULL && !DH_up_ref(srcctx->dhpeer))
323
0
        goto err;
324
0
    else
325
0
        dstctx->dhpeer = srcctx->dhpeer;
326
327
0
    if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
328
0
        goto err;
329
0
    else
330
0
        dstctx->kdf_md = srcctx->kdf_md;
331
332
    /* Duplicate UKM data if present */
333
0
    if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
334
0
        dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
335
0
            srcctx->kdf_ukmlen);
336
0
        if (dstctx->kdf_ukm == NULL)
337
0
            goto err;
338
0
    }
339
340
0
    if (srcctx->kdf_cekalg != NULL) {
341
0
        dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg);
342
0
        if (dstctx->kdf_cekalg == NULL)
343
0
            goto err;
344
0
    }
345
346
0
    return dstctx;
347
0
err:
348
0
    dh_freectx(dstctx);
349
0
    return NULL;
350
0
}
351
352
static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[])
353
0
{
354
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
355
0
    struct dh_set_ctx_params_st p;
356
0
    unsigned int pad;
357
0
    char name[80] = { '\0' }; /* should be big enough */
358
0
    char *str = NULL;
359
360
0
    if (pdhctx == NULL || !dh_set_ctx_params_decoder(params, &p))
361
0
        return 0;
362
363
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE0, p.ind_k))
364
0
        return 0;
365
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE1, p.ind_d))
366
0
        return 0;
367
368
0
    if (p.kdf != NULL) {
369
0
        str = name;
370
0
        if (!OSSL_PARAM_get_utf8_string(p.kdf, &str, sizeof(name)))
371
0
            return 0;
372
373
0
        if (name[0] == '\0')
374
0
            pdhctx->kdf_type = PROV_DH_KDF_NONE;
375
0
        else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0)
376
0
            pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1;
377
0
        else
378
0
            return 0;
379
0
    }
380
381
0
    if (p.digest != NULL) {
382
0
        char mdprops[80] = { '\0' }; /* should be big enough */
383
384
0
        str = name;
385
0
        if (!OSSL_PARAM_get_utf8_string(p.digest, &str, sizeof(name)))
386
0
            return 0;
387
388
0
        str = mdprops;
389
0
        if (p.propq != NULL) {
390
0
            if (!OSSL_PARAM_get_utf8_string(p.propq, &str, sizeof(mdprops)))
391
0
                return 0;
392
0
        }
393
394
0
        EVP_MD_free(pdhctx->kdf_md);
395
0
        pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops);
396
0
        if (pdhctx->kdf_md == NULL)
397
0
            return 0;
398
        /* XOF digests are not allowed */
399
0
        if (EVP_MD_xof(pdhctx->kdf_md)) {
400
0
            ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
401
0
            return 0;
402
0
        }
403
#ifdef FIPS_MODULE
404
        if (!digest_check(pdhctx, pdhctx->kdf_md)) {
405
            EVP_MD_free(pdhctx->kdf_md);
406
            pdhctx->kdf_md = NULL;
407
            return 0;
408
        }
409
#endif
410
0
    }
411
412
0
    if (p.len != NULL) {
413
0
        size_t outlen;
414
415
0
        if (!OSSL_PARAM_get_size_t(p.len, &outlen))
416
0
            return 0;
417
0
        pdhctx->kdf_outlen = outlen;
418
0
    }
419
420
0
    if (p.ukm != NULL) {
421
0
        void *tmp_ukm = NULL;
422
0
        size_t tmp_ukmlen;
423
424
0
        OPENSSL_free(pdhctx->kdf_ukm);
425
0
        pdhctx->kdf_ukm = NULL;
426
0
        pdhctx->kdf_ukmlen = 0;
427
        /* ukm is an optional field so it can be NULL */
428
0
        if (p.ukm->data != NULL && p.ukm->data_size != 0) {
429
0
            if (!OSSL_PARAM_get_octet_string(p.ukm, &tmp_ukm, 0, &tmp_ukmlen))
430
0
                return 0;
431
0
            pdhctx->kdf_ukm = tmp_ukm;
432
0
            pdhctx->kdf_ukmlen = tmp_ukmlen;
433
0
        }
434
0
    }
435
436
0
    if (p.pad != NULL) {
437
0
        if (!OSSL_PARAM_get_uint(p.pad, &pad))
438
0
            return 0;
439
0
        pdhctx->pad = pad ? 1 : 0;
440
0
    }
441
442
0
    if (p.cekalg != NULL) {
443
0
        str = name;
444
445
0
        OPENSSL_free(pdhctx->kdf_cekalg);
446
0
        pdhctx->kdf_cekalg = NULL;
447
0
        if (p.cekalg->data != NULL && p.cekalg->data_size != 0) {
448
0
            if (!OSSL_PARAM_get_utf8_string(p.cekalg, &str, sizeof(name)))
449
0
                return 0;
450
0
            pdhctx->kdf_cekalg = OPENSSL_strdup(name);
451
0
            if (pdhctx->kdf_cekalg == NULL)
452
0
                return 0;
453
0
        }
454
0
    }
455
0
    return 1;
456
0
}
457
458
static const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx,
459
    ossl_unused void *provctx)
460
0
{
461
0
    return dh_set_ctx_params_list;
462
0
}
463
464
static const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx,
465
    ossl_unused void *provctx)
466
0
{
467
0
    return dh_get_ctx_params_list;
468
0
}
469
470
static int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[])
471
0
{
472
0
    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
473
0
    struct dh_get_ctx_params_st p;
474
475
0
    if (pdhctx == NULL || !dh_get_ctx_params_decoder(params, &p))
476
0
        return 0;
477
478
0
    if (p.kdf != NULL) {
479
0
        const char *kdf_type = NULL;
480
481
0
        switch (pdhctx->kdf_type) {
482
0
        case PROV_DH_KDF_NONE:
483
0
            kdf_type = "";
484
0
            break;
485
0
        case PROV_DH_KDF_X9_42_ASN1:
486
0
            kdf_type = OSSL_KDF_NAME_X942KDF_ASN1;
487
0
            break;
488
0
        default:
489
0
            return 0;
490
0
        }
491
492
0
        if (!OSSL_PARAM_set_utf8_string(p.kdf, kdf_type))
493
0
            return 0;
494
0
    }
495
496
0
    if (p.digest != NULL
497
0
        && !OSSL_PARAM_set_utf8_string(p.digest, pdhctx->kdf_md == NULL ? "" : EVP_MD_get0_name(pdhctx->kdf_md))) {
498
0
        return 0;
499
0
    }
500
501
0
    if (p.len != NULL && !OSSL_PARAM_set_size_t(p.len, pdhctx->kdf_outlen))
502
0
        return 0;
503
504
0
    if (p.ukm != NULL
505
0
        && !OSSL_PARAM_set_octet_ptr(p.ukm, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen))
506
0
        return 0;
507
508
0
    if (p.cekalg != NULL
509
0
        && !OSSL_PARAM_set_utf8_string(p.cekalg, pdhctx->kdf_cekalg == NULL ? "" : pdhctx->kdf_cekalg))
510
0
        return 0;
511
512
0
    if (!OSSL_FIPS_IND_GET_CTX_FROM_PARAM(pdhctx, p.ind))
513
0
        return 0;
514
0
    return 1;
515
0
}
516
517
const OSSL_DISPATCH ossl_dh_keyexch_functions[] = {
518
    { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx },
519
    { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init },
520
    { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive },
521
    { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer },
522
    { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx },
523
    { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx },
524
    { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params },
525
    { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
526
        (void (*)(void))dh_settable_ctx_params },
527
    { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))dh_get_ctx_params },
528
    { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
529
        (void (*)(void))dh_gettable_ctx_params },
530
    OSSL_DISPATCH_END
531
};