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* ...@@ -44,6 +44,7 @@ stamp-h*
# /tests/tests-skeletons # /tests/tests-skeletons
/tests/tests-skeletons/check-* /tests/tests-skeletons/check-*
!/tests/tests-skeletons/check-*.c
# /doc/docsrc # /doc/docsrc
doc/docsrc/*.aux doc/docsrc/*.aux
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
(Severity: low; Security impact: medium) (Severity: low; Security impact: medium)
* Fix UPER string decoding constrained only by lower bound > 0 * Fix UPER string decoding constrained only by lower bound > 0
(Severity: low; Security impact: none) (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. * Fix XER decoder crash on maliciously constructed ENUMERATED input.
(Severity: medium; Security impact: medium) (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, ...@@ -218,6 +218,7 @@ ANY_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
/* Get the PER length */ /* Get the PER length */
raw_len = uper_get_length(pd, -1, 0, &repeat); raw_len = uper_get_length(pd, -1, 0, &repeat);
if(raw_len < 0) RETURN(RC_WMORE); 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, ASN_DEBUG("Got PER length len %zu, %s (%s)", raw_len,
repeat ? "repeat" : "once", td->name); repeat ? "repeat" : "once", td->name);
...@@ -254,8 +255,9 @@ ANY_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -254,8 +255,9 @@ ANY_encode_uper(asn_TYPE_descriptor_t *td,
buf = st->buf; buf = st->buf;
size = st->size; size = st->size;
while(size) { do {
ssize_t may_save = uper_put_length(po, size); int need_eom = 0;
ssize_t may_save = uper_put_length(po, size, &need_eom);
if(may_save < 0) ASN__ENCODE_FAILED; if(may_save < 0) ASN__ENCODE_FAILED;
ret = per_put_many_bits(po, buf, may_save * 8); ret = per_put_many_bits(po, buf, may_save * 8);
...@@ -264,7 +266,9 @@ ANY_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -264,7 +266,9 @@ ANY_encode_uper(asn_TYPE_descriptor_t *td,
buf += may_save; buf += may_save;
size -= may_save; size -= may_save;
assert(!(may_save & 0x07) || !size); 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); ASN__ENCODED_OK(er);
} }
......
...@@ -396,6 +396,7 @@ BIT_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -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, raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
&repeat); &repeat);
if(raw_len < 0) RETURN(RC_WMORE); 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)", ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
(long)csiz->effective_bits, (long)raw_len, (long)csiz->effective_bits, (long)raw_len,
...@@ -442,8 +443,6 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -442,8 +443,6 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td,
if(specs->subvariant == ASN_OSUBV_BIT) { if(specs->subvariant == ASN_OSUBV_BIT) {
if((st->size == 0 && st->bits_unused) || (st->bits_unused & ~7)) if((st->size == 0 && st->bits_unused) || (st->bits_unused & ~7))
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
ASN_DEBUG("BIT STRING of %zu bytes, %d bits unused", size_in_bits,
st->bits_unused);
} else { } else {
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
} }
...@@ -518,7 +517,8 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -518,7 +517,8 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td,
buf = st->buf; buf = st->buf;
do { 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; if(maySave < 0) ASN__ENCODE_FAILED;
ASN_DEBUG("Encoding %zd of %zu", maySave, size_in_bits); ASN_DEBUG("Encoding %zd of %zu", maySave, size_in_bits);
...@@ -529,6 +529,8 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -529,6 +529,8 @@ BIT_STRING_encode_uper(asn_TYPE_descriptor_t *td,
buf += maySave >> 3; buf += maySave >> 3;
size_in_bits -= maySave; size_in_bits -= maySave;
assert(!(maySave & 0x07) || !size_in_bits); 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); } while(size_in_bits);
ASN__ENCODED_OK(er); ASN__ENCODED_OK(er);
......
...@@ -770,12 +770,14 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -770,12 +770,14 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
} }
for(buf = st->buf, end = st->buf + st->size; buf < end;) { for(buf = st->buf, end = st->buf + st->size; buf < end;) {
ssize_t mayEncode = uper_put_length(po, end - buf); int need_eom = 0;
ssize_t mayEncode = uper_put_length(po, end - buf, &need_eom);
if(mayEncode < 0) if(mayEncode < 0)
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
if(per_put_many_bits(po, buf, 8 * mayEncode)) if(per_put_many_bits(po, buf, 8 * mayEncode))
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
buf += mayEncode; buf += mayEncode;
if(need_eom && uper_put_length(po, 0, 0)) ASN__ENCODE_FAILED;
} }
ASN__ENCODED_OK(er); ASN__ENCODED_OK(er);
......
...@@ -1253,8 +1253,8 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, ...@@ -1253,8 +1253,8 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,
} }
for(; buf < end; buf += bpc) { for(; buf < end; buf += bpc) {
int code = per_get_few_bits(po, unit_bits); int32_t code = per_get_few_bits(po, unit_bits);
int ch = code + lb; int32_t ch = code + lb;
if(code < 0) return -1; /* WMORE */ if(code < 0) return -1; /* WMORE */
if(ch > ub) { if(ch > ub) {
ASN_DEBUG("Code %d is out of range (%ld..%ld)", 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, ...@@ -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, raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
&repeat); &repeat);
if(raw_len < 0) RETURN(RC_WMORE); 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)", ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
(long)csiz->effective_bits, (long)raw_len, (long)csiz->effective_bits, (long)raw_len,
...@@ -1610,27 +1611,27 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1610,27 +1611,27 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
ASN_DEBUG("Encoding %zu bytes", st->size); 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; buf = st->buf;
while(size_in_units) { ASN_DEBUG("Encoding %zu in units", size_in_units);
ssize_t maySave = uper_put_length(po, size_in_units); do {
if(maySave < 0) ASN__ENCODE_FAILED; 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->lower_bound,
cval->upper_bound, pc); cval->upper_bound, pc);
if(ret) ASN__ENCODE_FAILED; if(ret) ASN__ENCODE_FAILED;
buf += maySave * bpc; buf += may_save * bpc;
size_in_units -= maySave; size_in_units -= may_save;
assert(!(maySave & 0x07) || !size_in_units); 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); ASN__ENCODED_OK(er);
} }
......
...@@ -190,7 +190,7 @@ SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -190,7 +190,7 @@ SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td,
if(ct && ct->effective_bits >= 0) { if(ct && ct->effective_bits >= 0) {
mayEncode = list->count; mayEncode = list->count;
} else { } else {
mayEncode = uper_put_length(po, list->count - seq); mayEncode = uper_put_length(po, list->count - seq, 0);
if(mayEncode < 0) ASN__ENCODE_FAILED; if(mayEncode < 0) ASN__ENCODE_FAILED;
} }
......
...@@ -30,28 +30,33 @@ uper_open_type_put(asn_TYPE_descriptor_t *td, const asn_per_constraints_t *const ...@@ -30,28 +30,33 @@ uper_open_type_put(asn_TYPE_descriptor_t *td, const asn_per_constraints_t *const
void *buf; void *buf;
void *bptr; void *bptr;
ssize_t size; ssize_t size;
size_t toGo;
ASN_DEBUG("Open type put %s ...", td->name); ASN_DEBUG("Open type put %s ...", td->name);
size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
if(size <= 0) return -1; if(size <= 0) return -1;
for(bptr = buf, toGo = size; toGo;) { ASN_DEBUG("Open type put %s of length %zd + overhead (1byte?)", td->name,
ssize_t maySave = uper_put_length(po, toGo); size);
ASN_DEBUG("Prepending length %d to %s and allowing to save %d",
(int)size, td->name, (int)maySave); 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(maySave < 0) break;
if(per_put_many_bits(po, bptr, maySave * 8)) break; if(per_put_many_bits(po, bptr, maySave * 8)) break;
bptr = (char *)bptr + maySave; bptr = (char *)bptr + maySave;
toGo -= maySave; size -= maySave;
if(need_eom && uper_put_length(po, 0, 0)) {
FREEMEM(buf);
return -1;
} }
} while(size);
FREEMEM(buf); FREEMEM(buf);
if(toGo) return -1; if(size) return -1;
ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",
td->name, (long)size);
return 0; return 0;
} }
......
...@@ -177,17 +177,26 @@ int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int ...@@ -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. * Put the length "n" (or part of it) into the stream.
*/ */
ssize_t 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) return per_put_few_bits(po, length, 8)
? -1 : (ssize_t)length; ? -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) return per_put_few_bits(po, length|0x8000, 16)
? -1 : (ssize_t)length; ? -1 : (ssize_t)length;
}
*need_eom = 0 == (length & 16383);
length >>= 14; length >>= 14;
if(length > 4) length = 4; if(length > 4) {
*need_eom = 0;
length = 4;
}
return per_put_few_bits(po, 0xC0 | length, 8) return per_put_few_bits(po, 0xC0 | length, 8)
? -1 : (ssize_t)(length << 14); ? -1 : (ssize_t)(length << 14);
...@@ -202,13 +211,14 @@ uper_put_length(asn_per_outp_t *po, size_t length) { ...@@ -202,13 +211,14 @@ uper_put_length(asn_per_outp_t *po, size_t length) {
*/ */
int int
uper_put_nslength(asn_per_outp_t *po, size_t length) { uper_put_nslength(asn_per_outp_t *po, size_t length) {
if(length <= 64) { if(length <= 64) {
/* #11.9.3.4 */ /* #11.9.3.4 */
if(length == 0) return -1; if(length == 0) return -1;
return per_put_few_bits(po, length-1, 7) ? -1 : 0; return per_put_few_bits(po, length - 1, 7) ? -1 : 0;
} else { } else {
if(uper_put_length(po, length) != (ssize_t)length) { 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 */ /* This might happen in case of >16K extensions */
return -1; return -1;
} }
......
...@@ -75,11 +75,14 @@ int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int ...@@ -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" * 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 * This function returns the number of units which may be flushed
* in the next units saving iteration. * 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. * Put the normally small length "n" to the Unaligned PER stream.
......
...@@ -17,3 +17,9 @@ T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(32)) ...@@ -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(31,...))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..32)) T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..32))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..31,...)) 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)) ...@@ -16,11 +16,12 @@ T ::= VisibleString (SIZE(1..127))
T ::= VisibleString (SIZE(1..128)) T ::= VisibleString (SIZE(1..128))
T ::= VisibleString (SIZE(1..129)) T ::= VisibleString (SIZE(1..129))
T ::= VisibleString (SIZE(5) INTERSECTION FROM("A".."Z")) 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")))
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. ...@@ -14,9 +14,9 @@ contstraints that are intended to affect encoding and parsing.
* By default, the random value generator attempts to generate values * By default, the random value generator attempts to generate values
limited to very roughly to around 128 bytes. If huge values are desired 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 (perhaps due to large constraints), the RMAX=<size> setting can be specified
on a line: in the ASN.1 comments:
RMAX=64000 T ::= VisibleString (SIZE(64000)) T ::= VisibleString (SIZE(64000)) -- RMAX=64000
...@@ -148,12 +148,11 @@ asn_compile() { ...@@ -148,12 +148,11 @@ asn_compile() {
local asn="$1" local asn="$1"
shift 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=[^ ]* //;') local short_asn=$(echo "$asn" | sed -e 's/ *--.*//;s/RMAX=[^ ]* //;')
if [ $(echo "$short_asn" | grep -c "::=") = 1 ]; then if [ $(echo "$short_asn" | grep -c "::=") = 1 ]; then
short_asn=$(echo "$short_asn" | sed -e 's/.*::= *//') short_asn=$(echo "$short_asn" | sed -e 's/.*::= *//')
fi fi
asn=$(echo "$asn" | sed -e 's/RMAX=[^ ]* //;')
test ! -f Makefile.am # Protection from accidental clobbering test ! -f Makefile.am # Protection from accidental clobbering
echo "Test DEFINITIONS ::= BEGIN $asn" > test.asn1 echo "Test DEFINITIONS ::= BEGIN $asn" > test.asn1
......
...@@ -15,6 +15,7 @@ check_PROGRAMS = \ ...@@ -15,6 +15,7 @@ check_PROGRAMS = \
check-OER-support \ check-OER-support \
check-OER-INTEGER \ check-OER-INTEGER \
check-OER-NativeEnumerated \ check-OER-NativeEnumerated \
check-PER-support \
check-PER-UniversalString \ check-PER-UniversalString \
check-PER-INTEGER 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