1/*	$OpenBSD: eap.c,v 1.26 2024/03/24 00:05:01 yasuoka 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
43int	 eap_message_send(struct iked *, struct iked_sa *, int, int);
44ssize_t	 eap_add_id_request(struct ibuf *);
45char	*eap_validate_id_response(struct eap_message *);
46int	 eap_mschap(struct iked *, const struct iked_sa *,
47	    struct iked_message *, struct eap_message *);
48
49ssize_t
50eap_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
64char *
65eap_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
88int
89eap_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_buf(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_buf(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_buf(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_buf(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
188int
189eap_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
242int
243eap_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
265int
266eap_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
271int
272eap_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
312int
313eap_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
339int
340eap_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
413int
414eap_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		log_debug("%s: unsupported EAP type %s", __func__,
587		    print_map(eap->eap_type, eap_type_map));
588		return (-1);
589	}
590
591	return (0);
592
593 fail:
594	log_debug("%s: short message", __func__);
595	return (-1);
596}
597