Line data Source code
1 : /*
2 : * EAP server/peer: EAP-EKE shared routines
3 : * Copyright (c) 2011-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/aes.h"
13 : #include "crypto/aes_wrap.h"
14 : #include "crypto/crypto.h"
15 : #include "crypto/dh_groups.h"
16 : #include "crypto/random.h"
17 : #include "crypto/sha1.h"
18 : #include "crypto/sha256.h"
19 : #include "eap_common/eap_defs.h"
20 : #include "eap_eke_common.h"
21 :
22 :
23 36 : static int eap_eke_dh_len(u8 group)
24 : {
25 36 : switch (group) {
26 : case EAP_EKE_DHGROUP_EKE_2:
27 4 : return 128;
28 : case EAP_EKE_DHGROUP_EKE_5:
29 0 : return 192;
30 : case EAP_EKE_DHGROUP_EKE_14:
31 12 : return 256;
32 : case EAP_EKE_DHGROUP_EKE_15:
33 4 : return 384;
34 : case EAP_EKE_DHGROUP_EKE_16:
35 16 : return 512;
36 : }
37 :
38 0 : return -1;
39 : }
40 :
41 :
42 20 : static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
43 : {
44 : int dhlen;
45 :
46 20 : dhlen = eap_eke_dh_len(dhgroup);
47 20 : if (dhlen < 0)
48 0 : return -1;
49 20 : if (encr != EAP_EKE_ENCR_AES128_CBC)
50 0 : return -1;
51 20 : return AES_BLOCK_SIZE + dhlen;
52 : }
53 :
54 :
55 32 : static const struct dh_group * eap_eke_dh_group(u8 group)
56 : {
57 32 : switch (group) {
58 : case EAP_EKE_DHGROUP_EKE_2:
59 4 : return dh_groups_get(2);
60 : case EAP_EKE_DHGROUP_EKE_5:
61 0 : return dh_groups_get(5);
62 : case EAP_EKE_DHGROUP_EKE_14:
63 8 : return dh_groups_get(14);
64 : case EAP_EKE_DHGROUP_EKE_15:
65 4 : return dh_groups_get(15);
66 : case EAP_EKE_DHGROUP_EKE_16:
67 16 : return dh_groups_get(16);
68 : }
69 :
70 0 : return NULL;
71 : }
72 :
73 :
74 16 : static int eap_eke_dh_generator(u8 group)
75 : {
76 16 : switch (group) {
77 : case EAP_EKE_DHGROUP_EKE_2:
78 2 : return 5;
79 : case EAP_EKE_DHGROUP_EKE_5:
80 0 : return 31;
81 : case EAP_EKE_DHGROUP_EKE_14:
82 4 : return 11;
83 : case EAP_EKE_DHGROUP_EKE_15:
84 2 : return 5;
85 : case EAP_EKE_DHGROUP_EKE_16:
86 8 : return 5;
87 : }
88 :
89 0 : return -1;
90 : }
91 :
92 :
93 20 : static int eap_eke_pnonce_len(u8 mac)
94 : {
95 : int mac_len;
96 :
97 20 : if (mac == EAP_EKE_MAC_HMAC_SHA1)
98 8 : mac_len = SHA1_MAC_LEN;
99 12 : else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
100 12 : mac_len = SHA256_MAC_LEN;
101 : else
102 0 : return -1;
103 :
104 20 : return AES_BLOCK_SIZE + 16 + mac_len;
105 : }
106 :
107 :
108 20 : static int eap_eke_pnonce_ps_len(u8 mac)
109 : {
110 : int mac_len;
111 :
112 20 : if (mac == EAP_EKE_MAC_HMAC_SHA1)
113 8 : mac_len = SHA1_MAC_LEN;
114 12 : else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
115 12 : mac_len = SHA256_MAC_LEN;
116 : else
117 0 : return -1;
118 :
119 20 : return AES_BLOCK_SIZE + 2 * 16 + mac_len;
120 : }
121 :
122 :
123 40 : static int eap_eke_prf_len(u8 prf)
124 : {
125 40 : if (prf == EAP_EKE_PRF_HMAC_SHA1)
126 16 : return 20;
127 24 : if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
128 24 : return 32;
129 0 : return -1;
130 : }
131 :
132 :
133 20 : static int eap_eke_nonce_len(u8 prf)
134 : {
135 : int prf_len;
136 :
137 20 : prf_len = eap_eke_prf_len(prf);
138 20 : if (prf_len < 0)
139 0 : return -1;
140 :
141 20 : if (prf_len > 2 * 16)
142 0 : return (prf_len + 1) / 2;
143 :
144 20 : return 16;
145 : }
146 :
147 :
148 20 : static int eap_eke_auth_len(u8 prf)
149 : {
150 20 : switch (prf) {
151 : case EAP_EKE_PRF_HMAC_SHA1:
152 8 : return SHA1_MAC_LEN;
153 : case EAP_EKE_PRF_HMAC_SHA2_256:
154 12 : return SHA256_MAC_LEN;
155 : }
156 :
157 0 : return -1;
158 : }
159 :
160 :
161 16 : int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
162 : {
163 : int generator;
164 : u8 gen;
165 : const struct dh_group *dh;
166 : size_t pub_len, i;
167 :
168 16 : generator = eap_eke_dh_generator(group);
169 16 : if (generator < 0 || generator > 255)
170 0 : return -1;
171 16 : gen = generator;
172 :
173 16 : dh = eap_eke_dh_group(group);
174 16 : if (dh == NULL)
175 0 : return -1;
176 :
177 : /* x = random number 2 .. p-1 */
178 16 : if (random_get_bytes(ret_priv, dh->prime_len))
179 0 : return -1;
180 16 : if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
181 : /* Make sure private value is smaller than prime */
182 0 : ret_priv[0] = 0;
183 : }
184 16 : for (i = 0; i < dh->prime_len - 1; i++) {
185 16 : if (ret_priv[i])
186 16 : break;
187 : }
188 16 : if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
189 0 : return -1;
190 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
191 : ret_priv, dh->prime_len);
192 :
193 : /* y = g ^ x (mod p) */
194 16 : pub_len = dh->prime_len;
195 16 : if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
196 : dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
197 0 : return -1;
198 16 : if (pub_len < dh->prime_len) {
199 0 : size_t pad = dh->prime_len - pub_len;
200 0 : os_memmove(ret_pub + pad, ret_pub, pub_len);
201 0 : os_memset(ret_pub, 0, pad);
202 : }
203 :
204 16 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
205 : ret_pub, dh->prime_len);
206 :
207 16 : return 0;
208 : }
209 :
210 :
211 56 : static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data,
212 : size_t data_len, const u8 *data2, size_t data2_len,
213 : u8 *res)
214 : {
215 : const u8 *addr[2];
216 : size_t len[2];
217 56 : size_t num_elem = 1;
218 :
219 56 : addr[0] = data;
220 56 : len[0] = data_len;
221 56 : if (data2) {
222 24 : num_elem++;
223 24 : addr[1] = data2;
224 24 : len[1] = data2_len;
225 : }
226 :
227 56 : if (prf == EAP_EKE_PRF_HMAC_SHA1)
228 12 : return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
229 44 : if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
230 44 : return hmac_sha256_vector(key, key_len, num_elem, addr, len,
231 : res);
232 0 : return -1;
233 : }
234 :
235 :
236 12 : static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data,
237 : size_t data_len, u8 *res, size_t len)
238 : {
239 : u8 hash[SHA1_MAC_LEN];
240 : u8 idx;
241 : const u8 *addr[3];
242 : size_t vlen[3];
243 : int ret;
244 :
245 12 : idx = 0;
246 12 : addr[0] = hash;
247 12 : vlen[0] = SHA1_MAC_LEN;
248 12 : addr[1] = data;
249 12 : vlen[1] = data_len;
250 12 : addr[2] = &idx;
251 12 : vlen[2] = 1;
252 :
253 52 : while (len > 0) {
254 28 : idx++;
255 28 : if (idx == 1)
256 12 : ret = hmac_sha1_vector(key, key_len, 2, &addr[1],
257 : &vlen[1], hash);
258 : else
259 16 : ret = hmac_sha1_vector(key, key_len, 3, addr, vlen,
260 : hash);
261 28 : if (ret < 0)
262 0 : return -1;
263 28 : if (len > SHA1_MAC_LEN) {
264 16 : os_memcpy(res, hash, SHA1_MAC_LEN);
265 16 : res += SHA1_MAC_LEN;
266 16 : len -= SHA1_MAC_LEN;
267 : } else {
268 12 : os_memcpy(res, hash, len);
269 12 : len = 0;
270 : }
271 : }
272 :
273 12 : return 0;
274 : }
275 :
276 :
277 44 : static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
278 : size_t data_len, u8 *res, size_t len)
279 : {
280 : u8 hash[SHA256_MAC_LEN];
281 : u8 idx;
282 : const u8 *addr[3];
283 : size_t vlen[3];
284 : int ret;
285 :
286 44 : idx = 0;
287 44 : addr[0] = hash;
288 44 : vlen[0] = SHA256_MAC_LEN;
289 44 : addr[1] = data;
290 44 : vlen[1] = data_len;
291 44 : addr[2] = &idx;
292 44 : vlen[2] = 1;
293 :
294 174 : while (len > 0) {
295 86 : idx++;
296 86 : if (idx == 1)
297 44 : ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
298 : &vlen[1], hash);
299 : else
300 42 : ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
301 : hash);
302 86 : if (ret < 0)
303 0 : return -1;
304 86 : if (len > SHA256_MAC_LEN) {
305 42 : os_memcpy(res, hash, SHA256_MAC_LEN);
306 42 : res += SHA256_MAC_LEN;
307 42 : len -= SHA256_MAC_LEN;
308 : } else {
309 44 : os_memcpy(res, hash, len);
310 44 : len = 0;
311 : }
312 : }
313 :
314 44 : return 0;
315 : }
316 :
317 :
318 56 : static int eap_eke_prfplus(u8 prf, const u8 *key, size_t key_len,
319 : const u8 *data, size_t data_len, u8 *res, size_t len)
320 : {
321 56 : if (prf == EAP_EKE_PRF_HMAC_SHA1)
322 12 : return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res,
323 : len);
324 44 : if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
325 44 : return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
326 : res, len);
327 0 : return -1;
328 : }
329 :
330 :
331 16 : int eap_eke_derive_key(struct eap_eke_session *sess,
332 : const u8 *password, size_t password_len,
333 : const u8 *id_s, size_t id_s_len, const u8 *id_p,
334 : size_t id_p_len, u8 *key)
335 : {
336 : u8 zeros[EAP_EKE_MAX_HASH_LEN];
337 : u8 temp[EAP_EKE_MAX_HASH_LEN];
338 16 : size_t key_len = 16; /* Only AES-128-CBC is used here */
339 : u8 *id;
340 :
341 : /* temp = prf(0+, password) */
342 16 : os_memset(zeros, 0, sess->prf_len);
343 16 : if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
344 : password, password_len, NULL, 0, temp) < 0)
345 0 : return -1;
346 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
347 16 : temp, sess->prf_len);
348 :
349 : /* key = prf+(temp, ID_S | ID_P) */
350 16 : id = os_malloc(id_s_len + id_p_len);
351 16 : if (id == NULL)
352 0 : return -1;
353 16 : os_memcpy(id, id_s, id_s_len);
354 16 : os_memcpy(id + id_s_len, id_p, id_p_len);
355 16 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
356 : id, id_s_len + id_p_len);
357 16 : if (eap_eke_prfplus(sess->prf, temp, sess->prf_len,
358 : id, id_s_len + id_p_len, key, key_len) < 0) {
359 0 : os_free(id);
360 0 : return -1;
361 : }
362 16 : os_free(id);
363 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
364 : key, key_len);
365 :
366 16 : return 0;
367 : }
368 :
369 :
370 16 : int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
371 : u8 *ret_dhcomp)
372 : {
373 : u8 pub[EAP_EKE_MAX_DH_LEN];
374 : int dh_len;
375 : u8 iv[AES_BLOCK_SIZE];
376 :
377 16 : dh_len = eap_eke_dh_len(sess->dhgroup);
378 16 : if (dh_len < 0)
379 0 : return -1;
380 :
381 : /*
382 : * DHComponent = Encr(key, y)
383 : *
384 : * All defined DH groups use primes that have length devisible by 16, so
385 : * no need to do extra padding for y (= pub).
386 : */
387 16 : if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
388 0 : return -1;
389 16 : if (random_get_bytes(iv, AES_BLOCK_SIZE))
390 0 : return -1;
391 16 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
392 : iv, AES_BLOCK_SIZE);
393 16 : os_memcpy(pub, dhpub, dh_len);
394 16 : if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
395 0 : return -1;
396 16 : os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
397 16 : os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
398 16 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
399 16 : ret_dhcomp, AES_BLOCK_SIZE + dh_len);
400 :
401 16 : return 0;
402 : }
403 :
404 :
405 16 : int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
406 : const u8 *dhpriv, const u8 *peer_dhcomp)
407 : {
408 : u8 zeros[EAP_EKE_MAX_HASH_LEN];
409 : u8 peer_pub[EAP_EKE_MAX_DH_LEN];
410 : u8 modexp[EAP_EKE_MAX_DH_LEN];
411 : size_t len;
412 : const struct dh_group *dh;
413 :
414 16 : if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
415 0 : return -1;
416 :
417 16 : dh = eap_eke_dh_group(sess->dhgroup);
418 16 : if (dh == NULL)
419 0 : return -1;
420 :
421 : /* Decrypt peer DHComponent */
422 16 : os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
423 16 : if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) {
424 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent");
425 0 : return -1;
426 : }
427 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey",
428 : peer_pub, dh->prime_len);
429 :
430 : /* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
431 16 : len = dh->prime_len;
432 16 : if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
433 : dh->prime, dh->prime_len, modexp, &len) < 0)
434 0 : return -1;
435 16 : if (len < dh->prime_len) {
436 0 : size_t pad = dh->prime_len - len;
437 0 : os_memmove(modexp + pad, modexp, len);
438 0 : os_memset(modexp, 0, pad);
439 : }
440 :
441 16 : os_memset(zeros, 0, sess->auth_len);
442 16 : if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
443 16 : NULL, 0, sess->shared_secret) < 0)
444 0 : return -1;
445 32 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
446 32 : sess->shared_secret, sess->auth_len);
447 :
448 16 : return 0;
449 : }
450 :
451 :
452 16 : int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
453 : const u8 *id_s, size_t id_s_len,
454 : const u8 *id_p, size_t id_p_len)
455 : {
456 : u8 buf[EAP_EKE_MAX_KE_LEN + EAP_EKE_MAX_KI_LEN];
457 : size_t ke_len, ki_len;
458 : u8 *data;
459 : size_t data_len;
460 16 : const char *label = "EAP-EKE Keys";
461 : size_t label_len;
462 :
463 : /*
464 : * Ke | Ki = prf+(SharedSecret, "EAP-EKE Keys" | ID_S | ID_P)
465 : * Ke = encryption key
466 : * Ki = integrity protection key
467 : * Length of each key depends on the selected algorithms.
468 : */
469 :
470 16 : if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
471 16 : ke_len = 16;
472 : else
473 0 : return -1;
474 :
475 16 : if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
476 4 : ki_len = 20;
477 12 : else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
478 12 : ki_len = 32;
479 : else
480 0 : return -1;
481 :
482 16 : label_len = os_strlen(label);
483 16 : data_len = label_len + id_s_len + id_p_len;
484 16 : data = os_malloc(data_len);
485 16 : if (data == NULL)
486 0 : return -1;
487 16 : os_memcpy(data, label, label_len);
488 16 : os_memcpy(data + label_len, id_s, id_s_len);
489 16 : os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
490 16 : if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
491 : data, data_len, buf, ke_len + ki_len) < 0) {
492 0 : os_free(data);
493 0 : return -1;
494 : }
495 :
496 16 : os_memcpy(sess->ke, buf, ke_len);
497 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
498 16 : os_memcpy(sess->ki, buf + ke_len, ki_len);
499 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
500 :
501 16 : os_free(data);
502 16 : return 0;
503 : }
504 :
505 :
506 12 : int eap_eke_derive_ka(struct eap_eke_session *sess,
507 : const u8 *id_s, size_t id_s_len,
508 : const u8 *id_p, size_t id_p_len,
509 : const u8 *nonce_p, const u8 *nonce_s)
510 : {
511 : u8 *data, *pos;
512 : size_t data_len;
513 12 : const char *label = "EAP-EKE Ka";
514 : size_t label_len;
515 :
516 : /*
517 : * Ka = prf+(SharedSecret, "EAP-EKE Ka" | ID_S | ID_P | Nonce_P |
518 : * Nonce_S)
519 : * Ka = authentication key
520 : * Length of the key depends on the selected algorithms.
521 : */
522 :
523 12 : label_len = os_strlen(label);
524 12 : data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
525 12 : data = os_malloc(data_len);
526 12 : if (data == NULL)
527 0 : return -1;
528 12 : pos = data;
529 12 : os_memcpy(pos, label, label_len);
530 12 : pos += label_len;
531 12 : os_memcpy(pos, id_s, id_s_len);
532 12 : pos += id_s_len;
533 12 : os_memcpy(pos, id_p, id_p_len);
534 12 : pos += id_p_len;
535 12 : os_memcpy(pos, nonce_p, sess->nonce_len);
536 12 : pos += sess->nonce_len;
537 12 : os_memcpy(pos, nonce_s, sess->nonce_len);
538 24 : if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
539 24 : data, data_len, sess->ka, sess->prf_len) < 0) {
540 0 : os_free(data);
541 0 : return -1;
542 : }
543 12 : os_free(data);
544 :
545 12 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
546 :
547 12 : return 0;
548 : }
549 :
550 :
551 12 : int eap_eke_derive_msk(struct eap_eke_session *sess,
552 : const u8 *id_s, size_t id_s_len,
553 : const u8 *id_p, size_t id_p_len,
554 : const u8 *nonce_p, const u8 *nonce_s,
555 : u8 *msk, u8 *emsk)
556 : {
557 : u8 *data, *pos;
558 : size_t data_len;
559 12 : const char *label = "EAP-EKE Exported Keys";
560 : size_t label_len;
561 : u8 buf[EAP_MSK_LEN + EAP_EMSK_LEN];
562 :
563 : /*
564 : * MSK | EMSK = prf+(SharedSecret, "EAP-EKE Exported Keys" | ID_S |
565 : * ID_P | Nonce_P | Nonce_S)
566 : */
567 :
568 12 : label_len = os_strlen(label);
569 12 : data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
570 12 : data = os_malloc(data_len);
571 12 : if (data == NULL)
572 0 : return -1;
573 12 : pos = data;
574 12 : os_memcpy(pos, label, label_len);
575 12 : pos += label_len;
576 12 : os_memcpy(pos, id_s, id_s_len);
577 12 : pos += id_s_len;
578 12 : os_memcpy(pos, id_p, id_p_len);
579 12 : pos += id_p_len;
580 12 : os_memcpy(pos, nonce_p, sess->nonce_len);
581 12 : pos += sess->nonce_len;
582 12 : os_memcpy(pos, nonce_s, sess->nonce_len);
583 12 : if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
584 : data, data_len, buf, EAP_MSK_LEN + EAP_EMSK_LEN) <
585 : 0) {
586 0 : os_free(data);
587 0 : return -1;
588 : }
589 12 : os_free(data);
590 :
591 12 : os_memcpy(msk, buf, EAP_MSK_LEN);
592 12 : os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
593 12 : os_memset(buf, 0, sizeof(buf));
594 :
595 12 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
596 12 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
597 :
598 12 : return 0;
599 : }
600 :
601 :
602 41 : static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
603 : u8 *res)
604 : {
605 41 : if (mac == EAP_EKE_MAC_HMAC_SHA1)
606 9 : return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
607 32 : if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
608 32 : return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
609 0 : return -1;
610 : }
611 :
612 :
613 21 : int eap_eke_prot(struct eap_eke_session *sess,
614 : const u8 *data, size_t data_len,
615 : u8 *prot, size_t *prot_len)
616 : {
617 : size_t block_size, icv_len, pad;
618 : u8 *pos, *iv, *e;
619 :
620 21 : if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
621 21 : block_size = AES_BLOCK_SIZE;
622 : else
623 0 : return -1;
624 :
625 21 : if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
626 5 : icv_len = SHA1_MAC_LEN;
627 16 : else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
628 16 : icv_len = SHA256_MAC_LEN;
629 : else
630 0 : return -1;
631 :
632 21 : pad = data_len % block_size;
633 21 : if (pad)
634 0 : pad = block_size - pad;
635 :
636 21 : if (*prot_len < block_size + data_len + pad + icv_len) {
637 0 : wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
638 : }
639 21 : pos = prot;
640 :
641 21 : if (random_get_bytes(pos, block_size))
642 0 : return -1;
643 21 : iv = pos;
644 21 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
645 21 : pos += block_size;
646 :
647 21 : e = pos;
648 21 : os_memcpy(pos, data, data_len);
649 21 : pos += data_len;
650 21 : if (pad) {
651 0 : if (random_get_bytes(pos, pad))
652 0 : return -1;
653 0 : pos += pad;
654 : }
655 :
656 21 : if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
657 0 : return -1;
658 :
659 21 : if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
660 0 : return -1;
661 21 : pos += icv_len;
662 :
663 21 : *prot_len = pos - prot;
664 21 : return 0;
665 : }
666 :
667 :
668 20 : int eap_eke_decrypt_prot(struct eap_eke_session *sess,
669 : const u8 *prot, size_t prot_len,
670 : u8 *data, size_t *data_len)
671 : {
672 : size_t block_size, icv_len;
673 : u8 icv[EAP_EKE_MAX_HASH_LEN];
674 :
675 20 : if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
676 20 : block_size = AES_BLOCK_SIZE;
677 : else
678 0 : return -1;
679 :
680 20 : if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
681 4 : icv_len = SHA1_MAC_LEN;
682 16 : else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
683 16 : icv_len = SHA256_MAC_LEN;
684 : else
685 0 : return -1;
686 :
687 20 : if (prot_len < 2 * block_size + icv_len)
688 0 : return -1;
689 20 : if ((prot_len - icv_len) % block_size)
690 0 : return -1;
691 :
692 20 : if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
693 20 : prot_len - block_size - icv_len, icv) < 0)
694 0 : return -1;
695 20 : if (os_memcmp_const(icv, prot + prot_len - icv_len, icv_len) != 0) {
696 2 : wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
697 2 : return -1;
698 : }
699 :
700 18 : if (*data_len < prot_len - block_size - icv_len) {
701 0 : wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data");
702 0 : return -1;
703 : }
704 :
705 18 : *data_len = prot_len - block_size - icv_len;
706 18 : os_memcpy(data, prot + block_size, *data_len);
707 18 : if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) {
708 0 : wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data");
709 0 : return -1;
710 : }
711 18 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
712 : data, *data_len);
713 :
714 18 : return 0;
715 : }
716 :
717 :
718 24 : int eap_eke_auth(struct eap_eke_session *sess, const char *label,
719 : const struct wpabuf *msgs, u8 *auth)
720 : {
721 24 : wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
722 48 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
723 48 : sess->ka, sess->auth_len);
724 24 : wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
725 48 : return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
726 : (const u8 *) label, os_strlen(label),
727 24 : wpabuf_head(msgs), wpabuf_len(msgs), auth);
728 : }
729 :
730 :
731 20 : int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
732 : u8 prf, u8 mac)
733 : {
734 20 : sess->dhgroup = dhgroup;
735 20 : sess->encr = encr;
736 20 : sess->prf = prf;
737 20 : sess->mac = mac;
738 :
739 20 : sess->prf_len = eap_eke_prf_len(prf);
740 20 : if (sess->prf_len < 0)
741 0 : return -1;
742 20 : sess->nonce_len = eap_eke_nonce_len(prf);
743 20 : if (sess->nonce_len < 0)
744 0 : return -1;
745 20 : sess->auth_len = eap_eke_auth_len(prf);
746 20 : if (sess->auth_len < 0)
747 0 : return -1;
748 20 : sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
749 20 : if (sess->dhcomp_len < 0)
750 0 : return -1;
751 20 : sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
752 20 : if (sess->pnonce_len < 0)
753 0 : return -1;
754 20 : sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
755 20 : if (sess->pnonce_ps_len < 0)
756 0 : return -1;
757 :
758 20 : return 0;
759 : }
760 :
761 :
762 56 : void eap_eke_session_clean(struct eap_eke_session *sess)
763 : {
764 56 : os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
765 56 : os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
766 56 : os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
767 56 : os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
768 56 : }
|