13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * hostapd / EAP-PSK (RFC 4764) server
33ff40c12SJohn Marino * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
73ff40c12SJohn Marino *
83ff40c12SJohn Marino * Note: EAP-PSK is an EAP authentication method and as such, completely
93ff40c12SJohn Marino * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
103ff40c12SJohn Marino */
113ff40c12SJohn Marino
123ff40c12SJohn Marino #include "includes.h"
133ff40c12SJohn Marino
143ff40c12SJohn Marino #include "common.h"
153ff40c12SJohn Marino #include "crypto/aes_wrap.h"
163ff40c12SJohn Marino #include "crypto/random.h"
173ff40c12SJohn Marino #include "eap_common/eap_psk_common.h"
183ff40c12SJohn Marino #include "eap_server/eap_i.h"
193ff40c12SJohn Marino
203ff40c12SJohn Marino
213ff40c12SJohn Marino struct eap_psk_data {
223ff40c12SJohn Marino enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
233ff40c12SJohn Marino u8 rand_s[EAP_PSK_RAND_LEN];
243ff40c12SJohn Marino u8 rand_p[EAP_PSK_RAND_LEN];
253ff40c12SJohn Marino u8 *id_p;
263ff40c12SJohn Marino size_t id_p_len;
273ff40c12SJohn Marino u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
283ff40c12SJohn Marino u8 msk[EAP_MSK_LEN];
293ff40c12SJohn Marino u8 emsk[EAP_EMSK_LEN];
303ff40c12SJohn Marino };
313ff40c12SJohn Marino
323ff40c12SJohn Marino
eap_psk_init(struct eap_sm * sm)333ff40c12SJohn Marino static void * eap_psk_init(struct eap_sm *sm)
343ff40c12SJohn Marino {
353ff40c12SJohn Marino struct eap_psk_data *data;
363ff40c12SJohn Marino
373ff40c12SJohn Marino data = os_zalloc(sizeof(*data));
383ff40c12SJohn Marino if (data == NULL)
393ff40c12SJohn Marino return NULL;
403ff40c12SJohn Marino data->state = PSK_1;
413ff40c12SJohn Marino
423ff40c12SJohn Marino return data;
433ff40c12SJohn Marino }
443ff40c12SJohn Marino
453ff40c12SJohn Marino
eap_psk_reset(struct eap_sm * sm,void * priv)463ff40c12SJohn Marino static void eap_psk_reset(struct eap_sm *sm, void *priv)
473ff40c12SJohn Marino {
483ff40c12SJohn Marino struct eap_psk_data *data = priv;
493ff40c12SJohn Marino os_free(data->id_p);
50*a1157835SDaniel Fojt bin_clear_free(data, sizeof(*data));
513ff40c12SJohn Marino }
523ff40c12SJohn Marino
533ff40c12SJohn Marino
eap_psk_build_1(struct eap_sm * sm,struct eap_psk_data * data,u8 id)543ff40c12SJohn Marino static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
553ff40c12SJohn Marino struct eap_psk_data *data, u8 id)
563ff40c12SJohn Marino {
573ff40c12SJohn Marino struct wpabuf *req;
583ff40c12SJohn Marino struct eap_psk_hdr_1 *psk;
593ff40c12SJohn Marino
603ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)");
613ff40c12SJohn Marino
623ff40c12SJohn Marino if (random_get_bytes(data->rand_s, EAP_PSK_RAND_LEN)) {
633ff40c12SJohn Marino wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
643ff40c12SJohn Marino data->state = FAILURE;
653ff40c12SJohn Marino return NULL;
663ff40c12SJohn Marino }
673ff40c12SJohn Marino wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_S (server rand)",
683ff40c12SJohn Marino data->rand_s, EAP_PSK_RAND_LEN);
693ff40c12SJohn Marino
703ff40c12SJohn Marino req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
713ff40c12SJohn Marino sizeof(*psk) + sm->server_id_len,
723ff40c12SJohn Marino EAP_CODE_REQUEST, id);
733ff40c12SJohn Marino if (req == NULL) {
743ff40c12SJohn Marino wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
753ff40c12SJohn Marino "request");
763ff40c12SJohn Marino data->state = FAILURE;
773ff40c12SJohn Marino return NULL;
783ff40c12SJohn Marino }
793ff40c12SJohn Marino
803ff40c12SJohn Marino psk = wpabuf_put(req, sizeof(*psk));
813ff40c12SJohn Marino psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
823ff40c12SJohn Marino os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
833ff40c12SJohn Marino wpabuf_put_data(req, sm->server_id, sm->server_id_len);
843ff40c12SJohn Marino
853ff40c12SJohn Marino return req;
863ff40c12SJohn Marino }
873ff40c12SJohn Marino
883ff40c12SJohn Marino
eap_psk_build_3(struct eap_sm * sm,struct eap_psk_data * data,u8 id)893ff40c12SJohn Marino static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
903ff40c12SJohn Marino struct eap_psk_data *data, u8 id)
913ff40c12SJohn Marino {
923ff40c12SJohn Marino struct wpabuf *req;
933ff40c12SJohn Marino struct eap_psk_hdr_3 *psk;
943ff40c12SJohn Marino u8 *buf, *pchannel, nonce[16];
953ff40c12SJohn Marino size_t buflen;
963ff40c12SJohn Marino
973ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)");
983ff40c12SJohn Marino
993ff40c12SJohn Marino req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
1003ff40c12SJohn Marino sizeof(*psk) + 4 + 16 + 1, EAP_CODE_REQUEST, id);
1013ff40c12SJohn Marino if (req == NULL) {
1023ff40c12SJohn Marino wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
1033ff40c12SJohn Marino "request");
1043ff40c12SJohn Marino data->state = FAILURE;
1053ff40c12SJohn Marino return NULL;
1063ff40c12SJohn Marino }
1073ff40c12SJohn Marino
1083ff40c12SJohn Marino psk = wpabuf_put(req, sizeof(*psk));
1093ff40c12SJohn Marino psk->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */
1103ff40c12SJohn Marino os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
1113ff40c12SJohn Marino
1123ff40c12SJohn Marino /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
1133ff40c12SJohn Marino buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
1143ff40c12SJohn Marino buf = os_malloc(buflen);
1153ff40c12SJohn Marino if (buf == NULL)
1163ff40c12SJohn Marino goto fail;
1173ff40c12SJohn Marino
1183ff40c12SJohn Marino os_memcpy(buf, sm->server_id, sm->server_id_len);
1193ff40c12SJohn Marino os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
1203ff40c12SJohn Marino if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
1213ff40c12SJohn Marino os_free(buf);
1223ff40c12SJohn Marino goto fail;
1233ff40c12SJohn Marino }
1243ff40c12SJohn Marino os_free(buf);
1253ff40c12SJohn Marino
1263ff40c12SJohn Marino if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
1273ff40c12SJohn Marino data->emsk))
1283ff40c12SJohn Marino goto fail;
1293ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
1303ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
1313ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
1323ff40c12SJohn Marino
1333ff40c12SJohn Marino os_memset(nonce, 0, sizeof(nonce));
1343ff40c12SJohn Marino pchannel = wpabuf_put(req, 4 + 16 + 1);
1353ff40c12SJohn Marino os_memcpy(pchannel, nonce + 12, 4);
1363ff40c12SJohn Marino os_memset(pchannel + 4, 0, 16); /* Tag */
1373ff40c12SJohn Marino pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
1383ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)",
1393ff40c12SJohn Marino pchannel, 4 + 16 + 1);
1403ff40c12SJohn Marino if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
1413ff40c12SJohn Marino wpabuf_head(req), 22,
1423ff40c12SJohn Marino pchannel + 4 + 16, 1, pchannel + 4))
1433ff40c12SJohn Marino goto fail;
1443ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)",
1453ff40c12SJohn Marino pchannel, 4 + 16 + 1);
1463ff40c12SJohn Marino
1473ff40c12SJohn Marino return req;
1483ff40c12SJohn Marino
1493ff40c12SJohn Marino fail:
1503ff40c12SJohn Marino wpabuf_free(req);
1513ff40c12SJohn Marino data->state = FAILURE;
1523ff40c12SJohn Marino return NULL;
1533ff40c12SJohn Marino }
1543ff40c12SJohn Marino
1553ff40c12SJohn Marino
eap_psk_buildReq(struct eap_sm * sm,void * priv,u8 id)1563ff40c12SJohn Marino static struct wpabuf * eap_psk_buildReq(struct eap_sm *sm, void *priv, u8 id)
1573ff40c12SJohn Marino {
1583ff40c12SJohn Marino struct eap_psk_data *data = priv;
1593ff40c12SJohn Marino
1603ff40c12SJohn Marino switch (data->state) {
1613ff40c12SJohn Marino case PSK_1:
1623ff40c12SJohn Marino return eap_psk_build_1(sm, data, id);
1633ff40c12SJohn Marino case PSK_3:
1643ff40c12SJohn Marino return eap_psk_build_3(sm, data, id);
1653ff40c12SJohn Marino default:
1663ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: Unknown state %d in buildReq",
1673ff40c12SJohn Marino data->state);
1683ff40c12SJohn Marino break;
1693ff40c12SJohn Marino }
1703ff40c12SJohn Marino return NULL;
1713ff40c12SJohn Marino }
1723ff40c12SJohn Marino
1733ff40c12SJohn Marino
eap_psk_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)1743ff40c12SJohn Marino static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
1753ff40c12SJohn Marino struct wpabuf *respData)
1763ff40c12SJohn Marino {
1773ff40c12SJohn Marino struct eap_psk_data *data = priv;
1783ff40c12SJohn Marino size_t len;
1793ff40c12SJohn Marino u8 t;
1803ff40c12SJohn Marino const u8 *pos;
1813ff40c12SJohn Marino
1823ff40c12SJohn Marino pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
1833ff40c12SJohn Marino if (pos == NULL || len < 1) {
1843ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
1853ff40c12SJohn Marino return TRUE;
1863ff40c12SJohn Marino }
1873ff40c12SJohn Marino t = EAP_PSK_FLAGS_GET_T(*pos);
1883ff40c12SJohn Marino
1893ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t);
1903ff40c12SJohn Marino
1913ff40c12SJohn Marino if (data->state == PSK_1 && t != 1) {
1923ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - "
1933ff40c12SJohn Marino "ignore T=%d", t);
1943ff40c12SJohn Marino return TRUE;
1953ff40c12SJohn Marino }
1963ff40c12SJohn Marino
1973ff40c12SJohn Marino if (data->state == PSK_3 && t != 3) {
1983ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - "
1993ff40c12SJohn Marino "ignore T=%d", t);
2003ff40c12SJohn Marino return TRUE;
2013ff40c12SJohn Marino }
2023ff40c12SJohn Marino
2033ff40c12SJohn Marino if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) ||
2043ff40c12SJohn Marino (t == 3 && len < sizeof(struct eap_psk_hdr_4))) {
2053ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame");
2063ff40c12SJohn Marino return TRUE;
2073ff40c12SJohn Marino }
2083ff40c12SJohn Marino
2093ff40c12SJohn Marino return FALSE;
2103ff40c12SJohn Marino }
2113ff40c12SJohn Marino
2123ff40c12SJohn Marino
eap_psk_process_2(struct eap_sm * sm,struct eap_psk_data * data,struct wpabuf * respData)2133ff40c12SJohn Marino static void eap_psk_process_2(struct eap_sm *sm,
2143ff40c12SJohn Marino struct eap_psk_data *data,
2153ff40c12SJohn Marino struct wpabuf *respData)
2163ff40c12SJohn Marino {
2173ff40c12SJohn Marino const struct eap_psk_hdr_2 *resp;
2183ff40c12SJohn Marino u8 *pos, mac[EAP_PSK_MAC_LEN], *buf;
2193ff40c12SJohn Marino size_t left, buflen;
2203ff40c12SJohn Marino int i;
2213ff40c12SJohn Marino const u8 *cpos;
2223ff40c12SJohn Marino
2233ff40c12SJohn Marino if (data->state != PSK_1)
2243ff40c12SJohn Marino return;
2253ff40c12SJohn Marino
2263ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2");
2273ff40c12SJohn Marino
2283ff40c12SJohn Marino cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData,
2293ff40c12SJohn Marino &left);
2303ff40c12SJohn Marino if (cpos == NULL || left < sizeof(*resp)) {
2313ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
2323ff40c12SJohn Marino return;
2333ff40c12SJohn Marino }
2343ff40c12SJohn Marino resp = (const struct eap_psk_hdr_2 *) cpos;
2353ff40c12SJohn Marino cpos = (const u8 *) (resp + 1);
2363ff40c12SJohn Marino left -= sizeof(*resp);
2373ff40c12SJohn Marino
2383ff40c12SJohn Marino os_free(data->id_p);
239*a1157835SDaniel Fojt data->id_p = os_memdup(cpos, left);
2403ff40c12SJohn Marino if (data->id_p == NULL) {
2413ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for "
2423ff40c12SJohn Marino "ID_P");
2433ff40c12SJohn Marino return;
2443ff40c12SJohn Marino }
2453ff40c12SJohn Marino data->id_p_len = left;
2463ff40c12SJohn Marino wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P",
2473ff40c12SJohn Marino data->id_p, data->id_p_len);
2483ff40c12SJohn Marino
2493ff40c12SJohn Marino if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) {
2503ff40c12SJohn Marino wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P",
2513ff40c12SJohn Marino data->id_p, data->id_p_len);
2523ff40c12SJohn Marino data->state = FAILURE;
2533ff40c12SJohn Marino return;
2543ff40c12SJohn Marino }
2553ff40c12SJohn Marino
2563ff40c12SJohn Marino for (i = 0;
2573ff40c12SJohn Marino i < EAP_MAX_METHODS &&
2583ff40c12SJohn Marino (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
2593ff40c12SJohn Marino sm->user->methods[i].method != EAP_TYPE_NONE);
2603ff40c12SJohn Marino i++) {
2613ff40c12SJohn Marino if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
2623ff40c12SJohn Marino sm->user->methods[i].method == EAP_TYPE_PSK)
2633ff40c12SJohn Marino break;
2643ff40c12SJohn Marino }
2653ff40c12SJohn Marino
2663ff40c12SJohn Marino if (i >= EAP_MAX_METHODS ||
2673ff40c12SJohn Marino sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
2683ff40c12SJohn Marino sm->user->methods[i].method != EAP_TYPE_PSK) {
2693ff40c12SJohn Marino wpa_hexdump_ascii(MSG_DEBUG,
2703ff40c12SJohn Marino "EAP-PSK: EAP-PSK not enabled for ID_P",
2713ff40c12SJohn Marino data->id_p, data->id_p_len);
2723ff40c12SJohn Marino data->state = FAILURE;
2733ff40c12SJohn Marino return;
2743ff40c12SJohn Marino }
2753ff40c12SJohn Marino
2763ff40c12SJohn Marino if (sm->user->password == NULL ||
2773ff40c12SJohn Marino sm->user->password_len != EAP_PSK_PSK_LEN) {
2783ff40c12SJohn Marino wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in "
2793ff40c12SJohn Marino "user database for ID_P",
2803ff40c12SJohn Marino data->id_p, data->id_p_len);
2813ff40c12SJohn Marino data->state = FAILURE;
2823ff40c12SJohn Marino return;
2833ff40c12SJohn Marino }
2843ff40c12SJohn Marino if (eap_psk_key_setup(sm->user->password, data->ak, data->kdk)) {
2853ff40c12SJohn Marino data->state = FAILURE;
2863ff40c12SJohn Marino return;
2873ff40c12SJohn Marino }
2883ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
2893ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
2903ff40c12SJohn Marino
2913ff40c12SJohn Marino wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)",
2923ff40c12SJohn Marino resp->rand_p, EAP_PSK_RAND_LEN);
2933ff40c12SJohn Marino os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
2943ff40c12SJohn Marino
2953ff40c12SJohn Marino /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
2963ff40c12SJohn Marino buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
2973ff40c12SJohn Marino buf = os_malloc(buflen);
2983ff40c12SJohn Marino if (buf == NULL) {
2993ff40c12SJohn Marino data->state = FAILURE;
3003ff40c12SJohn Marino return;
3013ff40c12SJohn Marino }
3023ff40c12SJohn Marino os_memcpy(buf, data->id_p, data->id_p_len);
3033ff40c12SJohn Marino pos = buf + data->id_p_len;
3043ff40c12SJohn Marino os_memcpy(pos, sm->server_id, sm->server_id_len);
3053ff40c12SJohn Marino pos += sm->server_id_len;
3063ff40c12SJohn Marino os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
3073ff40c12SJohn Marino pos += EAP_PSK_RAND_LEN;
3083ff40c12SJohn Marino os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
3093ff40c12SJohn Marino if (omac1_aes_128(data->ak, buf, buflen, mac)) {
3103ff40c12SJohn Marino os_free(buf);
3113ff40c12SJohn Marino data->state = FAILURE;
3123ff40c12SJohn Marino return;
3133ff40c12SJohn Marino }
3143ff40c12SJohn Marino os_free(buf);
3153ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN);
316*a1157835SDaniel Fojt if (os_memcmp_const(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
3173ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P");
3183ff40c12SJohn Marino wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P",
3193ff40c12SJohn Marino mac, EAP_PSK_MAC_LEN);
3203ff40c12SJohn Marino data->state = FAILURE;
3213ff40c12SJohn Marino return;
3223ff40c12SJohn Marino }
3233ff40c12SJohn Marino
3243ff40c12SJohn Marino data->state = PSK_3;
3253ff40c12SJohn Marino }
3263ff40c12SJohn Marino
3273ff40c12SJohn Marino
eap_psk_process_4(struct eap_sm * sm,struct eap_psk_data * data,struct wpabuf * respData)3283ff40c12SJohn Marino static void eap_psk_process_4(struct eap_sm *sm,
3293ff40c12SJohn Marino struct eap_psk_data *data,
3303ff40c12SJohn Marino struct wpabuf *respData)
3313ff40c12SJohn Marino {
3323ff40c12SJohn Marino const struct eap_psk_hdr_4 *resp;
3333ff40c12SJohn Marino u8 *decrypted, nonce[16];
3343ff40c12SJohn Marino size_t left;
3353ff40c12SJohn Marino const u8 *pos, *tag;
3363ff40c12SJohn Marino
3373ff40c12SJohn Marino if (data->state != PSK_3)
3383ff40c12SJohn Marino return;
3393ff40c12SJohn Marino
3403ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-4");
3413ff40c12SJohn Marino
3423ff40c12SJohn Marino pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &left);
3433ff40c12SJohn Marino if (pos == NULL || left < sizeof(*resp)) {
3443ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
3453ff40c12SJohn Marino return;
3463ff40c12SJohn Marino }
3473ff40c12SJohn Marino resp = (const struct eap_psk_hdr_4 *) pos;
3483ff40c12SJohn Marino pos = (const u8 *) (resp + 1);
3493ff40c12SJohn Marino left -= sizeof(*resp);
3503ff40c12SJohn Marino
3513ff40c12SJohn Marino wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Encrypted PCHANNEL", pos, left);
3523ff40c12SJohn Marino
3533ff40c12SJohn Marino if (left < 4 + 16 + 1) {
3543ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
3553ff40c12SJohn Marino "PSK-4 (len=%lu, expected 21)",
3563ff40c12SJohn Marino (unsigned long) left);
3573ff40c12SJohn Marino return;
3583ff40c12SJohn Marino }
3593ff40c12SJohn Marino
3603ff40c12SJohn Marino if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0) {
3613ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: Nonce did not increase");
3623ff40c12SJohn Marino return;
3633ff40c12SJohn Marino }
3643ff40c12SJohn Marino
3653ff40c12SJohn Marino os_memset(nonce, 0, 12);
3663ff40c12SJohn Marino os_memcpy(nonce + 12, pos, 4);
3673ff40c12SJohn Marino pos += 4;
3683ff40c12SJohn Marino left -= 4;
3693ff40c12SJohn Marino tag = pos;
3703ff40c12SJohn Marino pos += 16;
3713ff40c12SJohn Marino left -= 16;
3723ff40c12SJohn Marino
373*a1157835SDaniel Fojt decrypted = os_memdup(pos, left);
3743ff40c12SJohn Marino if (decrypted == NULL)
3753ff40c12SJohn Marino return;
3763ff40c12SJohn Marino
3773ff40c12SJohn Marino if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
3783ff40c12SJohn Marino wpabuf_head(respData), 22, decrypted, left,
3793ff40c12SJohn Marino tag)) {
3803ff40c12SJohn Marino wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
3813ff40c12SJohn Marino os_free(decrypted);
3823ff40c12SJohn Marino data->state = FAILURE;
3833ff40c12SJohn Marino return;
3843ff40c12SJohn Marino }
3853ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
3863ff40c12SJohn Marino decrypted, left);
3873ff40c12SJohn Marino
3883ff40c12SJohn Marino /* Verify R flag */
3893ff40c12SJohn Marino switch (decrypted[0] >> 6) {
3903ff40c12SJohn Marino case EAP_PSK_R_FLAG_CONT:
3913ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
3923ff40c12SJohn Marino data->state = FAILURE;
3933ff40c12SJohn Marino break;
3943ff40c12SJohn Marino case EAP_PSK_R_FLAG_DONE_SUCCESS:
3953ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
3963ff40c12SJohn Marino data->state = SUCCESS;
3973ff40c12SJohn Marino break;
3983ff40c12SJohn Marino case EAP_PSK_R_FLAG_DONE_FAILURE:
3993ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
4003ff40c12SJohn Marino data->state = FAILURE;
4013ff40c12SJohn Marino break;
4023ff40c12SJohn Marino }
4033ff40c12SJohn Marino os_free(decrypted);
4043ff40c12SJohn Marino }
4053ff40c12SJohn Marino
4063ff40c12SJohn Marino
eap_psk_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)4073ff40c12SJohn Marino static void eap_psk_process(struct eap_sm *sm, void *priv,
4083ff40c12SJohn Marino struct wpabuf *respData)
4093ff40c12SJohn Marino {
4103ff40c12SJohn Marino struct eap_psk_data *data = priv;
4113ff40c12SJohn Marino const u8 *pos;
4123ff40c12SJohn Marino size_t len;
4133ff40c12SJohn Marino
4143ff40c12SJohn Marino if (sm->user == NULL || sm->user->password == NULL) {
4153ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not "
4163ff40c12SJohn Marino "configured");
4173ff40c12SJohn Marino data->state = FAILURE;
4183ff40c12SJohn Marino return;
4193ff40c12SJohn Marino }
4203ff40c12SJohn Marino
4213ff40c12SJohn Marino pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
4223ff40c12SJohn Marino if (pos == NULL || len < 1)
4233ff40c12SJohn Marino return;
4243ff40c12SJohn Marino
4253ff40c12SJohn Marino switch (EAP_PSK_FLAGS_GET_T(*pos)) {
4263ff40c12SJohn Marino case 1:
4273ff40c12SJohn Marino eap_psk_process_2(sm, data, respData);
4283ff40c12SJohn Marino break;
4293ff40c12SJohn Marino case 3:
4303ff40c12SJohn Marino eap_psk_process_4(sm, data, respData);
4313ff40c12SJohn Marino break;
4323ff40c12SJohn Marino }
4333ff40c12SJohn Marino }
4343ff40c12SJohn Marino
4353ff40c12SJohn Marino
eap_psk_isDone(struct eap_sm * sm,void * priv)4363ff40c12SJohn Marino static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv)
4373ff40c12SJohn Marino {
4383ff40c12SJohn Marino struct eap_psk_data *data = priv;
4393ff40c12SJohn Marino return data->state == SUCCESS || data->state == FAILURE;
4403ff40c12SJohn Marino }
4413ff40c12SJohn Marino
4423ff40c12SJohn Marino
eap_psk_getKey(struct eap_sm * sm,void * priv,size_t * len)4433ff40c12SJohn Marino static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
4443ff40c12SJohn Marino {
4453ff40c12SJohn Marino struct eap_psk_data *data = priv;
4463ff40c12SJohn Marino u8 *key;
4473ff40c12SJohn Marino
4483ff40c12SJohn Marino if (data->state != SUCCESS)
4493ff40c12SJohn Marino return NULL;
4503ff40c12SJohn Marino
451*a1157835SDaniel Fojt key = os_memdup(data->msk, EAP_MSK_LEN);
4523ff40c12SJohn Marino if (key == NULL)
4533ff40c12SJohn Marino return NULL;
4543ff40c12SJohn Marino *len = EAP_MSK_LEN;
4553ff40c12SJohn Marino
4563ff40c12SJohn Marino return key;
4573ff40c12SJohn Marino }
4583ff40c12SJohn Marino
4593ff40c12SJohn Marino
eap_psk_get_emsk(struct eap_sm * sm,void * priv,size_t * len)4603ff40c12SJohn Marino static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
4613ff40c12SJohn Marino {
4623ff40c12SJohn Marino struct eap_psk_data *data = priv;
4633ff40c12SJohn Marino u8 *key;
4643ff40c12SJohn Marino
4653ff40c12SJohn Marino if (data->state != SUCCESS)
4663ff40c12SJohn Marino return NULL;
4673ff40c12SJohn Marino
468*a1157835SDaniel Fojt key = os_memdup(data->emsk, EAP_EMSK_LEN);
4693ff40c12SJohn Marino if (key == NULL)
4703ff40c12SJohn Marino return NULL;
4713ff40c12SJohn Marino *len = EAP_EMSK_LEN;
4723ff40c12SJohn Marino
4733ff40c12SJohn Marino return key;
4743ff40c12SJohn Marino }
4753ff40c12SJohn Marino
4763ff40c12SJohn Marino
eap_psk_isSuccess(struct eap_sm * sm,void * priv)4773ff40c12SJohn Marino static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
4783ff40c12SJohn Marino {
4793ff40c12SJohn Marino struct eap_psk_data *data = priv;
4803ff40c12SJohn Marino return data->state == SUCCESS;
4813ff40c12SJohn Marino }
4823ff40c12SJohn Marino
4833ff40c12SJohn Marino
eap_psk_get_session_id(struct eap_sm * sm,void * priv,size_t * len)484*a1157835SDaniel Fojt static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
485*a1157835SDaniel Fojt {
486*a1157835SDaniel Fojt struct eap_psk_data *data = priv;
487*a1157835SDaniel Fojt u8 *id;
488*a1157835SDaniel Fojt
489*a1157835SDaniel Fojt if (data->state != SUCCESS)
490*a1157835SDaniel Fojt return NULL;
491*a1157835SDaniel Fojt
492*a1157835SDaniel Fojt *len = 1 + 2 * EAP_PSK_RAND_LEN;
493*a1157835SDaniel Fojt id = os_malloc(*len);
494*a1157835SDaniel Fojt if (id == NULL)
495*a1157835SDaniel Fojt return NULL;
496*a1157835SDaniel Fojt
497*a1157835SDaniel Fojt id[0] = EAP_TYPE_PSK;
498*a1157835SDaniel Fojt os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
499*a1157835SDaniel Fojt os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
500*a1157835SDaniel Fojt wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
501*a1157835SDaniel Fojt
502*a1157835SDaniel Fojt return id;
503*a1157835SDaniel Fojt }
504*a1157835SDaniel Fojt
505*a1157835SDaniel Fojt
eap_server_psk_register(void)5063ff40c12SJohn Marino int eap_server_psk_register(void)
5073ff40c12SJohn Marino {
5083ff40c12SJohn Marino struct eap_method *eap;
5093ff40c12SJohn Marino
5103ff40c12SJohn Marino eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
5113ff40c12SJohn Marino EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
5123ff40c12SJohn Marino if (eap == NULL)
5133ff40c12SJohn Marino return -1;
5143ff40c12SJohn Marino
5153ff40c12SJohn Marino eap->init = eap_psk_init;
5163ff40c12SJohn Marino eap->reset = eap_psk_reset;
5173ff40c12SJohn Marino eap->buildReq = eap_psk_buildReq;
5183ff40c12SJohn Marino eap->check = eap_psk_check;
5193ff40c12SJohn Marino eap->process = eap_psk_process;
5203ff40c12SJohn Marino eap->isDone = eap_psk_isDone;
5213ff40c12SJohn Marino eap->getKey = eap_psk_getKey;
5223ff40c12SJohn Marino eap->isSuccess = eap_psk_isSuccess;
5233ff40c12SJohn Marino eap->get_emsk = eap_psk_get_emsk;
524*a1157835SDaniel Fojt eap->getSessionId = eap_psk_get_session_id;
5253ff40c12SJohn Marino
526*a1157835SDaniel Fojt return eap_server_method_register(eap);
5273ff40c12SJohn Marino }
528