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