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