1 /* $OpenBSD: eap.c,v 1.15 2020/06/18 19:55:03 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/wait.h> 22 #include <sys/uio.h> 23 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 27 #include <stdlib.h> 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <signal.h> 32 #include <errno.h> 33 #include <err.h> 34 #include <pwd.h> 35 #include <event.h> 36 37 #include <openssl/sha.h> 38 #include <openssl/evp.h> 39 40 #include "iked.h" 41 #include "ikev2.h" 42 #include "eap.h" 43 #include "chap_ms.h" 44 45 char *eap_identity_response(struct eap_message *); 46 int eap_challenge_request(struct iked *env, struct iked_sa *, 47 struct eap_header *); 48 int eap_success(struct iked *, struct iked_sa *, struct eap_header *); 49 int eap_mschap(struct iked *, struct iked_sa *, struct eap_message *); 50 51 ssize_t 52 eap_identity_request(struct ibuf *e) 53 { 54 struct eap_message *eap; 55 56 if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL) 57 return (-1); 58 eap->eap_code = EAP_CODE_REQUEST; 59 eap->eap_id = 0; 60 eap->eap_length = htobe16(sizeof(*eap)); 61 eap->eap_type = EAP_TYPE_IDENTITY; 62 63 return (sizeof(*eap)); 64 } 65 66 char * 67 eap_identity_response(struct eap_message *eap) 68 { 69 size_t len; 70 char *str; 71 uint8_t *ptr = (uint8_t *)eap; 72 73 len = betoh16(eap->eap_length) - sizeof(*eap); 74 ptr += sizeof(*eap); 75 76 if (len == 0 || (str = get_string(ptr, len)) == NULL) { 77 log_info("%s: invalid identity response, length %zu", 78 __func__, len); 79 return (NULL); 80 } 81 log_debug("%s: identity '%s' length %zd", __func__, str, len); 82 return (str); 83 } 84 85 int 86 eap_challenge_request(struct iked *env, struct iked_sa *sa, 87 struct eap_header *hdr) 88 { 89 struct eap_message *eap; 90 struct eap_mschap_challenge *ms; 91 const char *name; 92 int ret = -1; 93 struct ibuf *e; 94 95 if ((e = ibuf_static()) == NULL) 96 return (-1); 97 98 if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL) 99 goto done; 100 eap->eap_code = EAP_CODE_REQUEST; 101 eap->eap_id = hdr->eap_id + 1; 102 eap->eap_type = sa->sa_policy->pol_auth.auth_eap; 103 104 switch (sa->sa_policy->pol_auth.auth_eap) { 105 case EAP_TYPE_MSCHAP_V2: 106 name = IKED_USER; /* XXX should be user-configurable */ 107 eap->eap_length = htobe16(sizeof(*eap) + 108 sizeof(*ms) + strlen(name)); 109 110 if ((ms = ibuf_advance(e, sizeof(*ms))) == NULL) 111 return (-1); 112 ms->msc_opcode = EAP_MSOPCODE_CHALLENGE; 113 ms->msc_id = eap->eap_id; 114 ms->msc_length = htobe16(sizeof(*ms) + strlen(name)); 115 ms->msc_valuesize = sizeof(ms->msc_challenge); 116 arc4random_buf(ms->msc_challenge, sizeof(ms->msc_challenge)); 117 if (ibuf_add(e, name, strlen(name)) == -1) 118 goto done; 119 120 /* Store the EAP challenge value */ 121 sa->sa_eap.id_type = eap->eap_type; 122 if ((sa->sa_eap.id_buf = ibuf_new(ms->msc_challenge, 123 sizeof(ms->msc_challenge))) == NULL) 124 goto done; 125 break; 126 default: 127 log_debug("%s: unsupported EAP type %s", __func__, 128 print_map(eap->eap_type, eap_type_map)); 129 goto done; 130 } 131 132 ret = ikev2_send_ike_e(env, sa, e, 133 IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1); 134 135 done: 136 ibuf_release(e); 137 138 return (ret); 139 } 140 141 int 142 eap_success(struct iked *env, struct iked_sa *sa, struct eap_header *hdr) 143 { 144 struct eap_header *resp; 145 int ret = -1; 146 struct ibuf *e; 147 148 if ((e = ibuf_static()) == NULL) 149 return (-1); 150 151 if ((resp = ibuf_advance(e, sizeof(*resp))) == NULL) 152 goto done; 153 resp->eap_code = EAP_CODE_SUCCESS; 154 resp->eap_id = hdr->eap_id; 155 resp->eap_length = htobe16(sizeof(*resp)); 156 157 ret = ikev2_send_ike_e(env, sa, e, 158 IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1); 159 160 done: 161 ibuf_release(e); 162 163 return (ret); 164 } 165 166 int 167 eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) 168 { 169 struct iked_user *usr; 170 struct eap_message *resp; 171 struct eap_mschap_response *msr; 172 struct eap_mschap_peer *msp; 173 struct eap_mschap *ms; 174 struct eap_mschap_success *mss; 175 uint8_t *ptr, *pass; 176 size_t len, passlen; 177 char *name, *msg; 178 uint8_t ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; 179 uint8_t successmsg[EAP_MSCHAP_SUCCESS_SZ]; 180 struct ibuf *eapmsg = NULL; 181 int ret = -1; 182 183 if (!sa_stateok(sa, IKEV2_STATE_EAP)) { 184 log_debug("%s: unexpected EAP", __func__); 185 return (0); /* ignore */ 186 } 187 188 if (sa->sa_hdr.sh_initiator) { 189 log_debug("%s: initiator EAP not supported", __func__); 190 return (-1); 191 } 192 193 /* Only MSCHAP-V2 */ 194 if (eap->eap_type != EAP_TYPE_MSCHAP_V2) { 195 log_debug("%s: unsupported type EAP-%s", __func__, 196 print_map(eap->eap_type, eap_type_map)); 197 return (-1); 198 } 199 200 if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*ms))) { 201 log_debug("%s: short message", __func__); 202 return (-1); 203 } 204 205 ms = (struct eap_mschap *)(eap + 1); 206 ptr = (uint8_t *)(eap + 1); 207 208 switch (ms->ms_opcode) { 209 case EAP_MSOPCODE_RESPONSE: 210 msr = (struct eap_mschap_response *)ms; 211 if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*msr))) { 212 log_debug("%s: short response", __func__); 213 return (-1); 214 } 215 ptr += sizeof(*msr); 216 len = betoh16(eap->eap_length) - 217 sizeof(*eap) - sizeof(*msr); 218 if (len == 0 && sa->sa_eapid != NULL) 219 name = strdup(sa->sa_eapid); 220 else 221 name = get_string(ptr, len); 222 if (name == NULL) { 223 log_debug("%s: invalid response name", __func__); 224 return (-1); 225 } 226 if ((usr = user_lookup(env, name)) == NULL) { 227 log_debug("%s: unknown user '%s'", __func__, name); 228 free(name); 229 return (-1); 230 } 231 free(name); 232 233 if ((pass = string2unicode(usr->usr_pass, &passlen)) == NULL) 234 return (-1); 235 236 msp = &msr->msr_response.resp_peer; 237 mschap_nt_response(ibuf_data(sa->sa_eap.id_buf), 238 msp->msp_challenge, usr->usr_name, strlen(usr->usr_name), 239 pass, passlen, ntresponse); 240 241 if (memcmp(ntresponse, msp->msp_ntresponse, 242 sizeof(ntresponse)) != 0) { 243 log_debug("%s: '%s' authentication failed", __func__, 244 usr->usr_name); 245 free(pass); 246 247 /* XXX should we send an EAP failure packet? */ 248 return (-1); 249 } 250 251 bzero(&successmsg, sizeof(successmsg)); 252 mschap_auth_response(pass, passlen, 253 ntresponse, ibuf_data(sa->sa_eap.id_buf), 254 msp->msp_challenge, usr->usr_name, strlen(usr->usr_name), 255 successmsg); 256 if ((sa->sa_eapmsk = ibuf_new(NULL, MSCHAP_MSK_SZ)) == NULL) { 257 log_debug("%s: failed to get MSK", __func__); 258 free(pass); 259 return (-1); 260 } 261 mschap_msk(pass, passlen, ntresponse, 262 ibuf_data(sa->sa_eapmsk)); 263 free(pass); 264 265 log_info("%s: '%s' authenticated", __func__, usr->usr_name); 266 267 268 if ((eapmsg = ibuf_static()) == NULL) 269 return (-1); 270 271 msg = " M=Welcome"; 272 273 if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL) 274 goto done; 275 resp->eap_code = EAP_CODE_REQUEST; 276 resp->eap_id = eap->eap_id + 1; 277 resp->eap_length = htobe16(sizeof(*resp) + sizeof(*mss) + 278 sizeof(successmsg) + strlen(msg)); 279 resp->eap_type = EAP_TYPE_MSCHAP_V2; 280 281 if ((mss = ibuf_advance(eapmsg, sizeof(*mss))) == NULL) 282 goto done; 283 mss->mss_opcode = EAP_MSOPCODE_SUCCESS; 284 mss->mss_id = msr->msr_id; 285 mss->mss_length = htobe16(sizeof(*mss) + 286 sizeof(successmsg) + strlen(msg)); 287 if (ibuf_add(eapmsg, successmsg, sizeof(successmsg)) != 0) 288 goto done; 289 if (ibuf_add(eapmsg, msg, strlen(msg)) != 0) 290 goto done; 291 break; 292 case EAP_MSOPCODE_SUCCESS: 293 if ((eapmsg = ibuf_static()) == NULL) 294 return (-1); 295 if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL) 296 goto done; 297 resp->eap_code = EAP_CODE_RESPONSE; 298 resp->eap_id = eap->eap_id; 299 resp->eap_length = htobe16(sizeof(*resp) + sizeof(*ms)); 300 resp->eap_type = EAP_TYPE_MSCHAP_V2; 301 if ((ms = ibuf_advance(eapmsg, sizeof(*ms))) == NULL) 302 goto done; 303 ms->ms_opcode = EAP_MSOPCODE_SUCCESS; 304 break; 305 case EAP_MSOPCODE_FAILURE: 306 case EAP_MSOPCODE_CHANGE_PASSWORD: 307 case EAP_MSOPCODE_CHALLENGE: 308 default: 309 log_debug("%s: EAP-%s unsupported " 310 "responder operation %s", __func__, 311 print_map(eap->eap_type, eap_type_map), 312 print_map(ms->ms_opcode, eap_msopcode_map)); 313 return (-1); 314 } 315 316 if (eapmsg != NULL) 317 ret = ikev2_send_ike_e(env, sa, eapmsg, 318 IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1); 319 320 if (ret == 0) 321 sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS); 322 323 done: 324 ibuf_release(eapmsg); 325 return (ret); 326 } 327 328 int 329 eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) 330 { 331 struct eap_header *hdr = data; 332 struct eap_message *eap = data; 333 size_t len; 334 uint8_t *ptr; 335 struct eap_mschap *ms; 336 struct eap_mschap_challenge *msc; 337 struct eap_mschap_response *msr; 338 struct eap_mschap_success *mss; 339 struct eap_mschap_failure *msf; 340 char *str; 341 342 /* length is already verified by the caller against sizeof(eap) */ 343 len = betoh16(hdr->eap_length); 344 if (len < sizeof(*eap)) 345 goto fail; 346 ptr = (uint8_t *)(eap + 1); 347 len -= sizeof(*eap); 348 349 switch (hdr->eap_code) { 350 case EAP_CODE_REQUEST: 351 case EAP_CODE_RESPONSE: 352 break; 353 case EAP_CODE_SUCCESS: 354 return (0); 355 case EAP_CODE_FAILURE: 356 if (response) 357 return (0); 358 return (-1); 359 default: 360 log_debug("%s: unsupported EAP code %s", __func__, 361 print_map(hdr->eap_code, eap_code_map)); 362 return (-1); 363 } 364 365 switch (eap->eap_type) { 366 case EAP_TYPE_IDENTITY: 367 if (eap->eap_code == EAP_CODE_REQUEST) 368 break; 369 if ((str = eap_identity_response(eap)) == NULL) 370 return (-1); 371 if (response) { 372 free(str); 373 break; 374 } 375 if (sa->sa_eapid != NULL) { 376 free(str); 377 log_debug("%s: EAP identity already known", __func__); 378 return (0); 379 } 380 sa->sa_eapid = str; 381 return (eap_challenge_request(env, sa, hdr)); 382 case EAP_TYPE_MSCHAP_V2: 383 if (len < sizeof(*ms)) 384 goto fail; 385 ms = (struct eap_mschap *)ptr; 386 switch (ms->ms_opcode) { 387 case EAP_MSOPCODE_CHALLENGE: 388 if (len < sizeof(*msc)) 389 goto fail; 390 msc = (struct eap_mschap_challenge *)ptr; 391 ptr += sizeof(*msc); 392 len -= sizeof(*msc); 393 if ((str = get_string(ptr, len)) == NULL) { 394 log_debug("%s: invalid challenge name", 395 __func__); 396 return (-1); 397 } 398 log_info("%s: %s %s id %d " 399 "length %d valuesize %d name '%s' length %zu", 400 __func__, 401 print_map(eap->eap_type, eap_type_map), 402 print_map(ms->ms_opcode, eap_msopcode_map), 403 msc->msc_id, betoh16(msc->msc_length), 404 msc->msc_valuesize, str, len); 405 free(str); 406 print_hex(msc->msc_challenge, 0, 407 sizeof(msc->msc_challenge)); 408 break; 409 case EAP_MSOPCODE_RESPONSE: 410 if (len < sizeof(*msr)) 411 goto fail; 412 msr = (struct eap_mschap_response *)ptr; 413 ptr += sizeof(*msr); 414 len -= sizeof(*msr); 415 if ((str = get_string(ptr, len)) == NULL) { 416 log_debug("%s: invalid response name", 417 __func__); 418 return (-1); 419 } 420 log_info("%s: %s %s id %d " 421 "length %d valuesize %d name '%s' name-length %zu", 422 __func__, 423 print_map(eap->eap_type, eap_type_map), 424 print_map(ms->ms_opcode, eap_msopcode_map), 425 msr->msr_id, betoh16(msr->msr_length), 426 msr->msr_valuesize, str, len); 427 free(str); 428 print_hex(msr->msr_response.resp_data, 0, 429 sizeof(msr->msr_response.resp_data)); 430 break; 431 case EAP_MSOPCODE_SUCCESS: 432 if (eap->eap_code == EAP_CODE_REQUEST) { 433 if (len < sizeof(*mss)) 434 goto fail; 435 mss = (struct eap_mschap_success *)ptr; 436 ptr += sizeof(*mss); 437 len -= sizeof(*mss); 438 if ((str = get_string(ptr, len)) == NULL) { 439 log_debug("%s: invalid response name", 440 __func__); 441 return (-1); 442 } 443 log_info("%s: %s %s request id %d " 444 "length %d message '%s' message-len %zu", 445 __func__, 446 print_map(eap->eap_type, eap_type_map), 447 print_map(ms->ms_opcode, eap_msopcode_map), 448 mss->mss_id, betoh16(mss->mss_length), 449 str, len); 450 free(str); 451 } else { 452 if (len < sizeof(*ms)) 453 goto fail; 454 ms = (struct eap_mschap *)ptr; 455 log_info("%s: %s %s response", __func__, 456 print_map(eap->eap_type, eap_type_map), 457 print_map(ms->ms_opcode, eap_msopcode_map)); 458 if (response) 459 break; 460 if (!sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS)) 461 return (-1); 462 463 return (eap_success(env, sa, hdr)); 464 } 465 break; 466 case EAP_MSOPCODE_FAILURE: 467 if (len < sizeof(*msf)) 468 goto fail; 469 msf = (struct eap_mschap_failure *)ptr; 470 ptr += sizeof(*msf); 471 len -= sizeof(*msf); 472 if ((str = get_string(ptr, len)) == NULL) { 473 log_debug("%s: invalid failure message", 474 __func__); 475 return (-1); 476 } 477 log_info("%s: %s %s id %d " 478 "length %d message '%s'", __func__, 479 print_map(eap->eap_type, eap_type_map), 480 print_map(ms->ms_opcode, eap_msopcode_map), 481 msf->msf_id, betoh16(msf->msf_length), str); 482 free(str); 483 break; 484 default: 485 log_info("%s: unknown ms opcode %d", __func__, 486 ms->ms_opcode); 487 return (-1); 488 } 489 if (response) 490 break; 491 492 return (eap_mschap(env, sa, eap)); 493 default: 494 log_debug("%s: unsupported EAP type %s", __func__, 495 print_map(eap->eap_type, eap_type_map)); 496 return (-1); 497 } 498 499 return (0); 500 501 fail: 502 log_debug("%s: short message", __func__); 503 return (-1); 504 } 505