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_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