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 374 : static const char * eap_eke_state_txt(int state)
39 : {
40 374 : switch (state) {
41 : case IDENTITY:
42 158 : return "IDENTITY";
43 : case COMMIT:
44 76 : return "COMMIT";
45 : case CONFIRM:
46 44 : return "CONFIRM";
47 : case FAILURE_REPORT:
48 54 : return "FAILURE_REPORT";
49 : case SUCCESS:
50 14 : return "SUCCESS";
51 : case FAILURE:
52 28 : return "FAILURE";
53 : default:
54 0 : return "?";
55 : }
56 : }
57 :
58 :
59 187 : static void eap_eke_state(struct eap_eke_data *data, int state)
60 : {
61 374 : wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
62 187 : eap_eke_state_txt(data->state),
63 : eap_eke_state_txt(state));
64 187 : data->state = state;
65 187 : }
66 :
67 :
68 27 : static void eap_eke_fail(struct eap_eke_data *data, u32 code)
69 : {
70 27 : wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code);
71 27 : data->failure_code = code;
72 27 : eap_eke_state(data, FAILURE_REPORT);
73 27 : }
74 :
75 :
76 57 : static void * eap_eke_init(struct eap_sm *sm)
77 : {
78 : struct eap_eke_data *data;
79 : size_t i;
80 :
81 57 : data = os_zalloc(sizeof(*data));
82 57 : if (data == NULL)
83 2 : return NULL;
84 55 : eap_eke_state(data, IDENTITY);
85 :
86 55 : data->serverid_type = EAP_EKE_ID_OPAQUE;
87 493 : for (i = 0; i < sm->server_id_len; i++) {
88 456 : if (sm->server_id[i] == '.' &&
89 18 : data->serverid_type == EAP_EKE_ID_OPAQUE)
90 9 : data->serverid_type = EAP_EKE_ID_FQDN;
91 438 : if (sm->server_id[i] == '@')
92 1 : data->serverid_type = EAP_EKE_ID_NAI;
93 : }
94 :
95 55 : data->phase2 = sm->init_phase2;
96 :
97 55 : return data;
98 : }
99 :
100 :
101 55 : static void eap_eke_reset(struct eap_sm *sm, void *priv)
102 : {
103 55 : struct eap_eke_data *data = priv;
104 55 : eap_eke_session_clean(&data->sess);
105 55 : os_free(data->peerid);
106 55 : wpabuf_free(data->msgs);
107 55 : bin_clear_free(data, sizeof(*data));
108 55 : }
109 :
110 :
111 143 : 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 143 : plen = 1 + length;
118 :
119 143 : msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
120 : EAP_CODE_REQUEST, id);
121 143 : if (msg == NULL) {
122 8 : wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
123 8 : return NULL;
124 : }
125 :
126 135 : wpabuf_put_u8(msg, eke_exch);
127 :
128 135 : return msg;
129 : }
130 :
131 :
132 47 : static int supported_proposal(const u8 *pos)
133 : {
134 91 : if (pos[0] == EAP_EKE_DHGROUP_EKE_16 &&
135 88 : pos[1] == EAP_EKE_ENCR_AES128_CBC &&
136 88 : pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
137 44 : pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
138 44 : 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 27 : static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id)
163 : {
164 : struct wpabuf *msg;
165 :
166 27 : wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x",
167 : data->failure_code);
168 :
169 27 : msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
170 27 : if (msg == NULL) {
171 1 : eap_eke_state(data, FAILURE);
172 1 : return NULL;
173 : }
174 26 : wpabuf_put_be32(msg, data->failure_code);
175 :
176 26 : return msg;
177 : }
178 :
179 :
180 55 : 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 55 : wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
188 :
189 55 : plen = 2 + 4 * 4 + 1 + sm->server_id_len;
190 55 : msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
191 55 : if (msg == NULL)
192 3 : return NULL;
193 :
194 52 : wpabuf_put_u8(msg, 4); /* NumProposals */
195 52 : wpabuf_put_u8(msg, 0); /* Reserved */
196 :
197 : /* Proposal - DH Group 16 with AES128-CBC and SHA256 */
198 52 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */
199 52 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
200 52 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
201 52 : wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
202 :
203 : /* Proposal - DH Group 15 with AES128-CBC and SHA256 */
204 52 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */
205 52 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
206 52 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
207 52 : wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
208 :
209 : /* Proposal - DH Group 14 with AES128-CBC and SHA256 */
210 52 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
211 52 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
212 52 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
213 52 : 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 52 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
220 52 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
221 52 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */
222 52 : wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */
223 :
224 : /* Server IDType + Identity */
225 52 : wpabuf_put_u8(msg, data->serverid_type);
226 52 : wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
227 :
228 52 : wpabuf_free(data->msgs);
229 52 : data->msgs = wpabuf_dup(msg);
230 52 : if (data->msgs == NULL) {
231 2 : wpabuf_free(msg);
232 2 : return NULL;
233 : }
234 :
235 50 : return msg;
236 : }
237 :
238 :
239 38 : 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 38 : wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");
246 :
247 38 : 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 114 : if (eap_eke_derive_key(&data->sess, sm->user->password,
254 38 : sm->user->password_len,
255 : sm->server_id, sm->server_id_len,
256 76 : data->peerid, data->peerid_len, data->key) < 0) {
257 2 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
258 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
259 2 : return eap_eke_build_failure(data, id);
260 : }
261 :
262 36 : msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
263 : EAP_EKE_COMMIT);
264 36 : if (msg == NULL) {
265 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
266 2 : 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 34 : 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 34 : if (eap_eke_dhcomp(&data->sess, data->key, pub,
284 34 : 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 34 : if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) {
293 2 : wpabuf_free(msg);
294 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
295 2 : return eap_eke_build_failure(data, id);
296 : }
297 32 : wpabuf_put_buf(data->msgs, msg);
298 :
299 32 : return msg;
300 : }
301 :
302 :
303 25 : 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 25 : wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm");
312 :
313 25 : plen = data->sess.pnonce_ps_len + data->sess.prf_len;
314 25 : msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM);
315 25 : if (msg == NULL) {
316 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
317 2 : return eap_eke_build_failure(data, id);
318 : }
319 :
320 23 : 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 46 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
326 46 : data->nonce_s, data->sess.nonce_len);
327 :
328 23 : os_memcpy(nonces, data->nonce_p, data->sess.nonce_len);
329 23 : os_memcpy(nonces + data->sess.nonce_len, data->nonce_s,
330 : data->sess.nonce_len);
331 23 : prot_len = wpabuf_tailroom(msg);
332 23 : if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len,
333 23 : 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 23 : wpabuf_put(msg, prot_len);
339 :
340 46 : if (eap_eke_derive_ka(&data->sess,
341 : sm->server_id, sm->server_id_len,
342 23 : data->peerid, data->peerid_len,
343 23 : data->nonce_p, data->nonce_s) < 0) {
344 2 : wpabuf_free(msg);
345 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
346 2 : return eap_eke_build_failure(data, id);
347 : }
348 :
349 21 : auth = wpabuf_put(msg, data->sess.prf_len);
350 21 : 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 21 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len);
356 :
357 21 : return msg;
358 : }
359 :
360 :
361 135 : static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
362 : {
363 135 : struct eap_eke_data *data = priv;
364 :
365 135 : switch (data->state) {
366 : case IDENTITY:
367 55 : return eap_eke_build_identity(sm, data, id);
368 : case COMMIT:
369 38 : return eap_eke_build_commit(sm, data, id);
370 : case CONFIRM:
371 25 : return eap_eke_build_confirm(sm, data, id);
372 : case FAILURE_REPORT:
373 17 : 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 121 : static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
384 : struct wpabuf *respData)
385 : {
386 121 : struct eap_eke_data *data = priv;
387 : size_t len;
388 : const u8 *pos;
389 : u8 eke_exch;
390 :
391 121 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
392 121 : if (pos == NULL || len < 1) {
393 0 : wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
394 0 : return TRUE;
395 : }
396 :
397 121 : eke_exch = *pos;
398 121 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
399 :
400 121 : if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
401 47 : return FALSE;
402 :
403 74 : if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
404 32 : return FALSE;
405 :
406 42 : if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
407 15 : return FALSE;
408 :
409 27 : if (eke_exch == EAP_EKE_FAILURE)
410 27 : 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 47 : 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 47 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");
428 :
429 47 : if (data->state != IDENTITY) {
430 0 : eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
431 0 : return;
432 : }
433 :
434 47 : pos = payload;
435 47 : end = payload + payloadlen;
436 :
437 47 : 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 47 : 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 47 : pos += 2;
451 :
452 47 : 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 188 : wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
460 188 : pos[0], pos[1], pos[2], pos[3]);
461 47 : 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 47 : pos += 4;
467 :
468 47 : data->peerid_type = *pos++;
469 47 : os_free(data->peerid);
470 47 : data->peerid = os_malloc(end - pos);
471 47 : if (data->peerid == NULL) {
472 2 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
473 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
474 2 : return;
475 : }
476 45 : os_memcpy(data->peerid, pos, end - pos);
477 45 : data->peerid_len = end - pos;
478 45 : wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
479 90 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
480 45 : data->peerid, data->peerid_len);
481 :
482 45 : if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
483 5 : wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
484 5 : eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
485 5 : return;
486 : }
487 :
488 40 : for (i = 0; i < EAP_MAX_METHODS; i++) {
489 80 : if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
490 40 : sm->user->methods[i].method == EAP_TYPE_EKE)
491 40 : break;
492 : }
493 40 : 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 40 : 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 40 : if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
506 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
507 2 : return;
508 : }
509 38 : wpabuf_put_buf(data->msgs, respData);
510 :
511 38 : eap_eke_state(data, COMMIT);
512 : }
513 :
514 :
515 32 : 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 32 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
524 :
525 32 : if (data->state != COMMIT) {
526 0 : eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
527 0 : return;
528 : }
529 :
530 32 : pos = payload;
531 32 : end = payload + payloadlen;
532 :
533 32 : 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 32 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
540 32 : pos, data->sess.dhcomp_len);
541 32 : dhcomp = pos;
542 32 : pos += data->sess.dhcomp_len;
543 32 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
544 32 : pnonce = pos;
545 32 : pos += data->sess.pnonce_len;
546 32 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
547 :
548 32 : 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 64 : if (eap_eke_derive_ke_ki(&data->sess,
556 : sm->server_id, sm->server_id_len,
557 32 : data->peerid, data->peerid_len) < 0) {
558 2 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
559 2 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
560 2 : return;
561 : }
562 :
563 30 : decrypt_len = sizeof(data->nonce_p);
564 30 : if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
565 30 : data->nonce_p, &decrypt_len) < 0) {
566 2 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
567 2 : eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
568 2 : return;
569 : }
570 28 : 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 56 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
576 56 : data->nonce_p, data->sess.nonce_len);
577 :
578 28 : if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
579 3 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
580 3 : return;
581 : }
582 25 : wpabuf_put_buf(data->msgs, respData);
583 :
584 25 : eap_eke_state(data, CONFIRM);
585 : }
586 :
587 :
588 15 : 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 15 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
598 :
599 15 : if (data->state != CONFIRM) {
600 0 : eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
601 0 : return;
602 : }
603 :
604 15 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
605 :
606 15 : 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 15 : decrypt_len = sizeof(nonce);
613 15 : 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 15 : 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 15 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
625 15 : nonce, data->sess.nonce_len);
626 15 : 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 15 : 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 15 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
638 15 : if (os_memcmp_const(auth_p, payload + data->sess.pnonce_len,
639 15 : 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 30 : if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
646 15 : data->peerid, data->peerid_len,
647 15 : data->nonce_s, data->nonce_p,
648 15 : data->msk, data->emsk) < 0) {
649 1 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
650 1 : eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
651 1 : return;
652 : }
653 :
654 14 : os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
655 14 : os_memset(data->key, 0, sizeof(data->key));
656 14 : eap_eke_session_clean(&data->sess);
657 :
658 14 : eap_eke_state(data, SUCCESS);
659 : }
660 :
661 :
662 27 : 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 27 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure");
670 :
671 27 : if (payloadlen < 4) {
672 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
673 0 : eap_eke_state(data, FAILURE);
674 27 : return;
675 : }
676 :
677 27 : code = WPA_GET_BE32(payload);
678 27 : wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code);
679 :
680 27 : eap_eke_state(data, FAILURE);
681 : }
682 :
683 :
684 121 : static void eap_eke_process(struct eap_sm *sm, void *priv,
685 : struct wpabuf *respData)
686 : {
687 121 : struct eap_eke_data *data = priv;
688 : u8 eke_exch;
689 : size_t len;
690 : const u8 *pos, *end;
691 :
692 121 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
693 121 : if (pos == NULL || len < 1)
694 121 : return;
695 :
696 121 : eke_exch = *pos;
697 121 : end = pos + len;
698 121 : pos++;
699 :
700 121 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
701 :
702 121 : switch (eke_exch) {
703 : case EAP_EKE_ID:
704 47 : eap_eke_process_identity(sm, data, respData, pos, end - pos);
705 47 : break;
706 : case EAP_EKE_COMMIT:
707 32 : eap_eke_process_commit(sm, data, respData, pos, end - pos);
708 32 : break;
709 : case EAP_EKE_CONFIRM:
710 15 : eap_eke_process_confirm(sm, data, respData, pos, end - pos);
711 15 : break;
712 : case EAP_EKE_FAILURE:
713 27 : eap_eke_process_failure(sm, data, respData, pos, end - pos);
714 27 : break;
715 : }
716 : }
717 :
718 :
719 148 : static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
720 : {
721 148 : struct eap_eke_data *data = priv;
722 148 : return data->state == SUCCESS || data->state == FAILURE;
723 : }
724 :
725 :
726 41 : static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
727 : {
728 41 : struct eap_eke_data *data = priv;
729 : u8 *key;
730 :
731 41 : if (data->state != SUCCESS)
732 27 : return NULL;
733 :
734 14 : key = os_malloc(EAP_MSK_LEN);
735 14 : if (key == NULL)
736 1 : return NULL;
737 13 : os_memcpy(key, data->msk, EAP_MSK_LEN);
738 13 : *len = EAP_MSK_LEN;
739 :
740 13 : return key;
741 : }
742 :
743 :
744 1 : static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
745 : {
746 1 : struct eap_eke_data *data = priv;
747 : u8 *key;
748 :
749 1 : if (data->state != SUCCESS)
750 0 : return NULL;
751 :
752 1 : key = os_malloc(EAP_EMSK_LEN);
753 1 : if (key == NULL)
754 0 : return NULL;
755 1 : os_memcpy(key, data->emsk, EAP_EMSK_LEN);
756 1 : *len = EAP_EMSK_LEN;
757 :
758 1 : return key;
759 : }
760 :
761 :
762 68 : static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
763 : {
764 68 : struct eap_eke_data *data = priv;
765 68 : return data->state == SUCCESS;
766 : }
767 :
768 :
769 41 : static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
770 : {
771 41 : struct eap_eke_data *data = priv;
772 : u8 *sid;
773 : size_t sid_len;
774 :
775 41 : if (data->state != SUCCESS)
776 27 : return NULL;
777 :
778 14 : sid_len = 1 + 2 * data->sess.nonce_len;
779 14 : sid = os_malloc(sid_len);
780 14 : if (sid == NULL)
781 2 : return NULL;
782 12 : sid[0] = EAP_TYPE_EKE;
783 12 : os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len);
784 12 : os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s,
785 : data->sess.nonce_len);
786 12 : *len = sid_len;
787 :
788 12 : return sid;
789 : }
790 :
791 :
792 25 : int eap_server_eke_register(void)
793 : {
794 : struct eap_method *eap;
795 : int ret;
796 :
797 25 : eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
798 : EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
799 25 : if (eap == NULL)
800 0 : return -1;
801 :
802 25 : eap->init = eap_eke_init;
803 25 : eap->reset = eap_eke_reset;
804 25 : eap->buildReq = eap_eke_buildReq;
805 25 : eap->check = eap_eke_check;
806 25 : eap->process = eap_eke_process;
807 25 : eap->isDone = eap_eke_isDone;
808 25 : eap->getKey = eap_eke_getKey;
809 25 : eap->isSuccess = eap_eke_isSuccess;
810 25 : eap->get_emsk = eap_eke_get_emsk;
811 25 : eap->getSessionId = eap_eke_get_session_id;
812 :
813 25 : ret = eap_server_method_register(eap);
814 25 : if (ret)
815 0 : eap_server_method_free(eap);
816 25 : return ret;
817 : }
|