]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SAE-PK: Update SAE confirm IE design
authorJouni Malinen <jouni@codeaurora.org>
Tue, 9 Jun 2020 21:59:09 +0000 (00:59 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 10 Jun 2020 09:47:07 +0000 (12:47 +0300)
Move the FILS Public Key element and the FILS Key Confirmation element
to be separate IEs instead of being encapsulated within the SAE-PK
element. This is also removing the unnecessary length field for the
fixed-length EncryptedModifier.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ieee802_11_defs.h
src/common/sae_pk.c

index 5bfaece5a3892280e4359491e9f9b0c5c6446936..9cd631783dab9910fda75e3793fca00921375aed 100644 (file)
@@ -136,6 +136,10 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                case DPP_CC_OUI_TYPE:
                        /* DPP Configurator Connectivity element */
                        break;
+               case SAE_PK_OUI_TYPE:
+                       elems->sae_pk = pos + 4;
+                       elems->sae_pk_len = elen - 4;
+                       break;
                default:
                        wpa_printf(MSG_MSGDUMP, "Unknown WFA "
                                   "information element ignored "
index 4abe468ec4396db93a0cb67d780a304e7aefd1dc..0ddba06924c2f505abc8e89ffb013972d11d6ef8 100644 (file)
@@ -114,6 +114,7 @@ struct ieee802_11_elems {
        const u8 *he_operation;
        const u8 *short_ssid_list;
        const u8 *he_6ghz_band_cap;
+       const u8 *sae_pk;
 
        u8 ssid_len;
        u8 supp_rates_len;
@@ -166,6 +167,7 @@ struct ieee802_11_elems {
        u8 he_capabilities_len;
        u8 he_operation_len;
        u8 short_ssid_list_len;
+       u8 sae_pk_len;
 
        struct mb_ies_info mb_ies;
        struct frag_ies_info frag_ies;
index 3fc4200a07080546be78973fb33a05b1caa8c493..b7c69478dff84f50751c99128771a504c4e9afac 100644 (file)
@@ -1323,6 +1323,7 @@ struct ieee80211_ampe_ie {
 #define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
 #define DPP_CC_OUI_TYPE 0x1e
 #define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
+#define SAE_PK_OUI_TYPE 0x1f
 
 #define MULTI_AP_SUB_ELEM_TYPE 0x06
 #define MULTI_AP_TEAR_DOWN BIT(4)
index 5ccd601c2b33445f2097e0fea285de7e199de50d..b294312efde642d431da45c626a5feb006e82675 100644 (file)
@@ -375,8 +375,8 @@ fail:
 int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
 {
        struct sae_temporary_data *tmp = sae->tmp;
-       struct wpabuf *elem = NULL, *sig = NULL;
-       size_t extra;
+       struct wpabuf *sig = NULL;
+       size_t need;
        int ret = -1;
        u8 *encr_mod;
        size_t encr_mod_len;
@@ -425,55 +425,50 @@ int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
                goto fail;
        wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
 
-       elem = wpabuf_alloc(1500 + wpabuf_len(sig));
-       if (!elem)
-               goto fail;
+       /* TODO: fragmentation if any of the elements needs it for a group
+        * using sufficiently large primes (none of the currently supported
+        * ones do) */
 
-       /* EncryptedModifier = AES-SIV-Q(M); no AAD */
        encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
-       wpabuf_put_u8(elem, encr_mod_len);
-       encr_mod = wpabuf_put(elem, encr_mod_len);
-       if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
-                           wpabuf_head(pk->m), wpabuf_len(pk->m),
-                           0, NULL, NULL, encr_mod) < 0)
+       need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
+               6 + encr_mod_len;
+       if (wpabuf_tailroom(buf) < need) {
+               wpa_printf(MSG_INFO,
+                          "SAE-PK: No room in message buffer for SAE-PK elements (%zu < %zu)",
+                          wpabuf_tailroom(buf), need);
                goto fail;
-       wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
-                   encr_mod, encr_mod_len);
+       }
 
        /* FILS Public Key element */
-       wpabuf_put_u8(elem, WLAN_EID_EXTENSION);
-       wpabuf_put_u8(elem, 2 + wpabuf_len(pk->pubkey));
-       wpabuf_put_u8(elem, WLAN_EID_EXT_FILS_PUBLIC_KEY);
-       wpabuf_put_u8(elem, 2); /* Key Type: ECDSA public key */
-       wpabuf_put_buf(elem, pk->pubkey);
+       wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+       wpabuf_put_u8(buf, 2 + wpabuf_len(pk->pubkey));
+       wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_PUBLIC_KEY);
+       wpabuf_put_u8(buf, 2); /* Key Type: ECDSA public key */
+       wpabuf_put_buf(buf, pk->pubkey);
 
        /* FILS Key Confirmation element (KeyAuth) */
-       wpabuf_put_u8(elem, WLAN_EID_EXTENSION);
-       wpabuf_put_u8(elem, 1 + wpabuf_len(sig));
-       wpabuf_put_u8(elem, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+       wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+       wpabuf_put_u8(buf, 1 + wpabuf_len(sig));
+       wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
        /* KeyAuth = Sig_AP(eleAP || eleSTA || scaAP || scaSTA || M || K_AP ||
         *                  AP-BSSID || STA-MAC) */
-       wpabuf_put_buf(elem, sig);
-
-       /* TODO: fragmentation */
-       extra = 6; /* Vendor specific element header */
-
-       if (wpabuf_tailroom(elem) < extra + wpabuf_len(buf)) {
-               wpa_printf(MSG_INFO,
-                          "SAE-PK: No room in message buffer for SAE-PK element (%zu < %zu)",
-                          wpabuf_tailroom(buf), extra + wpabuf_len(buf));
-               goto fail;
-       }
+       wpabuf_put_buf(buf, sig);
 
        /* SAE-PK element */
        wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
-       wpabuf_put_u8(buf, 4 + wpabuf_len(elem));
+       wpabuf_put_u8(buf, 4 + encr_mod_len);
        wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
-       wpabuf_put_buf(buf, elem);
+       /* EncryptedModifier = AES-SIV-Q(M); no AAD */
+       encr_mod = wpabuf_put(buf, encr_mod_len);
+       if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
+                           wpabuf_head(pk->m), wpabuf_len(pk->m),
+                           0, NULL, NULL, encr_mod) < 0)
+               goto fail;
+       wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
+                   encr_mod, encr_mod_len);
 
        ret = 0;
 fail:
-       wpabuf_free(elem);
        wpabuf_free(sig);
        return ret;
 
@@ -569,14 +564,15 @@ static bool sae_pk_valid_fingerprint(struct sae_data *sae,
 int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
 {
        struct sae_temporary_data *tmp = sae->tmp;
-       const u8 *sae_pk, *pos, *end, *encr_mod, *k_ap, *key_auth;
+       const u8 *k_ap;
        u8 m[SAE_PK_M_LEN];
-       size_t k_ap_len, key_auth_len;
+       size_t k_ap_len;
        struct crypto_ec_key *key;
        int res;
        u8 hash[SAE_MAX_HASH_LEN];
        size_t hash_len;
        int group;
+       struct ieee802_11_elems elems;
 
        if (!tmp)
                return -1;
@@ -597,71 +593,29 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
        }
 
        wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
-       sae_pk = get_vendor_ie(ies, ies_len, SAE_PK_IE_VENDOR_TYPE);
-       if (!sae_pk) {
-               wpa_printf(MSG_INFO, "SAE-PK: No SAE-PK element included");
+       if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+               wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
                return -1;
        }
-       /* TODO: Fragment reassembly */
-       pos = sae_pk + 2;
-       end = pos + sae_pk[1];
-
-       if (end - pos < 4 + 1 + SAE_PK_M_LEN + AES_BLOCK_SIZE) {
-               wpa_printf(MSG_INFO,
-                          "SAE-PK: No room for EncryptedModifier in SAE-PK element");
-               return -1;
-       }
-       pos += 4;
-       if (*pos != SAE_PK_M_LEN + AES_BLOCK_SIZE) {
+       if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
                wpa_printf(MSG_INFO,
-                          "SAE-PK: Unexpected EncryptedModifier length %u",
-                          *pos);
+                          "SAE-PK: Not all mandatory IEs included in confirm");
                return -1;
        }
-       pos++;
-       encr_mod = pos;
-       pos += SAE_PK_M_LEN + AES_BLOCK_SIZE;
 
-       if (end - pos < 4 || pos[0] != WLAN_EID_EXTENSION || pos[1] < 2 ||
-           pos[1] > end - pos - 2 ||
-           pos[2] != WLAN_EID_EXT_FILS_PUBLIC_KEY) {
-               wpa_printf(MSG_INFO,
-                          "SAE-PK: No FILS Public Key element in SAE-PK element");
-               return -1;
-       }
-       if (pos[3] != 2) {
-               wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
-                          pos[3]);
-               return -1;
-       }
-       k_ap_len = pos[1] - 2;
-       pos += 4;
-       k_ap = pos;
-       pos += k_ap_len;
-
-       if (end - pos < 4 || pos[0] != WLAN_EID_EXTENSION || pos[1] < 1 ||
-           pos[1] > end - pos - 2 ||
-           pos[2] != WLAN_EID_EXT_FILS_KEY_CONFIRM) {
+       /* TODO: Fragment reassembly */
+
+       if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
                wpa_printf(MSG_INFO,
-                          "SAE-PK: No FILS Key Confirm element in SAE-PK element");
+                          "SAE-PK: No room for EncryptedModifier in SAE-PK element");
                return -1;
        }
-       key_auth_len = pos[1] - 1;
-       pos += 3;
-       key_auth = pos;
-       pos += key_auth_len;
-
-       if (pos < end) {
-               wpa_hexdump(MSG_DEBUG,
-                           "SAE-PK: Extra data at the end of SAE-PK element",
-                           pos, end - pos);
-       }
 
        wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
-                   encr_mod, SAE_PK_M_LEN + AES_BLOCK_SIZE);
+                   elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
 
        if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
-                           encr_mod, SAE_PK_M_LEN + AES_BLOCK_SIZE,
+                           elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE,
                            0, NULL, NULL, m) < 0) {
                wpa_printf(MSG_INFO,
                           "SAE-PK: Failed to decrypt EncryptedModifier");
@@ -669,6 +623,13 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
        }
        wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN);
 
+       if (elems.fils_pk[0] != 2) {
+               wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
+                          elems.fils_pk[0]);
+               return -1;
+       }
+       k_ap_len = elems.fils_pk_len - 1;
+       k_ap = elems.fils_pk + 1;
        wpa_hexdump(MSG_DEBUG, "SAE-PK: Received K_AP", k_ap, k_ap_len);
        /* TODO: Check against the public key, if one is stored in the network
         * profile */
@@ -687,7 +648,7 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
        }
 
        wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth",
-                   key_auth, key_auth_len);
+                   elems.fils_key_confirm, elems.fils_key_confirm_len);
 
        hash_len = sae_group_2_hash_len(group);
        if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN,
@@ -697,7 +658,8 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
        }
 
        res = crypto_ec_key_verify_signature(key, hash, hash_len,
-                                            key_auth, key_auth_len);
+                                            elems.fils_key_confirm,
+                                            elems.fils_key_confirm_len);
        crypto_ec_key_deinit(key);
 
        if (res != 1) {