1/* 2 * EAP peer method: EAP-PSK (RFC 4764) 3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 * 8 * Note: EAP-PSK is an EAP authentication method and as such, completely 9 * different from WPA-PSK. This file is not needed for WPA-PSK functionality. 10 */ 11 12#include "includes.h" 13 14#include "common.h" 15#include "crypto/aes_wrap.h" 16#include "crypto/random.h" 17#include "eap_common/eap_psk_common.h" 18#include "eap_i.h" 19 20 21struct eap_psk_data { 22 enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state; 23 u8 rand_p[EAP_PSK_RAND_LEN]; 24 u8 rand_s[EAP_PSK_RAND_LEN]; 25 u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; 26 u8 *id_s, *id_p; 27 size_t id_s_len, id_p_len; 28 u8 msk[EAP_MSK_LEN]; 29 u8 emsk[EAP_EMSK_LEN]; 30}; 31 32 33static void * eap_psk_init(struct eap_sm *sm) 34{ 35 struct eap_psk_data *data; 36 const u8 *identity, *password; 37 size_t identity_len, password_len; 38 39 password = eap_get_config_password(sm, &password_len); 40 if (!password || password_len != 16) { 41 wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not " 42 "configured"); 43 return NULL; 44 } 45 46 data = os_zalloc(sizeof(*data)); 47 if (data == NULL) 48 return NULL; 49 if (eap_psk_key_setup(password, data->ak, data->kdk)) { 50 os_free(data); 51 return NULL; 52 } 53 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); 54 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); 55 data->state = PSK_INIT; 56 57 identity = eap_get_config_identity(sm, &identity_len); 58 if (identity) { 59 data->id_p = os_malloc(identity_len); 60 if (data->id_p) 61 os_memcpy(data->id_p, identity, identity_len); 62 data->id_p_len = identity_len; 63 } 64 if (data->id_p == NULL) { 65 wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity"); 66 os_free(data); 67 return NULL; 68 } 69 70 return data; 71} 72 73 74static void eap_psk_deinit(struct eap_sm *sm, void *priv) 75{ 76 struct eap_psk_data *data = priv; 77 os_free(data->id_s); 78 os_free(data->id_p); 79 bin_clear_free(data, sizeof(*data)); 80} 81 82 83static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data, 84 struct eap_method_ret *ret, 85 const struct wpabuf *reqData) 86{ 87 const struct eap_psk_hdr_1 *hdr1; 88 struct eap_psk_hdr_2 *hdr2; 89 struct wpabuf *resp; 90 u8 *buf, *pos; 91 size_t buflen, len; 92 const u8 *cpos; 93 94 wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); 95 96 cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 97 hdr1 = (const struct eap_psk_hdr_1 *) cpos; 98 if (cpos == NULL || len < sizeof(*hdr1)) { 99 wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message " 100 "length (%lu; expected %lu or more)", 101 (unsigned long) len, 102 (unsigned long) sizeof(*hdr1)); 103 ret->ignore = TRUE; 104 return NULL; 105 } 106 wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); 107 if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) { 108 wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", 109 EAP_PSK_FLAGS_GET_T(hdr1->flags)); 110 ret->methodState = METHOD_DONE; 111 ret->decision = DECISION_FAIL; 112 return NULL; 113 } 114 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, 115 EAP_PSK_RAND_LEN); 116 os_memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); 117 os_free(data->id_s); 118 data->id_s_len = len - sizeof(*hdr1); 119 data->id_s = os_malloc(data->id_s_len); 120 if (data->id_s == NULL) { 121 wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " 122 "ID_S (len=%lu)", (unsigned long) data->id_s_len); 123 ret->ignore = TRUE; 124 return NULL; 125 } 126 os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); 127 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", 128 data->id_s, data->id_s_len); 129 130 if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) { 131 wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); 132 ret->ignore = TRUE; 133 return NULL; 134 } 135 136 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, 137 sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, 138 eap_get_id(reqData)); 139 if (resp == NULL) 140 return NULL; 141 hdr2 = wpabuf_put(resp, sizeof(*hdr2)); 142 hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ 143 os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); 144 os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); 145 wpabuf_put_data(resp, data->id_p, data->id_p_len); 146 /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ 147 buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; 148 buf = os_malloc(buflen); 149 if (buf == NULL) { 150 wpabuf_free(resp); 151 return NULL; 152 } 153 os_memcpy(buf, data->id_p, data->id_p_len); 154 pos = buf + data->id_p_len; 155 os_memcpy(pos, data->id_s, data->id_s_len); 156 pos += data->id_s_len; 157 os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); 158 pos += EAP_PSK_RAND_LEN; 159 os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); 160 if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { 161 os_free(buf); 162 wpabuf_free(resp); 163 return NULL; 164 } 165 os_free(buf); 166 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, 167 EAP_PSK_RAND_LEN); 168 wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); 169 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", 170 data->id_p, data->id_p_len); 171 172 data->state = PSK_MAC_SENT; 173 174 return resp; 175} 176 177 178static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, 179 struct eap_method_ret *ret, 180 const struct wpabuf *reqData) 181{ 182 const struct eap_psk_hdr_3 *hdr3; 183 struct eap_psk_hdr_4 *hdr4; 184 struct wpabuf *resp; 185 u8 *buf, *rpchannel, nonce[16], *decrypted; 186 const u8 *pchannel, *tag, *msg; 187 u8 mac[EAP_PSK_MAC_LEN]; 188 size_t buflen, left, data_len, len, plen; 189 int failed = 0; 190 const u8 *pos; 191 192 wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); 193 194 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, 195 reqData, &len); 196 hdr3 = (const struct eap_psk_hdr_3 *) pos; 197 if (pos == NULL || len < sizeof(*hdr3)) { 198 wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " 199 "length (%lu; expected %lu or more)", 200 (unsigned long) len, 201 (unsigned long) sizeof(*hdr3)); 202 ret->ignore = TRUE; 203 return NULL; 204 } 205 left = len - sizeof(*hdr3); 206 pchannel = (const u8 *) (hdr3 + 1); 207 wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); 208 if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { 209 wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", 210 EAP_PSK_FLAGS_GET_T(hdr3->flags)); 211 ret->methodState = METHOD_DONE; 212 ret->decision = DECISION_FAIL; 213 return NULL; 214 } 215 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, 216 EAP_PSK_RAND_LEN); 217 wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); 218 wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); 219 220 if (left < 4 + 16 + 1) { 221 wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " 222 "third message (len=%lu, expected 21)", 223 (unsigned long) left); 224 ret->ignore = TRUE; 225 return NULL; 226 } 227 228 /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ 229 buflen = data->id_s_len + EAP_PSK_RAND_LEN; 230 buf = os_malloc(buflen); 231 if (buf == NULL) 232 return NULL; 233 os_memcpy(buf, data->id_s, data->id_s_len); 234 os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); 235 if (omac1_aes_128(data->ak, buf, buflen, mac)) { 236 os_free(buf); 237 return NULL; 238 } 239 os_free(buf); 240 if (os_memcmp_const(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { 241 wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " 242 "message"); 243 ret->methodState = METHOD_DONE; 244 ret->decision = DECISION_FAIL; 245 return NULL; 246 } 247 wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); 248 249 if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, 250 data->msk, data->emsk)) { 251 ret->methodState = METHOD_DONE; 252 ret->decision = DECISION_FAIL; 253 return NULL; 254 } 255 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); 256 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); 257 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); 258 259 os_memset(nonce, 0, 12); 260 os_memcpy(nonce + 12, pchannel, 4); 261 pchannel += 4; 262 left -= 4; 263 264 tag = pchannel; 265 pchannel += 16; 266 left -= 16; 267 268 msg = pchannel; 269 270 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", 271 nonce, sizeof(nonce)); 272 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", 273 wpabuf_head(reqData), 5); 274 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); 275 276 decrypted = os_malloc(left); 277 if (decrypted == NULL) { 278 ret->methodState = METHOD_DONE; 279 ret->decision = DECISION_FAIL; 280 return NULL; 281 } 282 os_memcpy(decrypted, msg, left); 283 284 if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), 285 wpabuf_head(reqData), 286 sizeof(struct eap_hdr) + 1 + 287 sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, 288 left, tag)) { 289 wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); 290 os_free(decrypted); 291 return NULL; 292 } 293 wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", 294 decrypted, left); 295 296 /* Verify R flag */ 297 switch (decrypted[0] >> 6) { 298 case EAP_PSK_R_FLAG_CONT: 299 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); 300 failed = 1; 301 break; 302 case EAP_PSK_R_FLAG_DONE_SUCCESS: 303 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); 304 break; 305 case EAP_PSK_R_FLAG_DONE_FAILURE: 306 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); 307 wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " 308 "authentication"); 309 failed = 1; 310 break; 311 } 312 313 data_len = 1; 314 if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) 315 data_len++; 316 plen = sizeof(*hdr4) + 4 + 16 + data_len; 317 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, 318 EAP_CODE_RESPONSE, eap_get_id(reqData)); 319 if (resp == NULL) { 320 os_free(decrypted); 321 return NULL; 322 } 323 hdr4 = wpabuf_put(resp, sizeof(*hdr4)); 324 hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ 325 os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); 326 rpchannel = wpabuf_put(resp, 4 + 16 + data_len); 327 328 /* nonce++ */ 329 inc_byte_array(nonce, sizeof(nonce)); 330 os_memcpy(rpchannel, nonce + 12, 4); 331 332 if (decrypted[0] & EAP_PSK_E_FLAG) { 333 wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); 334 failed = 1; 335 rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | 336 EAP_PSK_E_FLAG; 337 if (left > 1) { 338 /* Add empty EXT_Payload with same EXT_Type */ 339 rpchannel[4 + 16 + 1] = decrypted[1]; 340 } 341 } else if (failed) 342 rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; 343 else 344 rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; 345 346 wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", 347 rpchannel + 4 + 16, data_len); 348 if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), 349 wpabuf_head(resp), 350 sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), 351 rpchannel + 4 + 16, data_len, rpchannel + 4)) { 352 os_free(decrypted); 353 wpabuf_free(resp); 354 return NULL; 355 } 356 wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", 357 rpchannel, 4 + 16 + data_len); 358 359 wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", 360 failed ? "un" : ""); 361 data->state = PSK_DONE; 362 ret->methodState = METHOD_DONE; 363 ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; 364 365 os_free(decrypted); 366 367 return resp; 368} 369 370 371static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, 372 struct eap_method_ret *ret, 373 const struct wpabuf *reqData) 374{ 375 struct eap_psk_data *data = priv; 376 const u8 *pos; 377 struct wpabuf *resp = NULL; 378 size_t len; 379 380 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 381 if (pos == NULL) { 382 ret->ignore = TRUE; 383 return NULL; 384 } 385 386 ret->ignore = FALSE; 387 ret->methodState = METHOD_MAY_CONT; 388 ret->decision = DECISION_FAIL; 389 ret->allowNotifications = TRUE; 390 391 switch (data->state) { 392 case PSK_INIT: 393 resp = eap_psk_process_1(data, ret, reqData); 394 break; 395 case PSK_MAC_SENT: 396 resp = eap_psk_process_3(data, ret, reqData); 397 break; 398 case PSK_DONE: 399 wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " 400 "unexpected message"); 401 ret->ignore = TRUE; 402 return NULL; 403 } 404 405 if (ret->methodState == METHOD_DONE) { 406 ret->allowNotifications = FALSE; 407 } 408 409 return resp; 410} 411 412 413static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) 414{ 415 struct eap_psk_data *data = priv; 416 return data->state == PSK_DONE; 417} 418 419 420static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) 421{ 422 struct eap_psk_data *data = priv; 423 u8 *key; 424 425 if (data->state != PSK_DONE) 426 return NULL; 427 428 key = os_malloc(EAP_MSK_LEN); 429 if (key == NULL) 430 return NULL; 431 432 *len = EAP_MSK_LEN; 433 os_memcpy(key, data->msk, EAP_MSK_LEN); 434 435 return key; 436} 437 438 439static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 440{ 441 struct eap_psk_data *data = priv; 442 u8 *id; 443 444 if (data->state != PSK_DONE) 445 return NULL; 446 447 *len = 1 + 2 * EAP_PSK_RAND_LEN; 448 id = os_malloc(*len); 449 if (id == NULL) 450 return NULL; 451 452 id[0] = EAP_TYPE_PSK; 453 os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN); 454 os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN); 455 wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len); 456 457 return id; 458} 459 460 461static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 462{ 463 struct eap_psk_data *data = priv; 464 u8 *key; 465 466 if (data->state != PSK_DONE) 467 return NULL; 468 469 key = os_malloc(EAP_EMSK_LEN); 470 if (key == NULL) 471 return NULL; 472 473 *len = EAP_EMSK_LEN; 474 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 475 476 return key; 477} 478 479 480int eap_peer_psk_register(void) 481{ 482 struct eap_method *eap; 483 int ret; 484 485 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 486 EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); 487 if (eap == NULL) 488 return -1; 489 490 eap->init = eap_psk_init; 491 eap->deinit = eap_psk_deinit; 492 eap->process = eap_psk_process; 493 eap->isKeyAvailable = eap_psk_isKeyAvailable; 494 eap->getKey = eap_psk_getKey; 495 eap->getSessionId = eap_psk_get_session_id; 496 eap->get_emsk = eap_psk_get_emsk; 497 498 ret = eap_peer_method_register(eap); 499 if (ret) 500 eap_peer_method_free(eap); 501 return ret; 502} 503