From: Arran Cudbard-Bell Date: Mon, 29 Mar 2021 14:43:42 +0000 (+0100) Subject: Avoid allocating a new EVP_CIPHER_CTX for every operation X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab3f1cc54d940a7a60e875e1fb692344b3e541b3;p=thirdparty%2Ffreeradius-server.git Avoid allocating a new EVP_CIPHER_CTX for every operation --- diff --git a/src/lib/eap_aka_sim/crypto.c b/src/lib/eap_aka_sim/crypto.c index 438ec229009..f36dd3be385 100644 --- a/src/lib/eap_aka_sim/crypto.c +++ b/src/lib/eap_aka_sim/crypto.c @@ -42,10 +42,43 @@ RCSID("$Id$") #include #include #include +#include #include #include "base.h" #include "attrs.h" +#include "crypto_priv.h" + +/** Used for every non-persistent EVP_CIPHER operation in this library + * + * Avoids memory churn allocating and freeing the ctx for each operation. + */ +static _Thread_local EVP_CIPHER_CTX *evp_chipher_ctx; + +static void _evp_cipher_ctx_free_on_exit(void *arg) +{ + EVP_CIPHER_CTX_free(arg); +} + +/** Allocate and reset a resumable EVP_CIPHER_CTX for each thread + * + * No two crypto operations ever occur simultaneously in the same thread, + * so it's fine to use a single context that persists for all operations. + */ +EVP_CIPHER_CTX *aka_sim_crypto_cipher_ctx(void) +{ + EVP_CIPHER_CTX *ctx; + + if (unlikely(!evp_chipher_ctx)) { + MEM(ctx = EVP_CIPHER_CTX_new()); + fr_thread_local_set_destructor(evp_chipher_ctx, _evp_cipher_ctx_free_on_exit, ctx); + } else { + ctx = evp_chipher_ctx; + EVP_CIPHER_CTX_reset(ctx); + } + + return ctx; +} /** Free OpenSSL memory associated with our checkcode ctx * diff --git a/src/lib/eap_aka_sim/crypto_priv.h b/src/lib/eap_aka_sim/crypto_priv.h new file mode 100644 index 00000000000..488fba52ded --- /dev/null +++ b/src/lib/eap_aka_sim/crypto_priv.h @@ -0,0 +1,35 @@ +#pragma once +/* + * This program is is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file src/lib/eap_aka_sim/crypto_priv.h + * @brief EAP-SIM/EAP-AKA Private crypto functions + * + * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EVP_CIPHER_CTX *aka_sim_crypto_cipher_ctx(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/lib/eap_aka_sim/decode.c b/src/lib/eap_aka_sim/decode.c index 7d7e81e1366..f02d6b5e347 100644 --- a/src/lib/eap_aka_sim/decode.c +++ b/src/lib/eap_aka_sim/decode.c @@ -35,8 +35,9 @@ RCSID("$Id$") #include #include -#include "base.h" #include "attrs.h" +#include "base.h" +#include "crypto_priv.h" /* * EAP-SIM/AKA/AKA' PACKET FORMAT @@ -173,17 +174,16 @@ static ssize_t sim_value_decrypt(TALLOC_CTX *ctx, uint8_t **out, } } - evp_ctx = EVP_CIPHER_CTX_new(); - if (!evp_ctx) { - tls_strerror_printf("%s: Failed initialising EVP ctx", __FUNCTION__); - return -1; + if (unlikely(!packet_ctx->k_encr)) { + fr_strerror_printf("%s: No k_encr set, cannot decrypt attributes", __FUNCTION__); + return PAIR_ENCODE_FATAL_ERROR; } - if (!EVP_DecryptInit_ex(evp_ctx, evp_cipher, NULL, packet_ctx->keys->k_encr, packet_ctx->iv)) { + evp_ctx = aka_sim_crypto_cipher_ctx(); + if (!EVP_DecryptInit_ex(evp_ctx, evp_cipher, NULL, packet_ctx->k_encr, packet_ctx->iv)) { tls_strerror_printf("%s: Failed setting decryption parameters", __FUNCTION__); error: talloc_free(decr); - EVP_CIPHER_CTX_free(evp_ctx); return -1; } @@ -211,8 +211,6 @@ static ssize_t sim_value_decrypt(TALLOC_CTX *ctx, uint8_t **out, } decr_len += len; - EVP_CIPHER_CTX_free(evp_ctx); - /* * Note: packet_ctx implicitly validates the length of the padding * attribute (if present), so we don't have to do it later. diff --git a/src/lib/eap_aka_sim/encode.c b/src/lib/eap_aka_sim/encode.c index bdcccdb8717..ff2850cbc2c 100644 --- a/src/lib/eap_aka_sim/encode.c +++ b/src/lib/eap_aka_sim/encode.c @@ -34,6 +34,7 @@ RCSID("$Id$") #include #include "base.h" #include "attrs.h" +#include "crypto_priv.h" #define SIM_MAX_ATTRIBUTE_VALUE_LEN ((255 * 4) - 2) /* max length field value less Type + Length fields */ @@ -191,18 +192,17 @@ static ssize_t encode_encrypted_value(fr_dbuff_t *dbuff, FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), pad_len, "Done padding attribute"); } - evp_ctx = EVP_CIPHER_CTX_new(); - if (!evp_ctx) { - tls_strerror_printf("Failed allocating EVP context"); + if (unlikely(!packet_ctx->k_encr)) { + fr_strerror_printf("%s: No k_encr set, cannot encrypt attributes", __FUNCTION__); return PAIR_ENCODE_FATAL_ERROR; } + evp_ctx = aka_sim_crypto_cipher_ctx(); if (unlikely(EVP_EncryptInit_ex(evp_ctx, evp_cipher, NULL, - packet_ctx->keys->k_encr, packet_ctx->iv) != 1)) { + packet_ctx->k_encr, packet_ctx->iv) != 1)) { tls_strerror_printf("Failed initialising AES-128-ECB context"); error: talloc_free(encr); - EVP_CIPHER_CTX_free(evp_ctx); return PAIR_ENCODE_FATAL_ERROR; } @@ -251,10 +251,10 @@ static ssize_t encode_encrypted_value(fr_dbuff_t *dbuff, * Overwrite the plaintext with our encrypted blob */ fr_dbuff_set_to_start(&work_dbuff); - FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, encr, encr_len); + slen = fr_dbuff_in_memcpy(&work_dbuff, encr, encr_len); talloc_free(encr); - EVP_CIPHER_CTX_free(evp_ctx); + if (slen <= 0) return slen; return fr_dbuff_set(dbuff, &work_dbuff); } diff --git a/src/lib/eap_aka_sim/id.c b/src/lib/eap_aka_sim/id.c index ff426c1c8e2..bbeb3d5a94a 100644 --- a/src/lib/eap_aka_sim/id.c +++ b/src/lib/eap_aka_sim/id.c @@ -26,6 +26,7 @@ #include #include "base.h" #include "id.h" +#include "crypto_priv.h" #define us(x) (uint8_t) x @@ -413,16 +414,10 @@ int fr_aka_sim_id_3gpp_pseudonym_encrypt(char out[AKA_SIM_3GPP_PSEUDONYM_LEN + 1 /* * Now we have to encrypt the padded IMSI with AES-ECB */ - evp_ctx = EVP_CIPHER_CTX_new(); - if (!evp_ctx) { - tls_strerror_printf("Failed allocating EVP context"); - return -1; - } - + evp_ctx = aka_sim_crypto_cipher_ctx(); if (unlikely(EVP_EncryptInit_ex(evp_ctx, EVP_aes_128_ecb(), NULL, key, NULL) != 1)) { tls_strerror_printf("Failed initialising AES-128-ECB context"); error: - EVP_CIPHER_CTX_free(evp_ctx); return -1; } @@ -457,8 +452,6 @@ int fr_aka_sim_id_3gpp_pseudonym_encrypt(char out[AKA_SIM_3GPP_PSEUDONYM_LEN + 1 goto error; } - EVP_CIPHER_CTX_free(evp_ctx); - /* * Now encode the entire output as base64. */ @@ -564,16 +557,10 @@ int fr_aka_sim_id_3gpp_pseudonym_decrypt(char out[AKA_SIM_IMSI_MAX_LEN + 1], p += 4; /* 32bit input -> 24bit output */ } - evp_ctx = EVP_CIPHER_CTX_new(); - if (!evp_ctx) { - tls_strerror_printf("Failed allocating EVP context"); - return -1; - } - + evp_ctx = aka_sim_crypto_cipher_ctx(); if (unlikely(EVP_DecryptInit_ex(evp_ctx, EVP_aes_128_ecb(), NULL, key, NULL) != 1)) { tls_strerror_printf("Failed initialising AES-128-ECB context"); error: - EVP_CIPHER_CTX_free(evp_ctx); return -1; } @@ -620,9 +607,6 @@ int fr_aka_sim_id_3gpp_pseudonym_decrypt(char out[AKA_SIM_IMSI_MAX_LEN + 1], *out_p++ = ((compressed[i] & 0xf0) >> 4) + '0'; *out_p++ = (compressed[i] & 0x0f) + '0'; } - - EVP_CIPHER_CTX_free(evp_ctx); - out[AKA_SIM_IMSI_MAX_LEN] = '\0'; return 0;