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 /epan/asn1.c | |
parent | e55fe95c2a44e8889217c3160b5a120d210ced98 (diff) |
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>
Diffstat (limited to 'epan/asn1.c')
-rw-r--r-- | epan/asn1.c | 73 |
1 files changed, 69 insertions, 4 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); } |