]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/eap_server/eap_server_eke.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / eap_server / eap_server_eke.c
1 /*
2  * hostapd / EAP-EKE (RFC 6124) server
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_server/eap_i.h"
14 #include "eap_common/eap_eke_common.h"
15
16
17 struct eap_eke_data {
18         enum {
19                 IDENTITY, COMMIT, CONFIRM, FAILURE_REPORT, SUCCESS, FAILURE
20         } state;
21         u8 msk[EAP_MSK_LEN];
22         u8 emsk[EAP_EMSK_LEN];
23         u8 *peerid;
24         size_t peerid_len;
25         u8 peerid_type;
26         u8 serverid_type;
27         u8 dh_priv[EAP_EKE_MAX_DH_LEN];
28         u8 key[EAP_EKE_MAX_KEY_LEN];
29         struct eap_eke_session sess;
30         u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
31         u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
32         struct wpabuf *msgs;
33         int phase2;
34         u32 failure_code;
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 FAILURE_REPORT:
48                 return "FAILURE_REPORT";
49         case SUCCESS:
50                 return "SUCCESS";
51         case FAILURE:
52                 return "FAILURE";
53         default:
54                 return "?";
55         }
56 }
57
58
59 static void eap_eke_state(struct eap_eke_data *data, int state)
60 {
61         wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
62                    eap_eke_state_txt(data->state),
63                    eap_eke_state_txt(state));
64         data->state = state;
65 }
66
67
68 static void eap_eke_fail(struct eap_eke_data *data, u32 code)
69 {
70         wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code);
71         data->failure_code = code;
72         eap_eke_state(data, FAILURE_REPORT);
73 }
74
75
76 static void * eap_eke_init(struct eap_sm *sm)
77 {
78         struct eap_eke_data *data;
79         size_t i;
80
81         data = os_zalloc(sizeof(*data));
82         if (data == NULL)
83                 return NULL;
84         eap_eke_state(data, IDENTITY);
85
86         data->serverid_type = EAP_EKE_ID_OPAQUE;
87         for (i = 0; i < sm->server_id_len; i++) {
88                 if (sm->server_id[i] == '.' &&
89                     data->serverid_type == EAP_EKE_ID_OPAQUE)
90                         data->serverid_type = EAP_EKE_ID_FQDN;
91                 if (sm->server_id[i] == '@')
92                         data->serverid_type = EAP_EKE_ID_NAI;
93         }
94
95         data->phase2 = sm->init_phase2;
96
97         return data;
98 }
99
100
101 static void eap_eke_reset(struct eap_sm *sm, void *priv)
102 {
103         struct eap_eke_data *data = priv;
104         eap_eke_session_clean(&data->sess);
105         os_free(data->peerid);
106         wpabuf_free(data->msgs);
107         bin_clear_free(data, sizeof(*data));
108 }
109
110
111 static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data,
112                                          u8 id, size_t length, u8 eke_exch)
113 {
114         struct wpabuf *msg;
115         size_t plen;
116
117         plen = 1 + length;
118
119         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
120                             EAP_CODE_REQUEST, id);
121         if (msg == NULL) {
122                 wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
123                 return NULL;
124         }
125
126         wpabuf_put_u8(msg, eke_exch);
127
128         return msg;
129 }
130
131
132 static int supported_proposal(const u8 *pos)
133 {
134         if (pos[0] == EAP_EKE_DHGROUP_EKE_16 &&
135             pos[1] == EAP_EKE_ENCR_AES128_CBC &&
136             pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
137             pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
138                 return 1;
139
140         if (pos[0] == EAP_EKE_DHGROUP_EKE_15 &&
141             pos[1] == EAP_EKE_ENCR_AES128_CBC &&
142             pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
143             pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
144                 return 1;
145
146         if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
147             pos[1] == EAP_EKE_ENCR_AES128_CBC &&
148             pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
149             pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
150                 return 1;
151
152         if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
153             pos[1] == EAP_EKE_ENCR_AES128_CBC &&
154             pos[2] == EAP_EKE_PRF_HMAC_SHA1 &&
155             pos[3] == EAP_EKE_MAC_HMAC_SHA1)
156                 return 1;
157
158         return 0;
159 }
160
161
162 static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id)
163 {
164         struct wpabuf *msg;
165
166         wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x",
167                    data->failure_code);
168
169         msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
170         if (msg == NULL) {
171                 eap_eke_state(data, FAILURE);
172                 return NULL;
173         }
174         wpabuf_put_be32(msg, data->failure_code);
175
176         return msg;
177 }
178
179
180 static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm,
181                                               struct eap_eke_data *data,
182                                               u8 id)
183 {
184         struct wpabuf *msg;
185         size_t plen;
186
187         wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
188
189         plen = 2 + 4 * 4 + 1 + sm->server_id_len;
190         msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
191         if (msg == NULL)
192                 return NULL;
193
194         wpabuf_put_u8(msg, 4); /* NumProposals */
195         wpabuf_put_u8(msg, 0); /* Reserved */
196
197         /* Proposal - DH Group 16 with AES128-CBC and SHA256 */
198         wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */
199         wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
200         wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
201         wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
202
203         /* Proposal - DH Group 15 with AES128-CBC and SHA256 */
204         wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */
205         wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
206         wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
207         wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
208
209         /* Proposal - DH Group 14 with AES128-CBC and SHA256 */
210         wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
211         wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
212         wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
213         wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
214
215         /*
216          * Proposal - DH Group 14 with AES128-CBC and SHA1
217          * (mandatory to implement algorithms)
218          */
219         wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
220         wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
221         wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */
222         wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */
223
224         /* Server IDType + Identity */
225         wpabuf_put_u8(msg, data->serverid_type);
226         wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
227
228         wpabuf_free(data->msgs);
229         data->msgs = wpabuf_dup(msg);
230         if (data->msgs == NULL) {
231                 wpabuf_free(msg);
232                 return NULL;
233         }
234
235         return msg;
236 }
237
238
239 static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm,
240                                             struct eap_eke_data *data, u8 id)
241 {
242         struct wpabuf *msg;
243         u8 pub[EAP_EKE_MAX_DH_LEN];
244
245         wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");
246
247         if (sm->user == NULL || sm->user->password == NULL) {
248                 wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured");
249                 eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
250                 return eap_eke_build_failure(data, id);
251         }
252
253         if (eap_eke_derive_key(&data->sess, sm->user->password,
254                                sm->user->password_len,
255                                sm->server_id, sm->server_id_len,
256                                data->peerid, data->peerid_len, data->key) < 0) {
257                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
258                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
259                 return eap_eke_build_failure(data, id);
260         }
261
262         msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
263                                 EAP_EKE_COMMIT);
264         if (msg == NULL) {
265                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
266                 return eap_eke_build_failure(data, id);
267         }
268
269         /*
270          * y_s = g ^ x_s (mod p)
271          * x_s = random number 2 .. p-1
272          * temp = prf(0+, password)
273          * key = prf+(temp, ID_S | ID_P)
274          * DHComponent_S = Encr(key, y_s)
275          */
276
277         if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
278                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
279                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
280                 return eap_eke_build_failure(data, id);
281         }
282
283         if (eap_eke_dhcomp(&data->sess, data->key, pub,
284                            wpabuf_put(msg, data->sess.dhcomp_len))
285             < 0) {
286                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
287                 wpabuf_free(msg);
288                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
289                 return eap_eke_build_failure(data, id);
290         }
291
292         if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) {
293                 wpabuf_free(msg);
294                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
295                 return eap_eke_build_failure(data, id);
296         }
297         wpabuf_put_buf(data->msgs, msg);
298
299         return msg;
300 }
301
302
303 static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm,
304                                              struct eap_eke_data *data, u8 id)
305 {
306         struct wpabuf *msg;
307         size_t plen, prot_len;
308         u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
309         u8 *auth;
310
311         wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm");
312
313         plen = data->sess.pnonce_ps_len + data->sess.prf_len;
314         msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM);
315         if (msg == NULL) {
316                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
317                 return eap_eke_build_failure(data, id);
318         }
319
320         if (random_get_bytes(data->nonce_s, data->sess.nonce_len)) {
321                 wpabuf_free(msg);
322                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
323                 return eap_eke_build_failure(data, id);
324         }
325         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
326                         data->nonce_s, data->sess.nonce_len);
327
328         os_memcpy(nonces, data->nonce_p, data->sess.nonce_len);
329         os_memcpy(nonces + data->sess.nonce_len, data->nonce_s,
330                   data->sess.nonce_len);
331         prot_len = wpabuf_tailroom(msg);
332         if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len,
333                          wpabuf_put(msg, 0), &prot_len) < 0) {
334                 wpabuf_free(msg);
335                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
336                 return eap_eke_build_failure(data, id);
337         }
338         wpabuf_put(msg, prot_len);
339
340         if (eap_eke_derive_ka(&data->sess,
341                               sm->server_id, sm->server_id_len,
342                               data->peerid, data->peerid_len,
343                               data->nonce_p, data->nonce_s) < 0) {
344                 wpabuf_free(msg);
345                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
346                 return eap_eke_build_failure(data, id);
347         }
348
349         auth = wpabuf_put(msg, data->sess.prf_len);
350         if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth) < 0) {
351                 wpabuf_free(msg);
352                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
353                 return eap_eke_build_failure(data, id);
354         }
355         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len);
356
357         return msg;
358 }
359
360
361 static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
362 {
363         struct eap_eke_data *data = priv;
364
365         switch (data->state) {
366         case IDENTITY:
367                 return eap_eke_build_identity(sm, data, id);
368         case COMMIT:
369                 return eap_eke_build_commit(sm, data, id);
370         case CONFIRM:
371                 return eap_eke_build_confirm(sm, data, id);
372         case FAILURE_REPORT:
373                 return eap_eke_build_failure(data, id);
374         default:
375                 wpa_printf(MSG_DEBUG, "EAP-EKE: Unknown state %d in buildReq",
376                            data->state);
377                 break;
378         }
379         return NULL;
380 }
381
382
383 static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
384                              struct wpabuf *respData)
385 {
386         struct eap_eke_data *data = priv;
387         size_t len;
388         const u8 *pos;
389         u8 eke_exch;
390
391         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
392         if (pos == NULL || len < 1) {
393                 wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
394                 return TRUE;
395         }
396
397         eke_exch = *pos;
398         wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
399
400         if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
401                 return FALSE;
402
403         if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
404                 return FALSE;
405
406         if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
407                 return FALSE;
408
409         if (eke_exch == EAP_EKE_FAILURE)
410                 return FALSE;
411
412         wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d",
413                    eke_exch, data->state);
414
415         return TRUE;
416 }
417
418
419 static void eap_eke_process_identity(struct eap_sm *sm,
420                                      struct eap_eke_data *data,
421                                      const struct wpabuf *respData,
422                                      const u8 *payload, size_t payloadlen)
423 {
424         const u8 *pos, *end;
425         int i;
426
427         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");
428
429         if (data->state != IDENTITY) {
430                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
431                 return;
432         }
433
434         pos = payload;
435         end = payload + payloadlen;
436
437         if (pos + 2 + 4 + 1 > end) {
438                 wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload");
439                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
440                 return;
441         }
442
443         if (*pos != 1) {
444                 wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)",
445                            *pos);
446                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
447                 return;
448         }
449
450         pos += 2;
451
452         if (!supported_proposal(pos)) {
453                 wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)",
454                            pos[0], pos[1], pos[2], pos[3]);
455                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
456                 return;
457         }
458
459         wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
460                    pos[0], pos[1], pos[2], pos[3]);
461         if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) <
462             0) {
463                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
464                 return;
465         }
466         pos += 4;
467
468         data->peerid_type = *pos++;
469         os_free(data->peerid);
470         data->peerid = os_memdup(pos, end - pos);
471         if (data->peerid == NULL) {
472                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
473                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
474                 return;
475         }
476         data->peerid_len = end - pos;
477         wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
478         wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
479                           data->peerid, data->peerid_len);
480
481         if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
482                 wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
483                 eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
484                 return;
485         }
486
487         for (i = 0; i < EAP_MAX_METHODS; i++) {
488                 if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
489                     sm->user->methods[i].method == EAP_TYPE_EKE)
490                         break;
491         }
492         if (i == EAP_MAX_METHODS) {
493                 wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE");
494                 eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
495                 return;
496         }
497
498         if (sm->user->password == NULL || sm->user->password_len == 0) {
499                 wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer");
500                 eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
501                 return;
502         }
503
504         if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
505                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
506                 return;
507         }
508         wpabuf_put_buf(data->msgs, respData);
509
510         eap_eke_state(data, COMMIT);
511 }
512
513
514 static void eap_eke_process_commit(struct eap_sm *sm,
515                                    struct eap_eke_data *data,
516                                    const struct wpabuf *respData,
517                                    const u8 *payload, size_t payloadlen)
518 {
519         const u8 *pos, *end, *dhcomp, *pnonce;
520         size_t decrypt_len;
521
522         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
523
524         if (data->state != COMMIT) {
525                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
526                 return;
527         }
528
529         pos = payload;
530         end = payload + payloadlen;
531
532         if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) {
533                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
534                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
535                 return;
536         }
537
538         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
539                     pos, data->sess.dhcomp_len);
540         dhcomp = pos;
541         pos += data->sess.dhcomp_len;
542         wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
543         pnonce = pos;
544         pos += data->sess.pnonce_len;
545         wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
546
547         if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp)
548             < 0) {
549                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
550                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
551                 return;
552         }
553
554         if (eap_eke_derive_ke_ki(&data->sess,
555                                  sm->server_id, sm->server_id_len,
556                                  data->peerid, data->peerid_len) < 0) {
557                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
558                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
559                 return;
560         }
561
562         decrypt_len = sizeof(data->nonce_p);
563         if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
564                                  data->nonce_p, &decrypt_len) < 0) {
565                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
566                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
567                 return;
568         }
569         if (decrypt_len < (size_t) data->sess.nonce_len) {
570                 wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P");
571                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
572                 return;
573         }
574         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
575                         data->nonce_p, data->sess.nonce_len);
576
577         if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
578                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
579                 return;
580         }
581         wpabuf_put_buf(data->msgs, respData);
582
583         eap_eke_state(data, CONFIRM);
584 }
585
586
587 static void eap_eke_process_confirm(struct eap_sm *sm,
588                                     struct eap_eke_data *data,
589                                     const struct wpabuf *respData,
590                                     const u8 *payload, size_t payloadlen)
591 {
592         size_t decrypt_len;
593         u8 nonce[EAP_EKE_MAX_NONCE_LEN];
594         u8 auth_p[EAP_EKE_MAX_HASH_LEN];
595
596         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
597
598         if (data->state != CONFIRM) {
599                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
600                 return;
601         }
602
603         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
604
605         if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) {
606                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
607                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
608                 return;
609         }
610
611         decrypt_len = sizeof(nonce);
612         if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len,
613                                  nonce, &decrypt_len) < 0) {
614                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S");
615                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
616                 return;
617         }
618         if (decrypt_len < (size_t) data->sess.nonce_len) {
619                 wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S");
620                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
621                 return;
622         }
623         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
624                         nonce, data->sess.nonce_len);
625         if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) {
626                 wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S");
627                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
628                 return;
629         }
630
631         if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) {
632                 wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P");
633                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
634                 return;
635         }
636         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
637         if (os_memcmp_const(auth_p, payload + data->sess.pnonce_len,
638                             data->sess.prf_len) != 0) {
639                 wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
640                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
641                 return;
642         }
643
644         if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
645                                data->peerid, data->peerid_len,
646                                data->nonce_s, data->nonce_p,
647                                data->msk, data->emsk) < 0) {
648                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
649                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
650                 return;
651         }
652
653         os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
654         os_memset(data->key, 0, sizeof(data->key));
655         eap_eke_session_clean(&data->sess);
656
657         eap_eke_state(data, SUCCESS);
658 }
659
660
661 static void eap_eke_process_failure(struct eap_sm *sm,
662                                     struct eap_eke_data *data,
663                                     const struct wpabuf *respData,
664                                     const u8 *payload, size_t payloadlen)
665 {
666         u32 code;
667
668         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure");
669
670         if (payloadlen < 4) {
671                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
672                 eap_eke_state(data, FAILURE);
673                 return;
674         }
675
676         code = WPA_GET_BE32(payload);
677         wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code);
678
679         eap_eke_state(data, FAILURE);
680 }
681
682
683 static void eap_eke_process(struct eap_sm *sm, void *priv,
684                              struct wpabuf *respData)
685 {
686         struct eap_eke_data *data = priv;
687         u8 eke_exch;
688         size_t len;
689         const u8 *pos, *end;
690
691         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
692         if (pos == NULL || len < 1)
693                 return;
694
695         eke_exch = *pos;
696         end = pos + len;
697         pos++;
698
699         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
700
701         switch (eke_exch) {
702         case EAP_EKE_ID:
703                 eap_eke_process_identity(sm, data, respData, pos, end - pos);
704                 break;
705         case EAP_EKE_COMMIT:
706                 eap_eke_process_commit(sm, data, respData, pos, end - pos);
707                 break;
708         case EAP_EKE_CONFIRM:
709                 eap_eke_process_confirm(sm, data, respData, pos, end - pos);
710                 break;
711         case EAP_EKE_FAILURE:
712                 eap_eke_process_failure(sm, data, respData, pos, end - pos);
713                 break;
714         }
715 }
716
717
718 static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
719 {
720         struct eap_eke_data *data = priv;
721         return data->state == SUCCESS || data->state == FAILURE;
722 }
723
724
725 static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
726 {
727         struct eap_eke_data *data = priv;
728         u8 *key;
729
730         if (data->state != SUCCESS)
731                 return NULL;
732
733         key = os_memdup(data->msk, EAP_MSK_LEN);
734         if (key == NULL)
735                 return NULL;
736         *len = EAP_MSK_LEN;
737
738         return key;
739 }
740
741
742 static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
743 {
744         struct eap_eke_data *data = priv;
745         u8 *key;
746
747         if (data->state != SUCCESS)
748                 return NULL;
749
750         key = os_memdup(data->emsk, EAP_EMSK_LEN);
751         if (key == NULL)
752                 return NULL;
753         *len = EAP_EMSK_LEN;
754
755         return key;
756 }
757
758
759 static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
760 {
761         struct eap_eke_data *data = priv;
762         return data->state == SUCCESS;
763 }
764
765
766 static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
767 {
768         struct eap_eke_data *data = priv;
769         u8 *sid;
770         size_t sid_len;
771
772         if (data->state != SUCCESS)
773                 return NULL;
774
775         sid_len = 1 + 2 * data->sess.nonce_len;
776         sid = os_malloc(sid_len);
777         if (sid == NULL)
778                 return NULL;
779         sid[0] = EAP_TYPE_EKE;
780         os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len);
781         os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s,
782                   data->sess.nonce_len);
783         *len = sid_len;
784
785         return sid;
786 }
787
788
789 int eap_server_eke_register(void)
790 {
791         struct eap_method *eap;
792
793         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
794                                       EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
795         if (eap == NULL)
796                 return -1;
797
798         eap->init = eap_eke_init;
799         eap->reset = eap_eke_reset;
800         eap->buildReq = eap_eke_buildReq;
801         eap->check = eap_eke_check;
802         eap->process = eap_eke_process;
803         eap->isDone = eap_eke_isDone;
804         eap->getKey = eap_eke_getKey;
805         eap->isSuccess = eap_eke_isSuccess;
806         eap->get_emsk = eap_eke_get_emsk;
807         eap->getSessionId = eap_eke_get_session_id;
808
809         return eap_server_method_register(eap);
810 }