13c260e60Schristos /*
23c260e60Schristos * IEEE 802.1X-2010 Key Hierarchy
33c260e60Schristos * Copyright (c) 2013, Qualcomm Atheros, Inc.
43c260e60Schristos *
53c260e60Schristos * This software may be distributed under the terms of the BSD license.
63c260e60Schristos * See README for more details.
73c260e60Schristos *
83c260e60Schristos * SAK derivation specified in IEEE Std 802.1X-2010, Clause 6.2
93c260e60Schristos */
103c260e60Schristos
113c260e60Schristos #include "utils/includes.h"
123c260e60Schristos
133c260e60Schristos #include "utils/common.h"
143c260e60Schristos #include "crypto/md5.h"
153c260e60Schristos #include "crypto/sha1.h"
163c260e60Schristos #include "crypto/aes_wrap.h"
173c260e60Schristos #include "crypto/crypto.h"
183c260e60Schristos #include "ieee802_1x_key.h"
193c260e60Schristos
203c260e60Schristos
joint_two_mac(const u8 * mac1,const u8 * mac2,u8 * out)213c260e60Schristos static void joint_two_mac(const u8 *mac1, const u8 *mac2, u8 *out)
223c260e60Schristos {
233c260e60Schristos if (os_memcmp(mac1, mac2, ETH_ALEN) < 0) {
243c260e60Schristos os_memcpy(out, mac1, ETH_ALEN);
253c260e60Schristos os_memcpy(out + ETH_ALEN, mac2, ETH_ALEN);
263c260e60Schristos } else {
273c260e60Schristos os_memcpy(out, mac2, ETH_ALEN);
283c260e60Schristos os_memcpy(out + ETH_ALEN, mac1, ETH_ALEN);
293c260e60Schristos }
303c260e60Schristos }
313c260e60Schristos
323c260e60Schristos
333c260e60Schristos /* 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*3d6c0713Schristos static int aes_kdf(const u8 *kdk, size_t kdk_bits,
35*3d6c0713Schristos const char *label, const u8 *context,
363c260e60Schristos int ctx_bits, int ret_bits, u8 *ret)
373c260e60Schristos {
383c260e60Schristos const int h = 128;
393c260e60Schristos const int r = 8;
403c260e60Schristos int i, n;
413c260e60Schristos int lab_len, ctx_len, ret_len, buf_len;
423c260e60Schristos u8 *buf;
433c260e60Schristos
44*3d6c0713Schristos if (kdk_bits != 128 && kdk_bits != 256)
45*3d6c0713Schristos return -1;
46*3d6c0713Schristos
473c260e60Schristos lab_len = os_strlen(label);
483c260e60Schristos ctx_len = (ctx_bits + 7) / 8;
493c260e60Schristos ret_len = ((ret_bits & 0xffff) + 7) / 8;
503c260e60Schristos buf_len = lab_len + ctx_len + 4;
513c260e60Schristos
523c260e60Schristos os_memset(ret, 0, ret_len);
533c260e60Schristos
543c260e60Schristos n = (ret_bits + h - 1) / h;
553c260e60Schristos if (n > ((0x1 << r) - 1))
563c260e60Schristos return -1;
573c260e60Schristos
583c260e60Schristos buf = os_zalloc(buf_len);
593c260e60Schristos if (buf == NULL)
603c260e60Schristos return -1;
613c260e60Schristos
623c260e60Schristos os_memcpy(buf + 1, label, lab_len);
633c260e60Schristos os_memcpy(buf + lab_len + 2, context, ctx_len);
643c260e60Schristos WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
653c260e60Schristos
663c260e60Schristos for (i = 0; i < n; i++) {
67*3d6c0713Schristos int res;
68*3d6c0713Schristos
693c260e60Schristos buf[0] = (u8) (i + 1);
70*3d6c0713Schristos if (kdk_bits == 128)
71*3d6c0713Schristos res = omac1_aes_128(kdk, buf, buf_len, ret);
72*3d6c0713Schristos else
73*3d6c0713Schristos res = omac1_aes_256(kdk, buf, buf_len, ret);
74*3d6c0713Schristos if (res) {
753c260e60Schristos os_free(buf);
763c260e60Schristos return -1;
773c260e60Schristos }
783c260e60Schristos ret = ret + h / 8;
793c260e60Schristos }
803c260e60Schristos os_free(buf);
813c260e60Schristos return 0;
823c260e60Schristos }
833c260e60Schristos
843c260e60Schristos
853c260e60Schristos /**
86*3d6c0713Schristos * ieee802_1x_cak_aes_cmac
873c260e60Schristos *
883c260e60Schristos * IEEE Std 802.1X-2010, 6.2.2
893c260e60Schristos * CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
903c260e60Schristos */
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*3d6c0713Schristos int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
92*3d6c0713Schristos const u8 *mac2, u8 *cak, size_t cak_bytes)
933c260e60Schristos {
943c260e60Schristos u8 context[2 * ETH_ALEN];
953c260e60Schristos
963c260e60Schristos joint_two_mac(mac1, mac2, context);
97*3d6c0713Schristos return aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CAK",
98*3d6c0713Schristos context, sizeof(context) * 8, 8 * cak_bytes, cak);
993c260e60Schristos }
1003c260e60Schristos
1013c260e60Schristos
1023c260e60Schristos /**
103*3d6c0713Schristos * ieee802_1x_ckn_aes_cmac
1043c260e60Schristos *
1053c260e60Schristos * IEEE Std 802.1X-2010, 6.2.2
1063c260e60Schristos * CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
1073c260e60Schristos */
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*3d6c0713Schristos int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
1093c260e60Schristos const u8 *mac2, const u8 *sid,
1103c260e60Schristos size_t sid_bytes, u8 *ckn)
1113c260e60Schristos {
1123c260e60Schristos int res;
1133c260e60Schristos u8 *context;
1143c260e60Schristos size_t ctx_len = sid_bytes + ETH_ALEN * 2;
1153c260e60Schristos
1163c260e60Schristos context = os_zalloc(ctx_len);
1173c260e60Schristos if (!context) {
1183c260e60Schristos wpa_printf(MSG_ERROR, "MKA-%s: out of memory", __func__);
1193c260e60Schristos return -1;
1203c260e60Schristos }
1213c260e60Schristos os_memcpy(context, sid, sid_bytes);
1223c260e60Schristos joint_two_mac(mac1, mac2, context + sid_bytes);
1233c260e60Schristos
124*3d6c0713Schristos res = aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CKN",
125*3d6c0713Schristos context, ctx_len * 8, 128, ckn);
1263c260e60Schristos os_free(context);
1273c260e60Schristos return res;
1283c260e60Schristos }
1293c260e60Schristos
1303c260e60Schristos
1313c260e60Schristos /**
132*3d6c0713Schristos * ieee802_1x_kek_aes_cmac
1333c260e60Schristos *
1343c260e60Schristos * IEEE Std 802.1X-2010, 9.3.3
1353c260e60Schristos * KEK = KDF(Key, Label, Keyid, KEKLength)
1363c260e60Schristos */
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*3d6c0713Schristos int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
138*3d6c0713Schristos size_t ckn_bytes, u8 *kek, size_t kek_bytes)
1393c260e60Schristos {
1403c260e60Schristos u8 context[16];
1413c260e60Schristos
1423c260e60Schristos /* First 16 octets of CKN, with null octets appended to pad if needed */
1433c260e60Schristos os_memset(context, 0, sizeof(context));
1443c260e60Schristos os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
1453c260e60Schristos
146*3d6c0713Schristos return aes_kdf(cak, 8 * cak_bytes, "IEEE8021 KEK",
147*3d6c0713Schristos context, sizeof(context) * 8,
148*3d6c0713Schristos 8 * kek_bytes, kek);
1493c260e60Schristos }
1503c260e60Schristos
1513c260e60Schristos
1523c260e60Schristos /**
153*3d6c0713Schristos * ieee802_1x_ick_aes_cmac
1543c260e60Schristos *
1553c260e60Schristos * IEEE Std 802.1X-2010, 9.3.3
1563c260e60Schristos * ICK = KDF(Key, Label, Keyid, ICKLength)
1573c260e60Schristos */
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*3d6c0713Schristos int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
159*3d6c0713Schristos size_t ckn_bytes, u8 *ick, size_t ick_bytes)
1603c260e60Schristos {
1613c260e60Schristos u8 context[16];
1623c260e60Schristos
1633c260e60Schristos /* First 16 octets of CKN, with null octets appended to pad if needed */
1643c260e60Schristos os_memset(context, 0, sizeof(context));
1653c260e60Schristos os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
1663c260e60Schristos
167*3d6c0713Schristos return aes_kdf(cak, 8 *cak_bytes, "IEEE8021 ICK",
168*3d6c0713Schristos context, sizeof(context) * 8,
169*3d6c0713Schristos 8 * ick_bytes, ick);
1703c260e60Schristos }
1713c260e60Schristos
1723c260e60Schristos
1733c260e60Schristos /**
174*3d6c0713Schristos * ieee802_1x_icv_aes_cmac
1753c260e60Schristos *
1763c260e60Schristos * IEEE Std 802.1X-2010, 9.4.1
1773c260e60Schristos * ICV = AES-CMAC(ICK, M, 128)
1783c260e60Schristos */
ieee802_1x_icv_aes_cmac(const u8 * ick,size_t ick_bytes,const u8 * msg,size_t msg_bytes,u8 * icv)179*3d6c0713Schristos int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
1803c260e60Schristos size_t msg_bytes, u8 *icv)
1813c260e60Schristos {
182*3d6c0713Schristos int res;
183*3d6c0713Schristos
184*3d6c0713Schristos if (ick_bytes == 16)
185*3d6c0713Schristos res = omac1_aes_128(ick, msg, msg_bytes, icv);
186*3d6c0713Schristos else if (ick_bytes == 32)
187*3d6c0713Schristos res = omac1_aes_256(ick, msg, msg_bytes, icv);
188*3d6c0713Schristos else
189*3d6c0713Schristos return -1;
190*3d6c0713Schristos if (res) {
191*3d6c0713Schristos wpa_printf(MSG_ERROR,
192*3d6c0713Schristos "MKA: AES-CMAC failed for ICV calculation");
1933c260e60Schristos return -1;
1943c260e60Schristos }
1953c260e60Schristos return 0;
1963c260e60Schristos }
1973c260e60Schristos
1983c260e60Schristos
1993c260e60Schristos /**
200*3d6c0713Schristos * ieee802_1x_sak_aes_cmac
2013c260e60Schristos *
2023c260e60Schristos * IEEE Std 802.1X-2010, 9.8.1
2033c260e60Schristos * SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
2043c260e60Schristos */
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*3d6c0713Schristos int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
206*3d6c0713Schristos size_t ctx_bytes, u8 *sak, size_t sak_bytes)
2073c260e60Schristos {
208*3d6c0713Schristos return aes_kdf(cak, cak_bytes * 8, "IEEE8021 SAK", ctx, ctx_bytes * 8,
209*3d6c0713Schristos sak_bytes * 8, sak);
2103c260e60Schristos }
211