WPA/WPA2 decoding fixes and improvements

- start decoding when we have eapol1+2 packets
  Do not insist on a complete captured handshake, decode what we can.

- more robust way to detect eapol #2 packets
  At least Win 10 is violating the spec on rekey by setting the secure
  bit in #2. Unpatched version shows and handles #2 as #4, breaking
  decoding after rekey.

- fixed eapol rekey key handling
  Inital patch (see https://code.wireshark.org/review/8268)
  is adding redundant keys, since it scans all the time
  and not only once.

- ignore tailing garbage after eapol sections in frame
  See https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9065#c8

Included testcase to test decode for incomplete handshakes and eapol2
packets with secure bit set on rekey.

Ping-Bug: 9065
Change-Id: Id775088db9b5aaa80da9efdeed6902d024b5c0cd
Reviewed-on: https://code.wireshark.org/review/11484
Reviewed-by: Michael Mann <mmann78@netscape.net>
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
This commit is contained in:
Alexander Wetzel 2015-11-01 18:49:42 +01:00 committed by Alexis La Goutte
parent d4985a5acb
commit cb3dd958af
8 changed files with 229 additions and 263 deletions

View File

@ -523,7 +523,7 @@ static INT AirPDcapScanForKeys(
/* 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) { /* Only check if frame is long enough for eapol header, ignore tailing garbage, see bug 9065 */
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "EAPOL body too short", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
}
@ -548,6 +548,7 @@ static INT AirPDcapScanForKeys(
/* search for a cached Security Association for current BSSID and AP */
sa = AirPDcapGetSaPtr(ctx, &id);
if (sa == NULL){
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForKeys", "No SA for BSSID found", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_UNSUCCESS;
}
@ -618,11 +619,12 @@ INT AirPDcapPacketProcess(
UCHAR *decrypt_data,
guint *decrypt_len,
PAIRPDCAP_KEY_ITEM key,
gboolean mngHandshake,
gboolean mngDecrypt)
gboolean scanHandshake)
{
const UCHAR *addr;
AIRPDCAP_SEC_ASSOCIATION_ID id;
UCHAR tmp_data[AIRPDCAP_MAX_CAPLEN];
guint tmp_len;
#ifdef _DEBUG
#define MSGBUF_LEN 255
@ -657,9 +659,6 @@ INT AirPDcapPacketProcess(
/* get BSSID */
if ( (addr=AirPDcapGetBssidAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) {
memcpy(id.bssid, addr, AIRPDCAP_MAC_LEN);
#ifdef _DEBUG
g_snprintf(msgbuf, MSGBUF_LEN, "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);
@ -669,9 +668,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
g_snprintf(msgbuf, MSGBUF_LEN, "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);
@ -679,77 +675,78 @@ INT AirPDcapPacketProcess(
}
/* check if data is encrypted (use the WEP bit in the Frame Control field) */
if (AIRPDCAP_WEP(data[1])==0)
{
if (mngHandshake) {
if (AIRPDCAP_WEP(data[1])==0) {
if (scanHandshake) {
/* 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);
return (AirPDcapScanForKeys(ctx, data, mac_header_len, tot_len, id, key));
}
} else {
if (mngDecrypt) {
PAIRPDCAP_SEC_ASSOCIATION sa;
int offset = 0;
PAIRPDCAP_SEC_ASSOCIATION sa;
int offset = 0;
/* get the Security Association structure for the STA and AP */
sa = AirPDcapGetSaPtr(ctx, &id);
if (sa == NULL){
return AIRPDCAP_RET_UNSUCCESS;
}
/* get the Security Association structure for the STA and AP */
sa = AirPDcapGetSaPtr(ctx, &id);
if (sa == NULL){
return AIRPDCAP_RET_UNSUCCESS;
}
/* cache offset in the packet data (to scan encryption data) */
offset = mac_header_len;
/* cache offset in the packet data (to scan encryption data) */
offset = mac_header_len;
if (decrypt_data==NULL)
return AIRPDCAP_RET_UNSUCCESS;
if (decrypt_data==NULL) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "no decrypt buffer, use local", AIRPDCAP_DEBUG_LEVEL_3);
decrypt_data=tmp_data;
decrypt_len=&tmp_len;
}
/* create new header and data to modify */
*decrypt_len = tot_len;
memcpy(decrypt_data, data, *decrypt_len);
/* create new header and data to modify */
*decrypt_len = tot_len;
memcpy(decrypt_data, data, *decrypt_len);
/* encrypted data */
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Encrypted data", AIRPDCAP_DEBUG_LEVEL_3);
/* encrypted data */
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Encrypted data", AIRPDCAP_DEBUG_LEVEL_3);
/* check the Extension IV to distinguish between WEP encryption and WPA encryption */
/* refer to IEEE 802.11i-2004, 8.2.1.2, pag.35 for WEP, */
/* IEEE 802.11i-2004, 8.3.2.2, pag. 45 for TKIP, */
/* IEEE 802.11i-2004, 8.3.3.2, pag. 57 for CCMP */
if (AIRPDCAP_EXTIV(data[offset+3])==0) {
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 {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "TKIP or CCMP encryption", AIRPDCAP_DEBUG_LEVEL_3);
/* check the Extension IV to distinguish between WEP encryption and WPA encryption */
/* refer to IEEE 802.11i-2004, 8.2.1.2, pag.35 for WEP, */
/* IEEE 802.11i-2004, 8.3.2.2, pag. 45 for TKIP, */
/* IEEE 802.11i-2004, 8.3.3.2, pag. 57 for CCMP */
if (AIRPDCAP_EXTIV(data[offset+3])==0) {
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 {
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
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 (AIRPDCAP_KEY_INDEX(data[offset+3])>=1){
/* If index >= 1, then 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 (AIRPDCAP_KEY_INDEX(data[offset+3])>=1){
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "The key index = 1. This is encrypted with a group key.", AIRPDCAP_DEBUG_LEVEL_3);
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "The key index = 1. This is encrypted with a group key.", AIRPDCAP_DEBUG_LEVEL_3);
/* force STA address to broadcast MAC so we load the SA for the groupkey */
memcpy(id.sta, broadcast_mac, AIRPDCAP_MAC_LEN);
/* force STA address to broadcast MAC so we load the SA for the groupkey */
memcpy(id.sta, broadcast_mac, AIRPDCAP_MAC_LEN);
#ifdef _DEBUG
g_snprintf(msgbuf, MSGBUF_LEN, "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);
g_snprintf(msgbuf, MSGBUF_LEN, "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){
return AIRPDCAP_RET_UNSUCCESS;
}
}
/* search for a cached Security Association for current BSSID and broadcast MAC */
sa = AirPDcapGetSaPtr(ctx, &id);
if (sa == NULL)
return AIRPDCAP_RET_UNSUCCESS;
}
/* Decrypt the packet using the appropriate SA */
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);
/* Decrypt the packet using the appropriate SA */
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. */
if (scanHandshake) {
return (AirPDcapScanForKeys(ctx, decrypt_data, mac_header_len, *decrypt_len, id, NULL));
} else {
return AIRPDCAP_RET_SUCCESS;
}
}
@ -980,8 +977,9 @@ AirPDcapRsnaMng(
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "No key associated", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_REQ_DATA;
}
if (sa->validKey==FALSE) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "Key not yet valid", AIRPDCAP_DEBUG_LEVEL_3);
if (*decrypt_len > try_data_len) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "Invalid decryption length", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_UNSUCCESS;
}
@ -991,11 +989,10 @@ AirPDcapRsnaMng(
/* start of loop added by GCS */
for(/* sa */; sa != NULL ;sa=sa->next) {
if (*decrypt_len > try_data_len) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "Invalid decryption length", AIRPDCAP_DEBUG_LEVEL_3);
g_free(try_data);
return AIRPDCAP_RET_UNSUCCESS;
}
if (sa->validKey==FALSE) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "Key not yet valid", AIRPDCAP_DEBUG_LEVEL_3);
continue;
}
/* copy the encrypted data into a temp buffer */
memcpy(try_data, decrypt_data, *decrypt_len);
@ -1107,8 +1104,7 @@ AirPDcapWepMng(
}
/* obviously, try only WEP keys... */
if (tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WEP)
{
if (tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WEP) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapWepMng", "Try WEP key...", AIRPDCAP_DEBUG_LEVEL_3);
memset(wep_key, 0, sizeof(wep_key));
@ -1202,13 +1198,6 @@ AirPDcapRsna4WHandshake(
/* TODO timeouts? */
/* This saves the sa since we are reauthenticating which will overwrite our current sa GCS*/
if(sa->handshake == 4) {
tmp_sa= g_new(AIRPDCAP_SEC_ASSOCIATION, 1);
memcpy(tmp_sa, sa, sizeof(AIRPDCAP_SEC_ASSOCIATION));
sa->next=tmp_sa;
}
/* TODO consider key-index */
/* TODO considera Deauthentications */
@ -1229,6 +1218,14 @@ AirPDcapRsna4WHandshake(
/* local value, the Supplicant discards the message. */
/* -> not checked, the Authenticator will be send another Message 1 (hopefully!) */
/* This saves the sa since we are reauthenticating which will overwrite our current sa GCS*/
if( sa->handshake >= 2) {
tmp_sa= g_new(AIRPDCAP_SEC_ASSOCIATION, 1);
memcpy(tmp_sa, sa, sizeof(AIRPDCAP_SEC_ASSOCIATION));
sa->validKey=FALSE;
sa->next=tmp_sa;
}
/* save ANonce (from authenticator) to derive the PTK with the SNonce (from the 2 message) */
memcpy(sa->wpa.nonce, data+offset+12, 32);
@ -1245,139 +1242,117 @@ AirPDcapRsna4WHandshake(
AIRPDCAP_EAP_ACK(data[offset+1])==0 &&
AIRPDCAP_EAP_MIC(data[offset])==1)
{
if (AIRPDCAP_EAP_SEC(data[offset])==0) {
/* Check nonce to differentiate between message 2 or 4
* nonce will be non zero for message 2 and zero for message 4.
* At least needed for Windows, since it is setting the secure bit on message 2 when rekeying */
if (!memiszero(data+offset+12, 32)) {
/* message 2 */
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 2", AIRPDCAP_DEBUG_LEVEL_3);
/* PATCH: some implementations set secure bit to 0 also in the 4th message */
/* to recognize which message is this check if wep_key data length is 0 */
/* in the 4th message */
if (data[offset+92]!=0 || data[offset+93]!=0) {
/* message 2 */
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 2", AIRPDCAP_DEBUG_LEVEL_3);
/* On reception of Message 2, the Authenticator checks that the key replay counter corresponds to the */
/* outstanding Message 1. If not, it silently discards the message. */
/* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, */
/* the Authenticator silently discards Message 2. */
/* -> not checked; the Supplicant will send another message 2 (hopefully!) */
/* On reception of Message 2, the Authenticator checks that the key replay counter corresponds to the */
/* outstanding Message 1. If not, it silently discards the message. */
/* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, */
/* the Authenticator silently discards Message 2. */
/* -> not checked; the Supplicant will send another message 2 (hopefully!) */
/* now you can derive the PTK */
for (key_index=0; key_index<(INT)ctx->keys_nr || useCache; key_index++) {
/* use the cached one, or try all keys */
if (!useCache) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Try WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
/* now you can derive the PTK */
for (key_index=0; key_index<(INT)ctx->keys_nr || useCache; key_index++) {
/* use the cached one, or try all keys */
if (!useCache) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Try WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
tmp_key=&ctx->keys[key_index];
} else {
/* there is a cached key in the security association, if it's a WPA key try it... */
if (sa->key!=NULL &&
(sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK)) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Try cached WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
tmp_key=sa->key;
} else {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Cached key is of a wrong type, try WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
tmp_key=&ctx->keys[key_index];
} else {
/* there is a cached key in the security association, if it's a WPA key try it... */
if (sa->key!=NULL &&
(sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK)) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Try cached WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
tmp_key=sa->key;
} else {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Cached key is of a wrong type, try WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
tmp_key=&ctx->keys[key_index];
}
}
/* obviously, try only WPA keys... */
if (tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK)
{
if (tmp_key->KeyType == AIRPDCAP_KEY_TYPE_WPA_PWD && tmp_key->UserPwd.SsidLen == 0 && ctx->pkt_ssid_len > 0 && ctx->pkt_ssid_len <= AIRPDCAP_WPA_SSID_MAX_LEN) {
/* We have a "wildcard" SSID. Use the one from the packet. */
memcpy(&pkt_key, tmp_key, sizeof(pkt_key));
memcpy(&pkt_key.UserPwd.Ssid, ctx->pkt_ssid, ctx->pkt_ssid_len);
pkt_key.UserPwd.SsidLen = ctx->pkt_ssid_len;
AirPDcapRsnaPwd2Psk(pkt_key.UserPwd.Passphrase, pkt_key.UserPwd.Ssid,
pkt_key.UserPwd.SsidLen, pkt_key.KeyData.Wpa.Psk);
tmp_pkt_key = &pkt_key;
} else {
tmp_pkt_key = tmp_key;
}
/* derive the PTK from the BSSID, STA MAC, PMK, SNonce, ANonce */
AirPDcapRsnaPrfX(sa, /* authenticator nonce, bssid, station mac */
tmp_pkt_key->KeyData.Wpa.Psk, /* PSK == PMK */
data+offset+12, /* supplicant nonce */
512,
sa->wpa.ptk);
/* verify the MIC (compare the MIC in the packet included in this message with a MIC calculated with the PTK) */
eapol_len=pntoh16(data+offset-3)+4;
memcpy(eapol, &data[offset-5], (eapol_len<AIRPDCAP_EAPOL_MAX_LEN?eapol_len:AIRPDCAP_EAPOL_MAX_LEN));
ret_value=AirPDcapRsnaMicCheck(eapol, /* eapol frame (header also) */
eapol_len, /* eapol frame length */
sa->wpa.ptk, /* Key Confirmation Key */
AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])); /* EAPOL-Key description version */
/* If the MIC is valid, the Authenticator checks that the RSN information element bit-wise matches */
/* that from the (Re)Association Request message. */
/* i) TODO If these are not exactly the same, the Authenticator uses MLME-DEAUTHENTICATE.request */
/* primitive to terminate the association. */
/* ii) If they do match bit-wise, the Authenticator constructs Message 3. */
}
if (!ret_value &&
(tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK))
{
/* the temporary key is the correct one, cached in the Security Association */
sa->key=tmp_key;
if (key!=NULL) {
memcpy(key, tmp_key, sizeof(AIRPDCAP_KEY_ITEM));
if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_NOT_CCMP)
key->KeyType=AIRPDCAP_KEY_TYPE_TKIP;
else if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_AES_CCMP)
key->KeyType=AIRPDCAP_KEY_TYPE_CCMP;
}
break;
} else {
/* the cached key was not valid, try other keys */
if (useCache==TRUE) {
useCache=FALSE;
key_index--;
}
}
}
if (ret_value) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "handshake step failed", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
/* obviously, try only WPA keys... */
if (tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK)
{
if (tmp_key->KeyType == AIRPDCAP_KEY_TYPE_WPA_PWD && tmp_key->UserPwd.SsidLen == 0 && ctx->pkt_ssid_len > 0 && ctx->pkt_ssid_len <= AIRPDCAP_WPA_SSID_MAX_LEN) {
/* We have a "wildcard" SSID. Use the one from the packet. */
memcpy(&pkt_key, tmp_key, sizeof(pkt_key));
memcpy(&pkt_key.UserPwd.Ssid, ctx->pkt_ssid, ctx->pkt_ssid_len);
pkt_key.UserPwd.SsidLen = ctx->pkt_ssid_len;
AirPDcapRsnaPwd2Psk(pkt_key.UserPwd.Passphrase, pkt_key.UserPwd.Ssid,
pkt_key.UserPwd.SsidLen, pkt_key.KeyData.Wpa.Psk);
tmp_pkt_key = &pkt_key;
} else {
tmp_pkt_key = tmp_key;
}
/* derive the PTK from the BSSID, STA MAC, PMK, SNonce, ANonce */
AirPDcapRsnaPrfX(sa, /* authenticator nonce, bssid, station mac */
tmp_pkt_key->KeyData.Wpa.Psk, /* PSK == PMK */
data+offset+12, /* supplicant nonce */
512,
sa->wpa.ptk);
/* verify the MIC (compare the MIC in the packet included in this message with a MIC calculated with the PTK) */
eapol_len=pntoh16(data+offset-3)+4;
memcpy(eapol, &data[offset-5], (eapol_len<AIRPDCAP_EAPOL_MAX_LEN?eapol_len:AIRPDCAP_EAPOL_MAX_LEN));
ret_value=AirPDcapRsnaMicCheck(eapol, /* eapol frame (header also) */
eapol_len, /* eapol frame length */
sa->wpa.ptk, /* Key Confirmation Key */
AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])); /* EAPOL-Key description version */
/* If the MIC is valid, the Authenticator checks that the RSN information element bit-wise matches */
/* that from the (Re)Association Request message. */
/* i) TODO If these are not exactly the same, the Authenticator uses MLME-DEAUTHENTICATE.request */
/* primitive to terminate the association. */
/* ii) If they do match bit-wise, the Authenticator constructs Message 3. */
}
sa->handshake=2;
if (!ret_value &&
(tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK))
{
/* the temporary key is the correct one, cached in the Security Association */
return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
} else {
/* message 4 */
sa->key=tmp_key;
/* TODO "Note that when the 4-Way Handshake is first used Message 4 is sent in the clear." */
if (key!=NULL) {
memcpy(key, tmp_key, sizeof(AIRPDCAP_KEY_ITEM));
if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_NOT_CCMP)
key->KeyType=AIRPDCAP_KEY_TYPE_TKIP;
else if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_AES_CCMP)
key->KeyType=AIRPDCAP_KEY_TYPE_CCMP;
}
/* TODO check MIC and Replay Counter */
/* On reception of Message 4, the Authenticator verifies that the Key Replay Counter field value is one */
/* that it used on this 4-Way Handshake; if it is not, it silently discards the message. */
/* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, the */
/* Authenticator silently discards Message 4. */
break;
} else {
/* the cached key was not valid, try other keys */
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 4 (patched)", AIRPDCAP_DEBUG_LEVEL_3);
sa->handshake=4;
sa->validKey=TRUE;
return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
if (useCache==TRUE) {
useCache=FALSE;
key_index--;
}
}
}
/* END OF PATCH */
/* */
if (ret_value) {
AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "handshake step failed", AIRPDCAP_DEBUG_LEVEL_3);
return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
}
sa->handshake=2;
sa->validKey=TRUE; /* we can use the key to decode, even if we have not captured the other eapol packets */
return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
} else {
/* message 4 */
/* message 4 */
/* TODO "Note that when the 4-Way Handshake is first used Message 4 is sent in the clear." */
@ -1391,8 +1366,6 @@ AirPDcapRsna4WHandshake(
sa->handshake=4;
sa->validKey=TRUE;
return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
}
}
@ -1536,7 +1509,6 @@ AirPDcapGetSa(
AIRPDCAP_SEC_ASSOCIATION_ID *id)
{
INT sa_index;
if (ctx->sa_index!=-1) {
/* at least one association was stored */
/* search for the association from sa_index to 0 (most recent added) */
@ -1559,7 +1531,6 @@ AirPDcapStoreSa(
AIRPDCAP_SEC_ASSOCIATION_ID *id)
{
INT last_free;
if (ctx->first_free_index>=AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR) {
/* there is no empty space available. FAILURE */
return -1;

View File

@ -89,7 +89,7 @@ void print_debug_line(const CHAR *function, const CHAR *msg, const INT level);
#endif
#endif
static inline void DEBUG_DUMP(x,y,z)
static inline void DEBUG_DUMP(const char* x, guint8* y, int z)
{
char* tmp_str = bytes_to_str(NULL, (const guint8 *) y, (z));
g_warning("%s: %s", x, tmp_str);

View File

@ -233,8 +233,7 @@ extern INT AirPDcapPacketProcess(
UCHAR *decrypt_data,
guint32 *decrypt_len,
PAIRPDCAP_KEY_ITEM key,
gboolean mngHandshake,
gboolean mngDecrypt)
gboolean scanHandshake)
;
/**

View File

@ -78,6 +78,17 @@
/* */
/* */
/******************************************************************************/
static inline gboolean memiszero (const void *ptr, size_t count) {
const guint8 *p = (const guint8 *)ptr;
while (count != 0) {
if (*p != 0)
return FALSE;
p++;
count--;
}
return TRUE;
}
/******************************************************************************/
/* Type definitions */

View File

@ -17709,7 +17709,8 @@ dissect_ieee80211_common (tvbuff_t *tvb, packet_info *pinfo,
/* and WPA2 decryption */
if (enable_decryption && !pinfo->fd->flags.visited) {
const guint8 *enc_data = tvb_get_ptr(tvb, 0, hdr_len+reported_len);
AirPDcapPacketProcess(&airpdcap_ctx, enc_data, hdr_len, hdr_len+reported_len, NULL, 0, NULL, TRUE, FALSE);
AirPDcapPacketProcess(&airpdcap_ctx, enc_data, hdr_len, hdr_len+reported_len, NULL, 0, NULL, TRUE);
}
/* Davide Schiera -------------------------------------------------------- */
@ -18532,7 +18533,7 @@ static gint ett_wlan_rsna_eapol_keydes_data = -1;
static const true_false_string keyinfo_key_type_tfs = { "Pairwise Key", "Group Key" };
static int
dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_rsn)
dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
int offset = 0;
guint16 keyinfo;
@ -18553,54 +18554,32 @@ dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_
col_set_str(pinfo->cinfo, COL_INFO, "Key (Request, Error)");
} else if (keyinfo & KEY_INFO_KEY_TYPE_MASK) {
guint16 masked;
/* At least Windows is incorrectly setting Secure bit on message 2 when rekeying
* we'll ignore the secure bit also for RSN and use the key nonce to differentiate between message 2 and 4 */
masked = keyinfo &
(KEY_INFO_INSTALL_MASK | KEY_INFO_KEY_ACK_MASK |
KEY_INFO_KEY_MIC_MASK | KEY_INFO_SECURE_MASK);
(KEY_INFO_INSTALL_MASK | KEY_INFO_KEY_ACK_MASK | KEY_INFO_KEY_MIC_MASK);
if (!is_rsn) {
/* WPA */
switch (masked) {
case KEY_INFO_KEY_ACK_MASK:
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 1 of 4)");
break;
switch (masked) {
case KEY_INFO_KEY_ACK_MASK:
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 1 of 4)");
break;
case KEY_INFO_KEY_MIC_MASK:
/* Check start of nonce for check if it is message 2 or 4
According to the IEEE specification, sections 11.6.6.3 and 11.6.6.5
define the value for the WPA Key Nonce as following:
Message #2, Key Nonce = SNonce (Supplicant Nonce)
Message #4, Key Nonce = 0 */
start_nonce = tvb_get_ntohl(tvb, offset+12);
if (start_nonce)
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 2 of 4)");
else
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 4 of 4)");
break;
case (KEY_INFO_INSTALL_MASK | KEY_INFO_KEY_ACK_MASK | KEY_INFO_KEY_MIC_MASK):
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 3 of 4)");
break;
}
} else {
/* RSN */
switch (masked) {
case KEY_INFO_KEY_ACK_MASK:
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 1 of 4)");
break;
case KEY_INFO_KEY_MIC_MASK:
case KEY_INFO_KEY_MIC_MASK:
/* Check start of nonce for check if it is message 2 or 4
According to the IEEE specification, sections 11.6.6.3 and 11.6.6.5
define the value for the WPA Key Nonce as following:
Message #2, Key Nonce = SNonce (Supplicant Nonce)
Message #4, Key Nonce = 0 */
start_nonce = tvb_get_ntohl(tvb, offset+12);
if (start_nonce)
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 2 of 4)");
break;
case (KEY_INFO_INSTALL_MASK | KEY_INFO_KEY_ACK_MASK | KEY_INFO_KEY_MIC_MASK | KEY_INFO_SECURE_MASK):
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 3 of 4)");
break;
case (KEY_INFO_KEY_MIC_MASK | KEY_INFO_SECURE_MASK):
else
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 4 of 4)");
break;
}
break;
case (KEY_INFO_INSTALL_MASK | KEY_INFO_KEY_ACK_MASK | KEY_INFO_KEY_MIC_MASK):
col_set_str(pinfo->cinfo, COL_INFO, "Key (Message 3 of 4)");
break;
}
} else {
if (keyinfo & KEY_INFO_KEY_ACK_MASK)
@ -18671,18 +18650,6 @@ dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_
return tvb_captured_length(tvb);
}
static int
dissect_wlan_rsna_eapol_wpa_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
return dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvb, pinfo, tree, FALSE);
}
static int
dissect_wlan_rsna_eapol_rsn_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
return dissect_wlan_rsna_eapol_wpa_or_rsn_key(tvb, pinfo, tree, TRUE);
}
/* Davide Schiera (2006-11-26): this function will try to decrypt with WEP or */
/* WPA and return a tvb to the caller to add a new tab. It returns the */
/* algorithm used for decryption (WEP, TKIP, CCMP) and the header and */
@ -18703,7 +18670,7 @@ 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)==AIRPDCAP_RET_SUCCESS)
{
guint8 *tmp;
*algorithm=used_key->KeyType;
@ -27294,10 +27261,10 @@ proto_reg_handoff_ieee80211(void)
/*
* EAPOL key descriptor types.
*/
wlan_rsna_eapol_wpa_key_handle = new_create_dissector_handle(dissect_wlan_rsna_eapol_wpa_key,
wlan_rsna_eapol_wpa_key_handle = new_create_dissector_handle(dissect_wlan_rsna_eapol_wpa_or_rsn_key,
proto_wlan_rsna_eapol);
dissector_add_uint("eapol.keydes.type", EAPOL_WPA_KEY, wlan_rsna_eapol_wpa_key_handle);
wlan_rsna_eapol_rsn_key_handle = new_create_dissector_handle(dissect_wlan_rsna_eapol_rsn_key,
wlan_rsna_eapol_rsn_key_handle = new_create_dissector_handle(dissect_wlan_rsna_eapol_wpa_or_rsn_key,
proto_wlan_rsna_eapol);
dissector_add_uint("eapol.keydes.type", EAPOL_RSN_KEY, wlan_rsna_eapol_rsn_key_handle);

Binary file not shown.

View File

@ -1,5 +1,6 @@
# Keys needed for the decryption test suite
"wpa-pwd","Induction"
"wpa-pwd","test0815"
"wpa-psk","a5001e18e0b3f792278825bc3abff72d7021d7c157b600470ef730e2490835d4"
"wpa-psk","79258f6ceeecedd3482b92deaabdb675f09bcb4003ef5074f5ddb10a94ebe00a"
"wpa-psk","23a9ee58c7810546ae3e7509fda9f97435778d689e53a54891c56d02f18ca162"

View File

@ -89,6 +89,22 @@ decryption_step_80211_wpa_eap() {
fi
test_step_ok
}
# WPA decode with message1+2 only and secure bit set on message 2
# Included in git sources test/captures/wpa-test-decode.pcap.gz
decryption_step_80211_wpa_eapol_incomplete_rekeys() {
$TESTS_DIR/run_and_catch_crashes env $TS_DC_ENV $TSHARK $TS_DC_ARGS \
-o "wlan.enable_decryption: TRUE" \
-r "$CAPTURE_DIR/wpa-test-decode.pcap.gz" \
-Y "icmp.resp_to == 4263" \
| grep "Echo" > /dev/null 2>&1
RETURNVALUE=$?
if [ ! $RETURNVALUE -eq $EXIT_OK ]; then
test_step_failed "Not able to follow rekey with missing eapol frames"
return
fi
test_step_ok
}
# DTLS
# https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=view&target=snakeoil.tgz
@ -266,6 +282,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 PSK Decryption2 (EAPOL frames missing for Win 10 client)" decryption_step_80211_wpa_eapol_incomplete_rekeys
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