aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordeagol <alexander.wetzel@web.de>2015-05-01 22:56:50 +0200
committerAnders Broman <a.broman58@gmail.com>2015-05-08 04:27:49 +0000
commit1439eb677820fff055df86e43341fde1d94a64d1 (patch)
tree31b136ae73871a6182c5c634100b9eea07185a16
parentb644698bef613c4bb1eda5d2f7481620583fc185 (diff)
IEEE 802.11: 802.1X (WPA-EAP) rekeying support
This patch extends the existing decryption support for WPA to also handle rekeys by checking each decrypted packet for a 4-way-handshake. Rekeys can be used for WPA-PSK, but are more common with WPA-Enterprise (WPA-EAP). For decrypting WPA-EAP secured packets the user must provide all used PMK's of the connection (aka PSK's) as WPA-PSK 32 byte hex values to wireshark via the existing interface. (The capture must have all 4-way-handshakes included also, starting with the first unencrypted one.) Every decrypted unicast packet will habe the used PMK and TK shown in the CCMP/TKIP section below the key index in the GUI. Group packets will display the GTK instead. Additionally this fixes a small issue with group rekey handling, so every packet can be selected in the GUI in random order, removing the need to manually find the correct group keying packets prior to that. It was tested primary with WPA-CCMP, but TKIP is also working. One section in the code touch bluetooth 802.1X support. It should do exactly the same, but will now also examine all decypted packets for rekeys. Ping-Bug: 11172 Change-Id: I19d055581fce6268df888da63485a48326046748 Reviewed-on: https://code.wireshark.org/review/8268 Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com> Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--caputils/airpcap_loader.h2
-rw-r--r--epan/crypt/airpdcap.c215
-rw-r--r--epan/crypt/airpdcap_system.h14
-rw-r--r--epan/crypt/airpdcap_user.h9
-rw-r--r--epan/dissectors/packet-ieee80211.c51
-rw-r--r--test/captures/wpa-eap-tls.pcap.gzbin0 -> 25629 bytes
-rw-r--r--test/config/80211_keys.tmpl5
-rwxr-xr-xtest/suite-decryption.sh17
8 files changed, 131 insertions, 182 deletions
diff --git a/caputils/airpcap_loader.h b/caputils/airpcap_loader.h
index 929604f082..ef8248f3a5 100644
--- a/caputils/airpcap_loader.h
+++ b/caputils/airpcap_loader.h
@@ -26,7 +26,7 @@
#ifndef __AIRPCAP_LOADER_H__
#define __AIRPCAP_LOADER_H__
-#include <epan/crypt/airpdcap_user.h>
+#include <epan/crypt/airpdcap_system.h>
#ifdef __cplusplus
extern "C" {
diff --git a/epan/crypt/airpdcap.c b/epan/crypt/airpdcap.c
index bc1ca32567..5b955fedea 100644
--- a/epan/crypt/airpdcap.c
+++ b/epan/crypt/airpdcap.c
@@ -308,41 +308,6 @@ typedef struct {
/* Minimum possible group key msg size (group key msg using CCMP as cipher)*/
#define GROUP_KEY_PAYLOAD_LEN_MIN RSN_KEY_WITHOUT_KEYBYTES_LEN+CCMP_GROUP_KEY_LEN
-/* A note about some limitations with the WPA decryption:
-
-Unless someone takes the time to restructure the current method used for maintaining decryption keys, there
-will be some anomalies observed when using the decryption feature.
-
-Currently, there is only one pairwise (unicast) key and one group (broadcast) key saved for each security association
-(SA). As a result, if a wireless sniffer session captures the traffic of a station (STA) associating with an AP
-more than once, or captures a STA roaming, then you will not be able to arbitrarilly click on different encrypted
-packets in the trace and observe their internal decrypted structure. This is because when you click on a packet,
-Wireshark immediately performs the decryption routine with whatever the last key used was. It does not maintain a
-cache of all the keys that were used by this STA/AP pairing.
-
-However, if you are just looking at the summary lines of a capture, it will appear that everything was decrypted properly.
-This is because when first performing a capture or initially reading a capture file, Wireshark will first
-process the packets in order. As it encounters new EAPOL packets, it will update its internal key list with the
-newfound key. Then it will use that key for decrypting subsequent packets. Each time a new key is found, the old key
-is overwritten. So, if you then click on a packet that was previously decrypted properly, it might suddenly no longer
-be decrypted because a later EAPOL key had caused the internal decryption key to be updated.
-
-For broadcast packets, there is a clunky work-around. If the AP is using group-key rotation, you simply have to find the appropriate
-EAPOL group key packet (usually size is 211 bytes and will have a protocol type of EAPOL and Info field of Key). If you click on it
-and then click on the broadcast packet you are trying to decrypt, the packet will be decrypted properly. By first
-clicking on the EAPOL packet for the group-key, you will force Wireshark to parse that packet and load the group-key it
-contains. That group key will then be used for decrypting all subsequent broadcast packets you click on.
-
-Ideally, it would be best to maintain an expanding list of SA keys. Perhaps we could associate packet number ranges
-that they apply to. Then, whenever we need to decrypt a packet, we can determine which key to use based on whether
-it is broadcast or unicast and within what packet number range it falls.
-
-Either that, or store two versions of encrypted packets - the orginal packet and its successfully
-decrypted version. Then Wireshark wouldn't have to decrypt packets on the fly if they were already successfully decrypted.
-
-*/
-
-
static void
AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption_key, PAIRPDCAP_SEC_ASSOCIATION sa, gboolean group_hshake)
{
@@ -352,6 +317,7 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
guint16 key_bytes_len = 0; /* Length of the total key data field */
guint16 key_len = 0; /* Actual group key length */
static AIRPDCAP_KEY_ITEM dummy_key; /* needed in case AirPDcapRsnaMng() wants the key structure */
+ AIRPDCAP_SEC_ASSOCIATION *tmp_sa;
/* We skip verifying the MIC of the key. If we were implementing a WPA supplicant we'd want to verify, but for a sniffer it's not needed. */
@@ -382,6 +348,11 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
memcpy(new_key+16, decryption_key, 16);
DEBUG_DUMP("FullDecrKey:", new_key, 32);
+ /* We are rekeying, save old sa */
+ tmp_sa=(AIRPDCAP_SEC_ASSOCIATION *)g_malloc(sizeof(AIRPDCAP_SEC_ASSOCIATION));
+ memcpy(tmp_sa, sa, sizeof(AIRPDCAP_SEC_ASSOCIATION));
+ sa->next=tmp_sa;
+
/* As we have no concept of the prior association request at this point, we need to deduce the */
/* group key cipher from the length of the key bytes. In WPA this is straightforward as the */
/* keybytes just contain the GTK, and the GTK is only in the group handshake, NOT the M3. */
@@ -490,15 +461,16 @@ AirPDcapGetSaPtr(
return &ctx->sa[sa_index];
}
-static INT AirPDcapScanForGroupKey(
+static INT AirPDcapScanForKeys(
PAIRPDCAP_CONTEXT ctx,
const guint8 *data,
const guint mac_header_len,
- const guint tot_len
+ const guint tot_len,
+ AIRPDCAP_SEC_ASSOCIATION_ID id,
+ PAIRPDCAP_KEY_ITEM key
)
{
const UCHAR *addr;
- AIRPDCAP_SEC_ASSOCIATION_ID id;
guint bodyLength;
PAIRPDCAP_SEC_ASSOCIATION sta_sa;
PAIRPDCAP_SEC_ASSOCIATION sa;
@@ -510,40 +482,41 @@ static INT AirPDcapScanForGroupKey(
0x00, 0x00, 0x00, /* Org. code=encaps. Ethernet */
0x88, 0x8E /* Type: 802.1X authentication */
};
+ const guint8 bt_dot1x_header[] = {
+ 0xAA, /* DSAP=SNAP */
+ 0xAA, /* SSAP=SNAP */
+ 0x03, /* Control field=Unnumbered frame */
+ 0x00, 0x19, 0x58, /* Org. code=Bluetooth SIG */
+ 0x00, 0x03 /* Type: Bluetooth Security */
+ };
const EAPOL_RSN_KEY *pEAPKey;
#ifdef _DEBUG
CHAR msgbuf[255];
#endif
- AIRPDCAP_DEBUG_TRACE_START("AirPDcapScanForGroupKey");
-
- if (mac_header_len + GROUP_KEY_PAYLOAD_LEN_MIN > tot_len) {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Message too short", AIRPDCAP_DEBUG_LEVEL_3);
- return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
- }
+ AIRPDCAP_DEBUG_TRACE_START("AirPDcapScanForKeys");
/* cache offset in the packet data */
offset = mac_header_len;
/* check if the packet has an LLC header and the packet is 802.1X authentication (IEEE 802.1X-2004, pg. 24) */
- if (memcmp(data+offset, dot1x_header, 8) == 0) {
+ if (memcmp(data+offset, dot1x_header, 8) == 0 || memcmp(data+offset, bt_dot1x_header, 8) == 0) {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Authentication: EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "Authentication: EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3);
/* skip LLC header */
offset+=8;
-
/* check if the packet is a EAPOL-Key (0x03) (IEEE 802.1X-2004, pg. 25) */
if (data[offset+1]!=3) {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Not EAPOL-Key", AIRPDCAP_DEBUG_LEVEL_3);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "Not EAPOL-Key", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
}
/* get and check the body length (IEEE 802.1X-2004, pg. 25) */
bodyLength=pntoh16(data+offset+2);
if ((tot_len-offset-4) > bodyLength) {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "EAPOL body too short", AIRPDCAP_DEBUG_LEVEL_3);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "EAPOL body too short", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
}
@@ -557,35 +530,38 @@ static INT AirPDcapScanForGroupKey(
pEAPKey->type != AIRPDCAP_RSN_WPA2_KEY_DESCRIPTOR && /* IEEE 802.11 Key Descriptor Type (WPA2) */
pEAPKey->type != AIRPDCAP_RSN_WPA_KEY_DESCRIPTOR) /* 254 = RSN_KEY_DESCRIPTOR - WPA, */
{
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Not valid key descriptor type", AIRPDCAP_DEBUG_LEVEL_3);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "Not valid key descriptor type", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
}
/* start with descriptor body */
offset+=1;
+ /* search for a cached Security Association for current BSSID and AP */
+ sa = AirPDcapGetSaPtr(ctx, &id);
+ if (sa == NULL){
+ return AIRPDCAP_RET_UNSUCCESS;
+ }
+
+ /* It could be a Pairwise Key exchange, check */
+ if (AirPDcapRsna4WHandshake(ctx, data, sa, key, offset) == AIRPDCAP_RET_SUCCESS_HANDSHAKE)
+ return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
+
+ if (mac_header_len + GROUP_KEY_PAYLOAD_LEN_MIN > tot_len) {
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "Message too short for Group Key", AIRPDCAP_DEBUG_LEVEL_3);
+ return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
+ }
+
/* Verify the bitfields: Key = 0(groupwise) Mic = 1 Ack = 1 Secure = 1 */
if (AIRPDCAP_EAP_KEY(data[offset+1])!=0 ||
AIRPDCAP_EAP_ACK(data[offset+1])!=1 ||
AIRPDCAP_EAP_MIC(data[offset]) != 1 ||
AIRPDCAP_EAP_SEC(data[offset]) != 1){
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Key bitfields not correct", AIRPDCAP_DEBUG_LEVEL_3);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "Key bitfields not correct for Group Key", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
}
- /* get BSSID */
- if ( (addr=AirPDcapGetBssidAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) {
- memcpy(id.bssid, addr, AIRPDCAP_MAC_LEN);
-#ifdef _DEBUG
- sprintf(msgbuf, "BSSID: %2X.%2X.%2X.%2X.%2X.%2X\t", id.bssid[0],id.bssid[1],id.bssid[2],id.bssid[3],id.bssid[4],id.bssid[5]);
-#endif
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
- } else {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "BSSID not found", AIRPDCAP_DEBUG_LEVEL_5);
- return AIRPDCAP_RET_REQ_DATA;
- }
-
/* force STA address to be the broadcast MAC so we create an SA for the groupkey */
memcpy(id.sta, broadcast_mac, AIRPDCAP_MAC_LEN);
@@ -600,12 +576,9 @@ static INT AirPDcapScanForGroupKey(
/* get STA address */
if ( (addr=AirPDcapGetStaAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) {
memcpy(id.sta, addr, AIRPDCAP_MAC_LEN);
-#ifdef _DEBUG
- sprintf(msgbuf, "ST_MAC: %2X.%2X.%2X.%2X.%2X.%2X\t", id.sta[0],id.sta[1],id.sta[2],id.sta[3],id.sta[4],id.sta[5]);
-#endif
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
} else {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "SA not found", AIRPDCAP_DEBUG_LEVEL_5);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "SA not found", AIRPDCAP_DEBUG_LEVEL_5);
return AIRPDCAP_RET_REQ_DATA;
}
@@ -618,10 +591,10 @@ static INT AirPDcapScanForGroupKey(
AirPDcapDecryptWPABroadcastKey(pEAPKey, sta_sa->wpa.ptk+16, sa, TRUE);
}else{
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Skipping: not an EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3);
+ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "Skipping: not an EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3);
}
- AIRPDCAP_DEBUG_TRACE_END("AirPDcapScanForGroupKey");
+ AIRPDCAP_DEBUG_TRACE_END("AirPDcapScanForKeys");
return 0;
}
@@ -641,22 +614,6 @@ INT AirPDcapPacketProcess(
AIRPDCAP_SEC_ASSOCIATION_ID id;
PAIRPDCAP_SEC_ASSOCIATION sa;
int offset = 0;
- guint bodyLength;
- const guint8 dot1x_header[] = {
- 0xAA, /* DSAP=SNAP */
- 0xAA, /* SSAP=SNAP */
- 0x03, /* Control field=Unnumbered frame */
- 0x00, 0x00, 0x00, /* Org. code=encaps. Ethernet */
- 0x88, 0x8E /* Type: 802.1X authentication */
- };
-
- const guint8 bt_dot1x_header[] = {
- 0xAA, /* DSAP=SNAP */
- 0xAA, /* SSAP=SNAP */
- 0x03, /* Control field=Unnumbered frame */
- 0x00, 0x19, 0x58, /* Org. code=Bluetooth SIG */
- 0x00, 0x03 /* Type: Bluetooth Security */
- };
#ifdef _DEBUG
CHAR msgbuf[255];
@@ -690,9 +647,6 @@ INT AirPDcapPacketProcess(
/* get BSSID */
if ( (addr=AirPDcapGetBssidAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) {
memcpy(id.bssid, addr, AIRPDCAP_MAC_LEN);
-#ifdef _DEBUG
- sprintf(msgbuf, "BSSID: %2X.%2X.%2X.%2X.%2X.%2X\t", id.bssid[0],id.bssid[1],id.bssid[2],id.bssid[3],id.bssid[4],id.bssid[5]);
-#endif
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
} else {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "BSSID not found", AIRPDCAP_DEBUG_LEVEL_5);
@@ -702,9 +656,6 @@ INT AirPDcapPacketProcess(
/* get STA address */
if ( (addr=AirPDcapGetStaAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) {
memcpy(id.sta, addr, AIRPDCAP_MAC_LEN);
-#ifdef _DEBUG
- sprintf(msgbuf, "ST_MAC: %2X.%2X.%2X.%2X.%2X.%2X\t", id.sta[0],id.sta[1],id.sta[2],id.sta[3],id.sta[4],id.sta[5]);
-#endif
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
} else {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "SA not found", AIRPDCAP_DEBUG_LEVEL_5);
@@ -726,58 +677,7 @@ INT AirPDcapPacketProcess(
if (mngHandshake) {
/* data is sent in cleartext, check if is an authentication message or end the process */
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Unencrypted data", AIRPDCAP_DEBUG_LEVEL_3);
-
- /* check if the packet as an LLC header and the packet is 802.1X authentication (IEEE 802.1X-2004, pg. 24) */
- if (memcmp(data+offset, dot1x_header, 8) == 0 || memcmp(data+offset, bt_dot1x_header, 8) == 0) {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Authentication: EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3);
-
- /* skip LLC header */
- offset+=8;
-
- /* check the version of the EAPOL protocol used (IEEE 802.1X-2004, pg. 24) */
- /* TODO EAPOL protocol version to check? */
-#if 0
- if (data[offset]!=2) {
- AIRPDCAP_DEBUG_PRINT_LINE("EAPOL protocol version not recognized", AIRPDCAP_DEBUG_LEVEL_5);
- return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
- }
-#endif
-
- /* check if the packet is a EAPOL-Key (0x03) (IEEE 802.1X-2004, pg. 25) */
- if (data[offset+1]!=3) {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Not EAPOL-Key", AIRPDCAP_DEBUG_LEVEL_5);
- return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
- }
-
- /* get and check the body length (IEEE 802.1X-2004, pg. 25) */
- bodyLength=pntoh16(data+offset+2);
- if ((tot_len-offset-4) < bodyLength) {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "EAPOL body too short", AIRPDCAP_DEBUG_LEVEL_5);
- return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
- }
-
- /* skip EAPOL MPDU and go to the first byte of the body */
- offset+=4;
-
- /* check if the key descriptor type is valid (IEEE 802.1X-2004, pg. 27) */
- if (/*data[offset]!=0x1 &&*/ /* RC4 Key Descriptor Type (deprecated) */
- data[offset]!=0x2 && /* IEEE 802.11 Key Descriptor Type */
- data[offset]!=0xFE) /* TODO what's this value??? */
- {
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Not valid key descriptor type", AIRPDCAP_DEBUG_LEVEL_5);
- return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
- }
-
- /* start with descriptor body */
- offset+=1;
-
- /* manage the 4-way handshake to define the key */
- return AirPDcapRsna4WHandshake(ctx, data, sa, key, offset);
- } else {
- /* cleartext message, not authentication */
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "No authentication data", AIRPDCAP_DEBUG_LEVEL_5);
- return AIRPDCAP_RET_NO_DATA_ENCRYPTED;
- }
+ return (AirPDcapScanForKeys(ctx, data, mac_header_len, tot_len, id, key));
}
} else {
if (mngDecrypt) {
@@ -800,7 +700,6 @@ INT AirPDcapPacketProcess(
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "WEP encryption", AIRPDCAP_DEBUG_LEVEL_3);
return AirPDcapWepMng(ctx, decrypt_data, mac_header_len, decrypt_len, key, sa, offset);
} else {
- INT status;
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "TKIP or CCMP encryption", AIRPDCAP_DEBUG_LEVEL_3);
/* If index >= 1, then use the group key. This will not work if the AP is using
@@ -814,11 +713,6 @@ INT AirPDcapPacketProcess(
/* force STA address to broadcast MAC so we load the SA for the groupkey */
memcpy(id.sta, broadcast_mac, AIRPDCAP_MAC_LEN);
-#ifdef _DEBUG
- sprintf(msgbuf, "ST_MAC: %2X.%2X.%2X.%2X.%2X.%2X\t", id.sta[0],id.sta[1],id.sta[2],id.sta[3],id.sta[4],id.sta[5]);
- AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
-#endif
-
/* search for a cached Security Association for current BSSID and broadcast MAC */
sa = AirPDcapGetSaPtr(ctx, &id);
if (sa == NULL){
@@ -827,18 +721,17 @@ INT AirPDcapPacketProcess(
}
/* Decrypt the packet using the appropriate SA */
- status = AirPDcapRsnaMng(decrypt_data, mac_header_len, decrypt_len, key, sa, offset);
-
- /* If we successfully decrypted a packet, scan it to see if it contains a group key handshake.
- The group key handshake could be sent at any time the AP wants to change the key (such as when
- it is using key rotation) so we must scan every packet. */
- if (status == AIRPDCAP_RET_SUCCESS)
- AirPDcapScanForGroupKey(ctx, decrypt_data, mac_header_len, *decrypt_len);
- return status;
+ if (AirPDcapRsnaMng(decrypt_data, mac_header_len, decrypt_len, key, sa, offset) == AIRPDCAP_RET_SUCCESS)
+ {
+ /* If we successfully decrypted a packet, scan it to see if it contains a key handshake.
+ The group key handshake could be sent at any time the AP wants to change the key (such as when
+ it is using key rotation) and it also could be a rekey for the Pairwise key. So we must scan every packet. */
+ AirPDcapScanForKeys(ctx, decrypt_data, mac_header_len, *decrypt_len, id, NULL);
+ return AIRPDCAP_RET_SUCCESS;
+ }
}
}
}
-
return AIRPDCAP_RET_UNSUCCESS;
}
@@ -1142,7 +1035,7 @@ AirPDcapRsnaMng(
if (key!=NULL) {
memcpy(key, sa->key, sizeof(AIRPDCAP_KEY_ITEM));
-
+ memcpy(&(key->KeyData.Wpa.Ptk), sa->wpa.ptk, AIRPDCAP_WPA_PTK_LEN); /* copy the PTK to the key structure for future use by wireshark */
if (sa->wpa.key_ver==AIRPDCAP_WPA_KEY_VER_NOT_CCMP)
key->KeyType=AIRPDCAP_KEY_TYPE_TKIP;
else if (sa->wpa.key_ver==AIRPDCAP_WPA_KEY_VER_AES_CCMP)
@@ -1383,7 +1276,7 @@ AirPDcapRsna4WHandshake(
/* derive the PTK from the BSSID, STA MAC, PMK, SNonce, ANonce */
AirPDcapRsnaPrfX(sa, /* authenticator nonce, bssid, station mac */
- tmp_pkt_key->KeyData.Wpa.Pmk, /* PMK */
+ tmp_pkt_key->KeyData.Wpa.Psk, /* PSK == PMK */
data+offset+12, /* supplicant nonce */
512,
sa->wpa.ptk);
diff --git a/epan/crypt/airpdcap_system.h b/epan/crypt/airpdcap_system.h
index 36d2be5484..08405fda21 100644
--- a/epan/crypt/airpdcap_system.h
+++ b/epan/crypt/airpdcap_system.h
@@ -36,13 +36,6 @@
#define _AIRPDCAP_SYSTEM_H
/************************************************************************/
-/* File includes */
-
-#include "airpdcap_interop.h"
-#include "airpdcap_user.h"
-#include "ws_symbol_export.h"
-
-/************************************************************************/
/* Constant definitions */
/* General definitions */
@@ -113,6 +106,13 @@
#define AIRPDCAP_CRC_LEN 4
/************************************************************************/
+/* File includes */
+
+#include "airpdcap_interop.h"
+#include "airpdcap_user.h"
+#include "ws_symbol_export.h"
+
+/************************************************************************/
/* Macro definitions */
/************************************************************************/
diff --git a/epan/crypt/airpdcap_user.h b/epan/crypt/airpdcap_user.h
index 43031b28da..d2ac85dd9b 100644
--- a/epan/crypt/airpdcap_user.h
+++ b/epan/crypt/airpdcap_user.h
@@ -68,8 +68,7 @@
#define AIRPDCAP_WPA_PASSPHRASE_MAX_LEN 63 /* null-terminated string, the actual length of the storage is 64 */
#define AIRPDCAP_WPA_SSID_MIN_LEN 0
#define AIRPDCAP_WPA_SSID_MAX_LEN 32
-#define AIRPDCAP_WPA_PSK_LEN 64
-#define AIRPDCAP_WPA_PMK_LEN 32
+#define AIRPDCAP_WPA_PSK_LEN 32
/* */
/* */
/******************************************************************************/
@@ -149,11 +148,9 @@ typedef struct _AIRPDCAP_KEY_ITEM {
* three fields and necessary fields will be automatically
* calculated.
*/
- union AIRPDCAP_KEY_ITEMDATA_WPA {
-
+ struct AIRPDCAP_KEY_ITEMDATA_WPA {
UCHAR Psk[AIRPDCAP_WPA_PSK_LEN];
-
- UCHAR Pmk[AIRPDCAP_WPA_PMK_LEN];
+ UCHAR Ptk[AIRPDCAP_WPA_PTK_LEN];
} Wpa;
} KeyData;
diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c
index 88551cf174..f46fca22b5 100644
--- a/epan/dissectors/packet-ieee80211.c
+++ b/epan/dissectors/packet-ieee80211.c
@@ -99,6 +99,7 @@
#include <epan/conversation_table.h>
#include <epan/uat.h>
#include <epan/eapol_keydes_types.h>
+#include <epan/to_str-int.h>
#include "packet-wps.h"
#include "packet-e212.h"
@@ -239,7 +240,7 @@ ieee_80211_add_tagged_parameters (tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, int tagged_parameters_len, int ftype);
/* Davide Schiera (2006-11-26): created function to decrypt WEP and WPA/WPA2 */
-static tvbuff_t *try_decrypt(tvbuff_t *tvb, guint32 offset, guint32 len, guint8 *algorithm, guint32 *sec_header, guint32 *sec_trailer);
+static tvbuff_t *try_decrypt(tvbuff_t *tvb, guint32 offset, guint32 len, guint8 *algorithm, guint32 *sec_header, guint32 *sec_trailer, PAIRPDCAP_KEY_ITEM used_key);
static int weak_iv(guchar *iv);
@@ -3792,6 +3793,9 @@ static int hf_ieee80211_tkip_extiv = -1;
static int hf_ieee80211_ccmp_extiv = -1;
static int hf_ieee80211_wep_key = -1;
static int hf_ieee80211_wep_icv = -1;
+static int hf_ieee80211_fc_analysis_pmk = -1;
+static int hf_ieee80211_fc_analysis_tk = -1;
+static int hf_ieee80211_fc_analysis_gtk = -1;
static int hf_ieee80211_block_ack_request_control = -1;
static int hf_ieee80211_block_ack_control = -1;
@@ -16622,6 +16626,8 @@ dissect_ieee80211_common (tvbuff_t *tvb, packet_info *pinfo,
tvbuff_t *volatile next_tvb = NULL;
wlan_hdr *volatile whdr;
+ AIRPDCAP_KEY_ITEM used_key;
+
p_add_proto_data(wmem_file_scope(), pinfo, proto_wlan, IS_DMG_KEY, &isDMG);
whdr= &whdrs[0];
@@ -17808,7 +17814,7 @@ dissect_ieee80211_common (tvbuff_t *tvb, packet_info *pinfo,
guint32 sec_header=0;
guint32 sec_trailer=0;
- next_tvb = try_decrypt(tvb, hdr_len, reported_len, &algorithm, &sec_header, &sec_trailer);
+ next_tvb = try_decrypt(tvb, hdr_len, reported_len, &algorithm, &sec_header, &sec_trailer, &used_key);
/* Davide Schiera ----------------------------------------------------- */
keybyte = tvb_get_guint8(tvb, hdr_len + 3);
@@ -17887,6 +17893,25 @@ dissect_ieee80211_common (tvbuff_t *tvb, packet_info *pinfo,
len -= sec_trailer;
reported_len -= sec_trailer;
can_decrypt = TRUE;
+
+ /* Add Key information to packet */
+ bytes_to_hexstr(out_buff, (*&(used_key.KeyData.Wpa.Ptk)+32), AIRPDCAP_TK_LEN); /* TK is stored in PTK at offset 32 bytes and 16 bytes long */
+ out_buff[2*AIRPDCAP_TK_LEN] = '\0';
+
+ if (key == 0) { /* 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);
+
+ /* Also add the PMK used to to decrypt the packet. (PMK==PSK) */
+ bytes_to_hexstr(out_buff, used_key.KeyData.Wpa.Psk, AIRPDCAP_WPA_PSK_LEN); /* 32 bytes */
+ out_buff[2*AIRPDCAP_WPA_PSK_LEN] = '\0';
+ ti = proto_tree_add_string(wep_tree, hf_ieee80211_fc_analysis_pmk, tvb, 0, 0, out_buff);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ } else { /* Encrypted with Group Key */
+ ti = proto_tree_add_string(wep_tree, hf_ieee80211_fc_analysis_gtk, tvb, 0, 0, out_buff); /* GTK is stored in PTK at offset 32 bytes and 16 bytes long */
+ PROTO_ITEM_SET_GENERATED(ti);
+ }
}
}
/* Davide Schiera -------------------------------------------------- */
@@ -18624,13 +18649,12 @@ dissect_wlan_rsna_eapol_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
/* algorithm used for decryption (WEP, TKIP, CCMP) and the header and */
/* trailer lengths. */
static tvbuff_t *
-try_decrypt(tvbuff_t *tvb, guint offset, guint len, guint8 *algorithm, guint32 *sec_header, guint32 *sec_trailer)
+try_decrypt(tvbuff_t *tvb, guint offset, guint len, guint8 *algorithm, guint32 *sec_header, guint32 *sec_trailer, PAIRPDCAP_KEY_ITEM used_key)
{
const guint8 *enc_data;
tvbuff_t *decr_tvb = NULL;
guint32 dec_caplen;
guchar dec_data[AIRPDCAP_MAX_CAPLEN];
- AIRPDCAP_KEY_ITEM used_key;
if (!enable_decryption)
return NULL;
@@ -18640,10 +18664,10 @@ try_decrypt(tvbuff_t *tvb, guint offset, guint len, guint8 *algorithm, guint32 *
/* process packet with AirPDcap */
if (AirPDcapPacketProcess(&airpdcap_ctx, enc_data, offset, offset+len, dec_data, &dec_caplen,
- &used_key, FALSE, TRUE)==AIRPDCAP_RET_SUCCESS)
+ used_key, FALSE, TRUE)==AIRPDCAP_RET_SUCCESS)
{
guint8 *tmp;
- *algorithm=used_key.KeyType;
+ *algorithm=used_key->KeyType;
switch (*algorithm) {
case AIRPDCAP_KEY_TYPE_WEP:
*sec_header=AIRPDCAP_WEP_HEADER;
@@ -19204,6 +19228,21 @@ proto_register_ieee80211 (void)
FT_UINT32, BASE_HEX, NULL, 0,
NULL, HFILL }},
+ {&hf_ieee80211_fc_analysis_pmk,
+ {"PMK", "wlan.analysis.pmk",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ {&hf_ieee80211_fc_analysis_tk,
+ {"TK", "wlan.analysis.tk",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ {&hf_ieee80211_fc_analysis_gtk,
+ {"GTK", "wlan.analysis.gtk",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
{&hf_ieee80211_block_ack_request_control,
{"Block Ack Request (BAR) Control", "wlan.bar.control",
FT_UINT16, BASE_HEX, NULL, 0,
diff --git a/test/captures/wpa-eap-tls.pcap.gz b/test/captures/wpa-eap-tls.pcap.gz
new file mode 100644
index 0000000000..307e5fadde
--- /dev/null
+++ b/test/captures/wpa-eap-tls.pcap.gz
Binary files differ
diff --git a/test/config/80211_keys.tmpl b/test/config/80211_keys.tmpl
index 121a912739..450da23791 100644
--- a/test/config/80211_keys.tmpl
+++ b/test/config/80211_keys.tmpl
@@ -1,2 +1,5 @@
-# This file is automatically generated, DO NOT MODIFY.
+# Keys needed for the decryption test suite
"wpa-pwd","Induction"
+"wpa-psk","a5001e18e0b3f792278825bc3abff72d7021d7c157b600470ef730e2490835d4"
+"wpa-psk","79258f6ceeecedd3482b92deaabdb675f09bcb4003ef5074f5ddb10a94ebe00a"
+"wpa-psk","23a9ee58c7810546ae3e7509fda9f97435778d689e53a54891c56d02f18ca162"
diff --git a/test/suite-decryption.sh b/test/suite-decryption.sh
index 269567810a..86931676b1 100755
--- a/test/suite-decryption.sh
+++ b/test/suite-decryption.sh
@@ -74,6 +74,22 @@ decryption_step_80211_wpa_psk() {
test_step_ok
}
+# WPA EAP (EAPOL Rekey)
+# Included in git sources test/captures/wpa-eap-tls.pcap.gz
+decryption_step_80211_wpa_eap() {
+ env $TS_DC_ENV $TSHARK $TS_DC_ARGS \
+ -o "wlan.enable_decryption: TRUE" \
+ -r "$CAPTURE_DIR/wpa-eap-tls.pcap.gz" \
+ -Y "wlan.analysis.tk==7d9987daf5876249b6c773bf454a0da7" \
+ | grep "Group Message" > /dev/null 2>&1
+ RETURNVALUE=$?
+ if [ ! $RETURNVALUE -eq $EXIT_OK ]; then
+ test_step_failed "Failed to decrypt IEEE 802.11 WPA EAP"
+ return
+ fi
+ test_step_ok
+}
+
# DTLS
# https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=view&target=snakeoil.tgz
decryption_step_dtls() {
@@ -214,6 +230,7 @@ decryption_step_http2() {
tshark_decryption_suite() {
test_step_add "IEEE 802.11 WPA PSK Decryption" decryption_step_80211_wpa_psk
+ test_step_add "IEEE 802.11 WPA EAP Decryption" decryption_step_80211_wpa_eap
test_step_add "DTLS Decryption" decryption_step_dtls
test_step_add "SSL Decryption (private key)" decryption_step_ssl
test_step_add "SSL Decryption (master secret)" decryption_step_ssl_master_secret