mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] scsi: target: iscsi: Use crypto library API
@ 2026-10-01  4:48 Eric Biggers
  0 siblings, 0 replies; only message in thread
From: Eric Biggers @ 2026-10-01  4:48 UTC (permalink / raw)
  To: linux-scsi, target-devel, Martin K . Petersen
  Cc: linux-crypto, linux-kernel, David Disseldorp, Lee Duncan,
	Alexandru Hossu, Eric Biggers

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 <ebiggers@kernel.org>
---
 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(-)

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 <crypto/hash.h>
+#include <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/sha3.h>
 #include <crypto/utils.h>
+#include <linux/fips.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/err.h>
 #include <linux/hex.h>
 #include <linux/random.h>
-#include <linux/scatterlist.h>
+#include <linux/slab.h>
 #include <target/iscsi/iscsi_target_core.h>
 #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 @@ static int chap_gen_challenge(
 	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;

base-commit: 551c722f40809618230001baccf219193e22fc5a
-- 
2.56.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-01  4:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-01  4:48 [PATCH] scsi: target: iscsi: Use crypto library API Eric Biggers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®