18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*******************************************************************************
38c2ecf20Sopenharmony_ci * This file houses the main functions for the iSCSI CHAP support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * (c) Copyright 2007-2013 Datera, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci ******************************************************************************/
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <crypto/hash.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/string.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/random.h>
168c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
178c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h>
188c2ecf20Sopenharmony_ci#include "iscsi_target_nego.h"
198c2ecf20Sopenharmony_ci#include "iscsi_target_auth.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic char *chap_get_digest_name(const int digest_type)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	switch (digest_type) {
248c2ecf20Sopenharmony_ci	case CHAP_DIGEST_MD5:
258c2ecf20Sopenharmony_ci		return "md5";
268c2ecf20Sopenharmony_ci	case CHAP_DIGEST_SHA1:
278c2ecf20Sopenharmony_ci		return "sha1";
288c2ecf20Sopenharmony_ci	case CHAP_DIGEST_SHA256:
298c2ecf20Sopenharmony_ci		return "sha256";
308c2ecf20Sopenharmony_ci	case CHAP_DIGEST_SHA3_256:
318c2ecf20Sopenharmony_ci		return "sha3-256";
328c2ecf20Sopenharmony_ci	default:
338c2ecf20Sopenharmony_ci		return NULL;
348c2ecf20Sopenharmony_ci	}
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int chap_gen_challenge(
388c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
398c2ecf20Sopenharmony_ci	int caller,
408c2ecf20Sopenharmony_ci	char *c_str,
418c2ecf20Sopenharmony_ci	unsigned int *c_len)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	int ret;
448c2ecf20Sopenharmony_ci	unsigned char *challenge_asciihex;
458c2ecf20Sopenharmony_ci	struct iscsi_chap *chap = conn->auth_protocol;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL);
488c2ecf20Sopenharmony_ci	if (!challenge_asciihex)
498c2ecf20Sopenharmony_ci		return -ENOMEM;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	ret = get_random_bytes_wait(chap->challenge, chap->challenge_len);
548c2ecf20Sopenharmony_ci	if (unlikely(ret))
558c2ecf20Sopenharmony_ci		goto out;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	bin2hex(challenge_asciihex, chap->challenge,
588c2ecf20Sopenharmony_ci				chap->challenge_len);
598c2ecf20Sopenharmony_ci	/*
608c2ecf20Sopenharmony_ci	 * Set CHAP_C, and copy the generated challenge into c_str.
618c2ecf20Sopenharmony_ci	 */
628c2ecf20Sopenharmony_ci	*c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
638c2ecf20Sopenharmony_ci	*c_len += 1;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
668c2ecf20Sopenharmony_ci			challenge_asciihex);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ciout:
698c2ecf20Sopenharmony_ci	kfree(challenge_asciihex);
708c2ecf20Sopenharmony_ci	return ret;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int chap_test_algorithm(const char *name)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct crypto_shash *tfm;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	tfm = crypto_alloc_shash(name, 0, 0);
788c2ecf20Sopenharmony_ci	if (IS_ERR(tfm))
798c2ecf20Sopenharmony_ci		return -1;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	crypto_free_shash(tfm);
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic int chap_check_algorithm(const char *a_str)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	char *tmp, *orig, *token, *digest_name;
888c2ecf20Sopenharmony_ci	long digest_type;
898c2ecf20Sopenharmony_ci	int r = CHAP_DIGEST_UNKNOWN;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	tmp = kstrdup(a_str, GFP_KERNEL);
928c2ecf20Sopenharmony_ci	if (!tmp) {
938c2ecf20Sopenharmony_ci		pr_err("Memory allocation failed for CHAP_A temporary buffer\n");
948c2ecf20Sopenharmony_ci		return CHAP_DIGEST_UNKNOWN;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	orig = tmp;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	token = strsep(&tmp, "=");
998c2ecf20Sopenharmony_ci	if (!token)
1008c2ecf20Sopenharmony_ci		goto out;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if (strcmp(token, "CHAP_A")) {
1038c2ecf20Sopenharmony_ci		pr_err("Unable to locate CHAP_A key\n");
1048c2ecf20Sopenharmony_ci		goto out;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci	while (token) {
1078c2ecf20Sopenharmony_ci		token = strsep(&tmp, ",");
1088c2ecf20Sopenharmony_ci		if (!token)
1098c2ecf20Sopenharmony_ci			goto out;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		if (kstrtol(token, 10, &digest_type))
1128c2ecf20Sopenharmony_ci			continue;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		digest_name = chap_get_digest_name(digest_type);
1158c2ecf20Sopenharmony_ci		if (!digest_name)
1168c2ecf20Sopenharmony_ci			continue;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		pr_debug("Selected %s Algorithm\n", digest_name);
1198c2ecf20Sopenharmony_ci		if (chap_test_algorithm(digest_name) < 0) {
1208c2ecf20Sopenharmony_ci			pr_err("failed to allocate %s algo\n", digest_name);
1218c2ecf20Sopenharmony_ci		} else {
1228c2ecf20Sopenharmony_ci			r = digest_type;
1238c2ecf20Sopenharmony_ci			goto out;
1248c2ecf20Sopenharmony_ci		}
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ciout:
1278c2ecf20Sopenharmony_ci	kfree(orig);
1288c2ecf20Sopenharmony_ci	return r;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void chap_close(struct iscsi_conn *conn)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	kfree(conn->auth_protocol);
1348c2ecf20Sopenharmony_ci	conn->auth_protocol = NULL;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic struct iscsi_chap *chap_server_open(
1388c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
1398c2ecf20Sopenharmony_ci	struct iscsi_node_auth *auth,
1408c2ecf20Sopenharmony_ci	const char *a_str,
1418c2ecf20Sopenharmony_ci	char *aic_str,
1428c2ecf20Sopenharmony_ci	unsigned int *aic_len)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	int digest_type;
1458c2ecf20Sopenharmony_ci	struct iscsi_chap *chap;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (!(auth->naf_flags & NAF_USERID_SET) ||
1488c2ecf20Sopenharmony_ci	    !(auth->naf_flags & NAF_PASSWORD_SET)) {
1498c2ecf20Sopenharmony_ci		pr_err("CHAP user or password not set for"
1508c2ecf20Sopenharmony_ci				" Initiator ACL\n");
1518c2ecf20Sopenharmony_ci		return NULL;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL);
1558c2ecf20Sopenharmony_ci	if (!conn->auth_protocol)
1568c2ecf20Sopenharmony_ci		return NULL;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	chap = conn->auth_protocol;
1598c2ecf20Sopenharmony_ci	digest_type = chap_check_algorithm(a_str);
1608c2ecf20Sopenharmony_ci	switch (digest_type) {
1618c2ecf20Sopenharmony_ci	case CHAP_DIGEST_MD5:
1628c2ecf20Sopenharmony_ci		chap->digest_size = MD5_SIGNATURE_SIZE;
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	case CHAP_DIGEST_SHA1:
1658c2ecf20Sopenharmony_ci		chap->digest_size = SHA1_SIGNATURE_SIZE;
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	case CHAP_DIGEST_SHA256:
1688c2ecf20Sopenharmony_ci		chap->digest_size = SHA256_SIGNATURE_SIZE;
1698c2ecf20Sopenharmony_ci		break;
1708c2ecf20Sopenharmony_ci	case CHAP_DIGEST_SHA3_256:
1718c2ecf20Sopenharmony_ci		chap->digest_size = SHA3_256_SIGNATURE_SIZE;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case CHAP_DIGEST_UNKNOWN:
1748c2ecf20Sopenharmony_ci	default:
1758c2ecf20Sopenharmony_ci		pr_err("Unsupported CHAP_A value\n");
1768c2ecf20Sopenharmony_ci		chap_close(conn);
1778c2ecf20Sopenharmony_ci		return NULL;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	chap->digest_name = chap_get_digest_name(digest_type);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* Tie the challenge length to the digest size */
1838c2ecf20Sopenharmony_ci	chap->challenge_len = chap->digest_size;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	pr_debug("[server] Got CHAP_A=%d\n", digest_type);
1868c2ecf20Sopenharmony_ci	*aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type);
1878c2ecf20Sopenharmony_ci	*aic_len += 1;
1888c2ecf20Sopenharmony_ci	pr_debug("[server] Sending CHAP_A=%d\n", digest_type);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/*
1918c2ecf20Sopenharmony_ci	 * Set Identifier.
1928c2ecf20Sopenharmony_ci	 */
1938c2ecf20Sopenharmony_ci	chap->id = conn->tpg->tpg_chap_id++;
1948c2ecf20Sopenharmony_ci	*aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id);
1958c2ecf20Sopenharmony_ci	*aic_len += 1;
1968c2ecf20Sopenharmony_ci	pr_debug("[server] Sending CHAP_I=%d\n", chap->id);
1978c2ecf20Sopenharmony_ci	/*
1988c2ecf20Sopenharmony_ci	 * Generate Challenge.
1998c2ecf20Sopenharmony_ci	 */
2008c2ecf20Sopenharmony_ci	if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
2018c2ecf20Sopenharmony_ci		chap_close(conn);
2028c2ecf20Sopenharmony_ci		return NULL;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	return chap;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int chap_server_compute_hash(
2098c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
2108c2ecf20Sopenharmony_ci	struct iscsi_node_auth *auth,
2118c2ecf20Sopenharmony_ci	char *nr_in_ptr,
2128c2ecf20Sopenharmony_ci	char *nr_out_ptr,
2138c2ecf20Sopenharmony_ci	unsigned int *nr_out_len)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	unsigned long id;
2168c2ecf20Sopenharmony_ci	unsigned char id_as_uchar;
2178c2ecf20Sopenharmony_ci	unsigned char type;
2188c2ecf20Sopenharmony_ci	unsigned char identifier[10], *initiatorchg = NULL;
2198c2ecf20Sopenharmony_ci	unsigned char *initiatorchg_binhex = NULL;
2208c2ecf20Sopenharmony_ci	unsigned char *digest = NULL;
2218c2ecf20Sopenharmony_ci	unsigned char *response = NULL;
2228c2ecf20Sopenharmony_ci	unsigned char *client_digest = NULL;
2238c2ecf20Sopenharmony_ci	unsigned char *server_digest = NULL;
2248c2ecf20Sopenharmony_ci	unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
2258c2ecf20Sopenharmony_ci	size_t compare_len;
2268c2ecf20Sopenharmony_ci	struct iscsi_chap *chap = conn->auth_protocol;
2278c2ecf20Sopenharmony_ci	struct crypto_shash *tfm = NULL;
2288c2ecf20Sopenharmony_ci	struct shash_desc *desc = NULL;
2298c2ecf20Sopenharmony_ci	int auth_ret = -1, ret, initiatorchg_len;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	digest = kzalloc(chap->digest_size, GFP_KERNEL);
2328c2ecf20Sopenharmony_ci	if (!digest) {
2338c2ecf20Sopenharmony_ci		pr_err("Unable to allocate the digest buffer\n");
2348c2ecf20Sopenharmony_ci		goto out;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL);
2388c2ecf20Sopenharmony_ci	if (!response) {
2398c2ecf20Sopenharmony_ci		pr_err("Unable to allocate the response buffer\n");
2408c2ecf20Sopenharmony_ci		goto out;
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	client_digest = kzalloc(chap->digest_size, GFP_KERNEL);
2448c2ecf20Sopenharmony_ci	if (!client_digest) {
2458c2ecf20Sopenharmony_ci		pr_err("Unable to allocate the client_digest buffer\n");
2468c2ecf20Sopenharmony_ci		goto out;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	server_digest = kzalloc(chap->digest_size, GFP_KERNEL);
2508c2ecf20Sopenharmony_ci	if (!server_digest) {
2518c2ecf20Sopenharmony_ci		pr_err("Unable to allocate the server_digest buffer\n");
2528c2ecf20Sopenharmony_ci		goto out;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	memset(identifier, 0, 10);
2568c2ecf20Sopenharmony_ci	memset(chap_n, 0, MAX_CHAP_N_SIZE);
2578c2ecf20Sopenharmony_ci	memset(chap_r, 0, MAX_RESPONSE_LENGTH);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
2608c2ecf20Sopenharmony_ci	if (!initiatorchg) {
2618c2ecf20Sopenharmony_ci		pr_err("Unable to allocate challenge buffer\n");
2628c2ecf20Sopenharmony_ci		goto out;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
2668c2ecf20Sopenharmony_ci	if (!initiatorchg_binhex) {
2678c2ecf20Sopenharmony_ci		pr_err("Unable to allocate initiatorchg_binhex buffer\n");
2688c2ecf20Sopenharmony_ci		goto out;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci	/*
2718c2ecf20Sopenharmony_ci	 * Extract CHAP_N.
2728c2ecf20Sopenharmony_ci	 */
2738c2ecf20Sopenharmony_ci	if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n,
2748c2ecf20Sopenharmony_ci				&type) < 0) {
2758c2ecf20Sopenharmony_ci		pr_err("Could not find CHAP_N.\n");
2768c2ecf20Sopenharmony_ci		goto out;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci	if (type == HEX) {
2798c2ecf20Sopenharmony_ci		pr_err("Could not find CHAP_N.\n");
2808c2ecf20Sopenharmony_ci		goto out;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* Include the terminating NULL in the compare */
2848c2ecf20Sopenharmony_ci	compare_len = strlen(auth->userid) + 1;
2858c2ecf20Sopenharmony_ci	if (strncmp(chap_n, auth->userid, compare_len) != 0) {
2868c2ecf20Sopenharmony_ci		pr_err("CHAP_N values do not match!\n");
2878c2ecf20Sopenharmony_ci		goto out;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	pr_debug("[server] Got CHAP_N=%s\n", chap_n);
2908c2ecf20Sopenharmony_ci	/*
2918c2ecf20Sopenharmony_ci	 * Extract CHAP_R.
2928c2ecf20Sopenharmony_ci	 */
2938c2ecf20Sopenharmony_ci	if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r,
2948c2ecf20Sopenharmony_ci				&type) < 0) {
2958c2ecf20Sopenharmony_ci		pr_err("Could not find CHAP_R.\n");
2968c2ecf20Sopenharmony_ci		goto out;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	if (type != HEX) {
2998c2ecf20Sopenharmony_ci		pr_err("Could not find CHAP_R.\n");
3008c2ecf20Sopenharmony_ci		goto out;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci	if (strlen(chap_r) != chap->digest_size * 2) {
3038c2ecf20Sopenharmony_ci		pr_err("Malformed CHAP_R\n");
3048c2ecf20Sopenharmony_ci		goto out;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci	if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) {
3078c2ecf20Sopenharmony_ci		pr_err("Malformed CHAP_R\n");
3088c2ecf20Sopenharmony_ci		goto out;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	pr_debug("[server] Got CHAP_R=%s\n", chap_r);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	tfm = crypto_alloc_shash(chap->digest_name, 0, 0);
3148c2ecf20Sopenharmony_ci	if (IS_ERR(tfm)) {
3158c2ecf20Sopenharmony_ci		tfm = NULL;
3168c2ecf20Sopenharmony_ci		pr_err("Unable to allocate struct crypto_shash\n");
3178c2ecf20Sopenharmony_ci		goto out;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
3218c2ecf20Sopenharmony_ci	if (!desc) {
3228c2ecf20Sopenharmony_ci		pr_err("Unable to allocate struct shash_desc\n");
3238c2ecf20Sopenharmony_ci		goto out;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	desc->tfm = tfm;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	ret = crypto_shash_init(desc);
3298c2ecf20Sopenharmony_ci	if (ret < 0) {
3308c2ecf20Sopenharmony_ci		pr_err("crypto_shash_init() failed\n");
3318c2ecf20Sopenharmony_ci		goto out;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	ret = crypto_shash_update(desc, &chap->id, 1);
3358c2ecf20Sopenharmony_ci	if (ret < 0) {
3368c2ecf20Sopenharmony_ci		pr_err("crypto_shash_update() failed for id\n");
3378c2ecf20Sopenharmony_ci		goto out;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	ret = crypto_shash_update(desc, (char *)&auth->password,
3418c2ecf20Sopenharmony_ci				  strlen(auth->password));
3428c2ecf20Sopenharmony_ci	if (ret < 0) {
3438c2ecf20Sopenharmony_ci		pr_err("crypto_shash_update() failed for password\n");
3448c2ecf20Sopenharmony_ci		goto out;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	ret = crypto_shash_finup(desc, chap->challenge,
3488c2ecf20Sopenharmony_ci				 chap->challenge_len, server_digest);
3498c2ecf20Sopenharmony_ci	if (ret < 0) {
3508c2ecf20Sopenharmony_ci		pr_err("crypto_shash_finup() failed for challenge\n");
3518c2ecf20Sopenharmony_ci		goto out;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	bin2hex(response, server_digest, chap->digest_size);
3558c2ecf20Sopenharmony_ci	pr_debug("[server] %s Server Digest: %s\n",
3568c2ecf20Sopenharmony_ci		chap->digest_name, response);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
3598c2ecf20Sopenharmony_ci		pr_debug("[server] %s Digests do not match!\n\n",
3608c2ecf20Sopenharmony_ci			chap->digest_name);
3618c2ecf20Sopenharmony_ci		goto out;
3628c2ecf20Sopenharmony_ci	} else
3638c2ecf20Sopenharmony_ci		pr_debug("[server] %s Digests match, CHAP connection"
3648c2ecf20Sopenharmony_ci				" successful.\n\n", chap->digest_name);
3658c2ecf20Sopenharmony_ci	/*
3668c2ecf20Sopenharmony_ci	 * One way authentication has succeeded, return now if mutual
3678c2ecf20Sopenharmony_ci	 * authentication is not enabled.
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci	if (!auth->authenticate_target) {
3708c2ecf20Sopenharmony_ci		auth_ret = 0;
3718c2ecf20Sopenharmony_ci		goto out;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci	/*
3748c2ecf20Sopenharmony_ci	 * Get CHAP_I.
3758c2ecf20Sopenharmony_ci	 */
3768c2ecf20Sopenharmony_ci	if (extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type) < 0) {
3778c2ecf20Sopenharmony_ci		pr_err("Could not find CHAP_I.\n");
3788c2ecf20Sopenharmony_ci		goto out;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	if (type == HEX)
3828c2ecf20Sopenharmony_ci		ret = kstrtoul(&identifier[2], 0, &id);
3838c2ecf20Sopenharmony_ci	else
3848c2ecf20Sopenharmony_ci		ret = kstrtoul(identifier, 0, &id);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	if (ret < 0) {
3878c2ecf20Sopenharmony_ci		pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
3888c2ecf20Sopenharmony_ci		goto out;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci	if (id > 255) {
3918c2ecf20Sopenharmony_ci		pr_err("chap identifier: %lu greater than 255\n", id);
3928c2ecf20Sopenharmony_ci		goto out;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci	/*
3958c2ecf20Sopenharmony_ci	 * RFC 1994 says Identifier is no more than octet (8 bits).
3968c2ecf20Sopenharmony_ci	 */
3978c2ecf20Sopenharmony_ci	pr_debug("[server] Got CHAP_I=%lu\n", id);
3988c2ecf20Sopenharmony_ci	/*
3998c2ecf20Sopenharmony_ci	 * Get CHAP_C.
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
4028c2ecf20Sopenharmony_ci			initiatorchg, &type) < 0) {
4038c2ecf20Sopenharmony_ci		pr_err("Could not find CHAP_C.\n");
4048c2ecf20Sopenharmony_ci		goto out;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (type != HEX) {
4088c2ecf20Sopenharmony_ci		pr_err("Could not find CHAP_C.\n");
4098c2ecf20Sopenharmony_ci		goto out;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci	initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2);
4128c2ecf20Sopenharmony_ci	if (!initiatorchg_len) {
4138c2ecf20Sopenharmony_ci		pr_err("Unable to convert incoming challenge\n");
4148c2ecf20Sopenharmony_ci		goto out;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci	if (initiatorchg_len > 1024) {
4178c2ecf20Sopenharmony_ci		pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
4188c2ecf20Sopenharmony_ci		goto out;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci	if (hex2bin(initiatorchg_binhex, initiatorchg, initiatorchg_len) < 0) {
4218c2ecf20Sopenharmony_ci		pr_err("Malformed CHAP_C\n");
4228c2ecf20Sopenharmony_ci		goto out;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci	pr_debug("[server] Got CHAP_C=%s\n", initiatorchg);
4258c2ecf20Sopenharmony_ci	/*
4268c2ecf20Sopenharmony_ci	 * During mutual authentication, the CHAP_C generated by the
4278c2ecf20Sopenharmony_ci	 * initiator must not match the original CHAP_C generated by
4288c2ecf20Sopenharmony_ci	 * the target.
4298c2ecf20Sopenharmony_ci	 */
4308c2ecf20Sopenharmony_ci	if (initiatorchg_len == chap->challenge_len &&
4318c2ecf20Sopenharmony_ci				!memcmp(initiatorchg_binhex, chap->challenge,
4328c2ecf20Sopenharmony_ci				initiatorchg_len)) {
4338c2ecf20Sopenharmony_ci		pr_err("initiator CHAP_C matches target CHAP_C, failing"
4348c2ecf20Sopenharmony_ci		       " login attempt\n");
4358c2ecf20Sopenharmony_ci		goto out;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci	/*
4388c2ecf20Sopenharmony_ci	 * Generate CHAP_N and CHAP_R for mutual authentication.
4398c2ecf20Sopenharmony_ci	 */
4408c2ecf20Sopenharmony_ci	ret = crypto_shash_init(desc);
4418c2ecf20Sopenharmony_ci	if (ret < 0) {
4428c2ecf20Sopenharmony_ci		pr_err("crypto_shash_init() failed\n");
4438c2ecf20Sopenharmony_ci		goto out;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/* To handle both endiannesses */
4478c2ecf20Sopenharmony_ci	id_as_uchar = id;
4488c2ecf20Sopenharmony_ci	ret = crypto_shash_update(desc, &id_as_uchar, 1);
4498c2ecf20Sopenharmony_ci	if (ret < 0) {
4508c2ecf20Sopenharmony_ci		pr_err("crypto_shash_update() failed for id\n");
4518c2ecf20Sopenharmony_ci		goto out;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	ret = crypto_shash_update(desc, auth->password_mutual,
4558c2ecf20Sopenharmony_ci				  strlen(auth->password_mutual));
4568c2ecf20Sopenharmony_ci	if (ret < 0) {
4578c2ecf20Sopenharmony_ci		pr_err("crypto_shash_update() failed for"
4588c2ecf20Sopenharmony_ci				" password_mutual\n");
4598c2ecf20Sopenharmony_ci		goto out;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci	/*
4628c2ecf20Sopenharmony_ci	 * Convert received challenge to binary hex.
4638c2ecf20Sopenharmony_ci	 */
4648c2ecf20Sopenharmony_ci	ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len,
4658c2ecf20Sopenharmony_ci				 digest);
4668c2ecf20Sopenharmony_ci	if (ret < 0) {
4678c2ecf20Sopenharmony_ci		pr_err("crypto_shash_finup() failed for ma challenge\n");
4688c2ecf20Sopenharmony_ci		goto out;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/*
4728c2ecf20Sopenharmony_ci	 * Generate CHAP_N and CHAP_R.
4738c2ecf20Sopenharmony_ci	 */
4748c2ecf20Sopenharmony_ci	*nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual);
4758c2ecf20Sopenharmony_ci	*nr_out_len += 1;
4768c2ecf20Sopenharmony_ci	pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual);
4778c2ecf20Sopenharmony_ci	/*
4788c2ecf20Sopenharmony_ci	 * Convert response from binary hex to ascii hext.
4798c2ecf20Sopenharmony_ci	 */
4808c2ecf20Sopenharmony_ci	bin2hex(response, digest, chap->digest_size);
4818c2ecf20Sopenharmony_ci	*nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
4828c2ecf20Sopenharmony_ci			response);
4838c2ecf20Sopenharmony_ci	*nr_out_len += 1;
4848c2ecf20Sopenharmony_ci	pr_debug("[server] Sending CHAP_R=0x%s\n", response);
4858c2ecf20Sopenharmony_ci	auth_ret = 0;
4868c2ecf20Sopenharmony_ciout:
4878c2ecf20Sopenharmony_ci	kfree_sensitive(desc);
4888c2ecf20Sopenharmony_ci	if (tfm)
4898c2ecf20Sopenharmony_ci		crypto_free_shash(tfm);
4908c2ecf20Sopenharmony_ci	kfree(initiatorchg);
4918c2ecf20Sopenharmony_ci	kfree(initiatorchg_binhex);
4928c2ecf20Sopenharmony_ci	kfree(digest);
4938c2ecf20Sopenharmony_ci	kfree(response);
4948c2ecf20Sopenharmony_ci	kfree(server_digest);
4958c2ecf20Sopenharmony_ci	kfree(client_digest);
4968c2ecf20Sopenharmony_ci	return auth_ret;
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ciu32 chap_main_loop(
5008c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
5018c2ecf20Sopenharmony_ci	struct iscsi_node_auth *auth,
5028c2ecf20Sopenharmony_ci	char *in_text,
5038c2ecf20Sopenharmony_ci	char *out_text,
5048c2ecf20Sopenharmony_ci	int *in_len,
5058c2ecf20Sopenharmony_ci	int *out_len)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct iscsi_chap *chap = conn->auth_protocol;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (!chap) {
5108c2ecf20Sopenharmony_ci		chap = chap_server_open(conn, auth, in_text, out_text, out_len);
5118c2ecf20Sopenharmony_ci		if (!chap)
5128c2ecf20Sopenharmony_ci			return 2;
5138c2ecf20Sopenharmony_ci		chap->chap_state = CHAP_STAGE_SERVER_AIC;
5148c2ecf20Sopenharmony_ci		return 0;
5158c2ecf20Sopenharmony_ci	} else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
5168c2ecf20Sopenharmony_ci		convert_null_to_semi(in_text, *in_len);
5178c2ecf20Sopenharmony_ci		if (chap_server_compute_hash(conn, auth, in_text, out_text,
5188c2ecf20Sopenharmony_ci				out_len) < 0) {
5198c2ecf20Sopenharmony_ci			chap_close(conn);
5208c2ecf20Sopenharmony_ci			return 2;
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci		if (auth->authenticate_target)
5238c2ecf20Sopenharmony_ci			chap->chap_state = CHAP_STAGE_SERVER_NR;
5248c2ecf20Sopenharmony_ci		else
5258c2ecf20Sopenharmony_ci			*out_len = 0;
5268c2ecf20Sopenharmony_ci		chap_close(conn);
5278c2ecf20Sopenharmony_ci		return 1;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return 2;
5318c2ecf20Sopenharmony_ci}
532