Branch data Line data Source code
1 : : /*
2 : : * EAP peer method: EAP-EKE (RFC 6124)
3 : : * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "crypto/random.h"
13 : : #include "eap_peer/eap_i.h"
14 : : #include "eap_common/eap_eke_common.h"
15 : :
16 : : struct eap_eke_data {
17 : : enum {
18 : : IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
19 : : } state;
20 : : u8 msk[EAP_MSK_LEN];
21 : : u8 emsk[EAP_EMSK_LEN];
22 : : u8 *peerid;
23 : : size_t peerid_len;
24 : : u8 *serverid;
25 : : size_t serverid_len;
26 : : u8 dh_priv[EAP_EKE_MAX_DH_LEN];
27 : : struct eap_eke_session sess;
28 : : u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
29 : : u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
30 : : struct wpabuf *msgs;
31 : : };
32 : :
33 : :
34 : 8 : static const char * eap_eke_state_txt(int state)
35 : : {
36 [ + + + + : 8 : switch (state) {
- - ]
37 : : case IDENTITY:
38 : 3 : return "IDENTITY";
39 : : case COMMIT:
40 : 2 : return "COMMIT";
41 : : case CONFIRM:
42 : 2 : return "CONFIRM";
43 : : case SUCCESS:
44 : 1 : return "SUCCESS";
45 : : case FAILURE:
46 : 0 : return "FAILURE";
47 : : default:
48 : 8 : return "?";
49 : : }
50 : : }
51 : :
52 : :
53 : 4 : static void eap_eke_state(struct eap_eke_data *data, int state)
54 : : {
55 : 4 : wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
56 : 4 : eap_eke_state_txt(data->state), eap_eke_state_txt(state));
57 : 4 : data->state = state;
58 : 4 : }
59 : :
60 : :
61 : : static void eap_eke_deinit(struct eap_sm *sm, void *priv);
62 : :
63 : :
64 : 1 : static void * eap_eke_init(struct eap_sm *sm)
65 : : {
66 : : struct eap_eke_data *data;
67 : : const u8 *identity, *password;
68 : : size_t identity_len, password_len;
69 : :
70 : 1 : password = eap_get_config_password(sm, &password_len);
71 [ - + ]: 1 : if (!password) {
72 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
73 : 0 : return NULL;
74 : : }
75 : :
76 : 1 : data = os_zalloc(sizeof(*data));
77 [ - + ]: 1 : if (data == NULL)
78 : 0 : return NULL;
79 : 1 : eap_eke_state(data, IDENTITY);
80 : :
81 : 1 : identity = eap_get_config_identity(sm, &identity_len);
82 [ + - ]: 1 : if (identity) {
83 : 1 : data->peerid = os_malloc(identity_len);
84 [ - + ]: 1 : if (data->peerid == NULL) {
85 : 0 : eap_eke_deinit(sm, data);
86 : 0 : return NULL;
87 : : }
88 : 1 : os_memcpy(data->peerid, identity, identity_len);
89 : 1 : data->peerid_len = identity_len;
90 : : }
91 : :
92 : 1 : return data;
93 : : }
94 : :
95 : :
96 : 1 : static void eap_eke_deinit(struct eap_sm *sm, void *priv)
97 : : {
98 : 1 : struct eap_eke_data *data = priv;
99 : 1 : eap_eke_session_clean(&data->sess);
100 : 1 : os_free(data->serverid);
101 : 1 : os_free(data->peerid);
102 : 1 : wpabuf_free(data->msgs);
103 : 1 : os_free(data);
104 : 1 : }
105 : :
106 : :
107 : 3 : static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
108 : : size_t length, u8 eke_exch)
109 : : {
110 : : struct wpabuf *msg;
111 : : size_t plen;
112 : :
113 : 3 : plen = 1 + length;
114 : :
115 : 3 : msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
116 : : EAP_CODE_RESPONSE, id);
117 [ - + ]: 3 : if (msg == NULL) {
118 : 0 : wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
119 : 0 : return NULL;
120 : : }
121 : :
122 : 3 : wpabuf_put_u8(msg, eke_exch);
123 : :
124 : 3 : return msg;
125 : : }
126 : :
127 : :
128 : 1 : static int eap_eke_supp_dhgroup(u8 dhgroup)
129 : : {
130 [ + - ][ + - ]: 2 : return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
131 [ + - ]: 1 : dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
132 [ + - ]: 1 : dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
133 [ + - ]: 1 : dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
134 : : dhgroup == EAP_EKE_DHGROUP_EKE_16;
135 : : }
136 : :
137 : :
138 : 1 : static int eap_eke_supp_encr(u8 encr)
139 : : {
140 : 1 : return encr == EAP_EKE_ENCR_AES128_CBC;
141 : : }
142 : :
143 : :
144 : 1 : static int eap_eke_supp_prf(u8 prf)
145 : : {
146 [ + - ][ + - ]: 1 : return prf == EAP_EKE_PRF_HMAC_SHA1 ||
147 : : prf == EAP_EKE_PRF_HMAC_SHA2_256;
148 : : }
149 : :
150 : :
151 : 1 : static int eap_eke_supp_mac(u8 mac)
152 : : {
153 [ + - ][ + - ]: 1 : return mac == EAP_EKE_MAC_HMAC_SHA1 ||
154 : : mac == EAP_EKE_MAC_HMAC_SHA2_256;
155 : : }
156 : :
157 : :
158 : 0 : static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
159 : : struct eap_method_ret *ret,
160 : : const struct wpabuf *reqData,
161 : : u32 failure_code)
162 : : {
163 : : struct wpabuf *resp;
164 : :
165 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
166 : : failure_code);
167 : :
168 : 0 : resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE);
169 [ # # ]: 0 : if (resp)
170 : 0 : wpabuf_put_be32(resp, failure_code);
171 : :
172 : 0 : os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
173 : 0 : eap_eke_session_clean(&data->sess);
174 : :
175 : 0 : eap_eke_state(data, FAILURE);
176 : 0 : ret->methodState = METHOD_DONE;
177 : 0 : ret->decision = DECISION_FAIL;
178 : 0 : ret->allowNotifications = FALSE;
179 : :
180 : 0 : return resp;
181 : : }
182 : :
183 : :
184 : 1 : static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
185 : : struct eap_method_ret *ret,
186 : : const struct wpabuf *reqData,
187 : : const u8 *payload,
188 : : size_t payload_len)
189 : : {
190 : : struct wpabuf *resp;
191 : : unsigned num_prop, i;
192 : : const u8 *pos, *end;
193 : 1 : const u8 *prop = NULL;
194 : : u8 idtype;
195 : :
196 [ - + ]: 1 : if (data->state != IDENTITY) {
197 : 0 : return eap_eke_build_fail(data, ret, reqData,
198 : : EAP_EKE_FAIL_PROTO_ERROR);
199 : : }
200 : :
201 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
202 : :
203 [ - + ]: 1 : if (payload_len < 2 + 4) {
204 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
205 : 0 : return eap_eke_build_fail(data, ret, reqData,
206 : : EAP_EKE_FAIL_PROTO_ERROR);
207 : : }
208 : :
209 : 1 : pos = payload;
210 : 1 : end = payload + payload_len;
211 : :
212 : 1 : num_prop = *pos++;
213 : 1 : pos++; /* Ignore Reserved field */
214 : :
215 [ - + ]: 1 : if (pos + num_prop * 4 > end) {
216 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
217 : : num_prop);
218 : 0 : return eap_eke_build_fail(data, ret, reqData,
219 : : EAP_EKE_FAIL_PROTO_ERROR);
220 : : }
221 : :
222 [ + - ]: 1 : for (i = 0; i < num_prop; i++) {
223 : 1 : const u8 *tmp = pos;
224 : :
225 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
226 : 4 : i, pos[0], pos[1], pos[2], pos[3]);
227 : 1 : pos += 4;
228 : :
229 [ - + ]: 1 : if (!eap_eke_supp_dhgroup(*tmp))
230 : 0 : continue;
231 : 1 : tmp++;
232 [ - + ]: 1 : if (!eap_eke_supp_encr(*tmp))
233 : 0 : continue;
234 : 1 : tmp++;
235 [ - + ]: 1 : if (!eap_eke_supp_prf(*tmp))
236 : 0 : continue;
237 : 1 : tmp++;
238 [ - + ]: 1 : if (!eap_eke_supp_mac(*tmp))
239 : 0 : continue;
240 : :
241 : 1 : prop = tmp - 3;
242 [ - + ]: 1 : if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
243 : 1 : prop[3]) < 0) {
244 : 0 : prop = NULL;
245 : 0 : continue;
246 : : }
247 : :
248 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
249 : 1 : break;
250 : : }
251 : :
252 [ - + ]: 1 : if (prop == NULL) {
253 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
254 : 0 : return eap_eke_build_fail(data, ret, reqData,
255 : : EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
256 : : }
257 : :
258 : 1 : pos += (num_prop - i - 1) * 4;
259 : :
260 [ - + ]: 1 : if (pos == end) {
261 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
262 : 0 : return eap_eke_build_fail(data, ret, reqData,
263 : : EAP_EKE_FAIL_PROTO_ERROR);
264 : : }
265 : :
266 : 1 : idtype = *pos++;
267 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
268 : 1 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
269 : 1 : pos, end - pos);
270 : 1 : os_free(data->serverid);
271 : 1 : data->serverid = os_malloc(end - pos);
272 [ - + ]: 1 : if (data->serverid == NULL) {
273 : 0 : return eap_eke_build_fail(data, ret, reqData,
274 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
275 : : }
276 : 1 : os_memcpy(data->serverid, pos, end - pos);
277 : 1 : data->serverid_len = end - pos;
278 : :
279 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
280 : :
281 : 1 : resp = eap_eke_build_msg(data, eap_get_id(reqData),
282 : 1 : 2 + 4 + 1 + data->peerid_len,
283 : : EAP_EKE_ID);
284 [ - + ]: 1 : if (resp == NULL) {
285 : 0 : return eap_eke_build_fail(data, ret, reqData,
286 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
287 : : }
288 : :
289 : 1 : wpabuf_put_u8(resp, 1); /* NumProposals */
290 : 1 : wpabuf_put_u8(resp, 0); /* Reserved */
291 : 1 : wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
292 : 1 : wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
293 [ + - ]: 1 : if (data->peerid)
294 : 1 : wpabuf_put_data(resp, data->peerid, data->peerid_len);
295 : :
296 : 1 : wpabuf_free(data->msgs);
297 : 1 : data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
298 [ - + ]: 1 : if (data->msgs == NULL) {
299 : 0 : wpabuf_free(resp);
300 : 0 : return eap_eke_build_fail(data, ret, reqData,
301 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
302 : : }
303 : 1 : wpabuf_put_buf(data->msgs, reqData);
304 : 1 : wpabuf_put_buf(data->msgs, resp);
305 : :
306 : 1 : eap_eke_state(data, COMMIT);
307 : :
308 : 1 : return resp;
309 : : }
310 : :
311 : :
312 : 1 : static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
313 : : struct eap_eke_data *data,
314 : : struct eap_method_ret *ret,
315 : : const struct wpabuf *reqData,
316 : : const u8 *payload,
317 : : size_t payload_len)
318 : : {
319 : : struct wpabuf *resp;
320 : : const u8 *pos, *end, *dhcomp;
321 : : size_t prot_len;
322 : : u8 *rpos;
323 : : u8 key[EAP_EKE_MAX_KEY_LEN];
324 : : u8 pub[EAP_EKE_MAX_DH_LEN];
325 : : const u8 *password;
326 : : size_t password_len;
327 : :
328 [ - + ]: 1 : if (data->state != COMMIT) {
329 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
330 : 0 : return eap_eke_build_fail(data, ret, reqData,
331 : : EAP_EKE_FAIL_PROTO_ERROR);
332 : : }
333 : :
334 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
335 : :
336 : 1 : password = eap_get_config_password(sm, &password_len);
337 [ - + ]: 1 : if (password == NULL) {
338 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
339 : 0 : return eap_eke_build_fail(data, ret, reqData,
340 : : EAP_EKE_FAIL_PASSWD_NOT_FOUND);
341 : : }
342 : :
343 : 1 : pos = payload;
344 : 1 : end = payload + payload_len;
345 : :
346 [ - + ]: 1 : if (pos + data->sess.dhcomp_len > end) {
347 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
348 : 0 : return eap_eke_build_fail(data, ret, reqData,
349 : : EAP_EKE_FAIL_PROTO_ERROR);
350 : : }
351 : :
352 : 1 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
353 : 1 : pos, data->sess.dhcomp_len);
354 : 1 : dhcomp = pos;
355 : 1 : pos += data->sess.dhcomp_len;
356 : 1 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
357 : :
358 : : /*
359 : : * temp = prf(0+, password)
360 : : * key = prf+(temp, ID_S | ID_P)
361 : : */
362 [ - + ]: 1 : if (eap_eke_derive_key(&data->sess, password, password_len,
363 : 1 : data->serverid, data->serverid_len,
364 : 1 : data->peerid, data->peerid_len, key) < 0) {
365 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
366 : 0 : return eap_eke_build_fail(data, ret, reqData,
367 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
368 : : }
369 : :
370 : : /*
371 : : * y_p = g ^ x_p (mod p)
372 : : * x_p = random number 2 .. p-1
373 : : */
374 [ - + ]: 1 : if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
375 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
376 : 0 : os_memset(key, 0, sizeof(key));
377 : 0 : return eap_eke_build_fail(data, ret, reqData,
378 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
379 : : }
380 : :
381 [ - + ]: 1 : if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
382 : : {
383 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
384 : 0 : os_memset(key, 0, sizeof(key));
385 : 0 : return eap_eke_build_fail(data, ret, reqData,
386 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
387 : : }
388 : :
389 [ - + ]: 1 : if (eap_eke_derive_ke_ki(&data->sess,
390 : 1 : data->serverid, data->serverid_len,
391 : 1 : data->peerid, data->peerid_len) < 0) {
392 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
393 : 0 : os_memset(key, 0, sizeof(key));
394 : 0 : return eap_eke_build_fail(data, ret, reqData,
395 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
396 : : }
397 : :
398 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
399 : :
400 : 1 : resp = eap_eke_build_msg(data, eap_get_id(reqData),
401 : 1 : data->sess.dhcomp_len + data->sess.pnonce_len,
402 : : EAP_EKE_COMMIT);
403 [ - + ]: 1 : if (resp == NULL) {
404 : 0 : os_memset(key, 0, sizeof(key));
405 : 0 : return eap_eke_build_fail(data, ret, reqData,
406 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
407 : : }
408 : :
409 : : /* DHComponent_P = Encr(key, y_p) */
410 : 1 : rpos = wpabuf_put(resp, data->sess.dhcomp_len);
411 [ - + ]: 1 : if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
412 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
413 : 0 : os_memset(key, 0, sizeof(key));
414 : 0 : return eap_eke_build_fail(data, ret, reqData,
415 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
416 : : }
417 : 1 : os_memset(key, 0, sizeof(key));
418 : :
419 : 1 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
420 : 1 : rpos, data->sess.dhcomp_len);
421 : :
422 [ - + ]: 1 : if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
423 : 0 : wpabuf_free(resp);
424 : 0 : return eap_eke_build_fail(data, ret, reqData,
425 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
426 : : }
427 : 1 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
428 : 2 : data->nonce_p, data->sess.nonce_len);
429 : 1 : prot_len = wpabuf_tailroom(resp);
430 [ - + ]: 1 : if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
431 : 1 : wpabuf_put(resp, 0), &prot_len) < 0) {
432 : 0 : wpabuf_free(resp);
433 : 0 : return eap_eke_build_fail(data, ret, reqData,
434 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
435 : : }
436 : 1 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
437 : 1 : wpabuf_put(resp, 0), prot_len);
438 : 1 : wpabuf_put(resp, prot_len);
439 : :
440 : : /* TODO: CBValue */
441 : :
442 [ - + ]: 1 : if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
443 : : < 0) {
444 : 0 : wpabuf_free(resp);
445 : 0 : return eap_eke_build_fail(data, ret, reqData,
446 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
447 : : }
448 : 1 : wpabuf_put_buf(data->msgs, reqData);
449 : 1 : wpabuf_put_buf(data->msgs, resp);
450 : :
451 : 1 : eap_eke_state(data, CONFIRM);
452 : :
453 : 1 : return resp;
454 : : }
455 : :
456 : :
457 : 1 : static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
458 : : struct eap_method_ret *ret,
459 : : const struct wpabuf *reqData,
460 : : const u8 *payload,
461 : : size_t payload_len)
462 : : {
463 : : struct wpabuf *resp;
464 : : const u8 *pos, *end;
465 : : size_t prot_len;
466 : : u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
467 : : u8 auth_s[EAP_EKE_MAX_HASH_LEN];
468 : : size_t decrypt_len;
469 : : u8 *auth;
470 : :
471 [ - + ]: 1 : if (data->state != CONFIRM) {
472 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
473 : 0 : data->state);
474 : 0 : return eap_eke_build_fail(data, ret, reqData,
475 : : EAP_EKE_FAIL_PROTO_ERROR);
476 : : }
477 : :
478 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
479 : :
480 : 1 : pos = payload;
481 : 1 : end = payload + payload_len;
482 : :
483 [ - + ]: 1 : if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
484 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
485 : 0 : return eap_eke_build_fail(data, ret, reqData,
486 : : EAP_EKE_FAIL_PROTO_ERROR);
487 : : }
488 : :
489 : 1 : decrypt_len = sizeof(nonces);
490 [ - + ]: 1 : if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
491 : : nonces, &decrypt_len) < 0) {
492 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
493 : 0 : return eap_eke_build_fail(data, ret, reqData,
494 : : EAP_EKE_FAIL_AUTHENTICATION_FAIL);
495 : : }
496 [ - + ]: 1 : if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
497 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
498 : 0 : return eap_eke_build_fail(data, ret, reqData,
499 : : EAP_EKE_FAIL_AUTHENTICATION_FAIL);
500 : : }
501 : 1 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
502 : 1 : nonces, 2 * data->sess.nonce_len);
503 [ - + ]: 1 : if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
504 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P");
505 : 0 : return eap_eke_build_fail(data, ret, reqData,
506 : : EAP_EKE_FAIL_AUTHENTICATION_FAIL);
507 : : }
508 : :
509 : 1 : os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
510 : : data->sess.nonce_len);
511 : 1 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
512 : 2 : data->nonce_s, data->sess.nonce_len);
513 : :
514 [ - + ]: 1 : if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
515 : 1 : data->peerid, data->peerid_len,
516 : 1 : data->nonce_p, data->nonce_s) < 0) {
517 : 0 : return eap_eke_build_fail(data, ret, reqData,
518 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
519 : : }
520 : :
521 [ - + ]: 1 : if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
522 : : {
523 : 0 : return eap_eke_build_fail(data, ret, reqData,
524 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
525 : : }
526 : 1 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
527 [ - + ]: 1 : if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len,
528 : : data->sess.prf_len) != 0) {
529 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
530 : 0 : return eap_eke_build_fail(data, ret, reqData,
531 : : EAP_EKE_FAIL_AUTHENTICATION_FAIL);
532 : : }
533 : :
534 : 1 : wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
535 : :
536 : 1 : resp = eap_eke_build_msg(data, eap_get_id(reqData),
537 : 1 : data->sess.pnonce_len + data->sess.prf_len,
538 : : EAP_EKE_CONFIRM);
539 [ - + ]: 1 : if (resp == NULL) {
540 : 0 : return eap_eke_build_fail(data, ret, reqData,
541 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
542 : : }
543 : :
544 : 1 : prot_len = wpabuf_tailroom(resp);
545 [ - + ]: 1 : if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
546 : 1 : wpabuf_put(resp, 0), &prot_len) < 0) {
547 : 0 : wpabuf_free(resp);
548 : 0 : return eap_eke_build_fail(data, ret, reqData,
549 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
550 : : }
551 : 1 : wpabuf_put(resp, prot_len);
552 : :
553 : 1 : auth = wpabuf_put(resp, data->sess.prf_len);
554 [ - + ]: 1 : if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
555 : 0 : wpabuf_free(resp);
556 : 0 : return eap_eke_build_fail(data, ret, reqData,
557 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
558 : : }
559 : 1 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
560 : :
561 [ - + ]: 1 : if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
562 : 1 : data->peerid, data->peerid_len,
563 : 1 : data->nonce_s, data->nonce_p,
564 : 1 : data->msk, data->emsk) < 0) {
565 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
566 : 0 : wpabuf_free(resp);
567 : 0 : return eap_eke_build_fail(data, ret, reqData,
568 : : EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
569 : : }
570 : :
571 : 1 : os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
572 : 1 : eap_eke_session_clean(&data->sess);
573 : :
574 : 1 : eap_eke_state(data, SUCCESS);
575 : 1 : ret->methodState = METHOD_MAY_CONT;
576 : 1 : ret->decision = DECISION_COND_SUCC;
577 : 1 : ret->allowNotifications = FALSE;
578 : :
579 : 1 : return resp;
580 : : }
581 : :
582 : :
583 : 0 : static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
584 : : struct eap_method_ret *ret,
585 : : const struct wpabuf *reqData,
586 : : const u8 *payload,
587 : : size_t payload_len)
588 : : {
589 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
590 : :
591 [ # # ]: 0 : if (payload_len < 4) {
592 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
593 : : } else {
594 : : u32 code;
595 : 0 : code = WPA_GET_BE32(payload);
596 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
597 : : }
598 : :
599 : 0 : return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR);
600 : : }
601 : :
602 : :
603 : 3 : static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
604 : : struct eap_method_ret *ret,
605 : : const struct wpabuf *reqData)
606 : : {
607 : 3 : struct eap_eke_data *data = priv;
608 : : struct wpabuf *resp;
609 : : const u8 *pos, *end;
610 : : size_t len;
611 : : u8 eke_exch;
612 : :
613 : 3 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
614 [ + - ][ - + ]: 3 : if (pos == NULL || len < 1) {
615 : 0 : ret->ignore = TRUE;
616 : 0 : return NULL;
617 : : }
618 : :
619 : 3 : end = pos + len;
620 : 3 : eke_exch = *pos++;
621 : :
622 : 3 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
623 : 3 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
624 : :
625 : 3 : ret->ignore = FALSE;
626 : 3 : ret->methodState = METHOD_MAY_CONT;
627 : 3 : ret->decision = DECISION_FAIL;
628 : 3 : ret->allowNotifications = TRUE;
629 : :
630 [ + + + - : 3 : switch (eke_exch) {
- ]
631 : : case EAP_EKE_ID:
632 : 1 : resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
633 : 1 : break;
634 : : case EAP_EKE_COMMIT:
635 : 1 : resp = eap_eke_process_commit(sm, data, ret, reqData,
636 : 1 : pos, end - pos);
637 : 1 : break;
638 : : case EAP_EKE_CONFIRM:
639 : 1 : resp = eap_eke_process_confirm(data, ret, reqData,
640 : 1 : pos, end - pos);
641 : 1 : break;
642 : : case EAP_EKE_FAILURE:
643 : 0 : resp = eap_eke_process_failure(data, ret, reqData,
644 : 0 : pos, end - pos);
645 : 0 : break;
646 : : default:
647 : 0 : wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
648 : 0 : ret->ignore = TRUE;
649 : 0 : return NULL;
650 : : }
651 : :
652 [ - + ]: 3 : if (ret->methodState == METHOD_DONE)
653 : 0 : ret->allowNotifications = FALSE;
654 : :
655 : 3 : return resp;
656 : : }
657 : :
658 : :
659 : 3 : static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
660 : : {
661 : 3 : struct eap_eke_data *data = priv;
662 : 3 : return data->state == SUCCESS;
663 : : }
664 : :
665 : :
666 : 1 : static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
667 : : {
668 : 1 : struct eap_eke_data *data = priv;
669 : : u8 *key;
670 : :
671 [ - + ]: 1 : if (data->state != SUCCESS)
672 : 0 : return NULL;
673 : :
674 : 1 : key = os_malloc(EAP_MSK_LEN);
675 [ - + ]: 1 : if (key == NULL)
676 : 0 : return NULL;
677 : 1 : os_memcpy(key, data->msk, EAP_MSK_LEN);
678 : 1 : *len = EAP_MSK_LEN;
679 : :
680 : 1 : return key;
681 : : }
682 : :
683 : :
684 : 0 : static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
685 : : {
686 : 0 : struct eap_eke_data *data = priv;
687 : : u8 *key;
688 : :
689 [ # # ]: 0 : if (data->state != SUCCESS)
690 : 0 : return NULL;
691 : :
692 : 0 : key = os_malloc(EAP_EMSK_LEN);
693 [ # # ]: 0 : if (key == NULL)
694 : 0 : return NULL;
695 : 0 : os_memcpy(key, data->emsk, EAP_EMSK_LEN);
696 : 0 : *len = EAP_EMSK_LEN;
697 : :
698 : 0 : return key;
699 : : }
700 : :
701 : :
702 : 3 : int eap_peer_eke_register(void)
703 : : {
704 : : struct eap_method *eap;
705 : : int ret;
706 : :
707 : 3 : eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
708 : : EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
709 [ - + ]: 3 : if (eap == NULL)
710 : 0 : return -1;
711 : :
712 : 3 : eap->init = eap_eke_init;
713 : 3 : eap->deinit = eap_eke_deinit;
714 : 3 : eap->process = eap_eke_process;
715 : 3 : eap->isKeyAvailable = eap_eke_isKeyAvailable;
716 : 3 : eap->getKey = eap_eke_getKey;
717 : 3 : eap->get_emsk = eap_eke_get_emsk;
718 : :
719 : 3 : ret = eap_peer_method_register(eap);
720 [ - + ]: 3 : if (ret)
721 : 0 : eap_peer_method_free(eap);
722 : 3 : return ret;
723 : : }
|