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
eap_add_id_request(struct ibuf * e)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 *
eap_validate_id_response(struct eap_message * eap)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
eap_identity_request(struct iked * env,struct iked_sa * sa)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
eap_challenge_request(struct iked * env,struct iked_sa * sa,int eap_id)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
eap_message_send(struct iked * env,struct iked_sa * sa,int eap_code,int eap_id)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
eap_success(struct iked * env,struct iked_sa * sa,int eap_id)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
eap_mschap_challenge(struct iked * env,struct iked_sa * sa,int eap_id,int msr_id,uint8_t * successmsg,size_t success_size)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
eap_mschap_success(struct iked * env,struct iked_sa * sa,int eap_id)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
eap_mschap(struct iked * env,const struct iked_sa * sa,struct iked_message * msg,struct eap_message * eap)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
eap_parse(struct iked * env,const struct iked_sa * sa,struct iked_message * msg,void * data,int response)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