From b633249f58832e6aeefa606d6d5aec76abfe6d89 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 30 Sep 2026 21:48:57 -0700 Subject: scsi: target: iscsi: Use crypto library API Make iscsi_target_auth.c call into the crypto library directly instead of going through crypto_shash. This is simpler and much more efficient, as it avoids overhead of the crypto_shash layer. The hash computation itself also no longer has error codes that need to be checked. For simplicity, still do a memory allocation per operation to buffer the data (which is typically less than 50 bytes here) so that the one-shot digest functions can be used. It's still much more efficient than doing the super slow crypto_alloc_shash(). Signed-off-by: Eric Biggers Reviewed-by: David Disseldorp Link: https://patch.msgid.link/20261001044857.169487-1-ebiggers@kernel.org Signed-off-by: Martin K. Petersen (Oracle) --- drivers/target/iscsi/Kconfig | 7 +- drivers/target/iscsi/iscsi_target_auth.c | 192 ++++++++++++------------------- drivers/target/iscsi/iscsi_target_auth.h | 8 +- 3 files changed, 78 insertions(+), 129 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/iscsi/Kconfig b/drivers/target/iscsi/Kconfig index 70d76f3dd693..44bbf1f32859 100644 --- a/drivers/target/iscsi/Kconfig +++ b/drivers/target/iscsi/Kconfig @@ -3,8 +3,11 @@ config ISCSI_TARGET tristate "SCSI Target Mode Stack" depends on INET select CRC32 - select CRYPTO - select CRYPTO_HASH + select CRYPTO_LIB_MD5 + select CRYPTO_LIB_SHA1 + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_SHA3 + select CRYPTO_LIB_UTILS help Say M to enable the SCSI target mode stack. A SCSI target mode stack is software that makes local storage available over a storage network diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index f3c0cdd31830..945dd6409723 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -8,31 +8,73 @@ * ******************************************************************************/ -#include +#include +#include +#include +#include #include +#include #include #include -#include #include #include -#include +#include #include #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" -static char *chap_get_digest_name(const int digest_type) +static const struct { + const char *digest_name; /* Used only in log messages */ + unsigned int digest_size; +} chap_digest_algs[] = { + [CHAP_DIGEST_MD5] = { + .digest_name = "md5", + .digest_size = MD5_DIGEST_SIZE, + }, + [CHAP_DIGEST_SHA1] = { + .digest_name = "sha1", + .digest_size = SHA1_DIGEST_SIZE, + }, + [CHAP_DIGEST_SHA256] = { + .digest_name = "sha256", + .digest_size = SHA256_DIGEST_SIZE, + }, + [CHAP_DIGEST_SHA3_256] = { + .digest_name = "sha3-256", + .digest_size = SHA3_256_DIGEST_SIZE, + }, +}; + +static int chap_digest(int digest_type, u8 chap_id, const char *password, + const u8 *challenge, size_t challenge_len, + u8 *out_digest) { + size_t pass_len = strlen(password); + size_t data_len = 1 + pass_len + challenge_len; + u8 *data __free(kfree_sensitive) = kmalloc(data_len, GFP_KERNEL); + + if (!data) + return -ENOMEM; + data[0] = chap_id; + memcpy(&data[1], password, pass_len); + memcpy(&data[1 + pass_len], challenge, challenge_len); + switch (digest_type) { case CHAP_DIGEST_MD5: - return "md5"; + md5(data, data_len, out_digest); + return 0; case CHAP_DIGEST_SHA1: - return "sha1"; + sha1(data, data_len, out_digest); + return 0; case CHAP_DIGEST_SHA256: - return "sha256"; + sha256(data, data_len, out_digest); + return 0; case CHAP_DIGEST_SHA3_256: - return "sha3-256"; + sha3_256(data, data_len, out_digest); + return 0; default: - return NULL; + WARN_ON_ONCE(1); + return -EINVAL; } } @@ -72,21 +114,9 @@ out: return ret; } -static int chap_test_algorithm(const char *name) -{ - struct crypto_shash *tfm; - - tfm = crypto_alloc_shash(name, 0, 0); - if (IS_ERR(tfm)) - return -1; - - crypto_free_shash(tfm); - return 0; -} - static int chap_check_algorithm(const char *a_str) { - char *tmp, *orig, *token, *digest_name; + char *tmp, *orig, *token; long digest_type; int r = CHAP_DIGEST_UNKNOWN; @@ -113,17 +143,17 @@ static int chap_check_algorithm(const char *a_str) if (kstrtol(token, 10, &digest_type)) continue; - digest_name = chap_get_digest_name(digest_type); - if (!digest_name) + if (fips_enabled && digest_type == CHAP_DIGEST_MD5) continue; - pr_debug("Selected %s Algorithm\n", digest_name); - if (chap_test_algorithm(digest_name) < 0) { - pr_err("failed to allocate %s algo\n", digest_name); - } else { - r = digest_type; - goto out; - } + if (digest_type < 0 || + digest_type >= ARRAY_SIZE(chap_digest_algs) || + chap_digest_algs[digest_type].digest_name == NULL) + continue; + pr_debug("Selected %s Algorithm\n", + chap_digest_algs[digest_type].digest_name); + r = digest_type; + goto out; } out: kfree(orig); @@ -159,27 +189,15 @@ static struct iscsi_chap *chap_server_open( chap = conn->auth_protocol; digest_type = chap_check_algorithm(a_str); - switch (digest_type) { - case CHAP_DIGEST_MD5: - chap->digest_size = MD5_SIGNATURE_SIZE; - break; - case CHAP_DIGEST_SHA1: - chap->digest_size = SHA1_SIGNATURE_SIZE; - break; - case CHAP_DIGEST_SHA256: - chap->digest_size = SHA256_SIGNATURE_SIZE; - break; - case CHAP_DIGEST_SHA3_256: - chap->digest_size = SHA3_256_SIGNATURE_SIZE; - break; - case CHAP_DIGEST_UNKNOWN: - default: + if (digest_type == CHAP_DIGEST_UNKNOWN) { pr_err("Unsupported CHAP_A value\n"); chap_close(conn); return NULL; } - chap->digest_name = chap_get_digest_name(digest_type); + chap->digest_name = chap_digest_algs[digest_type].digest_name; + chap->digest_type = digest_type; + chap->digest_size = chap_digest_algs[digest_type].digest_size; /* Tie the challenge length to the digest size */ chap->challenge_len = chap->digest_size; @@ -247,7 +265,6 @@ static int chap_server_compute_hash( unsigned int *nr_out_len) { unsigned long id; - unsigned char id_as_uchar; unsigned char type; unsigned char identifier[10], *initiatorchg = NULL; unsigned char *initiatorchg_binhex = NULL; @@ -258,8 +275,6 @@ static int chap_server_compute_hash( unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH]; size_t compare_len; struct iscsi_chap *chap = conn->auth_protocol; - struct crypto_shash *tfm = NULL; - struct shash_desc *desc = NULL; int auth_ret = -1, ret, initiatorchg_len; digest = kzalloc(chap->digest_size, GFP_KERNEL); @@ -364,44 +379,10 @@ static int chap_server_compute_hash( pr_debug("[server] Got CHAP_R=%s\n", chap_r); - tfm = crypto_alloc_shash(chap->digest_name, 0, 0); - if (IS_ERR(tfm)) { - tfm = NULL; - pr_err("Unable to allocate struct crypto_shash\n"); - goto out; - } - - desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL); - if (!desc) { - pr_err("Unable to allocate struct shash_desc\n"); - goto out; - } - - desc->tfm = tfm; - - ret = crypto_shash_init(desc); - if (ret < 0) { - pr_err("crypto_shash_init() failed\n"); - goto out; - } - - ret = crypto_shash_update(desc, &chap->id, 1); - if (ret < 0) { - pr_err("crypto_shash_update() failed for id\n"); - goto out; - } - - ret = crypto_shash_update(desc, (char *)&auth->password, - strlen(auth->password)); - if (ret < 0) { - pr_err("crypto_shash_update() failed for password\n"); - goto out; - } - - ret = crypto_shash_finup(desc, chap->challenge, - chap->challenge_len, server_digest); + ret = chap_digest(chap->digest_type, chap->id, auth->password, + chap->challenge, chap->challenge_len, server_digest); if (ret < 0) { - pr_err("crypto_shash_finup() failed for challenge\n"); + pr_err("chap_digest() failed\n"); goto out; } @@ -530,40 +511,12 @@ static int chap_server_compute_hash( /* * Generate CHAP_N and CHAP_R for mutual authentication. */ - ret = crypto_shash_init(desc); + ret = chap_digest(chap->digest_type, id, auth->password_mutual, + initiatorchg_binhex, initiatorchg_len, digest); if (ret < 0) { - pr_err("crypto_shash_init() failed\n"); + pr_err("chap_digest() failed\n"); goto out; } - - /* To handle both endiannesses */ - id_as_uchar = id; - ret = crypto_shash_update(desc, &id_as_uchar, 1); - if (ret < 0) { - pr_err("crypto_shash_update() failed for id\n"); - goto out; - } - - ret = crypto_shash_update(desc, auth->password_mutual, - strlen(auth->password_mutual)); - if (ret < 0) { - pr_err("crypto_shash_update() failed for" - " password_mutual\n"); - goto out; - } - /* - * Convert received challenge to binary hex. - */ - ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len, - digest); - if (ret < 0) { - pr_err("crypto_shash_finup() failed for ma challenge\n"); - goto out; - } - - /* - * Generate CHAP_N and CHAP_R. - */ *nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual); *nr_out_len += 1; pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual); @@ -577,9 +530,6 @@ static int chap_server_compute_hash( pr_debug("[server] Sending CHAP_R=0x%s\n", response); auth_ret = 0; out: - kfree_sensitive(desc); - if (tfm) - crypto_free_shash(tfm); kfree(initiatorchg); kfree(initiatorchg_binhex); kfree(digest); diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h index ceb9b7754770..7ed288936af2 100644 --- a/drivers/target/iscsi/iscsi_target_auth.h +++ b/drivers/target/iscsi/iscsi_target_auth.h @@ -15,11 +15,6 @@ #define MAX_RESPONSE_LENGTH 128 /* sufficient for SHA3 256 */ #define MAX_CHAP_N_SIZE 512 -#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */ -#define SHA1_SIGNATURE_SIZE 20 /* 20 bytes in a SHA1 message digest */ -#define SHA256_SIGNATURE_SIZE 32 /* 32 bytes in a SHA256 message digest */ -#define SHA3_256_SIGNATURE_SIZE 32 /* 32 bytes in a SHA3 256 message digest */ - #define CHAP_STAGE_CLIENT_A 1 #define CHAP_STAGE_SERVER_AIC 2 #define CHAP_STAGE_CLIENT_NR 3 @@ -36,7 +31,8 @@ struct iscsi_chap { unsigned char id; unsigned char challenge[MAX_CHAP_CHALLENGE_LEN]; unsigned int challenge_len; - unsigned char *digest_name; + const char *digest_name; + int digest_type; unsigned int digest_size; unsigned int authenticate_target; unsigned int chap_state; -- cgit v1.2.3