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