Coverage Report

Created: 2025-06-13 06:55

/src/openssl/crypto/evp/s_lib.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2025 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
static 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
    skey->skeymgmt = skeymgmt;
51
0
    return skey;
52
53
0
 err:
54
0
    CRYPTO_FREE_REF(&skey->references);
55
0
    CRYPTO_THREAD_lock_free(skey->lock);
56
0
    OPENSSL_free(skey);
57
0
    return NULL;
58
0
}
59
60
static EVP_SKEY *evp_skey_alloc_fetch(OSSL_LIB_CTX *libctx,
61
                                      const char *skeymgmtname,
62
                                      const char *propquery)
63
0
{
64
0
    EVP_SKEYMGMT *skeymgmt;
65
0
    EVP_SKEY *skey;
66
67
0
    skeymgmt = EVP_SKEYMGMT_fetch(libctx, skeymgmtname, propquery);
68
0
    if (skeymgmt == NULL) {
69
        /*
70
         * if the specific key_type is unknown, attempt to use the generic
71
         * key management
72
         */
73
0
        skeymgmt = EVP_SKEYMGMT_fetch(libctx, OSSL_SKEY_TYPE_GENERIC, propquery);
74
0
        if (skeymgmt == NULL) {
75
0
            ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
76
0
            return NULL;
77
0
        }
78
0
    }
79
80
0
    skey = evp_skey_alloc(skeymgmt);
81
0
    if (skey == NULL)
82
0
        EVP_SKEYMGMT_free(skeymgmt);
83
84
0
    return skey;
85
0
}
86
87
EVP_SKEY *EVP_SKEY_import(OSSL_LIB_CTX *libctx, const char *skeymgmtname, const char *propquery,
88
                          int selection, const OSSL_PARAM *params)
89
0
{
90
0
    EVP_SKEY *skey = evp_skey_alloc_fetch(libctx, skeymgmtname, propquery);
91
92
0
    if (skey == NULL)
93
0
        return NULL;
94
95
0
    skey->keydata = evp_skeymgmt_import(skey->skeymgmt, selection, params);
96
0
    if (skey->keydata == NULL)
97
0
        goto err;
98
99
0
    return skey;
100
101
0
 err:
102
0
    EVP_SKEY_free(skey);
103
0
    return NULL;
104
0
}
105
106
EVP_SKEY *EVP_SKEY_generate(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
107
                            const char *propquery, const OSSL_PARAM *params)
108
0
{
109
0
    EVP_SKEY *skey = evp_skey_alloc_fetch(libctx, skeymgmtname, propquery);
110
111
0
    if (skey == NULL)
112
0
        return NULL;
113
114
0
    skey->keydata = evp_skeymgmt_generate(skey->skeymgmt, params);
115
0
    if (skey->keydata == NULL)
116
0
        goto err;
117
118
0
    return skey;
119
120
0
 err:
121
0
    EVP_SKEY_free(skey);
122
0
    return NULL;
123
0
}
124
125
struct raw_key_details_st {
126
    const void **key;
127
    size_t *len;
128
};
129
130
static int get_secret_key(const OSSL_PARAM params[], void *arg)
131
0
{
132
0
    const OSSL_PARAM *p = NULL;
133
0
    struct raw_key_details_st *raw_key = arg;
134
135
0
    if ((p = OSSL_PARAM_locate_const(params, OSSL_SKEY_PARAM_RAW_BYTES)) != NULL)
136
0
        return OSSL_PARAM_get_octet_string_ptr(p, raw_key->key, raw_key->len);
137
138
0
    return 0;
139
0
}
140
141
int EVP_SKEY_get0_raw_key(const EVP_SKEY *skey, const unsigned char **key,
142
                          size_t *len)
143
0
{
144
0
    struct raw_key_details_st raw_key;
145
146
0
    if (skey == NULL || key == NULL || len == NULL) {
147
0
        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
148
0
        return 0;
149
0
    }
150
151
0
    raw_key.key = (const void **)key;
152
0
    raw_key.len = len;
153
154
0
    return evp_skeymgmt_export(skey->skeymgmt, skey->keydata,
155
0
                               OSSL_SKEYMGMT_SELECT_SECRET_KEY,
156
0
                               get_secret_key, &raw_key);
157
0
}
158
159
EVP_SKEY *EVP_SKEY_import_raw_key(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
160
                                  unsigned char *key, size_t keylen,
161
                                  const char *propquery)
162
0
{
163
0
    OSSL_PARAM params[2];
164
165
0
    params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
166
0
                                                  (void *)key, keylen);
167
0
    params[1] = OSSL_PARAM_construct_end();
168
169
0
    return EVP_SKEY_import(libctx, skeymgmtname, propquery,
170
0
                           OSSL_SKEYMGMT_SELECT_SECRET_KEY, params);
171
0
}
172
173
int EVP_SKEY_up_ref(EVP_SKEY *skey)
174
0
{
175
0
    int i;
176
177
0
    if (CRYPTO_UP_REF(&skey->references, &i) <= 0)
178
0
        return 0;
179
180
0
    REF_PRINT_COUNT("EVP_SKEY", i, skey);
181
0
    REF_ASSERT_ISNT(i < 2);
182
0
    return i > 1 ? 1 : 0;
183
0
}
184
185
void EVP_SKEY_free(EVP_SKEY *skey)
186
0
{
187
0
    int i;
188
189
0
    if (skey == NULL)
190
0
        return;
191
192
0
    CRYPTO_DOWN_REF(&skey->references, &i);
193
0
    REF_PRINT_COUNT("EVP_SKEY", i, skey);
194
0
    if (i > 0)
195
0
        return;
196
0
    REF_ASSERT_ISNT(i < 0);
197
0
    evp_skeymgmt_freedata(skey->skeymgmt, skey->keydata);
198
199
0
    EVP_SKEYMGMT_free(skey->skeymgmt);
200
201
0
    CRYPTO_THREAD_lock_free(skey->lock);
202
0
    CRYPTO_FREE_REF(&skey->references);
203
0
    OPENSSL_free(skey);
204
0
}
205
206
const char *EVP_SKEY_get0_key_id(const EVP_SKEY *skey)
207
0
{
208
0
    if (skey == NULL)
209
0
        return NULL;
210
211
0
    if (skey->skeymgmt->get_key_id)
212
0
        return skey->skeymgmt->get_key_id(skey->keydata);
213
214
0
    return NULL;
215
0
}
216
217
const char *EVP_SKEY_get0_skeymgmt_name(const EVP_SKEY *skey)
218
0
{
219
0
    if (skey == NULL)
220
0
        return NULL;
221
222
0
    return skey->skeymgmt->type_name;
223
224
0
}
225
226
const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey)
227
0
{
228
0
    if (skey == NULL)
229
0
        return NULL;
230
231
0
    return ossl_provider_name(skey->skeymgmt->prov);
232
0
}
233
234
int EVP_SKEY_is_a(const EVP_SKEY *skey, const char *name)
235
0
{
236
0
    if (skey == NULL)
237
0
        return 0;
238
239
0
    return EVP_SKEYMGMT_is_a(skey->skeymgmt, name);
240
0
}
241
242
struct transfer_cb_ctx {
243
    int selection;
244
    EVP_SKEYMGMT *skeymgmt;
245
    void *keydata;
246
};
247
248
static int transfer_cb(const OSSL_PARAM params[], void *arg)
249
0
{
250
0
    struct transfer_cb_ctx *ctx = arg;
251
252
0
    ctx->keydata = evp_skeymgmt_import(ctx->skeymgmt, ctx->selection, params);
253
0
    return 1;
254
0
}
255
256
EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx,
257
                               OSSL_PROVIDER *prov, const char *propquery)
258
0
{
259
0
    struct transfer_cb_ctx ctx = { 0 };
260
0
    EVP_SKEYMGMT *skeymgmt = NULL;
261
0
    EVP_SKEY *ret = NULL;
262
263
0
    if (skey == NULL) {
264
0
        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
265
0
        return NULL;
266
0
    }
267
268
0
    if (prov != NULL) {
269
0
        if (skey->skeymgmt->prov == prov)
270
0
            skeymgmt = skey->skeymgmt;
271
0
        else
272
0
            skeymgmt = evp_skeymgmt_fetch_from_prov(prov, skey->skeymgmt->type_name,
273
0
                                                    propquery);
274
0
    } else {
275
        /* If no provider, get the default skeymgmt */
276
0
        skeymgmt = EVP_SKEYMGMT_fetch(libctx, skey->skeymgmt->type_name,
277
0
                                      propquery);
278
0
    }
279
0
    if (skeymgmt == NULL) {
280
0
        ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
281
0
        return NULL;
282
0
    }
283
284
    /* Short-circuit if destination provider is the same as origin */
285
0
    if (skey->skeymgmt->name_id == skeymgmt->name_id
286
0
        && skey->skeymgmt->prov == skeymgmt->prov) {
287
0
        if (!EVP_SKEY_up_ref(skey))
288
0
            goto err;
289
0
        EVP_SKEYMGMT_free(skeymgmt);
290
0
        return skey;
291
0
    }
292
293
0
    ctx.selection = OSSL_SKEYMGMT_SELECT_ALL;
294
0
    ctx.skeymgmt = skeymgmt;
295
296
0
    if (!EVP_SKEY_export(skey, ctx.selection, transfer_cb, &ctx))
297
0
        goto err;
298
299
0
    if (ctx.keydata == NULL)
300
0
        goto err;
301
302
0
    ret = evp_skey_alloc(skeymgmt);
303
0
    if (ret == NULL)
304
0
        goto err;
305
306
0
    ret->keydata = ctx.keydata;
307
308
0
    return ret;
309
310
0
 err:
311
0
    EVP_SKEYMGMT_free(skeymgmt);
312
0
    EVP_SKEY_free(ret);
313
0
    return NULL;
314
0
}