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