X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=crypto%2Fcore_namemap.c;h=1dcf390fc2e770c6470ce2ebf38f54441f72b26a;hb=HEAD;hp=1cc76bf030be9a15cad1bb26152c1cd79714ef7c;hpb=cd3f8c1b11b0b9f4163bc8c62cbae38aec1b4030;p=thirdparty%2Fopenssl.git diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c index 1cc76bf030..1dcf390fc2 100644 --- a/crypto/core_namemap.c +++ b/crypto/core_namemap.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,11 +7,12 @@ * https://www.openssl.org/source/license.html */ -#include "e_os.h" /* strcasecmp */ #include "internal/namemap.h" #include -#include "crypto/lhash.h" /* openssl_lh_strcasehash */ +#include "crypto/lhash.h" /* ossl_lh_strcasehash */ #include "internal/tsan_assist.h" +#include "internal/sizes.h" +#include "crypto/context.h" /*- * The namenum entry @@ -22,7 +23,7 @@ typedef struct { int number; } NAMENUM_ENTRY; -DEFINE_LHASH_OF(NAMENUM_ENTRY); +DEFINE_LHASH_OF_EX(NAMENUM_ENTRY); /*- * The namemap itself @@ -36,23 +37,19 @@ struct ossl_namemap_st { CRYPTO_RWLOCK *lock; LHASH_OF(NAMENUM_ENTRY) *namenum; /* Name->number mapping */ -#ifdef tsan_ld_acq - TSAN_QUALIFIER int max_number; /* Current max number TSAN version */ -#else - int max_number; /* Current max number plain version */ -#endif + TSAN_QUALIFIER int max_number; /* Current max number */ }; /* LHASH callbacks */ static unsigned long namenum_hash(const NAMENUM_ENTRY *n) { - return openssl_lh_strcasehash(n->name); + return ossl_lh_strcasehash(n->name); } static int namenum_cmp(const NAMENUM_ENTRY *a, const NAMENUM_ENTRY *b) { - return strcasecmp(a->name, b->name); + return OPENSSL_strcasecmp(a->name, b->name); } static void namenum_free(NAMENUM_ENTRY *n) @@ -64,7 +61,7 @@ static void namenum_free(NAMENUM_ENTRY *n) /* OSSL_LIB_CTX_METHOD functions for a namemap stored in a library context */ -static void *stored_namemap_new(OSSL_LIB_CTX *libctx) +void *ossl_stored_namemap_new(OSSL_LIB_CTX *libctx) { OSSL_NAMEMAP *namemap = ossl_namemap_new(); @@ -74,7 +71,7 @@ static void *stored_namemap_new(OSSL_LIB_CTX *libctx) return namemap; } -static void stored_namemap_free(void *vnamemap) +void ossl_stored_namemap_free(void *vnamemap) { OSSL_NAMEMAP *namemap = vnamemap; @@ -85,11 +82,6 @@ static void stored_namemap_free(void *vnamemap) } } -static const OSSL_LIB_CTX_METHOD stored_namemap_method = { - stored_namemap_new, - stored_namemap_free, -}; - /*- * API functions * ============= @@ -97,10 +89,7 @@ static const OSSL_LIB_CTX_METHOD stored_namemap_method = { int ossl_namemap_empty(OSSL_NAMEMAP *namemap) { -#ifdef tsan_ld_acq - /* Have TSAN support */ - return namemap == NULL || tsan_load(&namemap->max_number) == 0; -#else +#ifdef TSAN_REQUIRES_LOCKING /* No TSAN support */ int rv; @@ -112,6 +101,9 @@ int ossl_namemap_empty(OSSL_NAMEMAP *namemap) rv = namemap->max_number == 0; CRYPTO_THREAD_unlock(namemap->lock); return rv; +#else + /* Have TSAN support */ + return namemap == NULL || tsan_load(&namemap->max_number) == 0; #endif } @@ -145,6 +137,9 @@ int ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number, cbdata.number = number; cbdata.found = 0; + if (namemap == NULL) + return 0; + /* * We collect all the names first under a read lock. Subsequently we call * the user function, so that we're not holding the read lock when in user @@ -174,22 +169,20 @@ int ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number, return 1; } -static int namemap_name2num_n(const OSSL_NAMEMAP *namemap, - const char *name, size_t name_len) +/* This function is not thread safe, the namemap must be locked */ +static int namemap_name2num(const OSSL_NAMEMAP *namemap, + const char *name) { NAMENUM_ENTRY *namenum_entry, namenum_tmpl; - if ((namenum_tmpl.name = OPENSSL_strndup(name, name_len)) == NULL) - return 0; + namenum_tmpl.name = (char *)name; namenum_tmpl.number = 0; namenum_entry = lh_NAMENUM_ENTRY_retrieve(namemap->namenum, &namenum_tmpl); - OPENSSL_free(namenum_tmpl.name); return namenum_entry != NULL ? namenum_entry->number : 0; } -int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, - const char *name, size_t name_len) +int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name) { int number; @@ -203,18 +196,24 @@ int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, if (!CRYPTO_THREAD_read_lock(namemap->lock)) return 0; - number = namemap_name2num_n(namemap, name, name_len); + number = namemap_name2num(namemap, name); CRYPTO_THREAD_unlock(namemap->lock); return number; } -int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name) +int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, + const char *name, size_t name_len) { - if (name == NULL) + char *tmp; + int ret; + + if (name == NULL || (tmp = OPENSSL_strndup(name, name_len)) == NULL) return 0; - return ossl_namemap_name2num_n(namemap, name, strlen(name)); + ret = ossl_namemap_name2num(namemap, tmp); + OPENSSL_free(tmp); + return ret; } struct num2name_data_st { @@ -244,20 +243,24 @@ const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number, return data.name; } -static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, - const char *name, size_t name_len) +/* This function is not thread safe, the namemap must be locked */ +static int namemap_add_name(OSSL_NAMEMAP *namemap, int number, + const char *name) { NAMENUM_ENTRY *namenum = NULL; int tmp_number; /* If it already exists, we don't add it */ - if ((tmp_number = namemap_name2num_n(namemap, name, name_len)) != 0) + if ((tmp_number = namemap_name2num(namemap, name)) != 0) return tmp_number; - if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL - || (namenum->name = OPENSSL_strndup(name, name_len)) == NULL) + if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL) + return 0; + + if ((namenum->name = OPENSSL_strdup(name)) == NULL) goto err; + /* The tsan_counter use here is safe since we're under lock */ namenum->number = number != 0 ? number : 1 + tsan_counter(&namemap->max_number); (void)lh_NAMENUM_ENTRY_insert(namemap->namenum, namenum); @@ -271,8 +274,8 @@ static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, return 0; } -int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, - const char *name, size_t name_len) +int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, + const char *name) { int tmp_number; @@ -281,29 +284,20 @@ int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, namemap = ossl_namemap_stored(NULL); #endif - if (name == NULL || name_len == 0 || namemap == NULL) + if (name == NULL || *name == 0 || namemap == NULL) return 0; if (!CRYPTO_THREAD_write_lock(namemap->lock)) return 0; - tmp_number = namemap_add_name_n(namemap, number, name, name_len); + tmp_number = namemap_add_name(namemap, number, name); CRYPTO_THREAD_unlock(namemap->lock); return tmp_number; } -int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name) -{ - if (name == NULL) - return 0; - - return ossl_namemap_add_name_n(namemap, number, name, strlen(name)); -} - int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, const char *names, const char separator) { - const char *p, *q; - size_t l; + char *tmp, *p, *q, *endp; /* Check that we have a namemap */ if (!ossl_assert(namemap != NULL)) { @@ -311,62 +305,71 @@ int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, return 0; } - if (!CRYPTO_THREAD_write_lock(namemap->lock)) + if ((tmp = OPENSSL_strdup(names)) == NULL) + return 0; + + if (!CRYPTO_THREAD_write_lock(namemap->lock)) { + OPENSSL_free(tmp); return 0; + } /* * Check that no name is an empty string, and that all names have at * most one numeric identity together. */ - for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) { + for (p = tmp; *p != '\0'; p = q) { int this_number; + size_t l; - if ((q = strchr(p, separator)) == NULL) + if ((q = strchr(p, separator)) == NULL) { l = strlen(p); /* offset to \0 */ - else + q = p + l; + } else { l = q - p; /* offset to the next separator */ + *q++ = '\0'; + } - this_number = namemap_name2num_n(namemap, p, l); - - if (*p == '\0' || *p == separator) { + if (*p == '\0') { ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME); - goto err; + number = 0; + goto end; } + + this_number = namemap_name2num(namemap, p); + if (number == 0) { number = this_number; } else if (this_number != 0 && this_number != number) { ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES, - "\"%.*s\" has an existing different identity %d (from \"%s\")", - l, p, this_number, names); - goto err; + "\"%s\" has an existing different identity %d (from \"%s\")", + p, this_number, names); + number = 0; + goto end; } } + endp = p; /* Now that we have checked, register all names */ - for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) { + for (p = tmp; p < endp; p = q) { int this_number; - if ((q = strchr(p, separator)) == NULL) - l = strlen(p); /* offset to \0 */ - else - l = q - p; /* offset to the next separator */ + q = p + strlen(p) + 1; - this_number = namemap_add_name_n(namemap, number, p, l); + this_number = namemap_add_name(namemap, number, p); if (number == 0) { number = this_number; } else if (this_number != number) { ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, "Got number %d when expecting %d", this_number, number); - goto err; + number = 0; + goto end; } } + end: CRYPTO_THREAD_unlock(namemap->lock); + OPENSSL_free(tmp); return number; - - err: - CRYPTO_THREAD_unlock(namemap->lock); - return 0; } /*- @@ -378,45 +381,84 @@ int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, #include /* Creates an initial namemap with names found in the legacy method db */ -static void get_legacy_evp_names(const char *main_name, const char *alias, +static void get_legacy_evp_names(int base_nid, int nid, const char *pem_name, void *arg) { - int main_id = ossl_namemap_add_name(arg, 0, main_name); + int num = 0; + ASN1_OBJECT *obj; - /* - * We could check that the returned value is the same as main_id, - * but since this is a void function, there's no sane way to report - * the error. The best we can do is trust ourselve to keep the legacy - * method database conflict free. - * - * This registers any alias with the same number as the main name. - * Should it be that the current |on| *has* the main name, this is - * simply a no-op. - */ - if (alias != NULL) { - (void)ossl_namemap_add_name(arg, main_id, alias); + if (base_nid != NID_undef) { + num = ossl_namemap_add_name(arg, num, OBJ_nid2sn(base_nid)); + num = ossl_namemap_add_name(arg, num, OBJ_nid2ln(base_nid)); } + + if (nid != NID_undef) { + num = ossl_namemap_add_name(arg, num, OBJ_nid2sn(nid)); + num = ossl_namemap_add_name(arg, num, OBJ_nid2ln(nid)); + if ((obj = OBJ_nid2obj(nid)) != NULL) { + char txtoid[OSSL_MAX_NAME_SIZE]; + + if (OBJ_obj2txt(txtoid, sizeof(txtoid), obj, 1) > 0) + num = ossl_namemap_add_name(arg, num, txtoid); + } + } + if (pem_name != NULL) + num = ossl_namemap_add_name(arg, num, pem_name); } static void get_legacy_cipher_names(const OBJ_NAME *on, void *arg) { const EVP_CIPHER *cipher = (void *)OBJ_NAME_get(on->name, on->type); - get_legacy_evp_names(EVP_CIPHER_name(cipher), on->name, arg); + if (cipher != NULL) + get_legacy_evp_names(NID_undef, EVP_CIPHER_get_type(cipher), NULL, arg); } static void get_legacy_md_names(const OBJ_NAME *on, void *arg) { const EVP_MD *md = (void *)OBJ_NAME_get(on->name, on->type); - /* We don't want the pkey_type names, so we need some extra care */ - int snid, lnid; - - snid = OBJ_sn2nid(on->name); - lnid = OBJ_ln2nid(on->name); - if (snid != EVP_MD_pkey_type(md) && lnid != EVP_MD_pkey_type(md)) - get_legacy_evp_names(EVP_MD_name(md), on->name, arg); - else - get_legacy_evp_names(EVP_MD_name(md), NULL, arg); + + if (md != NULL) + get_legacy_evp_names(0, EVP_MD_get_type(md), NULL, arg); +} + +static void get_legacy_pkey_meth_names(const EVP_PKEY_ASN1_METHOD *ameth, + void *arg) +{ + int nid = 0, base_nid = 0, flags = 0; + const char *pem_name = NULL; + + EVP_PKEY_asn1_get0_info(&nid, &base_nid, &flags, NULL, &pem_name, ameth); + if (nid != NID_undef) { + if ((flags & ASN1_PKEY_ALIAS) == 0) { + switch (nid) { + case EVP_PKEY_DHX: + /* We know that the name "DHX" is used too */ + get_legacy_evp_names(0, nid, "DHX", arg); + /* FALLTHRU */ + default: + get_legacy_evp_names(0, nid, pem_name, arg); + } + } else { + /* + * Treat aliases carefully, some of them are undesirable, or + * should not be treated as such for providers. + */ + + switch (nid) { + case EVP_PKEY_SM2: + /* + * SM2 is a separate keytype with providers, not an alias for + * EC. + */ + get_legacy_evp_names(0, nid, pem_name, arg); + break; + default: + /* Use the short name of the base nid as the common reference */ + get_legacy_evp_names(base_nid, nid, pem_name, arg); + } + } + } } #endif @@ -431,8 +473,7 @@ OSSL_NAMEMAP *ossl_namemap_stored(OSSL_LIB_CTX *libctx) int nms; #endif OSSL_NAMEMAP *namemap = - ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_NAMEMAP_INDEX, - &stored_namemap_method); + ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_NAMEMAP_INDEX); if (namemap == NULL) return NULL; @@ -447,6 +488,8 @@ OSSL_NAMEMAP *ossl_namemap_stored(OSSL_LIB_CTX *libctx) return NULL; } if (nms == 1) { + int i, end; + /* Before pilfering, we make sure the legacy database is populated */ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); @@ -455,6 +498,10 @@ OSSL_NAMEMAP *ossl_namemap_stored(OSSL_LIB_CTX *libctx) get_legacy_cipher_names, namemap); OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, get_legacy_md_names, namemap); + + /* We also pilfer data from the legacy EVP_PKEY_ASN1_METHODs */ + for (i = 0, end = EVP_PKEY_asn1_get_count(); i < end; i++) + get_legacy_pkey_meth_names(EVP_PKEY_asn1_get0(i), namemap); } #endif