1281681Srpaulo/*
2281681Srpaulo * IEEE 802.1X-2010 Key Hierarchy
3281681Srpaulo * Copyright (c) 2013, Qualcomm Atheros, Inc.
4281681Srpaulo *
5281681Srpaulo * This software may be distributed under the terms of the BSD license.
6281681Srpaulo * See README for more details.
7281681Srpaulo *
8281681Srpaulo * SAK derivation specified in IEEE Std 802.1X-2010, Clause 6.2
9281681Srpaulo*/
10281681Srpaulo
11281681Srpaulo#include "utils/includes.h"
12281681Srpaulo
13281681Srpaulo#include "utils/common.h"
14281681Srpaulo#include "crypto/md5.h"
15281681Srpaulo#include "crypto/sha1.h"
16281681Srpaulo#include "crypto/aes_wrap.h"
17281681Srpaulo#include "crypto/crypto.h"
18281681Srpaulo#include "ieee802_1x_key.h"
19281681Srpaulo
20281681Srpaulo
21281681Srpaulostatic void joint_two_mac(const u8 *mac1, const u8 *mac2, u8 *out)
22281681Srpaulo{
23281681Srpaulo	if (os_memcmp(mac1, mac2, ETH_ALEN) < 0) {
24281681Srpaulo		os_memcpy(out, mac1, ETH_ALEN);
25281681Srpaulo		os_memcpy(out + ETH_ALEN, mac2, ETH_ALEN);
26281681Srpaulo	} else {
27281681Srpaulo		os_memcpy(out, mac2, ETH_ALEN);
28281681Srpaulo		os_memcpy(out + ETH_ALEN, mac1, ETH_ALEN);
29281681Srpaulo	}
30281681Srpaulo}
31281681Srpaulo
32281681Srpaulo
33281681Srpaulo/* IEEE Std 802.1X-2010, 6.2.1 KDF */
34346981Scystatic int aes_kdf(const u8 *kdk, size_t kdk_bits,
35346981Scy		   const char *label, const u8 *context,
36346981Scy		   int ctx_bits, int ret_bits, u8 *ret)
37281681Srpaulo{
38281681Srpaulo	const int h = 128;
39281681Srpaulo	const int r = 8;
40281681Srpaulo	int i, n;
41281681Srpaulo	int lab_len, ctx_len, ret_len, buf_len;
42281681Srpaulo	u8 *buf;
43281681Srpaulo
44346981Scy	if (kdk_bits != 128 && kdk_bits != 256)
45346981Scy		return -1;
46346981Scy
47281681Srpaulo	lab_len = os_strlen(label);
48281681Srpaulo	ctx_len = (ctx_bits + 7) / 8;
49281681Srpaulo	ret_len = ((ret_bits & 0xffff) + 7) / 8;
50281681Srpaulo	buf_len = lab_len + ctx_len + 4;
51281681Srpaulo
52281681Srpaulo	os_memset(ret, 0, ret_len);
53281681Srpaulo
54281681Srpaulo	n = (ret_bits + h - 1) / h;
55281681Srpaulo	if (n > ((0x1 << r) - 1))
56281681Srpaulo		return -1;
57281681Srpaulo
58281681Srpaulo	buf = os_zalloc(buf_len);
59281681Srpaulo	if (buf == NULL)
60281681Srpaulo		return -1;
61281681Srpaulo
62281681Srpaulo	os_memcpy(buf + 1, label, lab_len);
63281681Srpaulo	os_memcpy(buf + lab_len + 2, context, ctx_len);
64281681Srpaulo	WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
65281681Srpaulo
66281681Srpaulo	for (i = 0; i < n; i++) {
67346981Scy		int res;
68346981Scy
69281681Srpaulo		buf[0] = (u8) (i + 1);
70346981Scy		if (kdk_bits == 128)
71346981Scy			res = omac1_aes_128(kdk, buf, buf_len, ret);
72346981Scy		else
73346981Scy			res = omac1_aes_256(kdk, buf, buf_len, ret);
74346981Scy		if (res) {
75281681Srpaulo			os_free(buf);
76281681Srpaulo			return -1;
77281681Srpaulo		}
78281681Srpaulo		ret = ret + h / 8;
79281681Srpaulo	}
80281681Srpaulo	os_free(buf);
81281681Srpaulo	return 0;
82281681Srpaulo}
83281681Srpaulo
84281681Srpaulo
85281681Srpaulo/**
86346981Scy * ieee802_1x_cak_aes_cmac
87281681Srpaulo *
88281681Srpaulo * IEEE Std 802.1X-2010, 6.2.2
89281681Srpaulo * CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
90281681Srpaulo */
91346981Scyint ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
92346981Scy			    const u8 *mac2, u8 *cak, size_t cak_bytes)
93281681Srpaulo{
94281681Srpaulo	u8 context[2 * ETH_ALEN];
95281681Srpaulo
96281681Srpaulo	joint_two_mac(mac1, mac2, context);
97346981Scy	return aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CAK",
98346981Scy		       context, sizeof(context) * 8, 8 * cak_bytes, cak);
99281681Srpaulo}
100281681Srpaulo
101281681Srpaulo
102281681Srpaulo/**
103346981Scy * ieee802_1x_ckn_aes_cmac
104281681Srpaulo *
105281681Srpaulo * IEEE Std 802.1X-2010, 6.2.2
106281681Srpaulo * CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
107281681Srpaulo */
108346981Scyint ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
109346981Scy			    const u8 *mac2, const u8 *sid,
110346981Scy			    size_t sid_bytes, u8 *ckn)
111281681Srpaulo{
112281681Srpaulo	int res;
113281681Srpaulo	u8 *context;
114281681Srpaulo	size_t ctx_len = sid_bytes + ETH_ALEN * 2;
115281681Srpaulo
116281681Srpaulo	context = os_zalloc(ctx_len);
117281681Srpaulo	if (!context) {
118281681Srpaulo		wpa_printf(MSG_ERROR, "MKA-%s: out of memory", __func__);
119281681Srpaulo		return -1;
120281681Srpaulo	}
121281681Srpaulo	os_memcpy(context, sid, sid_bytes);
122281681Srpaulo	joint_two_mac(mac1, mac2, context + sid_bytes);
123281681Srpaulo
124346981Scy	res = aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CKN",
125346981Scy		      context, ctx_len * 8, 128, ckn);
126281681Srpaulo	os_free(context);
127281681Srpaulo	return res;
128281681Srpaulo}
129281681Srpaulo
130281681Srpaulo
131281681Srpaulo/**
132346981Scy * ieee802_1x_kek_aes_cmac
133281681Srpaulo *
134281681Srpaulo * IEEE Std 802.1X-2010, 9.3.3
135281681Srpaulo * KEK = KDF(Key, Label, Keyid, KEKLength)
136281681Srpaulo */
137346981Scyint ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
138346981Scy			    size_t ckn_bytes, u8 *kek, size_t kek_bytes)
139281681Srpaulo{
140281681Srpaulo	u8 context[16];
141281681Srpaulo
142281681Srpaulo	/* First 16 octets of CKN, with null octets appended to pad if needed */
143281681Srpaulo	os_memset(context, 0, sizeof(context));
144281681Srpaulo	os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
145281681Srpaulo
146346981Scy	return aes_kdf(cak, 8 * cak_bytes, "IEEE8021 KEK",
147346981Scy		       context, sizeof(context) * 8,
148346981Scy		       8 * kek_bytes, kek);
149281681Srpaulo}
150281681Srpaulo
151281681Srpaulo
152281681Srpaulo/**
153346981Scy * ieee802_1x_ick_aes_cmac
154281681Srpaulo *
155281681Srpaulo * IEEE Std 802.1X-2010, 9.3.3
156281681Srpaulo * ICK = KDF(Key, Label, Keyid, ICKLength)
157281681Srpaulo */
158346981Scyint ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
159346981Scy			    size_t ckn_bytes, u8 *ick, size_t ick_bytes)
160281681Srpaulo{
161281681Srpaulo	u8 context[16];
162281681Srpaulo
163281681Srpaulo	/* First 16 octets of CKN, with null octets appended to pad if needed */
164281681Srpaulo	os_memset(context, 0, sizeof(context));
165281681Srpaulo	os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
166281681Srpaulo
167346981Scy	return aes_kdf(cak, 8 *cak_bytes, "IEEE8021 ICK",
168346981Scy		       context, sizeof(context) * 8,
169346981Scy		       8 * ick_bytes, ick);
170281681Srpaulo}
171281681Srpaulo
172281681Srpaulo
173281681Srpaulo/**
174346981Scy * ieee802_1x_icv_aes_cmac
175281681Srpaulo *
176281681Srpaulo * IEEE Std 802.1X-2010, 9.4.1
177281681Srpaulo * ICV = AES-CMAC(ICK, M, 128)
178281681Srpaulo */
179346981Scyint ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
180346981Scy			    size_t msg_bytes, u8 *icv)
181281681Srpaulo{
182346981Scy	int res;
183346981Scy
184346981Scy	if (ick_bytes == 16)
185346981Scy		res = omac1_aes_128(ick, msg, msg_bytes, icv);
186346981Scy	else if (ick_bytes == 32)
187346981Scy		res = omac1_aes_256(ick, msg, msg_bytes, icv);
188346981Scy	else
189281681Srpaulo		return -1;
190346981Scy	if (res) {
191346981Scy		wpa_printf(MSG_ERROR,
192346981Scy			   "MKA: AES-CMAC failed for ICV calculation");
193346981Scy		return -1;
194281681Srpaulo	}
195281681Srpaulo	return 0;
196281681Srpaulo}
197281681Srpaulo
198281681Srpaulo
199281681Srpaulo/**
200346981Scy * ieee802_1x_sak_aes_cmac
201281681Srpaulo *
202281681Srpaulo * IEEE Std 802.1X-2010, 9.8.1
203281681Srpaulo * SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
204281681Srpaulo */
205346981Scyint ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
206346981Scy			    size_t ctx_bytes, u8 *sak, size_t sak_bytes)
207281681Srpaulo{
208346981Scy	return aes_kdf(cak, cak_bytes * 8, "IEEE8021 SAK", ctx, ctx_bytes * 8,
209346981Scy		       sak_bytes * 8, sak);
210281681Srpaulo}
211