]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OWE: Support DH groups 20 (NIST P-384) and 21 (NIST P-521) in AP mode
authorJouni Malinen <jouni@qca.qualcomm.com>
Sun, 8 Oct 2017 13:37:32 +0000 (16:37 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 8 Oct 2017 14:12:35 +0000 (17:12 +0300)
This extends OWE support in hostapd to allow DH groups 20 and 21 to be
used in addition to the mandatory group 19 (NIST P-256).

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
hostapd/Android.mk
hostapd/Makefile
src/ap/ieee802_11.c
src/ap/sta_info.c
src/ap/sta_info.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_glue.c
wpa_supplicant/ibss_rsn.c
wpa_supplicant/mesh_rsn.c

index 0e781a31429e8bf98a6c1374b6938dd39fb6bae4..a1153b36f7568aa149d951de0c6e1140117f2301 100644 (file)
@@ -274,6 +274,11 @@ ifdef CONFIG_OWE
 L_CFLAGS += -DCONFIG_OWE
 NEED_ECC=y
 NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+NEED_SHA512=y
 endif
 
 ifdef CONFIG_FILS
index c54de3917369d77216d0eb5eed4a1d006d983f3a..a00e11c622990ba437bb41576ec8b8b225696968 100644 (file)
@@ -318,6 +318,11 @@ ifdef CONFIG_OWE
 CFLAGS += -DCONFIG_OWE
 NEED_ECC=y
 NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+NEED_SHA512=y
 endif
 
 ifdef CONFIG_FILS
index e4daec2e17d853eefcabe738aef3f3b76c5dafa2..25d8e3b2de47333eddc343b68b81ea2042d8d09f 100644 (file)
@@ -14,6 +14,8 @@
 #include "utils/eloop.h"
 #include "crypto/crypto.h"
 #include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
 #include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -2131,21 +2133,32 @@ static u16 owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh,
 {
        struct wpabuf *secret, *pub, *hkey;
        int res;
-       u8 prk[SHA256_MAC_LEN], pmkid[SHA256_MAC_LEN];
+       u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
        const char *info = "OWE Key Generation";
        const u8 *addr[2];
        size_t len[2];
-
-       if (WPA_GET_LE16(owe_dh) != OWE_DH_GROUP)
+       u16 group;
+       size_t hash_len, prime_len;
+
+       group = WPA_GET_LE16(owe_dh);
+       if (group == 19)
+               prime_len = 32;
+       else if (group == 20)
+               prime_len = 48;
+       else if (group == 21)
+               prime_len = 66;
+       else
                return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
 
        crypto_ecdh_deinit(sta->owe_ecdh);
-       sta->owe_ecdh = crypto_ecdh_init(OWE_DH_GROUP);
+       sta->owe_ecdh = crypto_ecdh_init(group);
        if (!sta->owe_ecdh)
                return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+       sta->owe_group = group;
 
        secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
                                         owe_dh_len - 2);
+       secret = wpabuf_zeropad(secret, prime_len);
        if (!secret) {
                wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2165,8 +2178,22 @@ static u16 owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh,
        len[0] = owe_dh_len - 2;
        addr[1] = wpabuf_head(pub);
        len[1] = wpabuf_len(pub);
-       res = sha256_vector(2, addr, len, pmkid);
-       if (res < 0) {
+       if (group == 19) {
+               res = sha256_vector(2, addr, len, pmkid);
+               hash_len = SHA256_MAC_LEN;
+       } else if (group == 20) {
+               res = sha384_vector(2, addr, len, pmkid);
+               hash_len = SHA384_MAC_LEN;
+       } else if (group == 21) {
+               res = sha512_vector(2, addr, len, pmkid);
+               hash_len = SHA512_MAC_LEN;
+       } else {
+               wpabuf_free(pub);
+               wpabuf_clear_free(secret);
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+       pub = wpabuf_zeropad(pub, prime_len);
+       if (res < 0 || !pub) {
                wpabuf_free(pub);
                wpabuf_clear_free(secret);
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2182,35 +2209,50 @@ static u16 owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh,
        wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
        wpabuf_put_buf(hkey, pub); /* A */
        wpabuf_free(pub);
-       wpabuf_put_le16(hkey, OWE_DH_GROUP); /* group */
-       res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
-                         wpabuf_head(secret), wpabuf_len(secret), prk);
+       wpabuf_put_le16(hkey, group); /* group */
+       if (group == 19)
+               res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
+                                 wpabuf_head(secret), wpabuf_len(secret), prk);
+       else if (group == 20)
+               res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
+                                 wpabuf_head(secret), wpabuf_len(secret), prk);
+       else if (group == 21)
+               res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
+                                 wpabuf_head(secret), wpabuf_len(secret), prk);
        wpabuf_clear_free(hkey);
        wpabuf_clear_free(secret);
        if (res < 0)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-       wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, SHA256_MAC_LEN);
+       wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
 
        /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
 
        os_free(sta->owe_pmk);
-       sta->owe_pmk = os_malloc(PMK_LEN);
+       sta->owe_pmk = os_malloc(hash_len);
        if (!sta->owe_pmk) {
-               os_memset(prk, 0, SHA256_MAC_LEN);
+               os_memset(prk, 0, SHA512_MAC_LEN);
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        }
 
-       res = hmac_sha256_kdf(prk, SHA256_MAC_LEN, NULL, (const u8 *) info,
-                             os_strlen(info), sta->owe_pmk, PMK_LEN);
-       os_memset(prk, 0, SHA256_MAC_LEN);
+       if (group == 19)
+               res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
+                                     os_strlen(info), sta->owe_pmk, hash_len);
+       else if (group == 20)
+               res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
+                                     os_strlen(info), sta->owe_pmk, hash_len);
+       else if (group == 21)
+               res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
+                                     os_strlen(info), sta->owe_pmk, hash_len);
+       os_memset(prk, 0, SHA512_MAC_LEN);
        if (res < 0) {
                os_free(sta->owe_pmk);
                sta->owe_pmk = NULL;
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        }
+       sta->owe_pmk_len = hash_len;
 
-       wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, PMK_LEN);
+       wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
        wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
        /* TODO: Add PMKSA cache entry */
 
@@ -2822,7 +2864,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
                *p++ = WLAN_EID_EXTENSION; /* Element ID */
                *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
                *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
-               WPA_PUT_LE16(p, OWE_DH_GROUP);
+               WPA_PUT_LE16(p, sta->owe_group);
                p += 2;
                os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
                p += wpabuf_len(pub);
index 1e21282c9484b2bbc413edf2fbc1946f206a26ae..b1fde3cf932ff4bc0c445bcbb4f345e5a01221f8 100644 (file)
@@ -353,7 +353,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 #endif /* CONFIG_FILS */
 
 #ifdef CONFIG_OWE
-       bin_clear_free(sta->owe_pmk, PMK_LEN);
+       bin_clear_free(sta->owe_pmk, sta->owe_pmk_len);
        crypto_ecdh_deinit(sta->owe_ecdh);
 #endif /* CONFIG_OWE */
 
index 271128b9e05511b9302ebfb1e75321d8e4d520df..efbbcebb36b4dd06f5a808473fa46678b91a4e40 100644 (file)
@@ -246,7 +246,9 @@ struct sta_info {
 
 #ifdef CONFIG_OWE
        u8 *owe_pmk;
+       size_t owe_pmk_len;
        struct crypto_ecdh *owe_ecdh;
+       u16 owe_group;
 #endif /* CONFIG_OWE */
 };
 
index aca687c70b264ac3cf101a8b539e57d50e9fe3c7..5a37a09cc0fefbe20cc72f68b6ba7209a8ce79f0 100644 (file)
@@ -110,12 +110,12 @@ static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
 static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
                                          const u8 *addr,
                                          const u8 *p2p_dev_addr,
-                                         const u8 *prev_psk)
+                                         const u8 *prev_psk, size_t *psk_len)
 {
        if (wpa_auth->cb->get_psk == NULL)
                return NULL;
        return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
-                                    prev_psk);
+                                    prev_psk, psk_len);
 }
 
 
@@ -848,17 +848,16 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
        struct wpa_ptk PTK;
        int ok = 0;
        const u8 *pmk = NULL;
-       unsigned int pmk_len;
+       size_t pmk_len;
 
        os_memset(&PTK, 0, sizeof(PTK));
        for (;;) {
                if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
                    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
                        pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
-                                              sm->p2p_dev_addr, pmk);
+                                              sm->p2p_dev_addr, pmk, &pmk_len);
                        if (pmk == NULL)
                                break;
-                       pmk_len = PMK_LEN;
                } else {
                        pmk = sm->PMK;
                        pmk_len = sm->pmk_len;
@@ -2020,11 +2019,14 @@ SM_STATE(WPA_PTK, INITPMK)
 SM_STATE(WPA_PTK, INITPSK)
 {
        const u8 *psk;
+       size_t psk_len;
+
        SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
-       psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
+       psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
+                              &psk_len);
        if (psk) {
-               os_memcpy(sm->PMK, psk, PMK_LEN);
-               sm->pmk_len = PMK_LEN;
+               os_memcpy(sm->PMK, psk, psk_len);
+               sm->pmk_len = psk_len;
 #ifdef CONFIG_IEEE80211R_AP
                os_memcpy(sm->xxkey, psk, PMK_LEN);
                sm->xxkey_len = PMK_LEN;
@@ -2619,7 +2621,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        struct wpa_ptk PTK;
        int ok = 0, psk_found = 0;
        const u8 *pmk = NULL;
-       unsigned int pmk_len;
+       size_t pmk_len;
        int ft;
        const u8 *eapol_key_ie, *key_data, *mic;
        u16 key_data_length;
@@ -2642,11 +2644,10 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
                    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
                        pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
-                                              sm->p2p_dev_addr, pmk);
+                                              sm->p2p_dev_addr, pmk, &pmk_len);
                        if (pmk == NULL)
                                break;
                        psk_found = 1;
-                       pmk_len = PMK_LEN;
                } else {
                        pmk = sm->PMK;
                        pmk_len = sm->pmk_len;
@@ -3169,7 +3170,7 @@ SM_STEP(WPA_PTK)
                break;
        case WPA_PTK_INITPSK:
                if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
-                                    NULL)) {
+                                    NULL, NULL)) {
                        SM_ENTER(WPA_PTK, PTKSTART);
 #ifdef CONFIG_SAE
                } else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
index 9ef660af128376336ffebdef4cfc2e6f72065322..49aadee72a815d7e0fdb1171da84b68e31d96c9a 100644 (file)
@@ -236,7 +236,7 @@ struct wpa_auth_callbacks {
                          int value);
        int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
        const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
-                             const u8 *prev_psk);
+                             const u8 *prev_psk, size_t *psk_len);
        int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
        int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
                       const u8 *addr, int idx, u8 *key, size_t key_len);
index dd99db70adc0efc30e4f4d0d043e77c024c6bb32..0ca27f8b9af64fcc02e37f9b0ff7bd3169bd7551 100644 (file)
@@ -443,7 +443,7 @@ static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth,
        if (wpa_auth->cb->get_psk == NULL)
                return NULL;
        return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
-                                    prev_psk);
+                                    prev_psk, NULL);
 }
 
 
index 5a09fb392fff3a0fa2c35793e75c430c151664dd..a44fd90fb9365a1fe80be0c301f6cd7e2578f6c7 100644 (file)
@@ -238,12 +238,15 @@ static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
 
 static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
                                           const u8 *p2p_dev_addr,
-                                          const u8 *prev_psk)
+                                          const u8 *prev_psk, size_t *psk_len)
 {
        struct hostapd_data *hapd = ctx;
        struct sta_info *sta = ap_get_sta(hapd, addr);
        const u8 *psk;
 
+       if (psk_len)
+               *psk_len = PMK_LEN;
+
 #ifdef CONFIG_SAE
        if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
                if (!sta->sae || prev_psk)
@@ -259,8 +262,11 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
 
 #ifdef CONFIG_OWE
        if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
-           sta && sta->owe_pmk)
+           sta && sta->owe_pmk) {
+               if (psk_len)
+                       *psk_len = sta->owe_pmk_len;
                return sta->owe_pmk;
+       }
 #endif /* CONFIG_OWE */
 
        psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
index 9b6c41698fca96101bdfdb3ec55a6f0841ec82ba..00919d14a55e97949c6e26a5794a411ef211445c 100644 (file)
@@ -259,9 +259,13 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level,
 
 
 static const u8 * auth_get_psk(void *ctx, const u8 *addr,
-                              const u8 *p2p_dev_addr, const u8 *prev_psk)
+                              const u8 *p2p_dev_addr, const u8 *prev_psk,
+                              size_t *psk_len)
 {
        struct ibss_rsn *ibss_rsn = ctx;
+
+       if (psk_len)
+               *psk_len = PMK_LEN;
        wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
                   __func__, MAC2STR(addr), prev_psk);
        if (prev_psk)
index 628382cbfb70e68a01dd4a7d225edeff2277decc..90137c444705301816be6f2cc5613c967a44edc7 100644 (file)
@@ -75,12 +75,15 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level,
 
 
 static const u8 *auth_get_psk(void *ctx, const u8 *addr,
-                             const u8 *p2p_dev_addr, const u8 *prev_psk)
+                             const u8 *p2p_dev_addr, const u8 *prev_psk,
+                             size_t *psk_len)
 {
        struct mesh_rsn *mesh_rsn = ctx;
        struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
        struct sta_info *sta = ap_get_sta(hapd, addr);
 
+       if (psk_len)
+               *psk_len = PMK_LEN;
        wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
                   __func__, MAC2STR(addr), prev_psk);