diff options
author | Anders Broman <anders.broman@ericsson.com> | 2007-03-05 23:11:11 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2007-03-05 23:11:11 +0000 |
commit | fc16dece75dc6c2cb3a3e921b2798e82381db27c (patch) | |
tree | 15a1c395edd2ab0de464446157b62cfd74b018fc /epan | |
parent | 1b65a2e9869e3f8ae52f40cbc138d513c3cde2b8 (diff) |
From Mikael Magnusson:
This patch adds support for key-mgmt session attributes in SDP (defined in RFC 4567). The patch also contains a Multimedia Internet KEYing (MIKEY is defined in RFC 3830) dissector plugin for "mikey" key-mgmt data.
svn path=/trunk/; revision=20977
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/Makefile.common | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-mikey.c | 1651 | ||||
-rw-r--r-- | epan/dissectors/packet-mikey.h | 34 | ||||
-rw-r--r-- | epan/dissectors/packet-sdp.c | 113 |
4 files changed, 1795 insertions, 5 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index bc181142cb..36f5d6ea7e 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -451,6 +451,7 @@ DISSECTOR_SRC = \ packet-mbtcp.c \ packet-mdshdr.c \ packet-media.c \ + packet-mikey.c \ packet-mip.c \ packet-mip6.c \ packet-mms.c \ @@ -884,6 +885,7 @@ DISSECTOR_INCLUDES = \ packet-llc.h \ packet-logotypecertextn.h \ packet-MAP_DialoguePDU.h \ + packet-mikey.h \ packet-mip6.h \ packet-mms.h \ packet-mount.h \ diff --git a/epan/dissectors/packet-mikey.c b/epan/dissectors/packet-mikey.c new file mode 100644 index 0000000000..376993db88 --- /dev/null +++ b/epan/dissectors/packet-mikey.c @@ -0,0 +1,1651 @@ +/* packet-mikey.c + * Routines for Multimedia Internet KEYing dissection + * Copyright 2007, Mikael Magnusson <mikma@users.sourceforge.net> + * + * $Id:$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Ref: + * http://www.ietf.org/rfc/rfc3830.txt?number=3830 + */ + +/* + * TODO + * tvbuff offset in 32-bit variable. + * Support CHASH and ERR payloads + * support key data salt and kv data + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> + +#include <epan/emem.h> +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/tfs.h> +#include <epan/dissectors/packet-x509af.h> +#include "packet-ntp.h" + +#ifdef HAVE_LIBGCRYPT + +#ifdef _WIN32 +#include <winposixtype.h> +#endif /* _WIN32 */ + +#include <gcrypt.h> +#endif /* HAVE_LIBGCRYPT */ + +#include "packet-mikey.h" + +static const value_string on_off_vals[] = { + { 0, "Off" }, + { 1, "On" }, + { 0, NULL } +}; + +enum data_type_t { + MIKEY_TYPE_PSK_INIT = 0, + MIKEY_TYPE_PSK_RESP, + MIKEY_TYPE_PK_INIT, + MIKEY_TYPE_PK_RESP, + MIKEY_TYPE_DH_INIT, + MIKEY_TYPE_DH_RESP, + MIKEY_TYPE_ERROR, + MIKEY_TYPE_DHHMAC_INIT, + MIKEY_TYPE_DHHMAC_RESP, + MIKEY_TYPE_RSA_R_INIT, + MIKEY_TYPE_RSA_R_RESP +}; + +static const value_string data_type_vals[] = { + { MIKEY_TYPE_PSK_INIT, "Pre-shared" }, + { MIKEY_TYPE_PSK_RESP, "PSK ver msg" }, + { MIKEY_TYPE_PK_INIT, "Public key" }, + { MIKEY_TYPE_PK_RESP, "PK ver msg" }, + { MIKEY_TYPE_DH_INIT, "D-H init" }, + { MIKEY_TYPE_DH_RESP, "D-H resp" }, + { MIKEY_TYPE_ERROR, "Error" }, + { MIKEY_TYPE_DHHMAC_INIT, "DHHMAC init" }, + { MIKEY_TYPE_DHHMAC_RESP, "DHHMAC resp" }, + { MIKEY_TYPE_RSA_R_INIT, "RSA-R I_MSG" }, + { MIKEY_TYPE_RSA_R_RESP, "RSA-R R_MSG" }, + { 0, NULL } +}; + +enum cs_id_map_t { + CS_ID_SRTP = 0 +}; + +static const value_string cs_id_map_vals[] = { + { CS_ID_SRTP, "SRTP-ID" }, + { 0, NULL } +}; + +enum payload_t { + PL_HDR = -1, + PL_LAST, + PL_KEMAC, + PL_PKE, + PL_DH, + PL_SIGN, + PL_T, + PL_ID, + PL_CERT, + PL_CHASH, + PL_V, + PL_SP, + PL_RAND, + PL_ERR, + PL_KEY_DATA = 20, + PL_GENERAL_EXT, + PL_MAX +}; + +#define PL_HDR_TEXT "Common Header (HDR)" +#define PL_LAST_TEXT "Last payload" +#define PL_KEMAC_TEXT "Key Data Transport (KEMAC)" +#define PL_PKE_TEXT "Envelope Data (PKE)" +#define PL_DH_TEXT "DH Data (DH)" +#define PL_SIGN_TEXT "Signature (SIGN)" +#define PL_T_TEXT "Timestamp (T)" +#define PL_ID_TEXT "ID" +#define PL_CERT_TEXT "Certificate (CERT)" +#define PL_CHASH_TEXT "CHASH" +#define PL_V_TEXT "Ver msg (V)" +#define PL_SP_TEXT "Security Policy (SP)" +#define PL_RAND_TEXT "RAND" +#define PL_ERR_TEXT "Error (ERR)" +#define PL_KEY_DATA_TEXT "Key data" +#define PL_GENERAL_EXT_TEXT "General Ext." + +static const value_string payload_vals[] = { + { PL_HDR, PL_HDR_TEXT }, + { PL_LAST, PL_LAST_TEXT }, + { PL_KEMAC, PL_KEMAC_TEXT }, + { PL_PKE, PL_PKE_TEXT }, + { PL_DH, PL_DH_TEXT }, + { PL_SIGN, PL_SIGN_TEXT }, + { PL_T, PL_T_TEXT }, + { PL_ID, PL_ID_TEXT }, + { PL_CERT, PL_CERT_TEXT }, + { PL_CHASH, PL_CHASH_TEXT }, + { PL_V, PL_V_TEXT }, + { PL_SP, PL_SP_TEXT }, + { PL_RAND, PL_RAND_TEXT }, + { PL_ERR, PL_ERR_TEXT }, + { PL_KEY_DATA, PL_KEY_DATA_TEXT }, + { PL_GENERAL_EXT, PL_GENERAL_EXT_TEXT }, + { 0, NULL } +}; + +enum ts_type_t { + T_NTP_UTC = 0, + T_NTP, + T_COUNTER, +}; + +static const value_string ts_type_vals[] = { + { T_NTP_UTC, "NTP-UTC" }, + { T_NTP, "NTP" }, + { T_COUNTER, "COUNTER" }, + { 0, NULL } +}; + +enum encr_alg_t { + ENCR_NULL = 0, + ENCR_AES_CM_128, + ENCR_AES_KW_128 +}; + +static const value_string encr_alg_vals[] = { + { ENCR_NULL, "NULL" }, + { ENCR_AES_CM_128, "AES-CM-128" }, + { ENCR_AES_KW_128, "AES-KW-128" }, + { 0, NULL } +}; + +enum oakley_t { + DH_OAKLEY_5 = 0, + DH_OAKLEY_1, + DH_OAKLEY_2 +}; + +static const value_string oakley_vals[] = { + { DH_OAKLEY_5, "OAKLEY 5" }, + { DH_OAKLEY_1, "OAKLEY 1" }, + { DH_OAKLEY_2, "OAKLEY 2" }, + { 0, NULL } +}; + +enum mac_alg_t { + MAC_NULL = 0, + MAC_HMAC_SHA_1_160 +}; + +static const value_string mac_alg_vals[] = { + { MAC_NULL, "NULL" }, + { MAC_HMAC_SHA_1_160, "HMAC-SHA-1-160" }, + { 0, NULL } +}; + +enum pke_c_t { + PKE_C_NO_CACHE = 0, + PKE_C_CACHE, + PKE_C_CACHE_CSB, +}; + +static const value_string pke_c_vals[] = { + { PKE_C_NO_CACHE, "No cache" }, + { PKE_C_CACHE, "Cache" }, + { PKE_C_CACHE_CSB, "Cache for CSB" }, + { 0, NULL } +}; + +enum sign_s_t { + SIGN_S_PKCS1 = 0, + SIGN_S_PSS +}; + +static const value_string sign_s_vals[] = { + { SIGN_S_PKCS1, "RSA/PKCS#1/1.5" }, + { SIGN_S_PSS, "RSA/PSS" }, + { 0, NULL } +}; + +enum id_type_t { + ID_TYPE_NAI = 0, + ID_TYPE_URI +}; + +static const value_string id_type_vals[] = { + { ID_TYPE_NAI, "NAI" }, + { ID_TYPE_URI, "URI" }, + { 0, NULL } +}; + +enum cert_type_t { + CERT_TYPE_X509V3 = 0, + CERT_TYPE_X509V3_URL, + CERT_TYPE_X509V3_SIGN, + CERT_TYPE_X509V3_ENCR +}; + +static const value_string cert_type_vals[] = { + { CERT_TYPE_X509V3, "X.509v3" }, + { CERT_TYPE_X509V3_URL, "X.509v3 URL" }, + { CERT_TYPE_X509V3_SIGN, "X.509v3 Sign" }, + { CERT_TYPE_X509V3_ENCR, "X.509v3 Encr" }, + { 0, NULL } +}; + +enum srtp_policy_type_t { + SP_ENCR_ALG, + SP_ENCR_LEN, + SP_AUTH_ALG, + SP_AUTH_KEY_LEN, + SP_SALT_LEN, + SP_PRF, + SP_KD_RATE, + SP_SRTP_ENCR, + SP_SRTCP_ENCR, + SP_FEC, + SP_SRTP_AUTH, + SP_AUTH_TAG_LEN, + SP_SRTP_PREFIX, + SP_MAX +}; + +#define SP_TEXT_ENCR_ALG "Encryption algorithm" +#define SP_TEXT_ENCR_LEN "Session Encr. key length" +#define SP_TEXT_AUTH_ALG "Authentication algorithm" +#define SP_TEXT_AUTH_KEY_LEN "Session Auth. key length" +#define SP_TEXT_SALT_LEN "Session Salt key length" +#define SP_TEXT_PRF "SRTP Pseudo Random Function" +#define SP_TEXT_KD_RATE "Key derivation rate" +#define SP_TEXT_SRTP_ENCR "SRTP encryption" +#define SP_TEXT_SRTCP_ENCR "SRTCP encryption" +#define SP_TEXT_FEC "Sender's FEC order" +#define SP_TEXT_SRTP_AUTH "SRTP authentication" +#define SP_TEXT_AUTH_TAG_LEN "Authentication tag length" +#define SP_TEXT_SRTP_PREFIX "SRTP prefix length" + +static const value_string srtp_policy_type_vals[] = { + { SP_ENCR_ALG, SP_TEXT_ENCR_ALG }, + { SP_ENCR_LEN, SP_TEXT_ENCR_LEN }, + { SP_AUTH_ALG, SP_TEXT_AUTH_ALG }, + { SP_AUTH_KEY_LEN, SP_TEXT_AUTH_KEY_LEN }, + { SP_SALT_LEN, SP_TEXT_SALT_LEN }, + { SP_PRF, SP_TEXT_PRF }, + { SP_KD_RATE, SP_TEXT_KD_RATE }, + { SP_SRTP_ENCR, SP_TEXT_SRTP_ENCR }, + { SP_SRTCP_ENCR, SP_TEXT_SRTCP_ENCR }, + { SP_FEC, SP_TEXT_FEC }, + { SP_SRTP_AUTH, SP_TEXT_SRTP_AUTH }, + { SP_AUTH_TAG_LEN, SP_TEXT_AUTH_TAG_LEN }, + { SP_SRTP_PREFIX, SP_TEXT_SRTP_PREFIX }, + { 0, NULL } +}; + +enum sp_encr_alg_t { + SP_ENCR_NULL = 0, + SP_ENCR_AES_CM, + SP_ENCR_AES_F8 +}; + +static const value_string sp_encr_alg_vals[] = { + { SP_ENCR_NULL, "NULL" }, + { SP_ENCR_AES_CM, "AES-CM" }, + { SP_ENCR_AES_F8, "AES-F8" }, + { 0, NULL } +}; + +enum sp_auth_alg_t { + SP_AUTH_NULL = 0, + SP_AUTH_HMAC_SHA_1 +}; + +static const value_string sp_auth_alg_vals[] = { + { SP_AUTH_NULL, "NULL" }, + { SP_AUTH_HMAC_SHA_1, "HMAC-SHA-1" }, + { 0, NULL } +}; + +enum sp_prf_t { + SP_PRF_AES_CM = 0 +}; + +static const value_string sp_prf_vals[] = { + { SP_PRF_AES_CM, "AES-CM" }, + { 0, NULL } +}; + +enum sp_fec_t { + SP_FEC_SRTP = 0 +}; + +static const value_string sp_fec_vals[] = { + { SP_FEC_SRTP, "FEC-SRTP" }, + { 0, NULL } +}; + +enum sp_prot_t { + SP_PROT_TYPE_SRTP = 0 +}; + +static const value_string sp_prot_type_vals[] = { + { SP_PROT_TYPE_SRTP, "SRTP" }, + { 0, NULL } +}; + +enum prf_func_t { + PRF_FUNC_MIKEY_1 = 0 +}; + +static const value_string prf_func_vals[] = { + { PRF_FUNC_MIKEY_1, "MIKEY-1" }, + { 0, NULL } +}; + +enum kv_t { + KV_NULL = 0, + KV_SPI, + KV_INTERVAL +}; + +static const value_string kv_vals[] = { + { KV_NULL, "Null" }, + { KV_SPI, "SPI/MKI" }, + { KV_INTERVAL, "Interval" }, + { 0, NULL } +}; + +enum kd_t { + KD_TGK = 0, + KD_TGK_SALT, + KD_TEK, + KD_TEK_SALT +}; + +static const value_string kd_vals[] = { + { KD_TGK, "TGK" }, + { KD_TGK_SALT, "TGK+SALT" }, + { KD_TEK, "TEK" }, + { KD_TEK_SALT, "TEK+SALT" }, + { 0, NULL } +}; + +enum { + /* HDR */ + POS_HDR_VERSION=0, + POS_HDR_DATA_TYPE, + POS_HDR_V, + POS_HDR_PRF_FUNC, + POS_HDR_CSB_ID, + POS_HDR_CS_COUNT, + POS_HDR_CS_ID_MAP_TYPE, + POS_ID_SRTP, + POS_ID_SRTP_NO, + POS_ID_SRTP_SSRC, + POS_ID_SRTP_ROC, + + /* KEMAC */ + POS_KEMAC_ENCR_ALG, + POS_KEMAC_ENCR_DATA_LEN, + POS_KEMAC_ENCR_DATA, + POS_KEMAC_MAC_ALG, + POS_KEMAC_MAC, + + /* PKE */ + POS_PKE_C, + POS_PKE_DATA_LEN, + POS_PKE_DATA, + + /* DH */ + POS_DH_GROUP, + POS_DH_VALUE, + POS_DH_RESERV, + POS_DH_KV, + + /* SIGN */ + POS_SIGNATURE_LEN, + POS_SIGNATURE, + POS_SIGN_S_TYPE, + + /* T */ + POS_TS_TYPE, + POS_TS_NTP, + + /* ID */ + POS_ID_TYPE, + POS_ID_LEN, + POS_ID, + + /* CERT */ + POS_CERT_TYPE, + POS_CERT_LEN, + POS_CERTIFICATE, + + /* V */ + POS_V_AUTH_ALG, + POS_V_DATA, + + /* SP */ + POS_SP_NO, + POS_SP_TYPE, + POS_SP_PARAM_LEN, +/* POS_SP_PARAM, */ + + /* SP param */ + POS_SP_PARAM_F, + POS_SP_PARAM_F_TYPE, + POS_SP_PARAM_F_LEN, + POS_SP_PARAM_F_VALUE, + + /* RAND */ + POS_RAND_LEN, + POS_RAND, + + /* Key data */ + POS_KEY_DATA_TYPE, + POS_KEY_DATA_KV, + POS_KEY_DATA_LEN, + POS_KEY_DATA, + + /* MIKEY */ + POS_PAYLOAD_STR, + POS_NEXT_PAYLOAD, + + /* Unused */ +/* POS_PAYLOAD, */ + + MAX_POS +}; + +typedef struct tag_mikey_t { + guint8 type; +} mikey_t; + +typedef int (*mikey_dissector_t)(mikey_t *, tvbuff_t *, packet_info *, proto_tree *); +struct mikey_dissector_entry { + int type; + mikey_dissector_t dissector; +}; + +/* Forward declaration we need below */ +void proto_reg_handoff_mikey(void); +static int dissect_payload(enum payload_t payload, mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +static const struct mikey_dissector_entry *mikey_dissector_lookup(const struct mikey_dissector_entry *map, int type); + + +/* Initialize the protocol and registered fields */ +static int proto_mikey = -1; +static int hf_mikey[MAX_POS+1]; +static int hf_mikey_sp_param[SP_MAX+1]; +static int hf_mikey_pl[PL_MAX]; + +/* Initialize the subtree pointers */ +static gint ett_mikey = -1; +static gint ett_mikey_payload = -1; +static gint ett_mikey_sp_param = -1; +static gint ett_mikey_hdr_id = -1; + + +static const struct mikey_dissector_entry * +mikey_dissector_lookup(const struct mikey_dissector_entry *map, int type) +{ + unsigned int i; + for (i = 0; map[i].dissector != NULL; i++) { + if (map[i].type == type) { + return &map[i]; + } + } + + return NULL; +} + +static void +add_next_payload(tvbuff_t *tvb, proto_tree *tree, int offset) +{ + guint8 next_payload; + + next_payload = tvb_get_guint8(tvb, offset); + + proto_tree_add_item(tree, hf_mikey[POS_NEXT_PAYLOAD], tvb, offset, 1, FALSE); +} + + +static int +dissect_payload_cs_id_srtp(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *id_ti; + proto_tree *id_tree; + guint8 no; + guint32 ssrc; + guint32 roc; + + tvb_ensure_bytes_exist(tvb, 0, 9); + + no = tvb_get_guint8(tvb, 0); + ssrc = tvb_get_ntohl(tvb, 1); + roc = tvb_get_ntohl(tvb, 5); + + if (tree) { + id_ti = proto_tree_add_none_format(tree, hf_mikey[POS_ID_SRTP], tvb, 0, 9, "SRTP ID: Policy: %d, SSRC: 0x%x, ROC: 0x%x", no, ssrc, roc); + id_tree = proto_item_add_subtree(id_ti, ett_mikey_hdr_id); + + proto_tree_add_item(id_tree, hf_mikey[POS_ID_SRTP_NO], tvb, 0, 1, FALSE); + proto_tree_add_item(id_tree, hf_mikey[POS_ID_SRTP_SSRC], tvb, 1, 4, FALSE); + proto_tree_add_item(id_tree, hf_mikey[POS_ID_SRTP_ROC], tvb, 5, 4, FALSE); + } + return 9; +} + +static const struct mikey_dissector_entry cs_id_map[] = { + { CS_ID_SRTP, dissect_payload_cs_id_srtp }, + { 0, NULL } +}; + +static int +dissect_payload_cs_id(enum cs_id_map_t type, mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + const struct mikey_dissector_entry *entry; + + entry = mikey_dissector_lookup(cs_id_map, type); + + if (!entry || !entry->dissector) { + return -1; + } + + return entry->dissector(mikey, tvb, pinfo, tree); + +} + +static int +dissect_payload_hdr(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint8 cs_id_map_type; + guint8 ncs; + int i; + proto_item* parent; + + + tvb_ensure_bytes_exist(tvb, offset, 10); + mikey->type = tvb_get_guint8(tvb, offset+1); + ncs = tvb_get_guint8(tvb, offset+8); + cs_id_map_type = tvb_get_guint8(tvb, offset+9); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_HDR_VERSION], + tvb, offset+0, 1, FALSE); + + proto_tree_add_item(tree, hf_mikey[POS_HDR_DATA_TYPE], tvb, offset+1, 1, FALSE); + parent = proto_tree_get_parent(tree); + proto_item_append_text(parent, " Type: %s", val_to_str(mikey->type, data_type_vals, "Unknown")); + + add_next_payload(tvb, tree, offset+2); + + proto_tree_add_item(tree, hf_mikey[POS_HDR_V], tvb, offset+3, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_HDR_PRF_FUNC], tvb, offset+3, 1, FALSE); + + proto_tree_add_item(tree, hf_mikey[POS_HDR_CSB_ID], tvb, offset+4, 4, FALSE); + + proto_tree_add_item(tree, hf_mikey[POS_HDR_CS_COUNT], tvb, offset+8, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_HDR_CS_ID_MAP_TYPE], tvb, offset+9, 1, FALSE); + } + + offset += 10; + for (i=0; i < ncs; i++) { + tvbuff_t *sub_tvb; + int len; + + sub_tvb = tvb_new_subset(tvb, offset, -1, -1); + len = dissect_payload_cs_id(cs_id_map_type, mikey, sub_tvb, pinfo, tree); + + if (len < 0) + return -1; + + offset += len; + } + + return offset; +} + +static int +dissect_payload_kemac(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint8 encr_alg; + guint16 encr_length; + guint16 mac_length; + guint8 mac_alg; + tvbuff_t *sub_tvb = NULL; + enum payload_t sub_payload = PL_LAST; + + tvb_ensure_bytes_exist(tvb, offset+0, 4); + encr_alg = tvb_get_guint8(tvb, offset+1); + encr_length = tvb_get_ntohs(tvb, offset+2); + tvb_ensure_bytes_exist(tvb, offset+4, encr_length+1); + mac_alg = tvb_get_guint8(tvb, offset+4+encr_length); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_KEMAC_ENCR_ALG], tvb, 1, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_KEMAC_ENCR_DATA_LEN], tvb, 2, 2, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_KEMAC_ENCR_DATA], tvb, 4, encr_length, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_KEMAC_MAC_ALG], tvb, 4+encr_length, 1, FALSE); + } + + switch (mac_alg) { + case MAC_NULL: + mac_length = 0; + break; + case MAC_HMAC_SHA_1_160: + mac_length = 160/8; + break; + default: + proto_tree_add_debug_text(tree, "Unknown mac alg %d", mac_alg); + return -1; + } + + tvb_ensure_bytes_exist(tvb, offset+4+encr_length+1, mac_length); + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_KEMAC_MAC], tvb, 4+encr_length+1, mac_length, FALSE); + } + +#if 0 + /* TODO */ + fprintf(stderr, "mikey type %d\n", mikey->type); + sub_tvb = tvb_new_subset(tvb, offset+4, encr_length, encr_length); +/* add_new_data_source(pinfo, sub_tvb, "Key data sub-payload"); */ + + switch (mikey->type) { + case MIKEY_TYPE_PSK_INIT:{ + fprintf(stderr, "Dissect PSK key data %d\n", encr_length); + sub_payload = PL_KEY_DATA; + break; + } + case MIKEY_TYPE_PK_INIT: + case MIKEY_TYPE_RSA_R_RESP:{ +/* tvbuff_t *sub_tvb; */ + fprintf(stderr, "Dissect PK/RSA-R key data %d\n", encr_length); +/* sub_tvb = tvb_new_subset(tvb, offset+4, encr_length, encr_length); */ + +/* dissect_payload_keydata(mikey, sub_tvb, tree); */ + sub_payload = PL_KEY_DATA; + break; + } + } +#endif + + if (sub_payload != PL_LAST) { + dissect_payload(sub_payload, mikey, sub_tvb, pinfo, tree); + } + + return 4+encr_length+1+mac_length; +} + +static int +dissect_payload_pke(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint16 length; + guint8 pke_c; + + tvb_ensure_bytes_exist(tvb, offset+0, 3); + pke_c = (tvb_get_guint8(tvb, offset+1) & 0xc0) >> 6; + length = ((tvb_get_guint8(tvb, offset+1) & 0x3f) << 8) | + tvb_get_guint8(tvb, offset+2); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_PKE_C], tvb, 1, 2, FALSE); + + proto_tree_add_item(tree, hf_mikey[POS_PKE_DATA_LEN], tvb, 1, 2, FALSE); + } + + tvb_ensure_bytes_exist(tvb, offset+3, length); + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_PKE_DATA], tvb, 3, length, FALSE); + } + return 3 + length; +} + +static int +dissect_payload_dh(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint8 dh_group; + int dh_length; + guint8 kv; + + tvb_ensure_bytes_exist(tvb, offset+0, 2); + dh_group = tvb_get_guint8(tvb, offset+1); + + switch (dh_group) { + case DH_OAKLEY_5: + dh_length = 1536/8; + break; + case DH_OAKLEY_1: + dh_length = 768/8; + break; + case DH_OAKLEY_2: + dh_length = 1024/8; + break; + default: + return -1; + } + + tvb_ensure_bytes_exist(tvb, offset+2, dh_length+1); + kv = tvb_get_guint8(tvb, offset+2+dh_length) & 0x0f; + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_DH_GROUP], tvb, 1, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_DH_VALUE], tvb, 2, dh_length, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_DH_RESERV], tvb, 2+dh_length, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_DH_KV], tvb, 2+dh_length, 1, FALSE); + } + + if (kv != 0) { + return -1; + } + + return 2+dh_length+1; +} + +static int +dissect_payload_sign(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint16 length; + guint8 s_type; + + tvb_ensure_bytes_exist(tvb, offset+0, 2); + s_type = (tvb_get_guint8(tvb, offset+0) & 0xf0) >> 4; + length = ((tvb_get_guint8(tvb, offset+0) & 0x0f) << 8) + tvb_get_guint8(tvb, offset+1); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_SIGN_S_TYPE], tvb, 0, 2, FALSE); + proto_tree_add_uint(tree, hf_mikey[POS_SIGNATURE_LEN], tvb, 0, 2, length); + } + + tvb_ensure_bytes_exist(tvb, offset+2, length); + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_SIGNATURE], tvb, 2, length, FALSE); + } + return 2 + length; +} + +static int +dissect_payload_t(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint8 ts_type; + int offset = 0; + int len = 0; + proto_tree* parent = NULL; + + tvb_ensure_bytes_exist(tvb, offset+0, 2); + ts_type = tvb_get_guint8(tvb, offset+1); + + if (tree) { + parent = proto_tree_get_parent(tree); + proto_tree_add_item(tree, hf_mikey[POS_TS_TYPE], tvb, offset+1, 1, FALSE); + } + + switch (ts_type) { + case T_NTP: + case T_NTP_UTC: { + gchar *buff; + + tvb_ensure_bytes_exist(tvb, offset+2, 8); + buff=ntp_fmt_ts(tvb_get_ptr( tvb, offset+2, 8 )); + + if(tree) + proto_tree_add_string_format( tree, hf_mikey[POS_TS_NTP], tvb, offset+2, 8, ( const char* ) buff, "NTP timestamp: %s", buff ); + + len = 10; + break; + } + case T_COUNTER: + len = 6; + break; + default: + len = -1; + break; + } + + return len; +} + +static int +dissect_payload_id(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint8 type; + guint16 length; + proto_item* parent = NULL; + + tvb_ensure_bytes_exist(tvb, offset+0, 4); + type = tvb_get_guint8(tvb, offset+1); + length = tvb_get_ntohs(tvb, offset+2); + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_ID_TYPE], tvb, 1, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_ID_LEN], tvb, 2, 2, FALSE); + } + + tvb_ensure_bytes_exist(tvb, offset+4, length); + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_ID], tvb, 4, length, FALSE); + + parent = proto_tree_get_parent(tree); + proto_item_append_text(parent, " %s: %s", val_to_str(type, id_type_vals, "Unknown"), tvb_get_ephemeral_string(tvb, 4, length)); + } + + return 4 + length; +} + +static int +dissect_payload_cert(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint8 type; + guint16 length; + tvbuff_t *subtvb; + proto_item* parent = NULL; + + tvb_ensure_bytes_exist(tvb, offset+0, 4); + type = tvb_get_guint8(tvb, offset+1); + length = tvb_get_ntohs(tvb, offset+2); + + tvb_ensure_bytes_exist(tvb, offset+4, length); + + if (tree) { + parent = proto_tree_get_parent(tree); + proto_tree_add_item(tree, hf_mikey[POS_CERT_TYPE], tvb, 1, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_CERT_LEN], tvb, 1, 2, FALSE); + + proto_item_append_text(parent, " Type: %s", val_to_str(type, cert_type_vals, "Unknown")); + } + + subtvb = tvb_new_subset(tvb, offset+4, length, length); + dissect_x509af_Certificate(FALSE, subtvb, 0, pinfo, tree, hf_mikey[POS_CERTIFICATE]); + + return 4 + length; +} + +static int +dissect_payload_v(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint16 length; + guint8 alg; + + tvb_ensure_bytes_exist(tvb, offset+0, 2); + alg = tvb_get_guint8(tvb, offset+1); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_V_AUTH_ALG], tvb, 1, 1, FALSE); + } + + switch (alg) { + case MAC_NULL: + length = 0; + break; + case MAC_HMAC_SHA_1_160: + length = 160/8; + break; + default: + proto_tree_add_debug_text(tree, "Unknown mac alg %d", alg); + return -1; + } + + tvb_ensure_bytes_exist(tvb, offset+2, length); + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_V_DATA], tvb, 2, length, FALSE); + } + + return 2 + length; +} + +static int +dissect_payload_sp_param(enum sp_prot_t proto, mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint8 type; + guint8 length; + proto_item *param_ti; + proto_tree *param_tree; + int hfindex; + + tvb_ensure_bytes_exist(tvb, offset+0, 2); + type = tvb_get_guint8(tvb, offset+0); + length = tvb_get_guint8(tvb, offset+1); + tvb_ensure_bytes_exist(tvb, offset+2, length); + + /* Default */ + hfindex = hf_mikey[POS_SP_PARAM_F]; + + switch(proto) { + case SP_PROT_TYPE_SRTP: + if (type < array_length(hf_mikey_sp_param)) + hfindex = hf_mikey_sp_param[type]; + break; + } + + if (tree) { + /* param_ti = proto_tree_add_item(tree, hfindex, tvb, 0, 2+length, FALSE); */ + param_ti = proto_tree_add_item(tree, hfindex, tvb, 2, length, FALSE); + param_tree = proto_item_add_subtree(param_ti, ett_mikey_sp_param); + + proto_tree_add_item(param_tree, hf_mikey[POS_SP_PARAM_F_TYPE], tvb, 0, 1, FALSE); + proto_tree_add_item(param_tree, hf_mikey[POS_SP_PARAM_F_LEN], tvb, 1, 1, FALSE); + proto_tree_add_item(param_tree, hf_mikey[POS_SP_PARAM_F_VALUE], tvb, 2, length, FALSE); + } + + return 2+length; +} + +static int +dissect_payload_sp(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint16 length; + int sub_pos; + guint8 no; + enum sp_prot_t type; + proto_item* parent = NULL; + + tvb_ensure_bytes_exist(tvb, offset+0, 5); + length = tvb_get_ntohs(tvb, offset+3); + no = tvb_get_guint8(tvb, offset+1); + type = tvb_get_guint8(tvb, offset+2); + + if (tree) { + parent = proto_tree_get_parent(tree); + proto_tree_add_item(tree, hf_mikey[POS_SP_NO], tvb, 1, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_SP_TYPE], tvb, 2, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_SP_PARAM_LEN], tvb, 3, 2, FALSE); + + proto_item_append_text(parent, " No: %d, Type: %s", no, val_to_str(type, sp_prot_type_vals, "Unknown")); + } + + tvb_ensure_bytes_exist(tvb, offset+5, length); +/* proto_tree_add_item(tree, hf_mikey[POS_SP_PARAM], tvb, 5, length, FALSE); */ + + offset += 5; + sub_pos = 0; + + while (sub_pos < length) { + int param_len; + tvbuff_t *subtvb; + + subtvb = tvb_new_subset(tvb, offset+sub_pos, length-sub_pos, length-sub_pos); + param_len = dissect_payload_sp_param(type, mikey, subtvb, pinfo, tree); + + if (param_len < 0) + return -1; + + sub_pos += param_len; + } + + return 5 + length; +} + + +static int +dissect_payload_rand(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint16 length; + + tvb_ensure_bytes_exist(tvb, offset+0, 2); + length = tvb_get_guint8(tvb, offset+1); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_RAND_LEN], tvb, 1, 1, FALSE); + } + + tvb_ensure_bytes_exist(tvb, offset+2, length); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_RAND], tvb, 2, length, FALSE); + } + return 2 + length; +} + +/* TODO support salt and kv data */ +static int +dissect_payload_keydata(mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint16 data_len; + + tvb_ensure_bytes_exist(tvb, 0, 4); + data_len = tvb_get_ntohs(tvb, 2); + + fprintf(stderr, "Data len %d\n", data_len); + tvb_ensure_bytes_exist(tvb, 4, data_len); + + if (tree) { + proto_tree_add_item(tree, hf_mikey[POS_KEY_DATA_TYPE], tvb, 1, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_KEY_DATA_KV], tvb, 1, 1, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_KEY_DATA_LEN], tvb, 2, 2, FALSE); + proto_tree_add_item(tree, hf_mikey[POS_KEY_DATA], tvb, 4, data_len, FALSE); + } + return 4+data_len; +} + +static const struct mikey_dissector_entry payload_map[] = { + { PL_HDR, dissect_payload_hdr }, + { PL_KEMAC, dissect_payload_kemac }, + { PL_PKE, dissect_payload_pke }, + { PL_DH, dissect_payload_dh }, + { PL_SIGN, dissect_payload_sign }, + { PL_T, dissect_payload_t }, + { PL_ID, dissect_payload_id }, + { PL_CERT, dissect_payload_cert }, + { PL_V, dissect_payload_v }, + { PL_SP, dissect_payload_sp }, + { PL_RAND, dissect_payload_rand }, + { PL_KEY_DATA, dissect_payload_keydata }, + { 0, NULL }, +}; + +static int +dissect_payload(enum payload_t payload, mikey_t *mikey, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + const struct mikey_dissector_entry *entry; + + entry = mikey_dissector_lookup(payload_map, payload); + + if (!entry || !entry->dissector) { + return -1; + } + + return entry->dissector(mikey, tvb, pinfo, tree); +} + +/* MIKEY dissector */ +int +dissect_mikey(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *ti = NULL; + proto_tree *mikey_tree = NULL; + int offset = 0; + int next_payload_offset; + tvbuff_t *subtvb = NULL; + int payload = -1; + mikey_t *mikey; + + mikey = p_get_proto_data(pinfo->fd, proto_mikey); + + if (!mikey) { + mikey = se_alloc0(sizeof(mikey_t)); + mikey->type = -1; + p_add_proto_data(pinfo->fd, proto_mikey, mikey); + } + + + tvb_ensure_bytes_exist(tvb, offset, 3); + next_payload_offset = offset+2; + payload = -1; + + if (tree) { + ti = proto_tree_add_item(tree, proto_mikey, tvb, 0, -1, FALSE); + mikey_tree = proto_item_add_subtree(ti, ett_mikey); + } + + while( payload != 0 ) { + int len; + proto_item *sub_ti = NULL; + proto_tree *mikey_payload_tree = NULL; + int next_payload; + + next_payload = tvb_get_guint8(tvb, next_payload_offset); + len = tvb_length_remaining(tvb, offset); + subtvb = tvb_new_subset(tvb, offset, len, len); + +/* sub_ti = proto_tree_add_string(mikey_tree, hf_mikey[POS_PAYLOAD_STR], subtvb, */ +/* 0, -1, val_to_str(payload, payload_vals, "Unassigned")); */ + + if (mikey_tree) { + int hf = payload; + + if (hf >= PL_MAX) + return -1; + + if (hf == -1) + hf = 0; + +/* sub_ti = proto_tree_add_string_format(mikey_tree, hf_mikey[POS_PAYLOAD_STR], subtvb, */ +/* 0, -1, "TODO", "%s", val_to_str(payload, payload_vals, "Unassigned")); */ + + sub_ti = proto_tree_add_item(mikey_tree, hf_mikey_pl[hf], subtvb, 0, -1, FALSE); + + mikey_payload_tree = proto_item_add_subtree(sub_ti, + ett_mikey_payload); + if (payload != PL_HDR && payload != PL_SIGN) + add_next_payload(tvb, mikey_payload_tree, next_payload_offset); + } + + len = dissect_payload(payload, mikey, subtvb, pinfo, mikey_payload_tree); + if (len < 0) { + proto_tree_add_debug_text(mikey_payload_tree, "Negative length"); + return -1; + } + + if (sub_ti) + proto_item_set_len(sub_ti, len); + + if (payload == PL_SIGN) + break; + + payload = next_payload; + offset += len; + next_payload_offset = offset; + } + + if (ti) { + proto_item_append_text(ti, ": %s", val_to_str(mikey->type, data_type_vals, "Unknown")); + } + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_append_str(pinfo->cinfo, COL_PROTOCOL, "/MIKEY"); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", Mikey: %s", val_to_str(mikey->type, data_type_vals, "Unknown")); + +/* Return the amount of data this dissector was able to dissect */ + return tvb_length(tvb); +} + + +/* Register the protocol with Wireshark */ + +/* this format is require because a script is used to build the C function + that calls all the protocol registration. +*/ + +void +proto_register_mikey(void) +{ + +/* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = { + /* Payload types */ + { &hf_mikey_pl[PL_HDR+1], + { PL_HDR_TEXT, "mikey.hdr", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_HDR_TEXT, HFILL }}, + { &hf_mikey_pl[PL_KEMAC], + { PL_KEMAC_TEXT, "mikey.kemac", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_KEMAC_TEXT, HFILL }}, + { &hf_mikey_pl[PL_PKE], + { PL_PKE_TEXT, "mikey.", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_PKE_TEXT, HFILL }}, + { &hf_mikey_pl[PL_DH], + { PL_DH_TEXT, "mikey.dh", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_DH_TEXT, HFILL }}, + { &hf_mikey_pl[PL_SIGN], + { PL_SIGN_TEXT, "mikey.sign", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_SIGN_TEXT, HFILL }}, + { &hf_mikey_pl[PL_T], + { PL_T_TEXT, "mikey.t", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_T_TEXT, HFILL }}, + { &hf_mikey_pl[PL_ID], + { PL_ID_TEXT, "mikey.id", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_ID_TEXT, HFILL }}, + { &hf_mikey_pl[PL_CERT], + { PL_CERT_TEXT, "mikey.cert", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_CERT_TEXT, HFILL }}, + { &hf_mikey_pl[PL_CHASH], + { PL_CHASH_TEXT, "mikey.chash", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_CHASH_TEXT, HFILL }}, + { &hf_mikey_pl[PL_V], + { PL_V_TEXT, "mikey.v", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_V_TEXT, HFILL }}, + { &hf_mikey_pl[PL_SP], + { PL_SP_TEXT, "mikey.sp", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_SP_TEXT, HFILL }}, + { &hf_mikey_pl[PL_RAND], + { PL_RAND_TEXT, "mikey.rand", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_RAND_TEXT, HFILL }}, + { &hf_mikey_pl[PL_ERR], + { PL_ERR_TEXT, "mikey.err", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_ERR_TEXT, HFILL }}, + { &hf_mikey_pl[PL_KEY_DATA], + { PL_KEY_DATA_TEXT, "mikey.key_data", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_KEY_DATA_TEXT, HFILL }}, + { &hf_mikey_pl[PL_GENERAL_EXT], + { PL_GENERAL_EXT_TEXT, "mikey.general_ext", + FT_NONE, BASE_NONE, NULL, 0x0, + PL_GENERAL_EXT_TEXT, HFILL }}, + + /* Common Header payload (HDR) */ + { &hf_mikey[POS_HDR_VERSION], + { "Version", "mikey.version", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Version", HFILL }}, + { &hf_mikey[POS_HDR_DATA_TYPE], + { "Data Type", "mikey.type", + FT_UINT8, BASE_DEC, VALS(data_type_vals), 0x0, + "Data Type", HFILL }}, + { &hf_mikey[POS_NEXT_PAYLOAD], + { "Next Payload", "", + FT_UINT8, BASE_DEC, VALS(payload_vals), 0x0, + "Next Payload", HFILL }}, + { &hf_mikey[POS_HDR_V], + { "V", "mikey.v", + FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x80, + "V", HFILL }}, + { &hf_mikey[POS_HDR_PRF_FUNC], + { "PRF func", "mikey.prf_func", + FT_UINT8, BASE_DEC, VALS(prf_func_vals), 0x7f, + "PRF func", HFILL }}, + { &hf_mikey[POS_HDR_CSB_ID], + { "CSB ID", "mikey.csb_id", + FT_UINT32, BASE_HEX, NULL, 0x0, + "CSB ID", HFILL }}, + { &hf_mikey[POS_HDR_CS_COUNT], + { "#CS", "mikey.cs_count", + FT_UINT8, BASE_DEC, NULL, 0x0, + "#CS", HFILL }}, + { &hf_mikey[POS_HDR_CS_ID_MAP_TYPE], + { "CS ID map type", "mikey.cs_id_map_type", + FT_UINT8, BASE_DEC, VALS(cs_id_map_vals), 0x0, + "CS ID map type", HFILL }}, + + /* SRTP ID */ + { &hf_mikey[POS_ID_SRTP], + { "SRTP ID", "mikey.srtp_id", + FT_NONE, BASE_NONE, NULL, 0x0, + "SRTP ID", HFILL }}, + { &hf_mikey[POS_ID_SRTP_NO], + { "Policy No", "mikey.srtp_id.policy_no", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Policy No", HFILL }}, + { &hf_mikey[POS_ID_SRTP_SSRC], + { "SSRC", "mikey.srtp_id.ssrc", + FT_UINT32, BASE_HEX, NULL, 0x0, + "SSRC", HFILL }}, + { &hf_mikey[POS_ID_SRTP_ROC], + { "ROC", "mikey.srtp_id.roc", + FT_UINT32, BASE_HEX, NULL, 0x0, + "ROC", HFILL }}, + + /* Key Data Transport payload (KEMAC) */ + { &hf_mikey[POS_KEMAC_ENCR_ALG], + { "Encr alg", "mikey.kemac.encr_alg", + FT_UINT8, BASE_DEC, VALS(encr_alg_vals), 0x0, + "Encr alg", HFILL }}, + { &hf_mikey[POS_KEMAC_ENCR_DATA_LEN], + { "Encr data len", "mikey.kemac.encr_data_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Encr data len", HFILL }}, + { &hf_mikey[POS_KEMAC_ENCR_DATA], + { "Encr data", "mikey.kemac.encr_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Encr data", HFILL }}, + { &hf_mikey[POS_KEMAC_MAC_ALG], + { "Mac alg", "mikey.kemac.mac_alg", + FT_UINT8, BASE_DEC, VALS(mac_alg_vals), 0x0, + "Mac alg", HFILL }}, + { &hf_mikey[POS_KEMAC_MAC], + { "MAC", "mikey.kemac.mac", + FT_BYTES, BASE_NONE, NULL, 0x0, + "MAC", HFILL }}, + + /* Envelope Data payload (PKE) */ + { &hf_mikey[POS_PKE_C], + { "C", "mikey.pke.c", + FT_UINT16, BASE_DEC, VALS(pke_c_vals), 0xc000, + "C", HFILL }}, + { &hf_mikey[POS_PKE_DATA_LEN], + { "Data len", "mikey.pke.len", + FT_UINT16, BASE_DEC, NULL, 0x3fff, + "Data len", HFILL }}, + { &hf_mikey[POS_PKE_DATA], + { "Data", "mikey.pke.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Data", HFILL }}, + + /* DH data payload (DH) */ + { &hf_mikey[POS_DH_GROUP], + { "DH-Group", "mikey.dh.group", + FT_UINT8, BASE_DEC, VALS(oakley_vals), 0x0, + "DH-Group", HFILL }}, + { &hf_mikey[POS_DH_VALUE], + { "DH-Value", "mikey.dh.value", + FT_BYTES, BASE_NONE, NULL, 0x0, + "DH-Value", HFILL }}, + { &hf_mikey[POS_DH_RESERV], + { "Reserv", "mikey.dh.reserv", + FT_UINT8, BASE_HEX, NULL, 0xf0, + "Reserv", HFILL }}, + { &hf_mikey[POS_DH_KV], + { "KV", "mikey.dh.kv", + FT_UINT8, BASE_DEC, VALS(kv_vals), 0x0f, + "KV", HFILL }}, + + /* Signature payload (SIGN) */ + { &hf_mikey[POS_SIGN_S_TYPE], + { "Signature type", "mikey.sign.type", + FT_UINT16, BASE_DEC, VALS(sign_s_vals), 0xf000, + "Signature type", HFILL }}, + { &hf_mikey[POS_SIGNATURE_LEN], + { "Signature len", "mikey.sign.len", + FT_UINT16, BASE_DEC, NULL, 0x0fff, + "Signature len", HFILL }}, + { &hf_mikey[POS_SIGNATURE], + { "Signature", "mikey.sign.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Signature", HFILL }}, + + /* Timestamp payload (T) */ + { &hf_mikey[POS_TS_TYPE], + { "TS type", "mikey.t.ts_type", + FT_UINT8, BASE_DEC, VALS(ts_type_vals), 0x0, + "TS type", HFILL }}, + { &hf_mikey[POS_TS_NTP], + { "NTP timestamp", "mikey.t.ntp", + FT_STRING, BASE_HEX, NULL, 0x0, + "NTP", HFILL }}, + + { &hf_mikey[POS_PAYLOAD_STR], + { "Payload", "mikey.payload", + FT_STRING, BASE_NONE, NULL, 0x0, + "Payload", HFILL }}, + + /* ID payload (ID) */ + { &hf_mikey[POS_ID_TYPE], + { "ID type", "mikey.id.type", + FT_UINT8, BASE_DEC, VALS(id_type_vals), 0x0, + "ID type", HFILL }}, + { &hf_mikey[POS_ID_LEN], + { "ID len", "mikey.id.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "ID len", HFILL }}, + { &hf_mikey[POS_ID], + { "ID", "mikey.id.data", + FT_STRING, BASE_NONE, NULL, 0x0, + "ID", HFILL }}, + + /* Certificate payload (CERT) */ + { &hf_mikey[POS_CERT_LEN], + { "Certificate len", "mikey.cert.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Certificate len", HFILL }}, + { &hf_mikey[POS_CERT_TYPE], + { "Certificate type", "mikey.cert.type", + FT_UINT8, BASE_DEC, VALS(cert_type_vals), 0x0, + "Certificate type", HFILL }}, + { &hf_mikey[POS_CERTIFICATE], + { "Certificate", "mikey.cert.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Certificate", HFILL }}, + + /* Ver msg payload (V) */ + { &hf_mikey[POS_V_AUTH_ALG], + { "Auth alg", "mikey.v.auth_alg", + FT_UINT8, BASE_DEC, VALS(mac_alg_vals), 0x0, + "Auth alg", HFILL }}, + { &hf_mikey[POS_V_DATA], + { "Ver data", "mikey.v.ver_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Ver data", HFILL }}, + + /* Security Policy payload (SP) */ + { &hf_mikey[POS_SP_NO], + { "Policy No", "mikey.sp.no", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Policy No", HFILL }}, + { &hf_mikey[POS_SP_TYPE], + { "Protocol type", "mikey.sp.proto_type", + FT_UINT8, BASE_DEC, VALS(sp_prot_type_vals), 0x0, + "Protocol type", HFILL }}, + { &hf_mikey[POS_SP_PARAM_LEN], + { "Policy param length", "mikey.sp.param_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Policy param length", HFILL }}, + + /* Security Policy param */ + { &hf_mikey[POS_SP_PARAM_F], + { "Policy param", "mikey.sp.param", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Policy param", HFILL }}, + { &hf_mikey[POS_SP_PARAM_F_TYPE], + { "Type", "mikey.sp.param.type", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Type", HFILL }}, + { &hf_mikey[POS_SP_PARAM_F_LEN], + { "Length", "mikey.sp.param.len", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Length", HFILL }}, + { &hf_mikey[POS_SP_PARAM_F_VALUE], + { "Value", "mikey.sp.patam.value", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Value", HFILL }}, + + /* SRTP policy param */ + { &hf_mikey_sp_param[SP_ENCR_ALG], + { SP_TEXT_ENCR_ALG, "mikey.sp.encr_alg", + FT_UINT8, BASE_DEC, VALS(sp_encr_alg_vals), 0x0, + SP_TEXT_ENCR_ALG, HFILL }}, + { &hf_mikey_sp_param[SP_ENCR_LEN], + { SP_TEXT_ENCR_LEN, "mikey.sp.encr_len", + FT_UINT8, BASE_DEC, NULL, 0x0, + SP_TEXT_ENCR_LEN, HFILL }}, + { &hf_mikey_sp_param[SP_AUTH_ALG], + { SP_TEXT_AUTH_ALG, "mikey.sp.auth_alg", + FT_UINT8, BASE_DEC, VALS(sp_auth_alg_vals), 0x0, + SP_TEXT_AUTH_ALG, HFILL }}, + { &hf_mikey_sp_param[SP_AUTH_KEY_LEN], + { SP_TEXT_AUTH_KEY_LEN, "mikey.sp.auth_key_len", + FT_UINT8, BASE_DEC, NULL, 0x0, + SP_TEXT_AUTH_KEY_LEN, HFILL }}, + { &hf_mikey_sp_param[SP_SALT_LEN], + { SP_TEXT_SALT_LEN, "mikey.sp.salt_len", + FT_UINT8, BASE_DEC, NULL, 0x0, + SP_TEXT_SALT_LEN, HFILL }}, + { &hf_mikey_sp_param[SP_PRF], + { SP_TEXT_PRF, "mikey.sp.prf", + FT_UINT8, BASE_DEC, VALS(sp_prf_vals), 0x0, + SP_TEXT_PRF, HFILL }}, + { &hf_mikey_sp_param[SP_KD_RATE], + { SP_TEXT_KD_RATE, "mikey.sp.kd_rate", + FT_UINT8, BASE_DEC, NULL, 0x0, + SP_TEXT_KD_RATE, HFILL }}, + { &hf_mikey_sp_param[SP_SRTP_ENCR], + { SP_TEXT_SRTP_ENCR, "mikey.sp.srtp_encr", + FT_UINT8, BASE_DEC, VALS(on_off_vals), 0x0, + SP_TEXT_SRTP_ENCR, HFILL }}, + { &hf_mikey_sp_param[SP_SRTCP_ENCR], + { SP_TEXT_SRTCP_ENCR, "mikey.sp.srtcp_encr", + FT_UINT8, BASE_DEC, VALS(on_off_vals), 0x0, + SP_TEXT_SRTCP_ENCR, HFILL }}, + { &hf_mikey_sp_param[SP_FEC], + { SP_TEXT_FEC, "mikey.sp.fec", + FT_UINT8, BASE_DEC, VALS(sp_fec_vals), 0x0, + SP_TEXT_FEC, HFILL }}, + { &hf_mikey_sp_param[SP_SRTP_AUTH], + { SP_TEXT_SRTP_AUTH, "mikey.sp.srtp_auth", + FT_UINT8, BASE_DEC, VALS(on_off_vals), 0x0, + SP_TEXT_SRTP_AUTH, HFILL }}, + { &hf_mikey_sp_param[SP_AUTH_TAG_LEN], + { SP_TEXT_AUTH_TAG_LEN, "mikey.sp.auth_tag_len", + FT_UINT8, BASE_DEC, NULL, 0x0, + SP_TEXT_AUTH_TAG_LEN, HFILL }}, + { &hf_mikey_sp_param[SP_SRTP_PREFIX], + { SP_TEXT_SRTP_PREFIX, "mikey.sp.srtp_prefix", + FT_UINT8, BASE_DEC, NULL, 0x0, + SP_TEXT_SRTP_PREFIX, HFILL }}, + + /* RAND payload (RAND) */ + { &hf_mikey[POS_RAND_LEN], + { "RAND len", "mikey.rand.len", + FT_UINT8, BASE_DEC, NULL, 0x0, + "RAND len", HFILL }}, + { &hf_mikey[POS_RAND], + { "RAND", "mikey.rand.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "RAND", HFILL }}, + + /* Key data sub-payload */ + { &hf_mikey[POS_KEY_DATA_TYPE], + { "Type", "mikey.key_data.type", + FT_UINT8, BASE_DEC, VALS(kd_vals), 0xf0, + "Type", HFILL }}, + { &hf_mikey[POS_KEY_DATA_KV], + { "KV", "mikey.key_data.kv", + FT_UINT8, BASE_DEC, VALS(kv_vals), 0x0f, + "KV", HFILL }}, + { &hf_mikey[POS_KEY_DATA_LEN], + { "Key data len", "mikey.key_data.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Key data len", HFILL }}, + { &hf_mikey[POS_KEY_DATA], + { "Key data", "mikey.key_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Key data", HFILL }}, + + +/* + { &hf_mikey[POS_SP_PARAM], + { "Policy param", "", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Policy param", HFILL }}, + + { &hf_mikey[POS_PAYLOAD], + { "Payload", "", + FT_BYTES, BASE_HEX, NULL, 0x0, + "Payload", HFILL }}, + + { &hf_mikey[POS_], + { "", "", + FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + { &hf_mikey[POS_], + { "", "", + FT_UINT16, BASE_DEC, NULL, 0x0, + "", HFILL }}, + { &hf_mikey[POS_], + { "", "", + FT_UINT24, BASE_DEC, NULL, 0x0, + "", HFILL }}, + { &hf_mikey[POS_], + { "", "", + FT_UINT32, BASE_HEX, NULL, 0x0, + "", HFILL }}, + { &hf_mikey[POS_], + { "", "", + FT_BYTES, BASE_NONE, NULL, 0x0, + "", HFILL }}, +*/ + }; + +/* Setup protocol subtree array */ + static gint *ett[] = { + &ett_mikey, + &ett_mikey_payload, + &ett_mikey_sp_param, + &ett_mikey_hdr_id, + }; + +/* Register the protocol name and description */ + proto_mikey = proto_register_protocol("Multimedia Internet KEYing", + "MIKEY", "mikey"); + +/* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_mikey, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + +/* Register preferences module (See Section 2.6 for more on preferences) */ +/* mikey_module = prefs_register_protocol(proto_mikey, */ +/* proto_reg_handoff_mikey); */ + +/* Register a sample preference */ +/* prefs_register_bool_preference(mikey_module, "showHex", */ +/* "Display numbers in Hex", */ +/* "Enable to display numerical values in hexadecimal.", */ +/* &gPREF_HEX); */ +} + + +void +proto_reg_handoff_mikey(void) +{ + static gboolean inited = FALSE; + static dissector_handle_t mikey_handle; + + if (!inited) { + +/* Use new_create_dissector_handle() to indicate that dissect_mikey() + * returns the number of bytes it dissected (or 0 if it thinks the packet + * does not belong to Multimedia Internet KEYing). + */ + mikey_handle = new_create_dissector_handle(dissect_mikey, + proto_mikey); + inited = TRUE; + } else { + dissector_delete_string("key_mgmt", "mikey", mikey_handle); + } + +/* media_type_subdissector_table = */ + dissector_add_string("key_mgmt", "mikey", mikey_handle); + + /* + If you perform registration functions which are dependant upon + prefs the you should de-register everything which was associated + with the previous settings and re-register using the new prefs + settings here. In general this means you need to keep track of what + value the preference had at the time you registered using a local + static in this function. ie. + + static int currentPort = -1; + + if (currentPort != -1) { + dissector_delete("tcp.port", currentPort, mikey_handle); + } + + currentPort = gPortPref; + + dissector_add("tcp.port", currentPort, mikey_handle); + + */ +} diff --git a/epan/dissectors/packet-mikey.h b/epan/dissectors/packet-mikey.h new file mode 100644 index 0000000000..f6e44ae060 --- /dev/null +++ b/epan/dissectors/packet-mikey.h @@ -0,0 +1,34 @@ +/* packet-mikey.h + * Routines for Multimedia Internet KEYing dissection + * Copyright 2007, Mikael Magnusson <mikma@users.sourceforge.net> + * + * $Id$ + * + * Copyright (c) 2003 by Erwin Rol <erwin@erwinrol.com> + * Copyright (c) 2006 by Electronic Theatre Controls, Inc. + * Bill Florac <bflorac@etcconnect.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __PACKET_MIKEY_H__ +#define __PACKET_MIKEY_H__ +int +dissect_mikey(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +#endif /* define __PACKET_MIKEY_H__ */ diff --git a/epan/dissectors/packet-sdp.c b/epan/dissectors/packet-sdp.c index f93ce41f93..f3b19bd344 100644 --- a/epan/dissectors/packet-sdp.c +++ b/epan/dissectors/packet-sdp.c @@ -54,6 +54,7 @@ #include <epan/conversation.h> #include <epan/strutil.h> #include <epan/emem.h> +#include <epan/base64.h> #include "tap.h" #include "packet-sdp.h" @@ -160,6 +161,11 @@ static int hf_sdp_fmtp_profile_level_id = -1; static int hf_sdp_fmtp_h263_profile = -1; static int hf_SDPh223LogicalChannelParameters = -1; +/* hf_session_attribute hf_media_attribute subfields */ +static int hf_key_mgmt_att_value = -1; +static int hf_key_mgmt_prtcl_id = -1; +static int hf_key_mgmt_data = -1; + /* trees */ static int ett_sdp = -1; static int ett_sdp_owner = -1; @@ -173,6 +179,7 @@ static int ett_sdp_session_attribute = -1; static int ett_sdp_media = -1; static int ett_sdp_media_attribute = -1; static int ett_sdp_fmtp = -1; +static int ett_sdp_key_mgmt = -1; #define SDP_MAX_RTP_CHANNELS 4 @@ -200,6 +207,12 @@ static gboolean msrp_transport_address_set = FALSE; static guint32 msrp_ipaddr[4]; static guint16 msrp_port_number; +/* key-mgmt dissector + * IANA registry: + * http://www.iana.org/assignments/sdp-parameters + */ +static dissector_table_t key_mgmt_dissector_table; + /* Protocol registration */ void proto_register_sdp(void); @@ -220,7 +233,7 @@ static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti); static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti); static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti); static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti); -static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item *ti); +static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti); static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti, transport_info_t *transport_info); static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti, transport_info_t *transport_info); @@ -543,7 +556,7 @@ call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, } else if ( hf == hf_encryption_key ) { dissect_sdp_encryption_key(tvb,ti); } else if ( hf == hf_session_attribute ){ - dissect_sdp_session_attribute(tvb,ti); + dissect_sdp_session_attribute(tvb,pinfo,ti); } else if ( hf == hf_media ) { dissect_sdp_media(tvb,ti,transport_info); } else if ( hf == hf_media_attribute ){ @@ -864,9 +877,77 @@ static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){ tvb, offset, -1, FALSE); } +/* Return a tvb that contains the binary representation of a base64 + string */ + +static tvbuff_t * +base64_to_tvb(const char *base64) +{ + tvbuff_t *tvb; + char *data = g_strdup(base64); + size_t len; + + len = epan_base64_decode(data); + tvb = tvb_new_real_data((const guint8 *)data, len, len); + + tvb_set_free_cb(tvb, g_free); + + return tvb; +} + + +static void dissect_key_mgmt(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){ + gchar *data = NULL; + gchar *prtcl_id = NULL; + gint len; + tvbuff_t *keymgmt_tvb; + gboolean found_match = FALSE; + proto_tree *key_tree; + gint next_offset; + gint offset = 0; + gint tokenlen; + key_tree = proto_item_add_subtree(ti, ett_sdp_key_mgmt); -static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item * ti){ + next_offset = tvb_find_guint8(tvb,offset,-1,' '); + + if (next_offset == -1) + return; + + tokenlen = next_offset - offset; + prtcl_id = tvb_get_ephemeral_string(tvb, offset, tokenlen); + + proto_tree_add_item(key_tree, hf_key_mgmt_prtcl_id, tvb, offset, tokenlen, FALSE); + + offset = next_offset + 1; + + len = tvb_length_remaining(tvb, offset); + if (len < 0) + return; + + data = tvb_get_ephemeral_string(tvb, offset, len); + keymgmt_tvb = base64_to_tvb(data); + tvb_set_child_real_data_tvbuff(tvb, keymgmt_tvb); + add_new_data_source(pinfo, keymgmt_tvb, "Key Management Data"); + + if ( prtcl_id != NULL && key_mgmt_dissector_table != NULL ) { + found_match = dissector_try_string(key_mgmt_dissector_table, + prtcl_id, + keymgmt_tvb, pinfo, + key_tree); + } + + if (found_match) + proto_tree_add_item_hidden(key_tree, hf_key_mgmt_data, + keymgmt_tvb, 0, -1, FALSE); + else + proto_tree_add_item(key_tree, hf_key_mgmt_data, + keymgmt_tvb, 0, -1, FALSE); + return; +} + + +static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){ proto_tree *sdp_session_attribute_tree; gint offset, next_offset, tokenlen; guint8 *field_name; @@ -918,7 +999,14 @@ static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item * ti){ return; proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE); - + } else if (strcmp((char*)field_name, "key-mgmt") == 0) { + tvbuff_t *key_tvb; + proto_item *key_ti; + + key_tvb = tvb_new_subset(tvb, offset, -1, -1); + key_ti = proto_tree_add_item(sdp_session_attribute_tree, hf_key_mgmt_att_value, key_tvb, 0, -1, FALSE); + + dissect_key_mgmt(key_tvb, pinfo, key_ti); } else { proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value, tvb, offset, -1, FALSE); @@ -1772,7 +1860,18 @@ proto_register_sdp(void) { "h223LogicalChannelParameters", "sdp.h223LogicalChannelParameters", FT_NONE, BASE_NONE, NULL, 0, "sdp.h223LogicalChannelParameters", HFILL }}, - + { &hf_key_mgmt_att_value, + { "Key Management", + "sdp.key_mgmt", FT_STRING, BASE_NONE, NULL, 0x0, + "Key Management", HFILL }}, + { &hf_key_mgmt_prtcl_id, + { "Key Management Protocol (kmpid)", + "sdp.key_mgmt.kmpid", FT_STRING, BASE_NONE, NULL, 0x0, + "Key Management Protocol", HFILL }}, + { &hf_key_mgmt_data, + { "Key Management Data", + "sdp.key_mgmt.data", FT_BYTES, BASE_NONE, NULL, 0x0, + "Key Management Data", HFILL }}, }; static gint *ett[] = { &ett_sdp, @@ -1787,6 +1886,7 @@ proto_register_sdp(void) &ett_sdp_media, &ett_sdp_media_attribute, &ett_sdp_fmtp, + &ett_sdp_key_mgmt, }; module_t *sdp_module; @@ -1796,6 +1896,9 @@ proto_register_sdp(void) proto_register_field_array(proto_sdp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + key_mgmt_dissector_table = register_dissector_table("key_mgmt", + "Key Management", FT_STRING, BASE_NONE); + /* * Preferences registration */ |