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