diff options
-rw-r--r-- | epan/crypt/airpdcap.c | 54 |
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; |