hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/target/iscsi/iscsi_target_auth.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*******************************************************************************
23 * This file houses the main functions for the iSCSI CHAP support
34 *
....@@ -5,15 +6,6 @@
56 *
67 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
78 *
8
- * This program is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version.
12
- *
13
- * This program is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
179 ******************************************************************************/
1810
1911 #include <crypto/hash.h>
....@@ -26,6 +18,22 @@
2618 #include "iscsi_target_nego.h"
2719 #include "iscsi_target_auth.h"
2820
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
+
2937 static int chap_gen_challenge(
3038 struct iscsi_conn *conn,
3139 int caller,
....@@ -33,16 +41,21 @@
3341 unsigned int *c_len)
3442 {
3543 int ret;
36
- unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
44
+ unsigned char *challenge_asciihex;
3745 struct iscsi_chap *chap = conn->auth_protocol;
3846
39
- memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
47
+ challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL);
48
+ if (!challenge_asciihex)
49
+ return -ENOMEM;
4050
41
- ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH);
51
+ memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN);
52
+
53
+ ret = get_random_bytes_wait(chap->challenge, chap->challenge_len);
4254 if (unlikely(ret))
43
- return ret;
55
+ goto out;
56
+
4457 bin2hex(challenge_asciihex, chap->challenge,
45
- CHAP_CHALLENGE_LENGTH);
58
+ chap->challenge_len);
4659 /*
4760 * Set CHAP_C, and copy the generated challenge into c_str.
4861 */
....@@ -51,12 +64,29 @@
5164
5265 pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
5366 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);
5482 return 0;
5583 }
5684
5785 static int chap_check_algorithm(const char *a_str)
5886 {
59
- char *tmp, *orig, *token;
87
+ char *tmp, *orig, *token, *digest_name;
88
+ long digest_type;
89
+ int r = CHAP_DIGEST_UNKNOWN;
6090
6191 tmp = kstrdup(a_str, GFP_KERNEL);
6292 if (!tmp) {
....@@ -78,15 +108,24 @@
78108 if (!token)
79109 goto out;
80110
81
- if (!strcmp(token, "5")) {
82
- pr_debug("Selected MD5 Algorithm\n");
83
- kfree(orig);
84
- return CHAP_DIGEST_MD5;
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;
85124 }
86125 }
87126 out:
88127 kfree(orig);
89
- return CHAP_DIGEST_UNKNOWN;
128
+ return r;
90129 }
91130
92131 static void chap_close(struct iscsi_conn *conn)
....@@ -102,7 +141,7 @@
102141 char *aic_str,
103142 unsigned int *aic_len)
104143 {
105
- int ret;
144
+ int digest_type;
106145 struct iscsi_chap *chap;
107146
108147 if (!(auth->naf_flags & NAF_USERID_SET) ||
....@@ -117,17 +156,19 @@
117156 return NULL;
118157
119158 chap = conn->auth_protocol;
120
- ret = chap_check_algorithm(a_str);
121
- switch (ret) {
159
+ digest_type = chap_check_algorithm(a_str);
160
+ switch (digest_type) {
122161 case CHAP_DIGEST_MD5:
123
- pr_debug("[server] Got CHAP_A=5\n");
124
- /*
125
- * Send back CHAP_A set to MD5.
126
- */
127
- *aic_len = sprintf(aic_str, "CHAP_A=5");
128
- *aic_len += 1;
129
- chap->digest_type = CHAP_DIGEST_MD5;
130
- pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
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;
131172 break;
132173 case CHAP_DIGEST_UNKNOWN:
133174 default:
....@@ -135,6 +176,16 @@
135176 chap_close(conn);
136177 return NULL;
137178 }
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);
138189
139190 /*
140191 * Set Identifier.
....@@ -154,7 +205,7 @@
154205 return chap;
155206 }
156207
157
-static int chap_server_compute_md5(
208
+static int chap_server_compute_hash(
158209 struct iscsi_conn *conn,
159210 struct iscsi_node_auth *auth,
160211 char *nr_in_ptr,
....@@ -163,36 +214,57 @@
163214 {
164215 unsigned long id;
165216 unsigned char id_as_uchar;
166
- unsigned char digest[MD5_SIGNATURE_SIZE];
167
- unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2];
168
- unsigned char identifier[10], *challenge = NULL;
169
- unsigned char *challenge_binhex = NULL;
170
- unsigned char client_digest[MD5_SIGNATURE_SIZE];
171
- unsigned char server_digest[MD5_SIGNATURE_SIZE];
217
+ unsigned char type;
218
+ unsigned char identifier[10], *initiatorchg = NULL;
219
+ unsigned char *initiatorchg_binhex = NULL;
220
+ unsigned char *digest = NULL;
221
+ unsigned char *response = NULL;
222
+ unsigned char *client_digest = NULL;
223
+ unsigned char *server_digest = NULL;
172224 unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
173225 size_t compare_len;
174226 struct iscsi_chap *chap = conn->auth_protocol;
175227 struct crypto_shash *tfm = NULL;
176228 struct shash_desc *desc = NULL;
177
- int auth_ret = -1, ret, challenge_len;
229
+ int auth_ret = -1, ret, initiatorchg_len;
230
+
231
+ digest = kzalloc(chap->digest_size, GFP_KERNEL);
232
+ if (!digest) {
233
+ pr_err("Unable to allocate the digest buffer\n");
234
+ goto out;
235
+ }
236
+
237
+ response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL);
238
+ if (!response) {
239
+ pr_err("Unable to allocate the response buffer\n");
240
+ goto out;
241
+ }
242
+
243
+ client_digest = kzalloc(chap->digest_size, GFP_KERNEL);
244
+ if (!client_digest) {
245
+ pr_err("Unable to allocate the client_digest buffer\n");
246
+ goto out;
247
+ }
248
+
249
+ server_digest = kzalloc(chap->digest_size, GFP_KERNEL);
250
+ if (!server_digest) {
251
+ pr_err("Unable to allocate the server_digest buffer\n");
252
+ goto out;
253
+ }
178254
179255 memset(identifier, 0, 10);
180256 memset(chap_n, 0, MAX_CHAP_N_SIZE);
181257 memset(chap_r, 0, MAX_RESPONSE_LENGTH);
182
- memset(digest, 0, MD5_SIGNATURE_SIZE);
183
- memset(response, 0, MD5_SIGNATURE_SIZE * 2 + 2);
184
- memset(client_digest, 0, MD5_SIGNATURE_SIZE);
185
- memset(server_digest, 0, MD5_SIGNATURE_SIZE);
186258
187
- challenge = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
188
- if (!challenge) {
259
+ initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
260
+ if (!initiatorchg) {
189261 pr_err("Unable to allocate challenge buffer\n");
190262 goto out;
191263 }
192264
193
- challenge_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
194
- if (!challenge_binhex) {
195
- pr_err("Unable to allocate challenge_binhex buffer\n");
265
+ initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
266
+ if (!initiatorchg_binhex) {
267
+ pr_err("Unable to allocate initiatorchg_binhex buffer\n");
196268 goto out;
197269 }
198270 /*
....@@ -227,18 +299,18 @@
227299 pr_err("Could not find CHAP_R.\n");
228300 goto out;
229301 }
230
- if (strlen(chap_r) != MD5_SIGNATURE_SIZE * 2) {
302
+ if (strlen(chap_r) != chap->digest_size * 2) {
231303 pr_err("Malformed CHAP_R\n");
232304 goto out;
233305 }
234
- if (hex2bin(client_digest, chap_r, MD5_SIGNATURE_SIZE) < 0) {
306
+ if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) {
235307 pr_err("Malformed CHAP_R\n");
236308 goto out;
237309 }
238310
239311 pr_debug("[server] Got CHAP_R=%s\n", chap_r);
240312
241
- tfm = crypto_alloc_shash("md5", 0, 0);
313
+ tfm = crypto_alloc_shash(chap->digest_name, 0, 0);
242314 if (IS_ERR(tfm)) {
243315 tfm = NULL;
244316 pr_err("Unable to allocate struct crypto_shash\n");
....@@ -252,7 +324,6 @@
252324 }
253325
254326 desc->tfm = tfm;
255
- desc->flags = 0;
256327
257328 ret = crypto_shash_init(desc);
258329 if (ret < 0) {
....@@ -274,21 +345,23 @@
274345 }
275346
276347 ret = crypto_shash_finup(desc, chap->challenge,
277
- CHAP_CHALLENGE_LENGTH, server_digest);
348
+ chap->challenge_len, server_digest);
278349 if (ret < 0) {
279350 pr_err("crypto_shash_finup() failed for challenge\n");
280351 goto out;
281352 }
282353
283
- bin2hex(response, server_digest, MD5_SIGNATURE_SIZE);
284
- pr_debug("[server] MD5 Server Digest: %s\n", response);
354
+ bin2hex(response, server_digest, chap->digest_size);
355
+ pr_debug("[server] %s Server Digest: %s\n",
356
+ chap->digest_name, response);
285357
286
- if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) {
287
- pr_debug("[server] MD5 Digests do not match!\n\n");
358
+ if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
359
+ pr_debug("[server] %s Digests do not match!\n\n",
360
+ chap->digest_name);
288361 goto out;
289362 } else
290
- pr_debug("[server] MD5 Digests match, CHAP connection"
291
- " successful.\n\n");
363
+ pr_debug("[server] %s Digests match, CHAP connection"
364
+ " successful.\n\n", chap->digest_name);
292365 /*
293366 * One way authentication has succeeded, return now if mutual
294367 * authentication is not enabled.
....@@ -326,7 +399,7 @@
326399 * Get CHAP_C.
327400 */
328401 if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
329
- challenge, &type) < 0) {
402
+ initiatorchg, &type) < 0) {
330403 pr_err("Could not find CHAP_C.\n");
331404 goto out;
332405 }
....@@ -335,26 +408,28 @@
335408 pr_err("Could not find CHAP_C.\n");
336409 goto out;
337410 }
338
- challenge_len = DIV_ROUND_UP(strlen(challenge), 2);
339
- if (!challenge_len) {
411
+ initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2);
412
+ if (!initiatorchg_len) {
340413 pr_err("Unable to convert incoming challenge\n");
341414 goto out;
342415 }
343
- if (challenge_len > 1024) {
416
+ if (initiatorchg_len > 1024) {
344417 pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
345418 goto out;
346419 }
347
- if (hex2bin(challenge_binhex, challenge, challenge_len) < 0) {
420
+ if (hex2bin(initiatorchg_binhex, initiatorchg, initiatorchg_len) < 0) {
348421 pr_err("Malformed CHAP_C\n");
349422 goto out;
350423 }
351
- pr_debug("[server] Got CHAP_C=%s\n", challenge);
424
+ pr_debug("[server] Got CHAP_C=%s\n", initiatorchg);
352425 /*
353426 * During mutual authentication, the CHAP_C generated by the
354427 * initiator must not match the original CHAP_C generated by
355428 * the target.
356429 */
357
- if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) {
430
+ if (initiatorchg_len == chap->challenge_len &&
431
+ !memcmp(initiatorchg_binhex, chap->challenge,
432
+ initiatorchg_len)) {
358433 pr_err("initiator CHAP_C matches target CHAP_C, failing"
359434 " login attempt\n");
360435 goto out;
....@@ -386,7 +461,7 @@
386461 /*
387462 * Convert received challenge to binary hex.
388463 */
389
- ret = crypto_shash_finup(desc, challenge_binhex, challenge_len,
464
+ ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len,
390465 digest);
391466 if (ret < 0) {
392467 pr_err("crypto_shash_finup() failed for ma challenge\n");
....@@ -402,41 +477,23 @@
402477 /*
403478 * Convert response from binary hex to ascii hext.
404479 */
405
- bin2hex(response, digest, MD5_SIGNATURE_SIZE);
480
+ bin2hex(response, digest, chap->digest_size);
406481 *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
407482 response);
408483 *nr_out_len += 1;
409484 pr_debug("[server] Sending CHAP_R=0x%s\n", response);
410485 auth_ret = 0;
411486 out:
412
- kzfree(desc);
487
+ kfree_sensitive(desc);
413488 if (tfm)
414489 crypto_free_shash(tfm);
415
- kfree(challenge);
416
- kfree(challenge_binhex);
490
+ kfree(initiatorchg);
491
+ kfree(initiatorchg_binhex);
492
+ kfree(digest);
493
+ kfree(response);
494
+ kfree(server_digest);
495
+ kfree(client_digest);
417496 return auth_ret;
418
-}
419
-
420
-static int chap_got_response(
421
- struct iscsi_conn *conn,
422
- struct iscsi_node_auth *auth,
423
- char *nr_in_ptr,
424
- char *nr_out_ptr,
425
- unsigned int *nr_out_len)
426
-{
427
- struct iscsi_chap *chap = conn->auth_protocol;
428
-
429
- switch (chap->digest_type) {
430
- case CHAP_DIGEST_MD5:
431
- if (chap_server_compute_md5(conn, auth, nr_in_ptr,
432
- nr_out_ptr, nr_out_len) < 0)
433
- return -1;
434
- return 0;
435
- default:
436
- pr_err("Unknown CHAP digest type %d!\n",
437
- chap->digest_type);
438
- return -1;
439
- }
440497 }
441498
442499 u32 chap_main_loop(
....@@ -457,7 +514,7 @@
457514 return 0;
458515 } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
459516 convert_null_to_semi(in_text, *in_len);
460
- if (chap_got_response(conn, auth, in_text, out_text,
517
+ if (chap_server_compute_hash(conn, auth, in_text, out_text,
461518 out_len) < 0) {
462519 chap_close(conn);
463520 return 2;