2
* EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-03.txt)
3
* Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
9
* Alternatively, this software may be distributed under the terms of BSD
12
* See README and COPYING for more details.
19
#include "config_ssid.h"
20
#include "eap_gpsk_common.h"
22
struct eap_gpsk_data {
23
enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
24
u8 rand_server[EAP_GPSK_RAND_LEN];
25
u8 rand_client[EAP_GPSK_RAND_LEN];
27
u8 emsk[EAP_EMSK_LEN];
28
u8 sk[EAP_GPSK_MAX_SK_LEN];
30
u8 pk[EAP_GPSK_MAX_PK_LEN];
38
int vendor; /* CSuite/Specifier */
39
int specifier; /* CSuite/Specifier */
45
#ifndef CONFIG_NO_STDOUT_DEBUG
46
static const char * eap_gpsk_state_txt(int state)
61
#endif /* CONFIG_NO_STDOUT_DEBUG */
64
static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
66
wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
67
eap_gpsk_state_txt(data->state),
68
eap_gpsk_state_txt(state));
73
static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
76
static void * eap_gpsk_init(struct eap_sm *sm)
78
struct wpa_ssid *config = eap_get_config(sm);
79
struct eap_gpsk_data *data;
82
wpa_printf(MSG_INFO, "EAP-GPSK: No configuration found");
86
if (config->eappsk == NULL) {
87
wpa_printf(MSG_INFO, "EAP-GPSK: No key (eappsk) configured");
91
data = os_zalloc(sizeof(*data));
97
data->id_client = os_malloc(config->nai_len);
98
if (data->id_client == NULL) {
99
eap_gpsk_deinit(sm, data);
102
os_memcpy(data->id_client, config->nai, config->nai_len);
103
data->id_client_len = config->nai_len;
106
data->psk = os_malloc(config->eappsk_len);
107
if (data->psk == NULL) {
108
eap_gpsk_deinit(sm, data);
111
os_memcpy(data->psk, config->eappsk, config->eappsk_len);
112
data->psk_len = config->eappsk_len;
118
static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
120
struct eap_gpsk_data *data = priv;
121
os_free(data->id_server);
122
os_free(data->id_client);
128
static u8 * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
129
struct eap_gpsk_data *data,
130
struct eap_method_ret *ret,
131
const u8 *reqData, size_t reqDataLen,
132
const u8 *payload, size_t payload_len,
135
size_t len, csuite_list_len, miclen;
136
struct eap_hdr *resp;
138
const u8 *csuite_list, *pos, *end;
139
const struct eap_hdr *req;
140
struct eap_gpsk_csuite *csuite;
144
if (data->state != GPSK_1) {
149
wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
151
req = (const struct eap_hdr *) reqData;
153
end = payload + payload_len;
156
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
159
alen = WPA_GET_BE16(pos);
161
if (end - pos < alen) {
162
wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
165
os_free(data->id_server);
166
data->id_server = os_malloc(alen);
167
if (data->id_server == NULL) {
168
wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
171
os_memcpy(data->id_server, pos, alen);
172
data->id_server_len = alen;
173
wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
174
data->id_server, data->id_server_len);
177
if (end - pos < EAP_GPSK_RAND_LEN) {
178
wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
181
os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
182
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
183
data->rand_server, EAP_GPSK_RAND_LEN);
184
pos += EAP_GPSK_RAND_LEN;
187
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
190
csuite_list_len = WPA_GET_BE16(pos);
192
if (end - pos < (int) csuite_list_len) {
193
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
198
if (csuite_list_len == 0 ||
199
csuite_list_len % sizeof(struct eap_gpsk_csuite)) {
200
wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %d",
204
count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
205
data->vendor = EAP_GPSK_VENDOR_IETF;
206
data->specifier = EAP_GPSK_CIPHER_RESERVED;
207
csuite = (struct eap_gpsk_csuite *) csuite_list;
208
for (i = 0; i < count; i++) {
209
int vendor, specifier;
210
vendor = WPA_GET_BE24(csuite->vendor);
211
specifier = WPA_GET_BE24(csuite->specifier);
212
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
213
i, vendor, specifier);
214
if (data->vendor == EAP_GPSK_VENDOR_IETF &&
215
data->specifier == EAP_GPSK_CIPHER_RESERVED &&
216
eap_gpsk_supported_ciphersuite(vendor, specifier)) {
217
data->vendor = vendor;
218
data->specifier = specifier;
222
if (data->vendor == EAP_GPSK_VENDOR_IETF &&
223
data->specifier == EAP_GPSK_CIPHER_RESERVED) {
224
wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
225
"ciphersuite found");
226
eap_gpsk_state(data, FAILURE);
229
wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
230
data->vendor, data->specifier);
232
wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
234
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
235
len = 1 + 2 + data->id_client_len + 2 + data->id_server_len +
236
2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
237
sizeof(struct eap_gpsk_csuite) + 2 + miclen;
239
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respDataLen, len,
240
EAP_CODE_RESPONSE, req->identifier, &rpos);
244
*rpos++ = EAP_GPSK_OPCODE_GPSK_2;
247
wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Client",
248
data->id_client, data->id_client_len);
249
WPA_PUT_BE16(rpos, data->id_client_len);
252
os_memcpy(rpos, data->id_client, data->id_client_len);
253
rpos += data->id_client_len;
255
WPA_PUT_BE16(rpos, data->id_server_len);
258
os_memcpy(rpos, data->id_server, data->id_server_len);
259
rpos += data->id_server_len;
261
if (os_get_random(data->rand_client, EAP_GPSK_RAND_LEN)) {
262
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
264
eap_gpsk_state(data, FAILURE);
268
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client",
269
data->rand_client, EAP_GPSK_RAND_LEN);
270
os_memcpy(rpos, data->rand_client, EAP_GPSK_RAND_LEN);
271
rpos += EAP_GPSK_RAND_LEN;
273
os_memcpy(rpos, data->rand_server, EAP_GPSK_RAND_LEN);
274
rpos += EAP_GPSK_RAND_LEN;
276
WPA_PUT_BE16(rpos, csuite_list_len);
278
os_memcpy(rpos, csuite_list, csuite_list_len);
279
rpos += csuite_list_len;
281
csuite = (struct eap_gpsk_csuite *) rpos;
282
WPA_PUT_BE24(csuite->vendor, data->vendor);
283
WPA_PUT_BE24(csuite->specifier, data->specifier);
284
rpos = (u8 *) (csuite + 1);
286
if (eap_gpsk_derive_keys(data->psk, data->psk_len,
287
data->vendor, data->specifier,
288
data->rand_client, data->rand_server,
289
data->id_client, data->id_client_len,
290
data->id_server, data->id_server_len,
291
data->msk, data->emsk,
292
data->sk, &data->sk_len,
293
data->pk, &data->pk_len) < 0) {
294
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
295
eap_gpsk_state(data, FAILURE);
300
/* No PD_Payload_1 */
301
WPA_PUT_BE16(rpos, 0);
304
if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
305
data->specifier, start, rpos - start, rpos) <
307
eap_gpsk_state(data, FAILURE);
312
eap_gpsk_state(data, GPSK_3);
318
static u8 * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
319
struct eap_gpsk_data *data,
320
struct eap_method_ret *ret,
321
const u8 *reqData, size_t reqDataLen,
322
const u8 *payload, size_t payload_len,
326
struct eap_hdr *resp;
328
const struct eap_hdr *req;
331
int vendor, specifier;
332
const struct eap_gpsk_csuite *csuite;
333
u8 mic[EAP_GPSK_MAX_MIC_LEN];
335
if (data->state != GPSK_3) {
340
wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
342
req = (const struct eap_hdr *) reqData;
344
end = payload + payload_len;
346
if (end - pos < EAP_GPSK_RAND_LEN) {
347
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
351
if (os_memcmp(pos, data->rand_client, EAP_GPSK_RAND_LEN) != 0) {
352
wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2 and "
353
"GPSK-3 did not match");
354
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2",
355
data->rand_client, EAP_GPSK_RAND_LEN);
356
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-3",
357
pos, EAP_GPSK_RAND_LEN);
358
eap_gpsk_state(data, FAILURE);
361
pos += EAP_GPSK_RAND_LEN;
363
if (end - pos < EAP_GPSK_RAND_LEN) {
364
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
368
if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
369
wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
370
"GPSK-3 did not match");
371
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
372
data->rand_server, EAP_GPSK_RAND_LEN);
373
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
374
pos, EAP_GPSK_RAND_LEN);
375
eap_gpsk_state(data, FAILURE);
378
pos += EAP_GPSK_RAND_LEN;
380
if (end - pos < (int) sizeof(*csuite)) {
381
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
385
csuite = (const struct eap_gpsk_csuite *) pos;
386
vendor = WPA_GET_BE24(csuite->vendor);
387
specifier = WPA_GET_BE24(csuite->specifier);
388
pos += sizeof(*csuite);
389
if (vendor != data->vendor || specifier != data->specifier) {
390
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
391
"match with the one sent in GPSK-2 (%d:%d)",
392
vendor, specifier, data->vendor, data->specifier);
393
eap_gpsk_state(data, FAILURE);
398
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
399
"PD_Payload_2 length");
400
eap_gpsk_state(data, FAILURE);
403
alen = WPA_GET_BE16(pos);
405
if (end - pos < alen) {
406
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
407
"%d-octet PD_Payload_2", alen);
408
eap_gpsk_state(data, FAILURE);
411
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
413
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
414
if (end - pos < (int) miclen) {
415
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
416
"(left=%d miclen=%d)", end - pos, miclen);
417
eap_gpsk_state(data, FAILURE);
420
if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
421
data->specifier, payload, pos - payload, mic)
423
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
424
eap_gpsk_state(data, FAILURE);
427
if (os_memcmp(mic, pos, miclen) != 0) {
428
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
429
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
430
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
431
eap_gpsk_state(data, FAILURE);
437
wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
438
"data in the end of GPSK-2", end - pos);
441
wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
443
len = 1 + 2 + miclen;
445
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respDataLen, len,
446
EAP_CODE_RESPONSE, req->identifier, &rpos);
450
*rpos++ = EAP_GPSK_OPCODE_GPSK_4;
453
/* No PD_Payload_3 */
454
WPA_PUT_BE16(rpos, 0);
457
if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
458
data->specifier, start, rpos - start, rpos) <
460
eap_gpsk_state(data, FAILURE);
465
eap_gpsk_state(data, SUCCESS);
466
ret->methodState = METHOD_DONE;
467
ret->decision = DECISION_UNCOND_SUCC;
473
static u8 * eap_gpsk_process(struct eap_sm *sm, void *priv,
474
struct eap_method_ret *ret,
475
const u8 *reqData, size_t reqDataLen,
478
struct eap_gpsk_data *data = priv;
483
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
484
reqData, reqDataLen, &len);
485
if (pos == NULL || len < 1) {
490
wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
493
ret->methodState = METHOD_MAY_CONT;
494
ret->decision = DECISION_FAIL;
495
ret->allowNotifications = FALSE;
498
case EAP_GPSK_OPCODE_GPSK_1:
499
resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
500
reqDataLen, pos + 1, len - 1,
503
case EAP_GPSK_OPCODE_GPSK_3:
504
resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
505
reqDataLen, pos + 1, len - 1,
509
wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
510
"unknown opcode %d", *pos);
519
static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
521
struct eap_gpsk_data *data = priv;
522
return data->state == SUCCESS;
526
static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
528
struct eap_gpsk_data *data = priv;
531
if (data->state != SUCCESS)
534
key = os_malloc(EAP_MSK_LEN);
537
os_memcpy(key, data->msk, EAP_MSK_LEN);
544
static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
546
struct eap_gpsk_data *data = priv;
549
if (data->state != SUCCESS)
552
key = os_malloc(EAP_EMSK_LEN);
555
os_memcpy(key, data->emsk, EAP_EMSK_LEN);
562
int eap_peer_gpsk_register(void)
564
struct eap_method *eap;
567
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
568
EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
572
eap->init = eap_gpsk_init;
573
eap->deinit = eap_gpsk_deinit;
574
eap->process = eap_gpsk_process;
575
eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
576
eap->getKey = eap_gpsk_getKey;
577
eap->get_emsk = eap_gpsk_get_emsk;
579
ret = eap_peer_method_register(eap);
581
eap_peer_method_free(eap);