Home | History | Annotate | Download | only in pae
      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(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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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