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