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