diff options
Diffstat (limited to 'contrib/wpa/src/common/wpa_common.c')
-rw-r--r-- | contrib/wpa/src/common/wpa_common.c | 586 |
1 files changed, 523 insertions, 63 deletions
diff --git a/contrib/wpa/src/common/wpa_common.c b/contrib/wpa/src/common/wpa_common.c index 8d7a11c..de81d53 100644 --- a/contrib/wpa/src/common/wpa_common.c +++ b/contrib/wpa/src/common/wpa_common.c @@ -1,6 +1,6 @@ /* * WPA/RSN - Shared functions for supplicant and authenticator - * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +12,7 @@ #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" +#include "crypto/sha384.h" #include "crypto/aes_wrap.h" #include "crypto/crypto.h" #include "ieee802_11_defs.h" @@ -19,9 +20,35 @@ #include "wpa_common.h" +static unsigned int wpa_kck_len(int akmp) +{ + if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + return 24; + return 16; +} + + +static unsigned int wpa_kek_len(int akmp) +{ + if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + return 32; + return 16; +} + + +unsigned int wpa_mic_len(int akmp) +{ + if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + return 24; + return 16; +} + + /** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) + * @key_len: KCK length in octets + * @akmp: WPA_KEY_MGMT_* used in key derivation * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) * @buf: Pointer to the beginning of the EAPOL header (version field) * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) @@ -37,18 +64,18 @@ * happened during final editing of the standard and the correct behavior is * defined in the last draft (IEEE 802.11i/D10). */ -int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, - u8 *mic) +int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, + const u8 *buf, size_t len, u8 *mic) { - u8 hash[SHA1_MAC_LEN]; + u8 hash[SHA384_MAC_LEN]; switch (ver) { #ifndef CONFIG_FIPS case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: - return hmac_md5(key, 16, buf, len, mic); + return hmac_md5(key, key_len, buf, len, mic); #endif /* CONFIG_FIPS */ case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: - if (hmac_sha1(key, 16, buf, len, hash)) + if (hmac_sha1(key, key_len, buf, len, hash)) return -1; os_memcpy(mic, hash, MD5_MAC_LEN); break; @@ -56,6 +83,30 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, case WPA_KEY_INFO_TYPE_AES_128_CMAC: return omac1_aes_128(key, buf, len, mic); #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ + case WPA_KEY_INFO_TYPE_AKM_DEFINED: + switch (akmp) { +#ifdef CONFIG_HS20 + case WPA_KEY_MGMT_OSEN: + return omac1_aes_128(key, buf, len, mic); +#endif /* CONFIG_HS20 */ +#ifdef CONFIG_SUITEB + case WPA_KEY_MGMT_IEEE8021X_SUITE_B: + if (hmac_sha256(key, key_len, buf, len, hash)) + return -1; + os_memcpy(mic, hash, MD5_MAC_LEN); + break; +#endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SUITEB192 + case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: + if (hmac_sha384(key, key_len, buf, len, hash)) + return -1; + os_memcpy(mic, hash, 24); + break; +#endif /* CONFIG_SUITEB192 */ + default: + return -1; + } + break; default: return -1; } @@ -74,8 +125,9 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, * @nonce1: ANonce or SNonce * @nonce2: SNonce or ANonce * @ptk: Buffer for pairwise transient key - * @ptk_len: Length of PTK - * @use_sha256: Whether to use SHA256-based KDF + * @akmp: Negotiated AKM + * @cipher: Negotiated pairwise cipher + * Returns: 0 on success, -1 on failure * * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy * PTK = PRF-X(PMK, "Pairwise key expansion", @@ -86,12 +138,14 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || * Min(INonce, PNonce) || Max(INonce, PNonce)) */ -void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, - const u8 *addr1, const u8 *addr2, - const u8 *nonce1, const u8 *nonce2, - u8 *ptk, size_t ptk_len, int use_sha256) +int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, + const u8 *addr1, const u8 *addr2, + const u8 *nonce1, const u8 *nonce2, + struct wpa_ptk *ptk, int akmp, int cipher) { u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; + u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; + size_t ptk_len; if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { os_memcpy(data, addr1, ETH_ALEN); @@ -111,27 +165,44 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, WPA_NONCE_LEN); } + ptk->kck_len = wpa_kck_len(akmp); + ptk->kek_len = wpa_kek_len(akmp); + ptk->tk_len = wpa_cipher_key_len(cipher); + ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len; + #ifdef CONFIG_IEEE80211W - if (use_sha256) + if (wpa_key_mgmt_sha256(akmp)) sha256_prf(pmk, pmk_len, label, data, sizeof(data), - ptk, ptk_len); + tmp, ptk_len); else #endif /* CONFIG_IEEE80211W */ - sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, - ptk_len); + sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len); wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2)); wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); - wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); + wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len); + + os_memcpy(ptk->kck, tmp, ptk->kck_len); + wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len); + + os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); + wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len); + + os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); + wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len); + + os_memset(tmp, 0, sizeof(tmp)); + return 0; } #ifdef CONFIG_IEEE80211R -int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, - u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, +int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, + const u8 *ap_addr, u8 transaction_seqnum, + const u8 *mdie, size_t mdie_len, const u8 *ftie, size_t ftie_len, const u8 *rsnie, size_t rsnie_len, const u8 *ric, size_t ric_len, u8 *mic) @@ -139,6 +210,12 @@ int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, u8 *buf, *pos; size_t buf_len; + if (kck_len != 16) { + wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u", + (unsigned int) kck_len); + return -1; + } + buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; buf = os_malloc(buf_len); if (buf == NULL) @@ -335,7 +412,6 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, #endif /* CONFIG_IEEE80211R */ -#ifndef CONFIG_NO_WPA2 static int rsn_selector_to_bitfield(const u8 *s) { if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) @@ -354,6 +430,18 @@ static int rsn_selector_to_bitfield(const u8 *s) #endif /* CONFIG_IEEE80211W */ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) return WPA_CIPHER_GCMP; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256) + return WPA_CIPHER_GCMP_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128) + return WPA_CIPHER_BIP_GMAC_128; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256) + return WPA_CIPHER_BIP_GMAC_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) + return WPA_CIPHER_BIP_CMAC_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED) + return WPA_CIPHER_GTK_NOT_USED; return 0; } @@ -382,9 +470,32 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE) return WPA_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B) + return WPA_KEY_MGMT_IEEE8021X_SUITE_B; + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192) + return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; return 0; } -#endif /* CONFIG_NO_WPA2 */ + + +static int wpa_cipher_valid_group(int cipher) +{ + return wpa_cipher_valid_pairwise(cipher) || + cipher == WPA_CIPHER_WEP104 || + cipher == WPA_CIPHER_WEP40 || + cipher == WPA_CIPHER_GTK_NOT_USED; +} + + +#ifdef CONFIG_IEEE80211W +int wpa_cipher_valid_mgmt_group(int cipher) +{ + return cipher == WPA_CIPHER_AES_128_CMAC || + cipher == WPA_CIPHER_BIP_GMAC_128 || + cipher == WPA_CIPHER_BIP_GMAC_256 || + cipher == WPA_CIPHER_BIP_CMAC_256; +} +#endif /* CONFIG_IEEE80211W */ /** @@ -397,7 +508,6 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data) { -#ifndef CONFIG_NO_WPA2 const struct rsn_ie_hdr *hdr; const u8 *pos; int left; @@ -443,13 +553,11 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); -#ifdef CONFIG_IEEE80211W - if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { - wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " - "cipher", __func__); + if (!wpa_cipher_valid_group(data->group_cipher)) { + wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x", + __func__, data->group_cipher); return -1; } -#endif /* CONFIG_IEEE80211W */ pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } else if (left > 0) { @@ -463,7 +571,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, count = WPA_GET_LE16(pos); pos += 2; left -= 2; - if (count == 0 || left < count * RSN_SELECTOR_LEN) { + if (count == 0 || count > left / RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", __func__, count, left); return -4; @@ -491,7 +599,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, count = WPA_GET_LE16(pos); pos += 2; left -= 2; - if (count == 0 || left < count * RSN_SELECTOR_LEN) { + if (count == 0 || count > left / RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", __func__, count, left); return -6; @@ -514,17 +622,17 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, } if (left >= 2) { - data->num_pmkid = WPA_GET_LE16(pos); + u16 num_pmkid = WPA_GET_LE16(pos); pos += 2; left -= 2; - if (left < (int) data->num_pmkid * PMKID_LEN) { + if (num_pmkid > (unsigned int) left / PMKID_LEN) { wpa_printf(MSG_DEBUG, "%s: PMKID underflow " - "(num_pmkid=%lu left=%d)", - __func__, (unsigned long) data->num_pmkid, - left); + "(num_pmkid=%u left=%d)", + __func__, num_pmkid, left); data->num_pmkid = 0; return -9; } else { + data->num_pmkid = num_pmkid; data->pmkid = pos; pos += data->num_pmkid * PMKID_LEN; left -= data->num_pmkid * PMKID_LEN; @@ -534,7 +642,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, #ifdef CONFIG_IEEE80211W if (left >= 4) { data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); - if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { + if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) { wpa_printf(MSG_DEBUG, "%s: Unsupported management " "group cipher 0x%x", __func__, data->mgmt_group_cipher); @@ -546,14 +654,12 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, #endif /* CONFIG_IEEE80211W */ if (left > 0) { - wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", - __func__, left); + wpa_hexdump(MSG_DEBUG, + "wpa_parse_wpa_ie_rsn: ignore trailing bytes", + pos, left); } return 0; -#else /* CONFIG_NO_WPA2 */ - return -1; -#endif /* CONFIG_NO_WPA2 */ } @@ -643,7 +749,7 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, count = WPA_GET_LE16(pos); pos += 2; left -= 2; - if (count == 0 || left < count * WPA_SELECTOR_LEN) { + if (count == 0 || count > left / WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", __func__, count, left); return -4; @@ -664,7 +770,7 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, count = WPA_GET_LE16(pos); pos += 2; left -= 2; - if (count == 0 || left < count * WPA_SELECTOR_LEN) { + if (count == 0 || count > left / WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", __func__, count, left); return -6; @@ -687,8 +793,9 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, } if (left > 0) { - wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", - __func__, left); + wpa_hexdump(MSG_DEBUG, + "wpa_parse_wpa_ie_wpa: ignore trailing bytes", + pos, left); } return 0; @@ -812,15 +919,17 @@ void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, * * IEEE Std 802.11r-2008 - 8.5.1.5.5 */ -void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, - const u8 *sta_addr, const u8 *bssid, - const u8 *pmk_r1_name, - u8 *ptk, size_t ptk_len, u8 *ptk_name) +int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, + const u8 *sta_addr, const u8 *bssid, + const u8 *pmk_r1_name, + struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher) { u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; u8 *pos, hash[32]; const u8 *addr[6]; size_t len[6]; + u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; + size_t ptk_len; /* * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || @@ -836,7 +945,12 @@ void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, os_memcpy(pos, sta_addr, ETH_ALEN); pos += ETH_ALEN; - sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); + ptk->kck_len = wpa_kck_len(akmp); + ptk->kek_len = wpa_kek_len(akmp); + ptk->tk_len = wpa_cipher_key_len(cipher); + ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len; + + sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len); /* * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || @@ -857,6 +971,19 @@ void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, sha256_vector(6, addr, len, hash); os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); + + os_memcpy(ptk->kck, tmp, ptk->kck_len); + os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); + os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); + + wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len); + wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len); + wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len); + wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); + + os_memset(tmp, 0, sizeof(tmp)); + + return 0; } #endif /* CONFIG_IEEE80211R */ @@ -896,6 +1023,72 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, } +#ifdef CONFIG_SUITEB +/** + * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM + * @kck: Key confirmation key + * @kck_len: Length of kck in bytes + * @aa: Authenticator address + * @spa: Supplicant address + * @pmkid: Buffer for PMKID + * Returns: 0 on success, -1 on failure + * + * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy + * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA)) + */ +int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa, + const u8 *spa, u8 *pmkid) +{ + char *title = "PMK Name"; + const u8 *addr[3]; + const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; + unsigned char hash[SHA256_MAC_LEN]; + + addr[0] = (u8 *) title; + addr[1] = aa; + addr[2] = spa; + + if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0) + return -1; + os_memcpy(pmkid, hash, PMKID_LEN); + return 0; +} +#endif /* CONFIG_SUITEB */ + + +#ifdef CONFIG_SUITEB192 +/** + * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM + * @kck: Key confirmation key + * @kck_len: Length of kck in bytes + * @aa: Authenticator address + * @spa: Supplicant address + * @pmkid: Buffer for PMKID + * Returns: 0 on success, -1 on failure + * + * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy + * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA)) + */ +int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa, + const u8 *spa, u8 *pmkid) +{ + char *title = "PMK Name"; + const u8 *addr[3]; + const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; + unsigned char hash[SHA384_MAC_LEN]; + + addr[0] = (u8 *) title; + addr[1] = aa; + addr[2] = spa; + + if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0) + return -1; + os_memcpy(pmkid, hash, PMKID_LEN); + return 0; +} +#endif /* CONFIG_SUITEB192 */ + + /** * wpa_cipher_txt - Convert cipher suite to a text string * @cipher: Cipher suite (WPA_CIPHER_* enum) @@ -918,6 +1111,12 @@ const char * wpa_cipher_txt(int cipher) return "CCMP+TKIP"; case WPA_CIPHER_GCMP: return "GCMP"; + case WPA_CIPHER_GCMP_256: + return "GCMP-256"; + case WPA_CIPHER_CCMP_256: + return "CCMP-256"; + case WPA_CIPHER_GTK_NOT_USED: + return "GTK_NOT_USED"; default: return "UNKNOWN"; } @@ -959,12 +1158,52 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto) case WPA_KEY_MGMT_PSK_SHA256: return "WPA2-PSK-SHA256"; #endif /* CONFIG_IEEE80211W */ + case WPA_KEY_MGMT_WPS: + return "WPS"; + case WPA_KEY_MGMT_SAE: + return "SAE"; + case WPA_KEY_MGMT_FT_SAE: + return "FT-SAE"; + case WPA_KEY_MGMT_OSEN: + return "OSEN"; + case WPA_KEY_MGMT_IEEE8021X_SUITE_B: + return "WPA2-EAP-SUITE-B"; + case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: + return "WPA2-EAP-SUITE-B-192"; default: return "UNKNOWN"; } } +u32 wpa_akm_to_suite(int akm) +{ + if (akm & WPA_KEY_MGMT_FT_IEEE8021X) + return WLAN_AKM_SUITE_FT_8021X; + if (akm & WPA_KEY_MGMT_FT_PSK) + return WLAN_AKM_SUITE_FT_PSK; + if (akm & WPA_KEY_MGMT_IEEE8021X) + return WLAN_AKM_SUITE_8021X; + if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256) + return WLAN_AKM_SUITE_8021X_SHA256; + if (akm & WPA_KEY_MGMT_IEEE8021X) + return WLAN_AKM_SUITE_8021X; + if (akm & WPA_KEY_MGMT_PSK_SHA256) + return WLAN_AKM_SUITE_PSK_SHA256; + if (akm & WPA_KEY_MGMT_PSK) + return WLAN_AKM_SUITE_PSK; + if (akm & WPA_KEY_MGMT_CCKM) + return WLAN_AKM_SUITE_CCKM; + if (akm & WPA_KEY_MGMT_OSEN) + return WLAN_AKM_SUITE_OSEN; + if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B) + return WLAN_AKM_SUITE_8021X_SUITE_B; + if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + return WLAN_AKM_SUITE_8021X_SUITE_B_192; + return 0; +} + + int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len) @@ -1084,8 +1323,15 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) int wpa_cipher_key_len(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + case WPA_CIPHER_GCMP_256: + case WPA_CIPHER_BIP_GMAC_256: + case WPA_CIPHER_BIP_CMAC_256: + return 32; case WPA_CIPHER_CCMP: case WPA_CIPHER_GCMP: + case WPA_CIPHER_AES_128_CMAC: + case WPA_CIPHER_BIP_GMAC_128: return 16; case WPA_CIPHER_TKIP: return 32; @@ -1102,6 +1348,8 @@ int wpa_cipher_key_len(int cipher) int wpa_cipher_rsc_len(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + case WPA_CIPHER_GCMP_256: case WPA_CIPHER_CCMP: case WPA_CIPHER_GCMP: case WPA_CIPHER_TKIP: @@ -1118,6 +1366,10 @@ int wpa_cipher_rsc_len(int cipher) int wpa_cipher_to_alg(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + return WPA_ALG_CCMP_256; + case WPA_CIPHER_GCMP_256: + return WPA_ALG_GCMP_256; case WPA_CIPHER_CCMP: return WPA_ALG_CCMP; case WPA_CIPHER_GCMP: @@ -1127,6 +1379,14 @@ int wpa_cipher_to_alg(int cipher) case WPA_CIPHER_WEP104: case WPA_CIPHER_WEP40: return WPA_ALG_WEP; + case WPA_CIPHER_AES_128_CMAC: + return WPA_ALG_IGTK; + case WPA_CIPHER_BIP_GMAC_128: + return WPA_ALG_BIP_GMAC_128; + case WPA_CIPHER_BIP_GMAC_256: + return WPA_ALG_BIP_GMAC_256; + case WPA_CIPHER_BIP_CMAC_256: + return WPA_ALG_BIP_CMAC_256; } return WPA_ALG_NONE; } @@ -1134,7 +1394,9 @@ int wpa_cipher_to_alg(int cipher) int wpa_cipher_valid_pairwise(int cipher) { - return cipher == WPA_CIPHER_CCMP || + return cipher == WPA_CIPHER_CCMP_256 || + cipher == WPA_CIPHER_GCMP_256 || + cipher == WPA_CIPHER_CCMP || cipher == WPA_CIPHER_GCMP || cipher == WPA_CIPHER_TKIP; } @@ -1142,6 +1404,10 @@ int wpa_cipher_valid_pairwise(int cipher) u32 wpa_cipher_to_suite(int proto, int cipher) { + if (cipher & WPA_CIPHER_CCMP_256) + return RSN_CIPHER_SUITE_CCMP_256; + if (cipher & WPA_CIPHER_GCMP_256) + return RSN_CIPHER_SUITE_GCMP_256; if (cipher & WPA_CIPHER_CCMP) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); @@ -1159,58 +1425,252 @@ u32 wpa_cipher_to_suite(int proto, int cipher) if (cipher & WPA_CIPHER_NONE) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); + if (cipher & WPA_CIPHER_GTK_NOT_USED) + return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; + if (cipher & WPA_CIPHER_AES_128_CMAC) + return RSN_CIPHER_SUITE_AES_128_CMAC; + if (cipher & WPA_CIPHER_BIP_GMAC_128) + return RSN_CIPHER_SUITE_BIP_GMAC_128; + if (cipher & WPA_CIPHER_BIP_GMAC_256) + return RSN_CIPHER_SUITE_BIP_GMAC_256; + if (cipher & WPA_CIPHER_BIP_CMAC_256) + return RSN_CIPHER_SUITE_BIP_CMAC_256; return 0; } -int rsn_cipher_put_suites(u8 *pos, int ciphers) +int rsn_cipher_put_suites(u8 *start, int ciphers) { - int num_suites = 0; + u8 *pos = start; + if (ciphers & WPA_CIPHER_CCMP_256) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256); + pos += RSN_SELECTOR_LEN; + } + if (ciphers & WPA_CIPHER_GCMP_256) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256); + pos += RSN_SELECTOR_LEN; + } if (ciphers & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; - num_suites++; } if (ciphers & WPA_CIPHER_GCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); pos += RSN_SELECTOR_LEN; - num_suites++; } if (ciphers & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; - num_suites++; } if (ciphers & WPA_CIPHER_NONE) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); pos += RSN_SELECTOR_LEN; - num_suites++; } - return num_suites; + return (pos - start) / RSN_SELECTOR_LEN; } -int wpa_cipher_put_suites(u8 *pos, int ciphers) +int wpa_cipher_put_suites(u8 *start, int ciphers) { - int num_suites = 0; + u8 *pos = start; if (ciphers & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); pos += WPA_SELECTOR_LEN; - num_suites++; } if (ciphers & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); pos += WPA_SELECTOR_LEN; - num_suites++; } if (ciphers & WPA_CIPHER_NONE) { RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); pos += WPA_SELECTOR_LEN; - num_suites++; } - return num_suites; + return (pos - start) / RSN_SELECTOR_LEN; +} + + +int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) +{ + if (ciphers & WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (ciphers & WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; + if (ciphers & WPA_CIPHER_CCMP) + return WPA_CIPHER_CCMP; + if (ciphers & WPA_CIPHER_GCMP) + return WPA_CIPHER_GCMP; + if (ciphers & WPA_CIPHER_TKIP) + return WPA_CIPHER_TKIP; + if (none_allowed && (ciphers & WPA_CIPHER_NONE)) + return WPA_CIPHER_NONE; + return -1; +} + + +int wpa_pick_group_cipher(int ciphers) +{ + if (ciphers & WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (ciphers & WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; + if (ciphers & WPA_CIPHER_CCMP) + return WPA_CIPHER_CCMP; + if (ciphers & WPA_CIPHER_GCMP) + return WPA_CIPHER_GCMP; + if (ciphers & WPA_CIPHER_GTK_NOT_USED) + return WPA_CIPHER_GTK_NOT_USED; + if (ciphers & WPA_CIPHER_TKIP) + return WPA_CIPHER_TKIP; + if (ciphers & WPA_CIPHER_WEP104) + return WPA_CIPHER_WEP104; + if (ciphers & WPA_CIPHER_WEP40) + return WPA_CIPHER_WEP40; + return -1; +} + + +int wpa_parse_cipher(const char *value) +{ + int val = 0, last; + char *start, *end, *buf; + + buf = os_strdup(value); + if (buf == NULL) + return -1; + start = buf; + + while (*start != '\0') { + while (*start == ' ' || *start == '\t') + start++; + if (*start == '\0') + break; + end = start; + while (*end != ' ' && *end != '\t' && *end != '\0') + end++; + last = *end == '\0'; + *end = '\0'; + if (os_strcmp(start, "CCMP-256") == 0) + val |= WPA_CIPHER_CCMP_256; + else if (os_strcmp(start, "GCMP-256") == 0) + val |= WPA_CIPHER_GCMP_256; + else if (os_strcmp(start, "CCMP") == 0) + val |= WPA_CIPHER_CCMP; + else if (os_strcmp(start, "GCMP") == 0) + val |= WPA_CIPHER_GCMP; + else if (os_strcmp(start, "TKIP") == 0) + val |= WPA_CIPHER_TKIP; + else if (os_strcmp(start, "WEP104") == 0) + val |= WPA_CIPHER_WEP104; + else if (os_strcmp(start, "WEP40") == 0) + val |= WPA_CIPHER_WEP40; + else if (os_strcmp(start, "NONE") == 0) + val |= WPA_CIPHER_NONE; + else if (os_strcmp(start, "GTK_NOT_USED") == 0) + val |= WPA_CIPHER_GTK_NOT_USED; + else { + os_free(buf); + return -1; + } + + if (last) + break; + start = end + 1; + } + os_free(buf); + + return val; +} + + +int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) +{ + char *pos = start; + int ret; + + if (ciphers & WPA_CIPHER_CCMP_256) { + ret = os_snprintf(pos, end - pos, "%sCCMP-256", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_GCMP_256) { + ret = os_snprintf(pos, end - pos, "%sGCMP-256", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_CCMP) { + ret = os_snprintf(pos, end - pos, "%sCCMP", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_GCMP) { + ret = os_snprintf(pos, end - pos, "%sGCMP", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_TKIP) { + ret = os_snprintf(pos, end - pos, "%sTKIP", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_WEP104) { + ret = os_snprintf(pos, end - pos, "%sWEP104", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_WEP40) { + ret = os_snprintf(pos, end - pos, "%sWEP40", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_NONE) { + ret = os_snprintf(pos, end - pos, "%sNONE", + pos == start ? "" : delim); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + return pos - start; +} + + +int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise) +{ + int pairwise = 0; + + /* Select group cipher based on the enabled pairwise cipher suites */ + if (wpa & 1) + pairwise |= wpa_pairwise; + if (wpa & 2) + pairwise |= rsn_pairwise; + + if (pairwise & WPA_CIPHER_TKIP) + return WPA_CIPHER_TKIP; + if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP) + return WPA_CIPHER_GCMP; + if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP | + WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; + if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP | + WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; + return WPA_CIPHER_CCMP; } |