Home | History | Annotate | Line # | Download | only in crypto
      1 /*
      2  * Copyright 2019-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 "internal/namemap.h"
     11 #include "internal/tsan_assist.h"
     12 #include "internal/hashtable.h"
     13 #include "internal/sizes.h"
     14 #include "crypto/context.h"
     15 
     16 #define NAMEMAP_HT_BUCKETS 512
     17 
     18 HT_START_KEY_DEFN(namenum_key)
     19 HT_DEF_KEY_FIELD_CHAR_ARRAY(name, 64)
     20 HT_END_KEY_DEFN(NAMENUM_KEY)
     21 
     22 /*-
     23  * The namemap itself
     24  * ==================
     25  */
     26 
     27 typedef STACK_OF(OPENSSL_STRING) NAMES;
     28 
     29 DEFINE_STACK_OF(NAMES)
     30 
     31 struct ossl_namemap_st {
     32     /* Flags */
     33     unsigned int stored : 1; /* If 1, it's stored in a library context */
     34 
     35     HT *namenum_ht; /* Name->number mapping */
     36 
     37     CRYPTO_RWLOCK *lock;
     38     STACK_OF(NAMES) *numnames;
     39 
     40     TSAN_QUALIFIER int max_number; /* Current max number */
     41 };
     42 
     43 static void name_string_free(char *name)
     44 {
     45     OPENSSL_free(name);
     46 }
     47 
     48 static void names_free(NAMES *n)
     49 {
     50     sk_OPENSSL_STRING_pop_free(n, name_string_free);
     51 }
     52 
     53 /* OSSL_LIB_CTX_METHOD functions for a namemap stored in a library context */
     54 
     55 void *ossl_stored_namemap_new(OSSL_LIB_CTX *libctx)
     56 {
     57     OSSL_NAMEMAP *namemap = ossl_namemap_new(libctx);
     58 
     59     if (namemap != NULL)
     60         namemap->stored = 1;
     61 
     62     return namemap;
     63 }
     64 
     65 void ossl_stored_namemap_free(void *vnamemap)
     66 {
     67     OSSL_NAMEMAP *namemap = vnamemap;
     68 
     69     if (namemap != NULL) {
     70         /* Pretend it isn't stored, or ossl_namemap_free() will do nothing */
     71         namemap->stored = 0;
     72         ossl_namemap_free(namemap);
     73     }
     74 }
     75 
     76 /*-
     77  * API functions
     78  * =============
     79  */
     80 
     81 int ossl_namemap_empty(OSSL_NAMEMAP *namemap)
     82 {
     83 #ifdef TSAN_REQUIRES_LOCKING
     84     /* No TSAN support */
     85     int rv;
     86 
     87     if (namemap == NULL)
     88         return 1;
     89 
     90     if (!CRYPTO_THREAD_read_lock(namemap->lock))
     91         return -1;
     92     rv = namemap->max_number == 0;
     93     CRYPTO_THREAD_unlock(namemap->lock);
     94     return rv;
     95 #else
     96     /* Have TSAN support */
     97     return namemap == NULL || tsan_load(&namemap->max_number) == 0;
     98 #endif
     99 }
    100 
    101 /*
    102  * Call the callback for all names in the namemap with the given number.
    103  * A return value 1 means that the callback was called for all names. A
    104  * return value of 0 means that the callback was not called for any names.
    105  */
    106 int ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number,
    107     void (*fn)(const char *name, void *data),
    108     void *data)
    109 {
    110     int i;
    111     NAMES *names;
    112 
    113     if (namemap == NULL || number <= 0)
    114         return 0;
    115 
    116     /*
    117      * We duplicate the NAMES stack under a read lock. Subsequently we call
    118      * the user function, so that we're not holding the read lock when in user
    119      * code. This could lead to deadlocks.
    120      */
    121     if (!CRYPTO_THREAD_read_lock(namemap->lock))
    122         return 0;
    123 
    124     names = sk_NAMES_value(namemap->numnames, number - 1);
    125     if (names != NULL)
    126         names = sk_OPENSSL_STRING_dup(names);
    127 
    128     CRYPTO_THREAD_unlock(namemap->lock);
    129 
    130     if (names == NULL)
    131         return 0;
    132 
    133     for (i = 0; i < sk_OPENSSL_STRING_num(names); i++)
    134         fn(sk_OPENSSL_STRING_value(names, i), data);
    135 
    136     sk_OPENSSL_STRING_free(names);
    137     return i > 0;
    138 }
    139 
    140 int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
    141 {
    142     int number = 0;
    143     HT_VALUE *val;
    144     NAMENUM_KEY key;
    145 
    146 #ifndef FIPS_MODULE
    147     if (namemap == NULL)
    148         namemap = ossl_namemap_stored(NULL);
    149 #endif
    150 
    151     if (namemap == NULL)
    152         return 0;
    153 
    154     HT_INIT_KEY(&key);
    155     HT_SET_KEY_STRING_CASE(&key, name, name);
    156 
    157     val = ossl_ht_get(namemap->namenum_ht, TO_HT_KEY(&key));
    158 
    159     if (val != NULL)
    160         /* We store a (small) int directly instead of a pointer to it. */
    161         number = (int)(intptr_t)val->value;
    162 
    163     return number;
    164 }
    165 
    166 int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap,
    167     const char *name, size_t name_len)
    168 {
    169     int number = 0;
    170     HT_VALUE *val;
    171     NAMENUM_KEY key;
    172 
    173 #ifndef FIPS_MODULE
    174     if (namemap == NULL)
    175         namemap = ossl_namemap_stored(NULL);
    176 #endif
    177 
    178     if (namemap == NULL)
    179         return 0;
    180 
    181     HT_INIT_KEY(&key);
    182     HT_SET_KEY_STRING_CASE_N(&key, name, name, name_len);
    183 
    184     val = ossl_ht_get(namemap->namenum_ht, TO_HT_KEY(&key));
    185 
    186     if (val != NULL)
    187         /* We store a (small) int directly instead of a pointer to it. */
    188         number = (int)(intptr_t)val->value;
    189 
    190     return number;
    191 }
    192 
    193 const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number,
    194     size_t idx)
    195 {
    196     NAMES *names;
    197     const char *ret = NULL;
    198 
    199     if (namemap == NULL || number <= 0)
    200         return NULL;
    201 
    202     if (!CRYPTO_THREAD_read_lock(namemap->lock))
    203         return NULL;
    204 
    205     names = sk_NAMES_value(namemap->numnames, number - 1);
    206     if (names != NULL)
    207         ret = sk_OPENSSL_STRING_value(names, idx);
    208 
    209     CRYPTO_THREAD_unlock(namemap->lock);
    210 
    211     return ret;
    212 }
    213 
    214 /* This function is not thread safe, the namemap must be locked */
    215 static int numname_insert(OSSL_NAMEMAP *namemap, int number,
    216     const char *name)
    217 {
    218     NAMES *names;
    219     char *tmpname;
    220 
    221     if (number > 0) {
    222         names = sk_NAMES_value(namemap->numnames, number - 1);
    223         if (!ossl_assert(names != NULL)) {
    224             /* cannot happen */
    225             return 0;
    226         }
    227     } else {
    228         /* a completely new entry */
    229         names = sk_OPENSSL_STRING_new_null();
    230         if (names == NULL)
    231             return 0;
    232     }
    233 
    234     if ((tmpname = OPENSSL_strdup(name)) == NULL)
    235         goto err;
    236 
    237     if (!sk_OPENSSL_STRING_push(names, tmpname))
    238         goto err;
    239     tmpname = NULL;
    240 
    241     if (number <= 0) {
    242         if (!sk_NAMES_push(namemap->numnames, names))
    243             goto err;
    244         number = sk_NAMES_num(namemap->numnames);
    245     }
    246     return number;
    247 
    248 err:
    249     if (number <= 0)
    250         sk_OPENSSL_STRING_pop_free(names, name_string_free);
    251     OPENSSL_free(tmpname);
    252     return 0;
    253 }
    254 
    255 /* This function is not thread safe, the namemap must be locked */
    256 static int namemap_add_name(OSSL_NAMEMAP *namemap, int number,
    257     const char *name)
    258 {
    259     int ret;
    260     HT_VALUE val = { 0 };
    261     NAMENUM_KEY key;
    262 
    263     /* If it already exists, we don't add it */
    264     if ((ret = ossl_namemap_name2num(namemap, name)) != 0)
    265         return ret;
    266 
    267     if ((number = numname_insert(namemap, number, name)) == 0)
    268         return 0;
    269 
    270     /* Using tsan_store alone here is safe since we're under lock */
    271     tsan_store(&namemap->max_number, number);
    272 
    273     HT_INIT_KEY(&key);
    274     HT_SET_KEY_STRING_CASE(&key, name, name);
    275     val.value = (void *)(intptr_t)number;
    276     ret = ossl_ht_insert(namemap->namenum_ht, TO_HT_KEY(&key), &val, NULL);
    277     if (!ossl_assert(ret != 0)) /* cannot happen as we are under write lock */
    278         return 0;
    279     if (ret < 1) {
    280         /* unable to insert due to too many collisions */
    281         ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_NAMES);
    282         return 0;
    283     }
    284     return number;
    285 }
    286 
    287 int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number,
    288     const char *name)
    289 {
    290     int tmp_number;
    291 
    292 #ifndef FIPS_MODULE
    293     if (namemap == NULL)
    294         namemap = ossl_namemap_stored(NULL);
    295 #endif
    296 
    297     if (name == NULL || *name == 0 || namemap == NULL)
    298         return 0;
    299 
    300     if (!CRYPTO_THREAD_write_lock(namemap->lock))
    301         return 0;
    302     tmp_number = namemap_add_name(namemap, number, name);
    303     CRYPTO_THREAD_unlock(namemap->lock);
    304     return tmp_number;
    305 }
    306 
    307 int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number,
    308     const char *names, const char separator)
    309 {
    310     char *tmp, *p, *q, *endp;
    311 
    312     /* Check that we have a namemap */
    313     if (!ossl_assert(namemap != NULL)) {
    314         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
    315         return 0;
    316     }
    317 
    318     if ((tmp = OPENSSL_strdup(names)) == NULL)
    319         return 0;
    320 
    321     if (!CRYPTO_THREAD_write_lock(namemap->lock)) {
    322         OPENSSL_free(tmp);
    323         return 0;
    324     }
    325     /*
    326      * Check that no name is an empty string, and that all names have at
    327      * most one numeric identity together.
    328      */
    329     for (p = tmp; *p != '\0'; p = q) {
    330         int this_number;
    331         size_t l;
    332 
    333         if ((q = strchr(p, separator)) == NULL) {
    334             l = strlen(p); /* offset to \0 */
    335             q = p + l;
    336         } else {
    337             l = q - p; /* offset to the next separator */
    338             *q++ = '\0';
    339         }
    340 
    341         if (*p == '\0') {
    342             ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME);
    343             number = 0;
    344             goto end;
    345         }
    346 
    347         this_number = ossl_namemap_name2num(namemap, p);
    348 
    349         if (number == 0) {
    350             number = this_number;
    351         } else if (this_number != 0 && this_number != number) {
    352             ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES,
    353                 "\"%s\" has an existing different identity %d (from \"%s\")",
    354                 p, this_number, names);
    355             number = 0;
    356             goto end;
    357         }
    358     }
    359     endp = p;
    360 
    361     /* Now that we have checked, register all names */
    362     for (p = tmp; p < endp; p = q) {
    363         int this_number;
    364 
    365         q = p + strlen(p) + 1;
    366 
    367         this_number = namemap_add_name(namemap, number, p);
    368         if (number == 0) {
    369             number = this_number;
    370         } else if (this_number != number) {
    371             ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR,
    372                 "Got number %d when expecting %d",
    373                 this_number, number);
    374             number = 0;
    375             goto end;
    376         }
    377     }
    378 
    379 end:
    380     CRYPTO_THREAD_unlock(namemap->lock);
    381     OPENSSL_free(tmp);
    382     return number;
    383 }
    384 
    385 /*-
    386  * Pre-population
    387  * ==============
    388  */
    389 
    390 #ifndef FIPS_MODULE
    391 #include <openssl/evp.h>
    392 
    393 /* Creates an initial namemap with names found in the legacy method db */
    394 static void get_legacy_evp_names(int base_nid, int nid, const char *pem_name,
    395     void *arg)
    396 {
    397     int num = 0;
    398     ASN1_OBJECT *obj;
    399 
    400     if (base_nid != NID_undef) {
    401         num = ossl_namemap_add_name(arg, num, OBJ_nid2sn(base_nid));
    402         num = ossl_namemap_add_name(arg, num, OBJ_nid2ln(base_nid));
    403     }
    404 
    405     if (nid != NID_undef) {
    406         num = ossl_namemap_add_name(arg, num, OBJ_nid2sn(nid));
    407         num = ossl_namemap_add_name(arg, num, OBJ_nid2ln(nid));
    408         if ((obj = OBJ_nid2obj(nid)) != NULL) {
    409             char txtoid[OSSL_MAX_NAME_SIZE];
    410 
    411             if (OBJ_obj2txt(txtoid, sizeof(txtoid), obj, 1) > 0)
    412                 num = ossl_namemap_add_name(arg, num, txtoid);
    413         }
    414     }
    415     if (pem_name != NULL)
    416         num = ossl_namemap_add_name(arg, num, pem_name);
    417 }
    418 
    419 static void get_legacy_cipher_names(const OBJ_NAME *on, void *arg)
    420 {
    421     const EVP_CIPHER *cipher = (void *)OBJ_NAME_get(on->name, on->type);
    422 
    423     if (cipher != NULL)
    424         get_legacy_evp_names(NID_undef, EVP_CIPHER_get_type(cipher), NULL, arg);
    425 }
    426 
    427 static void get_legacy_md_names(const OBJ_NAME *on, void *arg)
    428 {
    429     const EVP_MD *md = (void *)OBJ_NAME_get(on->name, on->type);
    430 
    431     if (md != NULL)
    432         get_legacy_evp_names(0, EVP_MD_get_type(md), NULL, arg);
    433 }
    434 
    435 static void get_legacy_pkey_meth_names(const EVP_PKEY_ASN1_METHOD *ameth,
    436     void *arg)
    437 {
    438     int nid = 0, base_nid = 0, flags = 0;
    439     const char *pem_name = NULL;
    440 
    441     EVP_PKEY_asn1_get0_info(&nid, &base_nid, &flags, NULL, &pem_name, ameth);
    442     if (nid != NID_undef) {
    443         if ((flags & ASN1_PKEY_ALIAS) == 0) {
    444             switch (nid) {
    445             case EVP_PKEY_DHX:
    446                 /* We know that the name "DHX" is used too */
    447                 get_legacy_evp_names(0, nid, "DHX", arg);
    448                 /* FALLTHRU */
    449             default:
    450                 get_legacy_evp_names(0, nid, pem_name, arg);
    451             }
    452         } else {
    453             /*
    454              * Treat aliases carefully, some of them are undesirable, or
    455              * should not be treated as such for providers.
    456              */
    457 
    458             switch (nid) {
    459             case EVP_PKEY_SM2:
    460                 /*
    461                  * SM2 is a separate keytype with providers, not an alias for
    462                  * EC.
    463                  */
    464                 get_legacy_evp_names(0, nid, pem_name, arg);
    465                 break;
    466             default:
    467                 /* Use the short name of the base nid as the common reference */
    468                 get_legacy_evp_names(base_nid, nid, pem_name, arg);
    469             }
    470         }
    471     }
    472 }
    473 #endif
    474 
    475 /*-
    476  * Constructors / destructors
    477  * ==========================
    478  */
    479 
    480 OSSL_NAMEMAP *ossl_namemap_stored(OSSL_LIB_CTX *libctx)
    481 {
    482 #ifndef FIPS_MODULE
    483     int nms;
    484 #endif
    485     OSSL_NAMEMAP *namemap = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_NAMEMAP_INDEX);
    486 
    487     if (namemap == NULL)
    488         return NULL;
    489 
    490 #ifndef FIPS_MODULE
    491     nms = ossl_namemap_empty(namemap);
    492     if (nms < 0) {
    493         /*
    494          * Could not get lock to make the count, so maybe internal objects
    495          * weren't added. This seems safest.
    496          */
    497         return NULL;
    498     }
    499     if (nms == 1) {
    500         int i, end;
    501 
    502         /* Before pilfering, we make sure the legacy database is populated */
    503         OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
    504                 | OPENSSL_INIT_ADD_ALL_DIGESTS,
    505             NULL);
    506 
    507         OBJ_NAME_do_all(OBJ_NAME_TYPE_CIPHER_METH,
    508             get_legacy_cipher_names, namemap);
    509         OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH,
    510             get_legacy_md_names, namemap);
    511 
    512         /* We also pilfer data from the legacy EVP_PKEY_ASN1_METHODs */
    513         for (i = 0, end = EVP_PKEY_asn1_get_count(); i < end; i++)
    514             get_legacy_pkey_meth_names(EVP_PKEY_asn1_get0(i), namemap);
    515     }
    516 #endif
    517 
    518     return namemap;
    519 }
    520 
    521 OSSL_NAMEMAP *ossl_namemap_new(OSSL_LIB_CTX *libctx)
    522 {
    523     OSSL_NAMEMAP *namemap;
    524     HT_CONFIG htconf = { NULL, NULL, NULL, NAMEMAP_HT_BUCKETS, 1, 1 };
    525 
    526     htconf.ctx = libctx;
    527 
    528     if ((namemap = OPENSSL_zalloc(sizeof(*namemap))) == NULL)
    529         goto err;
    530 
    531     if ((namemap->lock = CRYPTO_THREAD_lock_new()) == NULL)
    532         goto err;
    533 
    534     if ((namemap->namenum_ht = ossl_ht_new(&htconf)) == NULL)
    535         goto err;
    536 
    537     if ((namemap->numnames = sk_NAMES_new_null()) == NULL)
    538         goto err;
    539 
    540     return namemap;
    541 
    542 err:
    543     ossl_namemap_free(namemap);
    544     return NULL;
    545 }
    546 
    547 void ossl_namemap_free(OSSL_NAMEMAP *namemap)
    548 {
    549     if (namemap == NULL || namemap->stored)
    550         return;
    551 
    552     sk_NAMES_pop_free(namemap->numnames, names_free);
    553 
    554     ossl_ht_free(namemap->namenum_ht);
    555 
    556     CRYPTO_THREAD_lock_free(namemap->lock);
    557     OPENSSL_free(namemap);
    558 }
    559