1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2006-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/* We need to use some engine deprecated APIs */ 11e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED 12e1051a39Sopenharmony_ci 13e1051a39Sopenharmony_ci#include "e_os.h" 14e1051a39Sopenharmony_ci#include "eng_local.h" 15e1051a39Sopenharmony_ci#include <openssl/evp.h> 16e1051a39Sopenharmony_ci#include "crypto/asn1.h" 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci/* 19e1051a39Sopenharmony_ci * If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the 20e1051a39Sopenharmony_ci * function that is used by EVP to hook in pkey_asn1_meth code and cache 21e1051a39Sopenharmony_ci * defaults (etc), will display brief debugging summaries to stderr with the 22e1051a39Sopenharmony_ci * 'nid'. 23e1051a39Sopenharmony_ci */ 24e1051a39Sopenharmony_ci/* #define ENGINE_PKEY_ASN1_METH_DEBUG */ 25e1051a39Sopenharmony_ci 26e1051a39Sopenharmony_cistatic ENGINE_TABLE *pkey_asn1_meth_table = NULL; 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_civoid ENGINE_unregister_pkey_asn1_meths(ENGINE *e) 29e1051a39Sopenharmony_ci{ 30e1051a39Sopenharmony_ci engine_table_unregister(&pkey_asn1_meth_table, e); 31e1051a39Sopenharmony_ci} 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_cistatic void engine_unregister_all_pkey_asn1_meths(void) 34e1051a39Sopenharmony_ci{ 35e1051a39Sopenharmony_ci engine_table_cleanup(&pkey_asn1_meth_table); 36e1051a39Sopenharmony_ci} 37e1051a39Sopenharmony_ci 38e1051a39Sopenharmony_ciint ENGINE_register_pkey_asn1_meths(ENGINE *e) 39e1051a39Sopenharmony_ci{ 40e1051a39Sopenharmony_ci if (e->pkey_asn1_meths) { 41e1051a39Sopenharmony_ci const int *nids; 42e1051a39Sopenharmony_ci int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0); 43e1051a39Sopenharmony_ci if (num_nids > 0) 44e1051a39Sopenharmony_ci return engine_table_register(&pkey_asn1_meth_table, 45e1051a39Sopenharmony_ci engine_unregister_all_pkey_asn1_meths, 46e1051a39Sopenharmony_ci e, nids, num_nids, 0); 47e1051a39Sopenharmony_ci } 48e1051a39Sopenharmony_ci return 1; 49e1051a39Sopenharmony_ci} 50e1051a39Sopenharmony_ci 51e1051a39Sopenharmony_civoid ENGINE_register_all_pkey_asn1_meths(void) 52e1051a39Sopenharmony_ci{ 53e1051a39Sopenharmony_ci ENGINE *e; 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_ci for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) 56e1051a39Sopenharmony_ci ENGINE_register_pkey_asn1_meths(e); 57e1051a39Sopenharmony_ci} 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_ciint ENGINE_set_default_pkey_asn1_meths(ENGINE *e) 60e1051a39Sopenharmony_ci{ 61e1051a39Sopenharmony_ci if (e->pkey_asn1_meths) { 62e1051a39Sopenharmony_ci const int *nids; 63e1051a39Sopenharmony_ci int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0); 64e1051a39Sopenharmony_ci if (num_nids > 0) 65e1051a39Sopenharmony_ci return engine_table_register(&pkey_asn1_meth_table, 66e1051a39Sopenharmony_ci engine_unregister_all_pkey_asn1_meths, 67e1051a39Sopenharmony_ci e, nids, num_nids, 1); 68e1051a39Sopenharmony_ci } 69e1051a39Sopenharmony_ci return 1; 70e1051a39Sopenharmony_ci} 71e1051a39Sopenharmony_ci 72e1051a39Sopenharmony_ci/* 73e1051a39Sopenharmony_ci * Exposed API function to get a functional reference from the implementation 74e1051a39Sopenharmony_ci * table (ie. try to get a functional reference from the tabled structural 75e1051a39Sopenharmony_ci * references) for a given pkey_asn1_meth 'nid' 76e1051a39Sopenharmony_ci */ 77e1051a39Sopenharmony_ciENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid) 78e1051a39Sopenharmony_ci{ 79e1051a39Sopenharmony_ci return ossl_engine_table_select(&pkey_asn1_meth_table, nid, 80e1051a39Sopenharmony_ci OPENSSL_FILE, OPENSSL_LINE); 81e1051a39Sopenharmony_ci} 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci/* 84e1051a39Sopenharmony_ci * Obtains a pkey_asn1_meth implementation from an ENGINE functional 85e1051a39Sopenharmony_ci * reference 86e1051a39Sopenharmony_ci */ 87e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid) 88e1051a39Sopenharmony_ci{ 89e1051a39Sopenharmony_ci EVP_PKEY_ASN1_METHOD *ret; 90e1051a39Sopenharmony_ci ENGINE_PKEY_ASN1_METHS_PTR fn = ENGINE_get_pkey_asn1_meths(e); 91e1051a39Sopenharmony_ci if (!fn || !fn(e, &ret, NULL, nid)) { 92e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD); 93e1051a39Sopenharmony_ci return NULL; 94e1051a39Sopenharmony_ci } 95e1051a39Sopenharmony_ci return ret; 96e1051a39Sopenharmony_ci} 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ci/* Gets the pkey_asn1_meth callback from an ENGINE structure */ 99e1051a39Sopenharmony_ciENGINE_PKEY_ASN1_METHS_PTR ENGINE_get_pkey_asn1_meths(const ENGINE *e) 100e1051a39Sopenharmony_ci{ 101e1051a39Sopenharmony_ci return e->pkey_asn1_meths; 102e1051a39Sopenharmony_ci} 103e1051a39Sopenharmony_ci 104e1051a39Sopenharmony_ci/* Sets the pkey_asn1_meth callback in an ENGINE structure */ 105e1051a39Sopenharmony_ciint ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f) 106e1051a39Sopenharmony_ci{ 107e1051a39Sopenharmony_ci e->pkey_asn1_meths = f; 108e1051a39Sopenharmony_ci return 1; 109e1051a39Sopenharmony_ci} 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci/* 112e1051a39Sopenharmony_ci * Internal function to free up EVP_PKEY_ASN1_METHOD structures before an 113e1051a39Sopenharmony_ci * ENGINE is destroyed 114e1051a39Sopenharmony_ci */ 115e1051a39Sopenharmony_ci 116e1051a39Sopenharmony_civoid engine_pkey_asn1_meths_free(ENGINE *e) 117e1051a39Sopenharmony_ci{ 118e1051a39Sopenharmony_ci int i; 119e1051a39Sopenharmony_ci EVP_PKEY_ASN1_METHOD *pkm; 120e1051a39Sopenharmony_ci if (e->pkey_asn1_meths) { 121e1051a39Sopenharmony_ci const int *pknids; 122e1051a39Sopenharmony_ci int npknids; 123e1051a39Sopenharmony_ci npknids = e->pkey_asn1_meths(e, NULL, &pknids, 0); 124e1051a39Sopenharmony_ci for (i = 0; i < npknids; i++) { 125e1051a39Sopenharmony_ci if (e->pkey_asn1_meths(e, &pkm, NULL, pknids[i])) { 126e1051a39Sopenharmony_ci EVP_PKEY_asn1_free(pkm); 127e1051a39Sopenharmony_ci } 128e1051a39Sopenharmony_ci } 129e1051a39Sopenharmony_ci } 130e1051a39Sopenharmony_ci} 131e1051a39Sopenharmony_ci 132e1051a39Sopenharmony_ci/* 133e1051a39Sopenharmony_ci * Find a method based on a string. This does a linear search through all 134e1051a39Sopenharmony_ci * implemented algorithms. This is OK in practice because only a small number 135e1051a39Sopenharmony_ci * of algorithms are likely to be implemented in an engine and it is not used 136e1051a39Sopenharmony_ci * for speed critical operations. 137e1051a39Sopenharmony_ci */ 138e1051a39Sopenharmony_ci 139e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e, 140e1051a39Sopenharmony_ci const char *str, 141e1051a39Sopenharmony_ci int len) 142e1051a39Sopenharmony_ci{ 143e1051a39Sopenharmony_ci int i, nidcount; 144e1051a39Sopenharmony_ci const int *nids; 145e1051a39Sopenharmony_ci EVP_PKEY_ASN1_METHOD *ameth; 146e1051a39Sopenharmony_ci if (!e->pkey_asn1_meths) 147e1051a39Sopenharmony_ci return NULL; 148e1051a39Sopenharmony_ci if (len == -1) 149e1051a39Sopenharmony_ci len = strlen(str); 150e1051a39Sopenharmony_ci nidcount = e->pkey_asn1_meths(e, NULL, &nids, 0); 151e1051a39Sopenharmony_ci for (i = 0; i < nidcount; i++) { 152e1051a39Sopenharmony_ci e->pkey_asn1_meths(e, &ameth, NULL, nids[i]); 153e1051a39Sopenharmony_ci if (ameth != NULL 154e1051a39Sopenharmony_ci && ((int)strlen(ameth->pem_str) == len) 155e1051a39Sopenharmony_ci && OPENSSL_strncasecmp(ameth->pem_str, str, len) == 0) 156e1051a39Sopenharmony_ci return ameth; 157e1051a39Sopenharmony_ci } 158e1051a39Sopenharmony_ci return NULL; 159e1051a39Sopenharmony_ci} 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_citypedef struct { 162e1051a39Sopenharmony_ci ENGINE *e; 163e1051a39Sopenharmony_ci const EVP_PKEY_ASN1_METHOD *ameth; 164e1051a39Sopenharmony_ci const char *str; 165e1051a39Sopenharmony_ci int len; 166e1051a39Sopenharmony_ci} ENGINE_FIND_STR; 167e1051a39Sopenharmony_ci 168e1051a39Sopenharmony_cistatic void look_str_cb(int nid, STACK_OF(ENGINE) *sk, ENGINE *def, void *arg) 169e1051a39Sopenharmony_ci{ 170e1051a39Sopenharmony_ci ENGINE_FIND_STR *lk = arg; 171e1051a39Sopenharmony_ci int i; 172e1051a39Sopenharmony_ci if (lk->ameth) 173e1051a39Sopenharmony_ci return; 174e1051a39Sopenharmony_ci for (i = 0; i < sk_ENGINE_num(sk); i++) { 175e1051a39Sopenharmony_ci ENGINE *e = sk_ENGINE_value(sk, i); 176e1051a39Sopenharmony_ci EVP_PKEY_ASN1_METHOD *ameth; 177e1051a39Sopenharmony_ci e->pkey_asn1_meths(e, &ameth, NULL, nid); 178e1051a39Sopenharmony_ci if (ameth != NULL 179e1051a39Sopenharmony_ci && ((int)strlen(ameth->pem_str) == lk->len) 180e1051a39Sopenharmony_ci && OPENSSL_strncasecmp(ameth->pem_str, lk->str, lk->len) == 0) { 181e1051a39Sopenharmony_ci lk->e = e; 182e1051a39Sopenharmony_ci lk->ameth = ameth; 183e1051a39Sopenharmony_ci return; 184e1051a39Sopenharmony_ci } 185e1051a39Sopenharmony_ci } 186e1051a39Sopenharmony_ci} 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD *ENGINE_pkey_asn1_find_str(ENGINE **pe, 189e1051a39Sopenharmony_ci const char *str, 190e1051a39Sopenharmony_ci int len) 191e1051a39Sopenharmony_ci{ 192e1051a39Sopenharmony_ci ENGINE_FIND_STR fstr; 193e1051a39Sopenharmony_ci fstr.e = NULL; 194e1051a39Sopenharmony_ci fstr.ameth = NULL; 195e1051a39Sopenharmony_ci fstr.str = str; 196e1051a39Sopenharmony_ci fstr.len = len; 197e1051a39Sopenharmony_ci 198e1051a39Sopenharmony_ci if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) { 199e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE); 200e1051a39Sopenharmony_ci return NULL; 201e1051a39Sopenharmony_ci } 202e1051a39Sopenharmony_ci 203e1051a39Sopenharmony_ci if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 204e1051a39Sopenharmony_ci return NULL; 205e1051a39Sopenharmony_ci engine_table_doall(pkey_asn1_meth_table, look_str_cb, &fstr); 206e1051a39Sopenharmony_ci /* If found obtain a structural reference to engine */ 207e1051a39Sopenharmony_ci if (fstr.e) { 208e1051a39Sopenharmony_ci fstr.e->struct_ref++; 209e1051a39Sopenharmony_ci ENGINE_REF_PRINT(fstr.e, 0, 1); 210e1051a39Sopenharmony_ci } 211e1051a39Sopenharmony_ci *pe = fstr.e; 212e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(global_engine_lock); 213e1051a39Sopenharmony_ci return fstr.ameth; 214e1051a39Sopenharmony_ci} 215