aboutsummaryrefslogtreecommitdiffstats
path: root/epan/crypt
diff options
context:
space:
mode:
authorMikael Kanstrup <mikael.kanstrup@sony.com>2021-01-11 23:47:22 +0100
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-01-20 16:10:12 +0000
commitfbb9056d20c1768c1843d7ef576e0200845d474f (patch)
treee9a0b44c1e0054b13f83df33167b8ae57e96f2bd /epan/crypt
parent76932c250aeae6846d8de156875d0b74344d2702 (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.c106
-rw-r--r--epan/crypt/dot11decrypt_user.h19
-rw-r--r--epan/crypt/wep-wpadefs.h2
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
}