18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP server/peer: EAP-GPSK shared routines 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha256.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_defs.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_gpsk_common.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: CSuite/Vendor 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @specifier: CSuite/Specifier 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 if ciphersuite is support, or 0 if not 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_gpsk_supported_ciphersuite(int vendor, int specifier) 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vendor == EAP_GPSK_VENDOR_IETF && 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt specifier == EAP_GPSK_CIPHER_AES) 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef EAP_GPSK_SHA256 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vendor == EAP_GPSK_VENDOR_IETF && 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt specifier == EAP_GPSK_CIPHER_SHA256) 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */, 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data /* Z */, size_t data_len, 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf, size_t len /* X */) 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *opos; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, n, hashlen, left, clen; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 ibuf[2], hash[16]; 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t vlen[2]; 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hashlen = sizeof(hash); 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */ 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = ibuf; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vlen[0] = sizeof(ibuf); 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = data; 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vlen[1] = data_len; 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt opos = buf; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = len; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt n = (len + hashlen - 1) / hashlen; 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 1; i <= n; i++) { 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(ibuf, i); 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (omac1_aes_128_vector(psk, 2, addr, vlen, hash)) 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt clen = left > hashlen ? hashlen : left; 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(opos, hash, clen); 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt opos += clen; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= clen; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef EAP_GPSK_SHA256 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data /* Z */, size_t data_len, 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf, size_t len /* X */) 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *opos; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, n, hashlen, left, clen; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 ibuf[2], hash[SHA256_MAC_LEN]; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t vlen[2]; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hashlen = SHA256_MAC_LEN; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */ 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = ibuf; 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vlen[0] = sizeof(ibuf); 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = data; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vlen[1] = data_len; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt opos = buf; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = len; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt n = (len + hashlen - 1) / hashlen; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 1; i <= n; i++) { 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(ibuf, i); 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_sha256_vector(psk, 32, 2, addr, vlen, hash); 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt clen = left > hashlen ? hashlen : left; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(opos, hash, clen); 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt opos += clen; 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= clen; 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_gpsk_derive_keys_helper(u32 csuite_specifier, 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *kdf_out, size_t kdf_out_len, 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *psk, size_t psk_len, 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *seed, size_t seed_len, 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *msk, u8 *emsk, 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *sk, size_t sk_len, 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pk, size_t pk_len) 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 mk[32], *pos, *data; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t data_len, mk_len; 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len, 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf, size_t len); 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt gkdf = NULL; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (csuite_specifier) { 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_AES: 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt gkdf = eap_gpsk_gkdf_cmac; 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mk_len = 16; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef EAP_GPSK_SHA256 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_SHA256: 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt gkdf = eap_gpsk_gkdf_sha256; 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mk_len = SHA256_MAC_LEN; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (psk_len < mk_len) 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data_len = 2 + psk_len + 6 + seed_len; 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_malloc(data_len); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = data; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, psk_len); 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, psk, psk_len); 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += psk_len; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */ 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */ 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, seed, seed_len); /* inputString */ 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation", 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data, data_len); 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (gkdf(psk, data, data_len, mk, mk_len) < 0) { 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len); 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0) 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = kdf_out; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN); 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msk, pos, EAP_MSK_LEN); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += EAP_MSK_LEN; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN); 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(emsk, pos, EAP_EMSK_LEN); 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += EAP_EMSK_LEN; 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, sk_len); 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(sk, pos, sk_len); 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sk_len; 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pk) { 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, pk_len); 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pk, pos, pk_len); 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len, 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *seed, size_t seed_len, 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pk, size_t *pk_len) 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_GPSK_SK_LEN_AES 16 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_GPSK_PK_LEN_AES 16 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES + 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_GPSK_PK_LEN_AES]; 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (= seed) 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MK = GKDF-16 (PSK[0..15], PL || PSK || CSuite_Sel || inputString) 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MSK = GKDF-160 (MK, inputString)[0..63] 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EMSK = GKDF-160 (MK, inputString)[64..127] 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * SK = GKDF-160 (MK, inputString)[128..143] 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PK = GKDF-160 (MK, inputString)[144..159] 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * zero = 0x00 || 0x00 || ... || 0x00 (16 times) 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * CSuite_Sel || inputString) 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sk_len = EAP_GPSK_SK_LEN_AES; 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pk_len = EAP_GPSK_PK_LEN_AES; 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_AES, 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt kdf_out, sizeof(kdf_out), 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt psk, psk_len, seed, seed_len, 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msk, emsk, sk, *sk_len, 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pk, *pk_len); 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef EAP_GPSK_SHA256 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len, 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *seed, size_t seed_len, 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *msk, u8 *emsk, 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *sk, size_t *sk_len) 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 + 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_GPSK_PK_LEN_SHA256]; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (= seed) 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MK = GKDF-32 (PSK[0..31], PL || PSK || CSuite_Sel || inputString) 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MSK = GKDF-160 (MK, inputString)[0..63] 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EMSK = GKDF-160 (MK, inputString)[64..127] 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * SK = GKDF-160 (MK, inputString)[128..159] 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * zero = 0x00 || 0x00 || ... || 0x00 (32 times) 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * CSuite_Sel || inputString) 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sk_len = EAP_GPSK_SK_LEN_SHA256; 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_SHA256, 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt kdf_out, sizeof(kdf_out), 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt psk, psk_len, seed, seed_len, 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msk, emsk, sk, *sk_len, 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NULL, 0); 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_gpsk_derive_keys - Derive EAP-GPSK keys 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @psk: Pre-shared key 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @psk_len: Length of psk in bytes 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: CSuite/Vendor 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @specifier: CSuite/Specifier 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @rand_peer: 32-byte RAND_Peer 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @rand_server: 32-byte RAND_Server 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @id_peer: ID_Peer 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @id_peer_len: Length of ID_Peer 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @id_server: ID_Server 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @id_server_len: Length of ID_Server 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msk: Buffer for 64-byte MSK 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @emsk: Buffer for 64-byte EMSK 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes) 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sk_len: Buffer for returning length of SK 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pk: Buffer for PK (at least EAP_GPSK_MAX_PK_LEN bytes) 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pk_len: Buffer for returning length of PK 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int specifier, 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *rand_peer, const u8 *rand_server, 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *id_peer, size_t id_peer_len, 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *id_server, size_t id_server_len, 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pk, size_t *pk_len) 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *seed, *pos; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)", 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vendor, specifier); 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vendor != EAP_GPSK_VENDOR_IETF) 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */ 298c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len); 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (seed == NULL) { 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for key derivation"); 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = seed; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN); 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += EAP_GPSK_RAND_LEN; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, id_peer, id_peer_len); 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += id_peer_len; 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN); 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += EAP_GPSK_RAND_LEN; 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, id_server, id_server_len); 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += id_server_len; 314c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed); 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (specifier) { 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_AES: 318c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, pos - seed, 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msk, emsk, sk, sk_len, 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pk, pk_len); 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef EAP_GPSK_SHA256 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_SHA256: 324c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, 325c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt pos - seed, 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msk, emsk, sk, sk_len); 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "key derivation", vendor, specifier); 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = -1; 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(seed); 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 342f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstatic int eap_gpsk_derive_mid_helper(u32 csuite_specifier, 343f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt u8 *kdf_out, size_t kdf_out_len, 344f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt const u8 *psk, const u8 *seed, 345f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt size_t seed_len, u8 method_type) 346f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{ 347f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt u8 *pos, *data; 348f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt size_t data_len; 349f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len, 350f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt u8 *buf, size_t len); 351f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 352f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt gkdf = NULL; 353f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt switch (csuite_specifier) { 354f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt case EAP_GPSK_CIPHER_AES: 355f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt gkdf = eap_gpsk_gkdf_cmac; 356f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt break; 357f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef EAP_GPSK_SHA256 358f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt case EAP_GPSK_CIPHER_SHA256: 359f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt gkdf = eap_gpsk_gkdf_sha256; 360f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt break; 361f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 362f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt default: 363f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in " 364f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt "Session-Id derivation", csuite_specifier); 365f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return -1; 366f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt } 367f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 368f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#define SID_LABEL "Method ID" 369f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt /* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */ 370f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt data_len = strlen(SID_LABEL) + 1 + 6 + seed_len; 371f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt data = os_malloc(data_len); 372f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt if (data == NULL) 373f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return -1; 374f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos = data; 375f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(pos, SID_LABEL, strlen(SID_LABEL)); 376f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += strlen(SID_LABEL); 377f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#undef SID_LABEL 378f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(pos, &method_type, 1); 379f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += 1; 380f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */ 381f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += 4; 382f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */ 383f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += 2; 384f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(pos, seed, seed_len); /* inputString */ 385f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation", 386f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt data, data_len); 387f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 388f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) { 389f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_free(data); 390f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return -1; 391f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt } 392f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_free(data); 393f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len); 394f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 395f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return 0; 396f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt} 397f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 398f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 399f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt/** 400f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * eap_gpsk_session_id - Derive EAP-GPSK Session ID 401f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @psk: Pre-shared key 402f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @psk_len: Length of psk in bytes 403f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @vendor: CSuite/Vendor 404f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @specifier: CSuite/Specifier 405f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @rand_peer: 32-byte RAND_Peer 406f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @rand_server: 32-byte RAND_Server 407f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @id_peer: ID_Peer 408f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @id_peer_len: Length of ID_Peer 409f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @id_server: ID_Server 410f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @id_server_len: Length of ID_Server 411f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @method_type: EAP Authentication Method Type 412f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @sid: Buffer for 17-byte Session ID 413f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @sid_len: Buffer for returning length of Session ID 414f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * Returns: 0 on success, -1 on failure 415f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt */ 416f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtint eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, 417f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt int specifier, 418f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt const u8 *rand_peer, const u8 *rand_server, 419f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt const u8 *id_peer, size_t id_peer_len, 420f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt const u8 *id_server, size_t id_server_len, 421f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt u8 method_type, u8 *sid, size_t *sid_len) 422f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{ 423f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt u8 *seed, *pos; 424f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt u8 kdf_out[16]; 425f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt int ret; 426f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 427f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)", 428f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt vendor, specifier); 429f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 430f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt if (vendor != EAP_GPSK_VENDOR_IETF) 431f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return -1; 432f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 433f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); 434f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 435f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt /* 436f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server 437f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * (= seed) 438f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * KS = 16, CSuite_Sel = 0x00000000 0x0001 439f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || 440f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * CSuite_Sel || inputString) 441f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt */ 442c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len); 443f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt if (seed == NULL) { 444f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " 445f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt "for Session-Id derivation"); 446f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return -1; 447f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt } 448f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 449f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos = seed; 450f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN); 451f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += EAP_GPSK_RAND_LEN; 452f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(pos, id_peer, id_peer_len); 453f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += id_peer_len; 454f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN); 455f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += EAP_GPSK_RAND_LEN; 456f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(pos, id_server, id_server_len); 457f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt pos += id_server_len; 458c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed); 459f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 460f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt ret = eap_gpsk_derive_mid_helper(specifier, 461f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt kdf_out, sizeof(kdf_out), 462c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt psk, seed, pos - seed, 463f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt method_type); 464f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 465f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt sid[0] = method_type; 466f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_memcpy(sid + 1, kdf_out, sizeof(kdf_out)); 467f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt *sid_len = 1 + sizeof(kdf_out); 468f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 469f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt os_free(seed); 470f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 471f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return ret; 472f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt} 473f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 474f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_gpsk_mic_len - Get the length of the MIC 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: CSuite/Vendor 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @specifier: CSuite/Specifier 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: MIC length in bytes 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtsize_t eap_gpsk_mic_len(int vendor, int specifier) 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vendor != EAP_GPSK_VENDOR_IETF) 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (specifier) { 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_AES: 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 16; 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef EAP_GPSK_SHA256 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_SHA256: 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 32; 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len, 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t len, u8 *mic) 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sk_len != 16) { 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for " 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "AES-CMAC MIC", (unsigned long) sk_len); 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return omac1_aes_128(sk, data, len, mic); 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sk: Session key SK from eap_gpsk_derive_keys() 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sk_len: SK length in bytes from eap_gpsk_derive_keys() 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: CSuite/Vendor 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @specifier: CSuite/Specifier 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: Input data to MIC 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Input data length in bytes 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int specifier, const u8 *data, size_t len, u8 *mic) 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vendor != EAP_GPSK_VENDOR_IETF) 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (specifier) { 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_AES: 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic); 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef EAP_GPSK_SHA256 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_GPSK_CIPHER_SHA256: 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_sha256(sk, sk_len, data, len, mic); 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = 0; 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* EAP_GPSK_SHA256 */ 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "MIC computation", vendor, specifier); 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = -1; 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 550