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