xref: /freebsd/contrib/wpa/src/pae/ieee802_1x_key.c (revision b00ab754)
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 }
190