From Ivan Lawrow: Added IEEE 802.15.4-2003 AES-CCM security modes

https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=4912

svn path=/trunk/; revision=40004
This commit is contained in:
Bill Meier 2011-11-25 22:02:25 +00:00
parent a4fedb2a86
commit 78af0d3f86
3 changed files with 126 additions and 54 deletions

View File

@ -3350,6 +3350,10 @@ Mariusz Okrój <okrojmariusz [AT]gmail.com> {
XMPP enhancements
}
Ivan Lawrow <ivan.lawrow [AT] jennic.com> {
Added IEEE 802.15.4-2003 AES-CCM security modes
}
and by:

View File

@ -162,10 +162,6 @@ UAT_BUFFER_CB_DEF(addr_uat, eui64, static_addr_t, eui64, eui64_len)
*/
/* Register Functions. Loads the dissector into Wireshark. */
void proto_reg_handoff_ieee802154 (void);
void proto_register_ieee802154 (void);
static void proto_init_ieee802154 (void);
/* TODO: cleanup. */
/* Dissection Routines. */
static void dissect_ieee802154_nonask_phy (tvbuff_t *, packet_info *, proto_tree *);
@ -200,7 +196,7 @@ typedef enum {
static tvbuff_t * dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *,
ws_decrypt_status *);
static void ccm_init_block (gchar *, gboolean, gint, guint64, guint32, ieee802154_security_level, gint);
static void ccm_init_block (gchar *, gboolean, gint, guint64, ieee802154_packet *, gint);
static gboolean ccm_ctr_encrypt (const gchar *, const gchar *, gchar *, gchar *, gint);
static gboolean ccm_cbc_mac (const gchar *, const gchar *, const gchar *, gint, const gchar *, gint, gchar *);
@ -273,6 +269,10 @@ static int hf_ieee802154_aux_sec_frame_counter = -1;
static int hf_ieee802154_aux_sec_key_source = -1;
static int hf_ieee802154_aux_sec_key_index = -1;
/* 802.15.4-2003 security */
static int hf_ieee802154_sec_frame_counter = -1;
static int hf_ieee802154_sec_key_sequence_counter = -1;
/* Initialize Subtree Pointers */
static gint ett_ieee802154_nonask_phy = -1;
static gint ett_ieee802154_nonask_phy_phr = -1;
@ -347,8 +347,25 @@ static const true_false_string ieee802154_gts_direction_tfs = {
"Transmit Only"
};
/* The 802.15.4-2003 security suites for the security preferences (only AES-CCM suites are supported). */
/* NOTE: The equivalent 2006 security level identifer enumerations are used to simplify 2003 & 2006 integration! */
static enum_val_t ieee802154_2003_sec_suite_enums[] = {
{ "AES-CCM-128", "AES-128 Encryption, 128-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_128 },
{ "AES-CCM-64", "AES-128 Encryption, 64-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_64 },
{ "AES-CCM-32", "AES-128 Encryption, 32-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_32 },
{ NULL, NULL, 0 }
};
/* Preferences for 2003 security */
static gint ieee802154_sec_suite = SECURITY_LEVEL_ENC_MIC_64;
static gboolean ieee802154_extend_auth = TRUE;
/* Macro to check addressing, and throw a warning flag if incorrect. */
#define IEEE802154_CMD_ADDR_CHECK(_pinfo_, _item_, _cmdid_, _x_) if (!(_x_)) expert_add_info_format(_pinfo_, _item_, PI_MALFORMED, PI_WARN, "Invalid Addressing for %s", val_to_str(_cmdid_, ieee802154_cmd_names, "Unknown Command"))
#define IEEE802154_CMD_ADDR_CHECK(_pinfo_, _item_, _cmdid_, _x_) \
if (!(_x_)) \
expert_add_info_format(_pinfo_, _item_, PI_MALFORMED, PI_WARN, \
"Invalid Addressing for %s", \
val_to_str(_cmdid_, ieee802154_cmd_names, "Unknown Command"))
/* CRC definitions. IEEE 802.15.4 CRCs vary from CCITT by using an initial value of
* 0x0000, and no XOR out. IEEE802154_CRC_XOR is defined as 0xFFFF in order to un-XOR
@ -968,6 +985,23 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
* PAYLOAD DISSECTION
*=====================================================
*/
/* IEEE 802.15.4-2003 may have security information pre-pended to payload */
if (packet->security_enable && (packet->version == IEEE802154_VERSION_2003)) {
/* Store security suite preference in the 2006 security level identifier to simplify 2003 integration! */
packet->security_level = ieee802154_sec_suite;
/* Frame Counter and Key Sequence Counter prepended to the payload of an encrypted frame */
if (IEEE802154_IS_ENCRYPTED(packet->security_level)) {
packet->frame_counter = tvb_get_letohl (tvb, offset);
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_sec_frame_counter, tvb, offset, sizeof(guint32), packet->frame_counter);
offset += sizeof(guint32);
packet->key_sequence_counter = tvb_get_guint8 (tvb, offset);
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_sec_key_sequence_counter, tvb, offset, sizeof(guint8), packet->key_sequence_counter);
offset += sizeof(guint8);
}
}
/* Encrypted Payload. */
if (packet->security_enable) {
payload_tvb = dissect_ieee802154_decrypt(tvb, offset, pinfo, packet, &status);
@ -1766,13 +1800,13 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie
ieee802154_hints_t *ieee_hints;
/*
* Check the version; we only support IEEE 802.15.4-2006.
* We must do this first, as, if this isn't IEEE 802.15.4-2006,
* Check the version; we only support IEEE 802.15.4-2003 and IEEE 802.15.4-2006.
* We must do this first, as, if this isn't IEEE 802.15.4-2003 or IEEE 802.15.4-2006,
* we don't have the Auxiliary Security Header, and haven't
* filled in the information for it, and none of the stuff
* we do afterwards, which uses that information, is doable.
*/
if (packet->version != IEEE802154_VERSION_2006) {
if ((packet->version != IEEE802154_VERSION_2006) && (packet->version != IEEE802154_VERSION_2003)) {
*status = DECRYPT_VERSION_UNSUPPORTED;
return NULL;
}
@ -1845,7 +1879,7 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie
*=====================================================
*/
/* Create the CCM* initial block for decryption (Adata=0, M=0, counter=0). */
ccm_init_block(tmp, FALSE, 0, srcAddr, packet->frame_counter, packet->security_level, 0);
ccm_init_block(tmp, FALSE, 0, srcAddr, packet, 0);
/* Decrypt the ciphertext, and place the plaintext in a new tvb. */
if (IEEE802154_IS_ENCRYPTED(packet->security_level) && captured_len) {
@ -1899,9 +1933,12 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie
l_a += l_m;
l_m = 0;
}
else if ((packet->version == IEEE802154_VERSION_2003) && !ieee802154_extend_auth)
l_a -= 5; /* Exclude Frame Counter (4 bytes) and Key Sequence Counter (1 byte) from authentication data
/* Create the CCM* initial block for authentication (Adata!=0, M!=0, counter=l(m)). */
ccm_init_block(tmp, TRUE, M, srcAddr, packet->frame_counter, packet->security_level, l_m);
ccm_init_block(tmp, TRUE, M, srcAddr, packet, l_m);
/* Compute CBC-MAC authentication tag. */
/*
@ -1934,15 +1971,14 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie
* gboolean adata - TRUE if additional auth data is present
* gint M - CCM* parameter M.
* guint64 addr - Source extended address.
* guint32 counter - Frame counter.
* ieee802154_security_level level - Security leve being used.
* ieee802154_packet *packet - IEEE 802.15.4 packet information.
* guint16 ctr_val - Value in the last L bytes of the block.
* RETURNS
* void
*---------------------------------------------------------------
*/
static void
ccm_init_block(gchar *block, gboolean adata, gint M, guint64 addr, guint32 counter, ieee802154_security_level level, gint ctr_val)
ccm_init_block(gchar *block, gboolean adata, gint M, guint64 addr, ieee802154_packet * packet, gint ctr_val)
{
gint i = 0;
@ -1951,7 +1987,8 @@ ccm_init_block(gchar *block, gboolean adata, gint M, guint64 addr, guint32 count
if (M > 0) block[i] |= (((M-2)/2) << 3); /* (M-2)/2 */
if (adata) block[i] |= (1 << 6); /* Adata */
i++;
/* Nonce: Source Address || Frame Counter || Security Level */
/* 2003 CCM Nonce: Source Address || Frame Counter || Key Sequence Counter */
/* 2006 CCM* Nonce: Source Address || Frame Counter || Security Level */
block[i++] = (guint8)((addr >> 56) & 0xff);
block[i++] = (guint8)((addr >> 48) & 0xff);
block[i++] = (guint8)((addr >> 40) & 0xff);
@ -1960,11 +1997,14 @@ ccm_init_block(gchar *block, gboolean adata, gint M, guint64 addr, guint32 count
block[i++] = (guint8)((addr >> 16) & 0xff);
block[i++] = (guint8)((addr >> 8) & 0xff);
block[i++] = (guint8)((addr >> 0) & 0xff);
block[i++] = (guint8)((counter >> 24) & 0xff);
block[i++] = (guint8)((counter >> 16) & 0xff);
block[i++] = (guint8)((counter >> 8) & 0xff);
block[i++] = (guint8)((counter >> 0) & 0xff);
block[i++] = level;
block[i++] = (guint8)((packet->frame_counter >> 24) & 0xff);
block[i++] = (guint8)((packet->frame_counter >> 16) & 0xff);
block[i++] = (guint8)((packet->frame_counter >> 8) & 0xff);
block[i++] = (guint8)((packet->frame_counter >> 0) & 0xff);
if (packet->version == IEEE802154_VERSION_2003)
block[i++] = packet->key_sequence_counter;
else
block[i++] = packet->security_level;
/* Plaintext length. */
block[i++] = (guint8)((ctr_val >> 8) & 0xff);
block[i++] = (guint8)((ctr_val >> 0) & 0xff);
@ -2301,6 +2341,42 @@ gboolean ieee802154_long_addr_invalidate(guint64 long_addr, guint fnum)
} /* ieee802154_long_addr_invalidate */
/*FUNCTION:------------------------------------------------------
* NAME
* proto_init_ieee802154
* DESCRIPTION
* Init routine for the IEEE 802.15.4 dissector. Creates hash
* tables for mapping between 16-bit to 64-bit addresses and
* populates them with static address pairs from a UAT
* preference table.
* PARAMETERS
* none
* RETURNS
* void
*---------------------------------------------------------------
*/
static void
proto_init_ieee802154(void)
{
guint i;
/* Destroy hash tables, if they exist. */
if (ieee802154_map.short_table)
g_hash_table_destroy(ieee802154_map.short_table);
if (ieee802154_map.long_table)
g_hash_table_destroy(ieee802154_map.long_table);
/* Create the hash tables. */
ieee802154_map.short_table = g_hash_table_new(ieee802154_short_addr_hash, ieee802154_short_addr_equal);
ieee802154_map.long_table = g_hash_table_new(ieee802154_long_addr_hash, ieee802154_long_addr_equal);
/* Re-load the hash table from the static address UAT. */
for (i=0; (i<num_static_addrs) && (static_addrs); i++) {
ieee802154_addr_update(&ieee802154_map,(guint16)static_addrs[i].addr16, (guint16)static_addrs[i].pan,
pntoh64(static_addrs[i].eui64), ieee802154_user, IEEE802154_USER_MAPPING);
} /* for */
} /* proto_init_ieee802154 */
/*FUNCTION:------------------------------------------------------
* NAME
* proto_register_ieee802154
@ -2562,7 +2638,16 @@ void proto_register_ieee802154(void)
{ &hf_ieee802154_aux_sec_key_index,
{ "Key Index", "wpan.aux_sec.key_index", FT_UINT8, BASE_HEX, NULL, 0x0,
"Key Index for processing of the protected frame", HFILL }}
"Key Index for processing of the protected frame", HFILL }},
/* IEEE 802.15.4-2003 Security Header Fields */
{ &hf_ieee802154_sec_frame_counter,
{ "Frame Counter", "wpan.sec_frame_counter", FT_UINT32, BASE_HEX, NULL, 0x0,
"Frame counter of the originator of the protected frame (802.15.4-2003)", HFILL }},
{ &hf_ieee802154_sec_key_sequence_counter,
{ "Key Sequence Counter", "wpan.sec_key_sequence_counter", FT_UINT8, BASE_HEX, NULL, 0x0,
"Key Sequence counter of the originator of the protected frame (802.15.4-2003)", HFILL }}
};
/* Subtrees */
@ -2651,6 +2736,19 @@ void proto_register_ieee802154(void)
prefs_register_string_preference(ieee802154_module, "802154_key", "Decryption key",
"128-bit decryption key in hexadecimal format", (const char **)&ieee802154_key_str);
prefs_register_enum_preference(ieee802154_module, "802154_sec_suite",
"Security Suite (802.15.4-2003)",
"Specifies the security suite to use for 802.15.4-2003 secured frames"
" (only supported suites are listed). Option ignored for 802.15.4-2006"
" and unsecured frames.",
&ieee802154_sec_suite, ieee802154_2003_sec_suite_enums, FALSE);
prefs_register_bool_preference(ieee802154_module, "802154_extend_auth",
"Extend authentication data (802.15.4-2003)",
"Set if the manufacturer extends the authentication data with the"
" security header. Option ignored for 802.15.4-2006 and unsecured frames.",
&ieee802154_extend_auth);
/* Register the subdissector list */
register_heur_dissector_list(IEEE802154_PROTOABBREV_WPAN, &ieee802154_heur_subdissector_list);
@ -2661,6 +2759,7 @@ void proto_register_ieee802154(void)
register_dissector("wpan-nonask-phy", dissect_ieee802154_nonask_phy, proto_ieee802154_nonask_phy);
} /* proto_register_ieee802154 */
/*FUNCTION:------------------------------------------------------
* NAME
* proto_reg_handoff_ieee802154
@ -2714,36 +2813,3 @@ void proto_reg_handoff_ieee802154(void)
/* Register dissector handles. */
dissector_add_uint("ethertype", ieee802154_ethertype, ieee802154_handle);
} /* proto_reg_handoff_ieee802154 */
/*FUNCTION:------------------------------------------------------
* NAME
* proto_init_ieee802154
* DESCRIPTION
* Init routine for the IEEE 802.15.4 dissector. Creates hash
* tables for mapping between 16-bit to 64-bit addresses and
* populates them with static address pairs from a UAT
* preference table.
* PARAMETERS
* none
* RETURNS
* void
*---------------------------------------------------------------
*/
static void
proto_init_ieee802154(void)
{
guint i;
/* Destroy hash tables, if they exist. */
if (ieee802154_map.short_table) g_hash_table_destroy(ieee802154_map.short_table);
if (ieee802154_map.long_table) g_hash_table_destroy(ieee802154_map.long_table);
/* Create the hash tables. */
ieee802154_map.short_table = g_hash_table_new(ieee802154_short_addr_hash, ieee802154_short_addr_equal);
ieee802154_map.long_table = g_hash_table_new(ieee802154_long_addr_hash, ieee802154_long_addr_equal);
/* Re-load the hash table from the static address UAT. */
for (i=0; (i<num_static_addrs) && (static_addrs); i++) {
ieee802154_addr_update(&ieee802154_map,(guint16)static_addrs[i].addr16, (guint16)static_addrs[i].pan,
pntoh64(static_addrs[i].eui64), ieee802154_user, IEEE802154_USER_MAPPING);
} /* for */
} /* proto_init_ieee802154 */

View File

@ -193,6 +193,8 @@ typedef struct {
ieee802154_security_level security_level;
ieee802154_key_id_mode key_id_mode;
guint32 frame_counter;
guint8 key_sequence_counter; /* Only for 802.15.4-2003 security suite with encryption */
union {
guint32 addr32;
guint64 addr64;