xref: /dragonfly/contrib/wpa_supplicant/src/pae/ieee802_1x_key.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
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 
joint_two_mac(const u8 * mac1,const u8 * mac2,u8 * out)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 */
aes_kdf(const u8 * kdk,size_t kdk_bits,const char * label,const u8 * context,int ctx_bits,int ret_bits,u8 * ret)34 static int aes_kdf(const u8 *kdk, size_t kdk_bits,
35                        const char *label, const u8 *context,
36                        int ctx_bits, int ret_bits, u8 *ret)
37 {
38           const int h = 128;
39           const int r = 8;
40           int i, n;
41           int lab_len, ctx_len, ret_len, buf_len;
42           u8 *buf;
43 
44           if (kdk_bits != 128 && kdk_bits != 256)
45                     return -1;
46 
47           lab_len = os_strlen(label);
48           ctx_len = (ctx_bits + 7) / 8;
49           ret_len = ((ret_bits & 0xffff) + 7) / 8;
50           buf_len = lab_len + ctx_len + 4;
51 
52           os_memset(ret, 0, ret_len);
53 
54           n = (ret_bits + h - 1) / h;
55           if (n > ((0x1 << r) - 1))
56                     return -1;
57 
58           buf = os_zalloc(buf_len);
59           if (buf == NULL)
60                     return -1;
61 
62           os_memcpy(buf + 1, label, lab_len);
63           os_memcpy(buf + lab_len + 2, context, ctx_len);
64           WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
65 
66           for (i = 0; i < n; i++) {
67                     int res;
68 
69                     buf[0] = (u8) (i + 1);
70                     if (kdk_bits == 128)
71                               res = omac1_aes_128(kdk, buf, buf_len, ret);
72                     else
73                               res = omac1_aes_256(kdk, buf, buf_len, ret);
74                     if (res) {
75                               os_free(buf);
76                               return -1;
77                     }
78                     ret = ret + h / 8;
79           }
80           os_free(buf);
81           return 0;
82 }
83 
84 
85 /**
86  * ieee802_1x_cak_aes_cmac
87  *
88  * IEEE Std 802.1X-2010, 6.2.2
89  * CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
90  */
ieee802_1x_cak_aes_cmac(const u8 * msk,size_t msk_bytes,const u8 * mac1,const u8 * mac2,u8 * cak,size_t cak_bytes)91 int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
92                                   const u8 *mac2, u8 *cak, size_t cak_bytes)
93 {
94           u8 context[2 * ETH_ALEN];
95 
96           joint_two_mac(mac1, mac2, context);
97           return aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CAK",
98                            context, sizeof(context) * 8, 8 * cak_bytes, cak);
99 }
100 
101 
102 /**
103  * ieee802_1x_ckn_aes_cmac
104  *
105  * IEEE Std 802.1X-2010, 6.2.2
106  * CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
107  */
ieee802_1x_ckn_aes_cmac(const u8 * msk,size_t msk_bytes,const u8 * mac1,const u8 * mac2,const u8 * sid,size_t sid_bytes,u8 * ckn)108 int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
109                                   const u8 *mac2, const u8 *sid,
110                                   size_t sid_bytes, u8 *ckn)
111 {
112           int res;
113           u8 *context;
114           size_t ctx_len = sid_bytes + ETH_ALEN * 2;
115 
116           context = os_zalloc(ctx_len);
117           if (!context) {
118                     wpa_printf(MSG_ERROR, "MKA-%s: out of memory", __func__);
119                     return -1;
120           }
121           os_memcpy(context, sid, sid_bytes);
122           joint_two_mac(mac1, mac2, context + sid_bytes);
123 
124           res = aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CKN",
125                           context, ctx_len * 8, 128, ckn);
126           os_free(context);
127           return res;
128 }
129 
130 
131 /**
132  * ieee802_1x_kek_aes_cmac
133  *
134  * IEEE Std 802.1X-2010, 9.3.3
135  * KEK = KDF(Key, Label, Keyid, KEKLength)
136  */
ieee802_1x_kek_aes_cmac(const u8 * cak,size_t cak_bytes,const u8 * ckn,size_t ckn_bytes,u8 * kek,size_t kek_bytes)137 int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
138                                   size_t ckn_bytes, u8 *kek, size_t kek_bytes)
139 {
140           u8 context[16];
141 
142           /* First 16 octets of CKN, with null octets appended to pad if needed */
143           os_memset(context, 0, sizeof(context));
144           os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
145 
146           return aes_kdf(cak, 8 * cak_bytes, "IEEE8021 KEK",
147                            context, sizeof(context) * 8,
148                            8 * kek_bytes, kek);
149 }
150 
151 
152 /**
153  * ieee802_1x_ick_aes_cmac
154  *
155  * IEEE Std 802.1X-2010, 9.3.3
156  * ICK = KDF(Key, Label, Keyid, ICKLength)
157  */
ieee802_1x_ick_aes_cmac(const u8 * cak,size_t cak_bytes,const u8 * ckn,size_t ckn_bytes,u8 * ick,size_t ick_bytes)158 int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
159                                   size_t ckn_bytes, u8 *ick, size_t ick_bytes)
160 {
161           u8 context[16];
162 
163           /* First 16 octets of CKN, with null octets appended to pad if needed */
164           os_memset(context, 0, sizeof(context));
165           os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
166 
167           return aes_kdf(cak, 8 *cak_bytes, "IEEE8021 ICK",
168                            context, sizeof(context) * 8,
169                            8 * ick_bytes, ick);
170 }
171 
172 
173 /**
174  * ieee802_1x_icv_aes_cmac
175  *
176  * IEEE Std 802.1X-2010, 9.4.1
177  * ICV = AES-CMAC(ICK, M, 128)
178  */
ieee802_1x_icv_aes_cmac(const u8 * ick,size_t ick_bytes,const u8 * msg,size_t msg_bytes,u8 * icv)179 int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
180                                   size_t msg_bytes, u8 *icv)
181 {
182           int res;
183 
184           if (ick_bytes == 16)
185                     res = omac1_aes_128(ick, msg, msg_bytes, icv);
186           else if (ick_bytes == 32)
187                     res = omac1_aes_256(ick, msg, msg_bytes, icv);
188           else
189                     return -1;
190           if (res) {
191                     wpa_printf(MSG_ERROR,
192                                  "MKA: AES-CMAC failed for ICV calculation");
193                     return -1;
194           }
195           return 0;
196 }
197 
198 
199 /**
200  * ieee802_1x_sak_aes_cmac
201  *
202  * IEEE Std 802.1X-2010, 9.8.1
203  * SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
204  */
ieee802_1x_sak_aes_cmac(const u8 * cak,size_t cak_bytes,const u8 * ctx,size_t ctx_bytes,u8 * sak,size_t sak_bytes)205 int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
206                                   size_t ctx_bytes, u8 *sak, size_t sak_bytes)
207 {
208           return aes_kdf(cak, cak_bytes * 8, "IEEE8021 SAK", ctx, ctx_bytes * 8,
209                            sak_bytes * 8, sak);
210 }
211