aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDom Gifford <Dominic.Gifford@atmel.com>2014-07-24 15:32:55 +0100
committerMichael Mann <mmann78@netscape.net>2014-08-08 14:17:11 +0000
commit8da72cd43dcd597c9f03754831d55211a17f077c (patch)
tree153309d674253d9ab732aa52656d1bb1537d8a89
parent345a1d2242965b812371ad77db96351ff4673dce (diff)
Fix support for decrypting 802.11 broadcast messages.
A little bit of guess work is involved as the group key can use a different cipher to the pairwise key, and we are trying to do this purely based on the EAPOL messages with no prior knowledge of the associate request. We try to guess the cipher based on the lengths. Bug:8734 Change-Id: I4c456b45939c00a9d1122406891f704fa037349c Reviewed-on: https://code.wireshark.org/review/3183 Reviewed-by: Evan Huus <eapache@gmail.com> Reviewed-by: Michael Mann <mmann78@netscape.net>
-rw-r--r--epan/crypt/airpdcap.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/epan/crypt/airpdcap.c b/epan/crypt/airpdcap.c
index 051ee6cf82..1d920c6ff3 100644
--- a/epan/crypt/airpdcap.c
+++ b/epan/crypt/airpdcap.c
@@ -282,6 +282,16 @@ typedef struct {
#define EAPKEY_MIC_LEN 16 /* length of the MIC key for EAPoL_Key packet's MIC using MD5 */
#define NONCE_LEN 32
+#define TKIP_GROUP_KEY_LEN 32
+#define CCMP_GROUP_KEY_LEN 16
+/* Minimum size of the key bytes payload for a TKIP group key in an M3 message*/
+#define TKIP_GROUP_KEYBYTES_LEN ( sizeof(RSN_IE) + 8 + TKIP_GROUP_KEY_LEN + 6 ) /* 72 */
+/* arbitrary upper limit */
+#define TKIP_GROUP_KEYBYTES_LEN_MAX ( TKIP_GROUP_KEYBYTES_LEN + 28 )
+/* Minimum size of the key bytes payload for a TKIP group key in a group key message */
+#define TKIP_GROUP_KEYBYTES_LEN_GKEY (8 + 8 + TKIP_GROUP_KEY_LEN ) /* 48 */
+/* size of CCMP key bytes payload */
+#define CCMP_GROUP_KEYBYTES_LEN ( sizeof(RSN_IE) + 8 + CCMP_GROUP_KEY_LEN + 6 ) /* 56 */
typedef struct {
guint8 type;
guint8 key_information[2]; /* Make this an array to avoid alignment issues */
@@ -293,10 +303,11 @@ typedef struct {
guint8 key_id[8];
guint8 key_mic[EAPKEY_MIC_LEN];
guint8 key_data_len[2]; /* Make this an array rather than a U16 to avoid alignment shifting */
- guint8 ie[sizeof(RSN_IE)]; /* Make this an array to avoid alignment issues */
+ guint8 ie[TKIP_GROUP_KEYBYTES_LEN_MAX]; /* Make this an array to avoid alignment issues */
} EAPOL_RSN_KEY, * P_EAPOL_RSN_KEY;
-
-
+#define RSN_KEY_WITHOUT_KEYBYTES_LEN sizeof(EAPOL_RSN_KEY)-TKIP_GROUP_KEYBYTES_LEN_MAX
+/* 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:
@@ -334,7 +345,7 @@ decrypted version. Then Wireshark wouldn't have to decrypt packets on the fly i
static void
-AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption_key, PAIRPDCAP_SEC_ASSOCIATION sa)
+AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption_key, PAIRPDCAP_SEC_ASSOCIATION sa, gboolean group_hshake)
{
guint8 new_key[32];
guint8 key_version;
@@ -345,7 +356,7 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
/* 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. */
/* Preparation for decrypting the group key - determine group key data length */
- /* depending on whether it's a TKIP or AES encryption key */
+ /* depending on whether the pairwise key is TKIP or AES encryption key */
key_version = AIRPDCAP_EAP_KEY_DESCR_VER(pEAPKey->key_information[1]);
if (key_version == AIRPDCAP_WPA_KEY_VER_NOT_CCMP){
/* TKIP */
@@ -354,7 +365,8 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
/* AES */
key_len = pntoh16(pEAPKey->key_data_len);
}
- if (key_len > sizeof(RSN_IE) || key_len == 0) { /* Don't read past the end of pEAPKey->ie */
+
+ if (key_len > TKIP_GROUP_KEYBYTES_LEN_MAX || key_len == 0) { /* Don't read past the end of pEAPKey->ie */
return;
}
@@ -370,6 +382,13 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
memcpy(new_key+16, decryption_key, 16);
DEBUG_DUMP("FullDecrKey:", new_key, 32);
+ /* 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. */
+ /* In WPA2 its a little more tricky as the M3 keybytes contain an RSN_IE, but the group handshake */
+ /* does not. Also there are other (variable length) items in the keybytes which we need to account */
+ /* for to determine the true key length, and thus the group cipher. */
+
if (key_version == AIRPDCAP_WPA_KEY_VER_NOT_CCMP){
guint8 dummy[256];
/* TKIP key */
@@ -377,6 +396,11 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
/* group key is decrypted using RC4. Concatenate the IV with the 16 byte EK (PTK+16) to get the decryption key */
rc4_state_struct rc4_state;
+
+ /* The WPA group key just contains the GTK bytes so deducing the type is straightforward */
+ /* Note - WPA M3 doesn't contain a group key so we'll only be here for the group handshake */
+ sa->wpa.key_ver = (key_len >=TKIP_GROUP_KEY_LEN)?AIRPDCAP_WPA_KEY_VER_NOT_CCMP:AIRPDCAP_WPA_KEY_VER_AES_CCMP;
+
crypt_rc4_init(&rc4_state, new_key, sizeof(new_key));
/* Do dummy 256 iterations of the RC4 algorithm (per 802.11i, Draft 3.0, p. 97 line 6) */
@@ -390,6 +414,13 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
guint16 key_index;
guint8 *decrypted_data;
+ /* If this EAPOL frame is part of a separate group key handshake then this contains no */
+ /* RSN IE, so we can deduct that from the calculation. */
+ if (group_hshake)
+ sa->wpa.key_ver = (key_len >= (TKIP_GROUP_KEYBYTES_LEN_GKEY))?AIRPDCAP_WPA_KEY_VER_NOT_CCMP:AIRPDCAP_WPA_KEY_VER_AES_CCMP;
+ else
+ sa->wpa.key_ver = (key_len >= (TKIP_GROUP_KEYBYTES_LEN))?AIRPDCAP_WPA_KEY_VER_NOT_CCMP:AIRPDCAP_WPA_KEY_VER_AES_CCMP;
+
/* This storage is needed for the AES_unwrap function */
decrypted_data = (guint8 *) g_malloc(key_len);
@@ -429,7 +460,6 @@ AirPDcapDecryptWPABroadcastKey(const EAPOL_RSN_KEY *pEAPKey, guint8 *decryption
/* Load the proper key material info into the SA */
sa->key = &dummy_key; /* we just need key to be not null because it is checked in AirPDcapRsnaMng(). The WPA key materials are actually in the .wpa structure */
sa->validKey = TRUE;
- sa->wpa.key_ver = key_version;
/* Since this is a GTK and its size is only 32 bytes (vs. the 64 byte size of a PTK), we fake it and put it in at a 32-byte offset so the */
/* AirPDcapRsnaMng() function will extract the right piece of the GTK for decryption. (The first 16 bytes of the GTK are used for decryption.) */
@@ -458,7 +488,6 @@ AirPDcapGetSaPtr(
return &ctx->sa[sa_index];
}
-#define GROUP_KEY_PAYLOAD_LEN (8+4+sizeof(EAPOL_RSN_KEY))
static INT AirPDcapScanForGroupKey(
PAIRPDCAP_CONTEXT ctx,
const guint8 *data,
@@ -484,10 +513,9 @@ static INT AirPDcapScanForGroupKey(
#ifdef _DEBUG
CHAR msgbuf[255];
#endif
-
AIRPDCAP_DEBUG_TRACE_START("AirPDcapScanForGroupKey");
- if (mac_header_len + GROUP_KEY_PAYLOAD_LEN < tot_len) {
+ 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;
}
@@ -512,7 +540,7 @@ static INT AirPDcapScanForGroupKey(
/* get and check the body length (IEEE 802.1X-2004, pg. 25) */
bodyLength=pntoh16(data+offset+2);
- if ((tot_len-offset-4) < bodyLength) {
+ if ((tot_len-offset-4) > bodyLength) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "EAPOL body too short", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
}
@@ -585,7 +613,7 @@ static INT AirPDcapScanForGroupKey(
}
/* Extract the group key and install it in the SA */
- AirPDcapDecryptWPABroadcastKey(pEAPKey, sta_sa->wpa.ptk+16, sa);
+ AirPDcapDecryptWPABroadcastKey(pEAPKey, sta_sa->wpa.ptk+16, sa, TRUE);
}else{
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Skipping: not an EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3);
@@ -1448,7 +1476,7 @@ AirPDcapRsna4WHandshake(
if (broadcast_sa == NULL){
return AIRPDCAP_RET_UNSUCCESS;
}
- AirPDcapDecryptWPABroadcastKey(pEAPKey, sa->wpa.ptk+16, broadcast_sa);
+ AirPDcapDecryptWPABroadcastKey(pEAPKey, sa->wpa.ptk+16, broadcast_sa, FALSE);
}
return AIRPDCAP_RET_SUCCESS_HANDSHAKE;