~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to src/eap_server/eap_gpsk.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-08.txt) server
 
3
 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
 
4
 *
 
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.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
 
 
17
#include "common.h"
 
18
#include "eap_server/eap_i.h"
 
19
#include "eap_common/eap_gpsk_common.h"
 
20
 
 
21
 
 
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_peer[EAP_GPSK_RAND_LEN];
 
26
        u8 msk[EAP_MSK_LEN];
 
27
        u8 emsk[EAP_EMSK_LEN];
 
28
        u8 sk[EAP_GPSK_MAX_SK_LEN];
 
29
        size_t sk_len;
 
30
        u8 pk[EAP_GPSK_MAX_PK_LEN];
 
31
        size_t pk_len;
 
32
        u8 *id_peer;
 
33
        size_t id_peer_len;
 
34
        u8 *id_server;
 
35
        size_t id_server_len;
 
36
#define MAX_NUM_CSUITES 2
 
37
        struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
 
38
        size_t csuite_count;
 
39
        int vendor; /* CSuite/Vendor */
 
40
        int specifier; /* CSuite/Specifier */
 
41
};
 
42
 
 
43
 
 
44
static const char * eap_gpsk_state_txt(int state)
 
45
{
 
46
        switch (state) {
 
47
        case GPSK_1:
 
48
                return "GPSK-1";
 
49
        case GPSK_3:
 
50
                return "GPSK-3";
 
51
        case SUCCESS:
 
52
                return "SUCCESS";
 
53
        case FAILURE:
 
54
                return "FAILURE";
 
55
        default:
 
56
                return "?";
 
57
        }
 
58
}
 
59
 
 
60
 
 
61
static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
 
62
{
 
63
        wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
 
64
                   eap_gpsk_state_txt(data->state),
 
65
                   eap_gpsk_state_txt(state));
 
66
        data->state = state;
 
67
}
 
68
 
 
69
 
 
70
static void * eap_gpsk_init(struct eap_sm *sm)
 
71
{
 
72
        struct eap_gpsk_data *data;
 
73
 
 
74
        data = os_zalloc(sizeof(*data));
 
75
        if (data == NULL)
 
76
                return NULL;
 
77
        data->state = GPSK_1;
 
78
 
 
79
        /* TODO: add support for configuring ID_Server */
 
80
        data->id_server = (u8 *) os_strdup("hostapd");
 
81
        if (data->id_server)
 
82
                data->id_server_len = os_strlen((char *) data->id_server);
 
83
 
 
84
        data->csuite_count = 0;
 
85
        if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
 
86
                                           EAP_GPSK_CIPHER_AES)) {
 
87
                WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
 
88
                             EAP_GPSK_VENDOR_IETF);
 
89
                WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
 
90
                             EAP_GPSK_CIPHER_AES);
 
91
                data->csuite_count++;
 
92
        }
 
93
        if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
 
94
                                           EAP_GPSK_CIPHER_SHA256)) {
 
95
                WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
 
96
                             EAP_GPSK_VENDOR_IETF);
 
97
                WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
 
98
                             EAP_GPSK_CIPHER_SHA256);
 
99
                data->csuite_count++;
 
100
        }
 
101
 
 
102
        return data;
 
103
}
 
104
 
 
105
 
 
106
static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
 
107
{
 
108
        struct eap_gpsk_data *data = priv;
 
109
        os_free(data->id_server);
 
110
        os_free(data->id_peer);
 
111
        os_free(data);
 
112
}
 
113
 
 
114
 
 
115
static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
 
116
                                             struct eap_gpsk_data *data, u8 id)
 
117
{
 
118
        size_t len;
 
119
        struct wpabuf *req;
 
120
 
 
121
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1");
 
122
 
 
123
        if (os_get_random(data->rand_server, EAP_GPSK_RAND_LEN)) {
 
124
                wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data");
 
125
                eap_gpsk_state(data, FAILURE);
 
126
                return NULL;
 
127
        }
 
128
        wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
 
129
                    data->rand_server, EAP_GPSK_RAND_LEN);
 
130
 
 
131
        len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
 
132
                data->csuite_count * sizeof(struct eap_gpsk_csuite);
 
133
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
 
134
                            EAP_CODE_REQUEST, id);
 
135
        if (req == NULL) {
 
136
                wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
 
137
                           "for request/GPSK-1");
 
138
                eap_gpsk_state(data, FAILURE);
 
139
                return NULL;
 
140
        }
 
141
 
 
142
        wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
 
143
        wpabuf_put_be16(req, data->id_server_len);
 
144
        wpabuf_put_data(req, data->id_server, data->id_server_len);
 
145
        wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
 
146
        wpabuf_put_be16(req,
 
147
                        data->csuite_count * sizeof(struct eap_gpsk_csuite));
 
148
        wpabuf_put_data(req, data->csuite_list,
 
149
                        data->csuite_count * sizeof(struct eap_gpsk_csuite));
 
150
 
 
151
        return req;
 
152
}
 
153
 
 
154
 
 
155
static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
 
156
                                             struct eap_gpsk_data *data, u8 id)
 
157
{
 
158
        u8 *pos, *start;
 
159
        size_t len, miclen;
 
160
        struct eap_gpsk_csuite *csuite;
 
161
        struct wpabuf *req;
 
162
 
 
163
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
 
164
 
 
165
        miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
 
166
        len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len +
 
167
                sizeof(struct eap_gpsk_csuite) + 2 + miclen;
 
168
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
 
169
                            EAP_CODE_REQUEST, id);
 
170
        if (req == NULL) {
 
171
                wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
 
172
                           "for request/GPSK-3");
 
173
                eap_gpsk_state(data, FAILURE);
 
174
                return NULL;
 
175
        }
 
176
 
 
177
        wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3);
 
178
        start = wpabuf_put(req, 0);
 
179
 
 
180
        wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
 
181
        wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
 
182
        wpabuf_put_be16(req, data->id_server_len);
 
183
        wpabuf_put_data(req, data->id_server, data->id_server_len);
 
184
        csuite = wpabuf_put(req, sizeof(*csuite));
 
185
        WPA_PUT_BE32(csuite->vendor, data->vendor);
 
186
        WPA_PUT_BE16(csuite->specifier, data->specifier);
 
187
 
 
188
        /* no PD_Payload_2 */
 
189
        wpabuf_put_be16(req, 0);
 
190
 
 
191
        pos = wpabuf_put(req, miclen);
 
192
        if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
 
193
                                 data->specifier, start, pos - start, pos) < 0)
 
194
        {
 
195
                os_free(req);
 
196
                eap_gpsk_state(data, FAILURE);
 
197
                return NULL;
 
198
        }
 
199
 
 
200
        return req;
 
201
}
 
202
 
 
203
 
 
204
static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id)
 
205
{
 
206
        struct eap_gpsk_data *data = priv;
 
207
 
 
208
        switch (data->state) {
 
209
        case GPSK_1:
 
210
                return eap_gpsk_build_gpsk_1(sm, data, id);
 
211
        case GPSK_3:
 
212
                return eap_gpsk_build_gpsk_3(sm, data, id);
 
213
        default:
 
214
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq",
 
215
                           data->state);
 
216
                break;
 
217
        }
 
218
        return NULL;
 
219
}
 
220
 
 
221
 
 
222
static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
 
223
                              struct wpabuf *respData)
 
224
{
 
225
        struct eap_gpsk_data *data = priv;
 
226
        const u8 *pos;
 
227
        size_t len;
 
228
 
 
229
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
 
230
        if (pos == NULL || len < 1) {
 
231
                wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
 
232
                return TRUE;
 
233
        }
 
234
 
 
235
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
 
236
 
 
237
        if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
 
238
                return FALSE;
 
239
 
 
240
        if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
 
241
                return FALSE;
 
242
 
 
243
        wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
 
244
                   *pos, data->state);
 
245
 
 
246
        return TRUE;
 
247
}
 
248
 
 
249
 
 
250
static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
 
251
                                    struct eap_gpsk_data *data,
 
252
                                    const u8 *payload, size_t payloadlen)
 
253
{
 
254
        const u8 *pos, *end;
 
255
        u16 alen;
 
256
        const struct eap_gpsk_csuite *csuite;
 
257
        size_t i, miclen;
 
258
        u8 mic[EAP_GPSK_MAX_MIC_LEN];
 
259
 
 
260
        if (data->state != GPSK_1)
 
261
                return;
 
262
 
 
263
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");
 
264
 
 
265
        pos = payload;
 
266
        end = payload + payloadlen;
 
267
 
 
268
        if (end - pos < 2) {
 
269
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
270
                           "ID_Peer length");
 
271
                eap_gpsk_state(data, FAILURE);
 
272
                return;
 
273
        }
 
274
        alen = WPA_GET_BE16(pos);
 
275
        pos += 2;
 
276
        if (end - pos < alen) {
 
277
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
278
                           "ID_Peer");
 
279
                eap_gpsk_state(data, FAILURE);
 
280
                return;
 
281
        }
 
282
        os_free(data->id_peer);
 
283
        data->id_peer = os_malloc(alen);
 
284
        if (data->id_peer == NULL) {
 
285
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
 
286
                           "%d-octet ID_Peer", alen);
 
287
                return;
 
288
        }
 
289
        os_memcpy(data->id_peer, pos, alen);
 
290
        data->id_peer_len = alen;
 
291
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
 
292
                          data->id_peer, data->id_peer_len);
 
293
        pos += alen;
 
294
 
 
295
        if (end - pos < 2) {
 
296
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
297
                           "ID_Server length");
 
298
                eap_gpsk_state(data, FAILURE);
 
299
                return;
 
300
        }
 
301
        alen = WPA_GET_BE16(pos);
 
302
        pos += 2;
 
303
        if (end - pos < alen) {
 
304
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
305
                           "ID_Server");
 
306
                eap_gpsk_state(data, FAILURE);
 
307
                return;
 
308
        }
 
309
        if (alen != data->id_server_len ||
 
310
            os_memcmp(pos, data->id_server, alen) != 0) {
 
311
                wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
 
312
                           "GPSK-2 did not match");
 
313
                eap_gpsk_state(data, FAILURE);
 
314
                return;
 
315
        }
 
316
        pos += alen;
 
317
 
 
318
        if (end - pos < EAP_GPSK_RAND_LEN) {
 
319
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
320
                           "RAND_Peer");
 
321
                eap_gpsk_state(data, FAILURE);
 
322
                return;
 
323
        }
 
324
        os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN);
 
325
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
 
326
                    data->rand_peer, EAP_GPSK_RAND_LEN);
 
327
        pos += EAP_GPSK_RAND_LEN;
 
328
 
 
329
        if (end - pos < EAP_GPSK_RAND_LEN) {
 
330
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
331
                           "RAND_Server");
 
332
                eap_gpsk_state(data, FAILURE);
 
333
                return;
 
334
        }
 
335
        if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
 
336
                wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
 
337
                           "GPSK-2 did not match");
 
338
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
 
339
                            data->rand_server, EAP_GPSK_RAND_LEN);
 
340
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
 
341
                            pos, EAP_GPSK_RAND_LEN);
 
342
                eap_gpsk_state(data, FAILURE);
 
343
                return;
 
344
        }
 
345
        pos += EAP_GPSK_RAND_LEN;
 
346
 
 
347
        if (end - pos < 2) {
 
348
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
349
                           "CSuite_List length");
 
350
                eap_gpsk_state(data, FAILURE);
 
351
                return;
 
352
        }
 
353
        alen = WPA_GET_BE16(pos);
 
354
        pos += 2;
 
355
        if (end - pos < alen) {
 
356
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
357
                           "CSuite_List");
 
358
                eap_gpsk_state(data, FAILURE);
 
359
                return;
 
360
        }
 
361
        if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
 
362
            os_memcmp(pos, data->csuite_list, alen) != 0) {
 
363
                wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
 
364
                           "GPSK-2 did not match");
 
365
                eap_gpsk_state(data, FAILURE);
 
366
                return;
 
367
        }
 
368
        pos += alen;
 
369
 
 
370
        if (end - pos < (int) sizeof(*csuite)) {
 
371
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
372
                           "CSuite_Sel");
 
373
                eap_gpsk_state(data, FAILURE);
 
374
                return;
 
375
        }
 
376
        csuite = (const struct eap_gpsk_csuite *) pos;
 
377
        for (i = 0; i < data->csuite_count; i++) {
 
378
                if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite))
 
379
                    == 0)
 
380
                        break;
 
381
        }
 
382
        if (i == data->csuite_count) {
 
383
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
 
384
                           "ciphersuite %d:%d",
 
385
                           WPA_GET_BE32(csuite->vendor),
 
386
                           WPA_GET_BE16(csuite->specifier));
 
387
                eap_gpsk_state(data, FAILURE);
 
388
                return;
 
389
        }
 
390
        data->vendor = WPA_GET_BE32(csuite->vendor);
 
391
        data->specifier = WPA_GET_BE16(csuite->specifier);
 
392
        wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
 
393
                   data->vendor, data->specifier);
 
394
        pos += sizeof(*csuite); 
 
395
 
 
396
        if (end - pos < 2) {
 
397
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
398
                           "PD_Payload_1 length");
 
399
                eap_gpsk_state(data, FAILURE);
 
400
                return;
 
401
        }
 
402
        alen = WPA_GET_BE16(pos);
 
403
        pos += 2;
 
404
        if (end - pos < alen) {
 
405
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
406
                           "PD_Payload_1");
 
407
                eap_gpsk_state(data, FAILURE);
 
408
                return;
 
409
        }
 
410
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
 
411
        pos += alen;
 
412
 
 
413
        if (sm->user == NULL || sm->user->password == NULL) {
 
414
                wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
 
415
                           "for the user");
 
416
                eap_gpsk_state(data, FAILURE);
 
417
                return;
 
418
        }
 
419
 
 
420
        if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
 
421
                                 data->vendor, data->specifier,
 
422
                                 data->rand_peer, data->rand_server,
 
423
                                 data->id_peer, data->id_peer_len,
 
424
                                 data->id_server, data->id_server_len,
 
425
                                 data->msk, data->emsk,
 
426
                                 data->sk, &data->sk_len,
 
427
                                 data->pk, &data->pk_len) < 0) {
 
428
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
 
429
                eap_gpsk_state(data, FAILURE);
 
430
                return;
 
431
        }
 
432
 
 
433
        miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
 
434
        if (end - pos < (int) miclen) {
 
435
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
 
436
                           "(left=%d miclen=%d)", end - pos, miclen);
 
437
                eap_gpsk_state(data, FAILURE);
 
438
                return;
 
439
        }
 
440
        if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
 
441
                                 data->specifier, payload, pos - payload, mic)
 
442
            < 0) {
 
443
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
 
444
                eap_gpsk_state(data, FAILURE);
 
445
                return;
 
446
        }
 
447
        if (os_memcmp(mic, pos, miclen) != 0) {
 
448
                wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
 
449
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
 
450
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
 
451
                eap_gpsk_state(data, FAILURE);
 
452
                return;
 
453
        }
 
454
        pos += miclen;
 
455
 
 
456
        if (pos != end) {
 
457
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
 
458
                           "data in the end of GPSK-2", end - pos);
 
459
        }
 
460
 
 
461
        eap_gpsk_state(data, GPSK_3);
 
462
}
 
463
 
 
464
 
 
465
static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
 
466
                                    struct eap_gpsk_data *data,
 
467
                                    const u8 *payload, size_t payloadlen)
 
468
{
 
469
        const u8 *pos, *end;
 
470
        u16 alen;
 
471
        size_t miclen;
 
472
        u8 mic[EAP_GPSK_MAX_MIC_LEN];
 
473
 
 
474
        if (data->state != GPSK_3)
 
475
                return;
 
476
 
 
477
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
 
478
 
 
479
        pos = payload;
 
480
        end = payload + payloadlen;
 
481
 
 
482
        if (end - pos < 2) {
 
483
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
484
                           "PD_Payload_1 length");
 
485
                eap_gpsk_state(data, FAILURE);
 
486
                return;
 
487
        }
 
488
        alen = WPA_GET_BE16(pos);
 
489
        pos += 2;
 
490
        if (end - pos < alen) {
 
491
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
 
492
                           "PD_Payload_1");
 
493
                eap_gpsk_state(data, FAILURE);
 
494
                return;
 
495
        }
 
496
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
 
497
        pos += alen;
 
498
 
 
499
        miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
 
500
        if (end - pos < (int) miclen) {
 
501
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
 
502
                           "(left=%d miclen=%d)", end - pos, miclen);
 
503
                eap_gpsk_state(data, FAILURE);
 
504
                return;
 
505
        }
 
506
        if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
 
507
                                 data->specifier, payload, pos - payload, mic)
 
508
            < 0) {
 
509
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
 
510
                eap_gpsk_state(data, FAILURE);
 
511
                return;
 
512
        }
 
513
        if (os_memcmp(mic, pos, miclen) != 0) {
 
514
                wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
 
515
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
 
516
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
 
517
                eap_gpsk_state(data, FAILURE);
 
518
                return;
 
519
        }
 
520
        pos += miclen;
 
521
 
 
522
        if (pos != end) {
 
523
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
 
524
                           "data in the end of GPSK-4", end - pos);
 
525
        }
 
526
 
 
527
        eap_gpsk_state(data, SUCCESS);
 
528
}
 
529
 
 
530
 
 
531
static void eap_gpsk_process(struct eap_sm *sm, void *priv,
 
532
                             struct wpabuf *respData)
 
533
{
 
534
        struct eap_gpsk_data *data = priv;
 
535
        const u8 *pos;
 
536
        size_t len;
 
537
 
 
538
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
 
539
        if (pos == NULL || len < 1)
 
540
                return;
 
541
 
 
542
        switch (*pos) {
 
543
        case EAP_GPSK_OPCODE_GPSK_2:
 
544
                eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1);
 
545
                break;
 
546
        case EAP_GPSK_OPCODE_GPSK_4:
 
547
                eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1);
 
548
                break;
 
549
        }
 
550
}
 
551
 
 
552
 
 
553
static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
 
554
{
 
555
        struct eap_gpsk_data *data = priv;
 
556
        return data->state == SUCCESS || data->state == FAILURE;
 
557
}
 
558
 
 
559
 
 
560
static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
 
561
{
 
562
        struct eap_gpsk_data *data = priv;
 
563
        u8 *key;
 
564
 
 
565
        if (data->state != SUCCESS)
 
566
                return NULL;
 
567
 
 
568
        key = os_malloc(EAP_MSK_LEN);
 
569
        if (key == NULL)
 
570
                return NULL;
 
571
        os_memcpy(key, data->msk, EAP_MSK_LEN);
 
572
        *len = EAP_MSK_LEN;
 
573
 
 
574
        return key;
 
575
}
 
576
 
 
577
 
 
578
static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 
579
{
 
580
        struct eap_gpsk_data *data = priv;
 
581
        u8 *key;
 
582
 
 
583
        if (data->state != SUCCESS)
 
584
                return NULL;
 
585
 
 
586
        key = os_malloc(EAP_EMSK_LEN);
 
587
        if (key == NULL)
 
588
                return NULL;
 
589
        os_memcpy(key, data->emsk, EAP_EMSK_LEN);
 
590
        *len = EAP_EMSK_LEN;
 
591
 
 
592
        return key;
 
593
}
 
594
 
 
595
 
 
596
static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
 
597
{
 
598
        struct eap_gpsk_data *data = priv;
 
599
        return data->state == SUCCESS;
 
600
}
 
601
 
 
602
 
 
603
int eap_server_gpsk_register(void)
 
604
{
 
605
        struct eap_method *eap;
 
606
        int ret;
 
607
 
 
608
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 
609
                                      EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
 
610
        if (eap == NULL)
 
611
                return -1;
 
612
 
 
613
        eap->init = eap_gpsk_init;
 
614
        eap->reset = eap_gpsk_reset;
 
615
        eap->buildReq = eap_gpsk_buildReq;
 
616
        eap->check = eap_gpsk_check;
 
617
        eap->process = eap_gpsk_process;
 
618
        eap->isDone = eap_gpsk_isDone;
 
619
        eap->getKey = eap_gpsk_getKey;
 
620
        eap->isSuccess = eap_gpsk_isSuccess;
 
621
        eap->get_emsk = eap_gpsk_get_emsk;
 
622
 
 
623
        ret = eap_server_method_register(eap);
 
624
        if (ret)
 
625
                eap_server_method_free(eap);
 
626
        return ret;
 
627
}