wireshark/epan/dissectors/packet-eapol.c
Mikael Kanstrup 3fdabc62d4 dot11decrypt: Let dissector parse eapol frames
To be able to support authentication key management suites that use
different MIC, PMK, PTK lengths the engine would need to be extended
to support parsing EAPOL Key frames with variable field lengts. Though
as the IEEE 802.11 dissector already support this the alternative
(implemented in this patch) is to remove the EAPOL frame parsing inside
the engine and have the dissector feed it with a struct of parsed
fields instead.

For this a new type DOT11DECRYPT_EAPOL_PARSED is exported and
dot11decrypt now expects dissector to fill this struct with parsed
EAPOL fields before calling Dot11DecryptScanEapolForKeys.

Dissection of EAPOL fields is scattered over several functions in the
dissector code so parsed fields are temporarily stored in proto data
and then gathered before fed into dot11decrypt engine.

Change-Id: Ic6aeb4900f373dcde1ea3f1f0f24df2ae827576e
Reviewed-on: https://code.wireshark.org/review/35020
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
2019-11-14 08:25:13 +00:00

347 lines
11 KiB
C

/* packet-eapol.c
* Routines for EAPOL and EAPOL-Key IEEE 802.1X-2010 PDU dissection
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/etypes.h>
#include <epan/eapol_keydes_types.h>
#include <epan/proto_data.h>
#include "packet-eapol.h"
void proto_register_eapol(void);
void proto_reg_handoff_eapol(void);
int proto_eapol = -1;
static int hf_eapol_version = -1;
static int hf_eapol_type = -1;
static int hf_eapol_len = -1;
static int hf_eapol_keydes_type = -1;
static int hf_eapol_keydes_body = -1;
static int hf_eapol_keydes_key_len = -1;
static int hf_eapol_keydes_replay_counter = -1;
static int hf_eapol_keydes_key_iv = -1;
static int hf_eapol_keydes_key_index = -1;
static int hf_eapol_keydes_key_index_type = -1;
static int hf_eapol_keydes_key_index_number = -1;
static int hf_eapol_keydes_key_signature = -1;
static int hf_eapol_keydes_key = -1;
static int hf_eapol_keydes_key_generated_locally = -1;
static gint ett_eapol = -1;
static gint ett_eapol_key_index = -1;
static gint ett_keyinfo = -1;
static dissector_table_t eapol_type_dissector_table;
static dissector_table_t eapol_keydes_type_dissector_table;
static dissector_handle_t eapol_handle;
#define EAPOL_HDR_LEN 4
#define EAPOL_2001 1
#define EAPOL_2004 2
#define EAPOL_2010 3
static const value_string eapol_version_vals[] = {
{ EAPOL_2001, "802.1X-2001" },
{ EAPOL_2004, "802.1X-2004" },
{ EAPOL_2010, "802.1X-2010" },
{ 0, NULL }
};
static const value_string eapol_type_vals[] = {
{ EAPOL_EAP, "EAP Packet" },
{ EAPOL_START, "Start" },
{ EAPOL_LOGOFF, "Logoff" },
{ EAPOL_KEY, "Key" },
{ EAPOL_ENCAP_ASF_ALERT, "Encapsulated ASF Alert" },
{ EAPOL_MKA, "MKA" },
{ EAPOL_ANNOUNCEMENT_GENERIC, "Announcement (Generic)" },
{ EAPOL_ANNOUNCEMENT_SPECIFIC, "Announcement (Specific)" },
{ EAPOL_ANNOUNCEMENT_REQUEST, "Announcement Request" },
{ 0, NULL }
};
static const value_string eapol_keydes_type_vals[] = {
{ EAPOL_RC4_KEY, "RC4 Descriptor" },
{ EAPOL_RSN_KEY, "EAPOL RSN Key" },
{ EAPOL_WPA_KEY, "EAPOL WPA Key" },
{ 0, NULL }
};
static const true_false_string keytype_tfs = { "Unicast", "Broadcast" };
#define KEYDES_KEY_INDEX_TYPE_MASK 0x80
#define KEYDES_KEY_INDEX_NUMBER_MASK 0x7F
static int
dissect_eapol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
int offset = 0;
guint8 eapol_type;
guint16 eapol_len;
guint len;
proto_tree *ti;
proto_tree *eapol_tree;
tvbuff_t *next_tvb;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAPOL");
col_clear(pinfo->cinfo, COL_INFO);
ti = proto_tree_add_item(tree, proto_eapol, tvb, 0, -1, ENC_NA);
eapol_tree = proto_item_add_subtree(ti, ett_eapol);
proto_tree_add_item(eapol_tree, hf_eapol_version, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
eapol_type = tvb_get_guint8(tvb, offset);
proto_tree_add_item(eapol_tree, hf_eapol_type, tvb, offset, 1, ENC_BIG_ENDIAN);
col_add_str(pinfo->cinfo, COL_INFO,
val_to_str(eapol_type, eapol_type_vals, "Unknown Type (0x%02X)"));
offset++;
eapol_len = tvb_get_ntohs(tvb, offset);
len = EAPOL_HDR_LEN + eapol_len;
set_actual_length(tvb, len);
if (tree) {
proto_item_set_len(ti, len);
proto_tree_add_item(eapol_tree, hf_eapol_len, tvb, offset, 2, ENC_BIG_ENDIAN);
}
offset += 2;
/* Save eapol key type packets for IEEE 802.11 dissector */
if (!pinfo->fd->visited && eapol_type == EAPOL_KEY) {
proto_eapol_key_frame_t *key_frame = wmem_new(pinfo->pool, proto_eapol_key_frame_t);
key_frame->type = 0;
key_frame->len = len;
key_frame->data = (guint8 *)wmem_alloc(pinfo->pool, len);
tvb_memcpy(tvb, key_frame->data, 0, len);
p_add_proto_data(pinfo->pool, pinfo, proto_eapol, EAPOL_KEY_FRAME_KEY, key_frame);
}
next_tvb = tvb_new_subset_remaining(tvb, offset);
if (!dissector_try_uint_new(eapol_type_dissector_table,
eapol_type, next_tvb, pinfo, tree,
FALSE, eapol_tree)) {
call_data_dissector(next_tvb, pinfo, tree);
}
return tvb_captured_length(tvb);
}
static int
dissect_eapol_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data)
{
guint8 keydesc_type;
int offset = 0;
tvbuff_t *next_tvb;
proto_tree* eapol_tree = (proto_tree*)data;
keydesc_type = tvb_get_guint8(tvb, offset);
proto_tree_add_item(eapol_tree, hf_eapol_keydes_type, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
next_tvb = tvb_new_subset_remaining(tvb, offset);
/* Save keydesc_type for IEEE 802.11 dissector */
if (!pinfo->fd->visited) {
proto_eapol_key_frame_t *key_frame = (proto_eapol_key_frame_t *)
p_get_proto_data(pinfo->pool, pinfo, proto_eapol, EAPOL_KEY_FRAME_KEY);
if (key_frame) {
key_frame->type = keydesc_type;
}
}
if (!dissector_try_uint_new(eapol_keydes_type_dissector_table,
keydesc_type, next_tvb, pinfo, eapol_tree,
FALSE, NULL)) {
proto_tree_add_item(eapol_tree, hf_eapol_keydes_body, tvb, offset, -1, ENC_NA);
}
return tvb_captured_length(tvb);
}
static int
dissect_eapol_rc4_key(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
int offset = 0;
guint16 eapol_key_len;
gboolean generated_locally;
proto_tree *ti;
proto_tree *key_index_tree;
gint eapol_len;
eapol_key_len = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(tree, hf_eapol_keydes_key_len, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_eapol_keydes_replay_counter, tvb,
offset, 8, ENC_BIG_ENDIAN);
offset += 8;
proto_tree_add_item(tree, hf_eapol_keydes_key_iv, tvb,
offset, 16, ENC_NA);
offset += 16;
ti = proto_tree_add_item(tree, hf_eapol_keydes_key_index, tvb, offset, 1, ENC_BIG_ENDIAN);
key_index_tree = proto_item_add_subtree(ti, ett_eapol_key_index);
proto_tree_add_item(key_index_tree, hf_eapol_keydes_key_index_type,
tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(key_index_tree, hf_eapol_keydes_key_index_number,
tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
proto_tree_add_item(tree, hf_eapol_keydes_key_signature, tvb,
offset, 16, ENC_NA);
offset += 16;
if (eapol_key_len != 0) {
/*
* Body length of EAPOL-Key message in which we're contained is 1 byte
* larger than the reported length of the key descriptor we were handed,
* that 1 byte being the Key Descriptor Type.
*/
eapol_len = 1 + tvb_reported_length(tvb);
/* IEEE 802.1X-2004 7.6.3.6: If no bytes remain, then */
generated_locally = eapol_len <= 44; /* Size of rc4 key with no key content */
if (!generated_locally) {
proto_tree_add_item(tree, hf_eapol_keydes_key, tvb, offset,
eapol_key_len, ENC_NA);
}
proto_tree_add_boolean(tree, hf_eapol_keydes_key_generated_locally, tvb, offset,
0, generated_locally);
}
return tvb_captured_length(tvb);
}
void
proto_register_eapol(void)
{
static hf_register_info hf[] = {
{ &hf_eapol_version, {
"Version", "eapol.version",
FT_UINT8, BASE_DEC, VALS(eapol_version_vals), 0x0,
NULL, HFILL }},
{ &hf_eapol_type, {
"Type", "eapol.type",
FT_UINT8, BASE_DEC, VALS(eapol_type_vals), 0x0,
NULL, HFILL }},
{ &hf_eapol_len, {
"Length", "eapol.len",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_type, {
"Key Descriptor Type", "eapol.keydes.type",
FT_UINT8, BASE_DEC, VALS(eapol_keydes_type_vals), 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_body, {
"Key Descriptor Body", "eapol.keydes.body",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_key_len, {
"Key Length", "eapol.keydes.key_len",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_replay_counter, {
"Replay Counter", "eapol.keydes.replay_counter",
FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_key_iv, {
"Key IV", "eapol.keydes.key_iv",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_key_index, {
"Key Index", "eapol.keydes.key_index",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_key_index_type, {
"Type", "eapol.keydes.key_index.type",
FT_BOOLEAN, 8, TFS(&keytype_tfs), KEYDES_KEY_INDEX_TYPE_MASK ,
NULL, HFILL }},
{ &hf_eapol_keydes_key_index_number, {
"Number", "eapol.keydes.key_index.number",
FT_UINT8, BASE_DEC, NULL, KEYDES_KEY_INDEX_NUMBER_MASK,
NULL, HFILL }},
{ &hf_eapol_keydes_key_signature, {
"Key Signature", "eapol.keydes.key_signature",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_key, {
"Key", "eapol.keydes.key",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_eapol_keydes_key_generated_locally, {
"Key Generated Locally", "eapol.keydes.key.generated_locally",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
};
static gint *ett[] = {
&ett_eapol,
&ett_keyinfo,
&ett_eapol_key_index
};
proto_eapol = proto_register_protocol("802.1X Authentication", "EAPOL", "eapol");
eapol_handle = register_dissector("eapol", dissect_eapol, proto_eapol);
proto_register_field_array(proto_eapol, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
eapol_type_dissector_table = register_dissector_table("eapol.type",
"EAPOL Packet Type",
proto_eapol, FT_UINT8,
BASE_DEC);
eapol_keydes_type_dissector_table = register_dissector_table("eapol.keydes.type",
"EAPOL Key Descriptor Type",
proto_eapol, FT_UINT8,
BASE_DEC);
}
void
proto_reg_handoff_eapol(void)
{
dissector_handle_t eapol_rc4_key_handle, eapol_key_handle;
dissector_add_uint("ethertype", ETHERTYPE_EAPOL, eapol_handle);
dissector_add_uint("ethertype", ETHERTYPE_RSN_PREAUTH, eapol_handle);
/*
* EAPOL key descriptor types.
*/
eapol_rc4_key_handle = create_dissector_handle(dissect_eapol_rc4_key, proto_eapol);
dissector_add_uint("eapol.keydes.type", EAPOL_RC4_KEY, eapol_rc4_key_handle);
eapol_key_handle = create_dissector_handle(dissect_eapol_key, proto_eapol);
dissector_add_uint("eapol.type", EAPOL_KEY, eapol_key_handle);
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 2
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=2 tabstop=8 expandtab:
* :indentSize=2:tabSize=8:noTabs=true:
*/