From d08fa8402594d2f20517e107c657723fc6dfe7fb Mon Sep 17 00:00:00 2001 From: Mikael Kanstrup Date: Sat, 27 Mar 2021 10:44:49 +0100 Subject: [PATCH] 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 --- epan/crypt/dot11decrypt.c | 11 +++- epan/crypt/dot11decrypt_system.h | 24 ++++++++- epan/dissectors/packet-ieee80211.c | 85 +++++++++++++++++++++++------- 3 files changed, 97 insertions(+), 23 deletions(-) diff --git a/epan/crypt/dot11decrypt.c b/epan/crypt/dot11decrypt.c index a9c1e40971..faa50dcbd4 100644 --- a/epan/crypt/dot11decrypt.c +++ b/epan/crypt/dot11decrypt.c @@ -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; diff --git a/epan/crypt/dot11decrypt_system.h b/epan/crypt/dot11decrypt_system.h index 658ad7fbe1..32a0db8f6d 100644 --- a/epan/crypt/dot11decrypt_system.h +++ b/epan/crypt/dot11decrypt_system.h @@ -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. diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c index 48ca3fbc63..d8345eacc9 100644 --- a/epan/dissectors/packet-ieee80211.c +++ b/epan/dissectors/packet-ieee80211.c @@ -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,