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