diff options
author | Alexander Wetzel <alexander.wetzel@web.de> | 2019-10-28 18:19:00 +0100 |
---|---|---|
committer | Jaap Keuter <jaap.keuter@xs4all.nl> | 2019-11-02 11:40:57 +0000 |
commit | e7acb32a5a48d57ffd6dc17f6a9de60630f82c7e (patch) | |
tree | 4aecb398c81f66da4b5615dca4c86f89152472a5 | |
parent | 35615574e5691c7bf2e09254271ac32c9cf59d95 (diff) |
ieee80211: Extended Key ID support
Support Extended Key ID for Individually Addressed Frames from
IEEE 802.11 - 2016.
Extended Key ID allows unicast (PTK) keys to also use key ID 1 and has
an additional RSN attribute "KeyID" in EAPOL #3.
Add the additional attribute KeyID to the RSN parser, stop assuming
unicast keys are only using key ID 0 and add a test case to verify
Extended Key ID parsing and decoding.
Change-Id: I43005c74df561be5524fa3738149781f50dafa14
Reviewed-on: https://code.wireshark.org/review/34883
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Jaap Keuter <jaap.keuter@xs4all.nl>
-rw-r--r-- | epan/crypt/dot11decrypt.c | 7 | ||||
-rw-r--r-- | epan/dissectors/packet-ieee80211.c | 27 | ||||
-rw-r--r-- | test/captures/wpa_ptk_extended_key_id.pcap.gz | bin | 0 -> 20462 bytes | |||
-rw-r--r-- | test/suite_decryption.py | 25 |
4 files changed, 53 insertions, 6 deletions
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 Binary files differnew file mode 100644 index 0000000000..c093018f61 --- /dev/null +++ b/test/captures/wpa_ptk_extended_key_id.pcap.gz 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): |