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