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