Merge branch 'vendor/OPENSSL'
[dragonfly.git] / contrib / hostapd / src / eap_peer / eap_eke.c
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 }