xref: /openbsd-src/sbin/iked/eap.c (revision fa353a8f9b716432e67aba95e7a4beea67b6c3b5)
1 /*	$OpenBSD: eap.c,v 1.28 2024/11/21 13:26:49 claudio 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/uio.h>
22 
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <endian.h>
32 #include <errno.h>
33 #include <err.h>
34 #include <event.h>
35 
36 #include <openssl/sha.h>
37 #include <openssl/evp.h>
38 
39 #include "iked.h"
40 #include "ikev2.h"
41 #include "eap.h"
42 
43 int	 eap_message_send(struct iked *, struct iked_sa *, int, int);
44 ssize_t	 eap_add_id_request(struct ibuf *);
45 char	*eap_validate_id_response(struct eap_message *);
46 int	 eap_mschap(struct iked *, const struct iked_sa *,
47 	    struct iked_message *, struct eap_message *);
48 
49 ssize_t
50 eap_add_id_request(struct ibuf *e)
51 {
52 	struct eap_message		*eap;
53 
54 	if ((eap = ibuf_reserve(e, sizeof(*eap))) == NULL)
55 		return (-1);
56 	eap->eap_code = EAP_CODE_REQUEST;
57 	eap->eap_id = 0;
58 	eap->eap_length = htobe16(sizeof(*eap));
59 	eap->eap_type = EAP_TYPE_IDENTITY;
60 
61 	return (sizeof(*eap));
62 }
63 
64 char *
65 eap_validate_id_response(struct eap_message *eap)
66 {
67 	size_t			 len;
68 	char			*str;
69 	uint8_t			*ptr = (uint8_t *)eap;
70 
71 	len = betoh16(eap->eap_length) - sizeof(*eap);
72 	ptr += sizeof(*eap);
73 
74 	if (len == 0) {
75 		if ((str = strdup("")) == NULL) {
76 			log_warn("%s: strdup failed", __func__);
77 			return (NULL);
78 		}
79 	} else if ((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_identity_request(struct iked *env, struct iked_sa *sa)
90 {
91 	struct ikev2_payload		*pld;
92 	struct ikev2_cert		*cert;
93 	struct ikev2_auth		*auth;
94 	struct iked_id			*id, *certid;
95 	struct ibuf			*e = NULL;
96 	uint8_t				 firstpayload;
97 	int				 ret = -1;
98 	ssize_t				 len = 0;
99 	int				 i;
100 
101 	/* Responder only */
102 	if (sa->sa_hdr.sh_initiator)
103 		return (-1);
104 
105 	/* Check if "ca" has done its job yet */
106 	if (!sa->sa_localauth.id_type)
107 		return (0);
108 
109 	/* New encrypted message buffer */
110 	if ((e = ibuf_static()) == NULL)
111 		goto done;
112 
113 	id = &sa->sa_rid;
114 	certid = &sa->sa_rcert;
115 
116 	/* ID payload */
117 	if ((pld = ikev2_add_payload(e)) == NULL)
118 		goto done;
119 	firstpayload = IKEV2_PAYLOAD_IDr;
120 	if (ibuf_add_ibuf(e, id->id_buf) != 0)
121 		goto done;
122 	len = ibuf_size(id->id_buf);
123 
124 	if ((sa->sa_statevalid & IKED_REQ_CERT) &&
125 	    (certid->id_type != IKEV2_CERT_NONE)) {
126 		if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERT) == -1)
127 			goto done;
128 
129 		/* CERT payload */
130 		if ((pld = ikev2_add_payload(e)) == NULL)
131 			goto done;
132 		if ((cert = ibuf_reserve(e, sizeof(*cert))) == NULL)
133 			goto done;
134 		cert->cert_type = certid->id_type;
135 		if (ibuf_add_ibuf(e, certid->id_buf) != 0)
136 			goto done;
137 		len = ibuf_size(certid->id_buf) + sizeof(*cert);
138 
139 		for (i = 0; i < IKED_SCERT_MAX; i++) {
140 			if (sa->sa_scert[i].id_type == IKEV2_CERT_NONE)
141 				break;
142 			if (ikev2_next_payload(pld, len,
143 			    IKEV2_PAYLOAD_CERT) == -1)
144 				goto done;
145 			if ((pld = ikev2_add_payload(e)) == NULL)
146 				goto done;
147 			if ((cert = ibuf_reserve(e, sizeof(*cert))) == NULL)
148 				goto done;
149 			cert->cert_type = sa->sa_scert[i].id_type;
150 			if (ibuf_add_ibuf(e, sa->sa_scert[i].id_buf) != 0)
151 				goto done;
152 			len = ibuf_size(sa->sa_scert[i].id_buf) + sizeof(*cert);
153 		}
154 	}
155 
156 	if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1)
157 		goto done;
158 
159 	/* AUTH payload */
160 	if ((pld = ikev2_add_payload(e)) == NULL)
161 		goto done;
162 	if ((auth = ibuf_reserve(e, sizeof(*auth))) == NULL)
163 		goto done;
164 	auth->auth_method = sa->sa_localauth.id_type;
165 	if (ibuf_add_ibuf(e, sa->sa_localauth.id_buf) != 0)
166 		goto done;
167 	len = ibuf_size(sa->sa_localauth.id_buf) + sizeof(*auth);
168 
169 	if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_EAP) == -1)
170 		goto done;
171 
172 	/* EAP payload */
173 	if ((pld = ikev2_add_payload(e)) == NULL)
174 		goto done;
175 	if ((len = eap_add_id_request(e)) == -1)
176 		goto done;
177 
178 	if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1)
179 		goto done;
180 
181 	ret = ikev2_msg_send_encrypt(env, sa, &e,
182 	    IKEV2_EXCHANGE_IKE_AUTH, firstpayload, 1);
183  done:
184 	ibuf_free(e);
185 	return (ret);
186 }
187 
188 int
189 eap_challenge_request(struct iked *env, struct iked_sa *sa,
190     int eap_id)
191 {
192 	struct eap_message		*eap;
193 	struct eap_mschap_challenge	*ms;
194 	const char			*name;
195 	int				 ret = -1;
196 	struct ibuf			*e;
197 
198 	if ((e = ibuf_static()) == NULL)
199 		return (-1);
200 
201 	if ((eap = ibuf_reserve(e, sizeof(*eap))) == NULL)
202 		goto done;
203 	eap->eap_code = EAP_CODE_REQUEST;
204 	eap->eap_id = eap_id + 1;
205 	eap->eap_type = sa->sa_policy->pol_auth.auth_eap;
206 
207 	switch (sa->sa_policy->pol_auth.auth_eap) {
208 	case EAP_TYPE_MSCHAP_V2:
209 		name = IKED_USER;	/* XXX should be user-configurable */
210 		eap->eap_length = htobe16(sizeof(*eap) +
211 		    sizeof(*ms) + strlen(name));
212 
213 		if ((ms = ibuf_reserve(e, sizeof(*ms))) == NULL)
214 			return (-1);
215 		ms->msc_opcode = EAP_MSOPCODE_CHALLENGE;
216 		ms->msc_id = eap->eap_id;
217 		ms->msc_length = htobe16(sizeof(*ms) + strlen(name));
218 		ms->msc_valuesize = sizeof(ms->msc_challenge);
219 		arc4random_buf(ms->msc_challenge, sizeof(ms->msc_challenge));
220 		if (ibuf_add(e, name, strlen(name)) == -1)
221 			goto done;
222 
223 		/* Store the EAP challenge value */
224 		sa->sa_eap.id_type = eap->eap_type;
225 		if ((sa->sa_eap.id_buf = ibuf_new(ms->msc_challenge,
226 		    sizeof(ms->msc_challenge))) == NULL)
227 			goto done;
228 		break;
229 	default:
230 		log_debug("%s: unsupported EAP type %s", __func__,
231 		    print_map(eap->eap_type, eap_type_map));
232 		goto done;
233 	}
234 
235 	ret = ikev2_send_ike_e(env, sa, e,
236 	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
237  done:
238 	ibuf_free(e);
239 	return (ret);
240 }
241 
242 int
243 eap_message_send(struct iked *env, struct iked_sa *sa, int eap_code, int eap_id)
244 {
245 	struct eap_header		*resp;
246 	int				 ret = -1;
247 	struct ibuf			*e;
248 
249 	if ((e = ibuf_static()) == NULL)
250 		return (-1);
251 
252 	if ((resp = ibuf_reserve(e, sizeof(*resp))) == NULL)
253 		goto done;
254 	resp->eap_code = eap_code;
255 	resp->eap_id = eap_id;
256 	resp->eap_length = htobe16(sizeof(*resp));
257 
258 	ret = ikev2_send_ike_e(env, sa, e,
259 	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
260  done:
261 	ibuf_free(e);
262 	return (ret);
263 }
264 
265 int
266 eap_success(struct iked *env, struct iked_sa *sa, int eap_id)
267 {
268 	return (eap_message_send(env, sa, EAP_CODE_SUCCESS, eap_id));
269 }
270 
271 int
272 eap_mschap_challenge(struct iked *env, struct iked_sa *sa, int eap_id,
273     int msr_id, uint8_t *successmsg, size_t success_size)
274 {
275 	struct ibuf			*eapmsg = NULL;
276 	struct eap_message		*resp;
277 	struct eap_mschap_success	*mss;
278 	char				*msg;
279 	int				 ret = -1;
280 
281 	if ((eapmsg = ibuf_static()) == NULL)
282 		return (-1);
283 
284 	msg = " M=Welcome";
285 
286 	if ((resp = ibuf_reserve(eapmsg, sizeof(*resp))) == NULL)
287 		goto done;
288 	resp->eap_code = EAP_CODE_REQUEST;
289 	resp->eap_id = eap_id + 1;
290 	resp->eap_length = htobe16(sizeof(*resp) + sizeof(*mss) +
291 	    success_size + strlen(msg));
292 	resp->eap_type = EAP_TYPE_MSCHAP_V2;
293 
294 	if ((mss = ibuf_reserve(eapmsg, sizeof(*mss))) == NULL)
295 		goto done;
296 	mss->mss_opcode = EAP_MSOPCODE_SUCCESS;
297 	mss->mss_id = msr_id;
298 	mss->mss_length = htobe16(sizeof(*mss) +
299 	    success_size + strlen(msg));
300 	if (ibuf_add(eapmsg, successmsg, success_size) != 0)
301 		goto done;
302 	if (ibuf_add(eapmsg, msg, strlen(msg)) != 0)
303 		goto done;
304 
305 	ret = ikev2_send_ike_e(env, sa, eapmsg,
306 	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
307  done:
308 	ibuf_free(eapmsg);
309 	return (ret);
310 }
311 
312 int
313 eap_mschap_success(struct iked *env, struct iked_sa *sa, int eap_id)
314 {
315 	struct ibuf			*eapmsg = NULL;
316 	struct eap_message		*resp;
317 	struct eap_mschap		*ms;
318 	int				 ret = -1;
319 
320 	if ((eapmsg = ibuf_static()) == NULL)
321 		return (-1);
322 	if ((resp = ibuf_reserve(eapmsg, sizeof(*resp))) == NULL)
323 		goto done;
324 	resp->eap_code = EAP_CODE_RESPONSE;
325 	resp->eap_id = eap_id;
326 	resp->eap_length = htobe16(sizeof(*resp) + sizeof(*ms));
327 	resp->eap_type = EAP_TYPE_MSCHAP_V2;
328 	if ((ms = ibuf_reserve(eapmsg, sizeof(*ms))) == NULL)
329 		goto done;
330 	ms->ms_opcode = EAP_MSOPCODE_SUCCESS;
331 
332 	ret = ikev2_send_ike_e(env, sa, eapmsg,
333 	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
334  done:
335 	ibuf_free(eapmsg);
336 	return (ret);
337 }
338 
339 int
340 eap_mschap(struct iked *env, const struct iked_sa *sa,
341     struct iked_message *msg, struct eap_message *eap)
342 {
343 	struct eap_mschap_response	*msr;
344 	struct eap_mschap_peer		*msp;
345 	struct eap_mschap		*ms;
346 	uint8_t				*ptr;
347 	size_t				 len;
348 	int				 ret = -1;
349 
350 	if (!sa_stateok(sa, IKEV2_STATE_EAP)) {
351 		log_debug("%s: unexpected EAP", __func__);
352 		return (0);	/* ignore */
353 	}
354 
355 	if (sa->sa_hdr.sh_initiator) {
356 		log_debug("%s: initiator EAP not supported", __func__);
357 		return (-1);
358 	}
359 
360 	/* Only MSCHAP-V2 */
361 	if (eap->eap_type != EAP_TYPE_MSCHAP_V2) {
362 		log_debug("%s: unsupported type EAP-%s", __func__,
363 		    print_map(eap->eap_type, eap_type_map));
364 		return (-1);
365 	}
366 
367 	if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*ms))) {
368 		log_debug("%s: short message", __func__);
369 		return (-1);
370 	}
371 
372 	ms = (struct eap_mschap *)(eap + 1);
373 	ptr = (uint8_t *)(eap + 1);
374 
375 	switch (ms->ms_opcode) {
376 	case EAP_MSOPCODE_RESPONSE:
377 		msr = (struct eap_mschap_response *)ms;
378 		if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*msr))) {
379 			log_debug("%s: short response", __func__);
380 			return (-1);
381 		}
382 		ptr += sizeof(*msr);
383 		len = betoh16(eap->eap_length) -
384 		    sizeof(*eap) - sizeof(*msr);
385 		if (len != 0)
386 			msg->msg_parent->msg_eap.eam_user = get_string(ptr, len);
387 
388 		msg->msg_parent->msg_eap.eam_msrid = msr->msr_id;
389 		msp = &msr->msr_response.resp_peer;
390 		memcpy(msg->msg_parent->msg_eap.eam_challenge,
391 		    msp->msp_challenge, EAP_MSCHAP_CHALLENGE_SZ);
392 		memcpy(msg->msg_parent->msg_eap.eam_ntresponse,
393 		    msp->msp_ntresponse, EAP_MSCHAP_NTRESPONSE_SZ);
394 		msg->msg_parent->msg_eap.eam_state =
395 		    EAP_STATE_MSCHAPV2_CHALLENGE;
396 		return (0);
397 	case EAP_MSOPCODE_SUCCESS:
398 		msg->msg_parent->msg_eap.eam_state = EAP_STATE_MSCHAPV2_SUCCESS;
399 		return (0);
400 	case EAP_MSOPCODE_FAILURE:
401 	case EAP_MSOPCODE_CHANGE_PASSWORD:
402 	case EAP_MSOPCODE_CHALLENGE:
403 	default:
404 		log_debug("%s: EAP-%s unsupported "
405 		    "responder operation %s", __func__,
406 		    print_map(eap->eap_type, eap_type_map),
407 		    print_map(ms->ms_opcode, eap_msopcode_map));
408 		return (-1);
409 	}
410 	return (ret);
411 }
412 
413 int
414 eap_parse(struct iked *env, const struct iked_sa *sa, struct iked_message *msg,
415     void *data, int response)
416 {
417 	struct eap_header		*hdr = data;
418 	struct eap_message		*eap = data;
419 	size_t				 len;
420 	uint8_t				*ptr;
421 	struct eap_mschap		*ms;
422 	struct eap_mschap_challenge	*msc;
423 	struct eap_mschap_response	*msr;
424 	struct eap_mschap_success	*mss;
425 	struct eap_mschap_failure	*msf;
426 	char				*str;
427 
428 	/* length is already verified by the caller against sizeof(eap) */
429 	len = betoh16(hdr->eap_length);
430 	if (len < sizeof(*eap))
431 		goto fail;
432 	ptr = (uint8_t *)(eap + 1);
433 	len -= sizeof(*eap);
434 
435 	switch (hdr->eap_code) {
436 	case EAP_CODE_REQUEST:
437 	case EAP_CODE_RESPONSE:
438 		break;
439 	case EAP_CODE_SUCCESS:
440 		return (0);
441 	case EAP_CODE_FAILURE:
442 		if (response)
443 			return (0);
444 		return (-1);
445 	default:
446 		log_debug("%s: unsupported EAP code %s", __func__,
447 		    print_map(hdr->eap_code, eap_code_map));
448 		return (-1);
449 	}
450 
451 	msg->msg_parent->msg_eap.eam_id = hdr->eap_id;
452 	msg->msg_parent->msg_eap.eam_type = eap->eap_type;
453 
454 	switch (eap->eap_type) {
455 	case EAP_TYPE_IDENTITY:
456 		if (eap->eap_code == EAP_CODE_REQUEST)
457 			break;
458 		if ((str = eap_validate_id_response(eap)) == NULL)
459 			return (-1);
460 		if (response) {
461 			free(str);
462 			break;
463 		}
464 		if (sa->sa_eapid != NULL) {
465 			free(str);
466 			log_debug("%s: EAP identity already known", __func__);
467 			return (0);
468 		}
469 		msg->msg_parent->msg_eap.eam_response = 1;
470 		msg->msg_parent->msg_eap.eam_identity = str;
471 		msg->msg_parent->msg_eap.eam_state =
472 		    EAP_STATE_IDENTITY;
473 		return (0);
474 	case EAP_TYPE_MSCHAP_V2:
475 		if (len < sizeof(*ms))
476 			goto fail;
477 		ms = (struct eap_mschap *)ptr;
478 		switch (ms->ms_opcode) {
479 		case EAP_MSOPCODE_CHALLENGE:
480 			if (len < sizeof(*msc))
481 				goto fail;
482 			msc = (struct eap_mschap_challenge *)ptr;
483 			ptr += sizeof(*msc);
484 			len -= sizeof(*msc);
485 			if ((str = get_string(ptr, len)) == NULL) {
486 				log_debug("%s: invalid challenge name",
487 				    __func__);
488 				return (-1);
489 			}
490 			log_info("%s: %s %s id %d "
491 			    "length %d valuesize %d name '%s' length %zu",
492 			    SPI_SA(sa, __func__),
493 			    print_map(eap->eap_type, eap_type_map),
494 			    print_map(ms->ms_opcode, eap_msopcode_map),
495 			    msc->msc_id, betoh16(msc->msc_length),
496 			    msc->msc_valuesize, str, len);
497 			free(str);
498 			print_hex(msc->msc_challenge, 0,
499 			    sizeof(msc->msc_challenge));
500 			break;
501 		case EAP_MSOPCODE_RESPONSE:
502 			if (len < sizeof(*msr))
503 				goto fail;
504 			msr = (struct eap_mschap_response *)ptr;
505 			ptr += sizeof(*msr);
506 			len -= sizeof(*msr);
507 			if ((str = get_string(ptr, len)) == NULL) {
508 				log_debug("%s: invalid response name",
509 				    __func__);
510 				return (-1);
511 			}
512 			log_info("%s: %s %s id %d "
513 			    "length %d valuesize %d name '%s' name-length %zu",
514 			    __func__,
515 			    print_map(eap->eap_type, eap_type_map),
516 			    print_map(ms->ms_opcode, eap_msopcode_map),
517 			    msr->msr_id, betoh16(msr->msr_length),
518 			    msr->msr_valuesize, str, len);
519 			free(str);
520 			print_hex(msr->msr_response.resp_data, 0,
521 			    sizeof(msr->msr_response.resp_data));
522 			break;
523 		case EAP_MSOPCODE_SUCCESS:
524 			if (eap->eap_code == EAP_CODE_REQUEST) {
525 				if (len < sizeof(*mss))
526 					goto fail;
527 				mss = (struct eap_mschap_success *)ptr;
528 				ptr += sizeof(*mss);
529 				len -= sizeof(*mss);
530 				if ((str = get_string(ptr, len)) == NULL) {
531 					log_debug("%s: invalid response name",
532 					    __func__);
533 					return (-1);
534 				}
535 				log_info("%s: %s %s request id %d "
536 				    "length %d message '%s' message-len %zu",
537 				    __func__,
538 				    print_map(eap->eap_type, eap_type_map),
539 				    print_map(ms->ms_opcode, eap_msopcode_map),
540 				    mss->mss_id, betoh16(mss->mss_length),
541 				    str, len);
542 				free(str);
543 			} else {
544 				if (len < sizeof(*ms))
545 					goto fail;
546 				ms = (struct eap_mschap *)ptr;
547 				log_info("%s: %s %s response", __func__,
548 				    print_map(eap->eap_type, eap_type_map),
549 				    print_map(ms->ms_opcode, eap_msopcode_map));
550 				if (response)
551 					break;
552 				msg->msg_parent->msg_eap.eam_success = 1;
553 				msg->msg_parent->msg_eap.eam_state =
554 				    EAP_STATE_SUCCESS;
555 				return (0);
556 			}
557 			break;
558 		case EAP_MSOPCODE_FAILURE:
559 			if (len < sizeof(*msf))
560 				goto fail;
561 			msf = (struct eap_mschap_failure *)ptr;
562 			ptr += sizeof(*msf);
563 			len -= sizeof(*msf);
564 			if ((str = get_string(ptr, len)) == NULL) {
565 				log_debug("%s: invalid failure message",
566 				    __func__);
567 				return (-1);
568 			}
569 			log_info("%s: %s %s id %d "
570 			    "length %d message '%s'", __func__,
571 			    print_map(eap->eap_type, eap_type_map),
572 			    print_map(ms->ms_opcode, eap_msopcode_map),
573 			    msf->msf_id, betoh16(msf->msf_length), str);
574 			free(str);
575 			break;
576 		default:
577 			log_info("%s: unknown ms opcode %d", __func__,
578 			    ms->ms_opcode);
579 			return (-1);
580 		}
581 		if (response)
582 			break;
583 
584 		return (eap_mschap(env, sa, msg, eap));
585 	default:
586 		if (sa->sa_policy->pol_auth.auth_eap != EAP_TYPE_RADIUS) {
587 			log_debug("%s: unsupported EAP type %s", __func__,
588 			    print_map(eap->eap_type, eap_type_map));
589 			return (-1);
590 		} /* else, when RADIUS, pass it to the client */
591 		break;
592 	}
593 
594 	return (0);
595 
596  fail:
597 	log_debug("%s: short message", __func__);
598 	return (-1);
599 }
600