xref: /titanic_52/usr/src/uts/common/io/comstar/port/iscsit/iscsit_auth.c (revision 4558d122136f151d62acbbc02ddb42df89a5ef66)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/cpuvar.h>
26 #include <sys/types.h>
27 #include <sys/conf.h>
28 #include <sys/file.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
32 
33 #include <sys/socket.h>
34 #include <sys/strsubr.h>
35 #include <sys/sysmacros.h>
36 
37 #include <sys/stmf.h>
38 #include <sys/stmf_ioctl.h>
39 #include <sys/portif.h>
40 #include <sys/idm/idm.h>
41 #include <sys/idm/idm_text.h>
42 
43 #include "iscsit.h"
44 #include "iscsit_auth.h"
45 
46 static kv_status_t
47 iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp,
48     const idm_kv_xlate_t *ikvx);
49 
50 static kv_status_t
51 auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp,
52     const idm_kv_xlate_t *ikvx);
53 
54 static kv_status_t
55 auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp,
56     const idm_kv_xlate_t *ikvx);
57 
58 static kv_status_t
59 auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp,
60     const idm_kv_xlate_t *ikvx);
61 
62 static kv_status_t
63 auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp,
64     const idm_kv_xlate_t *ikvx);
65 
66 static kv_status_t
67 auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp,
68     const idm_kv_xlate_t *ikvx);
69 
70 static kv_status_t
71 auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp,
72     const idm_kv_xlate_t *ikvx);
73 
74 static kv_status_t
75 iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp,
76     const idm_kv_xlate_t *ikvx);
77 
78 static kv_status_t
79 iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp,
80     const idm_kv_xlate_t *ikvx);
81 
82 static kv_status_t
83 auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp,
84     const idm_kv_xlate_t *ikvx);
85 
86 static kv_status_t
87 auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp,
88     const idm_kv_xlate_t *ikvx);
89 
90 static kv_status_t
91 iscsit_auth_gen_challenge(iscsit_conn_t *ict);
92 
93 static kv_status_t
94 iscsit_auth_gen_response(iscsit_conn_t *ict);
95 
96 typedef struct {
97 	iscsit_auth_phase_t	phase;
98 	iscsikey_id_t		kv_id;
99 	iscsit_auth_handler_t	handler;
100 } auth_phase_entry_t;
101 
102 /*
103  * This table defines all authentication phases which have valid
104  * handler. The entries which have a non-zero key index are for
105  * a key/value pair handling when a key/value is being received,
106  * the rest of entries are for target checking the authentication
107  * phase after all key/value pair(s) are handled.
108  */
109 static const auth_phase_entry_t	apet[] = {
110 	/* by key */
111 	{ AP_AM_UNDECIDED,	KI_AUTH_METHOD,	iscsit_select_auth },
112 	{ AP_AM_PROPOSED,	KI_CHAP_A,	auth_propose_chap  },
113 
114 	{ AP_CHAP_A_WAITING,	KI_CHAP_A,	auth_chap_select_alg },
115 	{ AP_CHAP_R_WAITING,	KI_CHAP_N,	auth_chap_recv_n },
116 	{ AP_CHAP_R_WAITING,	KI_CHAP_R,	auth_chap_recv_r },
117 	{ AP_CHAP_R_WAITING,	KI_CHAP_I,	auth_chap_recv_i },
118 	{ AP_CHAP_R_WAITING,	KI_CHAP_C,	auth_chap_recv_c },
119 	{ AP_CHAP_R_RCVD,	KI_CHAP_N,	auth_chap_recv_n },
120 	{ AP_CHAP_R_RCVD,	KI_CHAP_R,	auth_chap_recv_r },
121 	{ AP_CHAP_R_RCVD,	KI_CHAP_I,	auth_chap_recv_i },
122 	{ AP_CHAP_R_RCVD,	KI_CHAP_C,	auth_chap_recv_c },
123 
124 	/* by target */
125 	{ AP_AM_UNDECIDED,	0,		iscsit_auth_propose },
126 	{ AP_AM_DECIDED,	0,		iscsit_auth_expect_key },
127 
128 	{ AP_CHAP_A_RCVD,	0,		auth_chap_expect_r },
129 	{ AP_CHAP_R_RCVD,	0,		auth_chap_done }
130 };
131 
132 typedef struct {
133 	iscsit_auth_method_t	am_id;
134 	char			*am_name;
135 } auth_id_name_t;
136 
137 /*
138  * a table of mapping from the authentication index to name.
139  */
140 static const auth_id_name_t aint[] = {
141 	{ AM_CHAP,	"CHAP" },
142 	{ AM_NONE,	"None" },
143 	/* { AM_KRB5,	"KRB5" }, */	/* Not supported */
144 	/* { AM_SPKM1,	"SPKM1" }, */	/* Not supported */
145 	/* { AM_SPKM2,	"SPKM2" }, */	/* Not supported */
146 	/* { AM_SRP,	"SRP" },  */	/* Not supported */
147 };
148 
149 #define	ARRAY_LENGTH(ARRAY)	(sizeof (ARRAY) / sizeof (ARRAY[0]))
150 
151 /*
152  * get the authentication method name for the method id.
153  */
154 static const char *
155 am_id_to_name(int id)
156 {
157 	int			i;
158 	const auth_id_name_t	*p;
159 	i = 0;
160 	while (i < ARRAY_LENGTH(aint)) {
161 		p = &(aint[i]);
162 		if (id == p->am_id) {
163 			return (p->am_name);
164 		}
165 		i ++;
166 	}
167 
168 	return (NULL);
169 }
170 
171 /*
172  * Look for an apporiate function handler which is defined for
173  * current authentication phase and matches the key which is
174  * being handled. The key index is passed in as zero when it
175  * is looking for an handler for checking the authentication phase
176  * after all security keys are handled.
177  */
178 iscsit_auth_handler_t
179 iscsit_auth_get_handler(iscsit_auth_client_t *client, iscsikey_id_t kv_id)
180 {
181 	iscsit_auth_phase_t		phase = client->phase;
182 	int				i;
183 	const auth_phase_entry_t	*p;
184 
185 	i = 0;
186 	p = NULL;
187 	while (i < ARRAY_LENGTH(apet)) {
188 		p = &(apet[i]);
189 		if (phase == p->phase &&
190 		    kv_id == p->kv_id) {
191 			return (p->handler);
192 		}
193 		i ++;
194 	}
195 
196 	/* No handler can be found, it must be an invalid requst. */
197 	return (NULL);
198 }
199 
200 /*
201  * Select an authentication method from a list of values proposed
202  * by initiator. After a valid method is selected, shift the
203  * authentication phase to AP_AM_DECIDED.
204  */
205 static kv_status_t
206 iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp,
207     const idm_kv_xlate_t *ikvx)
208 {
209 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
210 	conn_auth_t		*auth = &lsm->icl_auth;
211 	iscsit_auth_method_t	*am_list = &auth->ca_method_valid_list[0];
212 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
213 	int			nvrc;
214 	kv_status_t		kvrc;
215 	nvpair_t		*am_choice;
216 	char			*am;
217 	const char		*am_name;
218 	const char		*text;
219 	iscsit_auth_method_t	am_id;
220 	int			i;
221 
222 	client->phase = AP_AM_DECIDED;
223 
224 	/* select a valid authentication method */
225 	am_choice = idm_get_next_listvalue(nvp, NULL);
226 	while (am_choice != NULL) {
227 		nvrc = nvpair_value_string(am_choice, &am);
228 		ASSERT(nvrc == 0);
229 
230 		i = 0;
231 		am_id = am_list[i];
232 		while (am_id != 0) {
233 			am_name = am_id_to_name(am_id);
234 			if (strcasecmp(am, am_name) == 0) {
235 				text = am;
236 				goto am_decided;
237 			}
238 			i++;
239 			am_id = am_list[i];
240 		}
241 		am_choice = idm_get_next_listvalue(nvp, am_choice);
242 	}
243 
244 	/* none of authentication method is valid */
245 	am_id = 0;
246 	text = ISCSI_TEXT_REJECT;
247 
248 am_decided:
249 	client->negotiatedMethod = am_id;
250 	/* add the selected method to the response nvlist */
251 	nvrc = nvlist_add_string(lsm->icl_response_nvlist,
252 	    ikvx->ik_key_name, text);
253 	kvrc = idm_nvstat_to_kvstat(nvrc);
254 
255 	return (kvrc);
256 }
257 
258 /*
259  * Initiator chooses to use CHAP after target proposed a list of
260  * authentication method. Set the authentication method to CHAP and
261  * continue on chap authentication phase.
262  */
263 static kv_status_t
264 auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp,
265     const idm_kv_xlate_t *ikvx)
266 {
267 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
268 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
269 
270 	client->negotiatedMethod = AM_CHAP;
271 	client->phase = AP_AM_DECIDED;
272 
273 	return (auth_chap_select_alg(ict, nvp, ikvx));
274 }
275 
276 /*
277  * Select a CHAP algorithm from a list of values proposed by
278  * initiator and shift the authentication phase to AP_CHAP_A_RCVD.
279  */
280 static kv_status_t
281 auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp,
282     const idm_kv_xlate_t *ikvx)
283 {
284 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
285 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
286 	int			nvrc, rc;
287 	kv_status_t		kvrc;
288 	nvpair_t		*alg_choice;
289 	char			*alg_string;
290 	uint64_t		alg;
291 	const char		*text;
292 
293 	client->phase = AP_CHAP_A_RCVD;
294 
295 	alg_choice = idm_get_next_listvalue(nvp, NULL);
296 	while (alg_choice != NULL) {
297 		nvrc = nvpair_value_string(alg_choice, &alg_string);
298 		ASSERT(nvrc == 0);
299 		rc = ddi_strtoull(alg_string, NULL, 0, (u_longlong_t *)&alg);
300 		if (rc == 0 && alg == 5) {
301 			/* only MD5 is supported */
302 			text = alg_string;
303 			goto alg_selected;
304 		}
305 
306 		alg_choice = idm_get_next_listvalue(nvp, alg_choice);
307 	}
308 
309 	/* none of algorithm is selected */
310 	alg = 0;
311 	text = ISCSI_TEXT_REJECT;
312 
313 alg_selected:
314 	/* save the selected algorithm or zero for none is selected */
315 	client_set_numeric_data(
316 	    &client->recvKeyBlock,
317 	    AKT_CHAP_A,
318 	    (uint32_t)alg);
319 
320 	/* add the selected algorithm to the response nvlist */
321 	nvrc = nvlist_add_string(lsm->icl_response_nvlist,
322 	    ikvx->ik_key_name, text);
323 	if (alg == 0) {
324 		kvrc = KV_AUTH_FAILED; /* No algorithm selected */
325 	} else {
326 		kvrc = idm_nvstat_to_kvstat(nvrc);
327 		if (kvrc == 0) {
328 			kvrc = iscsit_auth_gen_challenge(ict);
329 		}
330 	}
331 
332 	return (kvrc);
333 }
334 
335 /*
336  * Validate and save the the chap name which is sent by initiator
337  * and shift the authentication phase to AP_CHAP_R_RCVD.
338  *
339  * Note: the CHAP_N, CHAP_R, optionally CHAP_I and CHAP_C key/value
340  * pairs need to be received in one packet, we handle each of them
341  * separately, in order to track the authentication phase, we set
342  * the authentication phase to AP_CHAP_R_RCVD once one of them is
343  * handled. So both of AP_CHAP_R_WAITING and AP_CHAP_R_RCVD phases
344  * are valid for these keys. The function auth_chap_done is going
345  * to detect if any of these keys is missing.
346  */
347 
348 /*ARGSUSED*/
349 static kv_status_t
350 auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp,
351     const idm_kv_xlate_t *ikvx)
352 {
353 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
354 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
355 	int			nvrc;
356 	char			*chap_name;
357 
358 	nvrc = nvpair_value_string(nvp, &chap_name);
359 	ASSERT(nvrc == 0);
360 
361 	client_set_string_data(&client->recvKeyBlock,
362 	    AKT_CHAP_N,
363 	    chap_name);
364 
365 	client->phase = AP_CHAP_R_RCVD;
366 
367 	return (KV_HANDLED);
368 }
369 
370 /*
371  * Validate and save the the chap response which is sent by initiator
372  * and shift the authentication phase to AP_CHAP_R_RCVD.
373  *
374  * Note: see function auth_chap_recv_n.
375  */
376 
377 /*ARGSUSED*/
378 static kv_status_t
379 auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp,
380     const idm_kv_xlate_t *ikvx)
381 {
382 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
383 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
384 	int			nvrc;
385 	unsigned char		*chap_resp;
386 	uint_t			len;
387 
388 	nvrc = nvpair_value_byte_array(nvp, &chap_resp, &len);
389 	ASSERT(nvrc == 0);
390 
391 	client_set_binary_data(&client->recvKeyBlock,
392 	    AKT_CHAP_R,
393 	    chap_resp, len);
394 
395 	client->phase = AP_CHAP_R_RCVD;
396 
397 	return (KV_HANDLED);
398 }
399 
400 /*
401  * Validate and save the the chap identifier which is sent by initiator
402  * and shift the authentication phase to AP_CHAP_R_RCVD.
403  *
404  * Note: see function auth_chap_recv_n.
405  */
406 
407 /*ARGSUSED*/
408 static kv_status_t
409 auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp,
410     const idm_kv_xlate_t *ikvx)
411 {
412 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
413 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
414 	int			nvrc;
415 	uint64_t		chap_id;
416 
417 	nvrc = nvpair_value_uint64(nvp, &chap_id);
418 	ASSERT(nvrc == 0);
419 
420 	client_set_numeric_data(&client->recvKeyBlock,
421 	    AKT_CHAP_I,
422 	    chap_id);
423 
424 	client->phase = AP_CHAP_R_RCVD;
425 
426 	return (KV_HANDLED);
427 }
428 
429 /*
430  * Validate and save the the chap challenge which is sent by initiator
431  * and shift the authentication phase to AP_CHAP_R_RCVD.
432  *
433  * Note: see function auth_chap_recv_n.
434  */
435 
436 /*ARGSUSED*/
437 static kv_status_t
438 auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp,
439     const idm_kv_xlate_t *ikvx)
440 {
441 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
442 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
443 	int			nvrc;
444 	unsigned char		*chap_challenge;
445 	uint_t			len;
446 
447 	nvrc = nvpair_value_byte_array(nvp, &chap_challenge, &len);
448 	ASSERT(nvrc == 0);
449 
450 	client_set_binary_data(
451 	    &client->recvKeyBlock,
452 	    AKT_CHAP_C,
453 	    chap_challenge, len);
454 
455 	client->phase = AP_CHAP_R_RCVD;
456 
457 	return (KV_HANDLED);
458 }
459 
460 /*
461  * Shift the authentication phase to AP_CHAP_R_WAITING after target
462  * has successfully selected a chap algorithm.
463  */
464 
465 /*ARGSUSED*/
466 static kv_status_t
467 auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp,
468     const idm_kv_xlate_t *ikvx)
469 {
470 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
471 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
472 
473 	uint32_t		alg;
474 
475 	client_get_numeric_data(&client->recvKeyBlock,
476 	    AKT_CHAP_A,
477 	    &alg);
478 
479 	if (alg != 0) {
480 		client->phase = AP_CHAP_R_WAITING;
481 	} else {
482 		/* none of proposed algorithm is supported or understood. */
483 		client->phase = AP_CHAP_A_WAITING;
484 	}
485 
486 	return (KV_HANDLED);
487 }
488 
489 /*
490  * Initiator does not propose security negotiation, target needs to
491  * verify if we can bypass the security negotiation phase or propose
492  * a security negotiation for the initiator.
493  */
494 
495 /*ARGSUSED*/
496 static kv_status_t
497 iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp,
498     const idm_kv_xlate_t *ikvx)
499 {
500 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
501 	conn_auth_t		*auth = &lsm->icl_auth;
502 	iscsit_auth_method_t	*am_list = &auth->ca_method_valid_list[0];
503 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
504 
505 	int			nvrc;
506 	kv_status_t		kvrc;
507 	const char		*am_name;
508 
509 	if (am_list[0] == AM_NONE || am_list[0] == 0) {
510 		lsm->icl_auth_pass = 1;
511 	}
512 
513 	if (lsm->icl_auth_pass == 0) {
514 		/*
515 		 * It should be noted that the negotiation might also
516 		 * be directed by the target if the initiator does
517 		 * support security, but is not ready to direct the
518 		 * negotiation (propose options).
519 		 * - RFC3720 section 5.3.2.
520 		 */
521 		am_name = am_id_to_name(am_list[0]);
522 		nvrc = nvlist_add_string(
523 		    lsm->icl_response_nvlist,
524 		    "AuthMethod", am_name);
525 		kvrc = idm_nvstat_to_kvstat(nvrc);
526 
527 		client->phase = AP_AM_PROPOSED;
528 	} else {
529 		kvrc = KV_HANDLED;
530 
531 		client->phase = AP_DONE;
532 	}
533 
534 	return (kvrc);
535 }
536 
537 /*
538  * Shift the authentication phase according to the authentication
539  * method once it is selected.
540  */
541 
542 /*ARGSUSED*/
543 static kv_status_t
544 iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp,
545     const idm_kv_xlate_t *ikvx)
546 {
547 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
548 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
549 
550 	if (client->negotiatedMethod != 0) {
551 		/* Shift security negotiation phase. */
552 		switch (client->negotiatedMethod) {
553 		case AM_CHAP:
554 			client->phase = AP_CHAP_A_WAITING;
555 			break;
556 		case AM_NONE:
557 			client->phase = AP_DONE;
558 			lsm->icl_auth_pass = 1;
559 			break;
560 		default:
561 			ASSERT(0);
562 			break;
563 		}
564 	} else {
565 		/* None of proposed method is supported or understood. */
566 		client->phase = AP_AM_UNDECIDED;
567 	}
568 
569 	return (KV_HANDLED);
570 }
571 
572 /*
573  * The last step of the chap authentication. We will validate the
574  * chap parameters we received and authenticate the client here.
575  */
576 
577 /*ARGSUSED*/
578 static kv_status_t
579 auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp,
580     const idm_kv_xlate_t *ikvx)
581 {
582 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
583 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
584 	kv_status_t		kvrc = KV_HANDLED;
585 
586 	conn_auth_t		*auth = &lsm->icl_auth;
587 	char			*username_in;
588 
589 	uint32_t		chap_id;
590 	unsigned char		*chap_challenge;
591 	unsigned int		challenge_len;
592 	char			*chap_name;
593 	unsigned char		*chap_resp;
594 	unsigned int		resp_len;
595 
596 	int			bi_auth;
597 
598 	username_in = auth->ca_ini_chapuser;
599 	if (username_in[0] == '\0')
600 		return (KV_AUTH_FAILED);
601 
602 	/*
603 	 * Check if we have received a valid list of response keys.
604 	 */
605 	if (!client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_N) ||
606 	    !client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_R) ||
607 	    ((bi_auth =
608 	    client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_I)) ^
609 	    client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_C))) {
610 		return (KV_MISSING_FIELDS);
611 	}
612 
613 	client->phase = AP_DONE;
614 
615 	client_get_string_data(&client->recvKeyBlock,
616 	    AKT_CHAP_N,
617 	    &chap_name);
618 
619 	/* check username */
620 	if (strcmp(username_in, chap_name) != 0) {
621 		return (KV_AUTH_FAILED);
622 	}
623 
624 	client_get_numeric_data(&client->sendKeyBlock,
625 	    AKT_CHAP_I,
626 	    &chap_id);
627 
628 	client_get_binary_data(&client->sendKeyBlock,
629 	    AKT_CHAP_C,
630 	    &chap_challenge, &challenge_len);
631 
632 	client_get_binary_data(&client->recvKeyBlock,
633 	    AKT_CHAP_R,
634 	    &chap_resp, &resp_len);
635 
636 	if (iscsit_verify_chap_resp(lsm,
637 	    chap_id, chap_challenge, challenge_len,
638 	    chap_resp, resp_len) != ISCSI_AUTH_PASSED) {
639 		return (KV_AUTH_FAILED);
640 	}
641 
642 	/* bi-direction authentication is required */
643 	if (bi_auth != 0) {
644 		kvrc = iscsit_auth_gen_response(ict);
645 	}
646 
647 	lsm->icl_auth_pass = 1;
648 
649 	return (kvrc);
650 }
651 
652 static kv_status_t
653 iscsit_auth_gen_challenge(iscsit_conn_t *ict)
654 {
655 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
656 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
657 	int			nvrc;
658 	kv_status_t		kvrc;
659 
660 	unsigned char		idData[1];
661 	unsigned char		*bin;
662 	int			len;
663 
664 	auth_random_set_data(idData, 1);
665 	client_set_numeric_data(&client->sendKeyBlock,
666 	    AKT_CHAP_I,
667 	    idData[0]);
668 
669 	/* send chap identifier */
670 	nvrc = nvlist_add_uint64(
671 	    lsm->icl_response_nvlist,
672 	    "CHAP_I", idData[0]);
673 	kvrc = idm_nvstat_to_kvstat(nvrc);
674 	if (kvrc != 0) {
675 		return (kvrc);
676 	}
677 
678 	bin = &(client->auth_send_binary_block.largeBinary[0]);
679 	len = iscsitAuthChapResponseLength;
680 	auth_random_set_data(bin, len);
681 	client_set_binary_data(&client->sendKeyBlock,
682 	    AKT_CHAP_C,
683 	    bin, len);
684 
685 	/* send chap challenge */
686 	nvrc = nvlist_add_byte_array(
687 	    lsm->icl_response_nvlist,
688 	    "CHAP_C", bin, len);
689 	kvrc = idm_nvstat_to_kvstat(nvrc);
690 
691 	return (kvrc);
692 }
693 
694 static kv_status_t
695 iscsit_auth_gen_response(iscsit_conn_t *ict)
696 {
697 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
698 	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
699 	int			nvrc;
700 	kv_status_t		kvrc;
701 
702 	conn_auth_t		*auth = &lsm->icl_auth;
703 	char			*tgt_username;
704 	uint8_t			*tgt_password;
705 	int			tgt_password_length;
706 
707 	uint32_t		chap_id;
708 	unsigned char		*chap_challenge;
709 	unsigned int		challenge_len;
710 	uchar_t			resp[iscsitAuthChapResponseLength];
711 
712 	tgt_username = auth->ca_tgt_chapuser;
713 	tgt_password = auth->ca_tgt_chapsecret;
714 	tgt_password_length = auth->ca_tgt_chapsecretlen;
715 
716 	/*
717 	 * We can't know in advance whether the initiator will attempt
718 	 * mutual authentication, so now we need to check whether we
719 	 * have a target CHAP secret configured.
720 	 */
721 	if (tgt_password_length == 0) {
722 		return (KV_AUTH_FAILED);
723 	}
724 
725 	client_get_numeric_data(&client->recvKeyBlock,
726 	    AKT_CHAP_I,
727 	    &chap_id);
728 
729 	client_get_binary_data(&client->recvKeyBlock,
730 	    AKT_CHAP_C,
731 	    &chap_challenge, &challenge_len);
732 
733 	client_compute_chap_resp(
734 	    &resp[0],
735 	    chap_id,
736 	    tgt_password, tgt_password_length,
737 	    chap_challenge, challenge_len);
738 
739 	nvrc = nvlist_add_string(
740 	    lsm->icl_response_nvlist,
741 	    "CHAP_N", tgt_username);
742 
743 	if (nvrc == 0) {
744 		nvrc = nvlist_add_byte_array(
745 		    lsm->icl_response_nvlist,
746 		    "CHAP_R", resp, sizeof (resp));
747 	}
748 	kvrc = idm_nvstat_to_kvstat(nvrc);
749 
750 	return (kvrc);
751 }
752