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