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
21static 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 */
34static 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 */
91int 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 */
108int 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 */
137int 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 */
158int 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 */
179int 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 */
205int 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