1b077aed3SPierre Pronchery /* 2*44096ebdSEnji Cooper * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. 3b077aed3SPierre Pronchery * 4b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use 5b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy 6b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at 7b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html 8b077aed3SPierre Pronchery */ 9b077aed3SPierre Pronchery 10b077aed3SPierre Pronchery #include <openssl/core_names.h> 11b077aed3SPierre Pronchery #include "internal/cryptlib.h" 12b077aed3SPierre Pronchery #include "internal/nelem.h" 13b077aed3SPierre Pronchery #include "crypto/evp.h" 14b077aed3SPierre Pronchery #include "internal/core.h" 15b077aed3SPierre Pronchery #include "internal/provider.h" 16b077aed3SPierre Pronchery #include "evp_local.h" 17b077aed3SPierre Pronchery 18b077aed3SPierre Pronchery /* 19b077aed3SPierre Pronchery * match_type() checks if two EVP_KEYMGMT are matching key types. This 20b077aed3SPierre Pronchery * function assumes that the caller has made all the necessary NULL checks. 21b077aed3SPierre Pronchery */ 22b077aed3SPierre Pronchery static int match_type(const EVP_KEYMGMT *keymgmt1, const EVP_KEYMGMT *keymgmt2) 23b077aed3SPierre Pronchery { 24b077aed3SPierre Pronchery const char *name2 = EVP_KEYMGMT_get0_name(keymgmt2); 25b077aed3SPierre Pronchery 26b077aed3SPierre Pronchery return EVP_KEYMGMT_is_a(keymgmt1, name2); 27b077aed3SPierre Pronchery } 28b077aed3SPierre Pronchery 29b077aed3SPierre Pronchery int evp_keymgmt_util_try_import(const OSSL_PARAM params[], void *arg) 30b077aed3SPierre Pronchery { 31b077aed3SPierre Pronchery struct evp_keymgmt_util_try_import_data_st *data = arg; 32b077aed3SPierre Pronchery int delete_on_error = 0; 33b077aed3SPierre Pronchery 34b077aed3SPierre Pronchery /* Just in time creation of keydata */ 35b077aed3SPierre Pronchery if (data->keydata == NULL) { 36b077aed3SPierre Pronchery if ((data->keydata = evp_keymgmt_newdata(data->keymgmt)) == NULL) { 37b077aed3SPierre Pronchery ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); 38b077aed3SPierre Pronchery return 0; 39b077aed3SPierre Pronchery } 40b077aed3SPierre Pronchery delete_on_error = 1; 41b077aed3SPierre Pronchery } 42b077aed3SPierre Pronchery 43b077aed3SPierre Pronchery /* 44b077aed3SPierre Pronchery * It's fine if there was no data to transfer, we just end up with an 45b077aed3SPierre Pronchery * empty destination key. 46b077aed3SPierre Pronchery */ 47b077aed3SPierre Pronchery if (params[0].key == NULL) 48b077aed3SPierre Pronchery return 1; 49b077aed3SPierre Pronchery 50b077aed3SPierre Pronchery if (evp_keymgmt_import(data->keymgmt, data->keydata, data->selection, 51b077aed3SPierre Pronchery params)) 52b077aed3SPierre Pronchery return 1; 53b077aed3SPierre Pronchery if (delete_on_error) { 54b077aed3SPierre Pronchery evp_keymgmt_freedata(data->keymgmt, data->keydata); 55b077aed3SPierre Pronchery data->keydata = NULL; 56b077aed3SPierre Pronchery } 57b077aed3SPierre Pronchery return 0; 58b077aed3SPierre Pronchery } 59b077aed3SPierre Pronchery 60b077aed3SPierre Pronchery int evp_keymgmt_util_assign_pkey(EVP_PKEY *pkey, EVP_KEYMGMT *keymgmt, 61b077aed3SPierre Pronchery void *keydata) 62b077aed3SPierre Pronchery { 63b077aed3SPierre Pronchery if (pkey == NULL || keymgmt == NULL || keydata == NULL 64b077aed3SPierre Pronchery || !EVP_PKEY_set_type_by_keymgmt(pkey, keymgmt)) { 65b077aed3SPierre Pronchery ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); 66b077aed3SPierre Pronchery return 0; 67b077aed3SPierre Pronchery } 68b077aed3SPierre Pronchery pkey->keydata = keydata; 69b077aed3SPierre Pronchery evp_keymgmt_util_cache_keyinfo(pkey); 70b077aed3SPierre Pronchery return 1; 71b077aed3SPierre Pronchery } 72b077aed3SPierre Pronchery 73b077aed3SPierre Pronchery EVP_PKEY *evp_keymgmt_util_make_pkey(EVP_KEYMGMT *keymgmt, void *keydata) 74b077aed3SPierre Pronchery { 75b077aed3SPierre Pronchery EVP_PKEY *pkey = NULL; 76b077aed3SPierre Pronchery 77b077aed3SPierre Pronchery if (keymgmt == NULL 78b077aed3SPierre Pronchery || keydata == NULL 79b077aed3SPierre Pronchery || (pkey = EVP_PKEY_new()) == NULL 80b077aed3SPierre Pronchery || !evp_keymgmt_util_assign_pkey(pkey, keymgmt, keydata)) { 81b077aed3SPierre Pronchery EVP_PKEY_free(pkey); 82b077aed3SPierre Pronchery return NULL; 83b077aed3SPierre Pronchery } 84b077aed3SPierre Pronchery return pkey; 85b077aed3SPierre Pronchery } 86b077aed3SPierre Pronchery 87b077aed3SPierre Pronchery int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection, 88b077aed3SPierre Pronchery OSSL_CALLBACK *export_cb, void *export_cbarg) 89b077aed3SPierre Pronchery { 90b077aed3SPierre Pronchery if (pk == NULL || export_cb == NULL) 91b077aed3SPierre Pronchery return 0; 92b077aed3SPierre Pronchery return evp_keymgmt_export(pk->keymgmt, pk->keydata, selection, 93b077aed3SPierre Pronchery export_cb, export_cbarg); 94b077aed3SPierre Pronchery } 95b077aed3SPierre Pronchery 96b077aed3SPierre Pronchery void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt, 97b077aed3SPierre Pronchery int selection) 98b077aed3SPierre Pronchery { 99b077aed3SPierre Pronchery struct evp_keymgmt_util_try_import_data_st import_data; 100b077aed3SPierre Pronchery OP_CACHE_ELEM *op; 101b077aed3SPierre Pronchery 102b077aed3SPierre Pronchery /* Export to where? */ 103b077aed3SPierre Pronchery if (keymgmt == NULL) 104b077aed3SPierre Pronchery return NULL; 105b077aed3SPierre Pronchery 106b077aed3SPierre Pronchery /* If we have an unassigned key, give up */ 107b077aed3SPierre Pronchery if (pk->keydata == NULL) 108b077aed3SPierre Pronchery return NULL; 109b077aed3SPierre Pronchery 110b077aed3SPierre Pronchery /* 111b077aed3SPierre Pronchery * If |keymgmt| matches the "origin" |keymgmt|, there is no more to do. 112b077aed3SPierre Pronchery * The "origin" is determined by the |keymgmt| pointers being identical 113b077aed3SPierre Pronchery * or when the provider and the name ID match. The latter case handles the 114b077aed3SPierre Pronchery * situation where the fetch cache is flushed and a "new" key manager is 115b077aed3SPierre Pronchery * created. 116b077aed3SPierre Pronchery */ 117b077aed3SPierre Pronchery if (pk->keymgmt == keymgmt 118b077aed3SPierre Pronchery || (pk->keymgmt->name_id == keymgmt->name_id 119b077aed3SPierre Pronchery && pk->keymgmt->prov == keymgmt->prov)) 120b077aed3SPierre Pronchery return pk->keydata; 121b077aed3SPierre Pronchery 122b077aed3SPierre Pronchery if (!CRYPTO_THREAD_read_lock(pk->lock)) 123b077aed3SPierre Pronchery return NULL; 124b077aed3SPierre Pronchery /* 125b077aed3SPierre Pronchery * If the provider native "origin" hasn't changed since last time, we 126b077aed3SPierre Pronchery * try to find our keymgmt in the operation cache. If it has changed 127b077aed3SPierre Pronchery * and our keymgmt isn't found, we will clear the cache further down. 128b077aed3SPierre Pronchery */ 129b077aed3SPierre Pronchery if (pk->dirty_cnt == pk->dirty_cnt_copy) { 130b077aed3SPierre Pronchery /* If this key is already exported to |keymgmt|, no more to do */ 131b077aed3SPierre Pronchery op = evp_keymgmt_util_find_operation_cache(pk, keymgmt, selection); 132b077aed3SPierre Pronchery if (op != NULL && op->keymgmt != NULL) { 133b077aed3SPierre Pronchery void *ret = op->keydata; 134b077aed3SPierre Pronchery 135b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(pk->lock); 136b077aed3SPierre Pronchery return ret; 137b077aed3SPierre Pronchery } 138b077aed3SPierre Pronchery } 139b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(pk->lock); 140b077aed3SPierre Pronchery 141b077aed3SPierre Pronchery /* If the "origin" |keymgmt| doesn't support exporting, give up */ 142b077aed3SPierre Pronchery if (pk->keymgmt->export == NULL) 143b077aed3SPierre Pronchery return NULL; 144b077aed3SPierre Pronchery 145b077aed3SPierre Pronchery /* 146b077aed3SPierre Pronchery * Make sure that the type of the keymgmt to export to matches the type 147b077aed3SPierre Pronchery * of the "origin" 148b077aed3SPierre Pronchery */ 149b077aed3SPierre Pronchery if (!ossl_assert(match_type(pk->keymgmt, keymgmt))) 150b077aed3SPierre Pronchery return NULL; 151b077aed3SPierre Pronchery 152b077aed3SPierre Pronchery /* 153b077aed3SPierre Pronchery * We look at the already cached provider keys, and import from the 154b077aed3SPierre Pronchery * first that supports it (i.e. use its export function), and export 155b077aed3SPierre Pronchery * the imported data to the new provider. 156b077aed3SPierre Pronchery */ 157b077aed3SPierre Pronchery 158b077aed3SPierre Pronchery /* Setup for the export callback */ 159b077aed3SPierre Pronchery import_data.keydata = NULL; /* evp_keymgmt_util_try_import will create it */ 160b077aed3SPierre Pronchery import_data.keymgmt = keymgmt; 161b077aed3SPierre Pronchery import_data.selection = selection; 162b077aed3SPierre Pronchery 163b077aed3SPierre Pronchery /* 164b077aed3SPierre Pronchery * The export function calls the callback (evp_keymgmt_util_try_import), 165b077aed3SPierre Pronchery * which does the import for us. If successful, we're done. 166b077aed3SPierre Pronchery */ 167b077aed3SPierre Pronchery if (!evp_keymgmt_util_export(pk, selection, 168b077aed3SPierre Pronchery &evp_keymgmt_util_try_import, &import_data)) 169b077aed3SPierre Pronchery /* If there was an error, bail out */ 170b077aed3SPierre Pronchery return NULL; 171b077aed3SPierre Pronchery 172b077aed3SPierre Pronchery if (!CRYPTO_THREAD_write_lock(pk->lock)) { 173b077aed3SPierre Pronchery evp_keymgmt_freedata(keymgmt, import_data.keydata); 174b077aed3SPierre Pronchery return NULL; 175b077aed3SPierre Pronchery } 176b077aed3SPierre Pronchery /* Check to make sure some other thread didn't get there first */ 177b077aed3SPierre Pronchery op = evp_keymgmt_util_find_operation_cache(pk, keymgmt, selection); 178b077aed3SPierre Pronchery if (op != NULL && op->keydata != NULL) { 179b077aed3SPierre Pronchery void *ret = op->keydata; 180b077aed3SPierre Pronchery 181b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(pk->lock); 182b077aed3SPierre Pronchery 183b077aed3SPierre Pronchery /* 184b077aed3SPierre Pronchery * Another thread seemms to have already exported this so we abandon 185b077aed3SPierre Pronchery * all the work we just did. 186b077aed3SPierre Pronchery */ 187b077aed3SPierre Pronchery evp_keymgmt_freedata(keymgmt, import_data.keydata); 188b077aed3SPierre Pronchery 189b077aed3SPierre Pronchery return ret; 190b077aed3SPierre Pronchery } 191b077aed3SPierre Pronchery 192b077aed3SPierre Pronchery /* 193b077aed3SPierre Pronchery * If the dirty counter changed since last time, then clear the 194b077aed3SPierre Pronchery * operation cache. In that case, we know that |i| is zero. 195b077aed3SPierre Pronchery */ 196b077aed3SPierre Pronchery if (pk->dirty_cnt != pk->dirty_cnt_copy) 197b077aed3SPierre Pronchery evp_keymgmt_util_clear_operation_cache(pk, 0); 198b077aed3SPierre Pronchery 199b077aed3SPierre Pronchery /* Add the new export to the operation cache */ 200b077aed3SPierre Pronchery if (!evp_keymgmt_util_cache_keydata(pk, keymgmt, import_data.keydata, 201b077aed3SPierre Pronchery selection)) { 202b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(pk->lock); 203b077aed3SPierre Pronchery evp_keymgmt_freedata(keymgmt, import_data.keydata); 204b077aed3SPierre Pronchery return NULL; 205b077aed3SPierre Pronchery } 206b077aed3SPierre Pronchery 207b077aed3SPierre Pronchery /* Synchronize the dirty count */ 208b077aed3SPierre Pronchery pk->dirty_cnt_copy = pk->dirty_cnt; 209b077aed3SPierre Pronchery 210b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(pk->lock); 211b077aed3SPierre Pronchery 212b077aed3SPierre Pronchery return import_data.keydata; 213b077aed3SPierre Pronchery } 214b077aed3SPierre Pronchery 215b077aed3SPierre Pronchery static void op_cache_free(OP_CACHE_ELEM *e) 216b077aed3SPierre Pronchery { 217b077aed3SPierre Pronchery evp_keymgmt_freedata(e->keymgmt, e->keydata); 218b077aed3SPierre Pronchery EVP_KEYMGMT_free(e->keymgmt); 219b077aed3SPierre Pronchery OPENSSL_free(e); 220b077aed3SPierre Pronchery } 221b077aed3SPierre Pronchery 222b077aed3SPierre Pronchery int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking) 223b077aed3SPierre Pronchery { 224b077aed3SPierre Pronchery if (pk != NULL) { 225b077aed3SPierre Pronchery if (locking && pk->lock != NULL && !CRYPTO_THREAD_write_lock(pk->lock)) 226b077aed3SPierre Pronchery return 0; 227b077aed3SPierre Pronchery sk_OP_CACHE_ELEM_pop_free(pk->operation_cache, op_cache_free); 228b077aed3SPierre Pronchery pk->operation_cache = NULL; 229b077aed3SPierre Pronchery if (locking && pk->lock != NULL) 230b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(pk->lock); 231b077aed3SPierre Pronchery } 232b077aed3SPierre Pronchery 233b077aed3SPierre Pronchery return 1; 234b077aed3SPierre Pronchery } 235b077aed3SPierre Pronchery 236b077aed3SPierre Pronchery OP_CACHE_ELEM *evp_keymgmt_util_find_operation_cache(EVP_PKEY *pk, 237b077aed3SPierre Pronchery EVP_KEYMGMT *keymgmt, 238b077aed3SPierre Pronchery int selection) 239b077aed3SPierre Pronchery { 240b077aed3SPierre Pronchery int i, end = sk_OP_CACHE_ELEM_num(pk->operation_cache); 241b077aed3SPierre Pronchery OP_CACHE_ELEM *p; 242b077aed3SPierre Pronchery 243b077aed3SPierre Pronchery /* 244b077aed3SPierre Pronchery * A comparison and sk_P_CACHE_ELEM_find() are avoided to not cause 245b077aed3SPierre Pronchery * problems when we've only a read lock. 246*44096ebdSEnji Cooper * A keymgmt is a match if the |keymgmt| pointers are identical or if the 247*44096ebdSEnji Cooper * provider and the name ID match 248b077aed3SPierre Pronchery */ 249b077aed3SPierre Pronchery for (i = 0; i < end; i++) { 250b077aed3SPierre Pronchery p = sk_OP_CACHE_ELEM_value(pk->operation_cache, i); 251*44096ebdSEnji Cooper if ((p->selection & selection) == selection 252*44096ebdSEnji Cooper && (keymgmt == p->keymgmt 253*44096ebdSEnji Cooper || (keymgmt->name_id == p->keymgmt->name_id 254*44096ebdSEnji Cooper && keymgmt->prov == p->keymgmt->prov))) 255b077aed3SPierre Pronchery return p; 256b077aed3SPierre Pronchery } 257b077aed3SPierre Pronchery return NULL; 258b077aed3SPierre Pronchery } 259b077aed3SPierre Pronchery 260b077aed3SPierre Pronchery int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt, 261b077aed3SPierre Pronchery void *keydata, int selection) 262b077aed3SPierre Pronchery { 263b077aed3SPierre Pronchery OP_CACHE_ELEM *p = NULL; 264b077aed3SPierre Pronchery 265b077aed3SPierre Pronchery if (keydata != NULL) { 266b077aed3SPierre Pronchery if (pk->operation_cache == NULL) { 267b077aed3SPierre Pronchery pk->operation_cache = sk_OP_CACHE_ELEM_new_null(); 268b077aed3SPierre Pronchery if (pk->operation_cache == NULL) 269b077aed3SPierre Pronchery return 0; 270b077aed3SPierre Pronchery } 271b077aed3SPierre Pronchery 272b077aed3SPierre Pronchery p = OPENSSL_malloc(sizeof(*p)); 273b077aed3SPierre Pronchery if (p == NULL) 274b077aed3SPierre Pronchery return 0; 275b077aed3SPierre Pronchery p->keydata = keydata; 276b077aed3SPierre Pronchery p->keymgmt = keymgmt; 277b077aed3SPierre Pronchery p->selection = selection; 278b077aed3SPierre Pronchery 279b077aed3SPierre Pronchery if (!EVP_KEYMGMT_up_ref(keymgmt)) { 280b077aed3SPierre Pronchery OPENSSL_free(p); 281b077aed3SPierre Pronchery return 0; 282b077aed3SPierre Pronchery } 283b077aed3SPierre Pronchery 284b077aed3SPierre Pronchery if (!sk_OP_CACHE_ELEM_push(pk->operation_cache, p)) { 285b077aed3SPierre Pronchery EVP_KEYMGMT_free(keymgmt); 286b077aed3SPierre Pronchery OPENSSL_free(p); 287b077aed3SPierre Pronchery return 0; 288b077aed3SPierre Pronchery } 289b077aed3SPierre Pronchery } 290b077aed3SPierre Pronchery return 1; 291b077aed3SPierre Pronchery } 292b077aed3SPierre Pronchery 293b077aed3SPierre Pronchery void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk) 294b077aed3SPierre Pronchery { 295b077aed3SPierre Pronchery /* 296b077aed3SPierre Pronchery * Cache information about the provider "origin" key. 297b077aed3SPierre Pronchery * 298b077aed3SPierre Pronchery * This services functions like EVP_PKEY_get_size, EVP_PKEY_get_bits, etc 299b077aed3SPierre Pronchery */ 300b077aed3SPierre Pronchery if (pk->keydata != NULL) { 301b077aed3SPierre Pronchery int bits = 0; 302b077aed3SPierre Pronchery int security_bits = 0; 303b077aed3SPierre Pronchery int size = 0; 304b077aed3SPierre Pronchery OSSL_PARAM params[4]; 305b077aed3SPierre Pronchery 306b077aed3SPierre Pronchery params[0] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_BITS, &bits); 307b077aed3SPierre Pronchery params[1] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_SECURITY_BITS, 308b077aed3SPierre Pronchery &security_bits); 309b077aed3SPierre Pronchery params[2] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_MAX_SIZE, &size); 310b077aed3SPierre Pronchery params[3] = OSSL_PARAM_construct_end(); 311b077aed3SPierre Pronchery if (evp_keymgmt_get_params(pk->keymgmt, pk->keydata, params)) { 312b077aed3SPierre Pronchery pk->cache.size = size; 313b077aed3SPierre Pronchery pk->cache.bits = bits; 314b077aed3SPierre Pronchery pk->cache.security_bits = security_bits; 315b077aed3SPierre Pronchery } 316b077aed3SPierre Pronchery } 317b077aed3SPierre Pronchery } 318b077aed3SPierre Pronchery 319b077aed3SPierre Pronchery void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, 320b077aed3SPierre Pronchery int selection, const OSSL_PARAM params[]) 321b077aed3SPierre Pronchery { 322b077aed3SPierre Pronchery void *keydata = NULL; 323b077aed3SPierre Pronchery 324b077aed3SPierre Pronchery if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL 325b077aed3SPierre Pronchery || !evp_keymgmt_import(keymgmt, keydata, selection, params) 326b077aed3SPierre Pronchery || !evp_keymgmt_util_assign_pkey(target, keymgmt, keydata)) { 327b077aed3SPierre Pronchery evp_keymgmt_freedata(keymgmt, keydata); 328b077aed3SPierre Pronchery keydata = NULL; 329b077aed3SPierre Pronchery } 330b077aed3SPierre Pronchery return keydata; 331b077aed3SPierre Pronchery } 332b077aed3SPierre Pronchery 333b077aed3SPierre Pronchery int evp_keymgmt_util_has(EVP_PKEY *pk, int selection) 334b077aed3SPierre Pronchery { 335b077aed3SPierre Pronchery /* Check if key is even assigned */ 336b077aed3SPierre Pronchery if (pk->keymgmt == NULL) 337b077aed3SPierre Pronchery return 0; 338b077aed3SPierre Pronchery 339b077aed3SPierre Pronchery return evp_keymgmt_has(pk->keymgmt, pk->keydata, selection); 340b077aed3SPierre Pronchery } 341b077aed3SPierre Pronchery 342b077aed3SPierre Pronchery /* 343b077aed3SPierre Pronchery * evp_keymgmt_util_match() doesn't just look at the provider side "origin", 344b077aed3SPierre Pronchery * but also in the operation cache to see if there's any common keymgmt that 345b077aed3SPierre Pronchery * supplies OP_keymgmt_match. 346b077aed3SPierre Pronchery * 347b077aed3SPierre Pronchery * evp_keymgmt_util_match() adheres to the return values that EVP_PKEY_eq() 348b077aed3SPierre Pronchery * and EVP_PKEY_parameters_eq() return, i.e.: 349b077aed3SPierre Pronchery * 350b077aed3SPierre Pronchery * 1 same key 351b077aed3SPierre Pronchery * 0 not same key 352b077aed3SPierre Pronchery * -1 not same key type 353b077aed3SPierre Pronchery * -2 unsupported operation 354b077aed3SPierre Pronchery */ 355b077aed3SPierre Pronchery int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection) 356b077aed3SPierre Pronchery { 357b077aed3SPierre Pronchery EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL; 358b077aed3SPierre Pronchery void *keydata1 = NULL, *keydata2 = NULL; 359b077aed3SPierre Pronchery 360b077aed3SPierre Pronchery if (pk1 == NULL || pk2 == NULL) { 361b077aed3SPierre Pronchery if (pk1 == NULL && pk2 == NULL) 362b077aed3SPierre Pronchery return 1; 363b077aed3SPierre Pronchery return 0; 364b077aed3SPierre Pronchery } 365b077aed3SPierre Pronchery 366b077aed3SPierre Pronchery keymgmt1 = pk1->keymgmt; 367b077aed3SPierre Pronchery keydata1 = pk1->keydata; 368b077aed3SPierre Pronchery keymgmt2 = pk2->keymgmt; 369b077aed3SPierre Pronchery keydata2 = pk2->keydata; 370b077aed3SPierre Pronchery 371b077aed3SPierre Pronchery if (keymgmt1 != keymgmt2) { 372b077aed3SPierre Pronchery /* 373b077aed3SPierre Pronchery * The condition for a successful cross export is that the 374b077aed3SPierre Pronchery * keydata to be exported is NULL (typed, but otherwise empty 375b077aed3SPierre Pronchery * EVP_PKEY), or that it was possible to export it with 376b077aed3SPierre Pronchery * evp_keymgmt_util_export_to_provider(). 377b077aed3SPierre Pronchery * 378b077aed3SPierre Pronchery * We use |ok| to determine if it's ok to cross export one way, 379b077aed3SPierre Pronchery * but also to determine if we should attempt a cross export 380b077aed3SPierre Pronchery * the other way. There's no point doing it both ways. 381b077aed3SPierre Pronchery */ 382b077aed3SPierre Pronchery int ok = 0; 383b077aed3SPierre Pronchery 384b077aed3SPierre Pronchery /* Complex case, where the keymgmt differ */ 385b077aed3SPierre Pronchery if (keymgmt1 != NULL 386b077aed3SPierre Pronchery && keymgmt2 != NULL 387b077aed3SPierre Pronchery && !match_type(keymgmt1, keymgmt2)) { 388b077aed3SPierre Pronchery ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); 389b077aed3SPierre Pronchery return -1; /* Not the same type */ 390b077aed3SPierre Pronchery } 391b077aed3SPierre Pronchery 392b077aed3SPierre Pronchery /* 393b077aed3SPierre Pronchery * The key types are determined to match, so we try cross export, 394b077aed3SPierre Pronchery * but only to keymgmt's that supply a matching function. 395b077aed3SPierre Pronchery */ 396b077aed3SPierre Pronchery if (keymgmt2 != NULL 397b077aed3SPierre Pronchery && keymgmt2->match != NULL) { 398b077aed3SPierre Pronchery void *tmp_keydata = NULL; 399b077aed3SPierre Pronchery 400b077aed3SPierre Pronchery ok = 1; 401b077aed3SPierre Pronchery if (keydata1 != NULL) { 402b077aed3SPierre Pronchery tmp_keydata = 403b077aed3SPierre Pronchery evp_keymgmt_util_export_to_provider(pk1, keymgmt2, 404b077aed3SPierre Pronchery selection); 405b077aed3SPierre Pronchery ok = (tmp_keydata != NULL); 406b077aed3SPierre Pronchery } 407b077aed3SPierre Pronchery if (ok) { 408b077aed3SPierre Pronchery keymgmt1 = keymgmt2; 409b077aed3SPierre Pronchery keydata1 = tmp_keydata; 410b077aed3SPierre Pronchery } 411b077aed3SPierre Pronchery } 412b077aed3SPierre Pronchery /* 413b077aed3SPierre Pronchery * If we've successfully cross exported one way, there's no point 414b077aed3SPierre Pronchery * doing it the other way, hence the |!ok| check. 415b077aed3SPierre Pronchery */ 416b077aed3SPierre Pronchery if (!ok 417b077aed3SPierre Pronchery && keymgmt1 != NULL 418b077aed3SPierre Pronchery && keymgmt1->match != NULL) { 419b077aed3SPierre Pronchery void *tmp_keydata = NULL; 420b077aed3SPierre Pronchery 421b077aed3SPierre Pronchery ok = 1; 422b077aed3SPierre Pronchery if (keydata2 != NULL) { 423b077aed3SPierre Pronchery tmp_keydata = 424b077aed3SPierre Pronchery evp_keymgmt_util_export_to_provider(pk2, keymgmt1, 425b077aed3SPierre Pronchery selection); 426b077aed3SPierre Pronchery ok = (tmp_keydata != NULL); 427b077aed3SPierre Pronchery } 428b077aed3SPierre Pronchery if (ok) { 429b077aed3SPierre Pronchery keymgmt2 = keymgmt1; 430b077aed3SPierre Pronchery keydata2 = tmp_keydata; 431b077aed3SPierre Pronchery } 432b077aed3SPierre Pronchery } 433b077aed3SPierre Pronchery } 434b077aed3SPierre Pronchery 435b077aed3SPierre Pronchery /* If we still don't have matching keymgmt implementations, we give up */ 436b077aed3SPierre Pronchery if (keymgmt1 != keymgmt2) 437b077aed3SPierre Pronchery return -2; 438b077aed3SPierre Pronchery 439b077aed3SPierre Pronchery /* If both keydata are NULL, then they're the same key */ 440b077aed3SPierre Pronchery if (keydata1 == NULL && keydata2 == NULL) 441b077aed3SPierre Pronchery return 1; 442b077aed3SPierre Pronchery /* If only one of the keydata is NULL, then they're different keys */ 443b077aed3SPierre Pronchery if (keydata1 == NULL || keydata2 == NULL) 444b077aed3SPierre Pronchery return 0; 445b077aed3SPierre Pronchery /* If both keydata are non-NULL, we let the backend decide */ 446b077aed3SPierre Pronchery return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection); 447b077aed3SPierre Pronchery } 448b077aed3SPierre Pronchery 449b077aed3SPierre Pronchery int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection) 450b077aed3SPierre Pronchery { 451b077aed3SPierre Pronchery /* Save copies of pointers we want to play with without affecting |to| */ 452b077aed3SPierre Pronchery EVP_KEYMGMT *to_keymgmt = to->keymgmt; 453b077aed3SPierre Pronchery void *to_keydata = to->keydata, *alloc_keydata = NULL; 454b077aed3SPierre Pronchery 455b077aed3SPierre Pronchery /* An unassigned key can't be copied */ 456b077aed3SPierre Pronchery if (from == NULL || from->keydata == NULL) 457b077aed3SPierre Pronchery return 0; 458b077aed3SPierre Pronchery 459b077aed3SPierre Pronchery /* 460b077aed3SPierre Pronchery * If |to| is unassigned, ensure it gets the same KEYMGMT as |from|, 461b077aed3SPierre Pronchery * Note that the final setting of KEYMGMT is done further down, with 462b077aed3SPierre Pronchery * EVP_PKEY_set_type_by_keymgmt(); we don't want to do that prematurely. 463b077aed3SPierre Pronchery */ 464b077aed3SPierre Pronchery if (to_keymgmt == NULL) 465b077aed3SPierre Pronchery to_keymgmt = from->keymgmt; 466b077aed3SPierre Pronchery 467b077aed3SPierre Pronchery if (to_keymgmt == from->keymgmt && to_keymgmt->dup != NULL 468b077aed3SPierre Pronchery && to_keydata == NULL) { 469b077aed3SPierre Pronchery to_keydata = alloc_keydata = evp_keymgmt_dup(to_keymgmt, 470b077aed3SPierre Pronchery from->keydata, 471b077aed3SPierre Pronchery selection); 472b077aed3SPierre Pronchery if (to_keydata == NULL) 473b077aed3SPierre Pronchery return 0; 474b077aed3SPierre Pronchery } else if (match_type(to_keymgmt, from->keymgmt)) { 475b077aed3SPierre Pronchery struct evp_keymgmt_util_try_import_data_st import_data; 476b077aed3SPierre Pronchery 477b077aed3SPierre Pronchery import_data.keymgmt = to_keymgmt; 478b077aed3SPierre Pronchery import_data.keydata = to_keydata; 479b077aed3SPierre Pronchery import_data.selection = selection; 480b077aed3SPierre Pronchery 481b077aed3SPierre Pronchery if (!evp_keymgmt_util_export(from, selection, 482b077aed3SPierre Pronchery &evp_keymgmt_util_try_import, 483b077aed3SPierre Pronchery &import_data)) 484b077aed3SPierre Pronchery return 0; 485b077aed3SPierre Pronchery 486b077aed3SPierre Pronchery /* 487b077aed3SPierre Pronchery * In case to_keydata was previously unallocated, 488b077aed3SPierre Pronchery * evp_keymgmt_util_try_import() may have created it for us. 489b077aed3SPierre Pronchery */ 490b077aed3SPierre Pronchery if (to_keydata == NULL) 491b077aed3SPierre Pronchery to_keydata = alloc_keydata = import_data.keydata; 492b077aed3SPierre Pronchery } else { 493b077aed3SPierre Pronchery ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); 494b077aed3SPierre Pronchery return 0; 495b077aed3SPierre Pronchery } 496b077aed3SPierre Pronchery 497b077aed3SPierre Pronchery /* 498b077aed3SPierre Pronchery * We only need to set the |to| type when its |keymgmt| isn't set. 499b077aed3SPierre Pronchery * We can then just set its |keydata| to what we have, which might 500b077aed3SPierre Pronchery * be exactly what it had when entering this function. 501b077aed3SPierre Pronchery * This is a bit different from using evp_keymgmt_util_assign_pkey(), 502b077aed3SPierre Pronchery * which isn't as careful with |to|'s original |keymgmt|, since it's 503b077aed3SPierre Pronchery * meant to forcibly reassign an EVP_PKEY no matter what, which is 504b077aed3SPierre Pronchery * why we don't use that one here. 505b077aed3SPierre Pronchery */ 506b077aed3SPierre Pronchery if (to->keymgmt == NULL 507b077aed3SPierre Pronchery && !EVP_PKEY_set_type_by_keymgmt(to, to_keymgmt)) { 508b077aed3SPierre Pronchery evp_keymgmt_freedata(to_keymgmt, alloc_keydata); 509b077aed3SPierre Pronchery return 0; 510b077aed3SPierre Pronchery } 511b077aed3SPierre Pronchery to->keydata = to_keydata; 512b077aed3SPierre Pronchery evp_keymgmt_util_cache_keyinfo(to); 513b077aed3SPierre Pronchery 514b077aed3SPierre Pronchery return 1; 515b077aed3SPierre Pronchery } 516b077aed3SPierre Pronchery 517b077aed3SPierre Pronchery void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, 518b077aed3SPierre Pronchery void *genctx, OSSL_CALLBACK *cb, void *cbarg) 519b077aed3SPierre Pronchery { 520b077aed3SPierre Pronchery void *keydata = NULL; 521b077aed3SPierre Pronchery 522b077aed3SPierre Pronchery if ((keydata = evp_keymgmt_gen(keymgmt, genctx, cb, cbarg)) == NULL 523b077aed3SPierre Pronchery || !evp_keymgmt_util_assign_pkey(target, keymgmt, keydata)) { 524b077aed3SPierre Pronchery evp_keymgmt_freedata(keymgmt, keydata); 525b077aed3SPierre Pronchery keydata = NULL; 526b077aed3SPierre Pronchery } 527b077aed3SPierre Pronchery 528b077aed3SPierre Pronchery return keydata; 529b077aed3SPierre Pronchery } 530b077aed3SPierre Pronchery 531b077aed3SPierre Pronchery /* 532b077aed3SPierre Pronchery * Returns the same numbers as EVP_PKEY_get_default_digest_name() 533b077aed3SPierre Pronchery * When the string from the EVP_KEYMGMT implementation is "", we use 534b077aed3SPierre Pronchery * SN_undef, since that corresponds to what EVP_PKEY_get_default_nid() 535b077aed3SPierre Pronchery * returns for no digest. 536b077aed3SPierre Pronchery */ 537b077aed3SPierre Pronchery int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt, 538b077aed3SPierre Pronchery void *keydata, 539b077aed3SPierre Pronchery char *mdname, size_t mdname_sz) 540b077aed3SPierre Pronchery { 541b077aed3SPierre Pronchery OSSL_PARAM params[3]; 542b077aed3SPierre Pronchery char mddefault[100] = ""; 543b077aed3SPierre Pronchery char mdmandatory[100] = ""; 544b077aed3SPierre Pronchery char *result = NULL; 545b077aed3SPierre Pronchery int rv = -2; 546b077aed3SPierre Pronchery 547b077aed3SPierre Pronchery params[0] = 548b077aed3SPierre Pronchery OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, 549b077aed3SPierre Pronchery mddefault, sizeof(mddefault)); 550b077aed3SPierre Pronchery params[1] = 551b077aed3SPierre Pronchery OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, 552b077aed3SPierre Pronchery mdmandatory, 553b077aed3SPierre Pronchery sizeof(mdmandatory)); 554b077aed3SPierre Pronchery params[2] = OSSL_PARAM_construct_end(); 555b077aed3SPierre Pronchery 556b077aed3SPierre Pronchery if (!evp_keymgmt_get_params(keymgmt, keydata, params)) 557b077aed3SPierre Pronchery return 0; 558b077aed3SPierre Pronchery 559b077aed3SPierre Pronchery if (OSSL_PARAM_modified(params + 1)) { 560b077aed3SPierre Pronchery if (params[1].return_size <= 1) /* Only a NUL byte */ 561b077aed3SPierre Pronchery result = SN_undef; 562b077aed3SPierre Pronchery else 563b077aed3SPierre Pronchery result = mdmandatory; 564b077aed3SPierre Pronchery rv = 2; 565b077aed3SPierre Pronchery } else if (OSSL_PARAM_modified(params)) { 566b077aed3SPierre Pronchery if (params[0].return_size <= 1) /* Only a NUL byte */ 567b077aed3SPierre Pronchery result = SN_undef; 568b077aed3SPierre Pronchery else 569b077aed3SPierre Pronchery result = mddefault; 570b077aed3SPierre Pronchery rv = 1; 571b077aed3SPierre Pronchery } 572b077aed3SPierre Pronchery if (rv > 0) 573b077aed3SPierre Pronchery OPENSSL_strlcpy(mdname, result, mdname_sz); 574b077aed3SPierre Pronchery return rv; 575b077aed3SPierre Pronchery } 576b077aed3SPierre Pronchery 577b077aed3SPierre Pronchery /* 578b077aed3SPierre Pronchery * If |keymgmt| has the method function |query_operation_name|, use it to get 579b077aed3SPierre Pronchery * the name of a supported operation identity. Otherwise, return the keytype, 580b077aed3SPierre Pronchery * assuming that it works as a default operation name. 581b077aed3SPierre Pronchery */ 582b077aed3SPierre Pronchery const char *evp_keymgmt_util_query_operation_name(EVP_KEYMGMT *keymgmt, 583b077aed3SPierre Pronchery int op_id) 584b077aed3SPierre Pronchery { 585b077aed3SPierre Pronchery const char *name = NULL; 586b077aed3SPierre Pronchery 587b077aed3SPierre Pronchery if (keymgmt != NULL) { 588b077aed3SPierre Pronchery if (keymgmt->query_operation_name != NULL) 589b077aed3SPierre Pronchery name = keymgmt->query_operation_name(op_id); 590b077aed3SPierre Pronchery if (name == NULL) 591b077aed3SPierre Pronchery name = EVP_KEYMGMT_get0_name(keymgmt); 592b077aed3SPierre Pronchery } 593b077aed3SPierre Pronchery return name; 594b077aed3SPierre Pronchery } 595