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
chap_get_digest_name(const int digest_type)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
chap_gen_challenge(struct iscsit_conn * conn,int caller,char * c_str,unsigned int * c_len)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
chap_test_algorithm(const char * name)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
chap_check_algorithm(const char * a_str)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
chap_close(struct iscsit_conn * conn)132 static void chap_close(struct iscsit_conn *conn)
133 {
134 kfree(conn->auth_protocol);
135 conn->auth_protocol = NULL;
136 }
137
chap_server_open(struct iscsit_conn * conn,struct iscsi_node_auth * auth,const char * a_str,char * aic_str,unsigned int * aic_len)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
chap_base64_decode(u8 * dst,const char * src,size_t len)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
chap_server_compute_hash(struct iscsit_conn * conn,struct iscsi_node_auth * auth,char * nr_in_ptr,char * nr_out_ptr,unsigned int * nr_out_len)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
chap_main_loop(struct iscsit_conn * conn,struct iscsi_node_auth * auth,char * in_text,char * out_text,int * in_len,int * out_len)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