eap_gpsk_common.c revision 267654
10Sstevel@tonic-gate/* 20Sstevel@tonic-gate * EAP server/peer: EAP-GPSK shared routines 30Sstevel@tonic-gate * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * This program is free software; you can redistribute it and/or modify 60Sstevel@tonic-gate * it under the terms of the GNU General Public License version 2 as 70Sstevel@tonic-gate * published by the Free Software Foundation. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * Alternatively, this software may be distributed under the terms of BSD 100Sstevel@tonic-gate * license. 110Sstevel@tonic-gate * 120Sstevel@tonic-gate * See README and COPYING for more details. 130Sstevel@tonic-gate */ 140Sstevel@tonic-gate 150Sstevel@tonic-gate#include "includes.h" 160Sstevel@tonic-gate 170Sstevel@tonic-gate#include "common.h" 180Sstevel@tonic-gate#include "crypto/aes_wrap.h" 190Sstevel@tonic-gate#include "crypto/sha256.h" 200Sstevel@tonic-gate#include "eap_defs.h" 210Sstevel@tonic-gate#include "eap_gpsk_common.h" 220Sstevel@tonic-gate 230Sstevel@tonic-gate 240Sstevel@tonic-gate/** 250Sstevel@tonic-gate * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported 260Sstevel@tonic-gate * @vendor: CSuite/Vendor 270Sstevel@tonic-gate * @specifier: CSuite/Specifier 280Sstevel@tonic-gate * Returns: 1 if ciphersuite is support, or 0 if not 290Sstevel@tonic-gate */ 300Sstevel@tonic-gateint eap_gpsk_supported_ciphersuite(int vendor, int specifier) 310Sstevel@tonic-gate{ 320Sstevel@tonic-gate if (vendor == EAP_GPSK_VENDOR_IETF && 330Sstevel@tonic-gate specifier == EAP_GPSK_CIPHER_AES) 340Sstevel@tonic-gate return 1; 350Sstevel@tonic-gate#ifdef EAP_GPSK_SHA256 360Sstevel@tonic-gate if (vendor == EAP_GPSK_VENDOR_IETF && 370Sstevel@tonic-gate specifier == EAP_GPSK_CIPHER_SHA256) 380Sstevel@tonic-gate return 1; 390Sstevel@tonic-gate#endif /* EAP_GPSK_SHA256 */ 400Sstevel@tonic-gate return 0; 410Sstevel@tonic-gate} 420Sstevel@tonic-gate 430Sstevel@tonic-gate 440Sstevel@tonic-gatestatic int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */, 450Sstevel@tonic-gate const u8 *data /* Z */, size_t data_len, 460Sstevel@tonic-gate u8 *buf, size_t len /* X */) 470Sstevel@tonic-gate{ 480Sstevel@tonic-gate u8 *opos; 490Sstevel@tonic-gate size_t i, n, hashlen, left, clen; 500Sstevel@tonic-gate u8 ibuf[2], hash[16]; 510Sstevel@tonic-gate const u8 *addr[2]; 520Sstevel@tonic-gate size_t vlen[2]; 530Sstevel@tonic-gate 540Sstevel@tonic-gate hashlen = sizeof(hash); 550Sstevel@tonic-gate /* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */ 56265Smws addr[0] = ibuf; 570Sstevel@tonic-gate vlen[0] = sizeof(ibuf); 580Sstevel@tonic-gate addr[1] = data; 590Sstevel@tonic-gate vlen[1] = data_len; 600Sstevel@tonic-gate 610Sstevel@tonic-gate opos = buf; 620Sstevel@tonic-gate left = len; 630Sstevel@tonic-gate n = (len + hashlen - 1) / hashlen; 640Sstevel@tonic-gate for (i = 1; i <= n; i++) { 650Sstevel@tonic-gate WPA_PUT_BE16(ibuf, i); 660Sstevel@tonic-gate if (omac1_aes_128_vector(psk, 2, addr, vlen, hash)) 670Sstevel@tonic-gate return -1; 680Sstevel@tonic-gate clen = left > hashlen ? hashlen : left; 690Sstevel@tonic-gate os_memcpy(opos, hash, clen); 700Sstevel@tonic-gate opos += clen; 710Sstevel@tonic-gate left -= clen; 720Sstevel@tonic-gate } 730Sstevel@tonic-gate 740Sstevel@tonic-gate return 0; 750Sstevel@tonic-gate} 760Sstevel@tonic-gate 770Sstevel@tonic-gate 780Sstevel@tonic-gate#ifdef EAP_GPSK_SHA256 790Sstevel@tonic-gatestatic int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, 800Sstevel@tonic-gate const u8 *data /* Z */, size_t data_len, 810Sstevel@tonic-gate u8 *buf, size_t len /* X */) 820Sstevel@tonic-gate{ 830Sstevel@tonic-gate u8 *opos; 840Sstevel@tonic-gate size_t i, n, hashlen, left, clen; 850Sstevel@tonic-gate u8 ibuf[2], hash[SHA256_MAC_LEN]; 860Sstevel@tonic-gate const u8 *addr[2]; 870Sstevel@tonic-gate size_t vlen[2]; 880Sstevel@tonic-gate 890Sstevel@tonic-gate hashlen = SHA256_MAC_LEN; 900Sstevel@tonic-gate /* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */ 910Sstevel@tonic-gate addr[0] = ibuf; 920Sstevel@tonic-gate vlen[0] = sizeof(ibuf); 930Sstevel@tonic-gate addr[1] = data; 940Sstevel@tonic-gate vlen[1] = data_len; 950Sstevel@tonic-gate 960Sstevel@tonic-gate opos = buf; 970Sstevel@tonic-gate left = len; 980Sstevel@tonic-gate n = (len + hashlen - 1) / hashlen; 990Sstevel@tonic-gate for (i = 1; i <= n; i++) { 1000Sstevel@tonic-gate WPA_PUT_BE16(ibuf, i); 1010Sstevel@tonic-gate hmac_sha256_vector(psk, 32, 2, addr, vlen, hash); 1020Sstevel@tonic-gate clen = left > hashlen ? hashlen : left; 1030Sstevel@tonic-gate os_memcpy(opos, hash, clen); 1040Sstevel@tonic-gate opos += clen; 105265Smws left -= clen; 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate return 0; 1090Sstevel@tonic-gate} 1100Sstevel@tonic-gate#endif /* EAP_GPSK_SHA256 */ 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate 1130Sstevel@tonic-gatestatic int eap_gpsk_derive_keys_helper(u32 csuite_specifier, 1140Sstevel@tonic-gate u8 *kdf_out, size_t kdf_out_len, 1150Sstevel@tonic-gate const u8 *psk, size_t psk_len, 1160Sstevel@tonic-gate const u8 *seed, size_t seed_len, 1170Sstevel@tonic-gate u8 *msk, u8 *emsk, 1180Sstevel@tonic-gate u8 *sk, size_t sk_len, 1190Sstevel@tonic-gate u8 *pk, size_t pk_len) 1200Sstevel@tonic-gate{ 1210Sstevel@tonic-gate u8 mk[32], *pos, *data; 1220Sstevel@tonic-gate size_t data_len, mk_len; 1230Sstevel@tonic-gate int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len, 1240Sstevel@tonic-gate u8 *buf, size_t len); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate gkdf = NULL; 1270Sstevel@tonic-gate switch (csuite_specifier) { 1280Sstevel@tonic-gate case EAP_GPSK_CIPHER_AES: 1290Sstevel@tonic-gate gkdf = eap_gpsk_gkdf_cmac; 1300Sstevel@tonic-gate mk_len = 16; 1310Sstevel@tonic-gate break; 1320Sstevel@tonic-gate#ifdef EAP_GPSK_SHA256 1330Sstevel@tonic-gate case EAP_GPSK_CIPHER_SHA256: 1340Sstevel@tonic-gate gkdf = eap_gpsk_gkdf_sha256; 1350Sstevel@tonic-gate mk_len = SHA256_MAC_LEN; 1360Sstevel@tonic-gate break; 1370Sstevel@tonic-gate#endif /* EAP_GPSK_SHA256 */ 1380Sstevel@tonic-gate default: 1390Sstevel@tonic-gate return -1; 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate if (psk_len < mk_len) 1430Sstevel@tonic-gate return -1; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate data_len = 2 + psk_len + 6 + seed_len; 1460Sstevel@tonic-gate data = os_malloc(data_len); 1470Sstevel@tonic-gate if (data == NULL) 1480Sstevel@tonic-gate return -1; 1490Sstevel@tonic-gate pos = data; 1500Sstevel@tonic-gate WPA_PUT_BE16(pos, psk_len); 1510Sstevel@tonic-gate pos += 2; 1520Sstevel@tonic-gate os_memcpy(pos, psk, psk_len); 1530Sstevel@tonic-gate pos += psk_len; 1540Sstevel@tonic-gate WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */ 1550Sstevel@tonic-gate pos += 4; 1560Sstevel@tonic-gate WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */ 1570Sstevel@tonic-gate pos += 2; 1580Sstevel@tonic-gate os_memcpy(pos, seed, seed_len); /* inputString */ 1590Sstevel@tonic-gate wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation", 1600Sstevel@tonic-gate data, data_len); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate if (gkdf(psk, data, data_len, mk, mk_len) < 0) { 1630Sstevel@tonic-gate os_free(data); 1640Sstevel@tonic-gate return -1; 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate os_free(data); 1670Sstevel@tonic-gate wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len); 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0) 1700Sstevel@tonic-gate return -1; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate pos = kdf_out; 1730Sstevel@tonic-gate wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN); 1740Sstevel@tonic-gate os_memcpy(msk, pos, EAP_MSK_LEN); 1750Sstevel@tonic-gate pos += EAP_MSK_LEN; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN); 1780Sstevel@tonic-gate os_memcpy(emsk, pos, EAP_EMSK_LEN); 1790Sstevel@tonic-gate pos += EAP_EMSK_LEN; 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, sk_len); 1820Sstevel@tonic-gate os_memcpy(sk, pos, sk_len); 1830Sstevel@tonic-gate pos += sk_len; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate if (pk) { 1860Sstevel@tonic-gate wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, pk_len); 1870Sstevel@tonic-gate os_memcpy(pk, pos, pk_len); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate return 0; 1910Sstevel@tonic-gate} 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate 1940Sstevel@tonic-gatestatic int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len, 1950Sstevel@tonic-gate const u8 *seed, size_t seed_len, 1960Sstevel@tonic-gate u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, 1970Sstevel@tonic-gate u8 *pk, size_t *pk_len) 1980Sstevel@tonic-gate{ 1990Sstevel@tonic-gate#define EAP_GPSK_SK_LEN_AES 16 2000Sstevel@tonic-gate#define EAP_GPSK_PK_LEN_AES 16 2010Sstevel@tonic-gate u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES + 2020Sstevel@tonic-gate EAP_GPSK_PK_LEN_AES]; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server 2060Sstevel@tonic-gate * (= seed) 2070Sstevel@tonic-gate * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001 2080Sstevel@tonic-gate * MK = GKDF-16 (PSK[0..15], PL || PSK || CSuite_Sel || inputString) 2090Sstevel@tonic-gate * MSK = GKDF-160 (MK, inputString)[0..63] 2100Sstevel@tonic-gate * EMSK = GKDF-160 (MK, inputString)[64..127] 2110Sstevel@tonic-gate * SK = GKDF-160 (MK, inputString)[128..143] 2120Sstevel@tonic-gate * PK = GKDF-160 (MK, inputString)[144..159] 2130Sstevel@tonic-gate * zero = 0x00 || 0x00 || ... || 0x00 (16 times) 2140Sstevel@tonic-gate * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || 2150Sstevel@tonic-gate * CSuite_Sel || inputString) 2160Sstevel@tonic-gate */ 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate *sk_len = EAP_GPSK_SK_LEN_AES; 2190Sstevel@tonic-gate *pk_len = EAP_GPSK_PK_LEN_AES; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_AES, 2220Sstevel@tonic-gate kdf_out, sizeof(kdf_out), 2230Sstevel@tonic-gate psk, psk_len, seed, seed_len, 2240Sstevel@tonic-gate msk, emsk, sk, *sk_len, 2250Sstevel@tonic-gate pk, *pk_len); 2260Sstevel@tonic-gate} 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate#ifdef EAP_GPSK_SHA256 2300Sstevel@tonic-gatestatic int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len, 2310Sstevel@tonic-gate const u8 *seed, size_t seed_len, 2320Sstevel@tonic-gate u8 *msk, u8 *emsk, 2330Sstevel@tonic-gate u8 *sk, size_t *sk_len) 2340Sstevel@tonic-gate{ 2350Sstevel@tonic-gate#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN 2360Sstevel@tonic-gate#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN 2370Sstevel@tonic-gate u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 + 2380Sstevel@tonic-gate EAP_GPSK_PK_LEN_SHA256]; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* 2410Sstevel@tonic-gate * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server 2420Sstevel@tonic-gate * (= seed) 2430Sstevel@tonic-gate * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002 2440Sstevel@tonic-gate * MK = GKDF-32 (PSK[0..31], PL || PSK || CSuite_Sel || inputString) 2450Sstevel@tonic-gate * MSK = GKDF-160 (MK, inputString)[0..63] 2460Sstevel@tonic-gate * EMSK = GKDF-160 (MK, inputString)[64..127] 2470Sstevel@tonic-gate * SK = GKDF-160 (MK, inputString)[128..159] 2480Sstevel@tonic-gate * zero = 0x00 || 0x00 || ... || 0x00 (32 times) 2490Sstevel@tonic-gate * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || 2500Sstevel@tonic-gate * CSuite_Sel || inputString) 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate *sk_len = EAP_GPSK_SK_LEN_SHA256; 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_SHA256, 2560Sstevel@tonic-gate kdf_out, sizeof(kdf_out), 2570Sstevel@tonic-gate psk, psk_len, seed, seed_len, 2580Sstevel@tonic-gate msk, emsk, sk, *sk_len, 2590Sstevel@tonic-gate NULL, 0); 2600Sstevel@tonic-gate} 2610Sstevel@tonic-gate#endif /* EAP_GPSK_SHA256 */ 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate/** 2650Sstevel@tonic-gate * eap_gpsk_derive_keys - Derive EAP-GPSK keys 2660Sstevel@tonic-gate * @psk: Pre-shared key 2670Sstevel@tonic-gate * @psk_len: Length of psk in bytes 2680Sstevel@tonic-gate * @vendor: CSuite/Vendor 2690Sstevel@tonic-gate * @specifier: CSuite/Specifier 2700Sstevel@tonic-gate * @rand_peer: 32-byte RAND_Peer 2710Sstevel@tonic-gate * @rand_server: 32-byte RAND_Server 2720Sstevel@tonic-gate * @id_peer: ID_Peer 2730Sstevel@tonic-gate * @id_peer_len: Length of ID_Peer 2740Sstevel@tonic-gate * @id_server: ID_Server 2750Sstevel@tonic-gate * @id_server_len: Length of ID_Server 2760Sstevel@tonic-gate * @msk: Buffer for 64-byte MSK 2770Sstevel@tonic-gate * @emsk: Buffer for 64-byte EMSK 2780Sstevel@tonic-gate * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes) 2790Sstevel@tonic-gate * @sk_len: Buffer for returning length of SK 2800Sstevel@tonic-gate * @pk: Buffer for PK (at least EAP_GPSK_MAX_PK_LEN bytes) 2810Sstevel@tonic-gate * @pk_len: Buffer for returning length of PK 2820Sstevel@tonic-gate * Returns: 0 on success, -1 on failure 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gateint eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, 2850Sstevel@tonic-gate int specifier, 2860Sstevel@tonic-gate const u8 *rand_peer, const u8 *rand_server, 2870Sstevel@tonic-gate const u8 *id_peer, size_t id_peer_len, 2880Sstevel@tonic-gate const u8 *id_server, size_t id_server_len, 2890Sstevel@tonic-gate u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, 2900Sstevel@tonic-gate u8 *pk, size_t *pk_len) 2910Sstevel@tonic-gate{ 2920Sstevel@tonic-gate u8 *seed, *pos; 2930Sstevel@tonic-gate size_t seed_len; 2940Sstevel@tonic-gate int ret; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)", 2970Sstevel@tonic-gate vendor, specifier); 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate if (vendor != EAP_GPSK_VENDOR_IETF) 3000Sstevel@tonic-gate return -1; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */ 3050Sstevel@tonic-gate seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len; 3060Sstevel@tonic-gate seed = os_malloc(seed_len); 3070Sstevel@tonic-gate if (seed == NULL) { 3080Sstevel@tonic-gate wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " 3090Sstevel@tonic-gate "for key derivation"); 3100Sstevel@tonic-gate return -1; 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate pos = seed; 3140Sstevel@tonic-gate os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN); 3150Sstevel@tonic-gate pos += EAP_GPSK_RAND_LEN; 3160Sstevel@tonic-gate os_memcpy(pos, id_peer, id_peer_len); 3170Sstevel@tonic-gate pos += id_peer_len; 3180Sstevel@tonic-gate os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN); 3190Sstevel@tonic-gate pos += EAP_GPSK_RAND_LEN; 3200Sstevel@tonic-gate os_memcpy(pos, id_server, id_server_len); 3210Sstevel@tonic-gate pos += id_server_len; 3220Sstevel@tonic-gate wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate switch (specifier) { 3250Sstevel@tonic-gate case EAP_GPSK_CIPHER_AES: 3260Sstevel@tonic-gate ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len, 3270Sstevel@tonic-gate msk, emsk, sk, sk_len, 3280Sstevel@tonic-gate pk, pk_len); 3290Sstevel@tonic-gate break; 3300Sstevel@tonic-gate#ifdef EAP_GPSK_SHA256 3310Sstevel@tonic-gate case EAP_GPSK_CIPHER_SHA256: 3320Sstevel@tonic-gate ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len, 3330Sstevel@tonic-gate msk, emsk, sk, sk_len); 3340Sstevel@tonic-gate break; 3350Sstevel@tonic-gate#endif /* EAP_GPSK_SHA256 */ 3360Sstevel@tonic-gate default: 3370Sstevel@tonic-gate wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " 3380Sstevel@tonic-gate "key derivation", vendor, specifier); 3390Sstevel@tonic-gate ret = -1; 3400Sstevel@tonic-gate break; 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate os_free(seed); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate return ret; 3460Sstevel@tonic-gate} 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate/** 3500Sstevel@tonic-gate * eap_gpsk_mic_len - Get the length of the MIC 3510Sstevel@tonic-gate * @vendor: CSuite/Vendor 3520Sstevel@tonic-gate * @specifier: CSuite/Specifier 3530Sstevel@tonic-gate * Returns: MIC length in bytes 3540Sstevel@tonic-gate */ 3550Sstevel@tonic-gatesize_t eap_gpsk_mic_len(int vendor, int specifier) 3560Sstevel@tonic-gate{ 3570Sstevel@tonic-gate if (vendor != EAP_GPSK_VENDOR_IETF) 3580Sstevel@tonic-gate return 0; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate switch (specifier) { 3610Sstevel@tonic-gate case EAP_GPSK_CIPHER_AES: 3620Sstevel@tonic-gate return 16; 3630Sstevel@tonic-gate#ifdef EAP_GPSK_SHA256 3640Sstevel@tonic-gate case EAP_GPSK_CIPHER_SHA256: 3650Sstevel@tonic-gate return 32; 3660Sstevel@tonic-gate#endif /* EAP_GPSK_SHA256 */ 3670Sstevel@tonic-gate default: 3680Sstevel@tonic-gate return 0; 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate} 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate 3730Sstevel@tonic-gatestatic int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len, 3740Sstevel@tonic-gate const u8 *data, size_t len, u8 *mic) 3750Sstevel@tonic-gate{ 3760Sstevel@tonic-gate if (sk_len != 16) { 3770Sstevel@tonic-gate wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for " 3780Sstevel@tonic-gate "AES-CMAC MIC", (unsigned long) sk_len); 3790Sstevel@tonic-gate return -1; 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate return omac1_aes_128(sk, data, len, mic); 3830Sstevel@tonic-gate} 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate/** 3870Sstevel@tonic-gate * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet 3880Sstevel@tonic-gate * @sk: Session key SK from eap_gpsk_derive_keys() 3890Sstevel@tonic-gate * @sk_len: SK length in bytes from eap_gpsk_derive_keys() 3900Sstevel@tonic-gate * @vendor: CSuite/Vendor 3910Sstevel@tonic-gate * @specifier: CSuite/Specifier 3920Sstevel@tonic-gate * @data: Input data to MIC 3930Sstevel@tonic-gate * @len: Input data length in bytes 3940Sstevel@tonic-gate * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes 3950Sstevel@tonic-gate * Returns: 0 on success, -1 on failure 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gateint eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, 3980Sstevel@tonic-gate int specifier, const u8 *data, size_t len, u8 *mic) 3990Sstevel@tonic-gate{ 4000Sstevel@tonic-gate int ret; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if (vendor != EAP_GPSK_VENDOR_IETF) 4030Sstevel@tonic-gate return -1; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate switch (specifier) { 4060Sstevel@tonic-gate case EAP_GPSK_CIPHER_AES: 4070Sstevel@tonic-gate ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic); 4080Sstevel@tonic-gate break; 4090Sstevel@tonic-gate#ifdef EAP_GPSK_SHA256 4100Sstevel@tonic-gate case EAP_GPSK_CIPHER_SHA256: 4110Sstevel@tonic-gate hmac_sha256(sk, sk_len, data, len, mic); 4120Sstevel@tonic-gate ret = 0; 4130Sstevel@tonic-gate break; 4140Sstevel@tonic-gate#endif /* EAP_GPSK_SHA256 */ 4150Sstevel@tonic-gate default: 4160Sstevel@tonic-gate wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " 4170Sstevel@tonic-gate "MIC computation", vendor, specifier); 4180Sstevel@tonic-gate ret = -1; 4190Sstevel@tonic-gate break; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate return ret; 4230Sstevel@tonic-gate} 4240Sstevel@tonic-gate