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