diff options
author | Maarten Bezemer <maarten.bezemer@gmail.com> | 2014-11-28 16:53:04 +0100 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2014-12-03 09:02:05 +0000 |
commit | 08c0247b78116dcfdba342222810697482108d3a (patch) | |
tree | 89ccc308a2c4fa3c2304c0b4970e6288f25d1051 | |
parent | e55fe95c2a44e8889217c3160b5a120d210ced98 (diff) | |
download | wireshark-08c0247b78116dcfdba342222810697482108d3a.tar.gz |
Support dissecting REAL (BER) data values
Both exponent and 'integer N' values are limited:
* max exponent is 3 octets/24-bits
* max integer N is 8 octets/64-bit
Tested with zero value/length, integers, doubles, positive and negative numbers all using the Basic Encoding Rules (BER)
Change-Id: If92e1b3e209c42909b8cb76e6f50b8e6cd1da0da
Reviewed-on: https://code.wireshark.org/review/5527
Reviewed-by: Michael Mann <mmann78@netscape.net>
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r-- | epan/asn1.c | 73 | ||||
-rw-r--r-- | epan/asn1.h | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-ber.c | 51 | ||||
-rw-r--r-- | epan/dissectors/packet-ber.h | 2 |
4 files changed, 109 insertions, 19 deletions
diff --git a/epan/asn1.c b/epan/asn1.c index 1ce1bdcb47..b878c719b8 100644 --- a/epan/asn1.c +++ b/epan/asn1.c @@ -196,24 +196,89 @@ rose_ctx_t *get_rose_ctx(void *ptr) { return rctx; } -double asn1_get_real(const guint8 *real_ptr, gint real_len) { +/** Only tested for BER */ +double asn1_get_real(const guint8 *real_ptr, gint len) { guint8 octet; const guint8 *p; guint8 *buf; double val = 0; - if (real_len < 1) return val; + /* 8.5.2 If the real value is the value zero, + * there shall be no contents octets in the encoding. + */ + if (len < 1) return val; + octet = real_ptr[0]; p = real_ptr + 1; - real_len -= 1; + len -= 1; if (octet & 0x80) { /* binary encoding */ + int i; + gboolean Eneg; + gint8 S; /* Sign */ + guint8 B; /* Base */ + guint8 F; /* scaling Factor */ + gint32 E = 0; /* Exponent (supported max 3 octets/24 bit) */ + guint64 N = 0; /* N (supported max 8 octets/64 bit) */ + + guint8 lenE, lenN; + + if(octet & 0x40) S = -1; else S = 1; + switch(octet & 0x30) { + case 0x00: B = 2; break; + case 0x10: B = 8; break; + case 0x20: B = 16; break; + case 0x30: /* Reserved */ + default: + /* TODO Add some warning in tree about reserved value for Base */ + return 0; + } + F = (octet & 0x0c) >> 2; + + /* 8.5.6.4 Exponent length */ + lenE = (octet & 0x3) + 1; + if(lenE == 4) + { + /* we can't handle exponents > 24 bits */ + /* TODO Next octet(s) define length of exponent */ + DISSECTOR_ASSERT_NOT_REACHED(); + } + + Eneg = (*p) & 0x80 ? TRUE : FALSE; + for (i = 0; i < lenE; i++) { + if(Eneg) { + /* 2's complement: inverse bits */ + E = (E<<8) | ((guint8) ~(*p)); + } else { + E = (E<<8) | *p; + } + p++; + } + if(Eneg) { + /* 2's complement: ... and add 1 (and make negative of course) */ + E = -(E + 1); + } + + lenN = len - lenE; + if(lenN > 8) + { + /* we can't handle integers > 64 bits */ + DISSECTOR_ASSERT_NOT_REACHED(); + } + for (i=0; i<lenN; i++) { + N = (N<<8) | *p; + p++; + } + val = (double) S * N * pow(2, F) * pow(B, E); +#ifdef DEBUG + printf("S = %d, N = %lu, F = %u, B = %u, E = %d -> %f\n", S, N, F, B, E, Eneg, val); +#endif } else if (octet & 0x40) { /* SpecialRealValue */ switch (octet & 0x3F) { case 0x00: val = HUGE_VAL; break; case 0x01: val = -HUGE_VAL; break; } } else { /* decimal encoding */ - buf = ep_strndup(p, real_len); + buf = ep_strndup(p, len); val = atof(buf); } diff --git a/epan/asn1.h b/epan/asn1.h index bb07a9d6eb..919b3076b1 100644 --- a/epan/asn1.h +++ b/epan/asn1.h @@ -199,7 +199,7 @@ WS_DLL_PUBLIC void rose_ctx_clean_data(rose_ctx_t *rctx); WS_DLL_PUBLIC asn1_ctx_t *get_asn1_ctx(void *ptr); WS_DLL_PUBLIC rose_ctx_t *get_rose_ctx(void *ptr); -extern double asn1_get_real(const guint8 *real_ptr, gint real_len); +extern double asn1_get_real(const guint8 *real_ptr, gint len); /* flags */ #define ASN1_EXT_ROOT 0x01 diff --git a/epan/dissectors/packet-ber.c b/epan/dissectors/packet-ber.c index b6cbf96e27..be99417381 100644 --- a/epan/dissectors/packet-ber.c +++ b/epan/dissectors/packet-ber.c @@ -118,6 +118,7 @@ static gint hf_ber_unknown_UTCTime = -1; static gint hf_ber_unknown_UTF8String = -1; static gint hf_ber_unknown_GeneralizedTime = -1; static gint hf_ber_unknown_INTEGER = -1; +static gint hf_ber_unknown_REAL = -1; static gint hf_ber_unknown_BITSTRING = -1; static gint hf_ber_unknown_ENUMERATED = -1; static gint hf_ber_error = -1; @@ -902,6 +903,9 @@ try_dissect_unknown_ber(packet_info *pinfo, tvbuff_t *tvb, volatile int offset, case BER_UNI_TAG_INTEGER: offset = dissect_ber_integer(FALSE, &asn1_ctx, tree, tvb, start_offset, hf_ber_unknown_INTEGER, NULL); break; + case BER_UNI_TAG_REAL: + offset = dissect_ber_real(FALSE, &asn1_ctx, tree, tvb, start_offset, hf_ber_unknown_REAL, NULL); + break; case BER_UNI_TAG_BITSTRING: offset = dissect_ber_bitstring(FALSE, &asn1_ctx, tree, tvb, start_offset, NULL, hf_ber_unknown_BITSTRING, -1, NULL); break; @@ -2065,35 +2069,53 @@ dissect_ber_boolean(gboolean implicit_tag, asn1_ctx_t *actx, proto_tree *tree, t /* 8.5 Encoding of a real value */ -/* NOT Tested*/ +/* Somewhat tested */ int dissect_ber_real(gboolean implicit_tag, asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id _U_, double *value) { gint8 ber_class; gboolean pc; gint32 tag; - guint32 val_length = 0, end_offset; + guint32 val_length = 0, len_remain, end_offset; double val = 0; + proto_item *cause; if (!implicit_tag) { offset = dissect_ber_identifier(actx->pinfo, tree, tvb, offset, &ber_class, &pc, &tag); offset = dissect_ber_length(actx->pinfo, tree, tvb, offset, &val_length, NULL); + + end_offset = offset + val_length; } else { - /* 8.5.1 The encoding of a real value shall be primitive. */ - DISSECTOR_ASSERT_NOT_REACHED(); + /* implicit tag so get from last tag/length */ + get_last_ber_identifier(&ber_class, &pc, &tag); + get_last_ber_length(&val_length, NULL); + + end_offset = offset + val_length; + + /* Check is buffer has (at least) the expected length */ + len_remain = (guint32)tvb_reported_length_remaining(tvb, offset); + if (len_remain < val_length) { + /* error - this item runs past the end of the item containing it */ + cause = proto_tree_add_string_format_value( + tree, hf_ber_error, tvb, offset, val_length, "illegal_length", + "length:%u longer than tvb_reported_length_remaining:%d", + val_length, + len_remain); + expert_add_info(actx->pinfo, cause, &ei_ber_error_length); + return end_offset; + } } - /* 8.5.2 If the real value is the value zero, - * there shall be no contents octets in the encoding. - */ - if (val_length == 0) { - if (value) - *value = 0; - return offset; + /* 8.5.1 The encoding of a real value shall be primitive. */ + if(pc) { + /* Constructed (not primitive) */ + cause = proto_tree_add_string_format_value( + tree, hf_ber_error, tvb, offset - 2, 1, "wrong_tag", + "REAL class must be encoded as primitive"); + expert_add_info(actx->pinfo, cause, &ei_ber_error_length); } - end_offset = offset + val_length; val = asn1_get_real(tvb_get_ptr(tvb, offset, val_length), val_length); - actx->created_item = proto_tree_add_double(tree, hf_id, tvb, offset, val_length, val); + actx->created_item = proto_tree_add_double(tree, hf_id, tvb, end_offset - val_length, val_length, val); if (value) *value = val; @@ -4302,6 +4324,9 @@ proto_register_ber(void) { &hf_ber_unknown_INTEGER, { "INTEGER", "ber.unknown.INTEGER", FT_INT64, BASE_DEC, NULL, 0, "This is an unknown INTEGER", HFILL }}, + { &hf_ber_unknown_REAL, { + "REAL", "ber.unknown.REAL", FT_DOUBLE, BASE_NONE, + NULL, 0, "This is an unknown REAL", HFILL }}, { &hf_ber_unknown_BITSTRING, { "BITSTRING", "ber.unknown.BITSTRING", FT_BYTES, BASE_NONE, NULL, 0, "This is an unknown BITSTRING", HFILL }}, diff --git a/epan/dissectors/packet-ber.h b/epan/dissectors/packet-ber.h index 707109c27b..c1a44991a5 100644 --- a/epan/dissectors/packet-ber.h +++ b/epan/dissectors/packet-ber.h @@ -118,7 +118,7 @@ extern int dissect_ber_constrained_integer(gboolean implicit_tag, asn1_ctx_t *ac WS_DLL_PUBLIC int dissect_ber_null(gboolean implicit_tag, asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id); WS_DLL_PUBLIC int dissect_ber_boolean(gboolean implicit_tag, asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, gboolean *value); -extern int dissect_ber_real(gboolean implicit_tag, asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, double *value); +WS_DLL_PUBLIC int dissect_ber_real(gboolean implicit_tag, asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, double *value); extern int dissect_ber_external_type(gboolean implicit_tag, proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx, gint hf_id, ber_callback func); WS_DLL_PUBLIC int dissect_ber_EmbeddedPDV_Type(gboolean implicit_tag, proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx, gint hf_id, ber_callback func); |