Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / pae / ieee802_1x_key.c
1 /*
2  * IEEE 802.1X-2010 Key Hierarchy
3  * Copyright (c) 2013, Qualcomm Atheros, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  *
8  * SAK derivation specified in IEEE Std 802.1X-2010, Clause 6.2
9 */
10
11 #include "utils/includes.h"
12
13 #include "utils/common.h"
14 #include "crypto/md5.h"
15 #include "crypto/sha1.h"
16 #include "crypto/aes_wrap.h"
17 #include "crypto/crypto.h"
18 #include "ieee802_1x_key.h"
19
20
21 static void joint_two_mac(const u8 *mac1, const u8 *mac2, u8 *out)
22 {
23         if (os_memcmp(mac1, mac2, ETH_ALEN) < 0) {
24                 os_memcpy(out, mac1, ETH_ALEN);
25                 os_memcpy(out + ETH_ALEN, mac2, ETH_ALEN);
26         } else {
27                 os_memcpy(out, mac2, ETH_ALEN);
28                 os_memcpy(out + ETH_ALEN, mac1, ETH_ALEN);
29         }
30 }
31
32
33 /* IEEE Std 802.1X-2010, 6.2.1 KDF */
34 static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
35                        int ctx_bits, int ret_bits, u8 *ret)
36 {
37         const int h = 128;
38         const int r = 8;
39         int i, n;
40         int lab_len, ctx_len, ret_len, buf_len;
41         u8 *buf;
42
43         lab_len = os_strlen(label);
44         ctx_len = (ctx_bits + 7) / 8;
45         ret_len = ((ret_bits & 0xffff) + 7) / 8;
46         buf_len = lab_len + ctx_len + 4;
47
48         os_memset(ret, 0, ret_len);
49
50         n = (ret_bits + h - 1) / h;
51         if (n > ((0x1 << r) - 1))
52                 return -1;
53
54         buf = os_zalloc(buf_len);
55         if (buf == NULL)
56                 return -1;
57
58         os_memcpy(buf + 1, label, lab_len);
59         os_memcpy(buf + lab_len + 2, context, ctx_len);
60         WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
61
62         for (i = 0; i < n; i++) {
63                 buf[0] = (u8) (i + 1);
64                 if (omac1_aes_128(kdk, buf, buf_len, ret)) {
65                         os_free(buf);
66                         return -1;
67                 }
68                 ret = ret + h / 8;
69         }
70         os_free(buf);
71         return 0;
72 }
73
74
75 /********** AES-CMAC-128 **********/
76 /**
77  * ieee802_1x_cak_128bits_aes_cmac
78  *
79  * IEEE Std 802.1X-2010, 6.2.2
80  * CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
81  */
82 int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
83                                     const u8 *mac2, u8 *cak)
84 {
85         u8 context[2 * ETH_ALEN];
86
87         joint_two_mac(mac1, mac2, context);
88         return aes_kdf_128(msk, "IEEE8021 EAP CAK",
89                            context, sizeof(context) * 8, 128, cak);
90 }
91
92
93 /**
94  * ieee802_1x_ckn_128bits_aes_cmac
95  *
96  * IEEE Std 802.1X-2010, 6.2.2
97  * CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
98  */
99 int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
100                                     const u8 *mac2, const u8 *sid,
101                                     size_t sid_bytes, u8 *ckn)
102 {
103         int res;
104         u8 *context;
105         size_t ctx_len = sid_bytes + ETH_ALEN * 2;
106
107         context = os_zalloc(ctx_len);
108         if (!context) {
109                 wpa_printf(MSG_ERROR, "MKA-%s: out of memory", __func__);
110                 return -1;
111         }
112         os_memcpy(context, sid, sid_bytes);
113         joint_two_mac(mac1, mac2, context + sid_bytes);
114
115         res = aes_kdf_128(msk, "IEEE8021 EAP CKN", context, ctx_len * 8,
116                           128, ckn);
117         os_free(context);
118         return res;
119 }
120
121
122 /**
123  * ieee802_1x_kek_128bits_aes_cmac
124  *
125  * IEEE Std 802.1X-2010, 9.3.3
126  * KEK = KDF(Key, Label, Keyid, KEKLength)
127  */
128 int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
129                                     size_t ckn_bytes, u8 *kek)
130 {
131         u8 context[16];
132
133         /* First 16 octets of CKN, with null octets appended to pad if needed */
134         os_memset(context, 0, sizeof(context));
135         os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
136
137         return aes_kdf_128(cak, "IEEE8021 KEK", context, sizeof(context) * 8,
138                            128, kek);
139 }
140
141
142 /**
143  * ieee802_1x_ick_128bits_aes_cmac
144  *
145  * IEEE Std 802.1X-2010, 9.3.3
146  * ICK = KDF(Key, Label, Keyid, ICKLength)
147  */
148 int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
149                                     size_t ckn_bytes, u8 *ick)
150 {
151         u8 context[16];
152
153         /* First 16 octets of CKN, with null octets appended to pad if needed */
154         os_memset(context, 0, sizeof(context));
155         os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
156
157         return aes_kdf_128(cak, "IEEE8021 ICK", context, sizeof(context) * 8,
158                            128, ick);
159 }
160
161
162 /**
163  * ieee802_1x_icv_128bits_aes_cmac
164  *
165  * IEEE Std 802.1X-2010, 9.4.1
166  * ICV = AES-CMAC(ICK, M, 128)
167  */
168 int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
169                                     size_t msg_bytes, u8 *icv)
170 {
171         if (omac1_aes_128(ick, msg, msg_bytes, icv)) {
172                 wpa_printf(MSG_ERROR, "MKA: omac1_aes_128 failed");
173                 return -1;
174         }
175         return 0;
176 }
177
178
179 /**
180  * ieee802_1x_sak_128bits_aes_cmac
181  *
182  * IEEE Std 802.1X-2010, 9.8.1
183  * SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
184  */
185 int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
186                                     size_t ctx_bytes, u8 *sak)
187 {
188         return aes_kdf_128(cak, "IEEE8021 SAK", ctx, ctx_bytes * 8, 128, sak);
189 }