diff options
author | Guy Harris <guy@alum.mit.edu> | 2010-02-19 10:24:13 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2010-02-19 10:24:13 +0000 |
commit | 1b59a2446f5360b5dc5875e1ba6ddd5dc2285132 (patch) | |
tree | 9acb0644cc0ed6d7ffee4b11790c842753083260 /epan | |
parent | 4ab14bc71e11916a9af7eb83a13672b79f2ce395 (diff) |
Clean up decryption; have it return various indications for whether it
was able to decrypt and, if it wasn't, why it wasn't, and put that
information into an expert information indication.
svn path=/trunk/; revision=31922
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-ieee802154.c | 176 |
1 files changed, 140 insertions, 36 deletions
diff --git a/epan/dissectors/packet-ieee802154.c b/epan/dissectors/packet-ieee802154.c index 17743076de..e9a3c437ad 100644 --- a/epan/dissectors/packet-ieee802154.c +++ b/epan/dissectors/packet-ieee802154.c @@ -57,12 +57,6 @@ * - ChipCon/Texas Instruments CC24xx style FCS. * - No FCS at all. *------------------------------------------------------------ - * - * No support has been provided for decryption. Maybe a TODO - * item, but this is unlikely as the decryption process requires - * the extended source address (to build the nonce/initial value) - * which will be absent most of the time. - *------------------------------------------------------------ */ /* Include files */ @@ -139,7 +133,19 @@ static void dissect_ieee802154_realign (tvbuff_t *, packet_info *, proto_tr static void dissect_ieee802154_gtsreq (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *); /* Decryption helpers. */ -static tvbuff_t * dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *); +typedef enum { + DECRYPT_PACKET_SUCCEEDED, + DECRYPT_NOT_ENCRYPTED, + DECRYPT_VERSION_UNSUPPORTED, + DECRYPT_PACKET_TOO_SMALL, + DECRYPT_SNAPLEN_TOO_SMALL, + DECRYPT_PACKET_NO_EXT_SRC_ADDR, + DECRYPT_PACKET_NO_KEY, + DECRYPT_PACKET_DECRYPT_FAILED, + DECRYPT_PACKET_MIC_CHECK_FAILED, + DECRYPT_PACKET_NO_PAYLOAD +} ws_decrypt_status; +static tvbuff_t * dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *, ws_decrypt_status *); static void ccm_init_block (gchar * block, gboolean adata, gint M, guint64 addr, guint32 counter, ieee802154_security_level level, gint ctr_val); static gboolean ccm_ctr_encrypt (const gchar *key, const gchar *iv, gchar *mic, gchar *data, gint length); static gboolean ccm_cbc_mac (const gchar * key, const gchar *iv, const gchar *a, gint a_len, const gchar *m, gint m_len, gchar *mic); @@ -610,6 +616,7 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g volatile gboolean fcs_ok = TRUE; const char *saved_proto; ieee802154_packet *packet = ep_alloc(sizeof(ieee802154_packet)); + ws_decrypt_status status; /* Link our packet info structure into the private data field for the * Network-Layer heuristic subdissectors. */ @@ -926,10 +933,52 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g */ /* Encrypted Payload. */ if (packet->security_enable) { - payload_tvb = dissect_ieee802154_decrypt(tvb, offset, pinfo, packet); + payload_tvb = dissect_ieee802154_decrypt(tvb, offset, pinfo, packet, &status); + switch (status) { + + case DECRYPT_PACKET_SUCCEEDED: + /* No problem. */ + break; + + case DECRYPT_NOT_ENCRYPTED: + /* Packet wasn't encrypted */ + break; + + case DECRYPT_VERSION_UNSUPPORTED: + /* We don't support decryption with that version of the protocol */ + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "We don't support decryption with protocol version %u", + packet->version); + break; + + case DECRYPT_PACKET_TOO_SMALL: + /* Packet was too small to include CRC and MIC */ + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Packet was too small to include the CRC and MIC"); + break; + + case DECRYPT_SNAPLEN_TOO_SMALL: + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Snapshot length was too small to include the CRC and MIC"); + break; + + case DECRYPT_PACKET_NO_EXT_SRC_ADDR: + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "No extended source address - can't decrypt"); + break; + + case DECRYPT_PACKET_NO_KEY: + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "No encryption key set - can't decrypt"); + break; + + case DECRYPT_PACKET_DECRYPT_FAILED: + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Decrypt failed"); + break; + + case DECRYPT_PACKET_MIC_CHECK_FAILED: + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "MIC check failed"); + break; + + case DECRYPT_PACKET_NO_PAYLOAD: + break; + } if (!payload_tvb) { - /* Set expert info. */ - expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Encrypted Payload"); /* Display the remaining payload using the data dissector. */ payload_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN); tvb_set_reported_length(payload_tvb, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN); @@ -1628,12 +1677,13 @@ dissect_ieee802154_gtsreq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i * packet_info * pinfo - Packet info structure. * guint offset - Offset where the ciphertext 'c' starts. * ieee802154_packet *packet - IEEE 802.15.4 packet information. + * ws_decrypt_status *status - status of decryption returned through here on failure. * RETURNS * tvbuff_t * - Decrypted payload, or NULL on decryption failure. *--------------------------------------------------------------- */ static tvbuff_t * -dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ieee802154_packet * packet) +dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ieee802154_packet * packet, ws_decrypt_status * status) { tvbuff_t * dec_tvb; gboolean have_mic = FALSE; @@ -1643,24 +1693,12 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie unsigned char rx_mic[16]; guint M; void * text; - gint real_len; - gint reported_len; - - /* Check the version, we only support IEEE 802.15.4-2006 */ - if (packet->version < IEEE802154_VERSION_2006) return NULL; + guint captured_len; + guint reported_len; - /* Compute the length of the MIC from the security level. */ - M = IEEE802154_MIC_LENGTH(packet->security_level); - /* If the last 'M' bytes of the payload exist, then parse the MIC. */ - have_mic = M && tvb_bytes_exist(tvb, tvb_reported_length(tvb)-M-IEEE802154_FCS_LEN, M); - if (have_mic) { - tvb_memcpy(tvb, rx_mic, tvb_reported_length(tvb)-M-IEEE802154_FCS_LEN, M); - } - /* Compute the real and reported length of the payload (since it might be truncated). */ - real_len = tvb_length(tvb) - offset - IEEE802154_FCS_LEN - M; - reported_len = tvb_reported_length(tvb) - offset - IEEE802154_FCS_LEN - M; - if (real_len < 0) return NULL; - if (reported_len < 0) return NULL; + /* Get the captured and on-the-wire length of the payload. */ + captured_len = tvb_length(tvb); + reported_len = tvb_reported_length(tvb); /* * If the payload is not encrypted, then we can get out now. @@ -1673,9 +1711,61 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie * anyone feels strongly about it, you're welcome to modify the code to * implement it. If you do go down that route, don't forget that l(m)==0 * and 'a' includes the payload when security_level < encryption. + * + * XXX - this probably shouldn't include the MIC. */ if (!IEEE802154_IS_ENCRYPTED(packet->security_level)) { - return tvb_new_subset(tvb, offset, real_len, reported_len); + *status = DECRYPT_NOT_ENCRYPTED; + return tvb_new_subset(tvb, offset, captured_len, reported_len); + } + + /* Check the version, we only support IEEE 802.15.4-2006 */ + if (packet->version < IEEE802154_VERSION_2006) { + *status = DECRYPT_VERSION_UNSUPPORTED; + return NULL; + } + + /* Is there at least enough room for the FCS? */ + if (reported_len < IEEE802154_FCS_LEN) { + /* No - the FCS is past the end of the packet */ + *status = DECRYPT_PACKET_TOO_SMALL; + return NULL; + } + if (captured_len < IEEE802154_FCS_LEN) { + /* No - the FCS is past the end of the captured_data */ + *status = DECRYPT_SNAPLEN_TOO_SMALL; + return NULL; + } + reported_len -= IEEE802154_FCS_LEN; + if (captured_len > reported_len) + captured_len = reported_len; + + /* + * Compute the length of the MIC from the security level. + * IEEE802154_MIC_LENGTH() returns a value that's either 0, 4, 8, or 16. + */ + M = IEEE802154_MIC_LENGTH(packet->security_level); + /* + * If 'M' is non-zero, and the last 'M' bytes of the payload exist, + * then parse the MIC. + * + * "The last 'M' bytes of the payload exist" only if the payload + * wasn't cut short by the snapshot length, i.e. only if + * captured_len >= reported_len (captured_len shouldn't be > + * reported_len, but...). + */ + if (M != 0) { + if (reported_len < M) { + *status = DECRYPT_PACKET_TOO_SMALL; + return NULL; /* packet too short for the MIC */ + } + if (captured_len >= reported_len) { + have_mic = TRUE; + tvb_memcpy(tvb, rx_mic, reported_len - M, M); + } + reported_len =- M; + if (captured_len > reported_len) + captured_len = reported_len; } /*===================================================== @@ -1698,6 +1788,7 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie } else { /* TODO: Implement a lookup table or something. */ + *status = DECRYPT_PACKET_NO_EXT_SRC_ADDR; return NULL; } @@ -1707,12 +1798,15 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie * and a variety of key configuration data. However, a single shared key * should be sufficient to get packet encryption off to a start. */ - if (!ieee802154_key_valid) return NULL; + if (!ieee802154_key_valid) { + *status = DECRYPT_PACKET_NO_KEY; + return NULL; + } memcpy(key, ieee802154_key, IEEE802154_CIPHER_SIZE); /* Make a copy of the ciphertext w/o the MIC. */ /* We will decrypt the message in-place and then use this for the new tvb. */ - text = tvb_memdup(tvb, offset, real_len); + text = tvb_memdup(tvb, offset, captured_len); /*===================================================== * CCM* - CTR mode payload encryption @@ -1721,8 +1815,9 @@ 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); /* Perform CTR-mode transformation. */ - if (!ccm_ctr_encrypt(key, tmp, rx_mic, text, real_len)) { + if (!ccm_ctr_encrypt(key, tmp, rx_mic, text, captured_len)) { g_free(text); + *status = DECRYPT_PACKET_DECRYPT_FAILED; return NULL; } @@ -1735,24 +1830,33 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie unsigned char dec_mic[16]; /* 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, real_len); + ccm_init_block(tmp, TRUE, M, srcAddr, packet->frame_counter, packet->security_level, captured_len); /* Compute CBC-MAC authentication tag. */ - if (!ccm_cbc_mac(key, tmp, ep_tvb_memdup(tvb, 0, offset), offset, text, real_len, dec_mic)) { + if (!ccm_cbc_mac(key, tmp, ep_tvb_memdup(tvb, 0, offset), offset, text, captured_len, dec_mic)) { g_free(text); + *status = DECRYPT_PACKET_MIC_CHECK_FAILED; return NULL; } /* Compare the received MIC with the one we generated. */ if (memcmp(rx_mic, dec_mic, M) != 0) { g_free(text); + *status = DECRYPT_PACKET_MIC_CHECK_FAILED; return NULL; } } - /* Done! */ - dec_tvb = tvb_new_real_data(text, real_len, reported_len); + /* Done! Do we actually have any decrypted payload? */ + if (captured_len == 0) { + /* No. */ + *status = DECRYPT_PACKET_NO_PAYLOAD; + return NULL; + } + /* Yes */ + dec_tvb = tvb_new_real_data(text, captured_len, reported_len); tvb_set_child_real_data_tvbuff(tvb, dec_tvb); add_new_data_source(pinfo, dec_tvb, "IEEE 802.15.4 decryption"); + *status = DECRYPT_PACKET_SUCCEEDED; return dec_tvb; } /* dissect_ieee802154_decrypt */ |