aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2017-03-06 14:28:31 +0100
committerBjörn Gustavsson <[email protected]>2017-03-14 09:47:40 +0100
commit3334c0c7b831ecf47738c713fd764eef891a298a (patch)
treebae651bf04cb7a5dead1a87bc8b6f896c4a23705
parent7cb3d41d40dbe6d72c8d3f5724b62da088dbf189 (diff)
downloadotp-3334c0c7b831ecf47738c713fd764eef891a298a.tar.gz
otp-3334c0c7b831ecf47738c713fd764eef891a298a.tar.bz2
otp-3334c0c7b831ecf47738c713fd764eef891a298a.zip
asn1_erl_nif.c: Correct handling of tags >= 16384
Tags number above 16383 were not decoded correctly in ber_decode_tag(). We could fix the problem, but there does not seem to be any need. First, the only way that high tag numbers can be created is with manual tagging; after 1994 manual tagging is no longer recommended. Second, the ASN.1 playground (http://asn1-playground.oss.com) only supports tags up to 16383 (the same is presumably true for OSS Nokalva's other tools). Therefore, clean up the existing code and make it an explicit 'invalid_tag' error when tags above 13383 are encountered (instead of an implicit 'wrong_tag' error).
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c38
-rw-r--r--lib/asn1/test/asn1_SUITE.erl1
-rw-r--r--lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn117
3 files changed, 39 insertions, 17 deletions
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
index b29c9a7ed3..7b7e11b02d 100644
--- a/lib/asn1/c_src/asn1_erl_nif.c
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -901,31 +901,35 @@ static int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_b
/* then get the tag number */
if ((tmp_tag = (int) INVMASK(in_buf[*ib_index],ASN1_CLASSFORM)) < 31) {
- *tag = enif_make_uint(env, tag_no + tmp_tag);
+ *tag = enif_make_uint(env, tag_no | tmp_tag);
(*ib_index)++;
} else {
- int n = 0; /* n is used to check that the 64K limit is not
- exceeded*/
-
/* should check that at least three bytes are left in
in-buffer,at least two tag byte and at least one length byte */
if ((*ib_index + 3) > in_buf_len)
return ASN1_VALUE_ERROR;
(*ib_index)++;
- /* The tag is in the following bytes in in_buf as
- 1ttttttt 1ttttttt ... 0ttttttt, where the t-bits
- is the tag number*/
- /* In practice is the tag size limited to 64K, i.e. 16 bits. If
- the tag is greater then 64K return an error */
- while (((tmp_tag = (int) in_buf[*ib_index]) >= 128) && n < 2) {
- /* m.s.b. = 1 */
- tag_no = tag_no + (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
+ /*
+ * The tag is in the following bytes in in_buf as:
+ *
+ * 1ttttttt 0ttttttt
+ *
+ * or
+ *
+ * 0ttttttt
+ *
+ * where the t-bits is the tag number. If the tag does not
+ * fit in two tag bytes (16K), return an error.
+ */
+ if ((tmp_tag = (int) in_buf[*ib_index]) >= 128) {
+ tag_no = tag_no | (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
(*ib_index)++;
- n++;
- };
- if ((n == 2) && in_buf[*ib_index] > 3)
- return ASN1_TAG_ERROR; /* tag number > 64K */
- tag_no = tag_no + in_buf[*ib_index];
+ }
+ tmp_tag = (int) in_buf[*ib_index];
+ if (tmp_tag >= 128) {
+ return ASN1_TAG_ERROR; /* tag number > 16K */
+ }
+ tag_no = tag_no | tmp_tag;
(*ib_index)++;
*tag = enif_make_uint(env, tag_no);
}
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 580c919b9d..d99190b6b0 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -1108,6 +1108,7 @@ test_modules() ->
"From",
"H235-SECURITY-MESSAGES",
"H323-MESSAGES",
+ "HighTagNumbers",
"Import",
"Int",
"MAP-commonDataTypes",
diff --git a/lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn1 b/lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn1
new file mode 100644
index 0000000000..b681063965
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn1
@@ -0,0 +1,17 @@
+HighTagNumbers DEFINITIONS ::=
+BEGIN
+
+S ::= SEQUENCE {
+ a [127] INTEGER,
+ b [128] INTEGER,
+ c [150] INTEGER,
+ d [207] INTEGER,
+ e [255] INTEGER,
+ f [256] INTEGER,
+ g [7777] INTEGER,
+ h [9999] INTEGER,
+ i [16382] INTEGER,
+ j [16383] INTEGER
+}
+
+END