Coverage Report

Created: 2024-05-15 07:16

/src/openssl/crypto/evp/exchange.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019 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
#include <openssl/crypto.h>
11
#include <openssl/evp.h>
12
#include <openssl/err.h>
13
#include "internal/refcount.h"
14
#include "crypto/evp.h"
15
#include "internal/provider.h"
16
#include "internal/numbers.h"   /* includes SIZE_MAX */
17
#include "evp_local.h"
18
19
static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
20
0
{
21
0
    EVP_KEYEXCH *exchange = OPENSSL_zalloc(sizeof(EVP_KEYEXCH));
22
23
0
    if (exchange == NULL) {
24
0
        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
25
0
        return NULL;
26
0
    }
27
28
0
    exchange->lock = CRYPTO_THREAD_lock_new();
29
0
    if (exchange->lock == NULL) {
30
0
        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
31
0
        OPENSSL_free(exchange);
32
0
        return NULL;
33
0
    }
34
0
    exchange->prov = prov;
35
0
    ossl_provider_up_ref(prov);
36
0
    exchange->refcnt = 1;
37
38
0
    return exchange;
39
0
}
40
41
static void *evp_keyexch_from_dispatch(int name_id,
42
                                       const OSSL_DISPATCH *fns,
43
                                       OSSL_PROVIDER *prov)
44
0
{
45
0
    EVP_KEYEXCH *exchange = NULL;
46
0
    int fncnt = 0, paramfncnt = 0;
47
48
0
    if ((exchange = evp_keyexch_new(prov)) == NULL) {
49
0
        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
50
0
        goto err;
51
0
    }
52
53
0
    exchange->name_id = name_id;
54
55
0
    for (; fns->function_id != 0; fns++) {
56
0
        switch (fns->function_id) {
57
0
        case OSSL_FUNC_KEYEXCH_NEWCTX:
58
0
            if (exchange->newctx != NULL)
59
0
                break;
60
0
            exchange->newctx = OSSL_get_OP_keyexch_newctx(fns);
61
0
            fncnt++;
62
0
            break;
63
0
        case OSSL_FUNC_KEYEXCH_INIT:
64
0
            if (exchange->init != NULL)
65
0
                break;
66
0
            exchange->init = OSSL_get_OP_keyexch_init(fns);
67
0
            fncnt++;
68
0
            break;
69
0
        case OSSL_FUNC_KEYEXCH_SET_PEER:
70
0
            if (exchange->set_peer != NULL)
71
0
                break;
72
0
            exchange->set_peer = OSSL_get_OP_keyexch_set_peer(fns);
73
0
            break;
74
0
        case OSSL_FUNC_KEYEXCH_DERIVE:
75
0
            if (exchange->derive != NULL)
76
0
                break;
77
0
            exchange->derive = OSSL_get_OP_keyexch_derive(fns);
78
0
            fncnt++;
79
0
            break;
80
0
        case OSSL_FUNC_KEYEXCH_FREECTX:
81
0
            if (exchange->freectx != NULL)
82
0
                break;
83
0
            exchange->freectx = OSSL_get_OP_keyexch_freectx(fns);
84
0
            fncnt++;
85
0
            break;
86
0
        case OSSL_FUNC_KEYEXCH_DUPCTX:
87
0
            if (exchange->dupctx != NULL)
88
0
                break;
89
0
            exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns);
90
0
            break;
91
0
        case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS:
92
0
            if (exchange->set_ctx_params != NULL)
93
0
                break;
94
0
            exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns);
95
0
            paramfncnt++;
96
0
            break;
97
0
        case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS:
98
0
            if (exchange->settable_ctx_params != NULL)
99
0
                break;
100
0
            exchange->settable_ctx_params
101
0
                = OSSL_get_OP_keyexch_settable_ctx_params(fns);
102
0
            paramfncnt++;
103
0
            break;
104
0
        }
105
0
    }
106
0
    if (fncnt != 4 || (paramfncnt != 0 && paramfncnt != 2)) {
107
        /*
108
         * In order to be a consistent set of functions we must have at least
109
         * a complete set of "exchange" functions: init, derive, newctx,
110
         * and freectx. The set_ctx_params and settable_ctx_params functions are
111
         * optional, but if one of them is present then the other one must also
112
         * be present. The dupctx and set_peer functions are optional.
113
         */
114
0
        EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH,
115
0
               EVP_R_INVALID_PROVIDER_FUNCTIONS);
116
0
        goto err;
117
0
    }
118
119
0
    return exchange;
120
121
0
 err:
122
0
    EVP_KEYEXCH_free(exchange);
123
0
    return NULL;
124
0
}
125
126
void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange)
127
0
{
128
0
    if (exchange != NULL) {
129
0
        int i;
130
131
0
        CRYPTO_DOWN_REF(&exchange->refcnt, &i, exchange->lock);
132
0
        if (i > 0)
133
0
            return;
134
0
        ossl_provider_free(exchange->prov);
135
0
        CRYPTO_THREAD_lock_free(exchange->lock);
136
0
        OPENSSL_free(exchange);
137
0
    }
138
0
}
139
140
int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange)
141
0
{
142
0
    int ref = 0;
143
144
0
    CRYPTO_UP_REF(&exchange->refcnt, &ref, exchange->lock);
145
0
    return 1;
146
0
}
147
148
OSSL_PROVIDER *EVP_KEYEXCH_provider(const EVP_KEYEXCH *exchange)
149
0
{
150
0
    return exchange->prov;
151
0
}
152
153
EVP_KEYEXCH *EVP_KEYEXCH_fetch(OPENSSL_CTX *ctx, const char *algorithm,
154
                               const char *properties)
155
0
{
156
0
    return evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties,
157
0
                             evp_keyexch_from_dispatch,
158
0
                             (int (*)(void *))EVP_KEYEXCH_up_ref,
159
0
                             (void (*)(void *))EVP_KEYEXCH_free);
160
0
}
161
162
int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
163
0
{
164
0
    int ret;
165
0
    void *provkey = NULL;
166
0
    EVP_KEYEXCH *exchange = NULL;
167
0
    EVP_KEYMGMT *tmp_keymgmt = NULL;
168
0
    const char *supported_exch = NULL;
169
170
0
    if (ctx == NULL) {
171
0
        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
172
0
        return -2;
173
0
    }
174
175
0
    evp_pkey_ctx_free_old_ops(ctx);
176
0
    ctx->operation = EVP_PKEY_OP_DERIVE;
177
178
    /*
179
     * TODO when we stop falling back to legacy, this and the ERR_pop_to_mark()
180
     * calls can be removed.
181
     */
182
0
    ERR_set_mark();
183
184
0
    if (ctx->engine != NULL || ctx->keytype == NULL)
185
0
        goto legacy;
186
187
    /* Ensure that the key is provided.  If not, go legacy */
188
0
    tmp_keymgmt = ctx->keymgmt;
189
0
    provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx,
190
0
                                     &tmp_keymgmt, ctx->propquery);
191
0
    if (provkey == NULL)
192
0
        goto legacy;
193
0
    if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
194
0
        ERR_clear_last_mark();
195
0
        ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
196
0
        goto err;
197
0
    }
198
0
    EVP_KEYMGMT_free(ctx->keymgmt);
199
0
    ctx->keymgmt = tmp_keymgmt;
200
201
0
    if (ctx->keymgmt->query_operation_name != NULL)
202
0
        supported_exch = ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH);
203
204
    /*
205
     * If we didn't get a supported exch, assume there is one with the
206
     * same name as the key type.
207
     */
208
0
    if (supported_exch == NULL)
209
0
        supported_exch = ctx->keytype;
210
211
    /*
212
     * Because we cleared out old ops, we shouldn't need to worry about
213
     * checking if exchange is already there.
214
     */
215
0
    exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
216
217
0
    if (exchange == NULL
218
0
        || (EVP_KEYMGMT_provider(ctx->keymgmt)
219
0
            != EVP_KEYEXCH_provider(exchange))) {
220
        /*
221
         * We don't need to free ctx->keymgmt here, as it's not necessarily
222
         * tied to this operation.  It will be freed by EVP_PKEY_CTX_free().
223
         */
224
0
        EVP_KEYEXCH_free(exchange);
225
0
        goto legacy;
226
0
    }
227
228
    /*
229
     * TODO remove this when legacy is gone
230
     * If we don't have the full support we need with provided methods,
231
     * let's go see if legacy does.
232
     */
233
0
    ERR_pop_to_mark();
234
235
    /* No more legacy from here down to legacy: */
236
237
0
    ctx->op.kex.exchange = exchange;
238
0
    ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
239
0
    if (ctx->op.kex.exchprovctx == NULL) {
240
        /* The provider key can stay in the cache */
241
0
        EVPerr(0, EVP_R_INITIALIZATION_ERROR);
242
0
        goto err;
243
0
    }
244
0
    ret = exchange->init(ctx->op.kex.exchprovctx, provkey);
245
246
0
    return ret ? 1 : 0;
247
0
 err:
248
0
    ctx->operation = EVP_PKEY_OP_UNDEFINED;
249
0
    return 0;
250
251
0
 legacy:
252
    /*
253
     * TODO remove this when legacy is gone
254
     * If we don't have the full support we need with provided methods,
255
     * let's go see if legacy does.
256
     */
257
0
    ERR_pop_to_mark();
258
259
#ifdef FIPS_MODE
260
    return 0;
261
#else
262
0
    if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
263
0
        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
264
0
        return -2;
265
0
    }
266
267
0
    if (ctx->pmeth->derive_init == NULL)
268
0
        return 1;
269
0
    ret = ctx->pmeth->derive_init(ctx);
270
0
    if (ret <= 0)
271
0
        ctx->operation = EVP_PKEY_OP_UNDEFINED;
272
0
    return ret;
273
0
#endif
274
0
}
275
276
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
277
0
{
278
0
    int ret = 0;
279
0
    void *provkey = NULL;
280
281
0
    if (ctx == NULL) {
282
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
283
0
               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
284
0
        return -2;
285
0
    }
286
287
0
    if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL)
288
0
        goto legacy;
289
290
0
    if (ctx->op.kex.exchange->set_peer == NULL) {
291
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
292
0
               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
293
0
        return -2;
294
0
    }
295
296
0
    provkey = evp_keymgmt_util_export_to_provider(peer, ctx->keymgmt);
297
    /* If export failed, legacy may be able to pick it up */
298
0
    if (provkey == NULL)
299
0
        goto legacy;
300
0
    return ctx->op.kex.exchange->set_peer(ctx->op.kex.exchprovctx, provkey);
301
302
0
 legacy:
303
#ifdef FIPS_MODE
304
    return ret;
305
#else
306
0
    if (ctx->pmeth == NULL
307
0
        || !(ctx->pmeth->derive != NULL
308
0
             || ctx->pmeth->encrypt != NULL
309
0
             || ctx->pmeth->decrypt != NULL)
310
0
        || ctx->pmeth->ctrl == NULL) {
311
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
312
0
               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
313
0
        return -2;
314
0
    }
315
0
    if (ctx->operation != EVP_PKEY_OP_DERIVE
316
0
        && ctx->operation != EVP_PKEY_OP_ENCRYPT
317
0
        && ctx->operation != EVP_PKEY_OP_DECRYPT) {
318
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
319
0
               EVP_R_OPERATON_NOT_INITIALIZED);
320
0
        return -1;
321
0
    }
322
323
0
    ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
324
325
0
    if (ret <= 0)
326
0
        return ret;
327
328
0
    if (ret == 2)
329
0
        return 1;
330
331
0
    if (ctx->pkey == NULL) {
332
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_NO_KEY_SET);
333
0
        return -1;
334
0
    }
335
336
0
    if (ctx->pkey->type != peer->type) {
337
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_KEY_TYPES);
338
0
        return -1;
339
0
    }
340
341
    /*
342
     * For clarity.  The error is if parameters in peer are
343
     * present (!missing) but don't match.  EVP_PKEY_cmp_parameters may return
344
     * 1 (match), 0 (don't match) and -2 (comparison is not defined).  -1
345
     * (different key types) is impossible here because it is checked earlier.
346
     * -2 is OK for us here, as well as 1, so we can check for 0 only.
347
     */
348
0
    if (!EVP_PKEY_missing_parameters(peer) &&
349
0
        !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) {
350
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_PARAMETERS);
351
0
        return -1;
352
0
    }
353
354
0
    EVP_PKEY_free(ctx->peerkey);
355
0
    ctx->peerkey = peer;
356
357
0
    ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
358
359
0
    if (ret <= 0) {
360
0
        ctx->peerkey = NULL;
361
0
        return ret;
362
0
    }
363
364
0
    EVP_PKEY_up_ref(peer);
365
0
    return 1;
366
0
#endif
367
0
}
368
369
int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen)
370
0
{
371
0
    int ret;
372
373
0
    if (ctx == NULL) {
374
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE,
375
0
               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
376
0
        return -2;
377
0
    }
378
379
0
    if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
380
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED);
381
0
        return -1;
382
0
    }
383
384
0
    if (ctx->op.kex.exchprovctx == NULL)
385
0
        goto legacy;
386
387
0
    ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen,
388
0
                                       SIZE_MAX);
389
390
0
    return ret;
391
0
 legacy:
392
0
    if (ctx ==  NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
393
0
        EVPerr(EVP_F_EVP_PKEY_DERIVE,
394
0
               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
395
0
        return -2;
396
0
    }
397
398
0
    M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE)
399
0
        return ctx->pmeth->derive(ctx, key, pkeylen);
400
0
}
401
402
int EVP_KEYEXCH_number(const EVP_KEYEXCH *keyexch)
403
0
{
404
0
    return keyexch->name_id;
405
0
}
406
407
int EVP_KEYEXCH_is_a(const EVP_KEYEXCH *keyexch, const char *name)
408
0
{
409
0
    return evp_is_a(keyexch->prov, keyexch->name_id, NULL, name);
410
0
}
411
412
void EVP_KEYEXCH_do_all_provided(OPENSSL_CTX *libctx,
413
                                 void (*fn)(EVP_KEYEXCH *keyexch, void *arg),
414
                                 void *arg)
415
0
{
416
0
    evp_generic_do_all(libctx, OSSL_OP_KEYEXCH,
417
0
                       (void (*)(void *, void *))fn, arg,
418
0
                       evp_keyexch_from_dispatch,
419
0
                       (void (*)(void *))EVP_KEYEXCH_free);
420
0
}
421
422
void EVP_KEYEXCH_names_do_all(const EVP_KEYEXCH *keyexch,
423
                              void (*fn)(const char *name, void *data),
424
                              void *data)
425
0
{
426
0
    if (keyexch->prov != NULL)
427
0
        evp_names_do_all(keyexch->prov, keyexch->name_id, fn, data);
428
0
}