hostapd vendor branch: Update version from 0.6.10 => 2.1
[dragonfly.git] / contrib / hostapd / 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         os_free(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_malloc(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         os_memcpy(data->peerid, pos, end - pos);
477         data->peerid_len = end - pos;
478         wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
479         wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
480                           data->peerid, data->peerid_len);
481
482         if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
483                 wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
484                 eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
485                 return;
486         }
487
488         for (i = 0; i < EAP_MAX_METHODS; i++) {
489                 if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
490                     sm->user->methods[i].method == EAP_TYPE_EKE)
491                         break;
492         }
493         if (i == EAP_MAX_METHODS) {
494                 wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE");
495                 eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
496                 return;
497         }
498
499         if (sm->user->password == NULL || sm->user->password_len == 0) {
500                 wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer");
501                 eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
502                 return;
503         }
504
505         if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
506                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
507                 return;
508         }
509         wpabuf_put_buf(data->msgs, respData);
510
511         eap_eke_state(data, COMMIT);
512 }
513
514
515 static void eap_eke_process_commit(struct eap_sm *sm,
516                                    struct eap_eke_data *data,
517                                    const struct wpabuf *respData,
518                                    const u8 *payload, size_t payloadlen)
519 {
520         const u8 *pos, *end, *dhcomp, *pnonce;
521         size_t decrypt_len;
522
523         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
524
525         if (data->state != COMMIT) {
526                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
527                 return;
528         }
529
530         pos = payload;
531         end = payload + payloadlen;
532
533         if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) {
534                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
535                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
536                 return;
537         }
538
539         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
540                     pos, data->sess.dhcomp_len);
541         dhcomp = pos;
542         pos += data->sess.dhcomp_len;
543         wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
544         pnonce = pos;
545         pos += data->sess.pnonce_len;
546         wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
547
548         if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp)
549             < 0) {
550                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
551                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
552                 return;
553         }
554
555         if (eap_eke_derive_ke_ki(&data->sess,
556                                  sm->server_id, sm->server_id_len,
557                                  data->peerid, data->peerid_len) < 0) {
558                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
559                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
560                 return;
561         }
562
563         decrypt_len = sizeof(data->nonce_p);
564         if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
565                                  data->nonce_p, &decrypt_len) < 0) {
566                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
567                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
568                 return;
569         }
570         if (decrypt_len < (size_t) data->sess.nonce_len) {
571                 wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P");
572                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
573                 return;
574         }
575         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
576                         data->nonce_p, data->sess.nonce_len);
577
578         if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
579                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
580                 return;
581         }
582         wpabuf_put_buf(data->msgs, respData);
583
584         eap_eke_state(data, CONFIRM);
585 }
586
587
588 static void eap_eke_process_confirm(struct eap_sm *sm,
589                                     struct eap_eke_data *data,
590                                     const struct wpabuf *respData,
591                                     const u8 *payload, size_t payloadlen)
592 {
593         size_t decrypt_len;
594         u8 nonce[EAP_EKE_MAX_NONCE_LEN];
595         u8 auth_p[EAP_EKE_MAX_HASH_LEN];
596
597         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
598
599         if (data->state != CONFIRM) {
600                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
601                 return;
602         }
603
604         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
605
606         if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) {
607                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
608                 eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
609                 return;
610         }
611
612         decrypt_len = sizeof(nonce);
613         if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len,
614                                  nonce, &decrypt_len) < 0) {
615                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S");
616                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
617                 return;
618         }
619         if (decrypt_len < (size_t) data->sess.nonce_len) {
620                 wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S");
621                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
622                 return;
623         }
624         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
625                         nonce, data->sess.nonce_len);
626         if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) {
627                 wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S");
628                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
629                 return;
630         }
631
632         if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) {
633                 wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P");
634                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
635                 return;
636         }
637         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
638         if (os_memcmp(auth_p, payload + data->sess.pnonce_len,
639                       data->sess.prf_len) != 0) {
640                 wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
641                 eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
642                 return;
643         }
644
645         if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
646                                data->peerid, data->peerid_len,
647                                data->nonce_s, data->nonce_p,
648                                data->msk, data->emsk) < 0) {
649                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
650                 eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
651                 return;
652         }
653
654         os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
655         os_memset(data->key, 0, sizeof(data->key));
656         eap_eke_session_clean(&data->sess);
657
658         eap_eke_state(data, SUCCESS);
659 }
660
661
662 static void eap_eke_process_failure(struct eap_sm *sm,
663                                     struct eap_eke_data *data,
664                                     const struct wpabuf *respData,
665                                     const u8 *payload, size_t payloadlen)
666 {
667         u32 code;
668
669         wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure");
670
671         if (payloadlen < 4) {
672                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
673                 eap_eke_state(data, FAILURE);
674                 return;
675         }
676
677         code = WPA_GET_BE32(payload);
678         wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code);
679
680         eap_eke_state(data, FAILURE);
681 }
682
683
684 static void eap_eke_process(struct eap_sm *sm, void *priv,
685                              struct wpabuf *respData)
686 {
687         struct eap_eke_data *data = priv;
688         u8 eke_exch;
689         size_t len;
690         const u8 *pos, *end;
691
692         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
693         if (pos == NULL || len < 1)
694                 return;
695
696         eke_exch = *pos;
697         end = pos + len;
698         pos++;
699
700         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
701
702         switch (eke_exch) {
703         case EAP_EKE_ID:
704                 eap_eke_process_identity(sm, data, respData, pos, end - pos);
705                 break;
706         case EAP_EKE_COMMIT:
707                 eap_eke_process_commit(sm, data, respData, pos, end - pos);
708                 break;
709         case EAP_EKE_CONFIRM:
710                 eap_eke_process_confirm(sm, data, respData, pos, end - pos);
711                 break;
712         case EAP_EKE_FAILURE:
713                 eap_eke_process_failure(sm, data, respData, pos, end - pos);
714                 break;
715         }
716 }
717
718
719 static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
720 {
721         struct eap_eke_data *data = priv;
722         return data->state == SUCCESS || data->state == FAILURE;
723 }
724
725
726 static u8 * eap_eke_getKey(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_MSK_LEN);
735         if (key == NULL)
736                 return NULL;
737         os_memcpy(key, data->msk, EAP_MSK_LEN);
738         *len = EAP_MSK_LEN;
739
740         return key;
741 }
742
743
744 static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
745 {
746         struct eap_eke_data *data = priv;
747         u8 *key;
748
749         if (data->state != SUCCESS)
750                 return NULL;
751
752         key = os_malloc(EAP_EMSK_LEN);
753         if (key == NULL)
754                 return NULL;
755         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
756         *len = EAP_EMSK_LEN;
757
758         return key;
759 }
760
761
762 static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
763 {
764         struct eap_eke_data *data = priv;
765         return data->state == SUCCESS;
766 }
767
768
769 int eap_server_eke_register(void)
770 {
771         struct eap_method *eap;
772         int ret;
773
774         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
775                                       EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
776         if (eap == NULL)
777                 return -1;
778
779         eap->init = eap_eke_init;
780         eap->reset = eap_eke_reset;
781         eap->buildReq = eap_eke_buildReq;
782         eap->check = eap_eke_check;
783         eap->process = eap_eke_process;
784         eap->isDone = eap_eke_isDone;
785         eap->getKey = eap_eke_getKey;
786         eap->isSuccess = eap_eke_isSuccess;
787         eap->get_emsk = eap_eke_get_emsk;
788
789         ret = eap_server_method_register(eap);
790         if (ret)
791                 eap_server_method_free(eap);
792         return ret;
793 }