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 21 struct 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 33 static 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 74 static 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 83 static 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_memdup(hdr1 + 1, 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 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", 127 data->id_s, data->id_s_len); 128 129 if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) { 130 wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); 131 ret->ignore = TRUE; 132 return NULL; 133 } 134 135 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, 136 sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, 137 eap_get_id(reqData)); 138 if (resp == NULL) 139 return NULL; 140 hdr2 = wpabuf_put(resp, sizeof(*hdr2)); 141 hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ 142 os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); 143 os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); 144 wpabuf_put_data(resp, data->id_p, data->id_p_len); 145 /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ 146 buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; 147 buf = os_malloc(buflen); 148 if (buf == NULL) { 149 wpabuf_free(resp); 150 return NULL; 151 } 152 os_memcpy(buf, data->id_p, data->id_p_len); 153 pos = buf + data->id_p_len; 154 os_memcpy(pos, data->id_s, data->id_s_len); 155 pos += data->id_s_len; 156 os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); 157 pos += EAP_PSK_RAND_LEN; 158 os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); 159 if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { 160 os_free(buf); 161 wpabuf_free(resp); 162 return NULL; 163 } 164 os_free(buf); 165 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, 166 EAP_PSK_RAND_LEN); 167 wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); 168 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", 169 data->id_p, data->id_p_len); 170 171 data->state = PSK_MAC_SENT; 172 173 return resp; 174 } 175 176 177 static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, 178 struct eap_method_ret *ret, 179 const struct wpabuf *reqData) 180 { 181 const struct eap_psk_hdr_3 *hdr3; 182 struct eap_psk_hdr_4 *hdr4; 183 struct wpabuf *resp; 184 u8 *buf, *rpchannel, nonce[16], *decrypted; 185 const u8 *pchannel, *tag, *msg; 186 u8 mac[EAP_PSK_MAC_LEN]; 187 size_t buflen, left, data_len, len, plen; 188 int failed = 0; 189 const u8 *pos; 190 191 wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); 192 193 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, 194 reqData, &len); 195 hdr3 = (const struct eap_psk_hdr_3 *) pos; 196 if (pos == NULL || len < sizeof(*hdr3)) { 197 wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " 198 "length (%lu; expected %lu or more)", 199 (unsigned long) len, 200 (unsigned long) sizeof(*hdr3)); 201 ret->ignore = TRUE; 202 return NULL; 203 } 204 left = len - sizeof(*hdr3); 205 pchannel = (const u8 *) (hdr3 + 1); 206 wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); 207 if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { 208 wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", 209 EAP_PSK_FLAGS_GET_T(hdr3->flags)); 210 ret->methodState = METHOD_DONE; 211 ret->decision = DECISION_FAIL; 212 return NULL; 213 } 214 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, 215 EAP_PSK_RAND_LEN); 216 wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); 217 wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); 218 219 if (left < 4 + 16 + 1) { 220 wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " 221 "third message (len=%lu, expected 21)", 222 (unsigned long) left); 223 ret->ignore = TRUE; 224 return NULL; 225 } 226 227 /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ 228 buflen = data->id_s_len + EAP_PSK_RAND_LEN; 229 buf = os_malloc(buflen); 230 if (buf == NULL) 231 return NULL; 232 os_memcpy(buf, data->id_s, data->id_s_len); 233 os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); 234 if (omac1_aes_128(data->ak, buf, buflen, mac)) { 235 os_free(buf); 236 return NULL; 237 } 238 os_free(buf); 239 if (os_memcmp_const(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { 240 wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " 241 "message"); 242 ret->methodState = METHOD_DONE; 243 ret->decision = DECISION_FAIL; 244 return NULL; 245 } 246 wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); 247 248 if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, 249 data->msk, data->emsk)) { 250 ret->methodState = METHOD_DONE; 251 ret->decision = DECISION_FAIL; 252 return NULL; 253 } 254 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); 255 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); 256 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); 257 258 os_memset(nonce, 0, 12); 259 os_memcpy(nonce + 12, pchannel, 4); 260 pchannel += 4; 261 left -= 4; 262 263 tag = pchannel; 264 pchannel += 16; 265 left -= 16; 266 267 msg = pchannel; 268 269 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", 270 nonce, sizeof(nonce)); 271 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", 272 wpabuf_head(reqData), 5); 273 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); 274 275 decrypted = os_memdup(msg, left); 276 if (decrypted == NULL) { 277 ret->methodState = METHOD_DONE; 278 ret->decision = DECISION_FAIL; 279 return NULL; 280 } 281 282 if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), 283 wpabuf_head(reqData), 284 sizeof(struct eap_hdr) + 1 + 285 sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, 286 left, tag)) { 287 wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); 288 os_free(decrypted); 289 return NULL; 290 } 291 wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", 292 decrypted, left); 293 294 /* Verify R flag */ 295 switch (decrypted[0] >> 6) { 296 case EAP_PSK_R_FLAG_CONT: 297 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); 298 failed = 1; 299 break; 300 case EAP_PSK_R_FLAG_DONE_SUCCESS: 301 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); 302 break; 303 case EAP_PSK_R_FLAG_DONE_FAILURE: 304 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); 305 wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " 306 "authentication"); 307 failed = 1; 308 break; 309 } 310 311 data_len = 1; 312 if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) 313 data_len++; 314 plen = sizeof(*hdr4) + 4 + 16 + data_len; 315 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, 316 EAP_CODE_RESPONSE, eap_get_id(reqData)); 317 if (resp == NULL) { 318 os_free(decrypted); 319 return NULL; 320 } 321 hdr4 = wpabuf_put(resp, sizeof(*hdr4)); 322 hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ 323 os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); 324 rpchannel = wpabuf_put(resp, 4 + 16 + data_len); 325 326 /* nonce++ */ 327 inc_byte_array(nonce, sizeof(nonce)); 328 os_memcpy(rpchannel, nonce + 12, 4); 329 330 if (decrypted[0] & EAP_PSK_E_FLAG) { 331 wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); 332 failed = 1; 333 rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | 334 EAP_PSK_E_FLAG; 335 if (left > 1) { 336 /* Add empty EXT_Payload with same EXT_Type */ 337 rpchannel[4 + 16 + 1] = decrypted[1]; 338 } 339 } else if (failed) 340 rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; 341 else 342 rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; 343 344 wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", 345 rpchannel + 4 + 16, data_len); 346 if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), 347 wpabuf_head(resp), 348 sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), 349 rpchannel + 4 + 16, data_len, rpchannel + 4)) { 350 os_free(decrypted); 351 wpabuf_free(resp); 352 return NULL; 353 } 354 wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", 355 rpchannel, 4 + 16 + data_len); 356 357 wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", 358 failed ? "un" : ""); 359 data->state = PSK_DONE; 360 ret->methodState = METHOD_DONE; 361 ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; 362 363 os_free(decrypted); 364 365 return resp; 366 } 367 368 369 static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, 370 struct eap_method_ret *ret, 371 const struct wpabuf *reqData) 372 { 373 struct eap_psk_data *data = priv; 374 const u8 *pos; 375 struct wpabuf *resp = NULL; 376 size_t len; 377 378 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 379 if (pos == NULL) { 380 ret->ignore = TRUE; 381 return NULL; 382 } 383 384 ret->ignore = FALSE; 385 ret->methodState = METHOD_MAY_CONT; 386 ret->decision = DECISION_FAIL; 387 ret->allowNotifications = TRUE; 388 389 switch (data->state) { 390 case PSK_INIT: 391 resp = eap_psk_process_1(data, ret, reqData); 392 break; 393 case PSK_MAC_SENT: 394 resp = eap_psk_process_3(data, ret, reqData); 395 break; 396 case PSK_DONE: 397 wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " 398 "unexpected message"); 399 ret->ignore = TRUE; 400 return NULL; 401 } 402 403 if (ret->methodState == METHOD_DONE) { 404 ret->allowNotifications = FALSE; 405 } 406 407 return resp; 408 } 409 410 411 static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) 412 { 413 struct eap_psk_data *data = priv; 414 return data->state == PSK_DONE; 415 } 416 417 418 static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) 419 { 420 struct eap_psk_data *data = priv; 421 u8 *key; 422 423 if (data->state != PSK_DONE) 424 return NULL; 425 426 key = os_memdup(data->msk, EAP_MSK_LEN); 427 if (key == NULL) 428 return NULL; 429 430 *len = EAP_MSK_LEN; 431 432 return key; 433 } 434 435 436 static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 437 { 438 struct eap_psk_data *data = priv; 439 u8 *id; 440 441 if (data->state != PSK_DONE) 442 return NULL; 443 444 *len = 1 + 2 * EAP_PSK_RAND_LEN; 445 id = os_malloc(*len); 446 if (id == NULL) 447 return NULL; 448 449 id[0] = EAP_TYPE_PSK; 450 os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN); 451 os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN); 452 wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len); 453 454 return id; 455 } 456 457 458 static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 459 { 460 struct eap_psk_data *data = priv; 461 u8 *key; 462 463 if (data->state != PSK_DONE) 464 return NULL; 465 466 key = os_memdup(data->emsk, EAP_EMSK_LEN); 467 if (key == NULL) 468 return NULL; 469 470 *len = EAP_EMSK_LEN; 471 472 return key; 473 } 474 475 476 int eap_peer_psk_register(void) 477 { 478 struct eap_method *eap; 479 480 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 481 EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); 482 if (eap == NULL) 483 return -1; 484 485 eap->init = eap_psk_init; 486 eap->deinit = eap_psk_deinit; 487 eap->process = eap_psk_process; 488 eap->isKeyAvailable = eap_psk_isKeyAvailable; 489 eap->getKey = eap_psk_getKey; 490 eap->getSessionId = eap_psk_get_session_id; 491 eap->get_emsk = eap_psk_get_emsk; 492 493 return eap_peer_method_register(eap); 494 } 495