~ubuntu-branches/ubuntu/trusty/wpa/trusty

« back to all changes in this revision

Viewing changes to src/eap_peer/eap_eke.c

  • Committer: Package Import Robot
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2014-03-04 16:13:24 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20140304161324-md40gw8imcectbuu
Tags: 2.1-0ubuntu1
* New upstream release (LP: #1099755)
* debian/get-orig-source: update for new git repository for the current
  hostap/wpasupplicant versions.
* Dropped patches due to being applied upstream and included in the current
  source tarball:
  - debian/patches/11_wpa_gui_ftbfs_gcc_4_7.patch
  - debian/patches/13_human_readable_signal.patch
  - debian/patches/git_deinit_p2p_context_on_mgmt_remove_ff1f9c8.patch
  - debian/patches/libnl3-includes.patch
* debian/patches/git_accept_client_cert_from_server.patch: revert the commit:
  "OpenSSL: Do not accept SSL Client certificate for server", which breaks
  many AAA servers that include both client and server EKUs. Cherry-picked
  from hostap git commit b62d5b5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * EAP peer method: EAP-EKE (RFC 6124)
 
3
 * Copyright (c) 2013, 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_eke_common.h"
 
15
 
 
16
struct eap_eke_data {
 
17
        enum {
 
18
                IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
 
19
        } state;
 
20
        u8 msk[EAP_MSK_LEN];
 
21
        u8 emsk[EAP_EMSK_LEN];
 
22
        u8 *peerid;
 
23
        size_t peerid_len;
 
24
        u8 *serverid;
 
25
        size_t serverid_len;
 
26
        u8 dh_priv[EAP_EKE_MAX_DH_LEN];
 
27
        struct eap_eke_session sess;
 
28
        u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
 
29
        u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
 
30
        struct wpabuf *msgs;
 
31
        u8 dhgroup; /* forced DH group or 0 to allow all supported */
 
32
        u8 encr; /* forced encryption algorithm or 0 to allow all supported */
 
33
        u8 prf; /* forced PRF or 0 to allow all supported */
 
34
        u8 mac; /* forced MAC or 0 to allow all supported */
 
35
};
 
36
 
 
37
 
 
38
static const char * eap_eke_state_txt(int state)
 
39
{
 
40
        switch (state) {
 
41
        case IDENTITY:
 
42
                return "IDENTITY";
 
43
        case COMMIT:
 
44
                return "COMMIT";
 
45
        case CONFIRM:
 
46
                return "CONFIRM";
 
47
        case SUCCESS:
 
48
                return "SUCCESS";
 
49
        case FAILURE:
 
50
                return "FAILURE";
 
51
        default:
 
52
                return "?";
 
53
        }
 
54
}
 
55
 
 
56
 
 
57
static void eap_eke_state(struct eap_eke_data *data, int state)
 
58
{
 
59
        wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
 
60
                   eap_eke_state_txt(data->state), eap_eke_state_txt(state));
 
61
        data->state = state;
 
62
}
 
63
 
 
64
 
 
65
static void eap_eke_deinit(struct eap_sm *sm, void *priv);
 
66
 
 
67
 
 
68
static void * eap_eke_init(struct eap_sm *sm)
 
69
{
 
70
        struct eap_eke_data *data;
 
71
        const u8 *identity, *password;
 
72
        size_t identity_len, password_len;
 
73
        const char *phase1;
 
74
 
 
75
        password = eap_get_config_password(sm, &password_len);
 
76
        if (!password) {
 
77
                wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
 
78
                return NULL;
 
79
        }
 
80
 
 
81
        data = os_zalloc(sizeof(*data));
 
82
        if (data == NULL)
 
83
                return NULL;
 
84
        eap_eke_state(data, IDENTITY);
 
85
 
 
86
        identity = eap_get_config_identity(sm, &identity_len);
 
87
        if (identity) {
 
88
                data->peerid = os_malloc(identity_len);
 
89
                if (data->peerid == NULL) {
 
90
                        eap_eke_deinit(sm, data);
 
91
                        return NULL;
 
92
                }
 
93
                os_memcpy(data->peerid, identity, identity_len);
 
94
                data->peerid_len = identity_len;
 
95
        }
 
96
 
 
97
        phase1 = eap_get_config_phase1(sm);
 
98
        if (phase1) {
 
99
                const char *pos;
 
100
 
 
101
                pos = os_strstr(phase1, "dhgroup=");
 
102
                if (pos) {
 
103
                        data->dhgroup = atoi(pos + 8);
 
104
                        wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u",
 
105
                                   data->dhgroup);
 
106
                }
 
107
 
 
108
                pos = os_strstr(phase1, "encr=");
 
109
                if (pos) {
 
110
                        data->encr = atoi(pos + 5);
 
111
                        wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u",
 
112
                                   data->encr);
 
113
                }
 
114
 
 
115
                pos = os_strstr(phase1, "prf=");
 
116
                if (pos) {
 
117
                        data->prf = atoi(pos + 4);
 
118
                        wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u",
 
119
                                   data->prf);
 
120
                }
 
121
 
 
122
                pos = os_strstr(phase1, "mac=");
 
123
                if (pos) {
 
124
                        data->mac = atoi(pos + 4);
 
125
                        wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u",
 
126
                                   data->mac);
 
127
                }
 
128
        }
 
129
 
 
130
        return data;
 
131
}
 
132
 
 
133
 
 
134
static void eap_eke_deinit(struct eap_sm *sm, void *priv)
 
135
{
 
136
        struct eap_eke_data *data = priv;
 
137
        eap_eke_session_clean(&data->sess);
 
138
        os_free(data->serverid);
 
139
        os_free(data->peerid);
 
140
        wpabuf_free(data->msgs);
 
141
        os_free(data);
 
142
}
 
143
 
 
144
 
 
145
static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
 
146
                                         size_t length, u8 eke_exch)
 
147
{
 
148
        struct wpabuf *msg;
 
149
        size_t plen;
 
150
 
 
151
        plen = 1 + length;
 
152
 
 
153
        msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
 
154
                            EAP_CODE_RESPONSE, id);
 
155
        if (msg == NULL) {
 
156
                wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
 
157
                return NULL;
 
158
        }
 
159
 
 
160
        wpabuf_put_u8(msg, eke_exch);
 
161
 
 
162
        return msg;
 
163
}
 
164
 
 
165
 
 
166
static int eap_eke_supp_dhgroup(u8 dhgroup)
 
167
{
 
168
        return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
 
169
                dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
 
170
                dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
 
171
                dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
 
172
                dhgroup == EAP_EKE_DHGROUP_EKE_16;
 
173
}
 
174
 
 
175
 
 
176
static int eap_eke_supp_encr(u8 encr)
 
177
{
 
178
        return encr == EAP_EKE_ENCR_AES128_CBC;
 
179
}
 
180
 
 
181
 
 
182
static int eap_eke_supp_prf(u8 prf)
 
183
{
 
184
        return prf == EAP_EKE_PRF_HMAC_SHA1 ||
 
185
                prf == EAP_EKE_PRF_HMAC_SHA2_256;
 
186
}
 
187
 
 
188
 
 
189
static int eap_eke_supp_mac(u8 mac)
 
190
{
 
191
        return mac == EAP_EKE_MAC_HMAC_SHA1 ||
 
192
                mac == EAP_EKE_MAC_HMAC_SHA2_256;
 
193
}
 
194
 
 
195
 
 
196
static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
 
197
                                          struct eap_method_ret *ret,
 
198
                                          const struct wpabuf *reqData,
 
199
                                          u32 failure_code)
 
200
{
 
201
        struct wpabuf *resp;
 
202
 
 
203
        wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
 
204
                   failure_code);
 
205
 
 
206
        resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE);
 
207
        if (resp)
 
208
                wpabuf_put_be32(resp, failure_code);
 
209
 
 
210
        os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
 
211
        eap_eke_session_clean(&data->sess);
 
212
 
 
213
        eap_eke_state(data, FAILURE);
 
214
        ret->methodState = METHOD_DONE;
 
215
        ret->decision = DECISION_FAIL;
 
216
        ret->allowNotifications = FALSE;
 
217
 
 
218
        return resp;
 
219
}
 
220
 
 
221
 
 
222
static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
 
223
                                          struct eap_method_ret *ret,
 
224
                                          const struct wpabuf *reqData,
 
225
                                          const u8 *payload,
 
226
                                          size_t payload_len)
 
227
{
 
228
        struct wpabuf *resp;
 
229
        unsigned num_prop, i;
 
230
        const u8 *pos, *end;
 
231
        const u8 *prop = NULL;
 
232
        u8 idtype;
 
233
 
 
234
        if (data->state != IDENTITY) {
 
235
                return eap_eke_build_fail(data, ret, reqData,
 
236
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
237
        }
 
238
 
 
239
        wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
 
240
 
 
241
        if (payload_len < 2 + 4) {
 
242
                wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
 
243
                return eap_eke_build_fail(data, ret, reqData,
 
244
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
245
        }
 
246
 
 
247
        pos = payload;
 
248
        end = payload + payload_len;
 
249
 
 
250
        num_prop = *pos++;
 
251
        pos++; /* Ignore Reserved field */
 
252
 
 
253
        if (pos + num_prop * 4 > end) {
 
254
                wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
 
255
                           num_prop);
 
256
                return eap_eke_build_fail(data, ret, reqData,
 
257
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
258
        }
 
259
 
 
260
        for (i = 0; i < num_prop; i++) {
 
261
                const u8 *tmp = pos;
 
262
 
 
263
                wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
 
264
                           i, pos[0], pos[1], pos[2], pos[3]);
 
265
                pos += 4;
 
266
 
 
267
                if ((data->dhgroup && data->dhgroup != *tmp) ||
 
268
                    !eap_eke_supp_dhgroup(*tmp))
 
269
                        continue;
 
270
                tmp++;
 
271
                if ((data->encr && data->encr != *tmp) ||
 
272
                    !eap_eke_supp_encr(*tmp))
 
273
                        continue;
 
274
                tmp++;
 
275
                if ((data->prf && data->prf != *tmp) ||
 
276
                    !eap_eke_supp_prf(*tmp))
 
277
                        continue;
 
278
                tmp++;
 
279
                if ((data->mac && data->mac != *tmp) ||
 
280
                    !eap_eke_supp_mac(*tmp))
 
281
                        continue;
 
282
 
 
283
                prop = tmp - 3;
 
284
                if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
 
285
                                         prop[3]) < 0) {
 
286
                        prop = NULL;
 
287
                        continue;
 
288
                }
 
289
 
 
290
                wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
 
291
                break;
 
292
        }
 
293
 
 
294
        if (prop == NULL) {
 
295
                wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
 
296
                return eap_eke_build_fail(data, ret, reqData,
 
297
                                          EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
 
298
        }
 
299
 
 
300
        pos += (num_prop - i - 1) * 4;
 
301
 
 
302
        if (pos == end) {
 
303
                wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
 
304
                return eap_eke_build_fail(data, ret, reqData,
 
305
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
306
        }
 
307
 
 
308
        idtype = *pos++;
 
309
        wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
 
310
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
 
311
                          pos, end - pos);
 
312
        os_free(data->serverid);
 
313
        data->serverid = os_malloc(end - pos);
 
314
        if (data->serverid == NULL) {
 
315
                return eap_eke_build_fail(data, ret, reqData,
 
316
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
317
        }
 
318
        os_memcpy(data->serverid, pos, end - pos);
 
319
        data->serverid_len = end - pos;
 
320
 
 
321
        wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
 
322
 
 
323
        resp = eap_eke_build_msg(data, eap_get_id(reqData),
 
324
                                 2 + 4 + 1 + data->peerid_len,
 
325
                                 EAP_EKE_ID);
 
326
        if (resp == NULL) {
 
327
                return eap_eke_build_fail(data, ret, reqData,
 
328
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
329
        }
 
330
 
 
331
        wpabuf_put_u8(resp, 1); /* NumProposals */
 
332
        wpabuf_put_u8(resp, 0); /* Reserved */
 
333
        wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
 
334
        wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
 
335
        if (data->peerid)
 
336
                wpabuf_put_data(resp, data->peerid, data->peerid_len);
 
337
 
 
338
        wpabuf_free(data->msgs);
 
339
        data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
 
340
        if (data->msgs == NULL) {
 
341
                wpabuf_free(resp);
 
342
                return eap_eke_build_fail(data, ret, reqData,
 
343
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
344
        }
 
345
        wpabuf_put_buf(data->msgs, reqData);
 
346
        wpabuf_put_buf(data->msgs, resp);
 
347
 
 
348
        eap_eke_state(data, COMMIT);
 
349
 
 
350
        return resp;
 
351
}
 
352
 
 
353
 
 
354
static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
 
355
                                              struct eap_eke_data *data,
 
356
                                              struct eap_method_ret *ret,
 
357
                                              const struct wpabuf *reqData,
 
358
                                              const u8 *payload,
 
359
                                              size_t payload_len)
 
360
{
 
361
        struct wpabuf *resp;
 
362
        const u8 *pos, *end, *dhcomp;
 
363
        size_t prot_len;
 
364
        u8 *rpos;
 
365
        u8 key[EAP_EKE_MAX_KEY_LEN];
 
366
        u8 pub[EAP_EKE_MAX_DH_LEN];
 
367
        const u8 *password;
 
368
        size_t password_len;
 
369
 
 
370
        if (data->state != COMMIT) {
 
371
                wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
 
372
                return eap_eke_build_fail(data, ret, reqData,
 
373
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
374
        }
 
375
 
 
376
        wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
 
377
 
 
378
        password = eap_get_config_password(sm, &password_len);
 
379
        if (password == NULL) {
 
380
                wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
 
381
                return eap_eke_build_fail(data, ret, reqData,
 
382
                                          EAP_EKE_FAIL_PASSWD_NOT_FOUND);
 
383
        }
 
384
 
 
385
        pos = payload;
 
386
        end = payload + payload_len;
 
387
 
 
388
        if (pos + data->sess.dhcomp_len > end) {
 
389
                wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
 
390
                return eap_eke_build_fail(data, ret, reqData,
 
391
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
392
        }
 
393
 
 
394
        wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
 
395
                    pos, data->sess.dhcomp_len);
 
396
        dhcomp = pos;
 
397
        pos += data->sess.dhcomp_len;
 
398
        wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
 
399
 
 
400
        /*
 
401
         * temp = prf(0+, password)
 
402
         * key = prf+(temp, ID_S | ID_P)
 
403
         */
 
404
        if (eap_eke_derive_key(&data->sess, password, password_len,
 
405
                               data->serverid, data->serverid_len,
 
406
                               data->peerid, data->peerid_len, key) < 0) {
 
407
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
 
408
                return eap_eke_build_fail(data, ret, reqData,
 
409
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
410
        }
 
411
 
 
412
        /*
 
413
         * y_p = g ^ x_p (mod p)
 
414
         * x_p = random number 2 .. p-1
 
415
         */
 
416
        if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
 
417
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
 
418
                os_memset(key, 0, sizeof(key));
 
419
                return eap_eke_build_fail(data, ret, reqData,
 
420
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
421
        }
 
422
 
 
423
        if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
 
424
        {
 
425
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
 
426
                os_memset(key, 0, sizeof(key));
 
427
                return eap_eke_build_fail(data, ret, reqData,
 
428
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
429
        }
 
430
 
 
431
        if (eap_eke_derive_ke_ki(&data->sess,
 
432
                                 data->serverid, data->serverid_len,
 
433
                                 data->peerid, data->peerid_len) < 0) {
 
434
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
 
435
                os_memset(key, 0, sizeof(key));
 
436
                return eap_eke_build_fail(data, ret, reqData,
 
437
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
438
        }
 
439
 
 
440
        wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
 
441
 
 
442
        resp = eap_eke_build_msg(data, eap_get_id(reqData),
 
443
                                 data->sess.dhcomp_len + data->sess.pnonce_len,
 
444
                                 EAP_EKE_COMMIT);
 
445
        if (resp == NULL) {
 
446
                os_memset(key, 0, sizeof(key));
 
447
                return eap_eke_build_fail(data, ret, reqData,
 
448
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
449
        }
 
450
 
 
451
        /* DHComponent_P = Encr(key, y_p) */
 
452
        rpos = wpabuf_put(resp, data->sess.dhcomp_len);
 
453
        if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
 
454
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
 
455
                os_memset(key, 0, sizeof(key));
 
456
                return eap_eke_build_fail(data, ret, reqData,
 
457
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
458
        }
 
459
        os_memset(key, 0, sizeof(key));
 
460
 
 
461
        wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
 
462
                    rpos, data->sess.dhcomp_len);
 
463
 
 
464
        if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
 
465
                wpabuf_free(resp);
 
466
                return eap_eke_build_fail(data, ret, reqData,
 
467
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
468
        }
 
469
        wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
 
470
                        data->nonce_p, data->sess.nonce_len);
 
471
        prot_len = wpabuf_tailroom(resp);
 
472
        if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
 
473
                         wpabuf_put(resp, 0), &prot_len) < 0) {
 
474
                wpabuf_free(resp);
 
475
                return eap_eke_build_fail(data, ret, reqData,
 
476
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
477
        }
 
478
        wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
 
479
                    wpabuf_put(resp, 0), prot_len);
 
480
        wpabuf_put(resp, prot_len);
 
481
 
 
482
        /* TODO: CBValue */
 
483
 
 
484
        if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
 
485
            < 0) {
 
486
                wpabuf_free(resp);
 
487
                return eap_eke_build_fail(data, ret, reqData,
 
488
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
489
        }
 
490
        wpabuf_put_buf(data->msgs, reqData);
 
491
        wpabuf_put_buf(data->msgs, resp);
 
492
 
 
493
        eap_eke_state(data, CONFIRM);
 
494
 
 
495
        return resp;
 
496
}
 
497
 
 
498
 
 
499
static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
 
500
                                               struct eap_method_ret *ret,
 
501
                                               const struct wpabuf *reqData,
 
502
                                               const u8 *payload,
 
503
                                               size_t payload_len)
 
504
{
 
505
        struct wpabuf *resp;
 
506
        const u8 *pos, *end;
 
507
        size_t prot_len;
 
508
        u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
 
509
        u8 auth_s[EAP_EKE_MAX_HASH_LEN];
 
510
        size_t decrypt_len;
 
511
        u8 *auth;
 
512
 
 
513
        if (data->state != CONFIRM) {
 
514
                wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
 
515
                           data->state);
 
516
                return eap_eke_build_fail(data, ret, reqData,
 
517
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
518
        }
 
519
 
 
520
        wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
 
521
 
 
522
        pos = payload;
 
523
        end = payload + payload_len;
 
524
 
 
525
        if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
 
526
                wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
 
527
                return eap_eke_build_fail(data, ret, reqData,
 
528
                                          EAP_EKE_FAIL_PROTO_ERROR);
 
529
        }
 
530
 
 
531
        decrypt_len = sizeof(nonces);
 
532
        if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
 
533
                                 nonces, &decrypt_len) < 0) {
 
534
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
 
535
                return eap_eke_build_fail(data, ret, reqData,
 
536
                                          EAP_EKE_FAIL_AUTHENTICATION_FAIL);
 
537
        }
 
538
        if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
 
539
                wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
 
540
                return eap_eke_build_fail(data, ret, reqData,
 
541
                                          EAP_EKE_FAIL_AUTHENTICATION_FAIL);
 
542
        }
 
543
        wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
 
544
                        nonces, 2 * data->sess.nonce_len);
 
545
        if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
 
546
                wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P");
 
547
                return eap_eke_build_fail(data, ret, reqData,
 
548
                                          EAP_EKE_FAIL_AUTHENTICATION_FAIL);
 
549
        }
 
550
 
 
551
        os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
 
552
                  data->sess.nonce_len);
 
553
        wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
 
554
                        data->nonce_s, data->sess.nonce_len);
 
555
 
 
556
        if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
 
557
                              data->peerid, data->peerid_len,
 
558
                              data->nonce_p, data->nonce_s) < 0) {
 
559
                return eap_eke_build_fail(data, ret, reqData,
 
560
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
561
        }
 
562
 
 
563
        if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
 
564
        {
 
565
                return eap_eke_build_fail(data, ret, reqData,
 
566
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
567
        }
 
568
        wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
 
569
        if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len,
 
570
                      data->sess.prf_len) != 0) {
 
571
                wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
 
572
                return eap_eke_build_fail(data, ret, reqData,
 
573
                                          EAP_EKE_FAIL_AUTHENTICATION_FAIL);
 
574
        }
 
575
 
 
576
        wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
 
577
 
 
578
        resp = eap_eke_build_msg(data, eap_get_id(reqData),
 
579
                                 data->sess.pnonce_len + data->sess.prf_len,
 
580
                                 EAP_EKE_CONFIRM);
 
581
        if (resp == NULL) {
 
582
                return eap_eke_build_fail(data, ret, reqData,
 
583
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
584
        }
 
585
 
 
586
        prot_len = wpabuf_tailroom(resp);
 
587
        if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
 
588
                         wpabuf_put(resp, 0), &prot_len) < 0) {
 
589
                wpabuf_free(resp);
 
590
                return eap_eke_build_fail(data, ret, reqData,
 
591
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
592
        }
 
593
        wpabuf_put(resp, prot_len);
 
594
 
 
595
        auth = wpabuf_put(resp, data->sess.prf_len);
 
596
        if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
 
597
                wpabuf_free(resp);
 
598
                return eap_eke_build_fail(data, ret, reqData,
 
599
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
600
        }
 
601
        wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
 
602
 
 
603
        if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
 
604
                               data->peerid, data->peerid_len,
 
605
                               data->nonce_s, data->nonce_p,
 
606
                               data->msk, data->emsk) < 0) {
 
607
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
 
608
                wpabuf_free(resp);
 
609
                return eap_eke_build_fail(data, ret, reqData,
 
610
                                          EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
 
611
        }
 
612
 
 
613
        os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
 
614
        eap_eke_session_clean(&data->sess);
 
615
 
 
616
        eap_eke_state(data, SUCCESS);
 
617
        ret->methodState = METHOD_MAY_CONT;
 
618
        ret->decision = DECISION_COND_SUCC;
 
619
        ret->allowNotifications = FALSE;
 
620
 
 
621
        return resp;
 
622
}
 
623
 
 
624
 
 
625
static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
 
626
                                               struct eap_method_ret *ret,
 
627
                                               const struct wpabuf *reqData,
 
628
                                               const u8 *payload,
 
629
                                               size_t payload_len)
 
630
{
 
631
        wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
 
632
 
 
633
        if (payload_len < 4) {
 
634
                wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
 
635
        } else {
 
636
                u32 code;
 
637
                code = WPA_GET_BE32(payload);
 
638
                wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
 
639
        }
 
640
 
 
641
        return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR);
 
642
}
 
643
 
 
644
 
 
645
static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
 
646
                                       struct eap_method_ret *ret,
 
647
                                       const struct wpabuf *reqData)
 
648
{
 
649
        struct eap_eke_data *data = priv;
 
650
        struct wpabuf *resp;
 
651
        const u8 *pos, *end;
 
652
        size_t len;
 
653
        u8 eke_exch;
 
654
 
 
655
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
 
656
        if (pos == NULL || len < 1) {
 
657
                ret->ignore = TRUE;
 
658
                return NULL;
 
659
        }
 
660
 
 
661
        end = pos + len;
 
662
        eke_exch = *pos++;
 
663
 
 
664
        wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
 
665
        wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
 
666
 
 
667
        ret->ignore = FALSE;
 
668
        ret->methodState = METHOD_MAY_CONT;
 
669
        ret->decision = DECISION_FAIL;
 
670
        ret->allowNotifications = TRUE;
 
671
 
 
672
        switch (eke_exch) {
 
673
        case EAP_EKE_ID:
 
674
                resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
 
675
                break;
 
676
        case EAP_EKE_COMMIT:
 
677
                resp = eap_eke_process_commit(sm, data, ret, reqData,
 
678
                                              pos, end - pos);
 
679
                break;
 
680
        case EAP_EKE_CONFIRM:
 
681
                resp = eap_eke_process_confirm(data, ret, reqData,
 
682
                                               pos, end - pos);
 
683
                break;
 
684
        case EAP_EKE_FAILURE:
 
685
                resp = eap_eke_process_failure(data, ret, reqData,
 
686
                                               pos, end - pos);
 
687
                break;
 
688
        default:
 
689
                wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
 
690
                ret->ignore = TRUE;
 
691
                return NULL;
 
692
        }
 
693
 
 
694
        if (ret->methodState == METHOD_DONE)
 
695
                ret->allowNotifications = FALSE;
 
696
 
 
697
        return resp;
 
698
}
 
699
 
 
700
 
 
701
static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
 
702
{
 
703
        struct eap_eke_data *data = priv;
 
704
        return data->state == SUCCESS;
 
705
}
 
706
 
 
707
 
 
708
static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
 
709
{
 
710
        struct eap_eke_data *data = priv;
 
711
        u8 *key;
 
712
 
 
713
        if (data->state != SUCCESS)
 
714
                return NULL;
 
715
 
 
716
        key = os_malloc(EAP_MSK_LEN);
 
717
        if (key == NULL)
 
718
                return NULL;
 
719
        os_memcpy(key, data->msk, EAP_MSK_LEN);
 
720
        *len = EAP_MSK_LEN;
 
721
 
 
722
        return key;
 
723
}
 
724
 
 
725
 
 
726
static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 
727
{
 
728
        struct eap_eke_data *data = priv;
 
729
        u8 *key;
 
730
 
 
731
        if (data->state != SUCCESS)
 
732
                return NULL;
 
733
 
 
734
        key = os_malloc(EAP_EMSK_LEN);
 
735
        if (key == NULL)
 
736
                return NULL;
 
737
        os_memcpy(key, data->emsk, EAP_EMSK_LEN);
 
738
        *len = EAP_EMSK_LEN;
 
739
 
 
740
        return key;
 
741
}
 
742
 
 
743
 
 
744
int eap_peer_eke_register(void)
 
745
{
 
746
        struct eap_method *eap;
 
747
        int ret;
 
748
 
 
749
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 
750
                                    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
 
751
        if (eap == NULL)
 
752
                return -1;
 
753
 
 
754
        eap->init = eap_eke_init;
 
755
        eap->deinit = eap_eke_deinit;
 
756
        eap->process = eap_eke_process;
 
757
        eap->isKeyAvailable = eap_eke_isKeyAvailable;
 
758
        eap->getKey = eap_eke_getKey;
 
759
        eap->get_emsk = eap_eke_get_emsk;
 
760
 
 
761
        ret = eap_peer_method_register(eap);
 
762
        if (ret)
 
763
                eap_peer_method_free(eap);
 
764
        return ret;
 
765
}