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