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