xref: /OK3568_Linux_fs/kernel/drivers/target/iscsi/iscsi_target_auth.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*******************************************************************************
3*4882a593Smuzhiyun  * This file houses the main functions for the iSCSI CHAP support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * (c) Copyright 2007-2013 Datera, Inc.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  ******************************************************************************/
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <crypto/hash.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/string.h>
14*4882a593Smuzhiyun #include <linux/err.h>
15*4882a593Smuzhiyun #include <linux/random.h>
16*4882a593Smuzhiyun #include <linux/scatterlist.h>
17*4882a593Smuzhiyun #include <target/iscsi/iscsi_target_core.h>
18*4882a593Smuzhiyun #include "iscsi_target_nego.h"
19*4882a593Smuzhiyun #include "iscsi_target_auth.h"
20*4882a593Smuzhiyun 
chap_get_digest_name(const int digest_type)21*4882a593Smuzhiyun static char *chap_get_digest_name(const int digest_type)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	switch (digest_type) {
24*4882a593Smuzhiyun 	case CHAP_DIGEST_MD5:
25*4882a593Smuzhiyun 		return "md5";
26*4882a593Smuzhiyun 	case CHAP_DIGEST_SHA1:
27*4882a593Smuzhiyun 		return "sha1";
28*4882a593Smuzhiyun 	case CHAP_DIGEST_SHA256:
29*4882a593Smuzhiyun 		return "sha256";
30*4882a593Smuzhiyun 	case CHAP_DIGEST_SHA3_256:
31*4882a593Smuzhiyun 		return "sha3-256";
32*4882a593Smuzhiyun 	default:
33*4882a593Smuzhiyun 		return NULL;
34*4882a593Smuzhiyun 	}
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun 
chap_gen_challenge(struct iscsi_conn * conn,int caller,char * c_str,unsigned int * c_len)37*4882a593Smuzhiyun static int chap_gen_challenge(
38*4882a593Smuzhiyun 	struct iscsi_conn *conn,
39*4882a593Smuzhiyun 	int caller,
40*4882a593Smuzhiyun 	char *c_str,
41*4882a593Smuzhiyun 	unsigned int *c_len)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	int ret;
44*4882a593Smuzhiyun 	unsigned char *challenge_asciihex;
45*4882a593Smuzhiyun 	struct iscsi_chap *chap = conn->auth_protocol;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL);
48*4882a593Smuzhiyun 	if (!challenge_asciihex)
49*4882a593Smuzhiyun 		return -ENOMEM;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	ret = get_random_bytes_wait(chap->challenge, chap->challenge_len);
54*4882a593Smuzhiyun 	if (unlikely(ret))
55*4882a593Smuzhiyun 		goto out;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	bin2hex(challenge_asciihex, chap->challenge,
58*4882a593Smuzhiyun 				chap->challenge_len);
59*4882a593Smuzhiyun 	/*
60*4882a593Smuzhiyun 	 * Set CHAP_C, and copy the generated challenge into c_str.
61*4882a593Smuzhiyun 	 */
62*4882a593Smuzhiyun 	*c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
63*4882a593Smuzhiyun 	*c_len += 1;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
66*4882a593Smuzhiyun 			challenge_asciihex);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun out:
69*4882a593Smuzhiyun 	kfree(challenge_asciihex);
70*4882a593Smuzhiyun 	return ret;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
chap_test_algorithm(const char * name)73*4882a593Smuzhiyun static int chap_test_algorithm(const char *name)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct crypto_shash *tfm;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	tfm = crypto_alloc_shash(name, 0, 0);
78*4882a593Smuzhiyun 	if (IS_ERR(tfm))
79*4882a593Smuzhiyun 		return -1;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	crypto_free_shash(tfm);
82*4882a593Smuzhiyun 	return 0;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
chap_check_algorithm(const char * a_str)85*4882a593Smuzhiyun static int chap_check_algorithm(const char *a_str)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	char *tmp, *orig, *token, *digest_name;
88*4882a593Smuzhiyun 	long digest_type;
89*4882a593Smuzhiyun 	int r = CHAP_DIGEST_UNKNOWN;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	tmp = kstrdup(a_str, GFP_KERNEL);
92*4882a593Smuzhiyun 	if (!tmp) {
93*4882a593Smuzhiyun 		pr_err("Memory allocation failed for CHAP_A temporary buffer\n");
94*4882a593Smuzhiyun 		return CHAP_DIGEST_UNKNOWN;
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 	orig = tmp;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	token = strsep(&tmp, "=");
99*4882a593Smuzhiyun 	if (!token)
100*4882a593Smuzhiyun 		goto out;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (strcmp(token, "CHAP_A")) {
103*4882a593Smuzhiyun 		pr_err("Unable to locate CHAP_A key\n");
104*4882a593Smuzhiyun 		goto out;
105*4882a593Smuzhiyun 	}
106*4882a593Smuzhiyun 	while (token) {
107*4882a593Smuzhiyun 		token = strsep(&tmp, ",");
108*4882a593Smuzhiyun 		if (!token)
109*4882a593Smuzhiyun 			goto out;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		if (kstrtol(token, 10, &digest_type))
112*4882a593Smuzhiyun 			continue;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 		digest_name = chap_get_digest_name(digest_type);
115*4882a593Smuzhiyun 		if (!digest_name)
116*4882a593Smuzhiyun 			continue;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 		pr_debug("Selected %s Algorithm\n", digest_name);
119*4882a593Smuzhiyun 		if (chap_test_algorithm(digest_name) < 0) {
120*4882a593Smuzhiyun 			pr_err("failed to allocate %s algo\n", digest_name);
121*4882a593Smuzhiyun 		} else {
122*4882a593Smuzhiyun 			r = digest_type;
123*4882a593Smuzhiyun 			goto out;
124*4882a593Smuzhiyun 		}
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun out:
127*4882a593Smuzhiyun 	kfree(orig);
128*4882a593Smuzhiyun 	return r;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
chap_close(struct iscsi_conn * conn)131*4882a593Smuzhiyun static void chap_close(struct iscsi_conn *conn)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	kfree(conn->auth_protocol);
134*4882a593Smuzhiyun 	conn->auth_protocol = NULL;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
chap_server_open(struct iscsi_conn * conn,struct iscsi_node_auth * auth,const char * a_str,char * aic_str,unsigned int * aic_len)137*4882a593Smuzhiyun static struct iscsi_chap *chap_server_open(
138*4882a593Smuzhiyun 	struct iscsi_conn *conn,
139*4882a593Smuzhiyun 	struct iscsi_node_auth *auth,
140*4882a593Smuzhiyun 	const char *a_str,
141*4882a593Smuzhiyun 	char *aic_str,
142*4882a593Smuzhiyun 	unsigned int *aic_len)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	int digest_type;
145*4882a593Smuzhiyun 	struct iscsi_chap *chap;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (!(auth->naf_flags & NAF_USERID_SET) ||
148*4882a593Smuzhiyun 	    !(auth->naf_flags & NAF_PASSWORD_SET)) {
149*4882a593Smuzhiyun 		pr_err("CHAP user or password not set for"
150*4882a593Smuzhiyun 				" Initiator ACL\n");
151*4882a593Smuzhiyun 		return NULL;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL);
155*4882a593Smuzhiyun 	if (!conn->auth_protocol)
156*4882a593Smuzhiyun 		return NULL;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	chap = conn->auth_protocol;
159*4882a593Smuzhiyun 	digest_type = chap_check_algorithm(a_str);
160*4882a593Smuzhiyun 	switch (digest_type) {
161*4882a593Smuzhiyun 	case CHAP_DIGEST_MD5:
162*4882a593Smuzhiyun 		chap->digest_size = MD5_SIGNATURE_SIZE;
163*4882a593Smuzhiyun 		break;
164*4882a593Smuzhiyun 	case CHAP_DIGEST_SHA1:
165*4882a593Smuzhiyun 		chap->digest_size = SHA1_SIGNATURE_SIZE;
166*4882a593Smuzhiyun 		break;
167*4882a593Smuzhiyun 	case CHAP_DIGEST_SHA256:
168*4882a593Smuzhiyun 		chap->digest_size = SHA256_SIGNATURE_SIZE;
169*4882a593Smuzhiyun 		break;
170*4882a593Smuzhiyun 	case CHAP_DIGEST_SHA3_256:
171*4882a593Smuzhiyun 		chap->digest_size = SHA3_256_SIGNATURE_SIZE;
172*4882a593Smuzhiyun 		break;
173*4882a593Smuzhiyun 	case CHAP_DIGEST_UNKNOWN:
174*4882a593Smuzhiyun 	default:
175*4882a593Smuzhiyun 		pr_err("Unsupported CHAP_A value\n");
176*4882a593Smuzhiyun 		chap_close(conn);
177*4882a593Smuzhiyun 		return NULL;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	chap->digest_name = chap_get_digest_name(digest_type);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	/* Tie the challenge length to the digest size */
183*4882a593Smuzhiyun 	chap->challenge_len = chap->digest_size;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	pr_debug("[server] Got CHAP_A=%d\n", digest_type);
186*4882a593Smuzhiyun 	*aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type);
187*4882a593Smuzhiyun 	*aic_len += 1;
188*4882a593Smuzhiyun 	pr_debug("[server] Sending CHAP_A=%d\n", digest_type);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	/*
191*4882a593Smuzhiyun 	 * Set Identifier.
192*4882a593Smuzhiyun 	 */
193*4882a593Smuzhiyun 	chap->id = conn->tpg->tpg_chap_id++;
194*4882a593Smuzhiyun 	*aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id);
195*4882a593Smuzhiyun 	*aic_len += 1;
196*4882a593Smuzhiyun 	pr_debug("[server] Sending CHAP_I=%d\n", chap->id);
197*4882a593Smuzhiyun 	/*
198*4882a593Smuzhiyun 	 * Generate Challenge.
199*4882a593Smuzhiyun 	 */
200*4882a593Smuzhiyun 	if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
201*4882a593Smuzhiyun 		chap_close(conn);
202*4882a593Smuzhiyun 		return NULL;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return chap;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
chap_server_compute_hash(struct iscsi_conn * conn,struct iscsi_node_auth * auth,char * nr_in_ptr,char * nr_out_ptr,unsigned int * nr_out_len)208*4882a593Smuzhiyun static int chap_server_compute_hash(
209*4882a593Smuzhiyun 	struct iscsi_conn *conn,
210*4882a593Smuzhiyun 	struct iscsi_node_auth *auth,
211*4882a593Smuzhiyun 	char *nr_in_ptr,
212*4882a593Smuzhiyun 	char *nr_out_ptr,
213*4882a593Smuzhiyun 	unsigned int *nr_out_len)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	unsigned long id;
216*4882a593Smuzhiyun 	unsigned char id_as_uchar;
217*4882a593Smuzhiyun 	unsigned char type;
218*4882a593Smuzhiyun 	unsigned char identifier[10], *initiatorchg = NULL;
219*4882a593Smuzhiyun 	unsigned char *initiatorchg_binhex = NULL;
220*4882a593Smuzhiyun 	unsigned char *digest = NULL;
221*4882a593Smuzhiyun 	unsigned char *response = NULL;
222*4882a593Smuzhiyun 	unsigned char *client_digest = NULL;
223*4882a593Smuzhiyun 	unsigned char *server_digest = NULL;
224*4882a593Smuzhiyun 	unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
225*4882a593Smuzhiyun 	size_t compare_len;
226*4882a593Smuzhiyun 	struct iscsi_chap *chap = conn->auth_protocol;
227*4882a593Smuzhiyun 	struct crypto_shash *tfm = NULL;
228*4882a593Smuzhiyun 	struct shash_desc *desc = NULL;
229*4882a593Smuzhiyun 	int auth_ret = -1, ret, initiatorchg_len;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	digest = kzalloc(chap->digest_size, GFP_KERNEL);
232*4882a593Smuzhiyun 	if (!digest) {
233*4882a593Smuzhiyun 		pr_err("Unable to allocate the digest buffer\n");
234*4882a593Smuzhiyun 		goto out;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL);
238*4882a593Smuzhiyun 	if (!response) {
239*4882a593Smuzhiyun 		pr_err("Unable to allocate the response buffer\n");
240*4882a593Smuzhiyun 		goto out;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	client_digest = kzalloc(chap->digest_size, GFP_KERNEL);
244*4882a593Smuzhiyun 	if (!client_digest) {
245*4882a593Smuzhiyun 		pr_err("Unable to allocate the client_digest buffer\n");
246*4882a593Smuzhiyun 		goto out;
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	server_digest = kzalloc(chap->digest_size, GFP_KERNEL);
250*4882a593Smuzhiyun 	if (!server_digest) {
251*4882a593Smuzhiyun 		pr_err("Unable to allocate the server_digest buffer\n");
252*4882a593Smuzhiyun 		goto out;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	memset(identifier, 0, 10);
256*4882a593Smuzhiyun 	memset(chap_n, 0, MAX_CHAP_N_SIZE);
257*4882a593Smuzhiyun 	memset(chap_r, 0, MAX_RESPONSE_LENGTH);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
260*4882a593Smuzhiyun 	if (!initiatorchg) {
261*4882a593Smuzhiyun 		pr_err("Unable to allocate challenge buffer\n");
262*4882a593Smuzhiyun 		goto out;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
266*4882a593Smuzhiyun 	if (!initiatorchg_binhex) {
267*4882a593Smuzhiyun 		pr_err("Unable to allocate initiatorchg_binhex buffer\n");
268*4882a593Smuzhiyun 		goto out;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 	/*
271*4882a593Smuzhiyun 	 * Extract CHAP_N.
272*4882a593Smuzhiyun 	 */
273*4882a593Smuzhiyun 	if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n,
274*4882a593Smuzhiyun 				&type) < 0) {
275*4882a593Smuzhiyun 		pr_err("Could not find CHAP_N.\n");
276*4882a593Smuzhiyun 		goto out;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 	if (type == HEX) {
279*4882a593Smuzhiyun 		pr_err("Could not find CHAP_N.\n");
280*4882a593Smuzhiyun 		goto out;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* Include the terminating NULL in the compare */
284*4882a593Smuzhiyun 	compare_len = strlen(auth->userid) + 1;
285*4882a593Smuzhiyun 	if (strncmp(chap_n, auth->userid, compare_len) != 0) {
286*4882a593Smuzhiyun 		pr_err("CHAP_N values do not match!\n");
287*4882a593Smuzhiyun 		goto out;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	pr_debug("[server] Got CHAP_N=%s\n", chap_n);
290*4882a593Smuzhiyun 	/*
291*4882a593Smuzhiyun 	 * Extract CHAP_R.
292*4882a593Smuzhiyun 	 */
293*4882a593Smuzhiyun 	if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r,
294*4882a593Smuzhiyun 				&type) < 0) {
295*4882a593Smuzhiyun 		pr_err("Could not find CHAP_R.\n");
296*4882a593Smuzhiyun 		goto out;
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 	if (type != HEX) {
299*4882a593Smuzhiyun 		pr_err("Could not find CHAP_R.\n");
300*4882a593Smuzhiyun 		goto out;
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 	if (strlen(chap_r) != chap->digest_size * 2) {
303*4882a593Smuzhiyun 		pr_err("Malformed CHAP_R\n");
304*4882a593Smuzhiyun 		goto out;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 	if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) {
307*4882a593Smuzhiyun 		pr_err("Malformed CHAP_R\n");
308*4882a593Smuzhiyun 		goto out;
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	pr_debug("[server] Got CHAP_R=%s\n", chap_r);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	tfm = crypto_alloc_shash(chap->digest_name, 0, 0);
314*4882a593Smuzhiyun 	if (IS_ERR(tfm)) {
315*4882a593Smuzhiyun 		tfm = NULL;
316*4882a593Smuzhiyun 		pr_err("Unable to allocate struct crypto_shash\n");
317*4882a593Smuzhiyun 		goto out;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
321*4882a593Smuzhiyun 	if (!desc) {
322*4882a593Smuzhiyun 		pr_err("Unable to allocate struct shash_desc\n");
323*4882a593Smuzhiyun 		goto out;
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	desc->tfm = tfm;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	ret = crypto_shash_init(desc);
329*4882a593Smuzhiyun 	if (ret < 0) {
330*4882a593Smuzhiyun 		pr_err("crypto_shash_init() failed\n");
331*4882a593Smuzhiyun 		goto out;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	ret = crypto_shash_update(desc, &chap->id, 1);
335*4882a593Smuzhiyun 	if (ret < 0) {
336*4882a593Smuzhiyun 		pr_err("crypto_shash_update() failed for id\n");
337*4882a593Smuzhiyun 		goto out;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	ret = crypto_shash_update(desc, (char *)&auth->password,
341*4882a593Smuzhiyun 				  strlen(auth->password));
342*4882a593Smuzhiyun 	if (ret < 0) {
343*4882a593Smuzhiyun 		pr_err("crypto_shash_update() failed for password\n");
344*4882a593Smuzhiyun 		goto out;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	ret = crypto_shash_finup(desc, chap->challenge,
348*4882a593Smuzhiyun 				 chap->challenge_len, server_digest);
349*4882a593Smuzhiyun 	if (ret < 0) {
350*4882a593Smuzhiyun 		pr_err("crypto_shash_finup() failed for challenge\n");
351*4882a593Smuzhiyun 		goto out;
352*4882a593Smuzhiyun 	}
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	bin2hex(response, server_digest, chap->digest_size);
355*4882a593Smuzhiyun 	pr_debug("[server] %s Server Digest: %s\n",
356*4882a593Smuzhiyun 		chap->digest_name, response);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
359*4882a593Smuzhiyun 		pr_debug("[server] %s Digests do not match!\n\n",
360*4882a593Smuzhiyun 			chap->digest_name);
361*4882a593Smuzhiyun 		goto out;
362*4882a593Smuzhiyun 	} else
363*4882a593Smuzhiyun 		pr_debug("[server] %s Digests match, CHAP connection"
364*4882a593Smuzhiyun 				" successful.\n\n", chap->digest_name);
365*4882a593Smuzhiyun 	/*
366*4882a593Smuzhiyun 	 * One way authentication has succeeded, return now if mutual
367*4882a593Smuzhiyun 	 * authentication is not enabled.
368*4882a593Smuzhiyun 	 */
369*4882a593Smuzhiyun 	if (!auth->authenticate_target) {
370*4882a593Smuzhiyun 		auth_ret = 0;
371*4882a593Smuzhiyun 		goto out;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 	/*
374*4882a593Smuzhiyun 	 * Get CHAP_I.
375*4882a593Smuzhiyun 	 */
376*4882a593Smuzhiyun 	if (extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type) < 0) {
377*4882a593Smuzhiyun 		pr_err("Could not find CHAP_I.\n");
378*4882a593Smuzhiyun 		goto out;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (type == HEX)
382*4882a593Smuzhiyun 		ret = kstrtoul(&identifier[2], 0, &id);
383*4882a593Smuzhiyun 	else
384*4882a593Smuzhiyun 		ret = kstrtoul(identifier, 0, &id);
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	if (ret < 0) {
387*4882a593Smuzhiyun 		pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
388*4882a593Smuzhiyun 		goto out;
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 	if (id > 255) {
391*4882a593Smuzhiyun 		pr_err("chap identifier: %lu greater than 255\n", id);
392*4882a593Smuzhiyun 		goto out;
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 	/*
395*4882a593Smuzhiyun 	 * RFC 1994 says Identifier is no more than octet (8 bits).
396*4882a593Smuzhiyun 	 */
397*4882a593Smuzhiyun 	pr_debug("[server] Got CHAP_I=%lu\n", id);
398*4882a593Smuzhiyun 	/*
399*4882a593Smuzhiyun 	 * Get CHAP_C.
400*4882a593Smuzhiyun 	 */
401*4882a593Smuzhiyun 	if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
402*4882a593Smuzhiyun 			initiatorchg, &type) < 0) {
403*4882a593Smuzhiyun 		pr_err("Could not find CHAP_C.\n");
404*4882a593Smuzhiyun 		goto out;
405*4882a593Smuzhiyun 	}
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	if (type != HEX) {
408*4882a593Smuzhiyun 		pr_err("Could not find CHAP_C.\n");
409*4882a593Smuzhiyun 		goto out;
410*4882a593Smuzhiyun 	}
411*4882a593Smuzhiyun 	initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2);
412*4882a593Smuzhiyun 	if (!initiatorchg_len) {
413*4882a593Smuzhiyun 		pr_err("Unable to convert incoming challenge\n");
414*4882a593Smuzhiyun 		goto out;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 	if (initiatorchg_len > 1024) {
417*4882a593Smuzhiyun 		pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
418*4882a593Smuzhiyun 		goto out;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 	if (hex2bin(initiatorchg_binhex, initiatorchg, initiatorchg_len) < 0) {
421*4882a593Smuzhiyun 		pr_err("Malformed CHAP_C\n");
422*4882a593Smuzhiyun 		goto out;
423*4882a593Smuzhiyun 	}
424*4882a593Smuzhiyun 	pr_debug("[server] Got CHAP_C=%s\n", initiatorchg);
425*4882a593Smuzhiyun 	/*
426*4882a593Smuzhiyun 	 * During mutual authentication, the CHAP_C generated by the
427*4882a593Smuzhiyun 	 * initiator must not match the original CHAP_C generated by
428*4882a593Smuzhiyun 	 * the target.
429*4882a593Smuzhiyun 	 */
430*4882a593Smuzhiyun 	if (initiatorchg_len == chap->challenge_len &&
431*4882a593Smuzhiyun 				!memcmp(initiatorchg_binhex, chap->challenge,
432*4882a593Smuzhiyun 				initiatorchg_len)) {
433*4882a593Smuzhiyun 		pr_err("initiator CHAP_C matches target CHAP_C, failing"
434*4882a593Smuzhiyun 		       " login attempt\n");
435*4882a593Smuzhiyun 		goto out;
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun 	/*
438*4882a593Smuzhiyun 	 * Generate CHAP_N and CHAP_R for mutual authentication.
439*4882a593Smuzhiyun 	 */
440*4882a593Smuzhiyun 	ret = crypto_shash_init(desc);
441*4882a593Smuzhiyun 	if (ret < 0) {
442*4882a593Smuzhiyun 		pr_err("crypto_shash_init() failed\n");
443*4882a593Smuzhiyun 		goto out;
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	/* To handle both endiannesses */
447*4882a593Smuzhiyun 	id_as_uchar = id;
448*4882a593Smuzhiyun 	ret = crypto_shash_update(desc, &id_as_uchar, 1);
449*4882a593Smuzhiyun 	if (ret < 0) {
450*4882a593Smuzhiyun 		pr_err("crypto_shash_update() failed for id\n");
451*4882a593Smuzhiyun 		goto out;
452*4882a593Smuzhiyun 	}
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	ret = crypto_shash_update(desc, auth->password_mutual,
455*4882a593Smuzhiyun 				  strlen(auth->password_mutual));
456*4882a593Smuzhiyun 	if (ret < 0) {
457*4882a593Smuzhiyun 		pr_err("crypto_shash_update() failed for"
458*4882a593Smuzhiyun 				" password_mutual\n");
459*4882a593Smuzhiyun 		goto out;
460*4882a593Smuzhiyun 	}
461*4882a593Smuzhiyun 	/*
462*4882a593Smuzhiyun 	 * Convert received challenge to binary hex.
463*4882a593Smuzhiyun 	 */
464*4882a593Smuzhiyun 	ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len,
465*4882a593Smuzhiyun 				 digest);
466*4882a593Smuzhiyun 	if (ret < 0) {
467*4882a593Smuzhiyun 		pr_err("crypto_shash_finup() failed for ma challenge\n");
468*4882a593Smuzhiyun 		goto out;
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	/*
472*4882a593Smuzhiyun 	 * Generate CHAP_N and CHAP_R.
473*4882a593Smuzhiyun 	 */
474*4882a593Smuzhiyun 	*nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual);
475*4882a593Smuzhiyun 	*nr_out_len += 1;
476*4882a593Smuzhiyun 	pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual);
477*4882a593Smuzhiyun 	/*
478*4882a593Smuzhiyun 	 * Convert response from binary hex to ascii hext.
479*4882a593Smuzhiyun 	 */
480*4882a593Smuzhiyun 	bin2hex(response, digest, chap->digest_size);
481*4882a593Smuzhiyun 	*nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
482*4882a593Smuzhiyun 			response);
483*4882a593Smuzhiyun 	*nr_out_len += 1;
484*4882a593Smuzhiyun 	pr_debug("[server] Sending CHAP_R=0x%s\n", response);
485*4882a593Smuzhiyun 	auth_ret = 0;
486*4882a593Smuzhiyun out:
487*4882a593Smuzhiyun 	kfree_sensitive(desc);
488*4882a593Smuzhiyun 	if (tfm)
489*4882a593Smuzhiyun 		crypto_free_shash(tfm);
490*4882a593Smuzhiyun 	kfree(initiatorchg);
491*4882a593Smuzhiyun 	kfree(initiatorchg_binhex);
492*4882a593Smuzhiyun 	kfree(digest);
493*4882a593Smuzhiyun 	kfree(response);
494*4882a593Smuzhiyun 	kfree(server_digest);
495*4882a593Smuzhiyun 	kfree(client_digest);
496*4882a593Smuzhiyun 	return auth_ret;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
chap_main_loop(struct iscsi_conn * conn,struct iscsi_node_auth * auth,char * in_text,char * out_text,int * in_len,int * out_len)499*4882a593Smuzhiyun u32 chap_main_loop(
500*4882a593Smuzhiyun 	struct iscsi_conn *conn,
501*4882a593Smuzhiyun 	struct iscsi_node_auth *auth,
502*4882a593Smuzhiyun 	char *in_text,
503*4882a593Smuzhiyun 	char *out_text,
504*4882a593Smuzhiyun 	int *in_len,
505*4882a593Smuzhiyun 	int *out_len)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	struct iscsi_chap *chap = conn->auth_protocol;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	if (!chap) {
510*4882a593Smuzhiyun 		chap = chap_server_open(conn, auth, in_text, out_text, out_len);
511*4882a593Smuzhiyun 		if (!chap)
512*4882a593Smuzhiyun 			return 2;
513*4882a593Smuzhiyun 		chap->chap_state = CHAP_STAGE_SERVER_AIC;
514*4882a593Smuzhiyun 		return 0;
515*4882a593Smuzhiyun 	} else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
516*4882a593Smuzhiyun 		convert_null_to_semi(in_text, *in_len);
517*4882a593Smuzhiyun 		if (chap_server_compute_hash(conn, auth, in_text, out_text,
518*4882a593Smuzhiyun 				out_len) < 0) {
519*4882a593Smuzhiyun 			chap_close(conn);
520*4882a593Smuzhiyun 			return 2;
521*4882a593Smuzhiyun 		}
522*4882a593Smuzhiyun 		if (auth->authenticate_target)
523*4882a593Smuzhiyun 			chap->chap_state = CHAP_STAGE_SERVER_NR;
524*4882a593Smuzhiyun 		else
525*4882a593Smuzhiyun 			*out_len = 0;
526*4882a593Smuzhiyun 		chap_close(conn);
527*4882a593Smuzhiyun 		return 1;
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	return 2;
531*4882a593Smuzhiyun }
532