xref: /openbsd/sbin/iked/eap.c (revision 4cfece93)
1 /*	$OpenBSD: eap.c,v 1.15 2020/06/18 19:55:03 tobhe 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 against sizeof(eap) */
343 	len = betoh16(hdr->eap_length);
344 	if (len < sizeof(*eap))
345 		goto fail;
346 	ptr = (uint8_t *)(eap + 1);
347 	len -= sizeof(*eap);
348 
349 	switch (hdr->eap_code) {
350 	case EAP_CODE_REQUEST:
351 	case EAP_CODE_RESPONSE:
352 		break;
353 	case EAP_CODE_SUCCESS:
354 		return (0);
355 	case EAP_CODE_FAILURE:
356 		if (response)
357 			return (0);
358 		return (-1);
359 	default:
360 		log_debug("%s: unsupported EAP code %s", __func__,
361 		    print_map(hdr->eap_code, eap_code_map));
362 		return (-1);
363 	}
364 
365 	switch (eap->eap_type) {
366 	case EAP_TYPE_IDENTITY:
367 		if (eap->eap_code == EAP_CODE_REQUEST)
368 			break;
369 		if ((str = eap_identity_response(eap)) == NULL)
370 			return (-1);
371 		if (response) {
372 			free(str);
373 			break;
374 		}
375 		if (sa->sa_eapid != NULL) {
376 			free(str);
377 			log_debug("%s: EAP identity already known", __func__);
378 			return (0);
379 		}
380 		sa->sa_eapid = str;
381 		return (eap_challenge_request(env, sa, hdr));
382 	case EAP_TYPE_MSCHAP_V2:
383 		if (len < sizeof(*ms))
384 			goto fail;
385 		ms = (struct eap_mschap *)ptr;
386 		switch (ms->ms_opcode) {
387 		case EAP_MSOPCODE_CHALLENGE:
388 			if (len < sizeof(*msc))
389 				goto fail;
390 			msc = (struct eap_mschap_challenge *)ptr;
391 			ptr += sizeof(*msc);
392 			len -= sizeof(*msc);
393 			if ((str = get_string(ptr, len)) == NULL) {
394 				log_debug("%s: invalid challenge name",
395 				    __func__);
396 				return (-1);
397 			}
398 			log_info("%s: %s %s id %d "
399 			    "length %d valuesize %d name '%s' length %zu",
400 			    __func__,
401 			    print_map(eap->eap_type, eap_type_map),
402 			    print_map(ms->ms_opcode, eap_msopcode_map),
403 			    msc->msc_id, betoh16(msc->msc_length),
404 			    msc->msc_valuesize, str, len);
405 			free(str);
406 			print_hex(msc->msc_challenge, 0,
407 			    sizeof(msc->msc_challenge));
408 			break;
409 		case EAP_MSOPCODE_RESPONSE:
410 			if (len < sizeof(*msr))
411 				goto fail;
412 			msr = (struct eap_mschap_response *)ptr;
413 			ptr += sizeof(*msr);
414 			len -= 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 				if (len < sizeof(*mss))
434 					goto fail;
435 				mss = (struct eap_mschap_success *)ptr;
436 				ptr += sizeof(*mss);
437 				len -= sizeof(*mss);
438 				if ((str = get_string(ptr, len)) == NULL) {
439 					log_debug("%s: invalid response name",
440 					    __func__);
441 					return (-1);
442 				}
443 				log_info("%s: %s %s request id %d "
444 				    "length %d message '%s' message-len %zu",
445 				    __func__,
446 				    print_map(eap->eap_type, eap_type_map),
447 				    print_map(ms->ms_opcode, eap_msopcode_map),
448 				    mss->mss_id, betoh16(mss->mss_length),
449 				    str, len);
450 				free(str);
451 			} else {
452 				if (len < sizeof(*ms))
453 					goto fail;
454 				ms = (struct eap_mschap *)ptr;
455 				log_info("%s: %s %s response", __func__,
456 				    print_map(eap->eap_type, eap_type_map),
457 				    print_map(ms->ms_opcode, eap_msopcode_map));
458 				if (response)
459 					break;
460 				if (!sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS))
461 					return (-1);
462 
463 				return (eap_success(env, sa, hdr));
464 			}
465 			break;
466 		case EAP_MSOPCODE_FAILURE:
467 			if (len < sizeof(*msf))
468 				goto fail;
469 			msf = (struct eap_mschap_failure *)ptr;
470 			ptr += sizeof(*msf);
471 			len -= 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  fail:
502 	log_debug("%s: short message", __func__);
503 	return (-1);
504 }
505