Branch data 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 : 68 : static const char * eap_eke_state_txt(int state)
39 : : {
40 [ + + + + : 68 : switch (state) {
+ + - ]
41 : : case IDENTITY:
42 : 27 : return "IDENTITY";
43 : : case COMMIT:
44 : 16 : return "COMMIT";
45 : : case CONFIRM:
46 : 14 : return "CONFIRM";
47 : : case FAILURE_REPORT:
48 : 2 : return "FAILURE_REPORT";
49 : : case SUCCESS:
50 : 7 : return "SUCCESS";
51 : : case FAILURE:
52 : 2 : return "FAILURE";
53 : : default:
54 : 68 : return "?";
55 : : }
56 : : }
57 : :
58 : :
59 : 34 : static void eap_eke_state(struct eap_eke_data *data, int state)
60 : : {
61 : 34 : wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
62 : 34 : eap_eke_state_txt(data->state),
63 : : eap_eke_state_txt(state));
64 : 34 : data->state = state;
65 : 34 : }
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 : 9 : static void * eap_eke_init(struct eap_sm *sm)
77 : : {
78 : : struct eap_eke_data *data;
79 : : size_t i;
80 : :
81 : 9 : data = os_zalloc(sizeof(*data));
82 [ - + ]: 9 : if (data == NULL)
83 : 0 : return NULL;
84 : 9 : eap_eke_state(data, IDENTITY);
85 : :
86 : 9 : data->serverid_type = EAP_EKE_ID_OPAQUE;
87 [ + + ]: 117 : for (i = 0; i < sm->server_id_len; i++) {
88 [ + + ][ + + ]: 108 : if (sm->server_id[i] == '.' &&
89 : 18 : data->serverid_type == EAP_EKE_ID_OPAQUE)
90 : 9 : data->serverid_type = EAP_EKE_ID_FQDN;
91 [ - + ]: 108 : if (sm->server_id[i] == '@')
92 : 0 : data->serverid_type = EAP_EKE_ID_NAI;
93 : : }
94 : :
95 : 9 : data->phase2 = sm->init_phase2;
96 : :
97 : 9 : return data;
98 : : }
99 : :
100 : :
101 : 9 : static void eap_eke_reset(struct eap_sm *sm, void *priv)
102 : : {
103 : 9 : struct eap_eke_data *data = priv;
104 : 9 : eap_eke_session_clean(&data->sess);
105 : 9 : os_free(data->peerid);
106 : 9 : wpabuf_free(data->msgs);
107 : 9 : os_free(data);
108 : 9 : }
109 : :
110 : :
111 : 25 : 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 : 25 : plen = 1 + length;
118 : :
119 : 25 : msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
120 : : EAP_CODE_REQUEST, id);
121 [ - + ]: 25 : if (msg == NULL) {
122 : 0 : wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
123 : 0 : return NULL;
124 : : }
125 : :
126 : 25 : wpabuf_put_u8(msg, eke_exch);
127 : :
128 : 25 : return msg;
129 : : }
130 : :
131 : :
132 : 8 : static int supported_proposal(const u8 *pos)
133 : : {
134 [ + + ][ + - ]: 8 : if (pos[0] == EAP_EKE_DHGROUP_EKE_16 &&
135 [ + - ]: 5 : pos[1] == EAP_EKE_ENCR_AES128_CBC &&
136 [ + - ]: 5 : pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
137 : 5 : pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
138 : 5 : return 1;
139 : :
140 [ + + ][ + - ]: 3 : if (pos[0] == EAP_EKE_DHGROUP_EKE_15 &&
141 [ + - ]: 1 : pos[1] == EAP_EKE_ENCR_AES128_CBC &&
142 [ + - ]: 1 : pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
143 : 1 : pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
144 : 1 : return 1;
145 : :
146 [ + - ][ + - ]: 2 : if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
147 [ + + ]: 2 : pos[1] == EAP_EKE_ENCR_AES128_CBC &&
148 [ + - ]: 1 : pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
149 : 1 : pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
150 : 1 : return 1;
151 : :
152 [ + - ][ + - ]: 1 : if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
153 [ + - ]: 1 : pos[1] == EAP_EKE_ENCR_AES128_CBC &&
154 [ + - ]: 1 : pos[2] == EAP_EKE_PRF_HMAC_SHA1 &&
155 : 1 : pos[3] == EAP_EKE_MAC_HMAC_SHA1)
156 : 1 : return 1;
157 : :
158 : 8 : 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 : 9 : 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 : 9 : wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
188 : :
189 : 9 : plen = 2 + 4 * 4 + 1 + sm->server_id_len;
190 : 9 : msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
191 [ - + ]: 9 : if (msg == NULL)
192 : 0 : return NULL;
193 : :
194 : 9 : wpabuf_put_u8(msg, 4); /* NumProposals */
195 : 9 : wpabuf_put_u8(msg, 0); /* Reserved */
196 : :
197 : : /* Proposal - DH Group 16 with AES128-CBC and SHA256 */
198 : 9 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */
199 : 9 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
200 : 9 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
201 : 9 : wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
202 : :
203 : : /* Proposal - DH Group 15 with AES128-CBC and SHA256 */
204 : 9 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */
205 : 9 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
206 : 9 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
207 : 9 : wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
208 : :
209 : : /* Proposal - DH Group 14 with AES128-CBC and SHA256 */
210 : 9 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
211 : 9 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
212 : 9 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
213 : 9 : 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 : 9 : wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
220 : 9 : wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
221 : 9 : wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */
222 : 9 : wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */
223 : :
224 : : /* Server IDType + Identity */
225 : 9 : wpabuf_put_u8(msg, data->serverid_type);
226 : 9 : wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
227 : :
228 : 9 : wpabuf_free(data->msgs);
229 : 9 : data->msgs = wpabuf_dup(msg);
230 [ - + ]: 9 : if (data->msgs == NULL) {
231 : 0 : wpabuf_free(msg);
232 : 0 : return NULL;
233 : : }
234 : :
235 : 9 : return msg;
236 : : }
237 : :
238 : :
239 : 8 : 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 : 8 : wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");
246 : :
247 [ - + ][ + - ]: 8 : 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 [ - + ]: 8 : if (eap_eke_derive_key(&data->sess, sm->user->password,
254 : 8 : sm->user->password_len,
255 : : sm->server_id, sm->server_id_len,
256 : 16 : 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 : 8 : msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
263 : : EAP_EKE_COMMIT);
264 [ - + ]: 8 : 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 [ - + ]: 8 : 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 [ - + ]: 8 : if (eap_eke_dhcomp(&data->sess, data->key, pub,
284 : 8 : 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 [ - + ]: 8 : 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 : 8 : wpabuf_put_buf(data->msgs, msg);
298 : :
299 : 8 : return msg;
300 : : }
301 : :
302 : :
303 : 7 : 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 : 7 : wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm");
312 : :
313 : 7 : plen = data->sess.pnonce_ps_len + data->sess.prf_len;
314 : 7 : msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM);
315 [ - + ]: 7 : 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 [ - + ]: 7 : 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 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
326 : 14 : data->nonce_s, data->sess.nonce_len);
327 : :
328 : 7 : os_memcpy(nonces, data->nonce_p, data->sess.nonce_len);
329 : 7 : os_memcpy(nonces + data->sess.nonce_len, data->nonce_s,
330 : : data->sess.nonce_len);
331 : 7 : prot_len = wpabuf_tailroom(msg);
332 [ - + ]: 7 : if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len,
333 : 7 : 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 : 7 : wpabuf_put(msg, prot_len);
339 : :
340 [ - + ]: 7 : if (eap_eke_derive_ka(&data->sess,
341 : : sm->server_id, sm->server_id_len,
342 : 7 : data->peerid, data->peerid_len,
343 : 7 : 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 : 7 : auth = wpabuf_put(msg, data->sess.prf_len);
350 [ - + ]: 7 : 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 : 7 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len);
356 : :
357 : 7 : return msg;
358 : : }
359 : :
360 : :
361 : 25 : static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
362 : : {
363 : 25 : struct eap_eke_data *data = priv;
364 : :
365 [ + + + + : 25 : switch (data->state) {
- ]
366 : : case IDENTITY:
367 : 9 : return eap_eke_build_identity(sm, data, id);
368 : : case COMMIT:
369 : 8 : return eap_eke_build_commit(sm, data, id);
370 : : case CONFIRM:
371 : 7 : 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 : 25 : return NULL;
380 : : }
381 : :
382 : :
383 : 25 : static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
384 : : struct wpabuf *respData)
385 : : {
386 : 25 : struct eap_eke_data *data = priv;
387 : : size_t len;
388 : : const u8 *pos;
389 : : u8 eke_exch;
390 : :
391 : 25 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
392 [ - + ][ + - ]: 25 : if (pos == NULL || len < 1) {
393 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
394 : 0 : return TRUE;
395 : : }
396 : :
397 : 25 : eke_exch = *pos;
398 : 25 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
399 : :
400 [ + + ][ + + ]: 25 : if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
401 : 8 : return FALSE;
402 : :
403 [ + + ][ + - ]: 17 : if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
404 : 8 : return FALSE;
405 : :
406 [ + + ][ + - ]: 9 : if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
407 : 7 : 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 : 25 : return TRUE;
416 : : }
417 : :
418 : :
419 : 8 : 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 : 8 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");
428 : :
429 [ - + ]: 8 : if (data->state != IDENTITY) {
430 : 0 : eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
431 : 0 : return;
432 : : }
433 : :
434 : 8 : pos = payload;
435 : 8 : end = payload + payloadlen;
436 : :
437 [ - + ]: 8 : 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 [ - + ]: 8 : 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 : 8 : pos += 2;
451 : :
452 [ - + ]: 8 : 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 : 8 : wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
460 : 32 : pos[0], pos[1], pos[2], pos[3]);
461 [ - + ]: 8 : 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 : 8 : pos += 4;
467 : :
468 : 8 : data->peerid_type = *pos++;
469 : 8 : os_free(data->peerid);
470 : 8 : data->peerid = os_malloc(end - pos);
471 [ - + ]: 8 : 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 : 8 : os_memcpy(data->peerid, pos, end - pos);
477 : 8 : data->peerid_len = end - pos;
478 : 8 : wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
479 : 8 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
480 : 8 : data->peerid, data->peerid_len);
481 : :
482 [ - + ]: 8 : 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 [ + - ]: 8 : for (i = 0; i < EAP_MAX_METHODS; i++) {
489 [ + - ][ + - ]: 8 : if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
490 : 8 : sm->user->methods[i].method == EAP_TYPE_EKE)
491 : 8 : break;
492 : : }
493 [ - + ]: 8 : 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 [ + - ][ - + ]: 8 : 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 [ - + ]: 8 : 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 : 8 : wpabuf_put_buf(data->msgs, respData);
510 : :
511 : 8 : eap_eke_state(data, COMMIT);
512 : : }
513 : :
514 : :
515 : 8 : 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 : 8 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
524 : :
525 [ - + ]: 8 : if (data->state != COMMIT) {
526 : 0 : eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
527 : 0 : return;
528 : : }
529 : :
530 : 8 : pos = payload;
531 : 8 : end = payload + payloadlen;
532 : :
533 [ - + ]: 8 : 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 : 8 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
540 : 8 : pos, data->sess.dhcomp_len);
541 : 8 : dhcomp = pos;
542 : 8 : pos += data->sess.dhcomp_len;
543 : 8 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
544 : 8 : pnonce = pos;
545 : 8 : pos += data->sess.pnonce_len;
546 : 8 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
547 : :
548 [ - + ]: 8 : 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 [ - + ]: 8 : if (eap_eke_derive_ke_ki(&data->sess,
556 : : sm->server_id, sm->server_id_len,
557 : 8 : 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 : 8 : decrypt_len = sizeof(data->nonce_p);
564 [ + + ]: 8 : if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
565 : 8 : 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 [ - + ]: 7 : 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 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
576 : 14 : data->nonce_p, data->sess.nonce_len);
577 : :
578 [ - + ]: 7 : 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 : 7 : wpabuf_put_buf(data->msgs, respData);
583 : :
584 : 8 : eap_eke_state(data, CONFIRM);
585 : : }
586 : :
587 : :
588 : 7 : 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 : 7 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
598 : :
599 [ - + ]: 7 : if (data->state != CONFIRM) {
600 : 0 : eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
601 : 0 : return;
602 : : }
603 : :
604 : 7 : wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
605 : :
606 [ - + ]: 7 : 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 : 7 : decrypt_len = sizeof(nonce);
613 [ - + ]: 7 : 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 [ - + ]: 7 : 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 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
625 : 7 : nonce, data->sess.nonce_len);
626 [ - + ]: 7 : 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 [ - + ]: 7 : 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 : 7 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
638 [ - + ]: 7 : 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 [ - + ]: 7 : if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
646 : 7 : data->peerid, data->peerid_len,
647 : 7 : data->nonce_s, data->nonce_p,
648 : 7 : 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 : 7 : os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
655 : 7 : os_memset(data->key, 0, sizeof(data->key));
656 : 7 : eap_eke_session_clean(&data->sess);
657 : :
658 : 7 : 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 : 25 : static void eap_eke_process(struct eap_sm *sm, void *priv,
685 : : struct wpabuf *respData)
686 : : {
687 : 25 : struct eap_eke_data *data = priv;
688 : : u8 eke_exch;
689 : : size_t len;
690 : : const u8 *pos, *end;
691 : :
692 : 25 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
693 [ - + ][ + - ]: 25 : if (pos == NULL || len < 1)
694 : 25 : return;
695 : :
696 : 25 : eke_exch = *pos;
697 : 25 : end = pos + len;
698 : 25 : pos++;
699 : :
700 : 25 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
701 : :
702 [ + + + + : 25 : switch (eke_exch) {
- ]
703 : : case EAP_EKE_ID:
704 : 8 : eap_eke_process_identity(sm, data, respData, pos, end - pos);
705 : 8 : break;
706 : : case EAP_EKE_COMMIT:
707 : 8 : eap_eke_process_commit(sm, data, respData, pos, end - pos);
708 : 8 : break;
709 : : case EAP_EKE_CONFIRM:
710 : 7 : eap_eke_process_confirm(sm, data, respData, pos, end - pos);
711 : 7 : 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 : 27 : static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
720 : : {
721 : 27 : struct eap_eke_data *data = priv;
722 [ + + ][ + + ]: 27 : return data->state == SUCCESS || data->state == FAILURE;
723 : : }
724 : :
725 : :
726 : 9 : static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
727 : : {
728 : 9 : struct eap_eke_data *data = priv;
729 : : u8 *key;
730 : :
731 [ + + ]: 9 : if (data->state != SUCCESS)
732 : 2 : return NULL;
733 : :
734 : 7 : key = os_malloc(EAP_MSK_LEN);
735 [ - + ]: 7 : if (key == NULL)
736 : 0 : return NULL;
737 : 7 : os_memcpy(key, data->msk, EAP_MSK_LEN);
738 : 7 : *len = EAP_MSK_LEN;
739 : :
740 : 9 : 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 : 11 : static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
763 : : {
764 : 11 : struct eap_eke_data *data = priv;
765 : 11 : 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 : : }
|