summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaarten Bezemer <maarten.bezemer@gmail.com>2014-11-28 16:53:04 +0100
committerAnders Broman <a.broman58@gmail.com>2014-12-03 09:02:05 +0000
commit08c0247b78116dcfdba342222810697482108d3a (patch)
tree89ccc308a2c4fa3c2304c0b4970e6288f25d1051
parente55fe95c2a44e8889217c3160b5a120d210ced98 (diff)
downloadwireshark-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.c73
-rw-r--r--epan/asn1.h2
-rw-r--r--epan/dissectors/packet-ber.c51
-rw-r--r--epan/dissectors/packet-ber.h2
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);