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