aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-radius.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-radius.c')
-rw-r--r--epan/dissectors/packet-radius.c562
1 files changed, 313 insertions, 249 deletions
diff --git a/epan/dissectors/packet-radius.c b/epan/dissectors/packet-radius.c
index 3164b970bd..0a86b56548 100644
--- a/epan/dissectors/packet-radius.c
+++ b/epan/dissectors/packet-radius.c
@@ -82,19 +82,6 @@ typedef struct {
#define RD_HDR_LENGTH 4
#define HDR_LENGTH (RD_HDR_LENGTH + AUTHENTICATOR_LENGTH)
-/* Item of request list */
-typedef struct _radius_call_t
-{
- guint code;
- guint ident;
- guint8 req_authenticator[AUTHENTICATOR_LENGTH];
-
- guint32 req_num; /* frame number request seen */
- guint32 rsp_num; /* frame number response seen */
- guint32 rspcode;
- nstime_t req_time;
- gboolean responded;
-} radius_call_t;
/* Container for tapping relevant data */
typedef struct _radius_info_t
@@ -122,94 +109,96 @@ typedef struct _radius_info_t
static radius_dictionary_t *dict = NULL;
-static int proto_radius = -1;
-
-static int hf_radius_req = -1;
-static int hf_radius_rsp = -1;
-static int hf_radius_req_frame = -1;
-static int hf_radius_rsp_frame = -1;
-static int hf_radius_time = -1;
-
-static int hf_radius_dup = -1;
-static int hf_radius_req_dup = -1;
-static int hf_radius_rsp_dup = -1;
-
-static int hf_radius_id = -1;
-static int hf_radius_code = -1;
-static int hf_radius_length = -1;
-static int hf_radius_authenticator = -1;
-static int hf_radius_authenticator_valid = -1;
-static int hf_radius_authenticator_invalid = -1;
-
-static int hf_radius_chap_password = -1;
-static int hf_radius_chap_ident = -1;
-static int hf_radius_chap_string = -1;
-static int hf_radius_framed_ip_address = -1;
-
-static int hf_radius_login_ip_host = -1;
-static int hf_radius_framed_ipx_network = -1;
-
-static int hf_radius_cosine_vpi = -1;
-static int hf_radius_cosine_vci = -1;
-
-static int hf_radius_ascend_data_filter = -1;
-static int hf_radius_ascend_data_filter_type = -1;
-static int hf_radius_ascend_data_filter_filteror = -1;
-static int hf_radius_ascend_data_filter_inout = -1;
-static int hf_radius_ascend_data_filter_spare = -1;
-static int hf_radius_ascend_data_filter_src_ipv4 = -1;
-static int hf_radius_ascend_data_filter_dst_ipv4 = -1;
-static int hf_radius_ascend_data_filter_src_ipv6 = -1;
-static int hf_radius_ascend_data_filter_dst_ipv6 = -1;
-static int hf_radius_ascend_data_filter_src_ip_prefix = -1;
-static int hf_radius_ascend_data_filter_dst_ip_prefix = -1;
-static int hf_radius_ascend_data_filter_protocol = -1;
-static int hf_radius_ascend_data_filter_established = -1;
-static int hf_radius_ascend_data_filter_src_port = -1;
-static int hf_radius_ascend_data_filter_dst_port = -1;
-static int hf_radius_ascend_data_filter_src_port_qualifier = -1;
-static int hf_radius_ascend_data_filter_dst_port_qualifier = -1;
-static int hf_radius_ascend_data_filter_reserved = -1;
-
-static int hf_radius_vsa_fragment = -1;
-static int hf_radius_eap_fragment = -1;
-static int hf_radius_avp = -1;
-static int hf_radius_avp_length = -1;
-static int hf_radius_avp_type = -1;
-static int hf_radius_avp_vendor_id = -1;
-static int hf_radius_avp_vendor_type = -1;
-static int hf_radius_avp_vendor_len = -1;
-static int hf_radius_avp_extended_type = -1;
-static int hf_radius_avp_extended_more = -1;
-static int hf_radius_3gpp_ms_tmime_zone = -1;
-
-static int hf_radius_egress_vlanid_tag = -1;
-static int hf_radius_egress_vlanid_pad = -1;
-static int hf_radius_egress_vlanid = -1;
-
-static int hf_radius_egress_vlan_name_tag = -1;
-static int hf_radius_egress_vlan_name = -1;
-
-
-static gint ett_radius = -1;
-static gint ett_radius_avp = -1;
-
-static gint ett_radius_authenticator = -1;
-static gint ett_radius_ascend = -1;
-
-static gint ett_eap = -1;
-static gint ett_chap = -1;
-
-static expert_field ei_radius_invalid_length = EI_INIT;
+static int proto_radius;
+
+static int hf_radius_req;
+static int hf_radius_rsp;
+static int hf_radius_req_frame;
+static int hf_radius_rsp_frame;
+static int hf_radius_time;
+
+static int hf_radius_dup;
+static int hf_radius_req_dup;
+static int hf_radius_rsp_dup;
+
+static int hf_radius_id;
+static int hf_radius_code;
+static int hf_radius_length;
+static int hf_radius_authenticator;
+static int hf_radius_authenticator_valid;
+static int hf_radius_authenticator_invalid;
+static int hf_radius_message_authenticator_valid;
+static int hf_radius_message_authenticator_invalid;
+
+static int hf_radius_chap_password;
+static int hf_radius_chap_ident;
+static int hf_radius_chap_string;
+static int hf_radius_framed_ip_address;
+
+static int hf_radius_login_ip_host;
+static int hf_radius_framed_ipx_network;
+
+static int hf_radius_cosine_vpi;
+static int hf_radius_cosine_vci;
+
+static int hf_radius_ascend_data_filter;
+static int hf_radius_ascend_data_filter_type;
+static int hf_radius_ascend_data_filter_filteror;
+static int hf_radius_ascend_data_filter_inout;
+static int hf_radius_ascend_data_filter_spare;
+static int hf_radius_ascend_data_filter_src_ipv4;
+static int hf_radius_ascend_data_filter_dst_ipv4;
+static int hf_radius_ascend_data_filter_src_ipv6;
+static int hf_radius_ascend_data_filter_dst_ipv6;
+static int hf_radius_ascend_data_filter_src_ip_prefix;
+static int hf_radius_ascend_data_filter_dst_ip_prefix;
+static int hf_radius_ascend_data_filter_protocol;
+static int hf_radius_ascend_data_filter_established;
+static int hf_radius_ascend_data_filter_src_port;
+static int hf_radius_ascend_data_filter_dst_port;
+static int hf_radius_ascend_data_filter_src_port_qualifier;
+static int hf_radius_ascend_data_filter_dst_port_qualifier;
+static int hf_radius_ascend_data_filter_reserved;
+
+static int hf_radius_vsa_fragment;
+static int hf_radius_eap_fragment;
+static int hf_radius_avp;
+static int hf_radius_avp_length;
+static int hf_radius_avp_type;
+static int hf_radius_avp_vendor_id;
+static int hf_radius_avp_vendor_type;
+static int hf_radius_avp_vendor_len;
+static int hf_radius_avp_extended_type;
+static int hf_radius_avp_extended_more;
+static int hf_radius_3gpp_ms_tmime_zone;
+
+static int hf_radius_egress_vlanid_tag;
+static int hf_radius_egress_vlanid_pad;
+static int hf_radius_egress_vlanid;
+
+static int hf_radius_egress_vlan_name_tag;
+static int hf_radius_egress_vlan_name;
+
+
+static gint ett_radius;
+static gint ett_radius_avp;
+
+static gint ett_radius_authenticator;
+static gint ett_radius_ascend;
+
+static gint ett_eap;
+static gint ett_chap;
+
+static expert_field ei_radius_invalid_length;
/*
* Define the tap for radius
*/
-static int radius_tap = -1;
+static int radius_tap;
static radius_vendor_info_t no_vendor = {"Unknown Vendor", 0, NULL, -1, 1, 1, FALSE};
-static radius_attr_info_t no_dictionary_entry = {"Unknown-Attribute", { { 0, 0 } }, FALSE, FALSE, radius_octets, NULL, NULL, -1, -1, -1, -1, -1, NULL };
+static radius_attr_info_t no_dictionary_entry = {"Unknown-Attribute", { { 0, 0 } }, FALSE, FALSE, radius_octets, NULL, NULL, -1, -1, -1, -1, -1, -1, NULL };
static dissector_handle_t eap_handle;
static dissector_handle_t radius_handle;
@@ -307,7 +296,7 @@ static const value_string radius_message_code[] = {
};
static tap_packet_status
-radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri, tap_flags_t flags _U_)
{
rtd_data_t *rtd_data = (rtd_data_t *)prs;
rtd_stat_table *rs = &rtd_data->stat_table;
@@ -680,7 +669,7 @@ dissect_ascend_data_filter(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _
return wmem_strdup_printf(wmem_packet_scope(), "Wrong attribute length %d", len);
}
- filterstr = wmem_strbuf_sized_new(wmem_packet_scope(), 128, 128);
+ filterstr = wmem_strbuf_new_sized(wmem_packet_scope(), 128);
ti = proto_tree_add_item(tree, hf_radius_ascend_data_filter, tvb, 0, -1, ENC_NA);
ascend_tree = proto_item_add_subtree(ti, ett_radius_ascend);
@@ -912,61 +901,41 @@ dissect_rfc4675_egress_vlan_name(proto_tree *tree, tvbuff_t *tvb, packet_info *p
}
static void
-radius_decrypt_avp(gchar *dest, int dest_len, tvbuff_t *tvb, int offset, int length)
+radius_decrypt_avp(guint8 *dest, packet_info *pinfo, tvbuff_t *tvb, int offset, int length, guint8 *request_authenticator, guint8 *salt, int salt_len, int type)
{
gcry_md_hd_t md5_handle;
guint8 digest[HASH_MD5_LENGTH];
int i, j;
- gint totlen = 0, returned_length, padded_length;
+ gint padded_length;
guint8 *pd;
- guchar c;
-
- DISSECTOR_ASSERT(dest_len > 0);
- dest[0] = '\0';
- if (length <= 0)
- return;
-
- /* The max avp length is 253 (255 - 2 for type & length), but only the
- * User-Password is marked with encrypt=1 in dictionary.rfc2865, and the
- * User-Password max length is only 128 (130 - 2 for type & length) per
- * tools.ietf.org/html/rfc2865#section-5.2, so enforce that limit here.
- */
- if (length > 128)
- length = 128;
if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
return;
}
- gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
- gcry_md_write(md5_handle, authenticator, AUTHENTICATOR_LENGTH);
+ if (type == 3){
+ gcry_md_write(md5_handle, request_authenticator, AUTHENTICATOR_LENGTH);
+ gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
+ } else {
+ gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
+ gcry_md_write(md5_handle, request_authenticator, AUTHENTICATOR_LENGTH);
+ gcry_md_write(md5_handle, salt, salt_len);
+ }
memcpy(digest, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
padded_length = length + ((length % AUTHENTICATOR_LENGTH) ?
(AUTHENTICATOR_LENGTH - (length % AUTHENTICATOR_LENGTH)) : 0);
- pd = (guint8 *)wmem_alloc0(wmem_packet_scope(), padded_length);
+ pd = (guint8 *)wmem_alloc0(pinfo->pool, padded_length);
tvb_memcpy(tvb, pd, offset, length);
for (i = 0; i < padded_length; i += AUTHENTICATOR_LENGTH) {
- for (j = 0; j < AUTHENTICATOR_LENGTH; j++) {
- c = pd[i + j] ^ digest[j];
- if (g_ascii_isprint(c)) {
- returned_length = g_snprintf(&dest[totlen], dest_len - totlen,
- "%c", c);
- totlen += MIN(returned_length, dest_len - totlen - 1);
- }
- else if (c) {
- returned_length = g_snprintf(&dest[totlen], dest_len - totlen,
- "\\%03o", c);
- totlen += MIN(returned_length, dest_len - totlen - 1);
- }
+ for (j = 0; j < AUTHENTICATOR_LENGTH && i + j < length; j++) {
+ dest[i + j] = pd[i + j] ^ digest[j];
}
-
gcry_md_reset(md5_handle);
gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
gcry_md_write(md5_handle, &pd[i], AUTHENTICATOR_LENGTH);
memcpy(digest, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
}
-
gcry_md_close(md5_handle);
}
@@ -995,7 +964,7 @@ radius_integer(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_,
case 8: {
guint64 uintv64 = tvb_get_ntoh64(tvb, offset);
proto_tree_add_uint64(tree, a->hf_alt, tvb, offset, len, uintv64);
- proto_item_append_text(avp_item, "%" G_GINT64_MODIFIER "u", uintv64);
+ proto_item_append_text(avp_item, "%" PRIu64, uintv64);
return;
}
default:
@@ -1032,7 +1001,7 @@ radius_signed(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, t
case 8: {
guint64 uintv64 = tvb_get_ntoh64(tvb, offset);
proto_tree_add_int64(tree, a->hf_alt, tvb, offset, len, uintv64);
- proto_item_append_text(avp_item, "%" G_GINT64_MODIFIER "u", uintv64);
+ proto_item_append_text(avp_item, "%" PRIu64, uintv64);
return;
}
default:
@@ -1052,36 +1021,8 @@ radius_signed(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, t
void
radius_string(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
{
- switch (a->encrypt) {
-
- case 0: /* not encrypted */
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_UTF_8|ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_format_text(pinfo->pool, tvb, offset, len));
- break;
-
- case 1: /* encrypted like User-Password as defined in RFC 2865 */
- if (*shared_secret == '\0') {
- proto_item_append_text(avp_item, "Encrypted");
- proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
- } else {
- gchar *buffer;
- buffer = (gchar *)wmem_alloc(wmem_packet_scope(), 1024); /* an AVP value can be at most 253 bytes */
- radius_decrypt_avp(buffer, 1024, tvb, offset, len);
- proto_item_append_text(avp_item, "Decrypted: %s", buffer);
- proto_tree_add_string(tree, a->hf, tvb, offset, len, buffer);
- }
- break;
-
- case 2: /* encrypted like Tunnel-Password as defined in RFC 2868 */
- proto_item_append_text(avp_item, "Encrypted");
- proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
- break;
-
- case 3: /* encrypted like Ascend-Send-Secret as defined by Ascend^WLucent^WAlcatel-Lucent */
- proto_item_append_text(avp_item, "Encrypted");
- proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
- break;
- }
+ proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_UTF_8|ENC_NA);
+ proto_item_append_text(avp_item, "%s", tvb_format_text(pinfo->pool, tvb, offset, len));
}
void
@@ -1285,7 +1226,8 @@ radius_tlv(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbu
len -= tlv_length;
- dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(tlv_type));
+ if (a->tlvs_by_id)
+ dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(tlv_type));
if (!dictionary_entry) {
dictionary_entry = &no_dictionary_entry;
@@ -1326,7 +1268,7 @@ add_avp_to_tree_with_dissector(proto_tree *avp_tree, proto_item *avp_item, packe
}
static void
-add_avp_to_tree(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_attr_info_t *dictionary_entry, guint32 avp_length, guint32 offset)
+add_avp_to_tree(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_attr_info_t *dictionary_entry, guint32 avp_length, guint32 offset, radius_call_t *radius_call)
{
if (dictionary_entry->tagged) {
@@ -1360,7 +1302,73 @@ add_avp_to_tree(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo,
return;
}
- dictionary_entry->type(dictionary_entry, avp_tree, pinfo, tvb, offset, avp_length, avp_item);
+ if (dictionary_entry->encrypt > 0) {
+ if (*shared_secret =='\0' || avp_length == 0 || !radius_call) {
+ proto_item_append_text(avp_item, "Encrypted");
+ proto_tree_add_item(avp_tree, dictionary_entry->hf_enc, tvb, offset, avp_length, ENC_NA);
+ } else {
+ tvbuff_t *tvb_decrypted;
+ guint8 *buffer;
+
+ switch (dictionary_entry->encrypt) {
+ case 1: /* encrypted like User-Password as defined in RFC 2865 */
+ /* decrypted data is same length as encrypted data */
+ buffer = (guint8 *)wmem_alloc(pinfo->pool, avp_length);
+
+ radius_decrypt_avp(buffer, pinfo, tvb, offset, avp_length, radius_call->req_authenticator, NULL, 0, 1);
+ tvb_decrypted = tvb_new_child_real_data(tvb, buffer, avp_length, avp_length);
+ proto_item_append_text(avp_item, "Decrypted: ");
+ add_new_data_source(pinfo, tvb_decrypted, "Decrypted Data");
+ /* strip padding for string type */
+ if (dictionary_entry->type == radius_string) {
+ for (guint8 i=0; i < avp_length; i++){
+ if (buffer[i] == '\0')
+ avp_length = i;
+ }
+ }
+ dictionary_entry->type(dictionary_entry, avp_tree, pinfo, tvb_decrypted, 0, avp_length, avp_item);
+ break;
+
+ case 2: /* encrypted like Tunnel-Password as defined in RFC 2868 */
+ /* check if there is at least 1 byte of encrypted data after salt */
+ if (avp_length < 3) {
+ proto_item_append_text(avp_item, "Encrypted");
+ proto_tree_add_item(avp_tree, dictionary_entry->hf_enc, tvb, offset, avp_length, ENC_NA);
+ break;
+ }
+ /* decrypted data is same length as encrypted data */
+ buffer = (gchar *)wmem_alloc(pinfo->pool, avp_length - 2);
+ guint8 salt[2];
+
+ tvb_memcpy(tvb, salt, offset, 2);
+ avp_length -= 2;
+ radius_decrypt_avp(buffer, pinfo, tvb, offset + 2, avp_length, radius_call->req_authenticator, salt, 2, 2);
+ tvb_decrypted = tvb_new_child_real_data(tvb, buffer, avp_length, avp_length);
+ proto_item_append_text(avp_item, "Decrypted: ");
+ /* first byte contains length of decrypted data */
+ avp_length = (buffer[0] < avp_length) ? buffer[0] : avp_length -1;
+ add_new_data_source(pinfo, tvb_decrypted, "Decrypted Data");
+ dictionary_entry->type(dictionary_entry, avp_tree, pinfo, tvb_decrypted, 1, avp_length, avp_item);
+ break;
+
+ case 3: /* encrypted like Ascend-Send-Secret as defined by Ascend^WLucent^WAlcatel-Lucent */
+ /* maximum length is MD5 hash length */
+ if (avp_length > HASH_MD5_LENGTH)
+ avp_length = HASH_MD5_LENGTH;
+ /* decrypted data is same length as encrypted data */
+ buffer = (guint8 *)wmem_alloc(pinfo->pool, avp_length);
+
+ radius_decrypt_avp(buffer, pinfo, tvb, offset, avp_length, radius_call->req_authenticator, NULL, 0, 3);
+ tvb_decrypted = tvb_new_child_real_data(tvb, buffer, avp_length, avp_length);
+ proto_item_append_text(avp_item, "Decrypted: ");
+ add_new_data_source(pinfo, tvb_decrypted, "Decrypted Data");
+ dictionary_entry->type(dictionary_entry, avp_tree, pinfo, tvb_decrypted, 0, avp_length, avp_item);
+ break;
+ }
+ }
+ } else {
+ dictionary_entry->type(dictionary_entry, avp_tree, pinfo, tvb, offset, avp_length, avp_item);
+ }
}
static gboolean
@@ -1389,8 +1397,80 @@ vsa_buffer_table_destroy_indirect(void *context)
}
}
+/*
+ * returns true if the authenticator is valid
+ * input: tvb of the radius packet, corresponding request authenticator (not used for request),
+ * uses the shared secret to calculate the (message) authenticator
+ * and checks with the current.
+ * see RFC 2865, packet format page 16
+ * see RFC 2866, Request Authenticator page 7
+ * see RFC 2869, Message-Authenticator page 33
+ */
+static int
+valid_authenticator (tvbuff_t *tvb, guint8 request_authenticator[], gboolean rfc2869, int offset)
+{
+ gcry_md_hd_t md5_handle;
+ guint8 *digest;
+ gboolean result;
+ guint tvb_length;
+ guint8 rh_code;
+ guint8 *payload;
+ guint8 message_authenticator[AUTHENTICATOR_LENGTH];
+
+ tvb_length = tvb_captured_length(tvb);
+
+ if (tvb_length != tvb_reported_length(tvb) || tvb_length < (guint)(offset + AUTHENTICATOR_LENGTH)) {
+ return -1;
+ }
+
+ /* copy packet into payload */
+ payload = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, 0, tvb_length);
+
+ rh_code = tvb_get_guint8(tvb, 0);
+
+ if (rfc2869) {
+ /* reset (message) authenticator field */
+ memset(payload+offset, 0, AUTHENTICATOR_LENGTH);
+ if (rh_code != RADIUS_PKT_TYPE_ACCESS_REQUEST) {
+ /* replace authenticator in reply with the one in request */
+ memcpy(payload+4, request_authenticator, AUTHENTICATOR_LENGTH);
+ }
+ /* copy authenticator data */
+ tvb_memcpy(tvb, message_authenticator, offset, AUTHENTICATOR_LENGTH);
+ /* calculate HMAC_MD5 hash (payload) */
+ if (gcry_md_open(&md5_handle, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC)) {
+ return -1;
+ }
+ gcry_md_setkey(md5_handle, shared_secret, strlen(shared_secret));
+ gcry_md_write(md5_handle, payload, tvb_length);
+ digest = gcry_md_read(md5_handle, 0);
+
+ result = !memcmp(digest, message_authenticator, AUTHENTICATOR_LENGTH);
+ gcry_md_close(md5_handle);
+ } else {
+ if (rh_code == RADIUS_PKT_TYPE_ACCOUNTING_REQUEST) {
+ /* reset (message) authenticator field */
+ memset(payload+4, 0, AUTHENTICATOR_LENGTH);
+ } else {
+ /* replace authenticator in reply with the one in request */
+ memcpy(payload+4, request_authenticator, AUTHENTICATOR_LENGTH);
+ }
+ /* calculate MD5 hash (payload+shared_secret) */
+ if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
+ return -1;
+ }
+ gcry_md_write(md5_handle, payload, tvb_length);
+ gcry_md_write(md5_handle, shared_secret, strlen(shared_secret));
+ digest = gcry_md_read(md5_handle, 0);
+
+ result = !memcmp(digest, authenticator, AUTHENTICATOR_LENGTH);
+ gcry_md_close(md5_handle);
+ }
+ return result;
+}
+
void
-dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, guint length)
+dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, guint length, radius_call_t *radius_call)
{
gboolean last_eap = FALSE;
guint8 *eap_buffer = NULL;
@@ -1402,7 +1482,7 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
GHashTable *vsa_buffer_table = NULL;
- if (hf_radius_code == -1)
+ if (hf_radius_code <= 0)
proto_registrar_get_byname("radius.code");
/*
@@ -1696,16 +1776,16 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
vsa_tvb = tvb_new_child_real_data(tvb, vsa_buffer->data, vsa_buffer->len, vsa_buffer->len);
tvb_set_free_cb(vsa_tvb, g_free);
add_new_data_source(pinfo, vsa_tvb, "Reassembled VSA");
- add_avp_to_tree(avp_tree, avp_item, pinfo, vsa_tvb, dictionary_entry, vsa_buffer->len, 0);
+ add_avp_to_tree(avp_tree, avp_item, pinfo, vsa_tvb, dictionary_entry, vsa_buffer->len, 0, radius_call);
g_hash_table_remove(vsa_buffer_table, &(vsa_buffer->key));
g_free(vsa_buffer);
} else {
- add_avp_to_tree(avp_tree, avp_item, pinfo, tvb, dictionary_entry, avp_vsa_len, offset);
+ add_avp_to_tree(avp_tree, avp_item, pinfo, tvb, dictionary_entry, avp_vsa_len, offset, radius_call);
}
}
} else {
- add_avp_to_tree(avp_tree, avp_item, pinfo, tvb, dictionary_entry, avp_vsa_len, offset);
+ add_avp_to_tree(avp_tree, avp_item, pinfo, tvb, dictionary_entry, avp_vsa_len, offset, radius_call);
}
offset += avp_vsa_len;
@@ -1854,8 +1934,27 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
continue;
}
+ if (avp_type0 == RADIUS_ATTR_TYPE_MESSAGE_AUTHENTICATOR && validate_authenticator && *shared_secret != '\0' && radius_call) {
+ proto_item *authenticator_tree, *item;
+ int valid;
+
+ valid = valid_authenticator(tvb, radius_call->req_authenticator, TRUE, offset);
+ if (valid >= 0) {
+ proto_item_append_text(avp_item, " [%s]", valid? "correct" : "incorrect");
+ }
+ authenticator_tree = proto_item_add_subtree(avp_item, ett_radius_authenticator);
+ item = proto_tree_add_boolean(authenticator_tree, hf_radius_message_authenticator_valid, tvb, offset, AUTHENTICATOR_LENGTH, valid == 1 ? TRUE : FALSE);
+ proto_item_set_generated(item);
+ item = proto_tree_add_boolean(authenticator_tree, hf_radius_message_authenticator_invalid, tvb, offset, AUTHENTICATOR_LENGTH, valid == 0 ? TRUE : FALSE);
+ proto_item_set_generated(item);
+
+ if (valid == 0) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " [incorrect message authenticator]");
+ }
+ }
+
add_avp_to_tree(avp_tree, avp_item, pinfo, tvb, dictionary_entry,
- avp_length, offset);
+ avp_length, offset, radius_call);
offset += avp_length;
} /* while (length > 0) */
@@ -1900,49 +1999,6 @@ is_radius(tvbuff_t *tvb)
return TRUE;
}
-/*
- * returns true if the response or accounting request authenticator is valid
- * input: tvb of the response, corresponding request authenticator (not used for request),
- * uses the shared secret to calculate the authenticator
- * and checks with the current.
- * see RFC 2865, packet format page 16
- * see RFC 2866, Request Authenticator page 7
- */
-static gboolean
-valid_authenticator(tvbuff_t *tvb, guint8 request_authenticator[], int request)
-{
- gcry_md_hd_t md5_handle;
- guint8 *digest;
- gboolean result;
- guint tvb_length;
- guint8 *payload;
-
- tvb_length = tvb_captured_length(tvb); /* should it be tvb_reported_length ? */
-
- /* copy response into payload */
- payload = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, 0, tvb_length);
-
- if (request) {
- /* reset authenticator field */
- memset(payload+4, 0, AUTHENTICATOR_LENGTH);
- } else {
- /* replace authenticator in reply with the one in request */
- memcpy(payload+4, request_authenticator, AUTHENTICATOR_LENGTH);
- }
-
- /* calculate MD5 hash (payload+shared_secret) */
- if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
- return FALSE;
- }
- gcry_md_write(md5_handle, payload, tvb_length);
- gcry_md_write(md5_handle, shared_secret, strlen(shared_secret));
- digest = gcry_md_read(md5_handle, 0);
-
- result = !memcmp(digest, authenticator, AUTHENTICATOR_LENGTH);
- gcry_md_close(md5_handle);
- return result;
-}
-
static int
dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
@@ -1991,7 +2047,7 @@ dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
rh.rh_ident);
/* Load header fields if not already done */
- if (hf_radius_code == -1)
+ if (hf_radius_code <= 0)
proto_registrar_get_byname("radius.code");
ti = proto_tree_add_item(tree, proto_radius, tvb, 0, rh.rh_pktlength, ENC_NA);
@@ -2052,13 +2108,13 @@ dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
* if you do that.
*/
conversation = find_conversation(pinfo->num, &pinfo->src,
- &null_address, conversation_pt_to_endpoint_type(pinfo->ptype), pinfo->srcport,
+ &null_address, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport,
pinfo->destport, 0);
if (conversation == NULL)
{
/* It's not part of any conversation - create a new one. */
conversation = conversation_new(pinfo->num, &pinfo->src,
- &null_address, conversation_pt_to_endpoint_type(pinfo->ptype), pinfo->srcport,
+ &null_address, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport,
pinfo->destport, 0);
}
@@ -2104,16 +2160,17 @@ dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
if (rh.rh_code == RADIUS_PKT_TYPE_ACCOUNTING_REQUEST && validate_authenticator && *shared_secret != '\0') {
proto_item *authenticator_tree, *item;
int valid;
- valid = valid_authenticator(tvb, radius_call->req_authenticator, 1);
-
- proto_item_append_text(authenticator_item, " [%s]", valid? "correct" : "incorrect");
+ valid = valid_authenticator(tvb, radius_call->req_authenticator, FALSE, 4);
+ if (valid >= 0) {
+ proto_item_append_text(authenticator_item, " [%s]", valid? "correct" : "incorrect");
+ }
authenticator_tree = proto_item_add_subtree(authenticator_item, ett_radius_authenticator);
- item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_valid, tvb, 4, AUTHENTICATOR_LENGTH, valid ? TRUE : FALSE);
+ item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_valid, tvb, 4, AUTHENTICATOR_LENGTH, valid == 1 ? TRUE : FALSE);
proto_item_set_generated(item);
- item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_invalid, tvb, 4, AUTHENTICATOR_LENGTH, valid ? FALSE : TRUE);
+ item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_invalid, tvb, 4, AUTHENTICATOR_LENGTH, valid == 0 ? TRUE : FALSE);
proto_item_set_generated(item);
- if (!valid) {
+ if (valid == 0) {
col_append_fstr(pinfo->cinfo, COL_INFO, " [incorrect authenticator]");
}
}
@@ -2190,7 +2247,7 @@ dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
* if you do that.
*/
conversation = find_conversation(pinfo->num, &null_address,
- &pinfo->dst, conversation_pt_to_endpoint_type(pinfo->ptype), pinfo->srcport, pinfo->destport, 0);
+ &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, 0);
if (conversation == NULL) {
/* Nothing more to do here */
break;
@@ -2238,16 +2295,17 @@ dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
if (validate_authenticator && *shared_secret != '\0') {
proto_item *authenticator_tree;
int valid;
- valid = valid_authenticator(tvb, radius_call->req_authenticator, 0);
-
- proto_item_append_text(authenticator_item, " [%s]", valid? "correct" : "incorrect");
+ valid = valid_authenticator(tvb, radius_call->req_authenticator, FALSE, 4);
+ if (valid >= 0) {
+ proto_item_append_text(authenticator_item, " [%s]", valid? "correct" : "incorrect");
+ }
authenticator_tree = proto_item_add_subtree(authenticator_item, ett_radius_authenticator);
- item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_valid, tvb, 4, AUTHENTICATOR_LENGTH, valid ? TRUE : FALSE);
+ item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_valid, tvb, 4, AUTHENTICATOR_LENGTH, valid == 1 ? TRUE : FALSE);
proto_item_set_generated(item);
- item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_invalid, tvb, 4, AUTHENTICATOR_LENGTH, valid ? FALSE : TRUE);
+ item = proto_tree_add_boolean(authenticator_tree, hf_radius_authenticator_invalid, tvb, 4, AUTHENTICATOR_LENGTH, valid == 0 ? TRUE : FALSE);
proto_item_set_generated(item);
- if (!valid) {
+ if (valid == 0) {
col_append_fstr(pinfo->cinfo, COL_INFO, " [incorrect authenticator]");
}
}
@@ -2294,7 +2352,7 @@ dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
avptree = proto_tree_add_subtree(radius_tree, tvb, HDR_LENGTH,
avplength, ett_radius_avp, NULL, "Attribute Value Pairs");
dissect_attribute_value_pairs(avptree, pinfo, tvb, HDR_LENGTH,
- avplength);
+ avplength, radius_call);
}
return tvb_captured_length(tvb);
@@ -2343,6 +2401,7 @@ register_attrs(gpointer k _U_, gpointer v, gpointer p)
{ NULL, { NULL, NULL, FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ NULL, { NULL, NULL, FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ NULL, { NULL, NULL, FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { NULL, { NULL, NULL, FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ NULL, { NULL, NULL, FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}
};
guint len_hf = 2;
@@ -2396,20 +2455,6 @@ register_attrs(gpointer k _U_, gpointer v, gpointer p)
} else if (a->type == radius_string) {
hfri[0].hfinfo.type = FT_STRING;
hfri[0].hfinfo.display = BASE_NONE;
-
- if (a->encrypt != 0) {
- /*
- * This attribute is encrypted, so create an
- * alternative field for the encrypted value.
- */
- hfri[2].p_id = &(a->hf_alt);
- hfri[2].hfinfo.name = wmem_strdup_printf(wmem_epan_scope(), "%s (encrypted)", a->name);
- hfri[2].hfinfo.abbrev = wmem_strdup_printf(wmem_epan_scope(), "%s_encrypted", abbrev);
- hfri[2].hfinfo.type = FT_BYTES;
- hfri[2].hfinfo.display = BASE_NONE;
-
- len_hf++;
- }
} else if (a->type == radius_octets) {
hfri[0].hfinfo.type = FT_BYTES;
hfri[0].hfinfo.display = BASE_NONE;
@@ -2465,6 +2510,19 @@ register_attrs(gpointer k _U_, gpointer v, gpointer p)
len_hf++;
}
+ if (a->encrypt != 0) {
+ /*
+ * This attribute is encrypted, so create an
+ * alternative field for the encrypted value.
+ */
+ hfri[len_hf].p_id = &(a->hf_enc);
+ hfri[len_hf].hfinfo.name = wmem_strdup_printf(wmem_epan_scope(), "%s (encrypted)", a->name);
+ hfri[len_hf].hfinfo.abbrev = wmem_strdup_printf(wmem_epan_scope(), "%s_encrypted", abbrev);
+ hfri[len_hf].hfinfo.type = FT_BYTES;
+ hfri[len_hf].hfinfo.display = BASE_NONE;
+ len_hf++;
+ }
+
wmem_array_append(ri->hf, hfri, len_hf);
wmem_array_append_one(ri->ett, ett);
@@ -2508,7 +2566,7 @@ radius_register_avp_dissector(guint32 vendor_id, guint32 _attribute_id, radius_a
if (!vendor) {
vendor = g_new(radius_vendor_info_t, 1);
- vendor->name = g_strdup_printf("%s-%u",
+ vendor->name = ws_strdup_printf("%s-%u",
enterprises_lookup(vendor_id, "Unknown"),
vendor_id);
vendor->code = vendor_id;
@@ -2534,7 +2592,7 @@ radius_register_avp_dissector(guint32 vendor_id, guint32 _attribute_id, radius_a
if (!dictionary_entry) {
dictionary_entry = g_new(radius_attr_info_t, 1);
- dictionary_entry->name = g_strdup_printf("Unknown-Attribute-%u", attribute_id.value);
+ dictionary_entry->name = ws_strdup_printf("Unknown-Attribute-%u", attribute_id.value);
dictionary_entry->code = attribute_id;
dictionary_entry->encrypt = 0;
dictionary_entry->type = NULL;
@@ -2632,6 +2690,12 @@ register_radius_fields(const char *unused _U_)
{ &hf_radius_authenticator_invalid,
{ "Invalid Authenticator", "radius.authenticator.invalid", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"TRUE if Authenticator is invalid", HFILL }},
+ { &hf_radius_message_authenticator_valid,
+ { "Valid Message-Authenticator", "radius.Message_Authenticator.valid", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "TRUE if Message-Authenticator is valid", HFILL }},
+ { &hf_radius_message_authenticator_invalid,
+ { "Invalid Message-Authenticator", "radius.Message_Authenticator.invalid", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "TRUE if Message-Authenticator is invalid", HFILL }},
{ &hf_radius_length,
{ "Length", "radius.length", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
@@ -2756,7 +2820,7 @@ register_radius_fields(const char *unused _U_)
{ "Extended Type", "radius.avp.extended_type", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_radius_avp_extended_more,
- { "Extended More", "radius.avp.extended_more", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x80,
+ { "Extended More", "radius.avp.extended_more", FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }},
{ &hf_radius_egress_vlanid_tag,
{ "Tag", "radius.egress_vlanid_tag", FT_UINT32, BASE_HEX, VALS(egress_vlan_tag_vals), 0xFF000000,
@@ -2855,8 +2919,8 @@ proto_register_radius(void)
prefs_register_string_preference(radius_module, "shared_secret", "Shared Secret",
"Shared secret used to decode User Passwords and validate Accounting Request and Response Authenticators",
&shared_secret);
- prefs_register_bool_preference(radius_module, "validate_authenticator", "Validate Accounting Request and Response Authenticator",
- "Whether to check or not if Accounting Request and Response Authenticator are correct. You need to define shared secret for this to work.",
+ prefs_register_bool_preference(radius_module, "validate_authenticator", "Validate Authenticator and Message-Authenticator",
+ "Whether to check or not if Authenticator and Message-Authenticator are correct. You need to define shared secret for this to work.",
&validate_authenticator);
prefs_register_bool_preference(radius_module, "show_length", "Show AVP Lengths",
"Whether to add or not to the tree the AVP's payload length",