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>
This commit is contained in:
deagol 2015-05-01 22:56:50 +02:00 committed by Anders Broman
parent b644698bef
commit 1439eb6778
8 changed files with 131 additions and 182 deletions

View File

@ -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" {

View File

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

View File

@ -35,13 +35,6 @@
#ifndef _AIRPDCAP_SYSTEM_H
#define _AIRPDCAP_SYSTEM_H
/************************************************************************/
/* File includes */
#include "airpdcap_interop.h"
#include "airpdcap_user.h"
#include "ws_symbol_export.h"
/************************************************************************/
/* Constant definitions */
@ -112,6 +105,13 @@
#define AIRPDCAP_CRC_LEN 4
/************************************************************************/
/* File includes */
#include "airpdcap_interop.h"
#include "airpdcap_user.h"
#include "ws_symbol_export.h"
/************************************************************************/
/* Macro definitions */

View File

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

View File

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

Binary file not shown.

View File

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

View File

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