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