diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-oer.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-oer.c')
-rw-r--r-- | epan/dissectors/packet-oer.c | 1038 |
1 files changed, 1038 insertions, 0 deletions
diff --git a/epan/dissectors/packet-oer.c b/epan/dissectors/packet-oer.c new file mode 100644 index 00000000..152b09fb --- /dev/null +++ b/epan/dissectors/packet-oer.c @@ -0,0 +1,1038 @@ +/* packet-oer.c + * Routines for ASN1 Octet Encoding Rules + * + * Copyright 2018, Anders Broman <anders.broman@ericsson.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + * Ref: ITU-T X.696 (08/2015) https://www.itu.int/itu-t/recommendations/rec.aspx?rec=12487 + * Based on the BER and PER dissectors by Ronnie Sahlberg. + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/oids.h> +#include <epan/asn1.h> +#include <epan/expert.h> +#include <epan/exceptions.h> + +#include "packet-oer.h" + + +#define PNAME "Octet Encoding Rules (ASN.1)" +#define PSNAME "OER" +#define PFNAME "oer" + +void proto_register_oer(void); +void proto_reg_handoff_oer(void); + +/* Initialize the protocol and registered fields */ +static int proto_oer = -1; + +static int hf_oer_optional_field_bit = -1; +static int hf_oer_class = -1; +static int hf_oer_tag = -1; +static int hf_oer_length_determinant = -1; +static int hf_oer_extension_present_bit; +static int hf_oer_open_type_length = -1; + +/* Initialize the subtree pointers */ +static int ett_oer = -1; +static int ett_oer_sequence_of_item = -1; +static int ett_oer_open_type = -1; + +static expert_field ei_oer_not_decoded_yet = EI_INIT; +static expert_field ei_oer_undecoded = EI_INIT; +static expert_field ei_oer_open_type = EI_INIT; + +/* whether the OER helpers should put the internal OER fields into the tree or not. */ +static gboolean display_internal_oer_fields = FALSE; + +/* +#define DEBUG_ENTRY(x) \ +printf("#%u %s tvb:0x%08x\n",actx->pinfo->num,x,(int)tvb); +*/ +#define DEBUG_ENTRY(x) \ + ; + +#define SEQ_MAX_COMPONENTS 128 + +/* +* XXX - if the specified length is less than the remaining length +* of data in the tvbuff, either 1) the specified length is bad and +* we should report that with an expert info or 2) the tvbuff is +* unreassembled and we should make the new tvbuff also be an +* unreassembled tvbuff. +*/ +static tvbuff_t * +oer_tvb_new_subset_length(tvbuff_t *tvb, const gint backing_offset, const gint backing_length) +{ + gint length_remaining; + + length_remaining = tvb_reported_length_remaining(tvb, backing_offset); + return tvb_new_subset_length(tvb, backing_offset, (length_remaining > backing_length) ? backing_length : length_remaining); +} + +static void +dissect_oer_not_decoded_yet(proto_tree* tree, packet_info* pinfo, tvbuff_t *tvb, const char* reason) +{ + proto_tree_add_expert_format(tree, pinfo, &ei_oer_undecoded, tvb, 0, 0, "something unknown here [%s]", reason); + col_append_fstr(pinfo->cinfo, COL_INFO, "[UNKNOWN OER: %s]", reason); + THROW(ReportedBoundsError); +} + +/* Given the ordinal of the option in the sequence, print the name. eg find the 1:th then the 2:nd etc*/ +static const char * +index_get_optional_name(const oer_sequence_t *sequence, int idx) +{ + int i; + header_field_info *hfi; + + for (i = 0; sequence[i].p_id; i++) { + if ((sequence[i].extension != ASN1_NOT_EXTENSION_ROOT) && (sequence[i].optional == ASN1_OPTIONAL)) { + if (idx == 0) { + hfi = proto_registrar_get_nth(*sequence[i].p_id); + return (hfi) ? hfi->name : "<unknown filed>"; + } + idx--; + } + } + return "<unknown type>"; +} + + +static const char * +index_get_field_name(const oer_sequence_t *sequence, int idx) +{ + header_field_info *hfi; + + hfi = proto_registrar_get_nth(*sequence[idx].p_id); + return (hfi) ? hfi->name : "<unknown filed>"; +} + + +/* 8.6 Length determinant */ +static guint32 +dissect_oer_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, guint32 *length) +{ + proto_item *item; + guint8 oct, value_len; + guint32 len; + + if (!length) { + length = &len; + } + + *length = 0; + + /* 8.6.3 There are two forms of length determinant - a short form and a long form... + * 8.6.4 The short form of length determinant consists of a single octet. Bit 8 of this octet shall be set to '0', + * and bits 7 to 1 of this octet shall contain the length (0 to 127) encoded as an unsigned binary integer into 7 bits. + */ + oct = tvb_get_guint8(tvb, offset); + if ((oct & 0x80) == 0) { + /* Short form */ + *length = oct; + if (hf_index != -1) { + item = proto_tree_add_item(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN); + if (!display_internal_oer_fields) proto_item_set_hidden(item); + } + offset++; + + return offset; + } + offset++; + /* Long form */ + /* 8.6.5 The long form of length determinant consists of an initial octet followed by one or more subsequent octets. + * Bit 8 of the initial octet shall be set to 1, and bits 7 to 1 of this octet shall indicate the number of subsequent octets (1 to 127). + * The length shall be encoded as a variable-size unsigned number into the subsequent octets. + */ + value_len = oct & 0x7f; + switch (value_len) { + case 1: + *length = tvb_get_guint8(tvb, offset); + offset++; + break; + case 2: + *length = tvb_get_ntohs(tvb, offset); + offset+=2; + break; + case 3: + *length = tvb_get_ntoh24(tvb, offset); + offset+=3; + break; + case 4: + *length = tvb_get_ntohl(tvb, offset); + offset+=4; + break; + default: + proto_tree_add_expert_format(tree, actx->pinfo, &ei_oer_not_decoded_yet, tvb, offset, 1, + "Length determinant: Long form %u octets not handled", value_len); + return tvb_reported_length(tvb); + } + + return offset; + +} + +/* 9 Encoding of Boolean values */ +guint32 dissect_oer_boolean(tvbuff_t* tvb, guint32 offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, gboolean* bool_val) +{ + guint32 val = 0; + DEBUG_ENTRY("dissect_oer_boolean"); + + actx->created_item = proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, &val); + offset++; + + if (bool_val) { + *bool_val = (gboolean)val; + } + + return offset; +} + +/* 10 Encoding of integer values */ + +guint32 +dissect_oer_constrained_integer(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint64 min, gint64 max, guint32 *value, gboolean has_extension _U_) +{ + DEBUG_ENTRY("dissect_oer_constrained_integer"); + guint32 val = 0; + + if (min >= 0) { + /* 10.2 There are two main cases: + * a) The effective value constraint has a lower bound, and that lower bound is zero or positive. + */ + if (max < 0x100) { + /* One octet */ + proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, &val); + offset++; + } else if (max < 0x10000) { + /* Two octets */ + proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, 2, ENC_BIG_ENDIAN, &val); + offset += 2; + } else if (max == 0xFFFFFFFF) { + /* Four octets */ + proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, 4, ENC_BIG_ENDIAN, &val); + offset += 4; + } else { + /* To large not handlet yet*/ + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer to large value"); + } + + } else { + /* b) The effective value constraint has either a negative lower bound or no lower bound. */ + if ((min >= -128) && (max <= 127)) { + /* 10.4 a a) If the lower bound is greater than or equal to -2^7 (-128) and the upper bound is less than or equal to 2^7-1 (127), + * then every value of the integer type shall be encoded as a fixed-size signed number in a one-octet word; + */ + proto_tree_add_item_ret_int(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, &val); + offset++; + } else if ((min >= -32768) && (max <= 32767)) { + /* if the lower bound is greater than or equal to -2^15 (-32768) and the upper bound is less than or equal to 2^15-1 (32767), + * then every value of the integer type shall be encoded as a fixed-size signed number in a two octet word; + */ + proto_tree_add_item_ret_int(tree, hf_index, tvb, offset, 2, ENC_BIG_ENDIAN, &val); + offset += 2; + } else if ((min >= -2147483648LL) && (max <= 2147483647)) { + /* if the lower bound is greater than or equal to -2^31 (-2147483648) and the upper bound is less than or equal to 2^31-1 (2147483647), + * then every value of the integer type shall be encoded as a fixed-size signed number in a four-octet word + */ + proto_tree_add_item_ret_int(tree, hf_index, tvb, offset, 4, ENC_BIG_ENDIAN, &val); + offset += 4; + } else { + /* To large not handlet yet*/ + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer to large value"); + } + + } + + if (value) { + *value = val; + } + + return offset; + +} + +guint32 +dissect_oer_constrained_integer_64b(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint64 min, guint64 max, guint64 *value, gboolean has_extension _U_) +{ + guint64 val = 0; + + /* XXX Negative numbers ???*/ + if (min >= 0) { + /* 10.2 There are two main cases: + * a) The effective value constraint has a lower bound, and that lower bound is zero or positive. + */ + /* 10.3 */ + if (max < 0x100) { + /* One octet, upper bound is less than or equal to 2 exp 8 - 1 (255) */ + proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, &val); + offset++; + } else if (max < 0x10000) { + /* Two octets, upper bound is less than or equal to 2 exp 16 - 1 (65535), */ + proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 2, ENC_BIG_ENDIAN, &val); + offset += 2; + } else if (max < 0x100000000) { + /* Four octets, upper bound is less than or equal to 2 exp 32 - 1 (4294967295), */ + proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 4, ENC_BIG_ENDIAN, &val); + offset += 4; + } else if (max == G_GUINT64_CONSTANT(18446744073709551615)) { + /* Eight octets, upper bound is less than or equal to 2 exp 64 - 1 (4294967295), */ + proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 8, ENC_BIG_ENDIAN, &val); + offset += 8; + } else { + /* eight-octet, upper bound is less than or equal to 2 exp 64 - 1 (18446744073709551615) */ + /* To large not handlet yet*/ + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer to large value"); + } + + } else { + /* b) The effective value constraint has either a negative lower bound or no lower bound. */ + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer negative value"); + } + + if (value) { + *value = val; + } + + return offset; + +} + +guint32 +dissect_oer_constrained_integer_64b_no_ub(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint64 min, guint64 max _U_, guint64 *value, gboolean has_extension _U_) +{ + guint64 val = 0; + guint32 length; + + /* Negative numbers ???*/ + if (min >= 0) { + + /* (the effective value constraint has either an upper bound greater than 2 exp 64-1 or no upper bound) + * every value of the integer type shall be encoded as a length determinant (see 8.6) + * followed by a variable-size unsigned number + * (occupying at least as many whole octets as are necessary to carry the value). + */ + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + if (length > 0) { + if (length < 5) { + proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, length, ENC_BIG_ENDIAN, &val); + offset += length; + } else { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer NO_BOUND to many octets"); + } + } else { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer unexpected length"); + } + } + if (value) { + *value = val; + } + + return offset; + +} + +guint32 +dissect_oer_integer(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint32 *value) +{ + guint32 val = 0, length; + /* 10.4 e) (the effective value constraint has a lower bound less than -263, no lower bound, + * an upper bound greater than 2 exp 63-1, or no upper bound) every value of the integer type + * shall be encoded as a length determinant (see 8.6) followed by a variable-size signed number + * (occupying at least as many whole octets as are necessary to carry the value). + */ + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + if (length > 0) { + if (length < 5) { + proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, length, ENC_BIG_ENDIAN, &val); + offset += length; + } else { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer NO_BOUND to many octets"); + } + } else { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer unexpected length"); + } + + if (value) { + *value = val; + } + + return offset; + +} +/* 11 Encoding of enumerated values */ +guint32 +dissect_oer_enumerated(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, guint32 root_num _U_, guint32 *value, gboolean has_extension _U_, guint32 ext_num _U_, guint32 *value_map _U_) +{ + int old_offset = offset; + guint32 val; + /* 11.2 There are two forms of enumerated type encoding - a short form and a long form... */ + + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, -1 /*Don't show length value as internal field*/, &val); + actx->created_item = proto_tree_add_uint(tree, hf_index, tvb, old_offset, offset - old_offset, val); + + if (value) { + *value = val; + } + + return offset; + + +} +/* 13 Encoding of bitstring values */ + +/* 13.1 General + * The encoding of a bitstring value depends on the effective size constraint of the bitstring type (see 8.2.8). + * If the lower and upper bounds of the effective size constraint are identical, 13.2 applies, otherwise 13.3 applies. + */ +guint32 +dissect_oer_bit_string(tvbuff_t *tvb, guint32 offset _U_, asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_, int min_len _U_, int max_len _U_, gboolean has_extension _U_, int * const *named_bits _U_, gint num_named_bits _U_, tvbuff_t **value_tvb _U_, int *len _U_) +{ + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "Encoding of bitstring values not handled yet"); + + return tvb_reported_length(tvb); +} + +static guint32 +dissect_oer_bit_string_unconstr(tvbuff_t *tvb, guint32 offset _U_, asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_, int min_len _U_, int max_len _U_, gboolean has_extension _U_, int * const *named_bits _U_, gint num_named_bits _U_, tvbuff_t **value_tvb _U_, guint8 * const values, int values_size, int *len _U_) +{ + int length; + guint8 unused_bit_count = 0; + + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, -1 /*Don't show length value as internal field*/, &length); + if (length > 0) { + unused_bit_count = tvb_get_guint8(tvb, offset); + if (unused_bit_count > 7) { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "too high unused bit count"); + return offset + length; + } + offset += 1; + length -= 1; + } + + *len = length; + if (values) { + memset(values, 0, values_size); + if (length > values_size) { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "too many bitstring elements"); + } + for (int i = 0; i < length; i++) { + guint8 value = tvb_get_guint8(tvb, offset); + if (i + 1 == length) { + /* unused bits of the last octet shall be set to zeros */ + value &= (0xFF << unused_bit_count); + } + if (i < values_size) { + values[i] = value; + } + offset += 1; + } + } + + return offset; +} + +/* 14 Encoding of octet string values */ +guint32 +dissect_oer_octet_string(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension _U_, tvbuff_t **value_tvb) +{ + guint length; + /* 14.1 For an octetstring type in which the lower and upper bounds of the effective size constraint are identical, + * the encoding shall consist of the octets of the octetstring value (zero or more octets), with no length determinant. + */ + if ((min_len != NO_BOUND ) && (min_len == max_len)) { + actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, min_len, ENC_NA); + if (value_tvb) { + *value_tvb = oer_tvb_new_subset_length(tvb, offset, min_len); + } + return offset + min_len; + } + + /* 14.2 For any other octetstring type, the encoding shall consist of a length determinant (see 8.6) + * followed by the octets of the octetstring value (zero or more octets). + */ + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, length, ENC_NA); + if (value_tvb) { + *value_tvb = oer_tvb_new_subset_length(tvb, offset, length); + } + + offset = offset + length; + + return offset; + +} + +/* 15 Encoding of the null value */ +guint32 +dissect_oer_null(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index) +{ + /* The encoding of the null value shall be empty. */ + proto_item *ti_tmp; + + ti_tmp = proto_tree_add_item(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_item_append_text(ti_tmp, ": NULL"); + + return offset; +} + +static const value_string oer_class_vals[] = { + { 0, "universal" }, + { 1, "application" }, + { 2, "context-specific" }, + { 3, "private" }, + { 0, NULL } +}; + +static const value_string oer_extension_present_bit_vals[] = { + { 0, "Not present" }, + { 1, "Present" }, + { 0, NULL } +}; + + + +/* 16 Encoding of sequence values */ +guint32 +dissect_oer_sequence(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const oer_sequence_t *sequence) +{ + guint64 optional_field_flag; + proto_item *item; + proto_tree *tree; + guint32 old_offset = offset; + guint32 i, j, num_opts; + guint32 optional_mask[SEQ_MAX_COMPONENTS >> 5]; + int bit_offset = 0; + guint64 extensions_present = 0; + + DEBUG_ENTRY("dissect_oer_sequence"); + + item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, 0, ENC_BIG_ENDIAN); + tree = proto_item_add_subtree(item, ett_index); + + + /* first check if there should be an extension bit for this SEQUENSE. + * we do this by just checking the first entry + */ + bit_offset = offset << 3; + if (sequence[0].extension == ASN1_NO_EXTENSIONS) { + /*extension_present=0; ?? */ + } else { + /* 16.2.2 The extension bit shall be present (as bit 8 of the first octet of the preamble) + * if, and only if, the sequence type definition contains an extension marker... + */ + actx->created_item = proto_tree_add_bits_ret_val(tree, hf_oer_extension_present_bit, tvb, bit_offset, 1, &extensions_present, ENC_BIG_ENDIAN); + bit_offset++; + if (!display_internal_oer_fields) proto_item_set_hidden(actx->created_item); + } + /* The presence bitmap is encoded as a bit string with a fixed size constraint (see 16.2.3), + * and has one bit for each field of the sequence type that has the keyword OPTIONAL or DEFAULT, + * in specification order. + */ + num_opts = 0; + for (i = 0; sequence[i].p_id; i++) { + if ((sequence[i].extension != ASN1_NOT_EXTENSION_ROOT) && (sequence[i].optional == ASN1_OPTIONAL)) { + num_opts++; + } + } + if (num_opts > SEQ_MAX_COMPONENTS) { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "too many optional/default components"); + } + + memset(optional_mask, 0, sizeof(optional_mask)); + for (i = 0; i<num_opts; i++) { + actx->created_item = proto_tree_add_bits_ret_val(tree, hf_oer_optional_field_bit, tvb, bit_offset, 1, &optional_field_flag, ENC_BIG_ENDIAN); + bit_offset++; + if (tree) { + proto_item_append_text(actx->created_item, " (%s %s present)", + index_get_optional_name(sequence, i), optional_field_flag ? "is" : "is NOT"); + } + if (!display_internal_oer_fields) proto_item_set_hidden(actx->created_item); + if (optional_field_flag) { + optional_mask[i >> 5] |= 0x80000000 >> (i & 0x1f); + } + } + if (num_opts > 0) { + guint8 len = num_opts >> 3; + guint8 remaining_bits = num_opts % 8; + if (remaining_bits) { + len++; + } + offset += len; + } + + /* */ + for (i = 0, j = 0; sequence[i].p_id; i++) { + if ((sequence[i].extension == ASN1_NO_EXTENSIONS) + || (sequence[i].extension == ASN1_EXTENSION_ROOT)) { + if (sequence[i].optional == ASN1_OPTIONAL) { + gboolean is_present; + if (num_opts == 0) { + continue; + } + is_present = (0x80000000 >> (j & 0x1f))&optional_mask[j >> 5]; + num_opts--; + j++; + if (!is_present) { + continue; + } + } + if (sequence[i].func) { + offset = sequence[i].func(tvb, offset, actx, tree, *sequence[i].p_id); + } else { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, index_get_field_name(sequence, i)); + } + } + } + + if (extensions_present) { + /* Parse the Extension Bitmap */ + int ext_bmp_len; + guint8 extension_mask[SEQ_MAX_COMPONENTS >> 3]; + offset = dissect_oer_bit_string_unconstr(tvb, offset, actx, tree, hf_index, NO_BOUND, NO_BOUND, FALSE, NULL, 0, NULL, extension_mask, SEQ_MAX_COMPONENTS >> 3, &ext_bmp_len); + + /* find first extension */ + int seq_pos; + for (seq_pos = 0; sequence[seq_pos].p_id; seq_pos++) { + if (sequence[seq_pos].extension == ASN1_NOT_EXTENSION_ROOT) { + break; + } + } + for (int bitstr_pos = 0; bitstr_pos < ext_bmp_len; bitstr_pos++) { + gint8 octet = extension_mask[bitstr_pos]; + for (int octet_pos = 0; octet_pos < 8; octet_pos++) { + gboolean ext_present = ((octet << octet_pos) & (0x80)) >> 7; + if (ext_present) { + /* If any extensions still known - use functions */ + if (sequence[seq_pos].p_id) { + guint length; + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + if (sequence[seq_pos].func) { + offset = sequence[seq_pos].func(tvb, offset, actx, tree, *sequence[seq_pos].p_id); + } else { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, index_get_field_name(sequence, seq_pos )); + } + } else { + offset = dissect_oer_octet_string(tvb, offset, actx, tree, hf_index, NO_BOUND, NO_BOUND, FALSE, NULL); + } + } + /* if still within known sequence elements - move to next */ + if (sequence[seq_pos].p_id) { + seq_pos++; + } + } + } + + } + + proto_item_set_len(item, offset - old_offset); + actx->created_item = item; + return offset; +} + +/* 17 Encoding of sequence-of values */ + +static guint32 +dissect_oer_sequence_of_helper(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, oer_type_fn func, int hf_index, guint32 length) +{ + guint32 i; + + DEBUG_ENTRY("dissect_oer_sequence_of_helper"); + for (i = 0; i<length; i++) { + guint32 lold_offset = offset; + proto_item *litem; + proto_tree *ltree; + + ltree = proto_tree_add_subtree_format(tree, tvb, offset, 0, ett_oer_sequence_of_item, &litem, "Item %d", i); + + offset = (*func)(tvb, offset, actx, ltree, hf_index); + proto_item_set_len(litem, offset - lold_offset); + } + + return offset; +} + +guint32 +dissect_oer_sequence_of(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const oer_sequence_t *seq) +{ + proto_item *item; + proto_tree *tree; + guint32 old_offset = offset; + guint32 occ_len, occurrence; + header_field_info *hfi; + + DEBUG_ENTRY("dissect_oer_sequence_of"); + + /* 17.1 The encoding of a sequence-of value shall consist of a quantity field...*/ + + /* 17.2 The quantity field shall be a non-negative integer value indicating the number of occurrences. + * This number shall be encoded as a length determinant (see 8.6) followed by a variable-size unsigned number + * (occupying at least as many whole octets as are necessary to carry the value). + */ + offset = dissect_oer_length_determinant(tvb, offset, actx, parent_tree, hf_oer_length_determinant, &occ_len); + + switch (occ_len) { + case 1: + occurrence = tvb_get_guint8(tvb, offset); + break; + case 2: + occurrence = tvb_get_ntohs(tvb, offset); + break; + case 3: + occurrence = tvb_get_ntoh24(tvb, offset); + break; + case 4: + occurrence = tvb_get_ntohl(tvb, offset); + break; + default: + proto_tree_add_expert_format(parent_tree, actx->pinfo, &ei_oer_not_decoded_yet, tvb, offset, 1, + "sequence_of Occurrence %u octets not handled", occ_len); + return tvb_reported_length(tvb); + } + + offset = offset + occ_len; + hfi = proto_registrar_get_nth(hf_index); + if (FT_IS_UINT(hfi->type)) { + item = proto_tree_add_uint(parent_tree, hf_index, tvb, old_offset, occ_len, occurrence); + proto_item_append_text(item, (occurrence == 1) ? " item" : " items"); + } else { + item = proto_tree_add_item(parent_tree, hf_index, tvb, old_offset, 0, ENC_BIG_ENDIAN); + } + tree = proto_item_add_subtree(item, ett_index); + + offset = dissect_oer_sequence_of_helper(tvb, offset, actx, tree, seq->func, *seq->p_id, occurrence); + + + proto_item_set_len(item, offset - old_offset); + return offset; + +} + +/* As we are using the per ASN1 generator define this "dummy" function */ +guint32 +dissect_oer_constrained_sequence_of(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const oer_sequence_t *seq, int min_len _U_, int max_len _U_ , gboolean has_extension _U_) +{ + return dissect_oer_sequence_of(tvb, offset, actx, parent_tree, hf_index, ett_index, seq); + +} +/* 20 Encoding of choice values */ +guint32 +dissect_oer_choice(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint ett_index, const oer_choice_t *choice, gint *value) +{ + proto_tree *choice_tree; + proto_item *item, *choice_item; + int bit_offset = offset << 3; + guint64 oer_class; + guint8 tag, oct; + int old_offset = offset; + + /* 20.1 The encoding of a value of a choice type shall consist of the encoding of the outermost tag of the type of the chosen alternative + * as specified in 8.7, followed by the encoding of the value of the chosen alternative. + */ + + /* 8.7.2.1 Bits 8 and 7 of the first octet shall denote the tag class */ + item = proto_tree_add_bits_ret_val(tree, hf_oer_class, tvb, bit_offset, 2, &oer_class, ENC_BIG_ENDIAN); + if (!display_internal_oer_fields) proto_item_set_hidden(item); + bit_offset += 2; + + tag = tvb_get_bits8(tvb, bit_offset, 6); + offset++; + /* 8.7.2.3 If the tag number is greater or equal to 63, Bits 6 to 1 of the initial octet shall be set to '111111'B.*/ + if (tag == 0x3f) { + /* The tag number shall be encoded into bits 7 to 1 of each subsequent octet (seven bits in each octet), + * with bit 1 of the final subsequent octet containing the least significant bit of the tag number ("big-endian" encoding). + */ + oct = tvb_get_guint8(tvb, offset); + if ((oct & 0x80) == 0x80) { + dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "Choice, Tag value > 0x7f not implemented yet"); + } else { + /* Bits 7 to 1 of the first subsequent octet shall not be all set to 0.*/ + tag = oct; + item = proto_tree_add_uint(tree, hf_oer_tag, tvb, offset, 1, tag); + if (!display_internal_oer_fields) proto_item_set_hidden(item); + } + } else { + /* Tag value in first octet */ + item = proto_tree_add_bits_item(tree, hf_oer_tag, tvb, bit_offset, 6, ENC_BIG_ENDIAN); + if (!display_internal_oer_fields) proto_item_set_hidden(item); + } + + /* 20.2 If the choice type contains an extension marker in the "AlternativeTypeLists" and the chosen alternative + * is one of the extension additions, then the value of the chosen alternative shall be encoded as if it were contained + * in an open type (see clause 30), otherwise it shall be encoded normally. + */ + if (value) { + (*value) = -1; + } + + /* XXX Extension handling is not implemented */ + while (choice->func) { + if (choice->value == tag) { + choice_item = proto_tree_add_uint(tree, hf_index, tvb, old_offset, 0, choice->value); + choice_tree = proto_item_add_subtree(choice_item, ett_index); + /* For known extensions parse length prefix */ + if (choice->extension == ASN1_NOT_EXTENSION_ROOT) { + guint length; + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + } + offset = choice->func(tvb, offset, actx, choice_tree, *choice->p_id); + proto_item_set_len(choice_item, offset - old_offset); + if (value) { + (*value) = tag; + } + return offset; + } + choice++; + } + /* None of the known choice options matched, parse the contents as an extension */ + // XXX : should check if the extensions are present in the CHOICE defintion + offset = dissect_oer_octet_string(tvb, offset, actx, tree, hf_index, NO_BOUND, NO_BOUND, FALSE, NULL); + + return offset; +} + +/* 21 Encoding of object identifier values + * The encoding of an object identifier value shall consist of a length determinant (see 8.6) followed by a series of octets, + * which are the contents octets of BER encoding of the object identifier value (see Rec. ITU-T X.690 | ISO/IEC 8825-1,8.19). + */ +static guint32 +dissect_oer_any_oid(tvbuff_t* tvb, guint32 offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, tvbuff_t** value_tvb, + gboolean is_absolute) +{ + guint length; + const char* str; + header_field_info* hfi; + + DEBUG_ENTRY("dissect_oer_any_oid"); + + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + + actx->created_item = NULL; + hfi = proto_registrar_get_nth(hf_index); + if ((is_absolute && hfi->type == FT_OID) || (!is_absolute && hfi->type == FT_REL_OID)) { + actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, length, ENC_BIG_ENDIAN); + } + else if (FT_IS_STRING(hfi->type)) { + str = oid_encoded2string(actx->pinfo->pool, tvb_get_ptr(tvb, offset, length), length); + actx->created_item = proto_tree_add_string(tree, hf_index, tvb, offset, length, str); + if (actx->created_item) { + /* see if we know the name of this oid */ + str = oid_resolved_from_encoded(actx->pinfo->pool, tvb_get_ptr(tvb, offset, length), length); + if (str) { + proto_item_append_text(actx->created_item, " (%s)", str); + } + } + } + else { + DISSECTOR_ASSERT_NOT_REACHED(); + } + + if (value_tvb) + *value_tvb = tvb_new_subset_length(tvb, offset, length); + + return offset; +} + +guint32 +dissect_oer_object_identifier(tvbuff_t* tvb, guint32 offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, tvbuff_t** value_tvb) +{ + return dissect_oer_any_oid(tvb, offset, actx, tree, hf_index, value_tvb, TRUE); +} + +/* 27 Encoding of values of the restricted character string types + * 27.1 The encoding of a restricted character string type depends on whether the type is a known-multiplier character + * string type or not. The following types are known-multiplier character string types: + * IA5String, VisibleString, ISO646String, PrintableString, NumericString, BMPString, and UniversalString. + */ + + +guint32 +dissect_oer_IA5String(tvbuff_t* tvb, guint32 offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, int min_len, int max_len, gboolean has_extension _U_) +{ + guint32 length = 0; + + /* 27.2 For a known-multiplier character string type in which the lower and upper bounds of the effective size constraint + * are identical, the encoding shall consist of the series of octets specified in 27.4, with no length determinant. + */ + if ((min_len == max_len) && (min_len != NO_BOUND )){ + length = min_len; + } + else { + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + } + actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, length, ENC_ASCII | ENC_NA); + + return offset + length; + +} + +guint32 +dissect_oer_UTF8String(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len _U_, int max_len _U_, gboolean has_extension _U_) +{ + guint32 length = 0; + /* 27.3 For every other character string type, the encoding shall consist of a length determinant + * (see 8.6) followed by the series of octets specified in 27.4. + */ + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); + actx->created_item = proto_tree_add_item( tree, hf_index, tvb, offset, length, ENC_UTF_8 | ENC_NA); + + return offset + length; + +} + +/* 30 Encoding of open type values + *NOTE – An open type is an ASN.1 type that can take any abstract value of any ASN.1 type. Each value of an open type consists + * of: + * a) a contained type; and + * b) a value of the contained type. + * The encoding of an open type value shall consist of a length determinant (see 8.6) followed by a series of octets, which + * are the encoding of the value of the contained type. + */ + +static guint32 +dissect_oer_open_type_internal(tvbuff_t* tvb, guint32 offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, void* type_cb, asn1_cb_variant variant) +{ + int type_length, start_offset; + tvbuff_t* val_tvb = NULL; + proto_tree* subtree = tree; + + start_offset = offset; + + + offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_open_type_length, &type_length); + val_tvb = tvb_new_subset_length(tvb, offset, type_length); + + actx->created_item = proto_tree_add_item(tree, hf_index, val_tvb, 0, type_length, ENC_BIG_ENDIAN); + subtree = proto_item_add_subtree(actx->created_item, ett_oer_open_type); + + if (variant == CB_NEW_DISSECTOR) { + add_new_data_source(actx->pinfo, val_tvb, "OCTET STRING"); + } + + if (type_cb) { + switch (variant) { + case CB_ASN1_ENC: + ((oer_type_fn)type_cb)(val_tvb, 0, actx, tree, hf_index); + break; + case CB_NEW_DISSECTOR: + /* Pas actx->private_data as "data" to the called function */ + ((dissector_t)type_cb)(val_tvb, actx->pinfo, subtree, actx->private_data); + break; + case CB_DISSECTOR_HANDLE: + break; + } + } + else { + actx->created_item = proto_tree_add_expert(tree, actx->pinfo, &ei_oer_open_type, tvb, start_offset, offset - start_offset); + } + + return offset; +} +guint32 +dissect_oer_open_type(tvbuff_t* tvb, guint32 offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, oer_type_fn type_cb) +{ + return dissect_oer_open_type_internal(tvb, offset, actx, tree, hf_index, (void*)type_cb, CB_ASN1_ENC); +} + +/*--- proto_register_oer ----------------------------------------------*/ +void proto_register_oer(void) { + + /* List of fields */ + static hf_register_info hf[] = { + { &hf_oer_optional_field_bit, + { "Optional Field Bit", "oer.optional_field_bit", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_oer_class, + { "Class", "oer.class", + FT_UINT8, BASE_DEC, VALS(oer_class_vals), 0x0, + NULL, HFILL } + }, + { &hf_oer_tag, + { "Tag", "oer.tag", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_oer_length_determinant, + { "length_determinant", "oer.length_determinant", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_oer_extension_present_bit, + { "Extension Present Bit", "oer.extension_present_bit", + FT_UINT8, BASE_DEC, VALS(oer_extension_present_bit_vals), 0x00, + NULL, HFILL } }, + { &hf_oer_open_type_length, + { "Open Type Length", "oer.open_type_length", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + }; + + /* List of subtrees hf_oer_extension*/ + static gint *ett[] = { + &ett_oer, + &ett_oer_sequence_of_item, + &ett_oer_open_type, + }; + + module_t *oer_module; + expert_module_t* expert_oer; + + /* Register protocol */ + proto_oer = proto_register_protocol(PNAME, PSNAME, PFNAME); + + /* Register fields and subtrees */ + proto_register_field_array(proto_oer, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + static ei_register_info ei[] = { + { &ei_oer_not_decoded_yet, + { "oer.not_decoded_yet", PI_UNDECODED, PI_WARN, "Not decoded yet", EXPFILL }}, + { &ei_oer_undecoded, + { "oer.error.undecoded", PI_UNDECODED, PI_WARN, "OER: Something unknown here", EXPFILL } }, + { &ei_oer_open_type, + { "oer.open_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown Open Type", EXPFILL }}, + }; + + expert_oer = expert_register_protocol(proto_oer); + expert_register_field_array(expert_oer, ei, array_length(ei)); + + oer_module = prefs_register_protocol(proto_oer, NULL); + prefs_register_bool_preference(oer_module, "display_internal_oer_fields", + "Display the internal OER fields in the tree", + "Whether the dissector should put the internal OER data in the tree or if it should hide it", + &display_internal_oer_fields); + + + proto_set_cant_toggle(proto_oer); + +} + + + /*--- proto_reg_handoff_oer -------------------------------------------*/ +void proto_reg_handoff_oer(void) { + +} + +/* +* Editor modelines - https://www.wireshark.org/tools/modelines.html +* +* Local variables: +* c-basic-offset: 4 +* tab-width: 8 +* indent-tabs-mode: nil +* End: +* +* vi: set shiftwidth=4 tabstop=8 expandtab: +* :indentSize=4:tabSize=8:noTabs=true: +*/ |