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