diff --git a/libr/util/asn1.c b/libr/util/asn1.c index 7ce51bc1d34c8..1dd7d07bb4921 100644 --- a/libr/util/asn1.c +++ b/libr/util/asn1.c @@ -53,7 +53,7 @@ static RASN1Object *asn1_parse_header(const ut8 *buffer_base, const ut8 *buffer, // Check for indefinite length. if (length8) { // Length over 6 bytes is not allowed. - if (length8 > length - 1 || length8 > 6) { + if (length8 > length - 2 || length8 > 6) { R_LOG_DEBUG ("ASN.1: length error"); goto out_error; } @@ -83,7 +83,7 @@ static RASN1Object *asn1_parse_header(const ut8 *buffer_base, const ut8 *buffer, // Calculate headerlength before BITSTRING adjustment obj->headerlength = obj->sector - initial_pos; if (obj->tag == TAG_BITSTRING) { - if (obj->length > 0) { + if (obj->length > 0 && obj->sector < buffer + length) { obj->length--; obj->bitlength = obj->length * 8 - obj->sector[0]; obj->sector++; // real sector starts + 1 diff --git a/test/unit/meson.build b/test/unit/meson.build index c98afac59af53..7cfa757c1183b 100644 --- a/test/unit/meson.build +++ b/test/unit/meson.build @@ -14,6 +14,7 @@ if get_option('enable_tests') 'anal_xrefs', 'anal_x86', 'arena', + 'asn1', 'axml', 'codemeta', 'base64', diff --git a/test/unit/test_asn1.c b/test/unit/test_asn1.c new file mode 100644 index 0000000000000..07cc36b189be5 --- /dev/null +++ b/test/unit/test_asn1.c @@ -0,0 +1,41 @@ +#include +#include "minunit.h" + +// long-form length-of-length that claims more length octets than the buffer +// holds: with a 3 byte buffer and two length octets the parser used to read +// buffer[3], one past the end. +bool test_asn1_longform_length_oob(void) { + ut8 *buf = malloc (3); + buf[0] = 0x30; // SEQUENCE + buf[1] = 0x82; // long form, two length octets + buf[2] = 0x00; + RASN1Object *o = r_asn1_object_parse (buf, buf, 3, 0); + mu_assert_null (o, "long-form length with more octets than the buffer holds must be rejected"); + r_asn1_object_free (o); + free (buf); + mu_end; +} + +// bitstring whose declared content starts exactly at the end of the buffer: +// the unused-bits byte (sector[0]) used to be read one past the end. +bool test_asn1_bitstring_sector_oob(void) { + ut8 *buf = malloc (3); + buf[0] = 0x23; // BITSTRING + buf[1] = 0x81; // long form, one length octet + buf[2] = 0x01; // length 1, so the content byte lands past the buffer + RASN1Object *o = r_asn1_object_parse (buf, buf, 3, 0); + mu_assert_notnull (o, "truncated bitstring should still parse without reading past the buffer"); + r_asn1_object_free (o); + free (buf); + mu_end; +} + +int all_tests(void) { + mu_run_test (test_asn1_longform_length_oob); + mu_run_test (test_asn1_bitstring_sector_oob); + return tests_passed != tests_run; +} + +int main(int argc, char **argv) { + return all_tests (); +}