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:
parent
f0704e7273
commit
a77d6d2203
4 changed files with 67 additions and 98 deletions
|
@ -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 "
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue