Commit 9d1b45f8 authored by Lev Walkin's avatar Lev Walkin

Fix UPER string decoding constrained only by lower bound > 0

parent ce6b0a66
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
(Severity: medium; Security impact: medium) (Severity: medium; Security impact: medium)
* Fix REAL type overwrite conversion memory leak. * Fix REAL type overwrite conversion memory leak.
(Severity: low; Security impact: medium) (Severity: low; Security impact: medium)
* Fix UPER string decoding constrained only by lower bound > 0
(Severity: low; Security impact: none)
0.9.28: 2017-03-26 0.9.28: 2017-03-26
* PER decoding: avoid memory leak on error. By github.com/simo5 * PER decoding: avoid memory leak on error. By github.com/simo5
......
...@@ -216,7 +216,7 @@ ANY_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ...@@ -216,7 +216,7 @@ ANY_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
int ret; int ret;
/* Get the PER length */ /* Get the PER length */
raw_len = uper_get_length(pd, -1, &repeat); raw_len = uper_get_length(pd, -1, 0, &repeat);
if(raw_len < 0) RETURN(RC_WMORE); if(raw_len < 0) RETURN(RC_WMORE);
ASN_DEBUG("Got PER length len %zu, %s (%s)", raw_len, ASN_DEBUG("Got PER length len %zu, %s (%s)", raw_len,
......
...@@ -656,7 +656,7 @@ INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t ...@@ -656,7 +656,7 @@ INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t
int ret = 0; int ret = 0;
/* Get the PER length */ /* Get the PER length */
len = uper_get_length(pd, -1, &repeat); len = uper_get_length(pd, -1, 0, &repeat);
if(len < 0) ASN__DECODE_STARVED; if(len < 0) ASN__DECODE_STARVED;
p = REALLOC(st->buf, st->size + len + 1); p = REALLOC(st->buf, st->size + len + 1);
......
...@@ -1424,7 +1424,6 @@ OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -1424,7 +1424,6 @@ OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
if(inext < 0) RETURN(RC_WMORE); if(inext < 0) RETURN(RC_WMORE);
if(inext) { if(inext) {
csiz = &asn_DEF_OCTET_STRING_constraints.size; csiz = &asn_DEF_OCTET_STRING_constraints.size;
cval = &asn_DEF_OCTET_STRING_constraints.value;
unit_bits = canonical_unit_bits; unit_bits = canonical_unit_bits;
} }
} }
...@@ -1477,9 +1476,9 @@ OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -1477,9 +1476,9 @@ OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
int ret; int ret;
/* Get the PER length */ /* Get the PER length */
raw_len = uper_get_length(pd, csiz->effective_bits, &repeat); raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
&repeat);
if(raw_len < 0) RETURN(RC_WMORE); if(raw_len < 0) RETURN(RC_WMORE);
raw_len += csiz->lower_bound;
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,
...@@ -1531,7 +1530,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1531,7 +1530,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
int inext = 0; /* Lies not within extension root */ int inext = 0; /* Lies not within extension root */
unsigned int unit_bits; unsigned int unit_bits;
unsigned int canonical_unit_bits; unsigned int canonical_unit_bits;
unsigned int sizeinunits; size_t size_in_units;
const uint8_t *buf; const uint8_t *buf;
int ret; int ret;
enum { enum {
...@@ -1561,23 +1560,23 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1561,23 +1560,23 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
case ASN_OSUBV_BIT: case ASN_OSUBV_BIT:
canonical_unit_bits = unit_bits = 1; canonical_unit_bits = unit_bits = 1;
bpc = OS__BPC_BIT; bpc = OS__BPC_BIT;
sizeinunits = st->size * 8 - (st->bits_unused & 0x07); size_in_units = st->size * 8 - (st->bits_unused & 0x07);
ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", ASN_DEBUG("BIT STRING of %zu bytes, %d bits unused",
sizeinunits, st->bits_unused); size_in_units, st->bits_unused);
break; break;
case ASN_OSUBV_STR: case ASN_OSUBV_STR:
canonical_unit_bits = unit_bits = 8; canonical_unit_bits = unit_bits = 8;
if(cval->flags & APC_CONSTRAINED) if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits; unit_bits = cval->range_bits;
bpc = OS__BPC_CHAR; bpc = OS__BPC_CHAR;
sizeinunits = st->size; size_in_units = st->size;
break; break;
case ASN_OSUBV_U16: case ASN_OSUBV_U16:
canonical_unit_bits = unit_bits = 16; canonical_unit_bits = unit_bits = 16;
if(cval->flags & APC_CONSTRAINED) if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits; unit_bits = cval->range_bits;
bpc = OS__BPC_U16; bpc = OS__BPC_U16;
sizeinunits = st->size >> 1; size_in_units = st->size >> 1;
if(st->size & 1) { if(st->size & 1) {
ASN_DEBUG("%s string size is not modulo 2", td->name); ASN_DEBUG("%s string size is not modulo 2", td->name);
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
...@@ -1588,7 +1587,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1588,7 +1587,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
if(cval->flags & APC_CONSTRAINED) if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits; unit_bits = cval->range_bits;
bpc = OS__BPC_U32; bpc = OS__BPC_U32;
sizeinunits = st->size >> 2; size_in_units = st->size >> 2;
if(st->size & 3) { if(st->size & 3) {
ASN_DEBUG("%s string size is not modulo 4", td->name); ASN_DEBUG("%s string size is not modulo 4", td->name);
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
...@@ -1596,92 +1595,85 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1596,92 +1595,85 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
break; break;
} }
ASN_DEBUG("Encoding %s into %d units of %d bits" ASN_DEBUG("Encoding %s into %zu units of %d bits"
" (%ld..%ld, effective %d)%s", " (%ld..%ld, effective %d)%s",
td->name, sizeinunits, unit_bits, td->name, size_in_units, unit_bits,
csiz->lower_bound, csiz->upper_bound, csiz->lower_bound, csiz->upper_bound,
csiz->effective_bits, ct_extensible ? " EXT" : ""); csiz->effective_bits, ct_extensible ? " EXT" : "");
/* Figure out whether size lies within PER visible constraint */ /* Figure out whether size lies within PER visible constraint */
if(csiz->effective_bits >= 0) { if(csiz->effective_bits >= 0) {
if((int)sizeinunits < csiz->lower_bound if((ssize_t)size_in_units < csiz->lower_bound
|| (int)sizeinunits > csiz->upper_bound) { || (ssize_t)size_in_units > csiz->upper_bound) {
if(ct_extensible) { if(ct_extensible) {
cval = &asn_DEF_OCTET_STRING_constraints.value; csiz = &asn_DEF_OCTET_STRING_constraints.size;
csiz = &asn_DEF_OCTET_STRING_constraints.size; unit_bits = canonical_unit_bits;
unit_bits = canonical_unit_bits; inext = 1;
inext = 1; } else {
} else { ASN__ENCODE_FAILED;
ASN__ENCODE_FAILED; }
} }
} } else {
} else { inext = 0;
inext = 0; }
}
if(ct_extensible) { if(ct_extensible) {
/* Declare whether length is [not] within extension root */ /* Declare whether length is [not] within extension root */
if(per_put_few_bits(po, inext, 1)) if(per_put_few_bits(po, inext, 1))
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
} }
/* X.691, #16.5: zero-length encoding */ if(csiz->effective_bits >= 0 && !inext) {
/* X.691, #16.6: short fixed length encoding (up to 2 octets) */ ASN_DEBUG("Encoding %zu bytes (%ld), length in %d bits", st->size,
/* X.691, #16.7: long fixed length encoding (up to 64K octets) */ size_in_units - csiz->lower_bound, csiz->effective_bits);
if(csiz->effective_bits >= 0) { ret = per_put_few_bits(po, size_in_units - csiz->lower_bound,
ASN_DEBUG("Encoding %zu bytes (%ld), length in %d bits", csiz->effective_bits);
st->size, sizeinunits - csiz->lower_bound, if(ret) ASN__ENCODE_FAILED;
csiz->effective_bits); if(bpc) {
ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound, ret = OCTET_STRING_per_put_characters(
csiz->effective_bits); po, st->buf, size_in_units, bpc, unit_bits, cval->lower_bound,
if(ret) ASN__ENCODE_FAILED; cval->upper_bound, pc);
if(bpc) { } else {
ret = OCTET_STRING_per_put_characters(po, st->buf, assert(unit_bits == 1);
sizeinunits, bpc, unit_bits, ret = per_put_many_bits(po, st->buf, size_in_units);
cval->lower_bound, cval->upper_bound, pc); }
} else { if(ret) ASN__ENCODE_FAILED;
ret = per_put_many_bits(po, st->buf, ASN__ENCODED_OK(er);
sizeinunits * unit_bits); }
}
if(ret) ASN__ENCODE_FAILED;
ASN__ENCODED_OK(er);
}
ASN_DEBUG("Encoding %zu bytes", st->size); ASN_DEBUG("Encoding %zu bytes", st->size);
if(sizeinunits == 0) { if(size_in_units == 0) {
if(uper_put_length(po, 0)) if(uper_put_length(po, 0)) ASN__ENCODE_FAILED;
ASN__ENCODE_FAILED; ASN__ENCODED_OK(er);
ASN__ENCODED_OK(er); }
}
buf = st->buf; buf = st->buf;
while(sizeinunits) { while(size_in_units) {
ssize_t maySave = uper_put_length(po, sizeinunits); ssize_t maySave = uper_put_length(po, size_in_units);
if(maySave < 0) ASN__ENCODE_FAILED; if(maySave < 0) ASN__ENCODE_FAILED;
ASN_DEBUG("Encoding %ld of %ld", ASN_DEBUG("Encoding %ld of %ld", (long)maySave, (long)sizeinunits);
(long)maySave, (long)sizeinunits);
if(bpc) { if(bpc) {
ret = OCTET_STRING_per_put_characters(po, buf, ret = OCTET_STRING_per_put_characters(po, buf, maySave, bpc,
maySave, bpc, unit_bits, unit_bits, cval->lower_bound,
cval->lower_bound, cval->upper_bound, pc); cval->upper_bound, pc);
} else { } else {
ret = per_put_many_bits(po, buf, maySave * unit_bits); ret = per_put_many_bits(po, buf, maySave);
} }
if(ret) ASN__ENCODE_FAILED; if(ret) ASN__ENCODE_FAILED;
if(bpc) if(bpc)
buf += maySave * bpc; buf += maySave * bpc;
else else
buf += maySave >> 3; buf += maySave >> 3;
sizeinunits -= maySave; size_in_units -= maySave;
assert(!(maySave & 0x07) || !sizeinunits); assert(!(maySave & 0x07) || !size_in_units);
} }
ASN__ENCODED_OK(er); ASN__ENCODED_OK(er);
} }
#endif /* ASN_DISABLE_PER_SUPPORT */ #endif /* ASN_DISABLE_PER_SUPPORT */
...@@ -1987,10 +1979,36 @@ OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, ...@@ -1987,10 +1979,36 @@ OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
const asn_per_constraint_t *pc = const asn_per_constraint_t *pc =
&td->encoding_constraints.per_constraints->size; &td->encoding_constraints.per_constraints->size;
if(pc->flags & APC_CONSTRAINED) { if(pc->flags & APC_CONSTRAINED) {
long suggested_upper_bound =
pc->upper_bound < max_length ? pc->upper_bound : max_length;
if(max_length < (size_t)pc->lower_bound) { if(max_length < (size_t)pc->lower_bound) {
return result_skipped; return result_skipped;
} }
rnd_len = asn_random_between(pc->lower_bound, pc->upper_bound); if(pc->flags & APC_EXTENSIBLE) {
switch(asn_random_between(0, 5)) {
case 0:
if(pc->lower_bound > 0) {
rnd_len = pc->lower_bound - 1;
break;
}
/* Fall through */
case 1:
rnd_len = pc->upper_bound + 1;
break;
case 2:
/* Keep rnd_len from the table */
if(rnd_len < max_length) {
break;
}
/* Fall through */
default:
rnd_len = asn_random_between(pc->lower_bound,
suggested_upper_bound);
}
} else {
rnd_len =
asn_random_between(pc->lower_bound, suggested_upper_bound);
}
} else { } else {
rnd_len = asn_random_between(0, max_length - 1); rnd_len = asn_random_between(0, max_length - 1);
} }
......
...@@ -910,8 +910,7 @@ SET_OF_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t * ...@@ -910,8 +910,7 @@ SET_OF_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *
do { do {
int i; int i;
if(nelems < 0) { if(nelems < 0) {
nelems = uper_get_length(pd, nelems = uper_get_length(pd, -1, 0, &repeat);
ct ? ct->effective_bits : -1, &repeat);
ASN_DEBUG("Got to decode %d elements (eff %d)", ASN_DEBUG("Got to decode %d elements (eff %d)",
(int)nelems, (int)(ct ? ct->effective_bits : -1)); (int)nelems, (int)(ct ? ct->effective_bits : -1));
if(nelems < 0) ASN__DECODE_STARVED; if(nelems < 0) ASN__DECODE_STARVED;
......
...@@ -73,10 +73,10 @@ oer_decoder.h oer_decoder.c OPEN_TYPE.h # OER decoding support ...@@ -73,10 +73,10 @@ oer_decoder.h oer_decoder.c OPEN_TYPE.h # OER decoding support
oer_encoder.h oer_encoder.c # OER encoding support oer_encoder.h oer_encoder.c # OER encoding support
oer_support.h oer_support.c # OER support oer_support.h oer_support.c # OER support
OPEN_TYPE.h OPEN_TYPE_oer.c constr_CHOICE.h OPEN_TYPE.h OPEN_TYPE_oer.c constr_CHOICE.h
INTEGER_oer.c INTEGER_oer.c INTEGER.h
OCTET_STRING_oer.c OCTET_STRING_oer.c
NativeInteger_oer.c NativeInteger_oer.c NativeInteger.h
NativeEnumerated_oer.c NativeEnumerated_oer.c NativeEnumerated.h
constr_SEQUENCE_oer.c constr_SEQUENCE.h constr_SEQUENCE_oer.c constr_SEQUENCE.h
constr_CHOICE_oer.c constr_CHOICE_oer.c
constr_SET_OF_oer.c constr_SET_OF.h asn_SET_OF.h asn_SET_OF.c constr_SET_OF_oer.c constr_SET_OF.h asn_SET_OF.h asn_SET_OF.c
......
...@@ -73,7 +73,7 @@ uper_open_type_get_simple(const asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, ...@@ -73,7 +73,7 @@ uper_open_type_get_simple(const asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
ASN_DEBUG("Getting open type %s...", td->name); ASN_DEBUG("Getting open type %s...", td->name);
do { do {
chunk_bytes = uper_get_length(pd, -1, &repeat); chunk_bytes = uper_get_length(pd, -1, 0, &repeat);
if(chunk_bytes < 0) { if(chunk_bytes < 0) {
FREEMEM(buf); FREEMEM(buf);
ASN__DECODE_STARVED; ASN__DECODE_STARVED;
...@@ -329,7 +329,7 @@ uper_ugot_refill(asn_per_data_t *pd) { ...@@ -329,7 +329,7 @@ uper_ugot_refill(asn_per_data_t *pd) {
return -1; return -1;
} }
next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); next_chunk_bytes = uper_get_length(oldpd, -1, 0, &arg->repeat);
ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld", ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",
(long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat); (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);
if(next_chunk_bytes < 0) return -1; if(next_chunk_bytes < 0) return -1;
......
...@@ -12,14 +12,17 @@ ...@@ -12,14 +12,17 @@
* Get the optionally constrained length "n" from the stream. * Get the optionally constrained length "n" from the stream.
*/ */
ssize_t ssize_t
uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { uper_get_length(asn_per_data_t *pd, int ebits, size_t lower_bound,
int *repeat) {
ssize_t value; ssize_t value;
*repeat = 0; *repeat = 0;
/* #11.9.4.1 Encoding if constrained (according to effective bits) */ /* #11.9.4.1 Encoding if constrained (according to effective bits) */
if(ebits >= 0 && ebits <= 16) { if(ebits >= 0 && ebits <= 16) {
return per_get_few_bits(pd, ebits); value = per_get_few_bits(pd, ebits);
if(value >= 0) value += lower_bound;
return value;
} }
value = per_get_few_bits(pd, 8); value = per_get_few_bits(pd, 8);
...@@ -58,7 +61,7 @@ uper_get_nslength(asn_per_data_t *pd) { ...@@ -58,7 +61,7 @@ uper_get_nslength(asn_per_data_t *pd) {
return length; return length;
} else { } else {
int repeat; int repeat;
length = uper_get_length(pd, -1, &repeat); length = uper_get_length(pd, -1, 0, &repeat);
if(length >= 0 && !repeat) return length; if(length >= 0 && !repeat) return length;
return -1; /* Error, or do not support >16K extensions */ return -1; /* Error, or do not support >16K extensions */
} }
...@@ -170,23 +173,25 @@ int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int ...@@ -170,23 +173,25 @@ 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" (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) {
if(length <= 127) /* #10.9.3.6 */ if(length <= 127) /* #11.9.3.6 */
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 */
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;
length >>= 14; length >>= 14;
if(length > 4) length = 4; if(length > 4) length = 4;
return per_put_few_bits(po, 0xC0 | length, 8)
? -1 : (ssize_t)(length << 14);
return per_put_few_bits(po, 0xC0 | length, 8)
? -1 : (ssize_t)(length << 14);
} }
...@@ -199,7 +204,7 @@ int ...@@ -199,7 +204,7 @@ 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) {
/* #10.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 {
......
...@@ -43,11 +43,11 @@ typedef struct asn_bit_data_s asn_per_data_t; ...@@ -43,11 +43,11 @@ typedef struct asn_bit_data_s asn_per_data_t;
asn_get_many_bits(data, dst, align, bits) asn_get_many_bits(data, dst, align, bits)
/* /*
* X.691 (08/2015) #11.9 "General rules for encoding a length determinant"
* Get the length "n" from the Unaligned PER stream. * Get the length "n" from the Unaligned PER stream.
*/ */
ssize_t uper_get_length(asn_per_data_t *pd, ssize_t uper_get_length(asn_per_data_t *pd, int effective_bound_bits,
int effective_bound_bits, size_t lower_bound, int *repeat);
int *repeat);
/* /*
* Get the normally small length "n". * Get the normally small length "n".
...@@ -74,6 +74,7 @@ int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits); ...@@ -74,6 +74,7 @@ int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits);
int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits); int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits);
/* /*
* 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 "n" to the Unaligned PER stream.
* 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.
......
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