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>
This commit is contained in:
Alexander Wetzel 2019-10-28 18:19:00 +01:00 committed by Jaap Keuter
parent 35615574e5
commit e7acb32a5a
4 changed files with 53 additions and 6 deletions

View File

@ -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);

View File

@ -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,

Binary file not shown.

View File

@ -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):