Commit 5d947a87 authored by Lev Walkin's avatar Lev Walkin

fix UPER decoding of large [bit-]strings of size a multiple of 16K

parent e0d9f2b7
......@@ -44,6 +44,7 @@ stamp-h*
# /tests/tests-skeletons
/tests/tests-skeletons/check-*
!/tests/tests-skeletons/check-*.c
# /doc/docsrc
doc/docsrc/*.aux
......
......@@ -25,6 +25,8 @@
(Severity: low; Security impact: medium)
* Fix UPER string decoding constrained only by lower bound > 0
(Severity: low; Security impact: none)
* Fix UPER decoding of large [bit-]strings of size a multiple of 16K
(Severity: low; Security impact: none)
* Fix XER decoder crash on maliciously constructed ENUMERATED input.
(Severity: medium; Security impact: medium)
......
......@@ -218,6 +218,7 @@ ANY_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
/* Get the PER length */
raw_len = uper_get_length(pd, -1, 0, &repeat);
if(raw_len < 0) RETURN(RC_WMORE);
if(raw_len == 0 && st->buf) break;
ASN_DEBUG("Got PER length len %zu, %s (%s)", raw_len,
repeat ? "repeat" : "once", td->name);
......@@ -254,8 +255,9 @@ ANY_encode_uper(asn_TYPE_descriptor_t *td,
buf = st->buf;
size = st->size;
while(size) {
ssize_t may_save = uper_put_length(po, size);
do {
int need_eom = 0;
ssize_t may_save = uper_put_length(po, size, &need_eom);
if(may_save < 0) ASN__ENCODE_FAILED;
ret = per_put_many_bits(po, buf, may_save * 8);
......@@ -264,7 +266,9 @@ ANY_encode_uper(asn_TYPE_descriptor_t *td,
buf += may_save;
size -= may_save;
assert(!(may_save & 0x07) || !size);
}
if(need_eom && uper_put_length(po, 0, 0))
ASN__ENCODE_FAILED; /* End of Message length */
} while(size);
ASN__ENCODED_OK(er);
}
......
......@@ -396,6 +396,7 @@ BIT_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
&repeat);
if(raw_len < 0) RETURN(RC_WMORE);
if(raw_len == 0 && st->buf) break;
ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
(long)csiz->effective_bits, (long)raw_len,
......@@ -442,8 +443,6 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td,
if(specs->subvariant == ASN_OSUBV_BIT) {
if((st->size == 0 && st->bits_unused) || (st->bits_unused & ~7))
ASN__ENCODE_FAILED;
ASN_DEBUG("BIT STRING of %zu bytes, %d bits unused", size_in_bits,
st->bits_unused);
} else {
ASN__ENCODE_FAILED;
}
......@@ -518,7 +517,8 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td,
buf = st->buf;
do {
ssize_t maySave = uper_put_length(po, size_in_bits);
int need_eom = 0;
ssize_t maySave = uper_put_length(po, size_in_bits, &need_eom);
if(maySave < 0) ASN__ENCODE_FAILED;
ASN_DEBUG("Encoding %zd of %zu", maySave, size_in_bits);
......@@ -529,6 +529,8 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td,
buf += maySave >> 3;
size_in_bits -= maySave;
assert(!(maySave & 0x07) || !size_in_bits);
if(need_eom && uper_put_length(po, 0, 0))
ASN__ENCODE_FAILED; /* End of Message length */
} while(size_in_bits);
ASN__ENCODED_OK(er);
......
......@@ -770,13 +770,15 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
}
for(buf = st->buf, end = st->buf + st->size; buf < end;) {
ssize_t mayEncode = uper_put_length(po, end - buf);
if(mayEncode < 0)
int need_eom = 0;
ssize_t mayEncode = uper_put_length(po, end - buf, &need_eom);
if(mayEncode < 0)
ASN__ENCODE_FAILED;
if(per_put_many_bits(po, buf, 8 * mayEncode))
ASN__ENCODE_FAILED;
buf += mayEncode;
}
if(need_eom && uper_put_length(po, 0, 0)) ASN__ENCODE_FAILED;
}
ASN__ENCODED_OK(er);
}
......
......@@ -1253,8 +1253,8 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,
}
for(; buf < end; buf += bpc) {
int code = per_get_few_bits(po, unit_bits);
int ch = code + lb;
int32_t code = per_get_few_bits(po, unit_bits);
int32_t ch = code + lb;
if(code < 0) return -1; /* WMORE */
if(ch > ub) {
ASN_DEBUG("Code %d is out of range (%ld..%ld)",
......@@ -1471,6 +1471,7 @@ OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
&repeat);
if(raw_len < 0) RETURN(RC_WMORE);
if(raw_len == 0 && st->buf) break;
ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
(long)csiz->effective_bits, (long)raw_len,
......@@ -1610,27 +1611,27 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
ASN_DEBUG("Encoding %zu bytes", st->size);
if(size_in_units == 0) {
if(uper_put_length(po, 0)) ASN__ENCODE_FAILED;
ASN__ENCODED_OK(er);
}
buf = st->buf;
while(size_in_units) {
ssize_t maySave = uper_put_length(po, size_in_units);
if(maySave < 0) ASN__ENCODE_FAILED;
ASN_DEBUG("Encoding %zu in units", size_in_units);
do {
int need_eom = 0;
ssize_t may_save = uper_put_length(po, size_in_units, &need_eom);
if(may_save < 0) ASN__ENCODE_FAILED;
ASN_DEBUG("Encoding %zd of %zu", maySave, size_in_units);
ASN_DEBUG("Encoding %zd of %zu%s", may_save, size_in_units,
need_eom ? ",+EOM" : "");
ret = OCTET_STRING_per_put_characters(po, buf, maySave, bpc, unit_bits,
ret = OCTET_STRING_per_put_characters(po, buf, may_save, bpc, unit_bits,
cval->lower_bound,
cval->upper_bound, pc);
if(ret) ASN__ENCODE_FAILED;
buf += maySave * bpc;
size_in_units -= maySave;
assert(!(maySave & 0x07) || !size_in_units);
}
buf += may_save * bpc;
size_in_units -= may_save;
assert(!(may_save & 0x07) || !size_in_units);
if(need_eom && uper_put_length(po, 0, 0))
ASN__ENCODE_FAILED; /* End of Message length */
} while(size_in_units);
ASN__ENCODED_OK(er);
}
......
......@@ -190,7 +190,7 @@ SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td,
if(ct && ct->effective_bits >= 0) {
mayEncode = list->count;
} else {
mayEncode = uper_put_length(po, list->count - seq);
mayEncode = uper_put_length(po, list->count - seq, 0);
if(mayEncode < 0) ASN__ENCODE_FAILED;
}
......
......@@ -27,33 +27,38 @@ static asn_dec_rval_t uper_sot_suck(const asn_codec_ctx_t *,
*/
int
uper_open_type_put(asn_TYPE_descriptor_t *td, const asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
void *buf;
void *bptr;
ssize_t size;
size_t toGo;
ASN_DEBUG("Open type put %s ...", td->name);
size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
if(size <= 0) return -1;
for(bptr = buf, toGo = size; toGo;) {
ssize_t maySave = uper_put_length(po, toGo);
ASN_DEBUG("Prepending length %d to %s and allowing to save %d",
(int)size, td->name, (int)maySave);
if(maySave < 0) break;
if(per_put_many_bits(po, bptr, maySave * 8)) break;
bptr = (char *)bptr + maySave;
toGo -= maySave;
}
FREEMEM(buf);
if(toGo) return -1;
ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",
td->name, (long)size);
return 0;
void *buf;
void *bptr;
ssize_t size;
ASN_DEBUG("Open type put %s ...", td->name);
size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
if(size <= 0) return -1;
ASN_DEBUG("Open type put %s of length %zd + overhead (1byte?)", td->name,
size);
bptr = buf;
do {
int need_eom = 0;
ssize_t maySave = uper_put_length(po, size, &need_eom);
ASN_DEBUG("Prepending length %zd to %s and allowing to save %d", size,
td->name, (int)maySave);
if(maySave < 0) break;
if(per_put_many_bits(po, bptr, maySave * 8)) break;
bptr = (char *)bptr + maySave;
size -= maySave;
if(need_eom && uper_put_length(po, 0, 0)) {
FREEMEM(buf);
return -1;
}
} while(size);
FREEMEM(buf);
if(size) return -1;
return 0;
}
static asn_dec_rval_t
......
......@@ -177,17 +177,26 @@ int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int
* Put the length "n" (or part of it) into the stream.
*/
ssize_t
uper_put_length(asn_per_outp_t *po, size_t length) {
uper_put_length(asn_per_outp_t *po, size_t length, int *need_eom) {
int dummy = 0;
if(!need_eom) need_eom = &dummy;
if(length <= 127) /* #11.9.3.6 */
if(length <= 127) { /* #11.9.3.6 */
*need_eom = 0;
return per_put_few_bits(po, length, 8)
? -1 : (ssize_t)length;
else if(length < 16384) /* #10.9.3.7 */
} else if(length < 16384) { /* #10.9.3.7 */
*need_eom = 0;
return per_put_few_bits(po, length|0x8000, 16)
? -1 : (ssize_t)length;
}
*need_eom = 0 == (length & 16383);
length >>= 14;
if(length > 4) length = 4;
if(length > 4) {
*need_eom = 0;
length = 4;
}
return per_put_few_bits(po, 0xC0 | length, 8)
? -1 : (ssize_t)(length << 14);
......@@ -202,18 +211,19 @@ uper_put_length(asn_per_outp_t *po, size_t length) {
*/
int
uper_put_nslength(asn_per_outp_t *po, size_t length) {
if(length <= 64) {
/* #11.9.3.4 */
if(length == 0) return -1;
return per_put_few_bits(po, length - 1, 7) ? -1 : 0;
} else {
int need_eom = 0;
if(uper_put_length(po, length, &need_eom) != (ssize_t)length
|| need_eom) {
/* This might happen in case of >16K extensions */
return -1;
}
}
if(length <= 64) {
/* #11.9.3.4 */
if(length == 0) return -1;
return per_put_few_bits(po, length-1, 7) ? -1 : 0;
} else {
if(uper_put_length(po, length) != (ssize_t)length) {
/* This might happen in case of >16K extensions */
return -1;
}
}
return 0;
return 0;
}
......@@ -75,11 +75,14 @@ int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int
/*
* X.691 (08/2015) #11.9 "General rules for encoding a length determinant"
* Put the length "n" to the Unaligned PER stream.
* Put the length "whole_length" to the Unaligned PER stream.
* If (opt_need_eom) is given, it will be set to 1 if final 0-length is needed.
* In that case, invoke uper_put_length(po, 0, 0) after encoding the last block.
* This function returns the number of units which may be flushed
* in the next units saving iteration.
*/
ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length);
ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length,
int *opt_need_eom);
/*
* Put the normally small length "n" to the Unaligned PER stream.
......
......@@ -17,3 +17,9 @@ T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(32))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(31,...))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..32))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..31,...))
T ::= BIT STRING { foo(0) } (SIZE(65535)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65536)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65537)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65535,...)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65536,...)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65537,...)) -- RMAX=65540
......@@ -16,11 +16,12 @@ T ::= VisibleString (SIZE(1..127))
T ::= VisibleString (SIZE(1..128))
T ::= VisibleString (SIZE(1..129))
T ::= VisibleString (SIZE(5) INTERSECTION FROM("A".."Z"))
RMAX=64000 VisibleString (SIZE(64000)) -- Length is not encoded, #11.9.3.3
RMAX=33000 T ::= VisibleString (SIZE(32000..32002))
RMAX=33000 T ::= VisibleString (SIZE(32000..32002)) (FROM("A".."B"))
RMAX=33000 T ::= VisibleString (SIZE(32000..32002,...)) (FROM("A".."B"))
RMAX=65536 T ::= VisibleString (SIZE(65530..65535))
RMAX=65536 T ::= VisibleString (SIZE(65530..65536))
T ::= VisibleString (SIZE(4..6) INTERSECTION (FROM("A".."B")))
T ::= VisibleString (SIZE(4..6,...) INTERSECTION (FROM("A".."B")))
VisibleString (SIZE(64000)) -- RMAX=64000, #11.9.3.3
T ::= VisibleString (SIZE(32000..32002)) -- RMAX=33000
T ::= VisibleString (SIZE(32000..32002)) (FROM("A".."B")) -- RMAX=33000
T ::= VisibleString (SIZE(32000..32002,...)) (FROM("A".."B")) -- RMAX=33000
T ::= VisibleString (SIZE(65530..65535)) -- RMAX=65536
T ::= VisibleString (SIZE(65530..65536)) -- RMAX=65536
T ::= VisibleString (SIZE(65535..65550)) -- RMAX=66000
......@@ -14,9 +14,9 @@ contstraints that are intended to affect encoding and parsing.
* By default, the random value generator attempts to generate values
limited to very roughly to around 128 bytes. If huge values are desired
(perhaps due to large constraints), the RMAX=<size> prefix can be specified
on a line:
(perhaps due to large constraints), the RMAX=<size> setting can be specified
in the ASN.1 comments:
RMAX=64000 T ::= VisibleString (SIZE(64000))
T ::= VisibleString (SIZE(64000)) -- RMAX=64000
......@@ -148,12 +148,11 @@ asn_compile() {
local asn="$1"
shift
# Create "INTEGER (1..2)" from "RMAX=5 T ::= INTEGER (1..2) -- Comment"
# Create "INTEGER (1..2)" from "T ::= INTEGER (1..2) -- RMAX=5"
local short_asn=$(echo "$asn" | sed -e 's/ *--.*//;s/RMAX=[^ ]* //;')
if [ $(echo "$short_asn" | grep -c "::=") = 1 ]; then
short_asn=$(echo "$short_asn" | sed -e 's/.*::= *//')
fi
asn=$(echo "$asn" | sed -e 's/RMAX=[^ ]* //;')
test ! -f Makefile.am # Protection from accidental clobbering
echo "Test DEFINITIONS ::= BEGIN $asn" > test.asn1
......
......@@ -15,6 +15,7 @@ check_PROGRAMS = \
check-OER-support \
check-OER-INTEGER \
check-OER-NativeEnumerated \
check-PER-support \
check-PER-UniversalString \
check-PER-INTEGER
......
#include <assert.h>
#include <per_support.h>
static void put(asn_per_outp_t *po, size_t length) {
fprintf(stderr, "put(%zd)\n", length);
do {
int need_eom = 123;
ssize_t may_write = uper_put_length(po, length, &need_eom);
fprintf(stderr, " put %zu\n", may_write);
assert(may_write >= 0);
assert(may_write <= length);
assert(need_eom != 123);
length -= may_write;
if(need_eom) {
assert(length == 0);
if(uper_put_length(po, 0, 0)) {
assert(!"Unreachable");
}
fprintf(stderr, " put EOM 0\n");
}
} while(length);
fprintf(stderr, "put(...) in %zu bits\n", po->nboff);
assert(po->nboff != 0);
assert(po->flushed_bytes == 0);
}
static size_t get(asn_per_outp_t *po) {
asn_bit_data_t data;
memset(&data, 0, sizeof(data));
data.buffer = po->tmpspace;
data.nboff = 0;
data.nbits = 8 * (po->buffer - po->tmpspace) + po->nboff;
fprintf(stderr, "get(): %s\n", asn_bit_data_string(&data));
size_t length = 0;
int repeat = 0;
do {
ssize_t n = uper_get_length(&data, -1, 0, &repeat);
fprintf(stderr, " get = %zu +%zd\n", length, n);
assert(n >= 0);
length += n;
} while(repeat);
fprintf(stderr, "get() = %zu\n", length);
return length;
}
static void
check_round_trip(size_t length) {
fprintf(stderr, "\nRound-trip for %zu\n", length);
asn_per_outp_t po;
memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace);
put(&po, length);
size_t recovered = get(&po);
assert(recovered == length);
}
int main() {
check_round_trip(0);
check_round_trip(1);
check_round_trip(127);
check_round_trip(128);
check_round_trip(129);
check_round_trip(255);
check_round_trip(256);
check_round_trip(65534);
check_round_trip(65535);
check_round_trip(65536);
check_round_trip(65538);
check_round_trip(128000);
for(size_t i = 1; i < 10; i++) {
check_round_trip(i*16384 - 1);
check_round_trip(i*16384);
check_round_trip(i*16384 + 1);
}
}
#include <stdio.h>
#include <assert.h>
#include <asn_bit_data.c>
#include <per_support.c>
#include <per_support.h>
static void
check_per_decoding() {
uint8_t buf[] = { 0xB7, 0x19, 0x2F, 0xEE, 0xAD };
uint8_t tmpbuf[10];
int32_t z;
asn_per_data_t pos;
memset(&pos, 0, sizeof(pos));
pos.buffer = buf;
pos.nboff = 0;
pos.nbits = sizeof(buf) * 8;
z = per_get_few_bits(&pos, 32);
assert(z == -1);
assert(pos.nbits == sizeof(buf) * 8);
z = per_get_few_bits(&pos, 0);
assert(z == 0);
assert(pos.nboff == 0);
assert(pos.nbits == sizeof(buf) * 8);
z = per_get_few_bits(&pos, 1);
assert(z == 1);
assert(pos.nboff == 1);
assert(pos.nbits == sizeof(buf) * 8);
z = per_get_few_bits(&pos, 2);
assert(z == 1);
assert(pos.nboff == 3);
assert(pos.nbits == sizeof(buf) * 8);
z = per_get_few_bits(&pos, 2);
assert(z == 2);
assert(pos.nboff == 5);
assert(pos.nbits == sizeof(buf) * 8);
z = per_get_few_bits(&pos, 3);
assert(z == 7);
assert(pos.nboff == 8);
assert(pos.nbits == sizeof(buf) * 8);
z = per_get_few_bits(&pos, 8);
assert(z == 0x19);
assert(pos.nboff == 8);
assert(pos.nbits == (sizeof(buf) - 1) * 8);
z = per_get_few_bits(&pos, 1);
assert(z == 0);
assert(pos.nboff == 1);
assert(pos.nbits == (sizeof(buf) - 2) * 8);
z = per_get_few_bits(&pos, 3);
assert(z == 2);
assert(pos.nboff == 4);
assert(pos.nbits == (sizeof(buf) - 2) * 8);
z = per_get_few_bits(&pos, 8);
assert(z == 254);
assert(pos.nboff == 12);
pos.buffer = buf;
pos.nboff = 2;
pos.nbits = sizeof(buf) * 8;
z = per_get_few_bits(&pos, 24);
assert(z == 14443711);
pos.buffer = (unsigned char *)"\001";
pos.nboff = 7;
pos.nbits = 7;
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 7);
assert(pos.nbits == 7);
assert(z == -1);
pos.buffer = (unsigned char *)"\001";
pos.nboff = 7;
pos.nbits = 8;
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 8);
assert(pos.nbits == 8);
assert(z == 1);
pos.buffer = (unsigned char *)"\000";
pos.nboff = 7;
pos.nbits = 8;
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 8);
assert(pos.nbits == 8);
assert(z == 0);
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 8);
assert(pos.nbits == 8);
assert(z == -1);
pos.buffer = (unsigned char *)"\000";
pos.nboff = 7;
pos.nbits = 9;
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 8);
assert(pos.nbits == 9);
assert(z == 0);
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 1);
assert(pos.nbits == 1);
assert(z == 0);
pos.buffer = (unsigned char *)"\001";
pos.nboff = 7;
pos.nbits = 9;
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 8);
assert(pos.nbits == 9);
assert(z == 1);
z = per_get_few_bits(&pos, 1);
assert(pos.nboff == 1);
assert(pos.nbits == 1);
assert(z == 0);
/* Get full 31-bit range */
pos.buffer = buf;
pos.nboff = 7;
pos.nbits = sizeof(buf) * 8;
z = per_get_few_bits(&pos, 31);
assert(z == 1179384747);
/* Get a bit shifted range */
pos.buffer = buf;
pos.nboff = 6;
pos.nbits = sizeof(buf) * 8;
z = per_get_few_bits(&pos, 31);
assert(z == 1663434197);
pos.buffer = buf;
pos.nboff = 0;
pos.nbits = sizeof(buf) * 8;
z = per_get_many_bits(&pos, tmpbuf, 0, sizeof(buf) * 8);
assert(z == 0);
assert(buf[0] == tmpbuf[0]);
assert(buf[1] == tmpbuf[1]);
assert(buf[2] == tmpbuf[2]);
assert(buf[3] == tmpbuf[3]);
assert(buf[4] == tmpbuf[4]);
pos.buffer = buf;
pos.nboff = 1;
pos.nbits = sizeof(buf) * 8;
z = per_get_many_bits(&pos, tmpbuf, 0, sizeof(buf) * 8);
assert(z == -1);
pos.buffer = buf;
pos.nboff = 1;
pos.nbits = sizeof(buf) * 8;
z = per_get_many_bits(&pos, tmpbuf, 0, sizeof(buf) * 8 - 1);
assert(z == 0);
assert(tmpbuf[0] == 110);
assert(tmpbuf[1] == 50);
assert(tmpbuf[2] == 95);
assert(tmpbuf[3] == 221);
assert(tmpbuf[4] == 90);
pos.buffer = buf;
pos.nboff = 1;
pos.nbits = sizeof(buf) * 8;
z = per_get_many_bits(&pos, tmpbuf, 1, sizeof(buf) * 8 - 1);
assert(z == 0);
assert(tmpbuf[0] == 55);
assert(tmpbuf[0] != buf[0]);
assert(tmpbuf[1] == buf[1]);
assert(tmpbuf[2] == buf[2]);
assert(tmpbuf[3] == buf[3]);
assert(tmpbuf[4] == buf[4]);
}
static int Ignore(const void *data, size_t size, void *op_key) {
(void)data;
(void)size;
(void)op_key;
return 0;
}
static void
check_per_encoding() {
asn_per_outp_t po;
int ret;
po.buffer = po.tmpspace;
po.nboff = 0;
po.nbits = 0;
po.output = Ignore;
po.op_key = 0;
po.tmpspace[0] = 0xff;
ret = per_put_few_bits(&po, 0, 0);
assert(ret == 0);
assert(po.nboff == 0);
assert(po.buffer == po.tmpspace);
assert(po.tmpspace[0] == 0xff);
ret = per_put_few_bits(&po, 0, 1);
assert(ret == 0);
assert(po.nboff == 1);
assert(po.nbits == 8 * sizeof(po.tmpspace));
assert(po.buffer == po.tmpspace);
assert(po.tmpspace[0] == 0x00);
ret = per_put_few_bits(&po, 1, 1);
assert(ret == 0);
assert(po.nboff == 2);
assert(po.nbits == 8 * sizeof(po.tmpspace));
assert(po.buffer == po.tmpspace);
assert(po.tmpspace[0] == 0x40);
ret = per_put_few_bits(&po, 1, 1);
assert(ret == 0);
assert(po.nboff == 3);
assert(po.nbits == 8 * sizeof(po.tmpspace));
assert(po.buffer == po.tmpspace);
assert(po.tmpspace[0] == 0x60);
ret = per_put_few_bits(&po, 15, 5);
assert(ret == 0);
assert(po.nboff == 8);
assert(po.nbits == 8 * sizeof(po.tmpspace));
assert(po.buffer == po.tmpspace);
assert(po.tmpspace[0] == 0x6F);
ret = per_put_few_bits(&po, 0xf0ff, 16);
assert(ret == 0);
assert(po.nboff == 16);
assert(po.nbits == 8 * sizeof(po.tmpspace) - 8);
assert(po.buffer == po.tmpspace + 1);
assert(po.tmpspace[0] == 0x6F);
assert(po.tmpspace[1] == 0xf0);
assert(po.tmpspace[2] == 0xff);
po.nboff--;
ret = per_put_few_bits(&po, 2, 1);
assert(ret == 0);
assert(po.nboff == 8);
assert(po.nbits == 8 * sizeof(po.tmpspace) - 16);
assert(po.buffer == po.tmpspace + 2);
assert(po.tmpspace[0] == 0x6F);
assert(po.tmpspace[1] == 0xf0);
assert(po.tmpspace[2] == 0xfe);
ret = per_put_few_bits(&po, 2, 32);
assert(ret == -1);
ret = per_put_few_bits(&po, 2, -1);
assert(ret == -1);
ret = per_put_few_bits(&po, -1, 31);
assert(ret == 0);
assert(po.nboff == 31);
assert(po.nbits == 8 * sizeof(po.tmpspace) - 24);
assert(po.buffer == po.tmpspace + 3);
assert(po.tmpspace[0] == 0x6F);
assert(po.tmpspace[1] == 0xf0);
assert(po.tmpspace[2] == 0xfe);
assert(po.tmpspace[3] == 0xff);
assert(po.tmpspace[4] == 0xff);
assert(po.tmpspace[5] == 0xff);
assert(po.tmpspace[6] == 0xfe);
}
/*
* Add N bits after P bits. Should result in N+P bits added.
*/
static void
check_per_encoding_auto() {
int prior, next;
int ret, i;
for(prior = 0; prior <= 31; prior++) {
for(next = 0; next <= 31; next++) {
asn_per_outp_t po;
po.buffer = po.tmpspace;
po.nboff = 0;
po.nbits = 0;
po.output = Ignore;
po.op_key = 0;
po.tmpspace[0] = 0xff;
ret = per_put_few_bits(&po, -1, prior);
assert(ret == 0);
ASN_DEBUG(" (out{nboff=%d,nbits=%d,buf_offset=%d})", (int)po.nboff, (int)po.nbits, (int)(po.buffer - po.tmpspace));
ret = per_put_few_bits(&po, -1, next);
assert(ret == 0);
ASN_DEBUG(" (out{nboff=%d,nbits=%d,buf_offset=%d})", (int)po.nboff, (int)po.nbits, (int)(po.buffer - po.tmpspace));
ASN_DEBUG("Putting %d + %d bits (%d/%d), got %d bytes and %d bits",
prior, next, (prior + next) / 8, (prior + next) % 8,
(int)(po.buffer - po.tmpspace), (int)po.nboff);
assert((po.buffer - po.tmpspace) * 8 + po.nboff == (size_t)(prior + next));
for(i = 0; i < (po.buffer - po.tmpspace); i++)
assert(po.tmpspace[0] == (unsigned char)-1);
}
}
}
static void
check_per_encoding_sweep_with(uint8_t buf[], int already_bits, int add_bits) {
size_t buf_size = 8;
asn_per_data_t pos;
asn_per_outp_t out;
int32_t d_already;
int32_t d_add;
int32_t d_left;
int left_bits;
memset(&pos, 0, sizeof(pos));
pos.buffer = buf;
pos.nboff = 0;
pos.nbits = buf_size * 8;
memset(&out, 0, sizeof(out));
out.buffer = out.tmpspace;
out.nbits = 8 * sizeof(out.tmpspace);
assert(sizeof(out.tmpspace) >= buf_size);
memcpy(out.buffer, buf, buf_size);
d_already = per_get_few_bits(&pos, already_bits);
d_add = per_get_few_bits(&pos, add_bits);
per_put_few_bits(&out, d_already, already_bits);
per_put_few_bits(&out, d_add, add_bits);
if(out.nboff % 8) {
left_bits = 8 - (out.nboff % 8);
d_left = per_get_few_bits(&pos, left_bits);
} else {
left_bits = 0;
d_left = 0;
}
per_put_few_bits(&out, d_left, left_bits);
assert(0 == (out.nboff % 8));
if(0 != memcmp(out.tmpspace, buf, buf_size)) {
printf("IN: ");
for(size_t i = 0; i < buf_size; i++)
printf(" %02x", buf[i]);
printf("\nOUT:");
for(size_t i = 0; i < buf_size; i++)
printf(" %02x", out.tmpspace[i]);
printf(" (out{nboff=%d,left=%d,%02x})\n", (int)out.nboff, left_bits, (int)d_left);
assert(0 == memcmp(out.tmpspace, buf, buf_size));
}
}
static void
check_per_encoding_sweep() {
uint8_t buf[3][8] = {
{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA },
{ 0xB7, 0x19, 0x2F, 0xEE, 0xAD, 0x11, 0xAA, 0x55 },
{ 0xEE, 0xAD, 0x11, 0xAA, 0x55, 0xB7, 0x19, 0x2F }
};
int already_bits;
int add_bits;
int buf_idx;
for(buf_idx = 0; buf_idx < 3; buf_idx++) {
for(already_bits = 0; already_bits < 24; already_bits++) {
for(add_bits = 0; add_bits <= 31; add_bits++) {
/*fprintf(stderr, "PER %d += %d\n", already_bits, add_bits);*/
check_per_encoding_sweep_with(buf[buf_idx], already_bits, add_bits);
}
}
}
}
int
main() {
check_per_decoding();
check_per_encoding();
check_per_encoding_auto();
check_per_encoding_sweep();
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment