Branch data 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 : 14 : static int eap_eke_dh_len(u8 group)
24 : : {
25 [ - - + + : 14 : switch (group) {
+ - ]
26 : : case EAP_EKE_DHGROUP_EKE_2:
27 : 0 : return 128;
28 : : case EAP_EKE_DHGROUP_EKE_5:
29 : 0 : return 192;
30 : : case EAP_EKE_DHGROUP_EKE_14:
31 : 4 : return 256;
32 : : case EAP_EKE_DHGROUP_EKE_15:
33 : 2 : return 384;
34 : : case EAP_EKE_DHGROUP_EKE_16:
35 : 8 : return 512;
36 : : }
37 : :
38 : 14 : return -1;
39 : : }
40 : :
41 : :
42 : 7 : static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
43 : : {
44 : : int dhlen;
45 : :
46 : 7 : dhlen = eap_eke_dh_len(dhgroup);
47 [ - + ]: 7 : if (dhlen < 0)
48 : 0 : return -1;
49 [ - + ]: 7 : if (encr != EAP_EKE_ENCR_AES128_CBC)
50 : 0 : return -1;
51 : 7 : return AES_BLOCK_SIZE + dhlen;
52 : : }
53 : :
54 : :
55 : 14 : static const struct dh_group * eap_eke_dh_group(u8 group)
56 : : {
57 [ - - + + : 14 : switch (group) {
+ - ]
58 : : case EAP_EKE_DHGROUP_EKE_2:
59 : 0 : 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 : 4 : return dh_groups_get(14);
64 : : case EAP_EKE_DHGROUP_EKE_15:
65 : 2 : return dh_groups_get(15);
66 : : case EAP_EKE_DHGROUP_EKE_16:
67 : 8 : return dh_groups_get(16);
68 : : }
69 : :
70 : 14 : return NULL;
71 : : }
72 : :
73 : :
74 : 7 : static int eap_eke_dh_generator(u8 group)
75 : : {
76 [ - - + + : 7 : switch (group) {
+ - ]
77 : : case EAP_EKE_DHGROUP_EKE_2:
78 : 0 : return 5;
79 : : case EAP_EKE_DHGROUP_EKE_5:
80 : 0 : return 31;
81 : : case EAP_EKE_DHGROUP_EKE_14:
82 : 2 : return 11;
83 : : case EAP_EKE_DHGROUP_EKE_15:
84 : 1 : return 5;
85 : : case EAP_EKE_DHGROUP_EKE_16:
86 : 4 : return 5;
87 : : }
88 : :
89 : 7 : return -1;
90 : : }
91 : :
92 : :
93 : 7 : static int eap_eke_pnonce_len(u8 mac)
94 : : {
95 : : int mac_len;
96 : :
97 [ + + ]: 7 : if (mac == EAP_EKE_MAC_HMAC_SHA1)
98 : 1 : mac_len = SHA1_MAC_LEN;
99 [ + - ]: 6 : else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
100 : 6 : mac_len = SHA256_MAC_LEN;
101 : : else
102 : 0 : return -1;
103 : :
104 : 7 : return AES_BLOCK_SIZE + 16 + mac_len;
105 : : }
106 : :
107 : :
108 : 7 : static int eap_eke_pnonce_ps_len(u8 mac)
109 : : {
110 : : int mac_len;
111 : :
112 [ + + ]: 7 : if (mac == EAP_EKE_MAC_HMAC_SHA1)
113 : 1 : mac_len = SHA1_MAC_LEN;
114 [ + - ]: 6 : else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
115 : 6 : mac_len = SHA256_MAC_LEN;
116 : : else
117 : 0 : return -1;
118 : :
119 : 7 : return AES_BLOCK_SIZE + 2 * 16 + mac_len;
120 : : }
121 : :
122 : :
123 : 14 : static int eap_eke_prf_len(u8 prf)
124 : : {
125 [ + + ]: 14 : if (prf == EAP_EKE_PRF_HMAC_SHA1)
126 : 2 : return 20;
127 [ + - ]: 12 : if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
128 : 12 : return 32;
129 : 14 : return -1;
130 : : }
131 : :
132 : :
133 : 7 : static int eap_eke_nonce_len(u8 prf)
134 : : {
135 : : int prf_len;
136 : :
137 : 7 : prf_len = eap_eke_prf_len(prf);
138 [ - + ]: 7 : if (prf_len < 0)
139 : 0 : return -1;
140 : :
141 [ - + ]: 7 : if (prf_len > 2 * 16)
142 : 0 : return (prf_len + 1) / 2;
143 : :
144 : 7 : return 16;
145 : : }
146 : :
147 : :
148 : 7 : static int eap_eke_auth_len(u8 prf)
149 : : {
150 [ + + - ]: 7 : switch (prf) {
151 : : case EAP_EKE_PRF_HMAC_SHA1:
152 : 1 : return SHA1_MAC_LEN;
153 : : case EAP_EKE_PRF_HMAC_SHA2_256:
154 : 6 : return SHA256_MAC_LEN;
155 : : }
156 : :
157 : 7 : return -1;
158 : : }
159 : :
160 : :
161 : 7 : 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 : 7 : generator = eap_eke_dh_generator(group);
169 [ + - ][ - + ]: 7 : if (generator < 0 || generator > 255)
170 : 0 : return -1;
171 : 7 : gen = generator;
172 : :
173 : 7 : dh = eap_eke_dh_group(group);
174 [ - + ]: 7 : if (dh == NULL)
175 : 0 : return -1;
176 : :
177 : : /* x = random number 2 .. p-1 */
178 [ - + ]: 7 : if (random_get_bytes(ret_priv, dh->prime_len))
179 : 0 : return -1;
180 [ - + ]: 7 : 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 [ + - ]: 7 : for (i = 0; i < dh->prime_len - 1; i++) {
185 [ + - ]: 7 : if (ret_priv[i])
186 : 7 : break;
187 : : }
188 [ - + ][ # # ]: 7 : if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
[ # # ]
189 : 0 : return -1;
190 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
191 : : ret_priv, dh->prime_len);
192 : :
193 : : /* y = g ^ x (mod p) */
194 : 7 : pub_len = dh->prime_len;
195 [ - + ]: 7 : 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 [ - + ]: 7 : 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 : 7 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
205 : : ret_pub, dh->prime_len);
206 : :
207 : 7 : return 0;
208 : : }
209 : :
210 : :
211 : 28 : 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 : 28 : size_t num_elem = 1;
218 : :
219 : 28 : addr[0] = data;
220 : 28 : len[0] = data_len;
221 [ + + ]: 28 : if (data2) {
222 : 14 : num_elem++;
223 : 14 : addr[1] = data2;
224 : 14 : len[1] = data2_len;
225 : : }
226 : :
227 [ + + ]: 28 : if (prf == EAP_EKE_PRF_HMAC_SHA1)
228 : 4 : return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
229 [ + - ]: 24 : if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
230 : 24 : return hmac_sha256_vector(key, key_len, num_elem, addr, len,
231 : : res);
232 : 28 : return -1;
233 : : }
234 : :
235 : :
236 : 4 : 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 : 4 : idx = 0;
246 : 4 : addr[0] = hash;
247 : 4 : vlen[0] = SHA1_MAC_LEN;
248 : 4 : addr[1] = data;
249 : 4 : vlen[1] = data_len;
250 : 4 : addr[2] = &idx;
251 : 4 : vlen[2] = 1;
252 : :
253 [ + + ]: 15 : while (len > 0) {
254 : 11 : idx++;
255 [ + + ]: 11 : if (idx == 1)
256 : 4 : ret = hmac_sha1_vector(key, key_len, 2, &addr[1],
257 : : &vlen[1], hash);
258 : : else
259 : 7 : ret = hmac_sha1_vector(key, key_len, 3, addr, vlen,
260 : : hash);
261 [ - + ]: 11 : if (ret < 0)
262 : 0 : return -1;
263 [ + + ]: 11 : if (len > SHA1_MAC_LEN) {
264 : 7 : os_memcpy(res, hash, SHA1_MAC_LEN);
265 : 7 : res += SHA1_MAC_LEN;
266 : 7 : len -= SHA1_MAC_LEN;
267 : : } else {
268 : 4 : os_memcpy(res, hash, len);
269 : 4 : len = 0;
270 : : }
271 : : }
272 : :
273 : 4 : return 0;
274 : : }
275 : :
276 : :
277 : 24 : 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 : 24 : idx = 0;
287 : 24 : addr[0] = hash;
288 : 24 : vlen[0] = SHA256_MAC_LEN;
289 : 24 : addr[1] = data;
290 : 24 : vlen[1] = data_len;
291 : 24 : addr[2] = &idx;
292 : 24 : vlen[2] = 1;
293 : :
294 [ + + ]: 72 : while (len > 0) {
295 : 48 : idx++;
296 [ + + ]: 48 : if (idx == 1)
297 : 24 : ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
298 : : &vlen[1], hash);
299 : : else
300 : 24 : ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
301 : : hash);
302 [ - + ]: 48 : if (ret < 0)
303 : 0 : return -1;
304 [ + + ]: 48 : if (len > SHA256_MAC_LEN) {
305 : 24 : os_memcpy(res, hash, SHA256_MAC_LEN);
306 : 24 : res += SHA256_MAC_LEN;
307 : 24 : len -= SHA256_MAC_LEN;
308 : : } else {
309 : 24 : os_memcpy(res, hash, len);
310 : 24 : len = 0;
311 : : }
312 : : }
313 : :
314 : 24 : return 0;
315 : : }
316 : :
317 : :
318 : 28 : 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 [ + + ]: 28 : if (prf == EAP_EKE_PRF_HMAC_SHA1)
322 : 4 : return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res,
323 : : len);
324 [ + - ]: 24 : if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
325 : 24 : return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
326 : : res, len);
327 : 28 : return -1;
328 : : }
329 : :
330 : :
331 : 7 : 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 : 7 : size_t key_len = 16; /* Only AES-128-CBC is used here */
339 : : u8 *id;
340 : :
341 : : /* temp = prf(0+, password) */
342 : 7 : os_memset(zeros, 0, sess->prf_len);
343 [ - + ]: 7 : if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
344 : : password, password_len, NULL, 0, temp) < 0)
345 : 0 : return -1;
346 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
347 : 7 : temp, sess->prf_len);
348 : :
349 : : /* key = prf+(temp, ID_S | ID_P) */
350 : 7 : id = os_malloc(id_s_len + id_p_len);
351 [ - + ]: 7 : if (id == NULL)
352 : 0 : return -1;
353 : 7 : os_memcpy(id, id_s, id_s_len);
354 : 7 : os_memcpy(id + id_s_len, id_p, id_p_len);
355 : 7 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
356 : : id, id_s_len + id_p_len);
357 [ - + ]: 7 : 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 : 7 : os_free(id);
363 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
364 : : key, key_len);
365 : :
366 : 7 : return 0;
367 : : }
368 : :
369 : :
370 : 7 : 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 : 7 : dh_len = eap_eke_dh_len(sess->dhgroup);
378 [ - + ]: 7 : 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 [ - + ]: 7 : if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
388 : 0 : return -1;
389 [ - + ]: 7 : if (random_get_bytes(iv, AES_BLOCK_SIZE))
390 : 0 : return -1;
391 : 7 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
392 : : iv, AES_BLOCK_SIZE);
393 : 7 : os_memcpy(pub, dhpub, dh_len);
394 [ - + ]: 7 : if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
395 : 0 : return -1;
396 : 7 : os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
397 : 7 : os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
398 : 7 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
399 : 7 : ret_dhcomp, AES_BLOCK_SIZE + dh_len);
400 : :
401 : 7 : return 0;
402 : : }
403 : :
404 : :
405 : 7 : 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 [ - + ]: 7 : if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
415 : 0 : return -1;
416 : :
417 : 7 : dh = eap_eke_dh_group(sess->dhgroup);
418 [ - + ]: 7 : if (dh == NULL)
419 : 0 : return -1;
420 : :
421 : : /* Decrypt peer DHComponent */
422 : 7 : os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
423 [ - + ]: 7 : 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 : 7 : 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 : 7 : len = dh->prime_len;
432 [ - + ]: 7 : 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 [ - + ]: 7 : 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 : 7 : os_memset(zeros, 0, sess->auth_len);
442 [ - + ]: 7 : if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
443 : 7 : NULL, 0, sess->shared_secret) < 0)
444 : 0 : return -1;
445 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
446 : 14 : sess->shared_secret, sess->auth_len);
447 : :
448 : 7 : return 0;
449 : : }
450 : :
451 : :
452 : 7 : 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 : 7 : 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 [ + - ]: 7 : if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
471 : 7 : ke_len = 16;
472 : : else
473 : 0 : return -1;
474 : :
475 [ + + ]: 7 : if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
476 : 1 : ki_len = 20;
477 [ + - ]: 6 : else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
478 : 6 : ki_len = 32;
479 : : else
480 : 0 : return -1;
481 : :
482 : 7 : label_len = os_strlen(label);
483 : 7 : data_len = label_len + id_s_len + id_p_len;
484 : 7 : data = os_malloc(data_len);
485 [ - + ]: 7 : if (data == NULL)
486 : 0 : return -1;
487 : 7 : os_memcpy(data, label, label_len);
488 : 7 : os_memcpy(data + label_len, id_s, id_s_len);
489 : 7 : os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
490 [ - + ]: 7 : 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 : 7 : os_memcpy(sess->ke, buf, ke_len);
497 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
498 : 7 : os_memcpy(sess->ki, buf + ke_len, ki_len);
499 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
500 : :
501 : 7 : os_free(data);
502 : 7 : return 0;
503 : : }
504 : :
505 : :
506 : 7 : 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 : 7 : 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 : 7 : label_len = os_strlen(label);
524 : 7 : data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
525 : 7 : data = os_malloc(data_len);
526 [ - + ]: 7 : if (data == NULL)
527 : 0 : return -1;
528 : 7 : pos = data;
529 : 7 : os_memcpy(pos, label, label_len);
530 : 7 : pos += label_len;
531 : 7 : os_memcpy(pos, id_s, id_s_len);
532 : 7 : pos += id_s_len;
533 : 7 : os_memcpy(pos, id_p, id_p_len);
534 : 7 : pos += id_p_len;
535 : 7 : os_memcpy(pos, nonce_p, sess->nonce_len);
536 : 7 : pos += sess->nonce_len;
537 : 7 : os_memcpy(pos, nonce_s, sess->nonce_len);
538 [ - + ]: 7 : if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
539 : 14 : data, data_len, sess->ka, sess->prf_len) < 0) {
540 : 0 : os_free(data);
541 : 0 : return -1;
542 : : }
543 : 7 : os_free(data);
544 : :
545 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
546 : :
547 : 7 : return 0;
548 : : }
549 : :
550 : :
551 : 7 : 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 : 7 : 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 : 7 : label_len = os_strlen(label);
569 : 7 : data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
570 : 7 : data = os_malloc(data_len);
571 [ - + ]: 7 : if (data == NULL)
572 : 0 : return -1;
573 : 7 : pos = data;
574 : 7 : os_memcpy(pos, label, label_len);
575 : 7 : pos += label_len;
576 : 7 : os_memcpy(pos, id_s, id_s_len);
577 : 7 : pos += id_s_len;
578 : 7 : os_memcpy(pos, id_p, id_p_len);
579 : 7 : pos += id_p_len;
580 : 7 : os_memcpy(pos, nonce_p, sess->nonce_len);
581 : 7 : pos += sess->nonce_len;
582 : 7 : os_memcpy(pos, nonce_s, sess->nonce_len);
583 [ - + ]: 7 : 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 : 7 : os_free(data);
590 : :
591 : 7 : os_memcpy(msk, buf, EAP_MSK_LEN);
592 : 7 : os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
593 : 7 : os_memset(buf, 0, sizeof(buf));
594 : :
595 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
596 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
597 : :
598 : 7 : return 0;
599 : : }
600 : :
601 : :
602 : 21 : static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
603 : : u8 *res)
604 : : {
605 [ + + ]: 21 : if (mac == EAP_EKE_MAC_HMAC_SHA1)
606 : 3 : return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
607 [ + - ]: 18 : if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
608 : 18 : return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
609 : 21 : return -1;
610 : : }
611 : :
612 : :
613 : 14 : 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 [ + - ]: 14 : if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
621 : 14 : block_size = AES_BLOCK_SIZE;
622 : : else
623 : 0 : return -1;
624 : :
625 [ + + ]: 14 : if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
626 : 2 : icv_len = SHA1_MAC_LEN;
627 [ + - ]: 12 : else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
628 : 12 : icv_len = SHA256_MAC_LEN;
629 : : else
630 : 0 : return -1;
631 : :
632 : 14 : pad = data_len % block_size;
633 [ - + ]: 14 : if (pad)
634 : 0 : pad = block_size - pad;
635 : :
636 [ - + ]: 14 : 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 : 14 : pos = prot;
640 : :
641 [ - + ]: 14 : if (random_get_bytes(pos, block_size))
642 : 0 : return -1;
643 : 14 : iv = pos;
644 : 14 : wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
645 : 14 : pos += block_size;
646 : :
647 : 14 : e = pos;
648 : 14 : os_memcpy(pos, data, data_len);
649 : 14 : pos += data_len;
650 [ - + ]: 14 : if (pad) {
651 [ # # ]: 0 : if (random_get_bytes(pos, pad))
652 : 0 : return -1;
653 : 0 : pos += pad;
654 : : }
655 : :
656 [ - + ]: 14 : if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
657 : 0 : return -1;
658 : :
659 [ - + ]: 14 : if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
660 : 0 : return -1;
661 : 14 : pos += icv_len;
662 : :
663 : 14 : *prot_len = pos - prot;
664 : 14 : return 0;
665 : : }
666 : :
667 : :
668 : 7 : 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 [ + - ]: 7 : if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
676 : 7 : block_size = AES_BLOCK_SIZE;
677 : : else
678 : 0 : return -1;
679 : :
680 [ + + ]: 7 : if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
681 : 1 : icv_len = SHA1_MAC_LEN;
682 [ + - ]: 6 : else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
683 : 6 : icv_len = SHA256_MAC_LEN;
684 : : else
685 : 0 : return -1;
686 : :
687 [ - + ]: 7 : if (prot_len < 2 * block_size + icv_len)
688 : 0 : return -1;
689 [ - + ]: 7 : if ((prot_len - icv_len) % block_size)
690 : 0 : return -1;
691 : :
692 [ - + ]: 7 : if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
693 : 7 : prot_len - block_size - icv_len, icv) < 0)
694 : 0 : return -1;
695 [ - + ]: 7 : if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) {
696 : 0 : wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
697 : 0 : return -1;
698 : : }
699 : :
700 [ - + ]: 7 : 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 : 7 : *data_len = prot_len - block_size - icv_len;
706 : 7 : os_memcpy(data, prot + block_size, *data_len);
707 [ - + ]: 7 : 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 : 7 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
712 : : data, *data_len);
713 : :
714 : 7 : return 0;
715 : : }
716 : :
717 : :
718 : 14 : int eap_eke_auth(struct eap_eke_session *sess, const char *label,
719 : : const struct wpabuf *msgs, u8 *auth)
720 : : {
721 : 14 : wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
722 : 14 : wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
723 : 28 : sess->ka, sess->auth_len);
724 : 14 : wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
725 : 28 : return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
726 : : (const u8 *) label, os_strlen(label),
727 : 14 : wpabuf_head(msgs), wpabuf_len(msgs), auth);
728 : : }
729 : :
730 : :
731 : 7 : int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
732 : : u8 prf, u8 mac)
733 : : {
734 : 7 : sess->dhgroup = dhgroup;
735 : 7 : sess->encr = encr;
736 : 7 : sess->prf = prf;
737 : 7 : sess->mac = mac;
738 : :
739 : 7 : sess->prf_len = eap_eke_prf_len(prf);
740 [ - + ]: 7 : if (sess->prf_len < 0)
741 : 0 : return -1;
742 : 7 : sess->nonce_len = eap_eke_nonce_len(prf);
743 [ - + ]: 7 : if (sess->nonce_len < 0)
744 : 0 : return -1;
745 : 7 : sess->auth_len = eap_eke_auth_len(prf);
746 [ - + ]: 7 : if (sess->auth_len < 0)
747 : 0 : return -1;
748 : 7 : sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
749 [ - + ]: 7 : if (sess->dhcomp_len < 0)
750 : 0 : return -1;
751 : 7 : sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
752 [ - + ]: 7 : if (sess->pnonce_len < 0)
753 : 0 : return -1;
754 : 7 : sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
755 [ - + ]: 7 : if (sess->pnonce_ps_len < 0)
756 : 0 : return -1;
757 : :
758 : 7 : return 0;
759 : : }
760 : :
761 : :
762 : 16 : void eap_eke_session_clean(struct eap_eke_session *sess)
763 : : {
764 : 16 : os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
765 : 16 : os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
766 : 16 : os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
767 : 16 : os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
768 : 16 : }
|