Hi, On Fri, Dec 10, 2021 at 8:09 AM Arne Schwabe <a...@rfc2549.org> wrote: > > Make the external crypto consumer oblivious to the internal cipher > type that both mbed TLS and OpenSSL use. This change is mainly done > so the cipher type that is used can be stay a const type but instead > of an SSL library type, we now use a simple string to identify a > cipher. This has the disadvantages that we do a cipher lookup every > time a function is called that needs to query properties of a cipher. > But none of these queries are in a critical path. > > This patch also fixes the memory leaks introduced by the > EVP_fetch_cipher commit by always freeing the EVP_CIPHER. > > This also changes kt->cipher to be always defined with the name of > the cipher. This only affects the "none" cipher cipher which was > previously represented by kt->cipher to be NULL. > > Patch v2: rebase on master > > Patch v3: fix errors with mbed TLS without having md_kt to const char * patch > also applied, fix logic inversion in tls_crypt_tk > > Signed-off-by: Arne Schwabe <a...@rfc2549.org>
For the record, this fixes my substantial comments (essentially, cipher_defined() called with NULL ciphername from init.c). That said I had missed the missing ! in cipher_defined() in tls_crypt.c (now fixed) and test failures that Gert identified... Selva > --- > src/openvpn/auth_token.c | 2 +- > src/openvpn/crypto.c | 32 +++--- > src/openvpn/crypto.h | 4 +- > src/openvpn/crypto_backend.h | 77 ++++++------- > src/openvpn/crypto_mbedtls.c | 85 +++++++++----- > src/openvpn/crypto_mbedtls.h | 3 - > src/openvpn/crypto_openssl.c | 151 ++++++++++++++++++------- > src/openvpn/crypto_openssl.h | 13 ++- > src/openvpn/init.c | 14 ++- > src/openvpn/openssl_compat.h | 7 ++ > src/openvpn/openvpn.h | 2 - > src/openvpn/options.c | 9 +- > src/openvpn/ssl.c | 4 +- > src/openvpn/ssl_ncp.c | 24 ++-- > src/openvpn/tls_crypt.c | 4 +- > tests/unit_tests/openvpn/test_crypto.c | 4 +- > tests/unit_tests/openvpn/test_ncp.c | 6 +- > 17 files changed, 274 insertions(+), 167 deletions(-) > > diff --git a/src/openvpn/auth_token.c b/src/openvpn/auth_token.c > index 5d5cea7f6..5c947004e 100644 > --- a/src/openvpn/auth_token.c > +++ b/src/openvpn/auth_token.c > @@ -35,7 +35,7 @@ auth_token_kt(void) > { > struct key_type kt = { 0 }; > /* We do not encrypt our session tokens */ > - kt.cipher = NULL; > + kt.cipher = "none"; > kt.digest = md_kt_get("SHA256"); > > if (!kt.digest) > diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c > index a63a26195..0b47dec44 100644 > --- a/src/openvpn/crypto.c > +++ b/src/openvpn/crypto.c > @@ -680,7 +680,7 @@ crypto_adjust_frame_parameters(struct frame *frame, > crypto_overhead += packet_id_size(packet_id_long_form); > } > > - if (kt->cipher) > + if (cipher_defined(kt->cipher)) > { > crypto_overhead += cipher_kt_iv_size(kt->cipher); > > @@ -710,16 +710,16 @@ crypto_max_overhead(void) > } > > static void > -warn_insecure_key_type(const char *ciphername, const cipher_kt_t *cipher) > +warn_insecure_key_type(const char *ciphername) > { > - if (cipher_kt_insecure(cipher)) > + if (cipher_kt_insecure(ciphername)) > { > msg(M_WARN, "WARNING: INSECURE cipher (%s) with block size less than > 128" > " bit (%d bit). This allows attacks like SWEET32. Mitigate by " > "using a --cipher with a larger block size (e.g. AES-256-CBC). " > "Support for these insecure ciphers will be removed in " > "OpenVPN 2.6.", > - ciphername, cipher_kt_block_size(cipher)*8); > + ciphername, cipher_kt_block_size(ciphername)*8); > } > } > > @@ -736,10 +736,10 @@ init_key_type(struct key_type *kt, const char > *ciphername, > ASSERT(authname); > > CLEAR(*kt); > + kt->cipher = ciphername; > if (strcmp(ciphername, "none") != 0) > { > - kt->cipher = cipher_kt_get(ciphername); > - if (!kt->cipher) > + if (!cipher_valid(ciphername)) > { > msg(M_FATAL, "Cipher %s not supported", ciphername); > } > @@ -762,7 +762,7 @@ init_key_type(struct key_type *kt, const char *ciphername, > } > if (warn) > { > - warn_insecure_key_type(ciphername, kt->cipher); > + warn_insecure_key_type(ciphername); > } > } > else > @@ -809,7 +809,7 @@ init_key_ctx(struct key_ctx *ctx, const struct key *key, > { > struct gc_arena gc = gc_new(); > CLEAR(*ctx); > - if (kt->cipher) > + if (cipher_defined(kt->cipher)) > { > > ctx->cipher = cipher_ctx_new(); > @@ -824,7 +824,7 @@ init_key_ctx(struct key_ctx *ctx, const struct key *key, > dmsg(D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", > prefix, cipher_kt_block_size(kt->cipher), > cipher_kt_iv_size(kt->cipher)); > - warn_insecure_key_type(ciphername, kt->cipher); > + warn_insecure_key_type(ciphername); > } > if (kt->digest) > { > @@ -912,7 +912,7 @@ key_is_zero(struct key *key, const struct key_type *kt) > bool > check_key(struct key *key, const struct key_type *kt) > { > - if (kt->cipher) > + if (cipher_defined(kt->cipher)) > { > /* > * Check for zero key > @@ -1622,22 +1622,22 @@ get_random(void) > } > > void > -print_cipher(const cipher_kt_t *cipher) > +print_cipher(const char *ciphername) > { > printf("%s (%d bit key, ", > - cipher_kt_name(cipher), > - cipher_kt_key_size(cipher) * 8); > + cipher_kt_name(ciphername), > + cipher_kt_key_size(ciphername) * 8); > > - if (cipher_kt_block_size(cipher) == 1) > + if (cipher_kt_block_size(ciphername) == 1) > { > printf("stream cipher"); > } > else > { > - printf("%d bit block", cipher_kt_block_size(cipher) * 8); > + printf("%d bit block", cipher_kt_block_size(ciphername) * 8); > } > > - if (!cipher_kt_mode_cbc(cipher)) > + if (!cipher_kt_mode_cbc(ciphername)) > { > printf(", TLS client/server mode only"); > } > diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h > index 1e2ca3cb0..af94b0eb5 100644 > --- a/src/openvpn/crypto.h > +++ b/src/openvpn/crypto.h > @@ -138,7 +138,7 @@ struct sha256_digest { > */ > struct key_type > { > - const cipher_kt_t *cipher; /**< Cipher static parameters */ > + const char *cipher; /**< const name of the cipher */ > const md_kt_t *digest; /**< Message digest static parameters */ > }; > > @@ -473,7 +473,7 @@ void prng_bytes(uint8_t *output, int len); > long int get_random(void); > > /** Print a cipher list entry */ > -void print_cipher(const cipher_kt_t *cipher); > +void print_cipher(const char *cipher); > > void test_crypto(struct crypto_options *co, struct frame *f); > > diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h > index cc3e40400..e3da5c957 100644 > --- a/src/openvpn/crypto_backend.h > +++ b/src/openvpn/crypto_backend.h > @@ -188,114 +188,115 @@ void cipher_des_encrypt_ecb(const unsigned char > key[DES_KEY_LENGTH], > #define MAX_CIPHER_KEY_LENGTH 64 > > /** > - * Return cipher parameters, based on the given cipher name. The > - * contents of these parameters are library-specific, and can be used to > - * initialise encryption/decryption. > + * Returns if the cipher is valid, based on the given cipher name. > * > - * @param ciphername Name of the cipher to retrieve parameters for (e.g. > + * @param ciphername Name of the cipher to check for validity (e.g. > * \c AES-128-CBC). Will be translated to the library > name > * from the openvpn config name if needed. > * > - * @return A statically allocated structure containing > parameters > - * for the given cipher, or NULL if no matching > parameters > - * were found. > + * @return if the cipher is valid > */ > -const cipher_kt_t *cipher_kt_get(const char *ciphername); > +bool cipher_valid(const char *ciphername); > > /** > - * Retrieve a string describing the cipher (e.g. \c AES-128-CBC). > + * Checks if the cipher is defined and is not the null (none) cipher > + * > + * @param ciphername Name of the cipher to check if it is defined, may not > + * be NULL > + * @return The cipher is defined and not the null (none) cipher > + */ > +static inline bool cipher_defined(const char *ciphername) > +{ > + ASSERT(ciphername); > + return strcmp(ciphername, "none") != 0; > +} > + > +/** > + * Retrieve a normalised string describing the cipher (e.g. \c AES-128-CBC). > * The returned name is normalised to the OpenVPN config name in case the > * name differs from the name used by the crypto library. > * > - * Returns [null-cipher] in case the cipher_kt is NULL. > + * Returns [null-cipher] in case the ciphername is none. NULL if the cipher > + * is not valid. > * > - * @param cipher_kt Static cipher parameters > + * @param ciphername Name of the cipher > * > * @return a statically allocated string describing the cipher. > */ > -const char *cipher_kt_name(const cipher_kt_t *cipher_kt); > +const char *cipher_kt_name(const char *ciphername); > > /** > * Returns the size of keys used by the cipher, in bytes. If the cipher has a > * variable key size, return the default key size. > * > - * @param cipher_kt Static cipher parameters > + * @param ciphername Cipher name to lookup > * > * @return (Default) size of keys used by the cipher, in bytes. > */ > -int cipher_kt_key_size(const cipher_kt_t *cipher_kt); > +int cipher_kt_key_size(const char *ciphername); > > /** > * Returns the size of the IV used by the cipher, in bytes, or 0 if no IV is > * used. > * > - * @param cipher_kt Static cipher parameters > + * @param ciphername cipher name to lookup > * > * @return Size of the IV, in bytes, or 0 if the cipher does not > * use an IV. > */ > -int cipher_kt_iv_size(const cipher_kt_t *cipher_kt); > +int cipher_kt_iv_size(const char *ciphername); > > /** > * Returns the block size of the cipher, in bytes. > * > - * @param cipher_kt Static cipher parameters > + * @param ciphername cipher name > * > * @return Block size, in bytes. > */ > -int cipher_kt_block_size(const cipher_kt_t *cipher_kt); > +int cipher_kt_block_size(const char *ciphername); > > /** > * Returns the MAC tag size of the cipher, in bytes. > * > - * @param ctx Static cipher parameters. > + * @param ciphername Name of the cipher > * > * @return Tag size in bytes, or 0 if the tag size could not be > * determined. > */ > -int cipher_kt_tag_size(const cipher_kt_t *cipher_kt); > +int cipher_kt_tag_size(const char *ciphername); > > /** > * Returns true if we consider this cipher to be insecure. > */ > -bool cipher_kt_insecure(const cipher_kt_t *cipher); > +bool cipher_kt_insecure(const char *ciphername); > > -/** > - * Returns the mode that the cipher runs in. > - * > - * @param cipher_kt Static cipher parameters. May not be NULL. > - * > - * @return Cipher mode, either \c OPENVPN_MODE_CBC, \c > - * OPENVPN_MODE_OFB or \c OPENVPN_MODE_CFB > - */ > -int cipher_kt_mode(const cipher_kt_t *cipher_kt); > > /** > * Check if the supplied cipher is a supported CBC mode cipher. > * > - * @param cipher Static cipher parameters. > + * @param ciphername cipher name > * > * @return true iff the cipher is a CBC mode cipher. > */ > -bool cipher_kt_mode_cbc(const cipher_kt_t *cipher); > +bool cipher_kt_mode_cbc(const char *ciphername); > > /** > * Check if the supplied cipher is a supported OFB or CFB mode cipher. > * > - * @param cipher Static cipher parameters. > + * @param ciphername cipher name > * > * @return true iff the cipher is a OFB or CFB mode cipher. > */ > -bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher); > +bool cipher_kt_mode_ofb_cfb(const char *ciphername); > > /** > * Check if the supplied cipher is a supported AEAD mode cipher. > * > - * @param cipher Static cipher parameters. > + * @param ciphername name of the cipher > * > * @return true iff the cipher is a AEAD mode cipher. > */ > -bool cipher_kt_mode_aead(const cipher_kt_t *cipher); > +bool cipher_kt_mode_aead(const char *ciphername); > > > /** > @@ -323,12 +324,12 @@ void cipher_ctx_free(cipher_ctx_t *ctx); > * > * @param ctx Cipher context. May not be NULL > * @param key Buffer containing the key to use > - * @param kt Static cipher parameters to use > + * @param ciphername Ciphername of the cipher to use > * @param enc Whether to encrypt or decrypt (either > * \c MBEDTLS_OP_ENCRYPT or \c MBEDTLS_OP_DECRYPT). > */ > void cipher_ctx_init(cipher_ctx_t *ctx, const uint8_t *key, > - const cipher_kt_t *kt, int enc); > + const char *cipername, int enc); > > /** > * Returns the size of the IV used by the cipher, in bytes, or 0 if no IV is > diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c > index 8acf0e184..c3e18a1bc 100644 > --- a/src/openvpn/crypto_mbedtls.c > +++ b/src/openvpn/crypto_mbedtls.c > @@ -169,11 +169,11 @@ show_available_ciphers(void) > > while (*ciphers != 0) > { > - const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); > - if (info && !cipher_kt_insecure(info) > - && (cipher_kt_mode_aead(info) || cipher_kt_mode_cbc(info))) > + const mbedtls_cipher_info_t *info = > mbedtls_cipher_info_from_type(*ciphers); > + if (info && !cipher_kt_insecure(info->name) > + && (cipher_kt_mode_aead(info->name) || > cipher_kt_mode_cbc(info->name))) > { > - print_cipher(info); > + print_cipher(info->name); > } > ciphers++; > } > @@ -183,11 +183,11 @@ show_available_ciphers(void) > ciphers = mbedtls_cipher_list(); > while (*ciphers != 0) > { > - const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); > - if (info && cipher_kt_insecure(info) > - && (cipher_kt_mode_aead(info) || cipher_kt_mode_cbc(info))) > + const mbedtls_cipher_info_t *info = > mbedtls_cipher_info_from_type(*ciphers); > + if (info && cipher_kt_insecure(info->name) > + && (cipher_kt_mode_aead(info->name) || > cipher_kt_mode_cbc(info->name))) > { > - print_cipher(info); > + print_cipher(info->name); > } > ciphers++; > } > @@ -390,17 +390,22 @@ rand_bytes(uint8_t *output, int len) > * Generic cipher key type functions > * > */ > - > - > -const mbedtls_cipher_info_t * > -cipher_kt_get(const char *ciphername) > +static const mbedtls_cipher_info_t * > +cipher_get(const char* ciphername) > { > - const mbedtls_cipher_info_t *cipher = NULL; > - > ASSERT(ciphername); > > + const mbedtls_cipher_info_t *cipher = NULL; > + > ciphername = translate_cipher_name_from_openvpn(ciphername); > cipher = mbedtls_cipher_info_from_string(ciphername); > + return cipher; > +} > + > +bool > +cipher_valid(const char *ciphername) > +{ > + const mbedtls_cipher_info_t *cipher = cipher_get(ciphername); > > if (NULL == cipher) > { > @@ -416,12 +421,13 @@ cipher_kt_get(const char *ciphername) > return NULL; > } > > - return cipher; > + return cipher != NULL; > } > > const char * > -cipher_kt_name(const mbedtls_cipher_info_t *cipher_kt) > +cipher_kt_name(const char *ciphername) > { > + const mbedtls_cipher_info_t *cipher_kt = cipher_get(ciphername); > if (NULL == cipher_kt) > { > return "[null-cipher]"; > @@ -431,8 +437,10 @@ cipher_kt_name(const mbedtls_cipher_info_t *cipher_kt) > } > > int > -cipher_kt_key_size(const mbedtls_cipher_info_t *cipher_kt) > +cipher_kt_key_size(const char *ciphername) > { > + const mbedtls_cipher_info_t *cipher_kt = cipher_get(ciphername); > + > if (NULL == cipher_kt) > { > return 0; > @@ -442,8 +450,10 @@ cipher_kt_key_size(const mbedtls_cipher_info_t > *cipher_kt) > } > > int > -cipher_kt_iv_size(const mbedtls_cipher_info_t *cipher_kt) > +cipher_kt_iv_size(const char *ciphername) > { > + const mbedtls_cipher_info_t *cipher_kt = cipher_get(ciphername); > + > if (NULL == cipher_kt) > { > return 0; > @@ -452,8 +462,9 @@ cipher_kt_iv_size(const mbedtls_cipher_info_t *cipher_kt) > } > > int > -cipher_kt_block_size(const mbedtls_cipher_info_t *cipher_kt) > +cipher_kt_block_size(const char *ciphername) > { > + const mbedtls_cipher_info_t *cipher_kt = cipher_get(ciphername); > if (NULL == cipher_kt) > { > return 0; > @@ -462,9 +473,9 @@ cipher_kt_block_size(const mbedtls_cipher_info_t > *cipher_kt) > } > > int > -cipher_kt_tag_size(const mbedtls_cipher_info_t *cipher_kt) > +cipher_kt_tag_size(const char *ciphername) > { > - if (cipher_kt && cipher_kt_mode_aead(cipher_kt)) > + if (cipher_kt_mode_aead(ciphername)) > { > return OPENVPN_AEAD_TAG_LENGTH; > } > @@ -472,16 +483,22 @@ cipher_kt_tag_size(const mbedtls_cipher_info_t > *cipher_kt) > } > > bool > -cipher_kt_insecure(const mbedtls_cipher_info_t *cipher_kt) > +cipher_kt_insecure(const char *ciphername) > { > - return !(cipher_kt_block_size(cipher_kt) >= 128 / 8 > + const mbedtls_cipher_info_t *cipher_kt = cipher_get(ciphername); > + if (!cipher_kt) > + { > + return true; > + } > + > + return !(cipher_kt_block_size(ciphername) >= 128 / 8 > #ifdef MBEDTLS_CHACHAPOLY_C > || cipher_kt->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 > #endif > ); > } > > -int > +static int > cipher_kt_mode(const mbedtls_cipher_info_t *cipher_kt) > { > ASSERT(NULL != cipher_kt); > @@ -489,21 +506,24 @@ cipher_kt_mode(const mbedtls_cipher_info_t *cipher_kt) > } > > bool > -cipher_kt_mode_cbc(const cipher_kt_t *cipher) > +cipher_kt_mode_cbc(const char *ciphername) > { > + const mbedtls_cipher_info_t *cipher = cipher_get(ciphername); > return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC; > } > > bool > -cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) > +cipher_kt_mode_ofb_cfb(const char *ciphername) > { > + const mbedtls_cipher_info_t *cipher = cipher_get(ciphername); > return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB > || cipher_kt_mode(cipher) == OPENVPN_MODE_CFB); > } > > bool > -cipher_kt_mode_aead(const cipher_kt_t *cipher) > +cipher_kt_mode_aead(const char *ciphername) > { > + const mbedtls_cipher_info_t *cipher = cipher_get(ciphername); > return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_GCM > #ifdef MBEDTLS_CHACHAPOLY_C > || cipher_kt_mode(cipher) == MBEDTLS_MODE_CHACHAPOLY > @@ -535,13 +555,16 @@ cipher_ctx_free(mbedtls_cipher_context_t *ctx) > > void > cipher_ctx_init(mbedtls_cipher_context_t *ctx, const uint8_t *key, > - const mbedtls_cipher_info_t *kt, const mbedtls_operation_t > operation) > + const char *ciphername, const mbedtls_operation_t operation) > { > - ASSERT(NULL != kt && NULL != ctx); > - int key_len = cipher_kt_key_size(kt); > - > + ASSERT(NULL != ciphername && NULL != ctx); > CLEAR(*ctx); > > + const mbedtls_cipher_info_t *kt = cipher_get(ciphername); > + int key_len = kt->key_bitlen/8; > + > + ASSERT(kt); > + > if (!mbed_ok(mbedtls_cipher_setup(ctx, kt))) > { > msg(M_FATAL, "mbed TLS cipher context init #1"); > diff --git a/src/openvpn/crypto_mbedtls.h b/src/openvpn/crypto_mbedtls.h > index b2e9eceab..b9d03f2f9 100644 > --- a/src/openvpn/crypto_mbedtls.h > +++ b/src/openvpn/crypto_mbedtls.h > @@ -33,9 +33,6 @@ > #include <mbedtls/md.h> > #include <mbedtls/ctr_drbg.h> > > -/** Generic cipher key type %context. */ > -typedef mbedtls_cipher_info_t cipher_kt_t; > - > /** Generic message digest key type %context. */ > typedef mbedtls_md_info_t md_kt_t; > > diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c > index e28e2f43a..193729177 100644 > --- a/src/openvpn/crypto_openssl.c > +++ b/src/openvpn/crypto_openssl.c > @@ -311,7 +311,7 @@ cipher_name_cmp(const void *a, const void *b) > const EVP_CIPHER *const *cipher_a = a; > const EVP_CIPHER *const *cipher_b = b; > > - return strcmp(cipher_kt_name(*cipher_a), cipher_kt_name(*cipher_b)); > + return strcmp(EVP_CIPHER_get0_name(*cipher_a), > EVP_CIPHER_get0_name(*cipher_b)); > } > > struct collect_ciphers { > @@ -329,11 +329,13 @@ static void collect_ciphers(EVP_CIPHER *cipher, void > *list) > return; > } > > - if (cipher && (cipher_kt_mode_cbc(cipher) > + const char *ciphername = EVP_CIPHER_get0_name(cipher); > + > + if (cipher && ciphername && (cipher_kt_mode_cbc(ciphername) > #ifdef ENABLE_OFB_CFB_MODE > - || cipher_kt_mode_ofb_cfb(cipher) > + || cipher_kt_mode_ofb_cfb(ciphername) > #endif > - || cipher_kt_mode_aead(cipher) > + || cipher_kt_mode_aead(ciphername) > )) > { > cipher_list->list[cipher_list->num++] = cipher; > @@ -370,9 +372,9 @@ show_available_ciphers(void) > > for (size_t i = 0; i < cipher_list.num; i++) > { > - if (!cipher_kt_insecure(cipher_list.list[i])) > + if (!cipher_kt_insecure(EVP_CIPHER_get0_name(cipher_list.list[i]))) > { > - print_cipher(cipher_list.list[i]); > + print_cipher(EVP_CIPHER_get0_name(cipher_list.list[i])); > } > } > > @@ -380,9 +382,9 @@ show_available_ciphers(void) > "and are therefore deprecated. Do not use unless you have > to.\n\n"); > for (int i = 0; i < cipher_list.num; i++) > { > - if (cipher_kt_insecure(cipher_list.list[i])) > + if (cipher_kt_insecure(EVP_CIPHER_get0_name(cipher_list.list[i]))) > { > - print_cipher(cipher_list.list[i]); > + print_cipher(EVP_CIPHER_get0_name(cipher_list.list[i])); > } > } > printf("\n"); > @@ -556,11 +558,10 @@ rand_bytes(uint8_t *output, int len) > * > */ > > - > -const EVP_CIPHER * > -cipher_kt_get(const char *ciphername) > +static evp_cipher_type * > +cipher_get(const char *ciphername) > { > - const EVP_CIPHER *cipher = NULL; > + evp_cipher_type *cipher = NULL; > > ASSERT(ciphername); > > @@ -569,7 +570,6 @@ cipher_kt_get(const char *ciphername) > > if (NULL == cipher) > { > - crypto_msg(D_LOW, "Cipher algorithm '%s' not found", ciphername); > return NULL; > } > > @@ -596,32 +596,67 @@ cipher_kt_get(const char *ciphername) > return cipher; > } > > +bool cipher_valid(const char *ciphername) > +{ > + evp_cipher_type *cipher = cipher_get(ciphername); > + bool valid = (cipher != NULL); > + if (!valid) > + { > + crypto_msg(D_LOW, "Cipher algorithm '%s' not found", ciphername); > + } > + EVP_CIPHER_free(cipher); > + return valid; > +} > + > +bool cipher_var_key_size(const char *ciphername) > +{ > + evp_cipher_type *cipher = cipher_get(ciphername); > + bool ret = EVP_CIPHER_flags(cipher) & EVP_CIPH_VARIABLE_LENGTH; > + EVP_CIPHER_free(cipher); > + return ret; > +} > + > + > const char * > -cipher_kt_name(const EVP_CIPHER *cipher_kt) > +cipher_kt_name(const char *ciphername) > { > - if (NULL == cipher_kt) > + ASSERT(ciphername); > + if (strcmp("none", ciphername) == 0) > { > return "[null-cipher]"; > } > > + evp_cipher_type *cipher_kt = cipher_get(ciphername); > + if (!cipher_kt) > + { > + return NULL; > + } > + > const char *name = EVP_CIPHER_name(cipher_kt); > + EVP_CIPHER_free(cipher_kt); > return translate_cipher_name_to_openvpn(name); > } > > int > -cipher_kt_key_size(const EVP_CIPHER *cipher_kt) > +cipher_kt_key_size(const char *ciphername) > { > - return EVP_CIPHER_key_length(cipher_kt); > + evp_cipher_type *cipher = cipher_get(ciphername); > + int size = EVP_CIPHER_key_length(cipher); > + EVP_CIPHER_free(cipher); > + return size; > } > > int > -cipher_kt_iv_size(const EVP_CIPHER *cipher_kt) > +cipher_kt_iv_size(const char *ciphername) > { > - return EVP_CIPHER_iv_length(cipher_kt); > + evp_cipher_type *cipher = cipher_get(ciphername); > + int ivsize = EVP_CIPHER_iv_length(cipher); > + EVP_CIPHER_free(cipher); > + return ivsize; > } > > int > -cipher_kt_block_size(const EVP_CIPHER *cipher) > +cipher_kt_block_size(const char *ciphername) > { > /* > * OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work > @@ -632,7 +667,12 @@ cipher_kt_block_size(const EVP_CIPHER *cipher) > char *name = NULL; > char *mode_str = NULL; > const char *orig_name = NULL; > - const EVP_CIPHER *cbc_cipher = NULL; > + evp_cipher_type *cbc_cipher = NULL; > + evp_cipher_type *cipher = cipher_get(ciphername); > + if (!cipher) > + { > + return 0; > + } > > int block_size = EVP_CIPHER_block_size(cipher); > > @@ -651,21 +691,23 @@ cipher_kt_block_size(const EVP_CIPHER *cipher) > > strcpy(mode_str, "-CBC"); > > - cbc_cipher = > EVP_CIPHER_fetch(NULL,translate_cipher_name_from_openvpn(name), NULL); > + cbc_cipher = EVP_CIPHER_fetch(NULL, > translate_cipher_name_from_openvpn(name), NULL); > if (cbc_cipher) > { > block_size = EVP_CIPHER_block_size(cbc_cipher); > } > > cleanup: > + EVP_CIPHER_free(cbc_cipher); > + EVP_CIPHER_free(cipher); > free(name); > return block_size; > } > > int > -cipher_kt_tag_size(const EVP_CIPHER *cipher_kt) > +cipher_kt_tag_size(const char *ciphername) > { > - if (cipher_kt_mode_aead(cipher_kt)) > + if (cipher_kt_mode_aead(ciphername)) > { > return OPENVPN_AEAD_TAG_LENGTH; > } > @@ -676,13 +718,26 @@ cipher_kt_tag_size(const EVP_CIPHER *cipher_kt) > } > > bool > -cipher_kt_insecure(const EVP_CIPHER *cipher) > +cipher_kt_insecure(const char *ciphername) > { > - return !(cipher_kt_block_size(cipher) >= 128 / 8 > + > + if (cipher_kt_block_size(ciphername) >= 128 / 8) > + { > + return false; > + } > #ifdef NID_chacha20_poly1305 > - || EVP_CIPHER_nid(cipher) == NID_chacha20_poly1305 > + evp_cipher_type *cipher = cipher_get(ciphername); > + if (cipher) > + { > + bool ischachapoly = (EVP_CIPHER_nid(cipher) == > NID_chacha20_poly1305); > + EVP_CIPHER_free(cipher); > + if (ischachapoly) > + { > + return false; > + } > + } > #endif > - ); > + return true; > } > > int > @@ -693,44 +748,56 @@ cipher_kt_mode(const EVP_CIPHER *cipher_kt) > } > > bool > -cipher_kt_mode_cbc(const cipher_kt_t *cipher) > +cipher_kt_mode_cbc(const char *ciphername) > { > - return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC > + evp_cipher_type *cipher = cipher_get(ciphername); > + > + bool ret = cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_CBC > /* Exclude AEAD cipher modes, they require a different API */ > #ifdef EVP_CIPH_FLAG_CTS > && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_CTS) > #endif > - && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER); > + && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)); > + EVP_CIPHER_free(cipher); > + return ret; > } > > bool > -cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) > +cipher_kt_mode_ofb_cfb(const char *ciphername) > { > - return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB > + evp_cipher_type *cipher = cipher_get(ciphername); > + bool ofb_cfb = cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB > || cipher_kt_mode(cipher) == OPENVPN_MODE_CFB) > - /* Exclude AEAD cipher modes, they require a different API */ > - && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER); > + /* Exclude AEAD cipher modes, they require a different > API */ > + && !(EVP_CIPHER_flags(cipher) & > EVP_CIPH_FLAG_AEAD_CIPHER); > + EVP_CIPHER_free(cipher); > + return ofb_cfb; > } > > bool > -cipher_kt_mode_aead(const cipher_kt_t *cipher) > +cipher_kt_mode_aead(const char *ciphername) > { > + bool isaead = false; > + > + evp_cipher_type *cipher = cipher_get(ciphername); > if (cipher) > { > if (EVP_CIPHER_mode(cipher) == OPENVPN_MODE_GCM) > { > - return true; > + isaead = true; > } > > #ifdef NID_chacha20_poly1305 > if (EVP_CIPHER_nid(cipher) == NID_chacha20_poly1305) > { > - return true; > + isaead = true; > } > #endif > } > > - return false; > + EVP_CIPHER_free(cipher); > + > + return isaead; > } > > /* > @@ -755,9 +822,10 @@ cipher_ctx_free(EVP_CIPHER_CTX *ctx) > > void > cipher_ctx_init(EVP_CIPHER_CTX *ctx, const uint8_t *key, > - const EVP_CIPHER *kt, int enc) > + const char *ciphername, int enc) > { > - ASSERT(NULL != kt && NULL != ctx); > + ASSERT(NULL != ciphername && NULL != ctx); > + evp_cipher_type *kt = cipher_get(ciphername); > > EVP_CIPHER_CTX_reset(ctx); > if (!EVP_CipherInit(ctx, kt, NULL, NULL, enc)) > @@ -769,6 +837,7 @@ cipher_ctx_init(EVP_CIPHER_CTX *ctx, const uint8_t *key, > crypto_msg(M_FATAL, "EVP cipher init #2"); > } > > + EVP_CIPHER_free(kt); > /* make sure we used a big enough key */ > ASSERT(EVP_CIPHER_CTX_key_length(ctx) <= EVP_CIPHER_key_length(kt)); > } > diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h > index 6eb16a906..3371d07e7 100644 > --- a/src/openvpn/crypto_openssl.h > +++ b/src/openvpn/crypto_openssl.h > @@ -37,10 +37,6 @@ > #include <openssl/provider.h> > #endif > > - > -/** Generic cipher key type %context. */ > -typedef EVP_CIPHER cipher_kt_t; > - > /** Generic message digest key type %context. */ > typedef EVP_MD md_kt_t; > > @@ -66,6 +62,15 @@ typedef struct { > typedef OSSL_PROVIDER provider_t; > #endif > > +/* In OpenSSL 3.0 the method that returns EVP_CIPHER, the cipher needs to be > + * freed afterwards, thus needing a non-const type. In constrast OpenSSL > 1.1.1 > + * and lower returns a const type, needing a const type */ > +#if OPENSSL_VERSION_NUMBER < 0x30000000L > +typedef const EVP_CIPHER evp_cipher_type; > +#else > +typedef EVP_CIPHER evp_cipher_type; > +#endif > + > /** Maximum length of an IV */ > #define OPENVPN_MAX_IV_LENGTH EVP_MAX_IV_LENGTH > > diff --git a/src/openvpn/init.c b/src/openvpn/init.c > index 4fee7f49f..acec876c4 100644 > --- a/src/openvpn/init.c > +++ b/src/openvpn/init.c > @@ -2529,7 +2529,7 @@ frame_finalize_options(struct context *c, const struct > options *o) > * Set adjustment factor for buffer alignment when no > * cipher is used. > */ > - if (!CIPHER_ENABLED(c)) > + if (!cipher_defined(c->c1.ks.key_type.cipher)) > { > frame_align_to_extra_frame(&c->c2.frame); > frame_or_align_flags(&c->c2.frame, > @@ -2660,6 +2660,7 @@ do_init_tls_wrap_key(struct context *c) > CLEAR(c->c1.ks.tls_auth_key_type); > if (!streq(options->authname, "none")) > { > + c->c1.ks.tls_auth_key_type.cipher = "none"; > c->c1.ks.tls_auth_key_type.digest = md_kt_get(options->authname); > } > else > @@ -2762,16 +2763,19 @@ do_init_crypto_tls_c1(struct context *c) > * Note that BF-CBC will still be part of the OCC string to retain > * backwards compatibility with older clients. > */ > + const char* ciphername = options->ciphername; > if (!streq(options->ciphername, "BF-CBC") > || tls_item_in_cipher_list("BF-CBC", options->ncp_ciphers) > || options->enable_ncp_fallback) > { > - /* Do not warn if the if the cipher is used only in OCC */ > - bool warn = options->enable_ncp_fallback; > - init_key_type(&c->c1.ks.key_type, options->ciphername, > options->authname, > - true, warn); > + ciphername = "none"; > } > > + /* Do not warn if the cipher is used only in OCC */ > + bool warn = options->enable_ncp_fallback; > + init_key_type(&c->c1.ks.key_type, ciphername, options->authname, > + true, warn); > + > /* initialize tls-auth/crypt/crypt-v2 key */ > do_init_tls_wrap_key(c); > > diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h > index 54fd5d60f..dcc210c79 100644 > --- a/src/openvpn/openssl_compat.h > +++ b/src/openvpn/openssl_compat.h > @@ -757,6 +757,7 @@ int EVP_PKEY_get_group_name(EVP_PKEY *pkey, char *gname, > size_t gname_sz, > > #if OPENSSL_VERSION_NUMBER < 0x30000000L > #define EVP_MD_get0_name EVP_MD_name > +#define EVP_CIPHER_get0_name EVP_CIPHER_name > #define EVP_CIPHER_CTX_get_mode EVP_CIPHER_CTX_mode > > /* Mimics the functions but only when the default context without > @@ -776,6 +777,12 @@ EVP_MD_fetch(void *ctx, const char *algorithm, const > char *properties) > ASSERT(!properties); > return EVP_get_digestbyname(algorithm); > } > + > +static inline void > +EVP_CIPHER_free(const EVP_CIPHER *cipher) > +{ > + /* OpenSSL 1.1.1 and lower use only const EVP_CIPHER, nothing to free */ > +} > #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ > > #endif /* OPENSSL_COMPAT_H_ */ > diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h > index 84477837e..aff63aef1 100644 > --- a/src/openvpn/openvpn.h > +++ b/src/openvpn/openvpn.h > @@ -529,8 +529,6 @@ struct context > |(c->options.tls_auth_file ? > md_kt_size(c->c1.ks.key_type.digest) : 0), \ > gc) > > -#define CIPHER_ENABLED(c) (c->c1.ks.key_type.cipher != NULL) > - > /* this represents "disabled peer-id" */ > #define MAX_PEER_ID 0xFFFFFF > > diff --git a/src/openvpn/options.c b/src/openvpn/options.c > index ac13412a4..b840b767b 100644 > --- a/src/openvpn/options.c > +++ b/src/openvpn/options.c > @@ -3084,7 +3084,7 @@ options_postprocess_setdefault_ncpciphers(struct > options *o) > /* custom --data-ciphers set, keep list */ > return; > } > - else if (cipher_kt_get("CHACHA20-POLY1305")) > + else if (cipher_valid("CHACHA20-POLY1305")) > { > o->ncp_ciphers = "AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305"; > } > @@ -3979,7 +3979,7 @@ options_string(const struct options *o, > /* Skip resolving BF-CBC to allow SSL libraries without BF-CBC > * to work here in the default configuration */ > const char *ciphername = o->ciphername; > - int keysize; > + int keysize = 0; > > if (strcmp(o->ciphername, "BF-CBC") == 0) > { > @@ -3990,7 +3990,10 @@ options_string(const struct options *o, > { > init_key_type(&kt, o->ciphername, o->authname, true, false); > ciphername = cipher_kt_name(kt.cipher); > - keysize = cipher_kt_key_size(kt.cipher) * 8; > + if (cipher_defined(o->ciphername)) > + { > + keysize = cipher_kt_key_size(kt.cipher) * 8; > + } > } > /* Only announce the cipher to our peer if we are willing to > * support it */ > diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c > index 81b2a1afd..05096ee0a 100644 > --- a/src/openvpn/ssl.c > +++ b/src/openvpn/ssl.c > @@ -281,9 +281,9 @@ tls_get_cipher_name_pair(const char *cipher_name, size_t > len) > * May *not* be NULL. > */ > static void > -tls_limit_reneg_bytes(const cipher_kt_t *cipher, int *reneg_bytes) > +tls_limit_reneg_bytes(const char *ciphername, int *reneg_bytes) > { > - if (cipher && cipher_kt_insecure(cipher)) > + if (cipher_kt_insecure(ciphername)) > { > if (*reneg_bytes == -1) /* Not user-specified */ > { > diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c > index 4b95406e9..ce82e8951 100644 > --- a/src/openvpn/ssl_ncp.c > +++ b/src/openvpn/ssl_ncp.c > @@ -105,8 +105,7 @@ mutate_ncp_cipher_list(const char *list, struct gc_arena > *gc) > while (token) > { > /* > - * Going through a roundtrip by using cipher_kt_get/cipher_kt_name > - * (and translate_cipher_name_from_openvpn/ > + * Going cipher_kt_name (and translate_cipher_name_from_openvpn/ > * translate_cipher_name_to_openvpn) also normalises the cipher name, > * e.g. replacing AeS-128-gCm with AES-128-GCM > * > @@ -114,15 +113,16 @@ mutate_ncp_cipher_list(const char *list, struct > gc_arena *gc) > * OpenVPN will only warn if they are not found (and remove them from > * the list) > */ > - > bool optional = false; > if (token[0] == '?') > { > token++; > optional = true; > } > - const cipher_kt_t *ktc = cipher_kt_get(token); > - if (strcmp(token, "none") == 0) > + > + const bool nonecipher = (strcmp(token, "none") == 0); > + > + if (nonecipher) > { > msg(M_WARN, "WARNING: cipher 'none' specified for > --data-ciphers. " > "This allows negotiation of NO encryption and " > @@ -130,7 +130,7 @@ mutate_ncp_cipher_list(const char *list, struct gc_arena > *gc) > "over the network! " > "PLEASE DO RECONSIDER THIS SETTING!"); > } > - if (!ktc && strcmp(token, "none") != 0) > + if (!nonecipher && !cipher_valid(token)) > { > const char* optstr = optional ? "optional ": ""; > msg(M_WARN, "Unsupported %scipher in --data-ciphers: %s", > optstr, token); > @@ -138,8 +138,8 @@ mutate_ncp_cipher_list(const char *list, struct gc_arena > *gc) > } > else > { > - const char *ovpn_cipher_name = cipher_kt_name(ktc); > - if (ktc == NULL) > + const char *ovpn_cipher_name = cipher_kt_name(token); > + if (nonecipher) > { > /* NULL resolves to [null-cipher] but we need none for > * data-ciphers */ > @@ -466,17 +466,17 @@ p2p_mode_ncp(struct tls_multi *multi, struct > tls_session *session) > if (!common_cipher) > { > struct buffer out = alloc_buf_gc(128, &gc); > - const cipher_kt_t *cipher = session->opt->key_type.cipher; > - > /* at this point we do not really know if our fallback is > * not enabled or if we use 'none' cipher as fallback, so > * keep this ambiguity here and print fallback-cipher: none > */ > > const char *fallback_name = "none"; > - if (cipher) > + const char *ciphername = session->opt->key_type.cipher; > + > + if (cipher_defined(ciphername)) > { > - fallback_name = cipher_kt_name(cipher); > + fallback_name = cipher_kt_name(ciphername); > } > > buf_printf(&out, "(not negotiated, fallback-cipher: %s)", > fallback_name); > diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c > index 80ed9684e..841261329 100644 > --- a/src/openvpn/tls_crypt.c > +++ b/src/openvpn/tls_crypt.c > @@ -51,10 +51,10 @@ static struct key_type > tls_crypt_kt(void) > { > struct key_type kt; > - kt.cipher = cipher_kt_get("AES-256-CTR"); > + kt.cipher = "AES-256-CTR"; > kt.digest = md_kt_get("SHA256"); > > - if (!kt.cipher) > + if (!cipher_valid(kt.cipher)) > { > msg(M_WARN, "ERROR: --tls-crypt requires AES-256-CTR support."); > return (struct key_type) { 0 }; > diff --git a/tests/unit_tests/openvpn/test_crypto.c > b/tests/unit_tests/openvpn/test_crypto.c > index 42632c72b..344817eef 100644 > --- a/tests/unit_tests/openvpn/test_crypto.c > +++ b/tests/unit_tests/openvpn/test_crypto.c > @@ -72,7 +72,7 @@ crypto_pem_encode_decode_loopback(void **state) > static void > test_translate_cipher(const char *ciphername, const char *openvpn_name) > { > - const cipher_kt_t *cipher = cipher_kt_get(ciphername); > + bool cipher = cipher_valid(ciphername); > > /* Empty cipher is fine */ > if (!cipher) > @@ -80,7 +80,7 @@ test_translate_cipher(const char *ciphername, const char > *openvpn_name) > return; > } > > - const char *kt_name = cipher_kt_name(cipher); > + const char *kt_name = cipher_kt_name(ciphername); > > assert_string_equal(kt_name, openvpn_name); > } > diff --git a/tests/unit_tests/openvpn/test_ncp.c > b/tests/unit_tests/openvpn/test_ncp.c > index f4c28ffdf..f3d7ed20a 100644 > --- a/tests/unit_tests/openvpn/test_ncp.c > +++ b/tests/unit_tests/openvpn/test_ncp.c > @@ -59,8 +59,8 @@ static void > test_check_ncp_ciphers_list(void **state) > { > struct gc_arena gc = gc_new(); > - bool have_chacha = cipher_kt_get("CHACHA20-POLY1305"); > - bool have_blowfish = cipher_kt_get("BF-CBC"); > + bool have_chacha = cipher_valid("CHACHA20-POLY1305"); > + bool have_blowfish = cipher_valid("BF-CBC"); > > assert_string_equal(mutate_ncp_cipher_list("none", &gc), "none"); > assert_string_equal(mutate_ncp_cipher_list("AES-256-GCM:none", &gc), > @@ -100,7 +100,7 @@ test_check_ncp_ciphers_list(void **state) > > /* For testing that with OpenSSL 1.1.0+ that also accepts ciphers in > * a different spelling the normalised cipher output is the same */ > - bool have_chacha_mixed_case = cipher_kt_get("ChaCha20-Poly1305"); > + bool have_chacha_mixed_case = cipher_valid("ChaCha20-Poly1305"); > if (have_chacha_mixed_case) > { > > assert_string_equal(mutate_ncp_cipher_list("AES-128-CBC:ChaCha20-Poly1305", > &gc), > -- > 2.33.0 > > > > _______________________________________________ > Openvpn-devel mailing list > Openvpn-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/openvpn-devel _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel