xref: /freebsd/crypto/openssl/crypto/evp/s_lib.c (revision e7be843b4a162e68651d3911f0357ed464915629)
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 }
225 
EVP_SKEY_get0_provider_name(const EVP_SKEY * skey)226 const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey)
227 {
228     if (skey == NULL)
229         return NULL;
230 
231     return ossl_provider_name(skey->skeymgmt->prov);
232 }
233 
EVP_SKEY_is_a(const EVP_SKEY * skey,const char * name)234 int EVP_SKEY_is_a(const EVP_SKEY *skey, const char *name)
235 {
236     if (skey == NULL)
237         return 0;
238 
239     return EVP_SKEYMGMT_is_a(skey->skeymgmt, name);
240 }
241 
242 struct transfer_cb_ctx {
243     int selection;
244     EVP_SKEYMGMT *skeymgmt;
245     void *keydata;
246 };
247 
transfer_cb(const OSSL_PARAM params[],void * arg)248 static int transfer_cb(const OSSL_PARAM params[], void *arg)
249 {
250     struct transfer_cb_ctx *ctx = arg;
251 
252     ctx->keydata = evp_skeymgmt_import(ctx->skeymgmt, ctx->selection, params);
253     return 1;
254 }
255 
EVP_SKEY_to_provider(EVP_SKEY * skey,OSSL_LIB_CTX * libctx,OSSL_PROVIDER * prov,const char * propquery)256 EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx,
257                                OSSL_PROVIDER *prov, const char *propquery)
258 {
259     struct transfer_cb_ctx ctx = { 0 };
260     EVP_SKEYMGMT *skeymgmt = NULL;
261     EVP_SKEY *ret = NULL;
262 
263     if (skey == NULL) {
264         ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
265         return NULL;
266     }
267 
268     if (prov != NULL) {
269         if (skey->skeymgmt->prov == prov)
270             skeymgmt = skey->skeymgmt;
271         else
272             skeymgmt = evp_skeymgmt_fetch_from_prov(prov, skey->skeymgmt->type_name,
273                                                     propquery);
274     } else {
275         /* If no provider, get the default skeymgmt */
276         skeymgmt = EVP_SKEYMGMT_fetch(libctx, skey->skeymgmt->type_name,
277                                       propquery);
278     }
279     if (skeymgmt == NULL) {
280         ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
281         return NULL;
282     }
283 
284     /* Short-circuit if destination provider is the same as origin */
285     if (skey->skeymgmt->name_id == skeymgmt->name_id
286         && skey->skeymgmt->prov == skeymgmt->prov) {
287         if (!EVP_SKEY_up_ref(skey))
288             goto err;
289         EVP_SKEYMGMT_free(skeymgmt);
290         return skey;
291     }
292 
293     ctx.selection = OSSL_SKEYMGMT_SELECT_ALL;
294     ctx.skeymgmt = skeymgmt;
295 
296     if (!EVP_SKEY_export(skey, ctx.selection, transfer_cb, &ctx))
297         goto err;
298 
299     if (ctx.keydata == NULL)
300         goto err;
301 
302     ret = evp_skey_alloc(skeymgmt);
303     if (ret == NULL)
304         goto err;
305 
306     ret->keydata = ctx.keydata;
307 
308     return ret;
309 
310  err:
311     EVP_SKEYMGMT_free(skeymgmt);
312     EVP_SKEY_free(ret);
313     return NULL;
314 }
315