Coverage Report

Created: 2026-10-16 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/evp/s_lib.c
Line
Count
Source
1
/*
2
 * Copyright 2025-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
#include <string.h>
11
#include <openssl/params.h>
12
#include <openssl/param_build.h>
13
#include <openssl/evp.h>
14
#include <openssl/core_names.h>
15
16
#include "internal/common.h"
17
#include "internal/provider.h"
18
#include "crypto/evp.h"
19
#include "evp_local.h"
20
21
int EVP_SKEY_export(const EVP_SKEY *skey, int selection,
22
    OSSL_CALLBACK *export_cb, void *export_cbarg)
23
0
{
24
0
    if (skey == NULL) {
25
0
        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
26
0
        return 0;
27
0
    }
28
29
0
    return evp_skeymgmt_export(skey->skeymgmt, skey->keydata, selection, export_cb, export_cbarg);
30
0
}
31
32
EVP_SKEY *evp_skey_alloc(EVP_SKEYMGMT *skeymgmt)
33
0
{
34
0
    EVP_SKEY *skey;
35
36
0
    if (!ossl_assert(skeymgmt != NULL))
37
0
        return NULL;
38
39
0
    if ((skey = OPENSSL_zalloc(sizeof(*skey))) == NULL)
40
0
        return NULL;
41
42
0
    if (!CRYPTO_NEW_REF(&skey->references, 1))
43
0
        goto err;
44
45
0
    skey->lock = CRYPTO_THREAD_lock_new();
46
0
    if (skey->lock == NULL) {
47
0
        ERR_raise(ERR_LIB_EVP, ERR_R_CRYPTO_LIB);
48
0
        goto err;
49
0
    }
50
0
    if (EVP_SKEYMGMT_up_ref(skeymgmt)) {
51
0
        skey->skeymgmt = skeymgmt;
52
0
        return skey;
53
0
    } else {
54
0
        goto err;
55
0
    }
56
57
0
err:
58
0
    CRYPTO_FREE_REF(&skey->references);
59
0
    CRYPTO_THREAD_lock_free(skey->lock);
60
0
    OPENSSL_free(skey);
61
0
    return NULL;
62
0
}
63
64
static EVP_SKEY *evp_skey_alloc_fetch(OSSL_LIB_CTX *libctx,
65
    const char *skeymgmtname,
66
    const char *propquery)
67
0
{
68
0
    EVP_SKEYMGMT *skeymgmt;
69
0
    EVP_SKEY *skey;
70
71
0
    skeymgmt = EVP_SKEYMGMT_fetch(libctx, skeymgmtname, propquery);
72
0
    if (skeymgmt == NULL) {
73
        /*
74
         * if the specific key_type is unknown, attempt to use the generic
75
         * key management
76
         */
77
0
        skeymgmt = EVP_SKEYMGMT_fetch(libctx, OSSL_SKEY_TYPE_GENERIC, propquery);
78
0
        if (skeymgmt == NULL) {
79
0
            ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
80
0
            return NULL;
81
0
        }
82
0
    }
83
84
0
    skey = evp_skey_alloc(skeymgmt);
85
0
    EVP_SKEYMGMT_free(skeymgmt);
86
87
0
    return skey;
88
0
}
89
90
EVP_SKEY *EVP_SKEY_import(OSSL_LIB_CTX *libctx, const char *skeymgmtname, const char *propquery,
91
    int selection, const OSSL_PARAM *params)
92
0
{
93
0
    EVP_SKEY *skey = evp_skey_alloc_fetch(libctx, skeymgmtname, propquery);
94
95
0
    if (skey == NULL)
96
0
        return NULL;
97
98
0
    skey->keydata = evp_skeymgmt_import(skey->skeymgmt, selection, params);
99
0
    if (skey->keydata == NULL)
100
0
        goto err;
101
102
0
    return skey;
103
104
0
err:
105
0
    EVP_SKEY_free(skey);
106
0
    return NULL;
107
0
}
108
109
EVP_SKEY *EVP_SKEY_import_SKEYMGMT(OSSL_LIB_CTX *libctx, EVP_SKEYMGMT *skeymgmt,
110
    int selection, const OSSL_PARAM *params)
111
0
{
112
0
    EVP_SKEY *skey = evp_skey_alloc(skeymgmt);
113
114
0
    if (skey == NULL)
115
0
        return NULL;
116
117
0
    skey->keydata = evp_skeymgmt_import(skey->skeymgmt, selection, params);
118
0
    if (skey->keydata == NULL)
119
0
        goto err;
120
121
0
    return skey;
122
123
0
err:
124
0
    EVP_SKEY_free(skey);
125
0
    return NULL;
126
0
}
127
128
EVP_SKEY *EVP_SKEY_generate(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
129
    const char *propquery, const OSSL_PARAM *params)
130
0
{
131
0
    EVP_SKEY *skey = evp_skey_alloc_fetch(libctx, skeymgmtname, propquery);
132
133
0
    if (skey == NULL)
134
0
        return NULL;
135
136
0
    skey->keydata = evp_skeymgmt_generate(skey->skeymgmt, params);
137
0
    if (skey->keydata == NULL)
138
0
        goto err;
139
140
0
    return skey;
141
142
0
err:
143
0
    EVP_SKEY_free(skey);
144
0
    return NULL;
145
0
}
146
147
struct raw_key_details_st {
148
    const void **key;
149
    size_t *len;
150
};
151
152
static int get_secret_key(const OSSL_PARAM params[], void *arg)
153
0
{
154
0
    const OSSL_PARAM *p = NULL;
155
0
    struct raw_key_details_st *raw_key = arg;
156
157
0
    if ((p = OSSL_PARAM_locate_const(params, OSSL_SKEY_PARAM_RAW_BYTES)) != NULL)
158
0
        return OSSL_PARAM_get_octet_string_ptr(p, raw_key->key, raw_key->len);
159
160
0
    return 0;
161
0
}
162
163
static int get_key_length(const OSSL_PARAM params[], void *arg)
164
0
{
165
0
    const OSSL_PARAM *p = NULL;
166
0
    size_t *len = arg;
167
168
0
    if ((p = OSSL_PARAM_locate_const(params, OSSL_SKEY_PARAM_KEY_LENGTH)) != NULL)
169
0
        return OSSL_PARAM_get_size_t(p, len);
170
171
0
    return 0;
172
0
}
173
174
int EVP_SKEY_get0_raw_key(const EVP_SKEY *skey, const unsigned char **key,
175
    size_t *len)
176
0
{
177
0
    struct raw_key_details_st raw_key;
178
179
0
    if (skey == NULL || len == NULL) {
180
0
        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
181
0
        return 0;
182
0
    }
183
184
    /*
185
     * Only the length is requested, so get it from the key parameters
186
     * instead of exporting the secret key.  This way the length is also
187
     * available for non-exportable keys if the key management reports it.
188
     */
189
0
    if (key == NULL)
190
0
        return evp_skeymgmt_export(skey->skeymgmt, skey->keydata,
191
0
            OSSL_SKEYMGMT_SELECT_PARAMETERS,
192
0
            get_key_length, len);
193
194
0
    raw_key.key = (const void **)key;
195
0
    raw_key.len = len;
196
197
0
    return evp_skeymgmt_export(skey->skeymgmt, skey->keydata,
198
0
        OSSL_SKEYMGMT_SELECT_SECRET_KEY,
199
0
        get_secret_key, &raw_key);
200
0
}
201
202
EVP_SKEY *EVP_SKEY_import_raw_key(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
203
    unsigned char *key, size_t keylen,
204
    const char *propquery)
205
0
{
206
0
    OSSL_PARAM params[2];
207
208
0
    params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
209
0
        (void *)key, keylen);
210
0
    params[1] = OSSL_PARAM_construct_end();
211
212
0
    return EVP_SKEY_import(libctx, skeymgmtname, propquery,
213
0
        OSSL_SKEYMGMT_SELECT_SECRET_KEY, params);
214
0
}
215
216
int EVP_SKEY_up_ref(EVP_SKEY *skey)
217
0
{
218
0
    int i;
219
220
0
    if (!CRYPTO_UP_REF(&skey->references, &i))
221
0
        return 0;
222
223
0
    REF_PRINT_COUNT("EVP_SKEY", i, skey);
224
0
    REF_ASSERT_ISNT(i < 2);
225
0
    return i > 1 ? 1 : 0;
226
0
}
227
228
void EVP_SKEY_free(EVP_SKEY *skey)
229
0
{
230
0
    int i;
231
232
0
    if (skey == NULL)
233
0
        return;
234
235
0
    CRYPTO_DOWN_REF(&skey->references, &i);
236
0
    REF_PRINT_COUNT("EVP_SKEY", i, skey);
237
0
    if (i > 0)
238
0
        return;
239
0
    REF_ASSERT_ISNT(i < 0);
240
0
    evp_skeymgmt_freedata(skey->skeymgmt, skey->keydata);
241
242
0
    EVP_SKEYMGMT_free(skey->skeymgmt);
243
244
0
    CRYPTO_THREAD_lock_free(skey->lock);
245
0
    CRYPTO_FREE_REF(&skey->references);
246
0
    OPENSSL_free(skey);
247
0
}
248
249
const char *EVP_SKEY_get0_key_id(const EVP_SKEY *skey)
250
0
{
251
0
    if (skey == NULL)
252
0
        return NULL;
253
254
0
    if (skey->skeymgmt->get_key_id)
255
0
        return skey->skeymgmt->get_key_id(skey->keydata);
256
257
0
    return NULL;
258
0
}
259
260
const char *EVP_SKEY_get0_skeymgmt_name(const EVP_SKEY *skey)
261
0
{
262
0
    if (skey == NULL)
263
0
        return NULL;
264
265
0
    return skey->skeymgmt->type_name;
266
0
}
267
268
const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey)
269
0
{
270
0
    if (skey == NULL)
271
0
        return NULL;
272
273
0
    return ossl_provider_name(skey->skeymgmt->prov);
274
0
}
275
276
int EVP_SKEY_is_a(const EVP_SKEY *skey, const char *name)
277
0
{
278
0
    if (skey == NULL)
279
0
        return 0;
280
281
0
    return EVP_SKEYMGMT_is_a(skey->skeymgmt, name);
282
0
}
283
284
struct transfer_cb_ctx {
285
    int selection;
286
    EVP_SKEYMGMT *skeymgmt;
287
    void *keydata;
288
};
289
290
static int transfer_cb(const OSSL_PARAM params[], void *arg)
291
0
{
292
0
    struct transfer_cb_ctx *ctx = arg;
293
294
0
    ctx->keydata = evp_skeymgmt_import(ctx->skeymgmt, ctx->selection, params);
295
0
    return 1;
296
0
}
297
298
EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx,
299
    OSSL_PROVIDER *prov, const char *propquery)
300
0
{
301
0
    struct transfer_cb_ctx ctx = { 0 };
302
0
    EVP_SKEYMGMT *skeymgmt = NULL;
303
0
    EVP_SKEY *ret = NULL;
304
305
0
    if (skey == NULL) {
306
0
        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
307
0
        return NULL;
308
0
    }
309
310
0
    if (prov != NULL) {
311
0
        if (skey->skeymgmt->prov == prov) {
312
0
            skeymgmt = skey->skeymgmt;
313
            /* Balance the short-circuit free below */
314
0
            if (!EVP_SKEYMGMT_up_ref(skeymgmt))
315
0
                goto err;
316
0
        } else {
317
0
            skeymgmt = evp_skeymgmt_fetch_from_prov(prov, skey->skeymgmt->type_name,
318
0
                propquery);
319
0
        }
320
0
    } else {
321
        /* If no provider, get the default skeymgmt */
322
0
        skeymgmt = EVP_SKEYMGMT_fetch(libctx, skey->skeymgmt->type_name,
323
0
            propquery);
324
0
    }
325
0
    if (skeymgmt == NULL) {
326
0
        ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
327
0
        return NULL;
328
0
    }
329
330
    /* Short-circuit if destination provider is the same as origin */
331
0
    if (skey->skeymgmt->name_id == skeymgmt->name_id
332
0
        && skey->skeymgmt->prov == skeymgmt->prov) {
333
0
        if (!EVP_SKEY_up_ref(skey))
334
0
            goto err;
335
0
        EVP_SKEYMGMT_free(skeymgmt);
336
0
        return skey;
337
0
    }
338
339
0
    ctx.selection = OSSL_SKEYMGMT_SELECT_ALL;
340
0
    ctx.skeymgmt = skeymgmt;
341
342
0
    if (!EVP_SKEY_export(skey, ctx.selection, transfer_cb, &ctx))
343
0
        goto err;
344
345
0
    if (ctx.keydata == NULL)
346
0
        goto err;
347
348
0
    ret = evp_skey_alloc(skeymgmt);
349
0
    if (ret == NULL)
350
0
        goto err;
351
352
0
    ret->keydata = ctx.keydata;
353
354
    /* Balance the local reference obtained earlier (fetch or alias up_ref) */
355
0
    EVP_SKEYMGMT_free(skeymgmt);
356
357
0
    return ret;
358
359
0
err:
360
0
    EVP_SKEYMGMT_free(skeymgmt);
361
0
    EVP_SKEY_free(ret);
362
0
    return NULL;
363
0
}
364
365
int EVP_SKEY_get0_local_keyid(const EVP_SKEY *skey,
366
    const unsigned char **id, size_t *len)
367
0
{
368
0
    if (skey == NULL || id == NULL || len == NULL) {
369
0
        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
370
0
        return 0;
371
0
    }
372
373
0
    if (skey->skeymgmt->get_local_keyid == NULL)
374
0
        return 0;
375
376
0
    return skey->skeymgmt->get_local_keyid(skey->keydata, id, len);
377
0
}
378
379
int EVP_SKEY_get0_algorithm_id(const EVP_SKEY *skey,
380
    const unsigned char **oid, size_t *oid_len,
381
    const unsigned char **params, size_t *params_len)
382
0
{
383
0
    int ret_oid = 0, ret_params = 0;
384
385
0
    if (skey == NULL) {
386
0
        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
387
0
        return 0;
388
0
    }
389
390
0
    if (skey->skeymgmt->get_algorithm_id == NULL)
391
0
        return 0;
392
393
0
    if (oid != NULL && oid_len != NULL)
394
0
        ret_oid = 1;
395
0
    if (params != NULL && params_len != NULL)
396
0
        ret_params = 1;
397
398
0
    if (ret_oid == 0 && ret_params == 0)
399
0
        return 0;
400
401
0
    if (ret_oid == 0 && (oid != NULL || oid_len != NULL))
402
0
        return 0;
403
404
0
    if (ret_params == 0 && (params != NULL || params_len != NULL))
405
0
        return 0;
406
407
0
    return skey->skeymgmt->get_algorithm_id(skey->keydata,
408
0
        oid, oid_len, params, params_len);
409
0
}