ieee80211: Dissect decrypted FT BSS Transition GTK subelem

The GTK key provided in FT BSS Transition IE is encrypted. Update
dot11decrypt engine to return the decrypted key for dissection.

Change-Id: Id31a8cf77e12568f2e449470822a64792895673c
This commit is contained in:
Mikael Kanstrup 2021-03-27 10:44:49 +01:00 committed by Wireshark GitLab Utility
parent 1f9ff3f547
commit d08fa84025
3 changed files with 97 additions and 23 deletions

View File

@ -1834,7 +1834,9 @@ Dot11DecryptRsna4WHandshake(
gint
Dot11DecryptScanFtAssocForKeys(
const PDOT11DECRYPT_CONTEXT ctx,
const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed)
const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed,
guint8 *decrypted_gtk, size_t *decrypted_len,
DOT11DECRYPT_KEY_ITEM* used_key)
{
DOT11DECRYPT_SEC_ASSOCIATION_ID id;
@ -1981,14 +1983,19 @@ Dot11DecryptScanFtAssocForKeys(
return DOT11DECRYPT_RET_UNSUCCESS;
}
Dot11DecryptCopyBroadcastKey(ctx, decrypted_key, decrypted_key_len, &id);
*decrypted_len = decrypted_key_len;
memcpy(decrypted_gtk, decrypted_key, decrypted_key_len);
}
Dot11DecryptCopyKey(sa, used_key);
return DOT11DECRYPT_RET_SUCCESS_HANDSHAKE;
}
#else
gint
Dot11DecryptScanFtAssocForKeys(
const PDOT11DECRYPT_CONTEXT ctx _U_,
const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed _U_)
const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed _U_,
guint8 *decrypted_gtk _U_, size_t *decrypted_len _U_,
DOT11DECRYPT_KEY_ITEM* used_item _U_)
{
DEBUG_PRINT_LINE("Skipped Dot11DecryptScanFtAssocForKeys, libgcrypt >= 1.6", DEBUG_LEVEL_3);
return DOT11DECRYPT_RET_UNSUCCESS;

View File

@ -316,10 +316,32 @@ extern INT Dot11DecryptScanEapolForKeys(
const UCHAR sta[DOT11DECRYPT_MAC_LEN])
;
/**
* This will try to extract keys from an FT (re)association frame and add
* corresponding SAs to current context. assoc_parsed must contain the already
* parsed association frame content. If the FT BSS Transition IE contains an
* encrypted GTK subelem and decryption is successful the decrypted GTK will
* be returned in decrypted_gtk.
* @param ctx [IN] Pointer to the current context
* @param assoc_parsed [IN] Extracted/Parsed pieces of association frame
* @param decrypted_gtk [OUT] Buffer for decrypted GTK subelem
* @param decrypted_len [OUT] Decrypted GTK subelem key length
* @param used_key [OUT] Buffer to hold the key used during the decryption process.
* @return
* - DOT11DECRYPT_RET_UNSUCCESS: Generic unspecified error (decrypted_gtk
* and decrypted_len will be not modified).
* - DOT11DECRYPT_RET_SUCCESS_HANDSHAKE: An association frame was successfuly parsed
* and key information extracted.
* - DOT11DECRYPT_RET_NO_VALID_HANDSHAKE: The association is invalid or no matching
* key for decryption was found.
*/
gint
Dot11DecryptScanFtAssocForKeys(
const PDOT11DECRYPT_CONTEXT ctx,
const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed);
const PDOT11DECRYPT_ASSOC_PARSED assoc_parsed,
guint8 *decrypted_gtk, size_t *decrypted_len,
DOT11DECRYPT_KEY_ITEM* used_key);
/**
* This will try to extract keys from a TDLS action frame (without MAC headers)
* and add corresponding SAs to current context.

View File

@ -88,7 +88,7 @@ typedef struct {
DOT11DECRYPT_KEY_ITEM used_key;
guint keydata_len;
guint8 *keydata;
} proto_eapol_keydata_t;
} proto_keydata_t;
extern value_string_ext eap_type_vals_ext; /* from packet-eap.c */
@ -326,6 +326,7 @@ typedef enum {
IS_CTRL_GRANT_OR_GRANT_ACK_KEY,
IS_S1G_KEY,
DECRYPTED_EAPOL_KEY,
DECRYPTED_GTK_KEY,
PACKET_DATA_KEY,
ASSOC_COUNTER_KEY,
STA_KEY,
@ -5544,6 +5545,7 @@ static int hf_ieee80211_tag_ft_subelem_gtk_key_id = -1;
static int hf_ieee80211_tag_ft_subelem_gtk_key_length = -1;
static int hf_ieee80211_tag_ft_subelem_gtk_rsc = -1;
static int hf_ieee80211_tag_ft_subelem_gtk_key = -1;
static int hf_ieee80211_tag_ft_subelem_gtk_key_encrypted = -1;
static int hf_ieee80211_tag_ft_subelem_r0kh_id = -1;
static int hf_ieee80211_tag_ft_subelem_igtk_key_id = -1;
static int hf_ieee80211_tag_ft_subelem_igtk_ipn = -1;
@ -8412,6 +8414,27 @@ get_tagged_parameter_tree(proto_tree * tree, tvbuff_t *tvb, int start, int size)
return proto_item_add_subtree(tagged_fields, ett_tagged_parameters);
}
static void
add_ptk_analysis(tvbuff_t *tvb, proto_tree *tree, DOT11DECRYPT_KEY_ITEM *used_key)
{
if (!used_key) {
return;
}
const guint8 *key = NULL;
proto_item *ti;
char buf[SHORT_STR];
int len = Dot11DecryptGetKCK(used_key, &key);
bytes_to_hexstr(buf, key, len);
buf[2 * len] = '\0';
ti = proto_tree_add_string(tree, hf_ieee80211_fc_analysis_kck, tvb, 0, 0, buf);
proto_item_set_generated(ti);
len = Dot11DecryptGetKEK(used_key, &key);
bytes_to_hexstr(buf, key, len);
buf[2 * len] = '\0';
ti = proto_tree_add_string(tree, hf_ieee80211_fc_analysis_kek, tvb, 0, 0, buf);
proto_item_set_generated(ti);
}
static int
dissect_vendor_action_marvell(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
@ -18432,6 +18455,7 @@ dissect_fast_bss_transition(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_item *ti;
proto_tree *subtree;
const gchar *subtree_name;
proto_keydata_t *proto;
id = tvb_get_guint8(tvb, offset);
len = tvb_get_guint8(tvb, offset + 1);
@ -18483,8 +18507,21 @@ dissect_fast_bss_transition(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
break;
save_proto_data_value(pinfo, s_end - offset, GTK_LEN_KEY);
save_proto_data(tvb, pinfo, offset, s_end - offset, GTK_KEY);
proto_tree_add_item(subtree, hf_ieee80211_tag_ft_subelem_gtk_key,
tvb, offset, s_end - offset, ENC_NA);
proto = (proto_keydata_t *)
p_get_proto_data(wmem_file_scope(), pinfo, proto_wlan, DECRYPTED_GTK_KEY);
if (proto) {
guint keydata_len = proto->keydata_len;
tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, proto->keydata,
keydata_len, keydata_len);
add_new_data_source(pinfo, next_tvb, "Decrypted GTK");
proto_tree_add_item(subtree, hf_ieee80211_tag_ft_subelem_gtk_key,
next_tvb, 0, keydata_len, ENC_NA);
add_ptk_analysis(tvb, subtree, &proto->used_key);
} else {
proto_tree_add_item(subtree, hf_ieee80211_tag_ft_subelem_gtk_key_encrypted,
tvb, offset, s_end - offset, ENC_NA);
}
break;
case 3:
save_proto_data(tvb, pinfo, offset, len, FTE_R0KH_ID_KEY);
@ -33269,7 +33306,7 @@ try_decrypt_keydata(packet_info *pinfo)
dec_data, &dec_caplen,
&used_key);
if (ret == DOT11DECRYPT_RET_SUCCESS && dec_caplen > 0) {
proto_eapol_keydata_t *eapol = wmem_new(wmem_file_scope(), proto_eapol_keydata_t);
proto_keydata_t *eapol = wmem_new(wmem_file_scope(), proto_keydata_t);
eapol->used_key = used_key;
eapol->keydata_len = dec_caplen;
eapol->keydata = (guint8 *)wmem_memdup(wmem_file_scope(), dec_data, dec_caplen);
@ -33312,6 +33349,10 @@ static void
try_scan_ft_assoc_keys(packet_info *pinfo, const wlan_hdr_t *whdr)
{
DOT11DECRYPT_ASSOC_PARSED assoc_parsed;
guint8 decrypted_buf[DOT11DECRYPT_WPA_PTK_MAX_LEN];
size_t decrypted_len = 0;
DOT11DECRYPT_KEY_ITEM used_key;
gint ret;
if (!enable_decryption || pinfo->fd->visited || !whdr) {
return;
@ -33329,7 +33370,18 @@ try_scan_ft_assoc_keys(packet_info *pinfo, const wlan_hdr_t *whdr)
memcpy(assoc_parsed.sa, whdr->src.data, 6);
memcpy(assoc_parsed.da, whdr->dst.data, 6);
Dot11DecryptScanFtAssocForKeys(&dot11decrypt_ctx, &assoc_parsed);
ret = Dot11DecryptScanFtAssocForKeys(&dot11decrypt_ctx, &assoc_parsed,
decrypted_buf, &decrypted_len,
&used_key);
if (ret == DOT11DECRYPT_RET_SUCCESS_HANDSHAKE && decrypted_len > 0) {
proto_keydata_t *proto = wmem_new(wmem_file_scope(), proto_keydata_t);
proto->used_key = used_key;
proto->keydata_len = (guint)decrypted_len;
proto->keydata = (guint8 *)wmem_memdup(wmem_file_scope(), decrypted_buf, decrypted_len);
/* Save decrypted GTK keydata for tag dissector */
p_add_proto_data(wmem_file_scope(), pinfo, proto_wlan, DECRYPTED_GTK_KEY, proto);
}
}
/*
@ -33599,15 +33651,14 @@ dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_
try_decrypt_keydata(pinfo);
}
proto_eapol_keydata_t *eapol;
eapol = (proto_eapol_keydata_t*)
proto_keydata_t *eapol;
eapol = (proto_keydata_t*)
p_get_proto_data(wmem_file_scope(), pinfo, proto_wlan, DECRYPTED_EAPOL_KEY);
if (eapol) {
int keydata_len = eapol->keydata_len;
tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, eapol->keydata,
keydata_len, keydata_len);
char out_buff[SHORT_STR];
keydes_tree = proto_item_add_subtree(ti, ett_wlan_rsna_eapol_keydes_data);
if (keydes_version == KEYDES_VER_TYPE1) {
@ -33627,18 +33678,7 @@ dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_
}
}
/* Also add the PTK used to to decrypt and validate the keydata. */
const guint8 *key = NULL;
int len = Dot11DecryptGetKCK(&eapol->used_key, &key);
bytes_to_hexstr(out_buff, key, len);
out_buff[2 * len] = '\0';
ti = proto_tree_add_string(keydes_tree, hf_ieee80211_fc_analysis_kck, tvb, 0, 0, out_buff);
proto_item_set_generated(ti);
len = Dot11DecryptGetKEK(&eapol->used_key, &key);
bytes_to_hexstr(out_buff, key, len);
out_buff[2 * len] = '\0';
ti = proto_tree_add_string(keydes_tree, hf_ieee80211_fc_analysis_kek, tvb, 0, 0, out_buff);
proto_item_set_generated(ti);
add_ptk_analysis(tvb, keydes_tree, &eapol->used_key);
}
} else {
keydes_tree = proto_item_add_subtree(ti, ett_wlan_rsna_eapol_keydes_data);
@ -46010,6 +46050,11 @@ proto_register_ieee80211(void)
FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL }},
{&hf_ieee80211_tag_ft_subelem_gtk_key_encrypted,
{"GTK (encrypted)", "wlan.ft.subelem.gtk.key_encrypted",
FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL }},
{&hf_ieee80211_tag_ft_subelem_r0kh_id,
{"PMK-R0 key holder identifier (R0KH-ID)", "wlan.ft.subelem.r0kh_id",
FT_BYTES, BASE_NONE, NULL, 0,