diff options
Diffstat (limited to 'epan/dissectors/packet-per.c')
-rw-r--r-- | epan/dissectors/packet-per.c | 368 |
1 files changed, 235 insertions, 133 deletions
diff --git a/epan/dissectors/packet-per.c b/epan/dissectors/packet-per.c index 15f05965d7..5c9da0119b 100644 --- a/epan/dissectors/packet-per.c +++ b/epan/dissectors/packet-per.c @@ -1,5 +1,5 @@ /* -XXX all this offset>>3 and calculations of bytes in the tvb everytime +XXX all this offset>>3 and calculations of bytes in the tvb every time we put something in the tree is just silly. should be replaced with some proper helper routines */ @@ -29,58 +29,59 @@ proper helper routines void proto_register_per(void); -static int proto_per = -1; -static int hf_per_GeneralString_length = -1; -static int hf_per_extension_bit = -1; -static int hf_per_extension_present_bit = -1; -static int hf_per_choice_index = -1; -static int hf_per_choice_extension_index = -1; -static int hf_per_enum_index = -1; -static int hf_per_enum_extension_index = -1; -static int hf_per_num_sequence_extensions = -1; -static int hf_per_small_number_bit = -1; -static int hf_per_optional_field_bit = -1; -static int hf_per_sequence_of_length = -1; -static int hf_per_object_identifier_length = -1; -static int hf_per_open_type_length = -1; -static int hf_per_real_length = -1; -static int hf_per_octet_string_length = -1; -static int hf_per_bit_string_length = -1; -static int hf_per_normally_small_nonnegative_whole_number_length = -1; -static int hf_per_const_int_len = -1; -static int hf_per_direct_reference = -1; /* T_direct_reference */ -static int hf_per_indirect_reference = -1; /* T_indirect_reference */ -static int hf_per_data_value_descriptor = -1; /* T_data_value_descriptor */ -static int hf_per_encoding = -1; /* External_encoding */ -static int hf_per_single_ASN1_type = -1; /* T_single_ASN1_type */ -static int hf_per_octet_aligned = -1; /* T_octet_aligned */ -static int hf_per_arbitrary = -1; /* T_arbitrary */ -static int hf_per_integer_length = -1; /* Show integer length if "show internal per fields" */ -/* static int hf_per_debug_pos = -1; */ -static int hf_per_internal_range = -1; -static int hf_per_internal_num_bits = -1; -static int hf_per_internal_min = -1; -static int hf_per_internal_value = -1; - -static gint ett_per_open_type = -1; -static gint ett_per_containing = -1; -static gint ett_per_sequence_of_item = -1; -static gint ett_per_External = -1; -static gint ett_per_External_encoding = -1; -static gint ett_per_named_bits = -1; - -static expert_field ei_per_size_constraint_value = EI_INIT; -static expert_field ei_per_size_constraint_too_few = EI_INIT; -static expert_field ei_per_size_constraint_too_many = EI_INIT; -static expert_field ei_per_choice_extension_unknown = EI_INIT; -static expert_field ei_per_sequence_extension_unknown = EI_INIT; -static expert_field ei_per_encoding_error = EI_INIT; -static expert_field ei_per_oid_not_implemented = EI_INIT; -static expert_field ei_per_undecoded = EI_INIT; -static expert_field ei_per_field_not_integer = EI_INIT; -static expert_field ei_per_external_type = EI_INIT; -static expert_field ei_per_open_type = EI_INIT; -static expert_field ei_per_open_type_len = EI_INIT; +static int proto_per; +static int hf_per_GeneralString_length; +static int hf_per_extension_bit; +static int hf_per_extension_present_bit; +static int hf_per_choice_index; +static int hf_per_choice_extension_index; +static int hf_per_enum_index; +static int hf_per_enum_extension_index; +static int hf_per_num_sequence_extensions; +static int hf_per_small_number_bit; +static int hf_per_optional_field_bit; +static int hf_per_sequence_of_length; +static int hf_per_object_identifier_length; +static int hf_per_open_type_length; +static int hf_per_real_length; +static int hf_per_octet_string_length; +static int hf_per_bit_string_length; +static int hf_per_normally_small_nonnegative_whole_number_length; +static int hf_per_const_int_len; +static int hf_per_direct_reference; /* T_direct_reference */ +static int hf_per_indirect_reference; /* T_indirect_reference */ +static int hf_per_data_value_descriptor; /* T_data_value_descriptor */ +static int hf_per_encoding; /* External_encoding */ +static int hf_per_single_ASN1_type; /* T_single_ASN1_type */ +static int hf_per_octet_aligned; /* T_octet_aligned */ +static int hf_per_arbitrary; /* T_arbitrary */ +static int hf_per_integer_length; /* Show integer length if "show internal per fields" */ +/* static int hf_per_debug_pos; */ +static int hf_per_internal_range; +static int hf_per_internal_num_bits; +static int hf_per_internal_min; +static int hf_per_internal_value; +static int hf_per_encoding_boiler_plate; + +static gint ett_per_open_type; +static gint ett_per_containing; +static gint ett_per_sequence_of_item; +static gint ett_per_External; +static gint ett_per_External_encoding; +static gint ett_per_named_bits; + +static expert_field ei_per_size_constraint_value; +static expert_field ei_per_size_constraint_too_few; +static expert_field ei_per_size_constraint_too_many; +static expert_field ei_per_choice_extension_unknown; +static expert_field ei_per_sequence_extension_unknown; +static expert_field ei_per_encoding_error; +static expert_field ei_per_oid_not_implemented; +static expert_field ei_per_undecoded; +static expert_field ei_per_field_not_integer; +static expert_field ei_per_external_type; +static expert_field ei_per_open_type; +static expert_field ei_per_open_type_len; static dissector_table_t per_oid_dissector_table = NULL; @@ -109,6 +110,15 @@ static const true_false_string tfs_small_number_bit = { "The number is large, >63" }; +void +add_per_encoded_label(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree) +{ + proto_item* ti; + + ti = proto_tree_add_item(tree, hf_per_encoding_boiler_plate, tvb, 0, -1, ENC_NA); + proto_item_set_generated(ti); + +} #define BYTE_ALIGN_OFFSET(offset) if(offset&0x07){offset=(offset&0xfffffff8)+8;} @@ -126,9 +136,9 @@ static void per_check_value(guint32 value, guint32 min_len, guint32 max_len, asn static void per_check_value64(guint64 value, guint64 min_len, guint64 max_len, asn1_ctx_t *actx, proto_item *item, gboolean is_signed) { if ((is_signed == FALSE) && (value > max_len)) { - expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %" G_GINT64_MODIFIER "u (%" G_GINT64_MODIFIER "u .. %" G_GINT64_MODIFIER "u)", value, min_len, max_len); + expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %" PRIu64 " (%" PRIu64 " .. %" PRIu64 ")", value, min_len, max_len); } else if ((is_signed == TRUE) && ((gint64)value > (gint64)max_len)) { - expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %" G_GINT64_MODIFIER "d (%" G_GINT64_MODIFIER "d .. %" G_GINT64_MODIFIER "d)", (gint64)value, (gint64)min_len, (gint64)max_len); + expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %" PRId64 " (%" PRId64 " .. %" PRId64 ")", (gint64)value, (gint64)min_len, (gint64)max_len); } } @@ -156,23 +166,24 @@ static guint32 dissect_per_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, end_offset, fragmented_length = 0, pdu_length, pdu_offset; - tvbuff_t *val_tvb = NULL, *pdu_tvb = NULL; + tvbuff_t *val_tvb = NULL, *pdu_tvb = NULL, *fragment_tvb = NULL; header_field_info *hfi; proto_tree *subtree = tree; gboolean is_fragmented; int captured_pdu_length; - hfi = (hf_index == -1) ? NULL : proto_registrar_get_nth(hf_index); + hfi = (hf_index <= 0) ? NULL : proto_registrar_get_nth(hf_index); start_offset = offset; do { offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_open_type_length, &type_length, &is_fragmented); if (actx->aligned) BYTE_ALIGN_OFFSET(offset); if (is_fragmented) { + fragment_tvb = tvb_new_octet_aligned(tvb, offset, 8*type_length); if (fragmented_length == 0) { pdu_tvb = tvb_new_composite(); } - tvb_composite_append(pdu_tvb, tvb_new_octet_aligned(tvb, offset, 8*type_length)); + tvb_composite_append(pdu_tvb, fragment_tvb); offset += 8*type_length; fragmented_length += type_length; } @@ -216,8 +227,8 @@ dissect_per_open_type_internal(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, } } if (hfi) { - if (IS_FT_UINT(hfi->type)||IS_FT_INT(hfi->type)) { - if (IS_FT_UINT(hfi->type)) + if (FT_IS_UINT(hfi->type)||FT_IS_INT(hfi->type)) { + if (FT_IS_UINT(hfi->type)) actx->created_item = proto_tree_add_uint(tree, hf_index, val_tvb, 0, pdu_length, pdu_length); else actx->created_item = proto_tree_add_int(tree, hf_index, val_tvb, 0, pdu_length, pdu_length); @@ -319,7 +330,7 @@ dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _ str=(char *)wmem_alloc(wmem_packet_scope(), str_length+1); str_index = 0; - str_length = g_snprintf(str, str_length+1, " "); + str_length = snprintf(str, str_length+1, " "); for(bit=0;bit<((int)(offset&0x07));bit++){ if(bit&&(!(bit%4))){ if (str_index < str_length) str[str_index++] = ' '; @@ -368,7 +379,7 @@ dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _ return offset; } *length *= 0x4000; - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length); if (display_internal_per_fields) proto_item_append_text(pi," %s", str); @@ -380,7 +391,7 @@ dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _ } else if((val&0x80)==0 && num_bits==8){ *length = val; - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length); if (display_internal_per_fields) proto_item_append_text(pi," %s", str); @@ -392,7 +403,7 @@ dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _ } else if (num_bits==16) { *length = val&0x3fff; - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-2, 2, *length); if (display_internal_per_fields) proto_item_append_text(pi," %s", str); @@ -411,7 +422,7 @@ dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _ /* 10.9.3.6 */ if((byte&0x80)==0){ *length=byte; - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length); if (!display_internal_per_fields) proto_item_set_hidden(pi); } @@ -423,7 +434,7 @@ dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _ *length=(byte&0x3f); *length=((*length)<<8)+tvb_get_guint8(tvb, offset>>3); offset+=8; - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-2, 2, *length); if (!display_internal_per_fields) proto_item_set_hidden(pi); } @@ -439,7 +450,7 @@ dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _ } *length *= 0x4000; *is_fragmented = TRUE; - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length); if (!display_internal_per_fields) proto_item_set_hidden(pi); } @@ -476,7 +487,7 @@ DEBUG_ENTRY("dissect_per_normally_small_nonnegative_whole_number"); *length|=1; } } - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset-6)>>3, (offset%8<6)?2:1, *length); if (!display_internal_per_fields) proto_item_set_hidden(pi); } @@ -511,7 +522,7 @@ DEBUG_ENTRY("dissect_per_normally_small_nonnegative_whole_number"); *length = 0; return offset; } - if(hf_index!=-1){ + if(hf_index > 0){ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset-(8*length_determinant))>>3, length_determinant, *length); if (!display_internal_per_fields) proto_item_set_hidden(pi); } @@ -548,19 +559,23 @@ guint32 dissect_per_null(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index) { proto_item *ti_tmp; - ti_tmp = proto_tree_add_item(tree, hf_index, tvb, offset>>3, 1, ENC_BIG_ENDIAN); + ti_tmp = proto_tree_add_item(tree, hf_index, tvb, offset>>3, 0, ENC_BIG_ENDIAN); proto_item_append_text(ti_tmp, ": NULL"); return offset; } /* 19 this function dissects a sequence of */ +// Arbitrary. Allow a sequence of NULLs, but not too many since we might add +// a hierarchy of tree items per NULL +#define PER_SEQUENCE_OF_MAX_NULLS 10 static guint32 dissect_per_sequence_of_helper(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, per_type_fn func, int hf_index, guint32 length) { guint32 i; DEBUG_ENTRY("dissect_per_sequence_of_helper"); + guint32 old_offset = offset; for(i=0;i<length;i++){ guint32 lold_offset=offset; proto_item *litem; @@ -570,6 +585,9 @@ DEBUG_ENTRY("dissect_per_sequence_of_helper"); offset=(*func)(tvb, offset, actx, ltree, hf_index); proto_item_set_len(litem, (offset>>3)!=(lold_offset>>3)?(offset>>3)-(lold_offset>>3):1); + if (i >= PER_SEQUENCE_OF_MAX_NULLS-1 && offset <= old_offset) { + dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too many nulls in sequence"); + } } return offset; @@ -591,7 +609,7 @@ DEBUG_ENTRY("dissect_per_sequence_of"); offset=dissect_per_length_determinant(tvb, offset, actx, parent_tree, hf_per_sequence_of_length, &length, NULL); hfi = proto_registrar_get_nth(hf_index); - if (IS_FT_UINT(hfi->type)) { + if (FT_IS_UINT(hfi->type)) { item = proto_tree_add_uint(parent_tree, hf_index, tvb, old_offset>>3, 0, length); proto_item_append_text(item, (length==1)?" item":" items"); } else { @@ -606,14 +624,15 @@ DEBUG_ENTRY("dissect_per_sequence_of"); return offset; } - /* XXX we don't do >64k length strings yet */ static guint32 -dissect_per_restricted_character_string_sorted(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_, guint16 lb _U_, guint16 ub, const char *alphabet, int alphabet_length, tvbuff_t **value_tvb) +dissect_per_restricted_character_string_sorted(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, guint16 lb, guint16 ub, const char *alphabet, int alphabet_length, tvbuff_t **value_tvb) { guint32 length; gboolean byte_aligned, use_canonical_order; - guint8 *buf; + wmem_strbuf_t *buf; + int str_len; + char *str; guint char_pos; int bits_per_char; guint32 old_offset; @@ -667,6 +686,7 @@ DEBUG_ENTRY("dissect_per_restricted_character_string"); bits_per_char=8; } } + /* 27.4 If the type is extensible for PER encodings (see 9.3.16), * then a bit-field consisting of a single bit shall be added to the field-list. * The single bit shall be set to zero if the value is within the range of the extension root, @@ -698,6 +718,7 @@ DEBUG_ENTRY("dissect_per_restricted_character_string"); /* xx.x */ length=max_len; + old_offset = offset; if (max_len == NO_BOUND) { offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_octet_string_length, &length, NULL); /* the unconstrained strings are always byte aligned (27.6.3)*/ @@ -713,7 +734,9 @@ DEBUG_ENTRY("dissect_per_restricted_character_string"); /* there is no string at all, so don't do any byte alignment */ /* byte_aligned=FALSE; */ /* Advance offset to next 'element' */ - offset = offset + 1; } + if (offset == old_offset) + offset = offset + 1; + } if((byte_aligned)&&(actx->aligned)){ BYTE_ALIGN_OFFSET(offset); @@ -725,7 +748,7 @@ DEBUG_ENTRY("dissect_per_restricted_character_string"); that is one greater than the value assigned to the previous character in the canonical order. These are the values "v" */ use_canonical_order = (ub <= ((guint16)(1<<bits_per_char)-1)) ? FALSE : TRUE; - buf = (guint8 *)wmem_alloc(actx->pinfo->pool, length+1); + buf = wmem_strbuf_new_len(actx->pinfo->pool, NULL, length); old_offset=offset; for(char_pos=0;char_pos<length;char_pos++){ guchar val; @@ -738,25 +761,31 @@ DEBUG_ENTRY("dissect_per_restricted_character_string"); val=(val<<1)|bit; } if(use_canonical_order == FALSE){ - buf[char_pos]=val; + if (val > ub || val < lb) { + wmem_strbuf_append_unichar_repl(buf); + } else { + wmem_strbuf_append_c(buf, val); + } } else { if (val < alphabet_length){ - buf[char_pos]=alphabet[val]; + wmem_strbuf_append_c(buf, alphabet[val]); } else { - buf[char_pos] = '?'; /* XXX - how to mark this? */ + wmem_strbuf_append_unichar_repl(buf); } } } - buf[char_pos]=0; - proto_tree_add_string(tree, hf_index, tvb, (old_offset>>3), (offset>>3)-(old_offset>>3), (char*)buf); + str_len = (int)wmem_strbuf_get_len(buf); + str = wmem_strbuf_finalize(buf); + /* Note that str can contain embedded nulls. Length claims any bytes partially used. */ + proto_tree_add_string(tree, hf_index, tvb, (old_offset>>3), ((offset+7)>>3)-(old_offset>>3), str); if (value_tvb) { - *value_tvb = tvb_new_child_real_data(tvb, buf, length, length); + *value_tvb = tvb_new_child_real_data(tvb, str, str_len, str_len); } return offset; } static const char* -sort_alphabet(char *sorted_alphabet, const char *alphabet, int alphabet_length) +sort_alphabet(char *sorted_alphabet, const char *alphabet, int alphabet_length, guint16 *lb, guint16 *ub) { int i, j; guchar c, c_max, c_min; @@ -764,7 +793,10 @@ sort_alphabet(char *sorted_alphabet, const char *alphabet, int alphabet_length) /* * XXX - presumably all members of alphabet will be in the - * range 0 to 127. + * range 0 to 127. asn2wrs.py doesn't properly handle the + * Quadruple or CharacterStringList types needed for other + * characters, nor representing characters outside ASCII + * in the "cstring" notation (possibly in UTF-8?) */ if (!alphabet_length) return sorted_alphabet; memset(tmp_buf, 0, 256); @@ -778,6 +810,8 @@ sort_alphabet(char *sorted_alphabet, const char *alphabet, int alphabet_length) for (i=c_min,j=0; i<=c_max; i++) { if (tmp_buf[i]) sorted_alphabet[j++] = i; } + *lb = (guint16)c_min; + *ub = (guint16)c_max; return sorted_alphabet; } @@ -786,45 +820,55 @@ dissect_per_restricted_character_string(tvbuff_t *tvb, guint32 offset, asn1_ctx_ { const char *alphabet_ptr; char sorted_alphabet[128]; + guint16 lb = 0; + guint16 ub = 65535; + /* XXX: We don't handle permitted-alphabet characters outside the + * ASCII range if used in BMPString (UCS2) or UniversalString (UCS4) + */ if (alphabet_length > 127) { alphabet_ptr = alphabet; } else { - alphabet_ptr = sort_alphabet(sorted_alphabet, alphabet, alphabet_length); + alphabet_ptr = sort_alphabet(sorted_alphabet, alphabet, alphabet_length, &lb, &ub); } - /* Not a known-multiplier character string: enforce lb and ub to max values */ - return dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, 0, 65535, alphabet_ptr, alphabet_length, value_tvb); + + /* This is for a restricted character string type with a permitted- + * alphabet constraint type. Such constraints are only PER-visible for + * the known-multiplier character string types. + */ + + return dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, lb, ub, alphabet_ptr, alphabet_length, value_tvb); } guint32 -dissect_per_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) +dissect_per_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, tvbuff_t **value_tvb) { offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, - 0, 127, NULL, 128, NULL); + 0, 127, NULL, 128, value_tvb); return offset; } guint32 -dissect_per_NumericString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension) +dissect_per_NumericString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb) { offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, - 32, 57, " 0123456789", 11, NULL); + 32, 57, " 0123456789", 11, value_tvb); return offset; } guint32 -dissect_per_PrintableString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension) +dissect_per_PrintableString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb) { offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, - 32, 122, " '()+,-.*0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 74, NULL); + 32, 122, " '()+,-.*0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 74, value_tvb); return offset; } guint32 -dissect_per_VisibleString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension) +dissect_per_VisibleString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb) { offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, - 32, 126, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 95, NULL); + 32, 126, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 95, value_tvb); return offset; } guint32 @@ -868,10 +912,43 @@ dissect_per_BMPString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tre return offset; } guint32 -dissect_per_UTF8String(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_) +dissect_per_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_) { - offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, - hf_index, min_len, max_len, has_extension, 0, 255, NULL, 256, NULL); + tvbuff_t *val_tvb; + guint32 length; + + /* UTF8String is not a known-multiplier character string (UTF8 + * characters are variable width.) Hence subclause 27.6 applies, + * and "constraints are never PER-visible, and the type can never + * be extensible for PER encoding." + */ + + /* 27.6.3 unconstrained length determinant with "n" in octets */ + offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_octet_string_length, &length, NULL); + + if(length){ + + /* Unnecessary because the length determinant is aligned. */ + if(actx->aligned) { + BYTE_ALIGN_OFFSET(offset); + } + + val_tvb = tvb_new_octet_aligned(tvb, offset, length * 8); + /* Add new data source if the offset was unaligned */ + if ((offset & 7) != 0) { + add_new_data_source(actx->pinfo, val_tvb, "Unaligned UTF8String"); + } + + proto_tree_add_item(tree, hf_index, val_tvb, 0, length, ENC_UTF_8); + } else { + /* tvb_new_octet_aligned doesn't like zero length. + * length zero indicates a present but empty string, so add it + */ + proto_tree_add_item(tree, hf_index, tvb, (offset-1)>>3, length, ENC_UTF_8); + } + + offset+=(length<<3); + return offset; } @@ -933,7 +1010,7 @@ DEBUG_ENTRY("dissect_per_constrained_sequence_of"); call_sohelper: hfi = proto_registrar_get_nth(hf_index); - if (IS_FT_UINT(hfi->type)) { + if (FT_IS_UINT(hfi->type)) { item = proto_tree_add_uint(parent_tree, hf_index, tvb, offset>>3, 0, length); proto_item_append_text(item, (length==1)?" item":" items"); } else { @@ -997,6 +1074,9 @@ dissect_per_any_oid(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree DEBUG_ENTRY("dissect_per_any_oid"); offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_object_identifier_length, &length, NULL); + if(length == 0){ + dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length"); + } if (actx->aligned) BYTE_ALIGN_OFFSET(offset); val_tvb = tvb_new_octet_aligned(tvb, offset, length * 8); /* Add new data source if the offet was unaligned */ @@ -1007,7 +1087,7 @@ dissect_per_any_oid(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree 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, val_tvb, 0, length, ENC_BIG_ENDIAN); - } else if (IS_FT_STRING(hfi->type)) { + } else if (FT_IS_STRING(hfi->type)) { str = oid_encoded2string(wmem_packet_scope(), tvb_get_ptr(val_tvb, 0, length), length); actx->created_item = proto_tree_add_string(tree, hf_index, val_tvb, 0, length, str); } else { @@ -1083,7 +1163,7 @@ DEBUG_ENTRY("dissect_per_boolean"); } else { value=0; } - if(hf_index!=-1){ + if(hf_index > 0){ char bits[10]; bits[0] = mask&0x80?'0'+value:'.'; bits[1] = mask&0x40?'0'+value:'.'; @@ -1131,6 +1211,10 @@ dissect_per_integer(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree length=4; } + if(length == 0){ + dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length"); + } + if (actx->aligned) BYTE_ALIGN_OFFSET(offset); val_tvb = tvb_new_octet_aligned(tvb, offset, length * 8); val=0; @@ -1151,9 +1235,9 @@ dissect_per_integer(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree hfi = proto_registrar_get_nth(hf_index); if (! hfi) THROW(ReportedBoundsError); - if (IS_FT_INT(hfi->type)) { + if (FT_IS_INT(hfi->type)) { it=proto_tree_add_int(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, val); - } else if (IS_FT_UINT(hfi->type)) { + } else if (FT_IS_UINT(hfi->type)) { it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, val); } else { proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_field_not_integer, tvb, (offset>>3)-(length+1), length+1, @@ -1205,9 +1289,9 @@ dissect_per_integer64b(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tr hfi = proto_registrar_get_nth(hf_index); if (! hfi) THROW(ReportedBoundsError); - if (IS_FT_INT(hfi->type)) { + if (FT_IS_INT(hfi->type)) { it=proto_tree_add_int64(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, (gint64)val); - } else if (IS_FT_UINT(hfi->type)) { + } else if (FT_IS_UINT(hfi->type)) { it=proto_tree_add_uint64(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, val); } else { proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_field_not_integer, tvb, (offset>>3)-(length+1), length+1, @@ -1393,13 +1477,13 @@ DEBUG_ENTRY("dissect_per_constrained_integer"); } timeval.secs = val; - if (IS_FT_UINT(hfi->type)) { + if (FT_IS_UINT(hfi->type)) { it = proto_tree_add_uint(tree, hf_index, tvb, val_start, val_length, val); per_check_value(val, min, max, actx, it, FALSE); - } else if (IS_FT_INT(hfi->type)) { + } else if (FT_IS_INT(hfi->type)) { it = proto_tree_add_int(tree, hf_index, tvb, val_start, val_length, val); per_check_value(val, min, max, actx, it, TRUE); - } else if (IS_FT_TIME(hfi->type)) { + } else if (FT_IS_TIME(hfi->type)) { it = proto_tree_add_time(tree, hf_index, tvb, val_start, val_length, &timeval); } else { THROW(ReportedBoundsError); @@ -1539,7 +1623,7 @@ DEBUG_ENTRY("dissect_per_constrained_integer_64b"); if (display_internal_per_fields) { proto_tree_add_uint64(tree, hf_per_internal_range, tvb, val_start, val_length, range); proto_tree_add_uint(tree, hf_per_internal_num_bits, tvb, val_start,val_length, num_bits); - proto_tree_add_uint64_format_value(tree, hf_per_internal_value, tvb, val_start, val_length, val, "%s decimal value: %" G_GINT64_MODIFIER "u", str, val); + proto_tree_add_uint64_format_value(tree, hf_per_internal_value, tvb, val_start, val_length, val, "%s decimal value: %" PRIu64, str, val); } } else if(range==256){ /* 10.5.7.2 */ @@ -1579,7 +1663,7 @@ DEBUG_ENTRY("dissect_per_constrained_integer_64b"); num_bytes++; /* lower bound for length determinant is 1 */ if (display_internal_per_fields){ int_item = proto_tree_add_bits_item(tree, hf_per_const_int_len, tvb, offset,n_bits, ENC_BIG_ENDIAN); - proto_item_append_text(int_item,"+1=%u bytes, Range = (%" G_GINT64_MODIFIER "u)",num_bytes, range); + proto_item_append_text(int_item,"+1=%u bytes, Range = (%" PRIu64 ")",num_bytes, range); } offset = offset+n_bits; /* byte aligned */ @@ -1594,13 +1678,13 @@ DEBUG_ENTRY("dissect_per_constrained_integer_64b"); } - if (IS_FT_UINT(hfi->type)) { + if (FT_IS_UINT(hfi->type)) { it = proto_tree_add_uint64(tree, hf_index, tvb, val_start, val_length, val); per_check_value64(val, min, max, actx, it, FALSE); - } else if (IS_FT_INT(hfi->type)) { + } else if (FT_IS_INT(hfi->type)) { it = proto_tree_add_int64(tree, hf_index, tvb, val_start, val_length, val); per_check_value64(val, min, max, actx, it, TRUE); - } else if (IS_FT_TIME(hfi->type)) { + } else if (FT_IS_TIME(hfi->type)) { timeval.secs = (guint32)val; it = proto_tree_add_time(tree, hf_index, tvb, val_start, val_length, &timeval); } else { @@ -1642,7 +1726,7 @@ dissect_per_enumerated(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tr } val = (value_map && (enum_index<(root_num+ext_num))) ? value_map[enum_index] : enum_index; hfi = proto_registrar_get_nth(hf_index); - if (IS_FT_UINT(hfi->type)) { + if (FT_IS_UINT(hfi->type)) { it = proto_tree_add_uint(tree, hf_index, tvb, start_offset>>3, BLEN(start_offset, offset), val); } else { THROW(ReportedBoundsError); @@ -1661,6 +1745,9 @@ dissect_per_real(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tr double val = 0; offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_real_length, &val_length, NULL); + if(val_length == 0){ + dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length"); + } if (actx->aligned) BYTE_ALIGN_OFFSET(offset); val_tvb = tvb_new_octet_aligned(tvb, offset, val_length * 8); /* Add new data source if the offet was unaligned */ @@ -1683,7 +1770,6 @@ dissect_per_choice(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree * { gboolean /*extension_present,*/ extension_flag; int extension_root_entries; - int extension_addition_entries; guint32 choice_index; int i, idx, cidx; guint32 ext_length = 0; @@ -1707,7 +1793,6 @@ DEBUG_ENTRY("dissect_per_choice"); /* count the number of entries in the extension root and extension addition */ extension_root_entries = 0; - extension_addition_entries = 0; for (i=0; choice[i].p_id; i++) { switch(choice[i].extension){ case ASN1_NO_EXTENSIONS: @@ -1715,7 +1800,6 @@ DEBUG_ENTRY("dissect_per_choice"); extension_root_entries++; break; case ASN1_NOT_EXTENSION_ROOT: - extension_addition_entries++; break; } } @@ -1788,7 +1872,7 @@ index_get_optional_name(const per_sequence_t *sequence, int idx) 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>"; + return (hfi) ? hfi->name : "<unknown field>"; } idx--; } @@ -1805,9 +1889,9 @@ index_get_extension_name(const per_sequence_t *sequence, int idx) for(i=0;sequence[i].p_id;i++){ if(sequence[i].extension==ASN1_NOT_EXTENSION_ROOT){ if (idx == 0) { - if (*sequence[i].p_id == -1) return "extension addition group"; + if (*sequence[i].p_id == -1 || *sequence[i].p_id == 0) return "extension addition group"; hfi = proto_registrar_get_nth(*sequence[i].p_id); - return (hfi) ? hfi->name : "<unknown filed>"; + return (hfi) ? hfi->name : "<unknown field>"; } idx--; } @@ -2133,7 +2217,7 @@ static tvbuff_t *dissect_per_bit_string_display(tvbuff_t *tvb, guint32 offset, a }else { value = tvb_get_bits64(out_tvb, 0, length, ENC_BIG_ENDIAN); } - proto_item_append_text(actx->created_item, ", %s decimal value %" G_GINT64_MODIFIER "u", + proto_item_append_text(actx->created_item, ", %s decimal value %" PRIu64, decode_bits_in_field(actx->pinfo->pool, 0, length, value, ENC_BIG_ENDIAN), value); if (named_bits) { const guint32 named_bits_bytelen = (num_named_bits + 7) / 8; @@ -2176,9 +2260,9 @@ dissect_per_bit_string(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tr guint32 length, fragmented_length = 0; header_field_info *hfi; gboolean is_fragmented = FALSE; - tvbuff_t *fragmented_tvb = NULL, *out_tvb = NULL; + tvbuff_t *fragmented_tvb = NULL, *out_tvb = NULL, *fragment_tvb = NULL; - hfi = (hf_index==-1) ? NULL : proto_registrar_get_nth(hf_index); + hfi = (hf_index <= 0) ? NULL : proto_registrar_get_nth(hf_index); DEBUG_ENTRY("dissect_per_bit_string"); /* 15.8 if the length is 0 bytes there will be no encoding */ @@ -2211,9 +2295,10 @@ DEBUG_ENTRY("dissect_per_bit_string"); BYTE_ALIGN_OFFSET(offset); } if(is_fragmented){ + fragment_tvb = tvb_new_octet_aligned(tvb, offset, length); if(fragmented_length==0) fragmented_tvb = tvb_new_composite(); - tvb_composite_append(fragmented_tvb, tvb_new_octet_aligned(tvb, offset, length)); + tvb_composite_append(fragmented_tvb, fragment_tvb); offset += length; fragmented_length += length; goto next_fragment1; @@ -2290,9 +2375,10 @@ DEBUG_ENTRY("dissect_per_bit_string"); BYTE_ALIGN_OFFSET(offset); } if(is_fragmented){ + fragment_tvb = tvb_new_octet_aligned(tvb, offset, length); if(fragmented_length==0) fragmented_tvb = tvb_new_composite(); - tvb_composite_append(fragmented_tvb, tvb_new_octet_aligned(tvb, offset, length)); + tvb_composite_append(fragmented_tvb, fragment_tvb); offset += length; fragmented_length += length; goto next_fragment2; @@ -2356,12 +2442,12 @@ guint32 dissect_per_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, tvbuff_t **value_tvb) { gint val_start = 0, val_length; - guint32 length = 0, fragmented_length = 0;; + guint32 length = 0, fragmented_length = 0; header_field_info *hfi; gboolean is_fragmented = FALSE; - tvbuff_t *out_tvb = NULL; + tvbuff_t *out_tvb = NULL, *fragment_tvb = NULL; - hfi = (hf_index==-1) ? NULL : proto_registrar_get_nth(hf_index); + hfi = (hf_index <= 0) ? NULL : proto_registrar_get_nth(hf_index); DEBUG_ENTRY("dissect_per_octet_string"); @@ -2424,9 +2510,10 @@ DEBUG_ENTRY("dissect_per_octet_string"); BYTE_ALIGN_OFFSET(offset); } if (is_fragmented) { + fragment_tvb = tvb_new_octet_aligned(tvb, offset, length * 8); if (fragmented_length == 0) out_tvb = tvb_new_composite(); - tvb_composite_append(out_tvb, tvb_new_octet_aligned(tvb, offset, length * 8)); + tvb_composite_append(out_tvb, fragment_tvb); offset += length * 8; fragmented_length += length; goto next_fragment; @@ -2452,11 +2539,11 @@ DEBUG_ENTRY("dissect_per_octet_string"); } if (hfi) { - if (IS_FT_UINT(hfi->type)||IS_FT_INT(hfi->type)) { + if (FT_IS_UINT(hfi->type)||FT_IS_INT(hfi->type)) { /* If the type has been converted to FT_UINT or FT_INT in the .cnf file * display the length of this octet string instead of the octetstring itself */ - if (IS_FT_UINT(hfi->type)) + if (FT_IS_UINT(hfi->type)) actx->created_item = proto_tree_add_uint(tree, hf_index, out_tvb, 0, val_length, val_length); else actx->created_item = proto_tree_add_int(tree, hf_index, out_tvb, 0, val_length, val_length); @@ -2688,11 +2775,15 @@ call_per_oid_callback(const char *oid, tvbuff_t *tvb, packet_info *pinfo, proto_ start_offset = offset; offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_open_type_length, &type_length, NULL); + if(type_length == 0){ + dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length"); + } if (actx->aligned) BYTE_ALIGN_OFFSET(offset); end_offset = offset + type_length; - val_tvb = tvb_new_octet_aligned(tvb, offset, type_length); + /* length in bits */ + val_tvb = tvb_new_octet_aligned(tvb, offset, type_length * 8); if ((offset & 7) != 0) { add_new_data_source(actx->pinfo, val_tvb, "Unaligned OCTET STRING"); } @@ -2712,6 +2803,12 @@ register_per_oid_dissector(const char *oid, dissector_t dissector, int proto, co { dissector_handle_t dissector_handle; + /* FIXME: This would be better as register_dissector() + * so the dissector could be referenced by name + * from the command line, Lua, etc. + * But can we blindly trust name to be a unique dissector name, + * or should we prefix "per." or something? + */ dissector_handle = create_dissector_handle(dissector, proto); dissector_add_string("per.oid", oid, dissector_handle); oid_add_from_string(name, oid); @@ -2830,6 +2927,11 @@ proto_register_per(void) { "Bits", "per.internal.value", FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL }}, + { &hf_per_encoding_boiler_plate, + { "PER encoded protocol, to see PER internal fields set protocol PER preferences", "per.encoding_boiler_plate", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } }, + }; static gint *ett[] = { @@ -2884,7 +2986,7 @@ proto_register_per(void) "Whether the dissector should put the internal PER data in the tree or if it should hide it", &display_internal_per_fields); - per_oid_dissector_table = register_dissector_table("per.oid", "PER OID", proto_per, FT_STRING, BASE_NONE); + per_oid_dissector_table = register_dissector_table("per.oid", "PER OID", proto_per, FT_STRING, STRING_CASE_SENSITIVE); } |