SAE-PK: Update SAE confirm IE design

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>
This commit is contained in:
Jouni Malinen 2020-06-10 00:59:09 +03:00 committed by Jouni Malinen
parent f0704e7273
commit a77d6d2203
4 changed files with 67 additions and 98 deletions

View file

@ -136,6 +136,10 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
case DPP_CC_OUI_TYPE: case DPP_CC_OUI_TYPE:
/* DPP Configurator Connectivity element */ /* DPP Configurator Connectivity element */
break; break;
case SAE_PK_OUI_TYPE:
elems->sae_pk = pos + 4;
elems->sae_pk_len = elen - 4;
break;
default: default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA " wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored " "information element ignored "

View file

@ -114,6 +114,7 @@ struct ieee802_11_elems {
const u8 *he_operation; const u8 *he_operation;
const u8 *short_ssid_list; const u8 *short_ssid_list;
const u8 *he_6ghz_band_cap; const u8 *he_6ghz_band_cap;
const u8 *sae_pk;
u8 ssid_len; u8 ssid_len;
u8 supp_rates_len; u8 supp_rates_len;
@ -166,6 +167,7 @@ struct ieee802_11_elems {
u8 he_capabilities_len; u8 he_capabilities_len;
u8 he_operation_len; u8 he_operation_len;
u8 short_ssid_list_len; u8 short_ssid_list_len;
u8 sae_pk_len;
struct mb_ies_info mb_ies; struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies; struct frag_ies_info frag_ies;

View file

@ -1323,6 +1323,7 @@ struct ieee80211_ampe_ie {
#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e #define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
#define DPP_CC_OUI_TYPE 0x1e #define DPP_CC_OUI_TYPE 0x1e
#define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f #define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
#define SAE_PK_OUI_TYPE 0x1f
#define MULTI_AP_SUB_ELEM_TYPE 0x06 #define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4) #define MULTI_AP_TEAR_DOWN BIT(4)

View file

@ -375,8 +375,8 @@ fail:
int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf) int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
{ {
struct sae_temporary_data *tmp = sae->tmp; struct sae_temporary_data *tmp = sae->tmp;
struct wpabuf *elem = NULL, *sig = NULL; struct wpabuf *sig = NULL;
size_t extra; size_t need;
int ret = -1; int ret = -1;
u8 *encr_mod; u8 *encr_mod;
size_t encr_mod_len; size_t encr_mod_len;
@ -425,14 +425,41 @@ int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
goto fail; goto fail;
wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig); wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
elem = wpabuf_alloc(1500 + wpabuf_len(sig)); /* TODO: fragmentation if any of the elements needs it for a group
if (!elem) * using sufficiently large primes (none of the currently supported
goto fail; * ones do) */
/* EncryptedModifier = AES-SIV-Q(M); no AAD */
encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE; encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
wpabuf_put_u8(elem, encr_mod_len); need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
encr_mod = wpabuf_put(elem, encr_mod_len); 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;
}
/* FILS Public Key element */
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(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(buf, sig);
/* SAE-PK element */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(buf, 4 + encr_mod_len);
wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
/* EncryptedModifier = AES-SIV-Q(M); no AAD */
encr_mod = wpabuf_put(buf, encr_mod_len);
if (aes_siv_encrypt(tmp->kek, tmp->kek_len, if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
wpabuf_head(pk->m), wpabuf_len(pk->m), wpabuf_head(pk->m), wpabuf_len(pk->m),
0, NULL, NULL, encr_mod) < 0) 0, NULL, NULL, encr_mod) < 0)
@ -440,40 +467,8 @@ int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier", wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
encr_mod, encr_mod_len); 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);
/* 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);
/* 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;
}
/* SAE-PK element */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(buf, 4 + wpabuf_len(elem));
wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
wpabuf_put_buf(buf, elem);
ret = 0; ret = 0;
fail: fail:
wpabuf_free(elem);
wpabuf_free(sig); wpabuf_free(sig);
return ret; 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) int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
{ {
struct sae_temporary_data *tmp = sae->tmp; 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]; u8 m[SAE_PK_M_LEN];
size_t k_ap_len, key_auth_len; size_t k_ap_len;
struct crypto_ec_key *key; struct crypto_ec_key *key;
int res; int res;
u8 hash[SAE_MAX_HASH_LEN]; u8 hash[SAE_MAX_HASH_LEN];
size_t hash_len; size_t hash_len;
int group; int group;
struct ieee802_11_elems elems;
if (!tmp) if (!tmp)
return -1; 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); 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 (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
if (!sae_pk) { wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
wpa_printf(MSG_INFO, "SAE-PK: No SAE-PK element included"); return -1;
}
if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
wpa_printf(MSG_INFO,
"SAE-PK: Not all mandatory IEs included in confirm");
return -1; 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) { /* TODO: Fragment reassembly */
if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
wpa_printf(MSG_INFO, wpa_printf(MSG_INFO,
"SAE-PK: No room for EncryptedModifier in SAE-PK element"); "SAE-PK: No room for EncryptedModifier in SAE-PK element");
return -1; return -1;
} }
pos += 4;
if (*pos != SAE_PK_M_LEN + AES_BLOCK_SIZE) {
wpa_printf(MSG_INFO,
"SAE-PK: Unexpected EncryptedModifier length %u",
*pos);
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) {
wpa_printf(MSG_INFO,
"SAE-PK: No FILS Key Confirm element 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", 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, 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) { 0, NULL, NULL, m) < 0) {
wpa_printf(MSG_INFO, wpa_printf(MSG_INFO,
"SAE-PK: Failed to decrypt EncryptedModifier"); "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); 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); 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 /* TODO: Check against the public key, if one is stored in the network
* profile */ * 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", 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); hash_len = sae_group_2_hash_len(group);
if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN, 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, 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); crypto_ec_key_deinit(key);
if (res != 1) { if (res != 1) {