16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer * EAP peer method: EAP-GPSK (RFC 5433)
33ff40c12SJohn Marino * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
76d49e1aeSJan Lentfer */
86d49e1aeSJan Lentfer
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer
116d49e1aeSJan Lentfer #include "common.h"
123ff40c12SJohn Marino #include "crypto/random.h"
136d49e1aeSJan Lentfer #include "eap_peer/eap_i.h"
146d49e1aeSJan Lentfer #include "eap_common/eap_gpsk_common.h"
156d49e1aeSJan Lentfer
166d49e1aeSJan Lentfer struct eap_gpsk_data {
176d49e1aeSJan Lentfer enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
186d49e1aeSJan Lentfer u8 rand_server[EAP_GPSK_RAND_LEN];
196d49e1aeSJan Lentfer u8 rand_peer[EAP_GPSK_RAND_LEN];
206d49e1aeSJan Lentfer u8 msk[EAP_MSK_LEN];
216d49e1aeSJan Lentfer u8 emsk[EAP_EMSK_LEN];
226d49e1aeSJan Lentfer u8 sk[EAP_GPSK_MAX_SK_LEN];
236d49e1aeSJan Lentfer size_t sk_len;
246d49e1aeSJan Lentfer u8 pk[EAP_GPSK_MAX_PK_LEN];
256d49e1aeSJan Lentfer size_t pk_len;
263ff40c12SJohn Marino u8 session_id[128];
273ff40c12SJohn Marino size_t id_len;
286d49e1aeSJan Lentfer u8 *id_peer;
296d49e1aeSJan Lentfer size_t id_peer_len;
306d49e1aeSJan Lentfer u8 *id_server;
316d49e1aeSJan Lentfer size_t id_server_len;
326d49e1aeSJan Lentfer int vendor; /* CSuite/Specifier */
336d49e1aeSJan Lentfer int specifier; /* CSuite/Specifier */
346d49e1aeSJan Lentfer u8 *psk;
356d49e1aeSJan Lentfer size_t psk_len;
363ff40c12SJohn Marino u16 forced_cipher; /* force cipher or 0 to allow all supported */
376d49e1aeSJan Lentfer };
386d49e1aeSJan Lentfer
396d49e1aeSJan Lentfer
406d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
416d49e1aeSJan Lentfer u8 identifier,
426d49e1aeSJan Lentfer const u8 *csuite_list,
436d49e1aeSJan Lentfer size_t csuite_list_len);
446d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
456d49e1aeSJan Lentfer u8 identifier);
466d49e1aeSJan Lentfer
476d49e1aeSJan Lentfer
486d49e1aeSJan Lentfer #ifndef CONFIG_NO_STDOUT_DEBUG
eap_gpsk_state_txt(int state)496d49e1aeSJan Lentfer static const char * eap_gpsk_state_txt(int state)
506d49e1aeSJan Lentfer {
516d49e1aeSJan Lentfer switch (state) {
526d49e1aeSJan Lentfer case GPSK_1:
536d49e1aeSJan Lentfer return "GPSK-1";
546d49e1aeSJan Lentfer case GPSK_3:
556d49e1aeSJan Lentfer return "GPSK-3";
566d49e1aeSJan Lentfer case SUCCESS:
576d49e1aeSJan Lentfer return "SUCCESS";
586d49e1aeSJan Lentfer case FAILURE:
596d49e1aeSJan Lentfer return "FAILURE";
606d49e1aeSJan Lentfer default:
616d49e1aeSJan Lentfer return "?";
626d49e1aeSJan Lentfer }
636d49e1aeSJan Lentfer }
646d49e1aeSJan Lentfer #endif /* CONFIG_NO_STDOUT_DEBUG */
656d49e1aeSJan Lentfer
666d49e1aeSJan Lentfer
eap_gpsk_state(struct eap_gpsk_data * data,int state)676d49e1aeSJan Lentfer static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
686d49e1aeSJan Lentfer {
696d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
706d49e1aeSJan Lentfer eap_gpsk_state_txt(data->state),
716d49e1aeSJan Lentfer eap_gpsk_state_txt(state));
726d49e1aeSJan Lentfer data->state = state;
736d49e1aeSJan Lentfer }
746d49e1aeSJan Lentfer
756d49e1aeSJan Lentfer
766d49e1aeSJan Lentfer static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
776d49e1aeSJan Lentfer
786d49e1aeSJan Lentfer
eap_gpsk_init(struct eap_sm * sm)796d49e1aeSJan Lentfer static void * eap_gpsk_init(struct eap_sm *sm)
806d49e1aeSJan Lentfer {
816d49e1aeSJan Lentfer struct eap_gpsk_data *data;
826d49e1aeSJan Lentfer const u8 *identity, *password;
836d49e1aeSJan Lentfer size_t identity_len, password_len;
843ff40c12SJohn Marino const char *phase1;
856d49e1aeSJan Lentfer
866d49e1aeSJan Lentfer password = eap_get_config_password(sm, &password_len);
876d49e1aeSJan Lentfer if (password == NULL) {
886d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
896d49e1aeSJan Lentfer return NULL;
906d49e1aeSJan Lentfer }
916d49e1aeSJan Lentfer
926d49e1aeSJan Lentfer data = os_zalloc(sizeof(*data));
936d49e1aeSJan Lentfer if (data == NULL)
946d49e1aeSJan Lentfer return NULL;
956d49e1aeSJan Lentfer data->state = GPSK_1;
966d49e1aeSJan Lentfer
976d49e1aeSJan Lentfer identity = eap_get_config_identity(sm, &identity_len);
986d49e1aeSJan Lentfer if (identity) {
99*a1157835SDaniel Fojt data->id_peer = os_memdup(identity, identity_len);
1006d49e1aeSJan Lentfer if (data->id_peer == NULL) {
1016d49e1aeSJan Lentfer eap_gpsk_deinit(sm, data);
1026d49e1aeSJan Lentfer return NULL;
1036d49e1aeSJan Lentfer }
1046d49e1aeSJan Lentfer data->id_peer_len = identity_len;
1056d49e1aeSJan Lentfer }
1066d49e1aeSJan Lentfer
1073ff40c12SJohn Marino phase1 = eap_get_config_phase1(sm);
1083ff40c12SJohn Marino if (phase1) {
1093ff40c12SJohn Marino const char *pos;
1103ff40c12SJohn Marino
1113ff40c12SJohn Marino pos = os_strstr(phase1, "cipher=");
1123ff40c12SJohn Marino if (pos) {
1133ff40c12SJohn Marino data->forced_cipher = atoi(pos + 7);
1143ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
1153ff40c12SJohn Marino data->forced_cipher);
1163ff40c12SJohn Marino }
1173ff40c12SJohn Marino }
1183ff40c12SJohn Marino
119*a1157835SDaniel Fojt data->psk = os_memdup(password, password_len);
1206d49e1aeSJan Lentfer if (data->psk == NULL) {
1216d49e1aeSJan Lentfer eap_gpsk_deinit(sm, data);
1226d49e1aeSJan Lentfer return NULL;
1236d49e1aeSJan Lentfer }
1246d49e1aeSJan Lentfer data->psk_len = password_len;
1256d49e1aeSJan Lentfer
1266d49e1aeSJan Lentfer return data;
1276d49e1aeSJan Lentfer }
1286d49e1aeSJan Lentfer
1296d49e1aeSJan Lentfer
eap_gpsk_deinit(struct eap_sm * sm,void * priv)1306d49e1aeSJan Lentfer static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
1316d49e1aeSJan Lentfer {
1326d49e1aeSJan Lentfer struct eap_gpsk_data *data = priv;
1336d49e1aeSJan Lentfer os_free(data->id_server);
1346d49e1aeSJan Lentfer os_free(data->id_peer);
135*a1157835SDaniel Fojt if (data->psk) {
136*a1157835SDaniel Fojt os_memset(data->psk, 0, data->psk_len);
1376d49e1aeSJan Lentfer os_free(data->psk);
138*a1157835SDaniel Fojt }
139*a1157835SDaniel Fojt bin_clear_free(data, sizeof(*data));
1406d49e1aeSJan Lentfer }
1416d49e1aeSJan Lentfer
1426d49e1aeSJan Lentfer
eap_gpsk_process_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)1436d49e1aeSJan Lentfer static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
1446d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
1456d49e1aeSJan Lentfer {
1466d49e1aeSJan Lentfer u16 alen;
1476d49e1aeSJan Lentfer
1486d49e1aeSJan Lentfer if (end - pos < 2) {
1496d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
1506d49e1aeSJan Lentfer return NULL;
1516d49e1aeSJan Lentfer }
1526d49e1aeSJan Lentfer alen = WPA_GET_BE16(pos);
1536d49e1aeSJan Lentfer pos += 2;
1546d49e1aeSJan Lentfer if (end - pos < alen) {
1556d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
1566d49e1aeSJan Lentfer return NULL;
1576d49e1aeSJan Lentfer }
1586d49e1aeSJan Lentfer os_free(data->id_server);
159*a1157835SDaniel Fojt data->id_server = os_memdup(pos, alen);
1606d49e1aeSJan Lentfer if (data->id_server == NULL) {
1616d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
1626d49e1aeSJan Lentfer return NULL;
1636d49e1aeSJan Lentfer }
1646d49e1aeSJan Lentfer data->id_server_len = alen;
1656d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
1666d49e1aeSJan Lentfer data->id_server, data->id_server_len);
1676d49e1aeSJan Lentfer pos += alen;
1686d49e1aeSJan Lentfer
1696d49e1aeSJan Lentfer return pos;
1706d49e1aeSJan Lentfer }
1716d49e1aeSJan Lentfer
1726d49e1aeSJan Lentfer
eap_gpsk_process_rand_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)1736d49e1aeSJan Lentfer static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
1746d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
1756d49e1aeSJan Lentfer {
1766d49e1aeSJan Lentfer if (pos == NULL)
1776d49e1aeSJan Lentfer return NULL;
1786d49e1aeSJan Lentfer
1796d49e1aeSJan Lentfer if (end - pos < EAP_GPSK_RAND_LEN) {
1806d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
1816d49e1aeSJan Lentfer return NULL;
1826d49e1aeSJan Lentfer }
1836d49e1aeSJan Lentfer os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
1846d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
1856d49e1aeSJan Lentfer data->rand_server, EAP_GPSK_RAND_LEN);
1866d49e1aeSJan Lentfer pos += EAP_GPSK_RAND_LEN;
1876d49e1aeSJan Lentfer
1886d49e1aeSJan Lentfer return pos;
1896d49e1aeSJan Lentfer }
1906d49e1aeSJan Lentfer
1916d49e1aeSJan Lentfer
eap_gpsk_select_csuite(struct eap_sm * sm,struct eap_gpsk_data * data,const u8 * csuite_list,size_t csuite_list_len)1926d49e1aeSJan Lentfer static int eap_gpsk_select_csuite(struct eap_sm *sm,
1936d49e1aeSJan Lentfer struct eap_gpsk_data *data,
1946d49e1aeSJan Lentfer const u8 *csuite_list,
1956d49e1aeSJan Lentfer size_t csuite_list_len)
1966d49e1aeSJan Lentfer {
1976d49e1aeSJan Lentfer struct eap_gpsk_csuite *csuite;
1986d49e1aeSJan Lentfer int i, count;
1996d49e1aeSJan Lentfer
2006d49e1aeSJan Lentfer count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
2016d49e1aeSJan Lentfer data->vendor = EAP_GPSK_VENDOR_IETF;
2026d49e1aeSJan Lentfer data->specifier = EAP_GPSK_CIPHER_RESERVED;
2036d49e1aeSJan Lentfer csuite = (struct eap_gpsk_csuite *) csuite_list;
2046d49e1aeSJan Lentfer for (i = 0; i < count; i++) {
2056d49e1aeSJan Lentfer int vendor, specifier;
2066d49e1aeSJan Lentfer vendor = WPA_GET_BE32(csuite->vendor);
2076d49e1aeSJan Lentfer specifier = WPA_GET_BE16(csuite->specifier);
2086d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
2096d49e1aeSJan Lentfer i, vendor, specifier);
2106d49e1aeSJan Lentfer if (data->vendor == EAP_GPSK_VENDOR_IETF &&
2116d49e1aeSJan Lentfer data->specifier == EAP_GPSK_CIPHER_RESERVED &&
2123ff40c12SJohn Marino eap_gpsk_supported_ciphersuite(vendor, specifier) &&
2133ff40c12SJohn Marino (!data->forced_cipher || data->forced_cipher == specifier))
2143ff40c12SJohn Marino {
2156d49e1aeSJan Lentfer data->vendor = vendor;
2166d49e1aeSJan Lentfer data->specifier = specifier;
2176d49e1aeSJan Lentfer }
2186d49e1aeSJan Lentfer csuite++;
2196d49e1aeSJan Lentfer }
2206d49e1aeSJan Lentfer if (data->vendor == EAP_GPSK_VENDOR_IETF &&
2216d49e1aeSJan Lentfer data->specifier == EAP_GPSK_CIPHER_RESERVED) {
2226d49e1aeSJan Lentfer wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
2236d49e1aeSJan Lentfer "ciphersuite found");
2246d49e1aeSJan Lentfer return -1;
2256d49e1aeSJan Lentfer }
2266d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
2276d49e1aeSJan Lentfer data->vendor, data->specifier);
2286d49e1aeSJan Lentfer
2296d49e1aeSJan Lentfer return 0;
2306d49e1aeSJan Lentfer }
2316d49e1aeSJan Lentfer
2326d49e1aeSJan Lentfer
eap_gpsk_process_csuite_list(struct eap_sm * sm,struct eap_gpsk_data * data,const u8 ** list,size_t * list_len,const u8 * pos,const u8 * end)2336d49e1aeSJan Lentfer static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
2346d49e1aeSJan Lentfer struct eap_gpsk_data *data,
2356d49e1aeSJan Lentfer const u8 **list,
2366d49e1aeSJan Lentfer size_t *list_len,
2376d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
2386d49e1aeSJan Lentfer {
239*a1157835SDaniel Fojt size_t len;
240*a1157835SDaniel Fojt
2416d49e1aeSJan Lentfer if (pos == NULL)
2426d49e1aeSJan Lentfer return NULL;
2436d49e1aeSJan Lentfer
2446d49e1aeSJan Lentfer if (end - pos < 2) {
2456d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
2466d49e1aeSJan Lentfer return NULL;
2476d49e1aeSJan Lentfer }
248*a1157835SDaniel Fojt len = WPA_GET_BE16(pos);
2496d49e1aeSJan Lentfer pos += 2;
250*a1157835SDaniel Fojt if (len > (size_t) (end - pos)) {
2516d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
2526d49e1aeSJan Lentfer return NULL;
2536d49e1aeSJan Lentfer }
254*a1157835SDaniel Fojt if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
2556d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
256*a1157835SDaniel Fojt (unsigned long) len);
2576d49e1aeSJan Lentfer return NULL;
2586d49e1aeSJan Lentfer }
2596d49e1aeSJan Lentfer
260*a1157835SDaniel Fojt if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
2616d49e1aeSJan Lentfer return NULL;
2626d49e1aeSJan Lentfer
263*a1157835SDaniel Fojt *list = pos;
264*a1157835SDaniel Fojt *list_len = len;
265*a1157835SDaniel Fojt pos += len;
266*a1157835SDaniel Fojt
2676d49e1aeSJan Lentfer return pos;
2686d49e1aeSJan Lentfer }
2696d49e1aeSJan Lentfer
2706d49e1aeSJan Lentfer
eap_gpsk_process_gpsk_1(struct eap_sm * sm,struct eap_gpsk_data * data,struct eap_method_ret * ret,u8 identifier,const u8 * payload,size_t payload_len)2716d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
2726d49e1aeSJan Lentfer struct eap_gpsk_data *data,
2736d49e1aeSJan Lentfer struct eap_method_ret *ret,
274*a1157835SDaniel Fojt u8 identifier,
2756d49e1aeSJan Lentfer const u8 *payload,
2766d49e1aeSJan Lentfer size_t payload_len)
2776d49e1aeSJan Lentfer {
2786d49e1aeSJan Lentfer size_t csuite_list_len;
2796d49e1aeSJan Lentfer const u8 *csuite_list, *pos, *end;
2806d49e1aeSJan Lentfer struct wpabuf *resp;
2816d49e1aeSJan Lentfer
2826d49e1aeSJan Lentfer if (data->state != GPSK_1) {
2836d49e1aeSJan Lentfer ret->ignore = TRUE;
2846d49e1aeSJan Lentfer return NULL;
2856d49e1aeSJan Lentfer }
2866d49e1aeSJan Lentfer
2876d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
2886d49e1aeSJan Lentfer
2896d49e1aeSJan Lentfer end = payload + payload_len;
2906d49e1aeSJan Lentfer
2916d49e1aeSJan Lentfer pos = eap_gpsk_process_id_server(data, payload, end);
2926d49e1aeSJan Lentfer pos = eap_gpsk_process_rand_server(data, pos, end);
2936d49e1aeSJan Lentfer pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
2946d49e1aeSJan Lentfer &csuite_list_len, pos, end);
2956d49e1aeSJan Lentfer if (pos == NULL) {
2963ff40c12SJohn Marino ret->methodState = METHOD_DONE;
2976d49e1aeSJan Lentfer eap_gpsk_state(data, FAILURE);
2986d49e1aeSJan Lentfer return NULL;
2996d49e1aeSJan Lentfer }
3006d49e1aeSJan Lentfer
301*a1157835SDaniel Fojt resp = eap_gpsk_send_gpsk_2(data, identifier,
3026d49e1aeSJan Lentfer csuite_list, csuite_list_len);
3036d49e1aeSJan Lentfer if (resp == NULL)
3046d49e1aeSJan Lentfer return NULL;
3056d49e1aeSJan Lentfer
3066d49e1aeSJan Lentfer eap_gpsk_state(data, GPSK_3);
3076d49e1aeSJan Lentfer
3086d49e1aeSJan Lentfer return resp;
3096d49e1aeSJan Lentfer }
3106d49e1aeSJan Lentfer
3116d49e1aeSJan Lentfer
eap_gpsk_send_gpsk_2(struct eap_gpsk_data * data,u8 identifier,const u8 * csuite_list,size_t csuite_list_len)3126d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
3136d49e1aeSJan Lentfer u8 identifier,
3146d49e1aeSJan Lentfer const u8 *csuite_list,
3156d49e1aeSJan Lentfer size_t csuite_list_len)
3166d49e1aeSJan Lentfer {
3176d49e1aeSJan Lentfer struct wpabuf *resp;
3186d49e1aeSJan Lentfer size_t len, miclen;
3196d49e1aeSJan Lentfer u8 *rpos, *start;
3206d49e1aeSJan Lentfer struct eap_gpsk_csuite *csuite;
3216d49e1aeSJan Lentfer
3226d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
3236d49e1aeSJan Lentfer
3246d49e1aeSJan Lentfer miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
3256d49e1aeSJan Lentfer len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
3266d49e1aeSJan Lentfer 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
3276d49e1aeSJan Lentfer sizeof(struct eap_gpsk_csuite) + 2 + miclen;
3286d49e1aeSJan Lentfer
3296d49e1aeSJan Lentfer resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
3306d49e1aeSJan Lentfer EAP_CODE_RESPONSE, identifier);
3316d49e1aeSJan Lentfer if (resp == NULL)
3326d49e1aeSJan Lentfer return NULL;
3336d49e1aeSJan Lentfer
3346d49e1aeSJan Lentfer wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
3356d49e1aeSJan Lentfer start = wpabuf_put(resp, 0);
3366d49e1aeSJan Lentfer
3376d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
3386d49e1aeSJan Lentfer data->id_peer, data->id_peer_len);
3396d49e1aeSJan Lentfer wpabuf_put_be16(resp, data->id_peer_len);
3406d49e1aeSJan Lentfer wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
3416d49e1aeSJan Lentfer
3426d49e1aeSJan Lentfer wpabuf_put_be16(resp, data->id_server_len);
3436d49e1aeSJan Lentfer wpabuf_put_data(resp, data->id_server, data->id_server_len);
3446d49e1aeSJan Lentfer
3453ff40c12SJohn Marino if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
3466d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
3476d49e1aeSJan Lentfer "for RAND_Peer");
3486d49e1aeSJan Lentfer eap_gpsk_state(data, FAILURE);
3496d49e1aeSJan Lentfer wpabuf_free(resp);
3506d49e1aeSJan Lentfer return NULL;
3516d49e1aeSJan Lentfer }
3526d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
3536d49e1aeSJan Lentfer data->rand_peer, EAP_GPSK_RAND_LEN);
3546d49e1aeSJan Lentfer wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
3556d49e1aeSJan Lentfer wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
3566d49e1aeSJan Lentfer
3576d49e1aeSJan Lentfer wpabuf_put_be16(resp, csuite_list_len);
3586d49e1aeSJan Lentfer wpabuf_put_data(resp, csuite_list, csuite_list_len);
3596d49e1aeSJan Lentfer
3606d49e1aeSJan Lentfer csuite = wpabuf_put(resp, sizeof(*csuite));
3616d49e1aeSJan Lentfer WPA_PUT_BE32(csuite->vendor, data->vendor);
3626d49e1aeSJan Lentfer WPA_PUT_BE16(csuite->specifier, data->specifier);
3636d49e1aeSJan Lentfer
3646d49e1aeSJan Lentfer if (eap_gpsk_derive_keys(data->psk, data->psk_len,
3656d49e1aeSJan Lentfer data->vendor, data->specifier,
3666d49e1aeSJan Lentfer data->rand_peer, data->rand_server,
3676d49e1aeSJan Lentfer data->id_peer, data->id_peer_len,
3686d49e1aeSJan Lentfer data->id_server, data->id_server_len,
3696d49e1aeSJan Lentfer data->msk, data->emsk,
3706d49e1aeSJan Lentfer data->sk, &data->sk_len,
3716d49e1aeSJan Lentfer data->pk, &data->pk_len) < 0) {
3726d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
3736d49e1aeSJan Lentfer eap_gpsk_state(data, FAILURE);
3746d49e1aeSJan Lentfer wpabuf_free(resp);
3756d49e1aeSJan Lentfer return NULL;
3766d49e1aeSJan Lentfer }
3776d49e1aeSJan Lentfer
3783ff40c12SJohn Marino if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
3793ff40c12SJohn Marino data->vendor, data->specifier,
3803ff40c12SJohn Marino data->rand_peer, data->rand_server,
3813ff40c12SJohn Marino data->id_peer, data->id_peer_len,
3823ff40c12SJohn Marino data->id_server, data->id_server_len,
3833ff40c12SJohn Marino EAP_TYPE_GPSK,
3843ff40c12SJohn Marino data->session_id, &data->id_len) < 0) {
3853ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
3863ff40c12SJohn Marino eap_gpsk_state(data, FAILURE);
3873ff40c12SJohn Marino wpabuf_free(resp);
3883ff40c12SJohn Marino return NULL;
3893ff40c12SJohn Marino }
3903ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
3913ff40c12SJohn Marino data->session_id, data->id_len);
3923ff40c12SJohn Marino
3936d49e1aeSJan Lentfer /* No PD_Payload_1 */
3946d49e1aeSJan Lentfer wpabuf_put_be16(resp, 0);
3956d49e1aeSJan Lentfer
3966d49e1aeSJan Lentfer rpos = wpabuf_put(resp, miclen);
3976d49e1aeSJan Lentfer if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
3986d49e1aeSJan Lentfer data->specifier, start, rpos - start, rpos) <
3996d49e1aeSJan Lentfer 0) {
4006d49e1aeSJan Lentfer eap_gpsk_state(data, FAILURE);
4016d49e1aeSJan Lentfer wpabuf_free(resp);
4026d49e1aeSJan Lentfer return NULL;
4036d49e1aeSJan Lentfer }
4046d49e1aeSJan Lentfer
4056d49e1aeSJan Lentfer return resp;
4066d49e1aeSJan Lentfer }
4076d49e1aeSJan Lentfer
4086d49e1aeSJan Lentfer
eap_gpsk_validate_rand(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)4096d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
4106d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
4116d49e1aeSJan Lentfer {
4126d49e1aeSJan Lentfer if (end - pos < EAP_GPSK_RAND_LEN) {
4136d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4146d49e1aeSJan Lentfer "RAND_Peer");
4156d49e1aeSJan Lentfer return NULL;
4166d49e1aeSJan Lentfer }
4176d49e1aeSJan Lentfer if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
4186d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
4196d49e1aeSJan Lentfer "GPSK-3 did not match");
4206d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
4216d49e1aeSJan Lentfer data->rand_peer, EAP_GPSK_RAND_LEN);
4226d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
4236d49e1aeSJan Lentfer pos, EAP_GPSK_RAND_LEN);
4246d49e1aeSJan Lentfer return NULL;
4256d49e1aeSJan Lentfer }
4266d49e1aeSJan Lentfer pos += EAP_GPSK_RAND_LEN;
4276d49e1aeSJan Lentfer
4286d49e1aeSJan Lentfer if (end - pos < EAP_GPSK_RAND_LEN) {
4296d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4306d49e1aeSJan Lentfer "RAND_Server");
4316d49e1aeSJan Lentfer return NULL;
4326d49e1aeSJan Lentfer }
4336d49e1aeSJan Lentfer if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
4346d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
4356d49e1aeSJan Lentfer "GPSK-3 did not match");
4366d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
4376d49e1aeSJan Lentfer data->rand_server, EAP_GPSK_RAND_LEN);
4386d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
4396d49e1aeSJan Lentfer pos, EAP_GPSK_RAND_LEN);
4406d49e1aeSJan Lentfer return NULL;
4416d49e1aeSJan Lentfer }
4426d49e1aeSJan Lentfer pos += EAP_GPSK_RAND_LEN;
4436d49e1aeSJan Lentfer
4446d49e1aeSJan Lentfer return pos;
4456d49e1aeSJan Lentfer }
4466d49e1aeSJan Lentfer
4476d49e1aeSJan Lentfer
eap_gpsk_validate_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)4486d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
4496d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
4506d49e1aeSJan Lentfer {
4516d49e1aeSJan Lentfer size_t len;
4526d49e1aeSJan Lentfer
4536d49e1aeSJan Lentfer if (pos == NULL)
4546d49e1aeSJan Lentfer return NULL;
4556d49e1aeSJan Lentfer
4566d49e1aeSJan Lentfer if (end - pos < (int) 2) {
4576d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4586d49e1aeSJan Lentfer "length(ID_Server)");
4596d49e1aeSJan Lentfer return NULL;
4606d49e1aeSJan Lentfer }
4616d49e1aeSJan Lentfer
4626d49e1aeSJan Lentfer len = WPA_GET_BE16(pos);
4636d49e1aeSJan Lentfer pos += 2;
4646d49e1aeSJan Lentfer
4656d49e1aeSJan Lentfer if (end - pos < (int) len) {
4666d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4676d49e1aeSJan Lentfer "ID_Server");
4686d49e1aeSJan Lentfer return NULL;
4696d49e1aeSJan Lentfer }
4706d49e1aeSJan Lentfer
4716d49e1aeSJan Lentfer if (len != data->id_server_len ||
4726d49e1aeSJan Lentfer os_memcmp(pos, data->id_server, len) != 0) {
4736d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
4746d49e1aeSJan Lentfer "the one used in GPSK-1");
4756d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
4766d49e1aeSJan Lentfer data->id_server, data->id_server_len);
4776d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
4786d49e1aeSJan Lentfer pos, len);
4796d49e1aeSJan Lentfer return NULL;
4806d49e1aeSJan Lentfer }
4816d49e1aeSJan Lentfer
4826d49e1aeSJan Lentfer pos += len;
4836d49e1aeSJan Lentfer
4846d49e1aeSJan Lentfer return pos;
4856d49e1aeSJan Lentfer }
4866d49e1aeSJan Lentfer
4876d49e1aeSJan Lentfer
eap_gpsk_validate_csuite(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)4886d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
4896d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
4906d49e1aeSJan Lentfer {
4916d49e1aeSJan Lentfer int vendor, specifier;
4926d49e1aeSJan Lentfer const struct eap_gpsk_csuite *csuite;
4936d49e1aeSJan Lentfer
4946d49e1aeSJan Lentfer if (pos == NULL)
4956d49e1aeSJan Lentfer return NULL;
4966d49e1aeSJan Lentfer
4976d49e1aeSJan Lentfer if (end - pos < (int) sizeof(*csuite)) {
4986d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4996d49e1aeSJan Lentfer "CSuite_Sel");
5006d49e1aeSJan Lentfer return NULL;
5016d49e1aeSJan Lentfer }
5026d49e1aeSJan Lentfer csuite = (const struct eap_gpsk_csuite *) pos;
5036d49e1aeSJan Lentfer vendor = WPA_GET_BE32(csuite->vendor);
5046d49e1aeSJan Lentfer specifier = WPA_GET_BE16(csuite->specifier);
5056d49e1aeSJan Lentfer pos += sizeof(*csuite);
5066d49e1aeSJan Lentfer if (vendor != data->vendor || specifier != data->specifier) {
5076d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
5086d49e1aeSJan Lentfer "match with the one sent in GPSK-2 (%d:%d)",
5096d49e1aeSJan Lentfer vendor, specifier, data->vendor, data->specifier);
5106d49e1aeSJan Lentfer return NULL;
5116d49e1aeSJan Lentfer }
5126d49e1aeSJan Lentfer
5136d49e1aeSJan Lentfer return pos;
5146d49e1aeSJan Lentfer }
5156d49e1aeSJan Lentfer
5166d49e1aeSJan Lentfer
eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)5176d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
5186d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
5196d49e1aeSJan Lentfer {
5206d49e1aeSJan Lentfer u16 alen;
5216d49e1aeSJan Lentfer
5226d49e1aeSJan Lentfer if (pos == NULL)
5236d49e1aeSJan Lentfer return NULL;
5246d49e1aeSJan Lentfer
5256d49e1aeSJan Lentfer if (end - pos < 2) {
5266d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
5276d49e1aeSJan Lentfer "PD_Payload_2 length");
5286d49e1aeSJan Lentfer return NULL;
5296d49e1aeSJan Lentfer }
5306d49e1aeSJan Lentfer alen = WPA_GET_BE16(pos);
5316d49e1aeSJan Lentfer pos += 2;
5326d49e1aeSJan Lentfer if (end - pos < alen) {
5336d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
5346d49e1aeSJan Lentfer "%d-octet PD_Payload_2", alen);
5356d49e1aeSJan Lentfer return NULL;
5366d49e1aeSJan Lentfer }
5376d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
5386d49e1aeSJan Lentfer pos += alen;
5396d49e1aeSJan Lentfer
5406d49e1aeSJan Lentfer return pos;
5416d49e1aeSJan Lentfer }
5426d49e1aeSJan Lentfer
5436d49e1aeSJan Lentfer
eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data * data,const u8 * payload,const u8 * pos,const u8 * end)5446d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
5456d49e1aeSJan Lentfer const u8 *payload,
5466d49e1aeSJan Lentfer const u8 *pos, const u8 *end)
5476d49e1aeSJan Lentfer {
5486d49e1aeSJan Lentfer size_t miclen;
5496d49e1aeSJan Lentfer u8 mic[EAP_GPSK_MAX_MIC_LEN];
5506d49e1aeSJan Lentfer
5516d49e1aeSJan Lentfer if (pos == NULL)
5526d49e1aeSJan Lentfer return NULL;
5536d49e1aeSJan Lentfer
5546d49e1aeSJan Lentfer miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
5556d49e1aeSJan Lentfer if (end - pos < (int) miclen) {
5566d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
5576d49e1aeSJan Lentfer "(left=%lu miclen=%lu)",
5586d49e1aeSJan Lentfer (unsigned long) (end - pos),
5596d49e1aeSJan Lentfer (unsigned long) miclen);
5606d49e1aeSJan Lentfer return NULL;
5616d49e1aeSJan Lentfer }
5626d49e1aeSJan Lentfer if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
5636d49e1aeSJan Lentfer data->specifier, payload, pos - payload, mic)
5646d49e1aeSJan Lentfer < 0) {
5656d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
5666d49e1aeSJan Lentfer return NULL;
5676d49e1aeSJan Lentfer }
568*a1157835SDaniel Fojt if (os_memcmp_const(mic, pos, miclen) != 0) {
5696d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
5706d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
5716d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
5726d49e1aeSJan Lentfer return NULL;
5736d49e1aeSJan Lentfer }
5746d49e1aeSJan Lentfer pos += miclen;
5756d49e1aeSJan Lentfer
5766d49e1aeSJan Lentfer return pos;
5776d49e1aeSJan Lentfer }
5786d49e1aeSJan Lentfer
5796d49e1aeSJan Lentfer
eap_gpsk_process_gpsk_3(struct eap_sm * sm,struct eap_gpsk_data * data,struct eap_method_ret * ret,u8 identifier,const u8 * payload,size_t payload_len)5806d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
5816d49e1aeSJan Lentfer struct eap_gpsk_data *data,
5826d49e1aeSJan Lentfer struct eap_method_ret *ret,
583*a1157835SDaniel Fojt u8 identifier,
5846d49e1aeSJan Lentfer const u8 *payload,
5856d49e1aeSJan Lentfer size_t payload_len)
5866d49e1aeSJan Lentfer {
5876d49e1aeSJan Lentfer struct wpabuf *resp;
5886d49e1aeSJan Lentfer const u8 *pos, *end;
5896d49e1aeSJan Lentfer
5906d49e1aeSJan Lentfer if (data->state != GPSK_3) {
5916d49e1aeSJan Lentfer ret->ignore = TRUE;
5926d49e1aeSJan Lentfer return NULL;
5936d49e1aeSJan Lentfer }
5946d49e1aeSJan Lentfer
5956d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
5966d49e1aeSJan Lentfer
5976d49e1aeSJan Lentfer end = payload + payload_len;
5986d49e1aeSJan Lentfer
5996d49e1aeSJan Lentfer pos = eap_gpsk_validate_rand(data, payload, end);
6006d49e1aeSJan Lentfer pos = eap_gpsk_validate_id_server(data, pos, end);
6016d49e1aeSJan Lentfer pos = eap_gpsk_validate_csuite(data, pos, end);
6026d49e1aeSJan Lentfer pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
6036d49e1aeSJan Lentfer pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
6046d49e1aeSJan Lentfer
6056d49e1aeSJan Lentfer if (pos == NULL) {
6066d49e1aeSJan Lentfer eap_gpsk_state(data, FAILURE);
6076d49e1aeSJan Lentfer return NULL;
6086d49e1aeSJan Lentfer }
6096d49e1aeSJan Lentfer if (pos != end) {
6106d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
6116d49e1aeSJan Lentfer "data in the end of GPSK-2",
6126d49e1aeSJan Lentfer (unsigned long) (end - pos));
6136d49e1aeSJan Lentfer }
6146d49e1aeSJan Lentfer
615*a1157835SDaniel Fojt resp = eap_gpsk_send_gpsk_4(data, identifier);
6166d49e1aeSJan Lentfer if (resp == NULL)
6176d49e1aeSJan Lentfer return NULL;
6186d49e1aeSJan Lentfer
6196d49e1aeSJan Lentfer eap_gpsk_state(data, SUCCESS);
6206d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
6216d49e1aeSJan Lentfer ret->decision = DECISION_UNCOND_SUCC;
6226d49e1aeSJan Lentfer
6236d49e1aeSJan Lentfer return resp;
6246d49e1aeSJan Lentfer }
6256d49e1aeSJan Lentfer
6266d49e1aeSJan Lentfer
eap_gpsk_send_gpsk_4(struct eap_gpsk_data * data,u8 identifier)6276d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
6286d49e1aeSJan Lentfer u8 identifier)
6296d49e1aeSJan Lentfer {
6306d49e1aeSJan Lentfer struct wpabuf *resp;
6316d49e1aeSJan Lentfer u8 *rpos, *start;
6326d49e1aeSJan Lentfer size_t mlen;
6336d49e1aeSJan Lentfer
6346d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
6356d49e1aeSJan Lentfer
6366d49e1aeSJan Lentfer mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
6376d49e1aeSJan Lentfer
6386d49e1aeSJan Lentfer resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
6396d49e1aeSJan Lentfer EAP_CODE_RESPONSE, identifier);
6406d49e1aeSJan Lentfer if (resp == NULL)
6416d49e1aeSJan Lentfer return NULL;
6426d49e1aeSJan Lentfer
6436d49e1aeSJan Lentfer wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
6446d49e1aeSJan Lentfer start = wpabuf_put(resp, 0);
6456d49e1aeSJan Lentfer
6466d49e1aeSJan Lentfer /* No PD_Payload_3 */
6476d49e1aeSJan Lentfer wpabuf_put_be16(resp, 0);
6486d49e1aeSJan Lentfer
6496d49e1aeSJan Lentfer rpos = wpabuf_put(resp, mlen);
6506d49e1aeSJan Lentfer if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
6516d49e1aeSJan Lentfer data->specifier, start, rpos - start, rpos) <
6526d49e1aeSJan Lentfer 0) {
6536d49e1aeSJan Lentfer eap_gpsk_state(data, FAILURE);
6546d49e1aeSJan Lentfer wpabuf_free(resp);
6556d49e1aeSJan Lentfer return NULL;
6566d49e1aeSJan Lentfer }
6576d49e1aeSJan Lentfer
6586d49e1aeSJan Lentfer return resp;
6596d49e1aeSJan Lentfer }
6606d49e1aeSJan Lentfer
6616d49e1aeSJan Lentfer
eap_gpsk_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)6626d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
6636d49e1aeSJan Lentfer struct eap_method_ret *ret,
6646d49e1aeSJan Lentfer const struct wpabuf *reqData)
6656d49e1aeSJan Lentfer {
6666d49e1aeSJan Lentfer struct eap_gpsk_data *data = priv;
6676d49e1aeSJan Lentfer struct wpabuf *resp;
6686d49e1aeSJan Lentfer const u8 *pos;
6696d49e1aeSJan Lentfer size_t len;
670*a1157835SDaniel Fojt u8 opcode, id;
6716d49e1aeSJan Lentfer
6726d49e1aeSJan Lentfer pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
6736d49e1aeSJan Lentfer if (pos == NULL || len < 1) {
6746d49e1aeSJan Lentfer ret->ignore = TRUE;
6756d49e1aeSJan Lentfer return NULL;
6766d49e1aeSJan Lentfer }
6776d49e1aeSJan Lentfer
678*a1157835SDaniel Fojt id = eap_get_id(reqData);
679*a1157835SDaniel Fojt opcode = *pos++;
680*a1157835SDaniel Fojt len--;
681*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
6826d49e1aeSJan Lentfer
6836d49e1aeSJan Lentfer ret->ignore = FALSE;
6846d49e1aeSJan Lentfer ret->methodState = METHOD_MAY_CONT;
6856d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
6866d49e1aeSJan Lentfer ret->allowNotifications = FALSE;
6876d49e1aeSJan Lentfer
688*a1157835SDaniel Fojt switch (opcode) {
6896d49e1aeSJan Lentfer case EAP_GPSK_OPCODE_GPSK_1:
690*a1157835SDaniel Fojt resp = eap_gpsk_process_gpsk_1(sm, data, ret, id, pos, len);
6916d49e1aeSJan Lentfer break;
6926d49e1aeSJan Lentfer case EAP_GPSK_OPCODE_GPSK_3:
693*a1157835SDaniel Fojt resp = eap_gpsk_process_gpsk_3(sm, data, ret, id, pos, len);
6946d49e1aeSJan Lentfer break;
6956d49e1aeSJan Lentfer default:
696*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
697*a1157835SDaniel Fojt "EAP-GPSK: Ignoring message with unknown opcode %d",
698*a1157835SDaniel Fojt opcode);
6996d49e1aeSJan Lentfer ret->ignore = TRUE;
7006d49e1aeSJan Lentfer return NULL;
7016d49e1aeSJan Lentfer }
7026d49e1aeSJan Lentfer
7036d49e1aeSJan Lentfer return resp;
7046d49e1aeSJan Lentfer }
7056d49e1aeSJan Lentfer
7066d49e1aeSJan Lentfer
eap_gpsk_isKeyAvailable(struct eap_sm * sm,void * priv)7076d49e1aeSJan Lentfer static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
7086d49e1aeSJan Lentfer {
7096d49e1aeSJan Lentfer struct eap_gpsk_data *data = priv;
7106d49e1aeSJan Lentfer return data->state == SUCCESS;
7116d49e1aeSJan Lentfer }
7126d49e1aeSJan Lentfer
7136d49e1aeSJan Lentfer
eap_gpsk_getKey(struct eap_sm * sm,void * priv,size_t * len)7146d49e1aeSJan Lentfer static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
7156d49e1aeSJan Lentfer {
7166d49e1aeSJan Lentfer struct eap_gpsk_data *data = priv;
7176d49e1aeSJan Lentfer u8 *key;
7186d49e1aeSJan Lentfer
7196d49e1aeSJan Lentfer if (data->state != SUCCESS)
7206d49e1aeSJan Lentfer return NULL;
7216d49e1aeSJan Lentfer
722*a1157835SDaniel Fojt key = os_memdup(data->msk, EAP_MSK_LEN);
7236d49e1aeSJan Lentfer if (key == NULL)
7246d49e1aeSJan Lentfer return NULL;
7256d49e1aeSJan Lentfer *len = EAP_MSK_LEN;
7266d49e1aeSJan Lentfer
7276d49e1aeSJan Lentfer return key;
7286d49e1aeSJan Lentfer }
7296d49e1aeSJan Lentfer
7306d49e1aeSJan Lentfer
eap_gpsk_get_emsk(struct eap_sm * sm,void * priv,size_t * len)7316d49e1aeSJan Lentfer static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
7326d49e1aeSJan Lentfer {
7336d49e1aeSJan Lentfer struct eap_gpsk_data *data = priv;
7346d49e1aeSJan Lentfer u8 *key;
7356d49e1aeSJan Lentfer
7366d49e1aeSJan Lentfer if (data->state != SUCCESS)
7376d49e1aeSJan Lentfer return NULL;
7386d49e1aeSJan Lentfer
739*a1157835SDaniel Fojt key = os_memdup(data->emsk, EAP_EMSK_LEN);
7406d49e1aeSJan Lentfer if (key == NULL)
7416d49e1aeSJan Lentfer return NULL;
7426d49e1aeSJan Lentfer *len = EAP_EMSK_LEN;
7436d49e1aeSJan Lentfer
7446d49e1aeSJan Lentfer return key;
7456d49e1aeSJan Lentfer }
7466d49e1aeSJan Lentfer
7476d49e1aeSJan Lentfer
eap_gpsk_get_session_id(struct eap_sm * sm,void * priv,size_t * len)7483ff40c12SJohn Marino static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
7493ff40c12SJohn Marino {
7503ff40c12SJohn Marino struct eap_gpsk_data *data = priv;
7513ff40c12SJohn Marino u8 *sid;
7523ff40c12SJohn Marino
7533ff40c12SJohn Marino if (data->state != SUCCESS)
7543ff40c12SJohn Marino return NULL;
7553ff40c12SJohn Marino
756*a1157835SDaniel Fojt sid = os_memdup(data->session_id, data->id_len);
7573ff40c12SJohn Marino if (sid == NULL)
7583ff40c12SJohn Marino return NULL;
7593ff40c12SJohn Marino *len = data->id_len;
7603ff40c12SJohn Marino
7613ff40c12SJohn Marino return sid;
7623ff40c12SJohn Marino }
7633ff40c12SJohn Marino
7643ff40c12SJohn Marino
eap_peer_gpsk_register(void)7656d49e1aeSJan Lentfer int eap_peer_gpsk_register(void)
7666d49e1aeSJan Lentfer {
7676d49e1aeSJan Lentfer struct eap_method *eap;
7686d49e1aeSJan Lentfer
7696d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
7706d49e1aeSJan Lentfer EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
7716d49e1aeSJan Lentfer if (eap == NULL)
7726d49e1aeSJan Lentfer return -1;
7736d49e1aeSJan Lentfer
7746d49e1aeSJan Lentfer eap->init = eap_gpsk_init;
7756d49e1aeSJan Lentfer eap->deinit = eap_gpsk_deinit;
7766d49e1aeSJan Lentfer eap->process = eap_gpsk_process;
7776d49e1aeSJan Lentfer eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
7786d49e1aeSJan Lentfer eap->getKey = eap_gpsk_getKey;
7796d49e1aeSJan Lentfer eap->get_emsk = eap_gpsk_get_emsk;
7803ff40c12SJohn Marino eap->getSessionId = eap_gpsk_get_session_id;
7816d49e1aeSJan Lentfer
782*a1157835SDaniel Fojt return eap_peer_method_register(eap);
7836d49e1aeSJan Lentfer }
784