~awe/wpasupplicant/add-fake-aps

« back to all changes in this revision

Viewing changes to src/eap_peer/eap_gpsk.c

  • Committer: Tony Espy
  • Date: 2015-09-03 17:55:32 UTC
  • Revision ID: espy@canonical.com-20150903175532-7uv6rqya9iqco340
Initial personal branch for feature devel (LP: #1480877).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * EAP peer method: EAP-GPSK (RFC 5433)
 
3
 * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
 
4
 *
 
5
 * This software may be distributed under the terms of the BSD license.
 
6
 * See README for more details.
 
7
 */
 
8
 
 
9
#include "includes.h"
 
10
 
 
11
#include "common.h"
 
12
#include "crypto/random.h"
 
13
#include "eap_peer/eap_i.h"
 
14
#include "eap_common/eap_gpsk_common.h"
 
15
 
 
16
struct eap_gpsk_data {
 
17
        enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
 
18
        u8 rand_server[EAP_GPSK_RAND_LEN];
 
19
        u8 rand_peer[EAP_GPSK_RAND_LEN];
 
20
        u8 msk[EAP_MSK_LEN];
 
21
        u8 emsk[EAP_EMSK_LEN];
 
22
        u8 sk[EAP_GPSK_MAX_SK_LEN];
 
23
        size_t sk_len;
 
24
        u8 pk[EAP_GPSK_MAX_PK_LEN];
 
25
        size_t pk_len;
 
26
        u8 session_id[128];
 
27
        size_t id_len;
 
28
        u8 *id_peer;
 
29
        size_t id_peer_len;
 
30
        u8 *id_server;
 
31
        size_t id_server_len;
 
32
        int vendor; /* CSuite/Specifier */
 
33
        int specifier; /* CSuite/Specifier */
 
34
        u8 *psk;
 
35
        size_t psk_len;
 
36
        u16 forced_cipher; /* force cipher or 0 to allow all supported */
 
37
};
 
38
 
 
39
 
 
40
static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
 
41
                                            u8 identifier,
 
42
                                            const u8 *csuite_list,
 
43
                                            size_t csuite_list_len);
 
44
static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
 
45
                                            u8 identifier);
 
46
 
 
47
 
 
48
#ifndef CONFIG_NO_STDOUT_DEBUG
 
49
static const char * eap_gpsk_state_txt(int state)
 
50
{
 
51
        switch (state) {
 
52
        case GPSK_1:
 
53
                return "GPSK-1";
 
54
        case GPSK_3:
 
55
                return "GPSK-3";
 
56
        case SUCCESS:
 
57
                return "SUCCESS";
 
58
        case FAILURE:
 
59
                return "FAILURE";
 
60
        default:
 
61
                return "?";
 
62
        }
 
63
}
 
64
#endif /* CONFIG_NO_STDOUT_DEBUG */
 
65
 
 
66
 
 
67
static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
 
68
{
 
69
        wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
 
70
                   eap_gpsk_state_txt(data->state),
 
71
                   eap_gpsk_state_txt(state));
 
72
        data->state = state;
 
73
}
 
74
 
 
75
 
 
76
static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
 
77
 
 
78
 
 
79
static void * eap_gpsk_init(struct eap_sm *sm)
 
80
{
 
81
        struct eap_gpsk_data *data;
 
82
        const u8 *identity, *password;
 
83
        size_t identity_len, password_len;
 
84
        const char *phase1;
 
85
 
 
86
        password = eap_get_config_password(sm, &password_len);
 
87
        if (password == NULL) {
 
88
                wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
 
89
                return NULL;
 
90
        }
 
91
 
 
92
        data = os_zalloc(sizeof(*data));
 
93
        if (data == NULL)
 
94
                return NULL;
 
95
        data->state = GPSK_1;
 
96
 
 
97
        identity = eap_get_config_identity(sm, &identity_len);
 
98
        if (identity) {
 
99
                data->id_peer = os_malloc(identity_len);
 
100
                if (data->id_peer == NULL) {
 
101
                        eap_gpsk_deinit(sm, data);
 
102
                        return NULL;
 
103
                }
 
104
                os_memcpy(data->id_peer, identity, identity_len);
 
105
                data->id_peer_len = identity_len;
 
106
        }
 
107
 
 
108
        phase1 = eap_get_config_phase1(sm);
 
109
        if (phase1) {
 
110
                const char *pos;
 
111
 
 
112
                pos = os_strstr(phase1, "cipher=");
 
113
                if (pos) {
 
114
                        data->forced_cipher = atoi(pos + 7);
 
115
                        wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
 
116
                                   data->forced_cipher);
 
117
                }
 
118
        }
 
119
 
 
120
        data->psk = os_malloc(password_len);
 
121
        if (data->psk == NULL) {
 
122
                eap_gpsk_deinit(sm, data);
 
123
                return NULL;
 
124
        }
 
125
        os_memcpy(data->psk, password, password_len);
 
126
        data->psk_len = password_len;
 
127
 
 
128
        return data;
 
129
}
 
130
 
 
131
 
 
132
static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
 
133
{
 
134
        struct eap_gpsk_data *data = priv;
 
135
        os_free(data->id_server);
 
136
        os_free(data->id_peer);
 
137
        os_free(data->psk);
 
138
        os_free(data);
 
139
}
 
140
 
 
141
 
 
142
static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
 
143
                                             const u8 *pos, const u8 *end)
 
144
{
 
145
        u16 alen;
 
146
 
 
147
        if (end - pos < 2) {
 
148
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
 
149
                return NULL;
 
150
        }
 
151
        alen = WPA_GET_BE16(pos);
 
152
        pos += 2;
 
153
        if (end - pos < alen) {
 
154
                wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
 
155
                return NULL;
 
156
        }
 
157
        os_free(data->id_server);
 
158
        data->id_server = os_malloc(alen);
 
159
        if (data->id_server == NULL) {
 
160
                wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
 
161
                return NULL;
 
162
        }
 
163
        os_memcpy(data->id_server, pos, alen);
 
164
        data->id_server_len = alen;
 
165
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
 
166
                          data->id_server, data->id_server_len);
 
167
        pos += alen;
 
168
 
 
169
        return pos;
 
170
}
 
171
 
 
172
 
 
173
static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
 
174
                                               const u8 *pos, const u8 *end)
 
175
{
 
176
        if (pos == NULL)
 
177
                return NULL;
 
178
 
 
179
        if (end - pos < EAP_GPSK_RAND_LEN) {
 
180
                wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
 
181
                return NULL;
 
182
        }
 
183
        os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
 
184
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
 
185
                    data->rand_server, EAP_GPSK_RAND_LEN);
 
186
        pos += EAP_GPSK_RAND_LEN;
 
187
 
 
188
        return pos;
 
189
}
 
190
 
 
191
 
 
192
static int eap_gpsk_select_csuite(struct eap_sm *sm,
 
193
                                  struct eap_gpsk_data *data,
 
194
                                  const u8 *csuite_list,
 
195
                                  size_t csuite_list_len)
 
196
{
 
197
        struct eap_gpsk_csuite *csuite;
 
198
        int i, count;
 
199
 
 
200
        count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
 
201
        data->vendor = EAP_GPSK_VENDOR_IETF;
 
202
        data->specifier = EAP_GPSK_CIPHER_RESERVED;
 
203
        csuite = (struct eap_gpsk_csuite *) csuite_list;
 
204
        for (i = 0; i < count; i++) {
 
205
                int vendor, specifier;
 
206
                vendor = WPA_GET_BE32(csuite->vendor);
 
207
                specifier = WPA_GET_BE16(csuite->specifier);
 
208
                wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
 
209
                           i, vendor, specifier);
 
210
                if (data->vendor == EAP_GPSK_VENDOR_IETF &&
 
211
                    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
 
212
                    eap_gpsk_supported_ciphersuite(vendor, specifier) &&
 
213
                    (!data->forced_cipher || data->forced_cipher == specifier))
 
214
                {
 
215
                        data->vendor = vendor;
 
216
                        data->specifier = specifier;
 
217
                }
 
218
                csuite++;
 
219
        }
 
220
        if (data->vendor == EAP_GPSK_VENDOR_IETF &&
 
221
            data->specifier == EAP_GPSK_CIPHER_RESERVED) {
 
222
                wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
 
223
                        "ciphersuite found");
 
224
                return -1;
 
225
        }
 
226
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
 
227
                   data->vendor, data->specifier);
 
228
 
 
229
        return 0;
 
230
}
 
231
 
 
232
 
 
233
static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
 
234
                                               struct eap_gpsk_data *data,
 
235
                                               const u8 **list,
 
236
                                               size_t *list_len,
 
237
                                               const u8 *pos, const u8 *end)
 
238
{
 
239
        if (pos == NULL)
 
240
                return NULL;
 
241
 
 
242
        if (end - pos < 2) {
 
243
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
 
244
                return NULL;
 
245
        }
 
246
        *list_len = WPA_GET_BE16(pos);
 
247
        pos += 2;
 
248
        if (end - pos < (int) *list_len) {
 
249
                wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
 
250
                return NULL;
 
251
        }
 
252
        if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
 
253
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
 
254
                           (unsigned long) *list_len);
 
255
                return NULL;
 
256
        }
 
257
        *list = pos;
 
258
        pos += *list_len;
 
259
 
 
260
        if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
 
261
                return NULL;
 
262
 
 
263
        return pos;
 
264
}
 
265
 
 
266
 
 
267
static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
 
268
                                               struct eap_gpsk_data *data,
 
269
                                               struct eap_method_ret *ret,
 
270
                                               const struct wpabuf *reqData,
 
271
                                               const u8 *payload,
 
272
                                               size_t payload_len)
 
273
{
 
274
        size_t csuite_list_len;
 
275
        const u8 *csuite_list, *pos, *end;
 
276
        struct wpabuf *resp;
 
277
 
 
278
        if (data->state != GPSK_1) {
 
279
                ret->ignore = TRUE;
 
280
                return NULL;
 
281
        }
 
282
 
 
283
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
 
284
 
 
285
        end = payload + payload_len;
 
286
 
 
287
        pos = eap_gpsk_process_id_server(data, payload, end);
 
288
        pos = eap_gpsk_process_rand_server(data, pos, end);
 
289
        pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
 
290
                                           &csuite_list_len, pos, end);
 
291
        if (pos == NULL) {
 
292
                ret->methodState = METHOD_DONE;
 
293
                eap_gpsk_state(data, FAILURE);
 
294
                return NULL;
 
295
        }
 
296
 
 
297
        resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
 
298
                                    csuite_list, csuite_list_len);
 
299
        if (resp == NULL)
 
300
                return NULL;
 
301
 
 
302
        eap_gpsk_state(data, GPSK_3);
 
303
 
 
304
        return resp;
 
305
}
 
306
 
 
307
 
 
308
static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
 
309
                                            u8 identifier,
 
310
                                            const u8 *csuite_list,
 
311
                                            size_t csuite_list_len)
 
312
{
 
313
        struct wpabuf *resp;
 
314
        size_t len, miclen;
 
315
        u8 *rpos, *start;
 
316
        struct eap_gpsk_csuite *csuite;
 
317
 
 
318
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
 
319
 
 
320
        miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
 
321
        len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
 
322
                2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
 
323
                sizeof(struct eap_gpsk_csuite) + 2 + miclen;
 
324
 
 
325
        resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
 
326
                             EAP_CODE_RESPONSE, identifier);
 
327
        if (resp == NULL)
 
328
                return NULL;
 
329
 
 
330
        wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
 
331
        start = wpabuf_put(resp, 0);
 
332
 
 
333
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
 
334
                          data->id_peer, data->id_peer_len);
 
335
        wpabuf_put_be16(resp, data->id_peer_len);
 
336
        wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
 
337
 
 
338
        wpabuf_put_be16(resp, data->id_server_len);
 
339
        wpabuf_put_data(resp, data->id_server, data->id_server_len);
 
340
 
 
341
        if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
 
342
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
 
343
                           "for RAND_Peer");
 
344
                eap_gpsk_state(data, FAILURE);
 
345
                wpabuf_free(resp);
 
346
                return NULL;
 
347
        }
 
348
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
 
349
                    data->rand_peer, EAP_GPSK_RAND_LEN);
 
350
        wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
 
351
        wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
 
352
 
 
353
        wpabuf_put_be16(resp, csuite_list_len);
 
354
        wpabuf_put_data(resp, csuite_list, csuite_list_len);
 
355
 
 
356
        csuite = wpabuf_put(resp, sizeof(*csuite));
 
357
        WPA_PUT_BE32(csuite->vendor, data->vendor);
 
358
        WPA_PUT_BE16(csuite->specifier, data->specifier);
 
359
 
 
360
        if (eap_gpsk_derive_keys(data->psk, data->psk_len,
 
361
                                 data->vendor, data->specifier,
 
362
                                 data->rand_peer, data->rand_server,
 
363
                                 data->id_peer, data->id_peer_len,
 
364
                                 data->id_server, data->id_server_len,
 
365
                                 data->msk, data->emsk,
 
366
                                 data->sk, &data->sk_len,
 
367
                                 data->pk, &data->pk_len) < 0) {
 
368
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
 
369
                eap_gpsk_state(data, FAILURE);
 
370
                wpabuf_free(resp);
 
371
                return NULL;
 
372
        }
 
373
 
 
374
        if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
 
375
                                       data->vendor, data->specifier,
 
376
                                       data->rand_peer, data->rand_server,
 
377
                                       data->id_peer, data->id_peer_len,
 
378
                                       data->id_server, data->id_server_len,
 
379
                                       EAP_TYPE_GPSK,
 
380
                                       data->session_id, &data->id_len) < 0) {
 
381
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
 
382
                eap_gpsk_state(data, FAILURE);
 
383
                wpabuf_free(resp);
 
384
                return NULL;
 
385
        }
 
386
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
 
387
                    data->session_id, data->id_len);
 
388
 
 
389
        /* No PD_Payload_1 */
 
390
        wpabuf_put_be16(resp, 0);
 
391
 
 
392
        rpos = wpabuf_put(resp, miclen);
 
393
        if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
 
394
                                 data->specifier, start, rpos - start, rpos) <
 
395
            0) {
 
396
                eap_gpsk_state(data, FAILURE);
 
397
                wpabuf_free(resp);
 
398
                return NULL;
 
399
        }
 
400
 
 
401
        return resp;
 
402
}
 
403
 
 
404
 
 
405
static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
 
406
                                         const u8 *pos, const u8 *end)
 
407
{
 
408
        if (end - pos < EAP_GPSK_RAND_LEN) {
 
409
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
 
410
                           "RAND_Peer");
 
411
                return NULL;
 
412
        }
 
413
        if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
 
414
                wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
 
415
                           "GPSK-3 did not match");
 
416
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
 
417
                            data->rand_peer, EAP_GPSK_RAND_LEN);
 
418
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
 
419
                            pos, EAP_GPSK_RAND_LEN);
 
420
                return NULL;
 
421
        }
 
422
        pos += EAP_GPSK_RAND_LEN;
 
423
 
 
424
        if (end - pos < EAP_GPSK_RAND_LEN) {
 
425
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
 
426
                           "RAND_Server");
 
427
                return NULL;
 
428
        }
 
429
        if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
 
430
                wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
 
431
                           "GPSK-3 did not match");
 
432
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
 
433
                            data->rand_server, EAP_GPSK_RAND_LEN);
 
434
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
 
435
                            pos, EAP_GPSK_RAND_LEN);
 
436
                return NULL;
 
437
        }
 
438
        pos += EAP_GPSK_RAND_LEN;
 
439
 
 
440
        return pos;
 
441
}
 
442
 
 
443
 
 
444
static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
 
445
                                              const u8 *pos, const u8 *end)
 
446
{
 
447
        size_t len;
 
448
 
 
449
        if (pos == NULL)
 
450
                return NULL;
 
451
 
 
452
        if (end - pos < (int) 2) {
 
453
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
 
454
                           "length(ID_Server)");
 
455
                return NULL;
 
456
        }
 
457
 
 
458
        len = WPA_GET_BE16(pos);
 
459
        pos += 2;
 
460
 
 
461
        if (end - pos < (int) len) {
 
462
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
 
463
                           "ID_Server");
 
464
                return NULL;
 
465
        }
 
466
 
 
467
        if (len != data->id_server_len ||
 
468
            os_memcmp(pos, data->id_server, len) != 0) {
 
469
                wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
 
470
                           "the one used in GPSK-1");
 
471
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
 
472
                                  data->id_server, data->id_server_len);
 
473
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
 
474
                                  pos, len);
 
475
                return NULL;
 
476
        }
 
477
 
 
478
        pos += len;
 
479
 
 
480
        return pos;
 
481
}
 
482
 
 
483
 
 
484
static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
 
485
                                           const u8 *pos, const u8 *end)
 
486
{
 
487
        int vendor, specifier;
 
488
        const struct eap_gpsk_csuite *csuite;
 
489
 
 
490
        if (pos == NULL)
 
491
                return NULL;
 
492
 
 
493
        if (end - pos < (int) sizeof(*csuite)) {
 
494
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
 
495
                           "CSuite_Sel");
 
496
                return NULL;
 
497
        }
 
498
        csuite = (const struct eap_gpsk_csuite *) pos;
 
499
        vendor = WPA_GET_BE32(csuite->vendor);
 
500
        specifier = WPA_GET_BE16(csuite->specifier);
 
501
        pos += sizeof(*csuite);
 
502
        if (vendor != data->vendor || specifier != data->specifier) {
 
503
                wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
 
504
                           "match with the one sent in GPSK-2 (%d:%d)",
 
505
                           vendor, specifier, data->vendor, data->specifier);
 
506
                return NULL;
 
507
        }
 
508
 
 
509
        return pos;
 
510
}
 
511
 
 
512
 
 
513
static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
 
514
                                                 const u8 *pos, const u8 *end)
 
515
{
 
516
        u16 alen;
 
517
 
 
518
        if (pos == NULL)
 
519
                return NULL;
 
520
 
 
521
        if (end - pos < 2) {
 
522
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
 
523
                           "PD_Payload_2 length");
 
524
                return NULL;
 
525
        }
 
526
        alen = WPA_GET_BE16(pos);
 
527
        pos += 2;
 
528
        if (end - pos < alen) {
 
529
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
 
530
                           "%d-octet PD_Payload_2", alen);
 
531
                return NULL;
 
532
        }
 
533
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
 
534
        pos += alen;
 
535
 
 
536
        return pos;
 
537
}
 
538
 
 
539
 
 
540
static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
 
541
                                               const u8 *payload,
 
542
                                               const u8 *pos, const u8 *end)
 
543
{
 
544
        size_t miclen;
 
545
        u8 mic[EAP_GPSK_MAX_MIC_LEN];
 
546
 
 
547
        if (pos == NULL)
 
548
                return NULL;
 
549
 
 
550
        miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
 
551
        if (end - pos < (int) miclen) {
 
552
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
 
553
                           "(left=%lu miclen=%lu)",
 
554
                           (unsigned long) (end - pos),
 
555
                           (unsigned long) miclen);
 
556
                return NULL;
 
557
        }
 
558
        if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
 
559
                                 data->specifier, payload, pos - payload, mic)
 
560
            < 0) {
 
561
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
 
562
                return NULL;
 
563
        }
 
564
        if (os_memcmp(mic, pos, miclen) != 0) {
 
565
                wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
 
566
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
 
567
                wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
 
568
                return NULL;
 
569
        }
 
570
        pos += miclen;
 
571
 
 
572
        return pos;
 
573
}
 
574
 
 
575
 
 
576
static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
 
577
                                               struct eap_gpsk_data *data,
 
578
                                               struct eap_method_ret *ret,
 
579
                                               const struct wpabuf *reqData,
 
580
                                               const u8 *payload,
 
581
                                               size_t payload_len)
 
582
{
 
583
        struct wpabuf *resp;
 
584
        const u8 *pos, *end;
 
585
 
 
586
        if (data->state != GPSK_3) {
 
587
                ret->ignore = TRUE;
 
588
                return NULL;
 
589
        }
 
590
 
 
591
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
 
592
 
 
593
        end = payload + payload_len;
 
594
 
 
595
        pos = eap_gpsk_validate_rand(data, payload, end);
 
596
        pos = eap_gpsk_validate_id_server(data, pos, end);
 
597
        pos = eap_gpsk_validate_csuite(data, pos, end);
 
598
        pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
 
599
        pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
 
600
 
 
601
        if (pos == NULL) {
 
602
                eap_gpsk_state(data, FAILURE);
 
603
                return NULL;
 
604
        }
 
605
        if (pos != end) {
 
606
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
 
607
                           "data in the end of GPSK-2",
 
608
                           (unsigned long) (end - pos));
 
609
        }
 
610
 
 
611
        resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
 
612
        if (resp == NULL)
 
613
                return NULL;
 
614
 
 
615
        eap_gpsk_state(data, SUCCESS);
 
616
        ret->methodState = METHOD_DONE;
 
617
        ret->decision = DECISION_UNCOND_SUCC;
 
618
 
 
619
        return resp;
 
620
}
 
621
 
 
622
 
 
623
static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
 
624
                                            u8 identifier)
 
625
{
 
626
        struct wpabuf *resp;
 
627
        u8 *rpos, *start;
 
628
        size_t mlen;
 
629
 
 
630
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
 
631
 
 
632
        mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
 
633
 
 
634
        resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
 
635
                             EAP_CODE_RESPONSE, identifier);
 
636
        if (resp == NULL)
 
637
                return NULL;
 
638
 
 
639
        wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
 
640
        start = wpabuf_put(resp, 0);
 
641
 
 
642
        /* No PD_Payload_3 */
 
643
        wpabuf_put_be16(resp, 0);
 
644
 
 
645
        rpos = wpabuf_put(resp, mlen);
 
646
        if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
 
647
                                 data->specifier, start, rpos - start, rpos) <
 
648
            0) {
 
649
                eap_gpsk_state(data, FAILURE);
 
650
                wpabuf_free(resp);
 
651
                return NULL;
 
652
        }
 
653
 
 
654
        return resp;
 
655
}
 
656
 
 
657
 
 
658
static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
 
659
                                        struct eap_method_ret *ret,
 
660
                                        const struct wpabuf *reqData)
 
661
{
 
662
        struct eap_gpsk_data *data = priv;
 
663
        struct wpabuf *resp;
 
664
        const u8 *pos;
 
665
        size_t len;
 
666
 
 
667
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
 
668
        if (pos == NULL || len < 1) {
 
669
                ret->ignore = TRUE;
 
670
                return NULL;
 
671
        }
 
672
 
 
673
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
 
674
 
 
675
        ret->ignore = FALSE;
 
676
        ret->methodState = METHOD_MAY_CONT;
 
677
        ret->decision = DECISION_FAIL;
 
678
        ret->allowNotifications = FALSE;
 
679
 
 
680
        switch (*pos) {
 
681
        case EAP_GPSK_OPCODE_GPSK_1:
 
682
                resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
 
683
                                               pos + 1, len - 1);
 
684
                break;
 
685
        case EAP_GPSK_OPCODE_GPSK_3:
 
686
                resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
 
687
                                               pos + 1, len - 1);
 
688
                break;
 
689
        default:
 
690
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
 
691
                           "unknown opcode %d", *pos);
 
692
                ret->ignore = TRUE;
 
693
                return NULL;
 
694
        }
 
695
 
 
696
        return resp;
 
697
}
 
698
 
 
699
 
 
700
static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
 
701
{
 
702
        struct eap_gpsk_data *data = priv;
 
703
        return data->state == SUCCESS;
 
704
}
 
705
 
 
706
 
 
707
static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
 
708
{
 
709
        struct eap_gpsk_data *data = priv;
 
710
        u8 *key;
 
711
 
 
712
        if (data->state != SUCCESS)
 
713
                return NULL;
 
714
 
 
715
        key = os_malloc(EAP_MSK_LEN);
 
716
        if (key == NULL)
 
717
                return NULL;
 
718
        os_memcpy(key, data->msk, EAP_MSK_LEN);
 
719
        *len = EAP_MSK_LEN;
 
720
 
 
721
        return key;
 
722
}
 
723
 
 
724
 
 
725
static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 
726
{
 
727
        struct eap_gpsk_data *data = priv;
 
728
        u8 *key;
 
729
 
 
730
        if (data->state != SUCCESS)
 
731
                return NULL;
 
732
 
 
733
        key = os_malloc(EAP_EMSK_LEN);
 
734
        if (key == NULL)
 
735
                return NULL;
 
736
        os_memcpy(key, data->emsk, EAP_EMSK_LEN);
 
737
        *len = EAP_EMSK_LEN;
 
738
 
 
739
        return key;
 
740
}
 
741
 
 
742
 
 
743
static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 
744
{
 
745
        struct eap_gpsk_data *data = priv;
 
746
        u8 *sid;
 
747
 
 
748
        if (data->state != SUCCESS)
 
749
                return NULL;
 
750
 
 
751
        sid = os_malloc(data->id_len);
 
752
        if (sid == NULL)
 
753
                return NULL;
 
754
        os_memcpy(sid, data->session_id, data->id_len);
 
755
        *len = data->id_len;
 
756
 
 
757
        return sid;
 
758
}
 
759
 
 
760
 
 
761
int eap_peer_gpsk_register(void)
 
762
{
 
763
        struct eap_method *eap;
 
764
        int ret;
 
765
 
 
766
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 
767
                                    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
 
768
        if (eap == NULL)
 
769
                return -1;
 
770
 
 
771
        eap->init = eap_gpsk_init;
 
772
        eap->deinit = eap_gpsk_deinit;
 
773
        eap->process = eap_gpsk_process;
 
774
        eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
 
775
        eap->getKey = eap_gpsk_getKey;
 
776
        eap->get_emsk = eap_gpsk_get_emsk;
 
777
        eap->getSessionId = eap_gpsk_get_session_id;
 
778
 
 
779
        ret = eap_peer_method_register(eap);
 
780
        if (ret)
 
781
                eap_peer_method_free(eap);
 
782
        return ret;
 
783
}