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