/*
* EAP peer method: EAP-GPSK (RFC 5433)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "common.h"
+#include "crypto/random.h"
#include "eap_peer/eap_i.h"
#include "eap_common/eap_gpsk_common.h"
size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len;
- u8 session_id;
- int session_id_set;
+ u8 session_id[128];
+ size_t id_len;
u8 *id_peer;
size_t id_peer_len;
u8 *id_server;
int specifier; /* CSuite/Specifier */
u8 *psk;
size_t psk_len;
+ u16 forced_cipher; /* force cipher or 0 to allow all supported */
};
struct eap_gpsk_data *data;
const u8 *identity, *password;
size_t identity_len, password_len;
+ const char *phase1;
password = eap_get_config_password(sm, &password_len);
if (password == NULL) {
data->id_peer_len = identity_len;
}
+ phase1 = eap_get_config_phase1(sm);
+ if (phase1) {
+ const char *pos;
+
+ pos = os_strstr(phase1, "cipher=");
+ if (pos) {
+ data->forced_cipher = atoi(pos + 7);
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
+ data->forced_cipher);
+ }
+ }
+
data->psk = os_malloc(password_len);
if (data->psk == NULL) {
eap_gpsk_deinit(sm, data);
struct eap_gpsk_data *data = priv;
os_free(data->id_server);
os_free(data->id_peer);
- os_free(data->psk);
- os_free(data);
+ if (data->psk) {
+ os_memset(data->psk, 0, data->psk_len);
+ os_free(data->psk);
+ }
+ bin_clear_free(data, sizeof(*data));
}
i, vendor, specifier);
if (data->vendor == EAP_GPSK_VENDOR_IETF &&
data->specifier == EAP_GPSK_CIPHER_RESERVED &&
- eap_gpsk_supported_ciphersuite(vendor, specifier)) {
+ eap_gpsk_supported_ciphersuite(vendor, specifier) &&
+ (!data->forced_cipher || data->forced_cipher == specifier))
+ {
data->vendor = vendor;
data->specifier = specifier;
}
size_t *list_len,
const u8 *pos, const u8 *end)
{
+ size_t len;
+
if (pos == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
return NULL;
}
- *list_len = WPA_GET_BE16(pos);
+ len = WPA_GET_BE16(pos);
pos += 2;
- if (end - pos < (int) *list_len) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
return NULL;
}
- if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
+ if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
- (unsigned long) *list_len);
+ (unsigned long) len);
return NULL;
}
- *list = pos;
- pos += *list_len;
- if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
+ if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
return NULL;
+ *list = pos;
+ *list_len = len;
+ pos += len;
+
return pos;
}
static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
struct eap_gpsk_data *data,
struct eap_method_ret *ret,
- const struct wpabuf *reqData,
+ u8 identifier,
const u8 *payload,
size_t payload_len)
{
pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
&csuite_list_len, pos, end);
if (pos == NULL) {
+ ret->methodState = METHOD_DONE;
eap_gpsk_state(data, FAILURE);
return NULL;
}
- resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
+ resp = eap_gpsk_send_gpsk_2(data, identifier,
csuite_list, csuite_list_len);
if (resp == NULL)
return NULL;
wpabuf_put_be16(resp, data->id_server_len);
wpabuf_put_data(resp, data->id_server, data->id_server_len);
- if (os_get_random(data->rand_peer, EAP_GPSK_RAND_LEN)) {
+ if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
"for RAND_Peer");
eap_gpsk_state(data, FAILURE);
return NULL;
}
+ if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
+ data->vendor, data->specifier,
+ data->rand_peer, data->rand_server,
+ data->id_peer, data->id_peer_len,
+ data->id_server, data->id_server_len,
+ EAP_TYPE_GPSK,
+ data->session_id, &data->id_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+ eap_gpsk_state(data, FAILURE);
+ wpabuf_free(resp);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+ data->session_id, data->id_len);
+
/* No PD_Payload_1 */
wpabuf_put_be16(resp, 0);
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
return NULL;
}
- if (os_memcmp(mic, pos, miclen) != 0) {
+ if (os_memcmp_const(mic, pos, miclen) != 0) {
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
struct eap_gpsk_data *data,
struct eap_method_ret *ret,
- const struct wpabuf *reqData,
+ u8 identifier,
const u8 *payload,
size_t payload_len)
{
(unsigned long) (end - pos));
}
- resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
+ resp = eap_gpsk_send_gpsk_4(data, identifier);
if (resp == NULL)
return NULL;
struct wpabuf *resp;
const u8 *pos;
size_t len;
+ u8 opcode, id;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
if (pos == NULL || len < 1) {
return NULL;
}
- wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
+ id = eap_get_id(reqData);
+ opcode = *pos++;
+ len--;
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
ret->ignore = FALSE;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = FALSE;
- switch (*pos) {
+ switch (opcode) {
case EAP_GPSK_OPCODE_GPSK_1:
- resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
- pos + 1, len - 1);
+ resp = eap_gpsk_process_gpsk_1(sm, data, ret, id, pos, len);
break;
case EAP_GPSK_OPCODE_GPSK_3:
- resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
- pos + 1, len - 1);
+ resp = eap_gpsk_process_gpsk_3(sm, data, ret, id, pos, len);
break;
default:
- wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
- "unknown opcode %d", *pos);
+ wpa_printf(MSG_DEBUG,
+ "EAP-GPSK: Ignoring message with unknown opcode %d",
+ opcode);
ret->ignore = TRUE;
return NULL;
}
}
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(data->id_len);
+ if (sid == NULL)
+ return NULL;
+ os_memcpy(sid, data->session_id, data->id_len);
+ *len = data->id_len;
+
+ return sid;
+}
+
+
int eap_peer_gpsk_register(void)
{
struct eap_method *eap;
eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
eap->getKey = eap_gpsk_getKey;
eap->get_emsk = eap_gpsk_get_emsk;
+ eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)