diff options
author | Mikael Kanstrup <mikael.kanstrup@sony.com> | 2021-01-11 23:47:22 +0100 |
---|---|---|
committer | Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org> | 2021-01-20 16:10:12 +0000 |
commit | fbb9056d20c1768c1843d7ef576e0200845d474f (patch) | |
tree | e9a0b44c1e0054b13f83df33167b8ae57e96f2bd /epan/crypt | |
parent | 76932c250aeae6846d8de156875d0b74344d2702 (diff) |
dot11decrypt: Add partial FT-EAP decryption support
Add partial support for decrypting captures with connections
established using FT-EAP. To support deriving keys for FT-EAP
the MSK is needed. This change adds MSK as a valid IEEE 802.11
protocol input key type preference as well.
Note that FT-EAP support comes with the following imitations:
- Keys can only be derived from the FT 4-way handshake messages.
- Roaming is not supported.
Diffstat (limited to 'epan/crypt')
-rw-r--r-- | epan/crypt/dot11decrypt.c | 106 | ||||
-rw-r--r-- | epan/crypt/dot11decrypt_user.h | 19 | ||||
-rw-r--r-- | epan/crypt/wep-wpadefs.h | 2 |
3 files changed, 117 insertions, 10 deletions
diff --git a/epan/crypt/dot11decrypt.c b/epan/crypt/dot11decrypt.c index a2de4e2862..d86f4d59e9 100644 --- a/epan/crypt/dot11decrypt.c +++ b/epan/crypt/dot11decrypt.c @@ -1485,6 +1485,57 @@ static gboolean Dot11DecryptIsFtAkm(int akm) return FALSE; } +/* Get xxkey portion of MSK */ +/* From IEEE 802.11-2016 12.7.1.7.3 PMK-R0 */ +static const guint8 * +Dot11DecryptGetXXKeyFromMSK(const guint8 *msk, size_t msk_len, + int akm, size_t *xxkey_len) +{ + if (!xxkey_len) { + return NULL; + } + switch (akm) { + case 3: + if (msk_len < 64) { + return NULL; + } + *xxkey_len = 32; + return msk + 32; + case 13: + if (msk_len < 48) { + return NULL; + } + *xxkey_len = 48; + return msk; + default: + return NULL; + } +} + +/* From IEEE 802.11-2016 12.7.1.3 Pairwise key hierarchy */ +static void +Dot11DecryptDerivePmkFromMsk(const guint8 *msk, guint8 msk_len, int akm, + guint8 *pmk, guint8 *pmk_len) +{ + if (!msk || !pmk || !pmk_len) { + return; + } + // When using AKM suite selector 00-0F-AC:12, the length of the PMK, PMK_bits, + // shall be 384 bits. With all other AKM suite selectors, the length of the PMK, + // PMK_bits, shall be 256 bits. + if (akm == 12) { + *pmk_len = 384 / 8; + } else { + *pmk_len = 256 / 8; + } + if (msk_len + *pmk_len < msk_len) { + *pmk_len = 0; + return; + } + // PMK = L(MSK, 0, PMK_bits). + memcpy(pmk, msk, *pmk_len); +} + /* Refer to IEEE 802.11i-2004, 8.5.3, pag. 85 */ static INT Dot11DecryptRsna4WHandshake( @@ -1589,7 +1640,8 @@ Dot11DecryptRsna4WHandshake( if (sa->key!=NULL && (sa->key->KeyType==DOT11DECRYPT_KEY_TYPE_WPA_PWD || sa->key->KeyType==DOT11DECRYPT_KEY_TYPE_WPA_PSK || - sa->key->KeyType==DOT11DECRYPT_KEY_TYPE_WPA_PMK)) { + sa->key->KeyType == DOT11DECRYPT_KEY_TYPE_WPA_PMK || + sa->key->KeyType == DOT11DECRYPT_KEY_TYPE_MSK)) { DEBUG_PRINT_LINE("Try cached WPA key...", DEBUG_LEVEL_3); tmp_key=sa->key; } else { @@ -1601,7 +1653,8 @@ Dot11DecryptRsna4WHandshake( /* obviously, try only WPA keys... */ if (tmp_key->KeyType==DOT11DECRYPT_KEY_TYPE_WPA_PWD || tmp_key->KeyType==DOT11DECRYPT_KEY_TYPE_WPA_PSK || - tmp_key->KeyType==DOT11DECRYPT_KEY_TYPE_WPA_PMK) + tmp_key->KeyType == DOT11DECRYPT_KEY_TYPE_WPA_PMK || + tmp_key->KeyType == DOT11DECRYPT_KEY_TYPE_MSK) { if (tmp_key->KeyType == DOT11DECRYPT_KEY_TYPE_WPA_PWD && tmp_key->UserPwd.SsidLen == 0 && ctx->pkt_ssid_len > 0 && ctx->pkt_ssid_len <= DOT11DECRYPT_WPA_SSID_MAX_LEN) { /* We have a "wildcard" SSID. Use the one from the packet. */ @@ -1634,6 +1687,12 @@ Dot11DecryptRsna4WHandshake( return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; } + if (tmp_key->KeyType == DOT11DECRYPT_KEY_TYPE_MSK) { + Dot11DecryptDerivePmkFromMsk(tmp_key->Msk.Msk, tmp_key->Msk.Len, akm, + tmp_key->KeyData.Wpa.Psk, + &tmp_key->KeyData.Wpa.PskLen); + } + if (Dot11DecryptIsFtAkm(akm)) { int hash_algo = Dot11DecryptGetHashAlgoFromAkm(akm); guint8 pmk_r0[DOT11DECRYPT_WPA_PMK_MAX_LEN]; @@ -1644,14 +1703,29 @@ Dot11DecryptRsna4WHandshake( size_t pmk_r0_len; size_t pmk_r1_len; size_t ptk_len = Dot11DecryptGetPtkLen(akm, cipher) / 8; + const guint8 *xxkey = NULL; + size_t xxkey_len; if (!eapol_parsed->mdid || !eapol_parsed->r0kh_id || !eapol_parsed->r1kh_id) { DEBUG_PRINT_LINE("Fields missing for FT", DEBUG_LEVEL_3); return DOT11DECRYPT_RET_NO_VALID_HANDSHAKE; } - /* TODO Handle other AKMS (xxkey == PSK is only valid for FT PSK) */ - dot11decrypt_derive_pmk_r0(tmp_pkt_key->KeyData.Wpa.Psk, - tmp_pkt_key->KeyData.Wpa.PskLen, + if (tmp_key->KeyType == DOT11DECRYPT_KEY_TYPE_MSK) + { + xxkey = Dot11DecryptGetXXKeyFromMSK(tmp_key->Msk.Msk, + tmp_key->Msk.Len, + akm, + &xxkey_len); + } + if (!xxkey && tmp_pkt_key->KeyData.Wpa.PskLen > 0) { + xxkey = tmp_pkt_key->KeyData.Wpa.Psk; + xxkey_len = tmp_pkt_key->KeyData.Wpa.PskLen; + } + if (!xxkey) { + DEBUG_PRINT_LINE("no xxkey. Skipping", DEBUG_LEVEL_3); + continue; + } + dot11decrypt_derive_pmk_r0(xxkey, xxkey_len, ctx->pkt_ssid, ctx->pkt_ssid_len, eapol_parsed->mdid, eapol_parsed->r0kh_id, eapol_parsed->r0kh_id_len, @@ -1920,6 +1994,9 @@ Dot11DecryptValidateKey( case DOT11DECRYPT_KEY_TYPE_TK: break; + case DOT11DECRYPT_KEY_TYPE_MSK: + break; + default: ret=FALSE; } @@ -2556,6 +2633,25 @@ parse_key_string(gchar* input_string, guint8 key_type) g_byte_array_free(key_ba, TRUE); return dk; } + case DOT11DECRYPT_KEY_TYPE_MSK: + { + key_ba = g_byte_array_new(); + res = hex_str_to_bytes(input_string, key_ba, FALSE); + + if (!res || key_ba->len < DOT11DECRYPT_MSK_MIN_LEN || + key_ba->len > DOT11DECRYPT_MSK_MAX_LEN) + { + g_byte_array_free(key_ba, TRUE); + return NULL; + } + dk = g_new(decryption_key_t, 1); + dk->type = DOT11DECRYPT_KEY_TYPE_MSK; + dk->key = g_string_new(input_string); + dk->bits = (guint)dk->key->len * 4; + dk->ssid = NULL; + g_byte_array_free(key_ba, TRUE); + return dk; + } } /* Type not supported */ diff --git a/epan/crypt/dot11decrypt_user.h b/epan/crypt/dot11decrypt_user.h index e6bf15cb46..19cc5147f2 100644 --- a/epan/crypt/dot11decrypt_user.h +++ b/epan/crypt/dot11decrypt_user.h @@ -30,11 +30,13 @@ #define DOT11DECRYPT_KEY_TYPE_WPA_PSK 4 #define DOT11DECRYPT_KEY_TYPE_WPA_PMK 5 #define DOT11DECRYPT_KEY_TYPE_TK 6 -#define DOT11DECRYPT_KEY_TYPE_TKIP 7 -#define DOT11DECRYPT_KEY_TYPE_CCMP 8 -#define DOT11DECRYPT_KEY_TYPE_CCMP_256 9 -#define DOT11DECRYPT_KEY_TYPE_GCMP 10 -#define DOT11DECRYPT_KEY_TYPE_GCMP_256 11 +#define DOT11DECRYPT_KEY_TYPE_MSK 7 + +#define DOT11DECRYPT_KEY_TYPE_TKIP 100 +#define DOT11DECRYPT_KEY_TYPE_CCMP 101 +#define DOT11DECRYPT_KEY_TYPE_CCMP_256 102 +#define DOT11DECRYPT_KEY_TYPE_GCMP 103 +#define DOT11DECRYPT_KEY_TYPE_GCMP_256 104 #define DOT11DECRYPT_KEY_TYPE_UNKNOWN -1 /* Decryption algorithms fields size definition (bytes) */ @@ -50,6 +52,8 @@ #define DOT11DECRYPT_WPA_PMK_MAX_LEN 48 #define DOT11DECRYPT_WPA_PWD_PSK_LEN 32 #define DOT11DECRYPT_TK_MAX_LEN 32 +#define DOT11DECRYPT_MSK_MIN_LEN 64 +#define DOT11DECRYPT_MSK_MAX_LEN 128 /* */ /* */ /******************************************************************************/ @@ -145,6 +149,11 @@ typedef struct _DOT11DECRYPT_KEY_ITEM { guint8 Len; } Tk; + struct DOT11DECRYPT_KEY_ITEMDATA_MSK { + guint8 Msk[DOT11DECRYPT_MSK_MAX_LEN]; + guint8 Len; + } Msk; + struct DOT11DECRYPT_KEY_ITEMDATA_PWD { /** * The string (null-terminated) value of diff --git a/epan/crypt/wep-wpadefs.h b/epan/crypt/wep-wpadefs.h index 4395994a6f..ae6aa988cf 100644 --- a/epan/crypt/wep-wpadefs.h +++ b/epan/crypt/wep-wpadefs.h @@ -73,6 +73,8 @@ extern "C" { #define STRING_KEY_TYPE_WPA_PWD "wpa-pwd" #define STRING_KEY_TYPE_WPA_PSK "wpa-psk" #define STRING_KEY_TYPE_TK "tk" +#define STRING_KEY_TYPE_MSK "msk" + #ifdef __cplusplus } |