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