diff --git a/epan/crypt/dot11decrypt.c b/epan/crypt/dot11decrypt.c index 6e028654f8..a9908c1dba 100644 --- a/epan/crypt/dot11decrypt.c +++ b/epan/crypt/dot11decrypt.c @@ -984,13 +984,12 @@ INT Dot11DecryptPacketProcess( } else { DOT11DECRYPT_DEBUG_PRINT_LINE("Dot11DecryptPacketProcess", "TKIP or CCMP encryption", DOT11DECRYPT_DEBUG_LEVEL_3); - /* If index >= 1, then use the group key. This will not work if the AP is using + /* If the destination is a multicast address use the group key. This will not work if the AP is using more than one group key simultaneously. I've not seen this in practice, however. Usually an AP will rotate between the two key index values of 1 and 2 whenever it needs to change the group key to be used. */ - if (DOT11DECRYPT_KEY_INDEX(data[offset+3])>=1){ - - DOT11DECRYPT_DEBUG_PRINT_LINE("Dot11DecryptPacketProcess", "The key index >= 1. This is encrypted with a group key.", DOT11DECRYPT_DEBUG_LEVEL_3); + if (((const DOT11DECRYPT_MAC_FRAME_ADDR4 *)(data))->addr1[0] & 0x01) { + DOT11DECRYPT_DEBUG_PRINT_LINE("Dot11DecryptPacketProcess", "Broadcast/Multicast address. This is encrypted with a group key.", DOT11DECRYPT_DEBUG_LEVEL_3); /* force STA address to broadcast MAC so we load the SA for the groupkey */ memcpy(id.sta, broadcast_mac, DOT11DECRYPT_MAC_LEN); diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c index e234a0f7c3..a72063e714 100644 --- a/epan/dissectors/packet-ieee80211.c +++ b/epan/dissectors/packet-ieee80211.c @@ -4671,6 +4671,7 @@ static int hf_ieee80211_rsn_cap_mfpr = -1; static int hf_ieee80211_rsn_cap_mfpc = -1; static int hf_ieee80211_rsn_cap_jmr = -1; static int hf_ieee80211_rsn_cap_peerkey = -1; +static int hf_ieee80211_rsn_cap_extended_key_id_iaf = -1; static int hf_ieee80211_rsn_pmkid_count = -1; static int hf_ieee80211_rsn_pmkid_list = -1; static int hf_ieee80211_rsn_pmkid = -1; @@ -4798,6 +4799,8 @@ static int hf_ieee80211_vs_aerohive_data = -1; static int hf_ieee80211_vs_mist_ap_name = -1; static int hf_ieee80211_vs_mist_data = -1; +static int hf_ieee80211_rsn_ie_ptk_keyid = -1; + static int hf_ieee80211_rsn_ie_gtk_keyid = -1; static int hf_ieee80211_rsn_ie_gtk_tx = -1; static int hf_ieee80211_rsn_ie_gtk_reserved1 = -1; @@ -13808,6 +13811,15 @@ dissect_vendor_ie_rsn(proto_item * item, proto_tree * tree, tvbuff_t * tvb, int proto_item_append_text(item, ": RSN IGTK"); break; } + case 10: + { + /* IEEE 802.11 - 2016 / Key Data Encapsulation / Data Type=10 - KeyID + * This is only used within EAPOL-Key frame Key Data when using Extended Key ID */ + offset += 1; + proto_tree_add_item(tree, hf_ieee80211_rsn_ie_ptk_keyid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_item_append_text(item, ": RSN PTK"); + break; + } default: proto_tree_add_item(tree, hf_ieee80211_rsn_ie_unknown, tvb, offset, tag_len, ENC_NA); proto_item_append_text(item, ": RSN UNKNOWN"); @@ -14522,6 +14534,7 @@ dissect_rsn_ie(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, &hf_ieee80211_rsn_cap_mfpc, &hf_ieee80211_rsn_cap_jmr, &hf_ieee80211_rsn_cap_peerkey, + &hf_ieee80211_rsn_cap_extended_key_id_iaf, NULL }; @@ -24945,7 +24958,7 @@ dissect_ieee80211_common(tvbuff_t *tvb, packet_info *pinfo, bytes_to_hexstr(out_buff, used_key.KeyData.Wpa.Ptk+32, DOT11DECRYPT_TK_LEN); /* TK is stored in PTK at offset 32 bytes and 16 bytes long */ out_buff[2*DOT11DECRYPT_TK_LEN] = '\0'; - if (key == 0) { /* encrypted with pairwise key */ + if (!tvb_get_bits8(tvb, 39, 1)) { /* RA is unicast, encrypted with pairwise key */ ti = proto_tree_add_string(wep_tree, hf_ieee80211_fc_analysis_tk, tvb, 0, 0, out_buff); proto_item_set_generated(ti); @@ -30714,6 +30727,11 @@ proto_register_ieee80211(void) FT_BOOLEAN, 16, NULL, 0x0200, NULL, HFILL }}, + {&hf_ieee80211_rsn_cap_extended_key_id_iaf, + {"Extended Key ID for Individually Addressed Frames", + "wlan.rsn.capabilities.extended_key_id_iaf", + FT_BOOLEAN, 16, TFS(&tfs_supported_not_supported), 0x2000, NULL, HFILL }}, + {&hf_ieee80211_rsn_pmkid_count, {"PMKID Count", "wlan.rsn.pmkid.count", FT_UINT16, BASE_DEC, NULL, 0, @@ -33701,6 +33719,11 @@ proto_register_ieee80211(void) FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, + {&hf_ieee80211_rsn_ie_ptk_keyid, + {"KeyID", "wlan.rsn.ie.ptk.keyid", + FT_UINT8, BASE_DEC, NULL, 0x03, + NULL, HFILL }}, + {&hf_ieee80211_rsn_ie_gtk_key, {"GTK", "wlan.rsn.ie.gtk.key", FT_BYTES, BASE_NONE, NULL, 0, @@ -35289,7 +35312,7 @@ proto_register_ieee80211(void) {&hf_ieee80211_osen_extended_key_id_iaf, {"Extended Key ID for Individually Addressed Frames", - "wlan.osn.rsn.extended_key_id_iaf", + "wlan.osn.rsn.extended_key_id_iaf", FT_BOOLEAN, 16, TFS(&tfs_supported_not_supported), 0x2000, NULL, HFILL }}, {&hf_ieee80211_osen_reserved, diff --git a/test/captures/wpa_ptk_extended_key_id.pcap.gz b/test/captures/wpa_ptk_extended_key_id.pcap.gz new file mode 100644 index 0000000000..c093018f61 Binary files /dev/null and b/test/captures/wpa_ptk_extended_key_id.pcap.gz differ diff --git a/test/suite_decryption.py b/test/suite_decryption.py index e87358ee86..62735c250e 100644 --- a/test/suite_decryption.py +++ b/test/suite_decryption.py @@ -112,6 +112,31 @@ class case_decrypt_80211(subprocesstest.SubprocessTestCase): self.assertTrue(self.grepOutput('DHCP Discover')) self.assertEqual(self.countOutput('ICMP.*Echo .ping'), 8) + def test_80211_wpa_extended_key_id_rekey(self, cmd_tshark, capture_file): + '''WPA decode for Extended Key ID''' + # Included in git sources test/captures/wpa_ptk_extended_key_id.pcap.gz + self.assertRun((cmd_tshark, + '-o', 'wlan.enable_decryption: TRUE', + '-r', capture_file('wpa_ptk_extended_key_id.pcap.gz'), + '-Tfields', + '-e' 'wlan.fc.type_subtype', + '-e' 'wlan.ra', + '-e' 'wlan.analysis.tk', + '-e' 'wlan.analysis.gtk', + '-e' 'wlan.rsn.ie.ptk.keyid', + )) + # Verify frames are decoded with the correct key + self.assertEqual(self.countOutput('^32\t33:33:00:00:00:16\t\t234a9a6ddcca3cb728751cea49d01bb0\t$'), 5) + self.assertEqual(self.countOutput('^32\t33:33:ff:00:00:00\t\t234a9a6ddcca3cb728751cea49d01bb0\t$'), 1) + self.assertEqual(self.countOutput('^32\t33:33:ff:00:03:00\t\t234a9a6ddcca3cb728751cea49d01bb0\t$'), 1) + self.assertEqual(self.countOutput('^32\tff:ff:ff:ff:ff:ff\t\t234a9a6ddcca3cb728751cea49d01bb0\t$'), 4) + self.assertEqual(self.countOutput('^40\t02:00:00:00:03:00\t618b4d1829e2a496d7fd8c034a6d024d\t\t$'), 2) + self.assertEqual(self.countOutput('^40\t02:00:00:00:00:00\t618b4d1829e2a496d7fd8c034a6d024d\t\t$'), 1) + # Verify RSN PTK KeyID parsing + self.assertEqual(self.countOutput('^40\t02:00:00:00:00:00\t\t\t1$'), 1) + self.assertEqual(self.countOutput('^40\t02:00:00:00:00:00\tf31ecff5452f4c286cf66ef50d10dabe\t\t0$'), 1) + self.assertEqual(self.countOutput('^40\t02:00:00:00:00:00\t28dd851decf3f1c2a35df8bcc22fa1d2\t\t1$'), 1) + @fixtures.mark_usefixtures('test_env') @fixtures.uses_fixtures class case_decrypt_dtls(subprocesstest.SubprocessTestCase):