xref: /openbsd-src/sbin/iked/eap.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: eap.c,v 1.5 2011/05/27 12:01:02 reyk Exp $	*/
2 /*	$vantronix: eap.c,v 1.12 2010/05/31 11:30:08 reyk Exp $	*/
3 
4 /*
5  * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/socket.h>
24 #include <sys/wait.h>
25 #include <sys/uio.h>
26 
27 #include <netinet/in.h>
28 #include <netinet/ip_ipsp.h>
29 #include <arpa/inet.h>
30 
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <getopt.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <err.h>
39 #include <pwd.h>
40 #include <event.h>
41 
42 #include <openssl/sha.h>
43 #include <openssl/evp.h>
44 
45 #include "iked.h"
46 #include "ikev2.h"
47 #include "eap.h"
48 #include "chap_ms.h"
49 
50 char	*eap_identity_response(struct eap_message *);
51 int	 eap_challenge_request(struct iked *env, struct iked_sa *,
52 	    struct eap_header *);
53 int	 eap_success(struct iked *, struct iked_sa *, struct eap_header *);
54 int	 eap_mschap(struct iked *, struct iked_sa *, struct eap_message *);
55 
56 ssize_t
57 eap_identity_request(struct ibuf *e)
58 {
59 	struct eap_message		*eap;
60 
61 	if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL)
62 		return (-1);
63 	eap->eap_code = EAP_CODE_REQUEST;
64 	eap->eap_id = 0;
65 	eap->eap_length = htobe16(sizeof(*eap));
66 	eap->eap_type = EAP_TYPE_IDENTITY;
67 
68 	return (sizeof(*eap));
69 }
70 
71 char *
72 eap_identity_response(struct eap_message *eap)
73 {
74 	size_t				 len;
75 	char				*str;
76 	u_int8_t			*ptr = (u_int8_t *)eap;
77 
78 	len = betoh16(eap->eap_length) - sizeof(*eap);
79 	ptr += sizeof(*eap);
80 
81 	if (len == 0 || (str = get_string(ptr, len)) == NULL) {
82 		log_info("%s: invalid identity response, length %d",
83 		    __func__, len);
84 		return (NULL);
85 	}
86 	log_debug("%s: identity '%s' length %d", __func__, str, len);
87 	return (str);
88 }
89 
90 int
91 eap_challenge_request(struct iked *env, struct iked_sa *sa,
92     struct eap_header *hdr)
93 {
94 	struct eap_message		*eap;
95 	struct eap_mschap_challenge	*ms;
96 	ssize_t				 len = 0;
97 	const char			*name;
98 	int				 ret = -1;
99 	struct ibuf			*e;
100 
101 	if ((e = ibuf_static()) == NULL)
102 		return (-1);
103 
104 	if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL)
105 		goto done;
106 	eap->eap_code = EAP_CODE_REQUEST;
107 	eap->eap_id = hdr->eap_id + 1;
108 	eap->eap_type = sa->sa_policy->pol_auth.auth_eap;
109 
110 	switch (sa->sa_policy->pol_auth.auth_eap) {
111 	case EAP_TYPE_MSCHAP_V2:
112 		name = IKED_USER;	/* XXX should be user-configurable */
113 		eap->eap_length = htobe16(sizeof(*eap) +
114 		    sizeof(*ms) + strlen(name));
115 
116 		if ((ms = ibuf_advance(e, sizeof(*ms))) == NULL)
117 			return (-1);
118 		ms->msc_opcode = EAP_MSOPCODE_CHALLENGE;
119 		ms->msc_id = eap->eap_id;
120 		ms->msc_length = htobe16(sizeof(*ms) + strlen(name));
121 		ms->msc_valuesize = sizeof(ms->msc_challenge);
122 		arc4random_buf(ms->msc_challenge, sizeof(ms->msc_challenge));
123 		if (ibuf_add(e, name, strlen(name)) == -1)
124 			goto done;
125 		len = betoh16(eap->eap_length);
126 
127 		/* Store the EAP challenge value */
128 		sa->sa_eap.id_type = eap->eap_type;
129 		if ((sa->sa_eap.id_buf = ibuf_new(ms->msc_challenge,
130 		    sizeof(ms->msc_challenge))) == NULL)
131 			goto done;
132 		break;
133 	default:
134 		log_debug("%s: unsupported EAP type %s", __func__,
135 		    print_map(eap->eap_type, eap_type_map));
136 		goto done;
137 	}
138 
139 	ret = ikev2_send_ike_e(env, sa, e,
140 	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
141 
142  done:
143 	ibuf_release(e);
144 
145 	return (ret);
146 }
147 
148 int
149 eap_success(struct iked *env, struct iked_sa *sa, struct eap_header *hdr)
150 {
151 	struct eap_header		*resp;
152 	int				 ret = -1;
153 	struct ibuf			*e;
154 
155 	if ((e = ibuf_static()) == NULL)
156 		return (-1);
157 
158 	if ((resp = ibuf_advance(e, sizeof(*resp))) == NULL)
159 		goto done;
160 	resp->eap_code = EAP_CODE_SUCCESS;
161 	resp->eap_id = hdr->eap_id;
162 	resp->eap_length = htobe16(sizeof(*resp));
163 
164 	ret = ikev2_send_ike_e(env, sa, e,
165 	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
166 
167  done:
168 	ibuf_release(e);
169 
170 	return (ret);
171 }
172 
173 int
174 eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap)
175 {
176 	struct iked_user		*usr;
177 	struct eap_message		*resp;
178 	struct eap_mschap_response	*msr;
179 	struct eap_mschap_peer		*msp;
180 	struct eap_mschap		*ms;
181 	struct eap_mschap_success	*mss;
182 	u_int8_t			*ptr, *pass;
183 	size_t				 len, passlen;
184 	char				*name, *msg;
185 	u_int8_t			 ntresponse[EAP_MSCHAP_NTRESPONSE_SZ];
186 	u_int8_t			 successmsg[EAP_MSCHAP_SUCCESS_SZ];
187 	struct ibuf			*eapmsg = NULL;
188 	int				 ret = -1;
189 
190 	if (!sa_stateok(sa, IKEV2_STATE_EAP)) {
191 		log_debug("%s: unexpected EAP", __func__);
192 		return (0);	/* ignore */
193 	}
194 
195 	if (sa->sa_hdr.sh_initiator) {
196 		log_debug("%s: initiator EAP not supported", __func__);
197 		return (-1);
198 	}
199 
200 	/* Only MSCHAP-V2 */
201 	if (eap->eap_type != EAP_TYPE_MSCHAP_V2) {
202 		log_debug("%s: unsupported type EAP-%s", __func__,
203 		    print_map(eap->eap_type, eap_type_map));
204 		return (-1);
205 	}
206 
207 	if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*ms))) {
208 		log_debug("%s: short message", __func__);
209 		return (-1);
210 	}
211 
212 	ms = (struct eap_mschap *)(eap + 1);
213 	ptr = (u_int8_t *)(eap + 1);
214 
215 	switch (ms->ms_opcode) {
216 	case EAP_MSOPCODE_RESPONSE:
217 		msr = (struct eap_mschap_response *)ms;
218 		if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*msr))) {
219 			log_debug("%s: short response", __func__);
220 			return (-1);
221 		}
222 		ptr += sizeof(*msr);
223 		len = betoh16(eap->eap_length) -
224 		    sizeof(*eap) - sizeof(*msr);
225 		if (len == 0 && sa->sa_eapid != NULL)
226 			name = strdup(sa->sa_eapid);
227 		else
228 			name = get_string(ptr, len);
229 		if (name == NULL) {
230 			log_debug("%s: invalid response name", __func__);
231 			return (-1);
232 		}
233 		if ((usr = user_lookup(env, name)) == NULL) {
234 			log_debug("%s: unknown user '%s'", __func__, name);
235 			free(name);
236 			return (-1);
237 		}
238 		free(name);
239 
240 		if ((pass = string2unicode(usr->usr_pass, &passlen)) == NULL)
241 			return (-1);
242 
243 		msp = &msr->msr_response.resp_peer;
244 		mschap_nt_response(ibuf_data(sa->sa_eap.id_buf),
245 		    msp->msp_challenge, usr->usr_name, strlen(usr->usr_name),
246 		    pass, passlen, ntresponse);
247 
248 		if (memcmp(ntresponse, msp->msp_ntresponse,
249 		    sizeof(ntresponse)) != 0) {
250 			log_debug("%s: '%s' authentication failed", __func__,
251 			    usr->usr_name);
252 			free(pass);
253 
254 			/* XXX should we send an EAP failure packet? */
255 			return (-1);
256 		}
257 
258 		bzero(&successmsg, sizeof(successmsg));
259 		mschap_auth_response(pass, passlen,
260 		    ntresponse, ibuf_data(sa->sa_eap.id_buf),
261 		    msp->msp_challenge, usr->usr_name, strlen(usr->usr_name),
262 		    successmsg);
263 		if ((sa->sa_eapmsk = ibuf_new(NULL, MSCHAP_MSK_SZ)) == NULL) {
264 			log_debug("%s: failed to get MSK", __func__);
265 			free(pass);
266 			return (-1);
267 		}
268 		mschap_msk(pass, passlen, ntresponse,
269 		    ibuf_data(sa->sa_eapmsk));
270 		free(pass);
271 
272 		log_info("%s: '%s' authenticated", __func__, usr->usr_name);
273 
274 
275 		if ((eapmsg = ibuf_static()) == NULL)
276 			return (-1);
277 
278 		msg = " M=Welcome";
279 
280 		if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL)
281 			goto done;
282 		resp->eap_code = EAP_CODE_REQUEST;
283 		resp->eap_id = eap->eap_id + 1;
284 		resp->eap_length = htobe16(sizeof(*resp) + sizeof(*mss) +
285 		    sizeof(successmsg) + strlen(msg));
286 		resp->eap_type = EAP_TYPE_MSCHAP_V2;
287 
288 		if ((mss = ibuf_advance(eapmsg, sizeof(*mss))) == NULL)
289 			goto done;
290 		mss->mss_opcode = EAP_MSOPCODE_SUCCESS;
291 		mss->mss_id = msr->msr_id;
292 		mss->mss_length = htobe16(sizeof(*mss) +
293 		    sizeof(successmsg) + strlen(msg));
294 		if (ibuf_add(eapmsg, successmsg, sizeof(successmsg)) != 0)
295 			goto done;
296 		if (ibuf_add(eapmsg, msg, strlen(msg)) != 0)
297 			goto done;
298 		break;
299 	case EAP_MSOPCODE_SUCCESS:
300 		if ((eapmsg = ibuf_static()) == NULL)
301 			return (-1);
302 		if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL)
303 			goto done;
304 		resp->eap_code = EAP_CODE_RESPONSE;
305 		resp->eap_id = eap->eap_id;
306 		resp->eap_length = htobe16(sizeof(*resp) + sizeof(*ms));
307 		resp->eap_type = EAP_TYPE_MSCHAP_V2;
308 		if ((ms = ibuf_advance(eapmsg, sizeof(*ms))) == NULL)
309 			goto done;
310 		ms->ms_opcode = EAP_MSOPCODE_SUCCESS;
311 		break;
312 	case EAP_MSOPCODE_FAILURE:
313 	case EAP_MSOPCODE_CHANGE_PASSWORD:
314 	case EAP_MSOPCODE_CHALLENGE:
315 	default:
316 		log_debug("%s: EAP-%s unsupported "
317 		    "responder operation %s", __func__,
318 		    print_map(eap->eap_type, eap_type_map),
319 		    print_map(ms->ms_opcode, eap_msopcode_map));
320 		return (-1);
321 	}
322 
323 	if (eapmsg != NULL)
324 		ret = ikev2_send_ike_e(env, sa, eapmsg,
325 		    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
326 
327 	if (ret == 0)
328 		sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS);
329 
330  done:
331 	ibuf_release(eapmsg);
332 	return (ret);
333 }
334 
335 int
336 eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response)
337 {
338 	struct eap_header		*hdr = data;
339 	struct eap_message		*eap = data;
340 	size_t				 len;
341 	u_int8_t			*ptr;
342 	struct eap_mschap		*ms;
343 	struct eap_mschap_challenge	*msc;
344 	struct eap_mschap_response	*msr;
345 	struct eap_mschap_success	*mss;
346 	struct eap_mschap_failure	*msf;
347 	char				*str;
348 
349 	/* length is already verified by the caller */
350 	len = betoh16(hdr->eap_length);
351 	ptr = (u_int8_t *)(eap + 1);
352 
353 	switch (hdr->eap_code) {
354 	case EAP_CODE_REQUEST:
355 	case EAP_CODE_RESPONSE:
356 		if (len < sizeof(*eap)) {
357 			log_debug("%s: short message", __func__);
358 			return (-1);
359 		}
360 		break;
361 	case EAP_CODE_SUCCESS:
362 		return (0);
363 	case EAP_CODE_FAILURE:
364 		if (response)
365 			return (0);
366 		return (-1);
367 	default:
368 		log_debug("%s: unsupported EAP code %s", __func__,
369 		    print_map(hdr->eap_code, eap_code_map));
370 		return (-1);
371 	}
372 
373 	switch (eap->eap_type) {
374 	case EAP_TYPE_IDENTITY:
375 		if (eap->eap_code == EAP_CODE_REQUEST)
376 			break;
377 		if ((str = eap_identity_response(eap)) == NULL)
378 			return (-1);
379 		if (response) {
380 			free(str);
381 			break;
382 		}
383 		if (sa->sa_eapid != NULL) {
384 			free(str);
385 			log_debug("%s: EAP identity already known", __func__);
386 			return (0);
387 		}
388 		sa->sa_eapid = str;
389 		return (eap_challenge_request(env, sa, hdr));
390 	case EAP_TYPE_MSCHAP_V2:
391 		ms = (struct eap_mschap *)ptr;
392 		switch (ms->ms_opcode) {
393 		case EAP_MSOPCODE_CHALLENGE:
394 			msc = (struct eap_mschap_challenge *)ptr;
395 			ptr += sizeof(*msc);
396 			len = betoh16(eap->eap_length) -
397 			    sizeof(*eap) - sizeof(*msc);
398 			if ((str = get_string(ptr, len)) == NULL) {
399 				log_debug("%s: invalid challenge name",
400 				    __func__);
401 				return (-1);
402 			}
403 			log_info("%s: %s %s id %d "
404 			    "length %d valuesize %d name '%s' length %d",
405 			    __func__,
406 			    print_map(eap->eap_type, eap_type_map),
407 			    print_map(ms->ms_opcode, eap_msopcode_map),
408 			    msc->msc_id, betoh16(msc->msc_length),
409 			    msc->msc_valuesize, str, len);
410 			free(str);
411 			print_hex(msc->msc_challenge, 0,
412 			    sizeof(msc->msc_challenge));
413 			break;
414 		case EAP_MSOPCODE_RESPONSE:
415 			msr = (struct eap_mschap_response *)ptr;
416 			ptr += sizeof(*msr);
417 			len = betoh16(eap->eap_length) -
418 			    sizeof(*eap) - sizeof(*msr);
419 			if ((str = get_string(ptr, len)) == NULL) {
420 				log_debug("%s: invalid response name",
421 				    __func__);
422 				return (-1);
423 			}
424 			log_info("%s: %s %s id %d "
425 			    "length %d valuesize %d name '%s' name-length %d",
426 			    __func__,
427 			    print_map(eap->eap_type, eap_type_map),
428 			    print_map(ms->ms_opcode, eap_msopcode_map),
429 			    msr->msr_id, betoh16(msr->msr_length),
430 			    msr->msr_valuesize, str, len);
431 			free(str);
432 			print_hex(msr->msr_response.resp_data, 0,
433 			    sizeof(msr->msr_response.resp_data));
434 			break;
435 		case EAP_MSOPCODE_SUCCESS:
436 			if (eap->eap_code == EAP_CODE_REQUEST) {
437 				mss = (struct eap_mschap_success *)ptr;
438 				ptr += sizeof(*mss);
439 				len = betoh16(eap->eap_length) -
440 				    sizeof(*eap) - sizeof(*mss);
441 				if ((str = get_string(ptr, len)) == NULL) {
442 					log_debug("%s: invalid response name",
443 					    __func__);
444 					return (-1);
445 				}
446 				log_info("%s: %s %s request id %d "
447 				    "length %d message '%s' message-len %d",
448 				    __func__,
449 				    print_map(eap->eap_type, eap_type_map),
450 				    print_map(ms->ms_opcode, eap_msopcode_map),
451 				    mss->mss_id, betoh16(mss->mss_length),
452 				    str, len);
453 				free(str);
454 			} else {
455 				ms = (struct eap_mschap *)ptr;
456 				log_info("%s: %s %s response", __func__,
457 				    print_map(eap->eap_type, eap_type_map),
458 				    print_map(ms->ms_opcode, eap_msopcode_map));
459 				if (response)
460 					break;
461 				if (!sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS))
462 					return (-1);
463 
464 				return (eap_success(env, sa, hdr));
465 			}
466 			break;
467 		case EAP_MSOPCODE_FAILURE:
468 			msf = (struct eap_mschap_failure *)ptr;
469 			ptr += sizeof(*msf);
470 			len = betoh16(eap->eap_length) -
471 			    sizeof(*eap) - sizeof(*msf);
472 			if ((str = get_string(ptr, len)) == NULL) {
473 				log_debug("%s: invalid failure message",
474 				    __func__);
475 				return (-1);
476 			}
477 			log_info("%s: %s %s id %d "
478 			    "length %d message '%s'", __func__,
479 			    print_map(eap->eap_type, eap_type_map),
480 			    print_map(ms->ms_opcode, eap_msopcode_map),
481 			    msf->msf_id, betoh16(msf->msf_length), str);
482 			free(str);
483 			break;
484 		default:
485 			log_info("%s: unknown ms opcode %d", __func__,
486 			    ms->ms_opcode);
487 			return (-1);
488 		}
489 		if (response)
490 			break;
491 
492 		return (eap_mschap(env, sa, eap));
493 	default:
494 		log_debug("%s: unsupported EAP type %s", __func__,
495 		    print_map(eap->eap_type, eap_type_map));
496 		return (-1);
497 	}
498 
499 	return (0);
500 }
501