Commit 52b88e1b authored by Lev Walkin's avatar Lev Walkin

uper and oer SET OF and SEQUENCE OF verified

parent e5f0d94a
......@@ -149,7 +149,7 @@ SEQUENCE_OF_encode_uper(const asn_TYPE_descriptor_t *td,
const asn_per_constraint_t *ct;
asn_enc_rval_t er;
const asn_TYPE_member_t *elm = td->elements;
int seq;
size_t encoded_edx;
if(!sptr) ASN__ENCODE_FAILED;
list = _A_CSEQUENCE_FROM_VOID(sptr);
......@@ -158,59 +158,96 @@ SEQUENCE_OF_encode_uper(const asn_TYPE_descriptor_t *td,
ASN_DEBUG("Encoding %s as SEQUENCE OF (%d)", td->name, list->count);
if(constraints) ct = &constraints->size;
else if(td->encoding_constraints.per_constraints)
ct = &td->encoding_constraints.per_constraints->size;
else ct = 0;
/* If extensible constraint, check if size is in root */
if(ct) {
int not_in_root = (list->count < ct->lower_bound
|| list->count > ct->upper_bound);
ASN_DEBUG("lb %ld ub %ld %s",
ct->lower_bound, ct->upper_bound,
ct->flags & APC_EXTENSIBLE ? "ext" : "fix");
if(ct->flags & APC_EXTENSIBLE) {
/* Declare whether size is in extension root */
if(per_put_few_bits(po, not_in_root, 1))
ASN__ENCODE_FAILED;
if(not_in_root) ct = 0;
} else if(not_in_root && ct->effective_bits >= 0)
ASN__ENCODE_FAILED;
}
if(constraints) ct = &constraints->size;
else if(td->encoding_constraints.per_constraints)
ct = &td->encoding_constraints.per_constraints->size;
else ct = 0;
/* If extensible constraint, check if size is in root */
if(ct) {
int not_in_root =
(list->count < ct->lower_bound || list->count > ct->upper_bound);
ASN_DEBUG("lb %ld ub %ld %s", ct->lower_bound, ct->upper_bound,
ct->flags & APC_EXTENSIBLE ? "ext" : "fix");
if(ct->flags & APC_EXTENSIBLE) {
/* Declare whether size is in extension root */
if(per_put_few_bits(po, not_in_root, 1)) ASN__ENCODE_FAILED;
if(not_in_root) ct = 0;
} else if(not_in_root && ct->effective_bits >= 0) {
ASN__ENCODE_FAILED;
}
if(ct && ct->effective_bits >= 0) {
/* X.691, #19.5: No length determinant */
if(per_put_few_bits(po, list->count - ct->lower_bound,
ct->effective_bits))
ASN__ENCODE_FAILED;
}
if(ct && ct->effective_bits >= 0) {
/* X.691, #19.5: No length determinant */
if(per_put_few_bits(po, list->count - ct->lower_bound,
ct->effective_bits))
ASN__ENCODE_FAILED;
}
}
for(seq = -1; seq < list->count;) {
ssize_t mayEncode;
if(seq < 0) seq = 0;
if(ct && ct->effective_bits >= 0) {
mayEncode = list->count;
} else {
mayEncode = uper_put_length(po, list->count - seq, 0);
if(mayEncode < 0) ASN__ENCODE_FAILED;
}
while(mayEncode--) {
void *memb_ptr = list->array[seq++];
if(!memb_ptr) ASN__ENCODE_FAILED;
er = elm->type->op->uper_encoder(elm->type,
elm->encoding_constraints.per_constraints, memb_ptr, po);
if(er.encoded == -1)
ASN__ENCODE_FAILED;
}
}
for(encoded_edx = 0; (ssize_t)encoded_edx < list->count;) {
ssize_t may_encode;
size_t edx;
int need_eom = 0;
if(ct && ct->effective_bits >= 0) {
may_encode = list->count;
} else {
may_encode =
uper_put_length(po, list->count - encoded_edx, &need_eom);
if(may_encode < 0) ASN__ENCODE_FAILED;
}
for(edx = encoded_edx; edx < encoded_edx + may_encode; edx++) {
void *memb_ptr = list->array[edx];
if(!memb_ptr) ASN__ENCODE_FAILED;
er = elm->type->op->uper_encoder(
elm->type, elm->encoding_constraints.per_constraints, memb_ptr,
po);
if(er.encoded == -1) ASN__ENCODE_FAILED;
}
if(need_eom && uper_put_length(po, 0, 0))
ASN__ENCODE_FAILED; /* End of Message length */
encoded_edx += may_encode;
}
ASN__ENCODED_OK(er);
}
#endif /* ASN_DISABLE_PER_SUPPORT */
int
SEQUENCE_OF_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
const void *bptr) {
const asn_anonymous_sequence_ *a = _A_CSEQUENCE_FROM_VOID(aptr);
const asn_anonymous_sequence_ *b = _A_CSEQUENCE_FROM_VOID(bptr);
ssize_t idx;
if(a && b) {
ssize_t common_length = (a->count < b->count ? a->count : b->count);
for(idx = 0; idx < common_length; idx++) {
int ret = td->elements->type->op->compare_struct(
td->elements->type, a->array[idx], b->array[idx]);
if(ret) return ret;
}
if(idx < b->count) /* more elements in b */
return -1; /* a is shorter, so put it first */
if(idx < a->count) return 1;
} else if(!a) {
return -1;
} else if(!b) {
return 1;
}
return 0;
}
asn_TYPE_operation_t asn_OP_SEQUENCE_OF = {
SEQUENCE_OF_free,
SEQUENCE_OF_print,
......
......@@ -16,9 +16,14 @@ extern "C" {
* A set specialized functions dealing with the SEQUENCE OF type.
* Generally implemented using SET OF.
*/
asn_struct_compare_f SEQUENCE_OF_compare;
der_type_encoder_f SEQUENCE_OF_encode_der;
xer_type_encoder_f SEQUENCE_OF_encode_xer;
per_type_encoder_f SEQUENCE_OF_encode_uper;
extern asn_TYPE_operation_t asn_OP_SEQUENCE_OF;
#define SEQUENCE_OF_free SET_OF_free
#define SEQUENCE_OF_print SET_OF_print
#define SEQUENCE_OF_compare SET_OF_compare
#define SEQUENCE_OF_constraint SET_OF_constraint
#define SEQUENCE_OF_decode_ber SET_OF_decode_ber
#define SEQUENCE_OF_decode_xer SET_OF_decode_xer
......@@ -26,10 +31,6 @@ extern "C" {
#define SEQUENCE_OF_decode_oer SET_OF_decode_oer
#define SEQUENCE_OF_encode_oer SET_OF_encode_oer
#define SEQUENCE_OF_random_fill SET_OF_random_fill
der_type_encoder_f SEQUENCE_OF_encode_der;
xer_type_encoder_f SEQUENCE_OF_encode_xer;
per_type_encoder_f SEQUENCE_OF_encode_uper;
extern asn_TYPE_operation_t asn_OP_SEQUENCE_OF;
#ifdef __cplusplus
}
......
......@@ -340,7 +340,8 @@ SET_OF__encode_sorted_free(struct _el_buffer *el_buf, size_t count) {
}
enum SET_OF__encode_method {
SOES_DER
SOES_DER, /* Distinguished Encoding Rules */
SOES_CUPER /* Canonical Unaligned Packed Encoding Rules */
};
static struct _el_buffer *
......@@ -361,7 +362,7 @@ SET_OF__encode_sorted(const asn_TYPE_member_t *elm,
*/
for(edx = 0; edx < list->count; edx++) {
const void *memb_ptr = list->array[edx];
struct _el_buffer *encoded_el = &encoded_els[edx];
struct _el_buffer *encoding_el = &encoded_els[edx];
asn_enc_rval_t erval;
if(!memb_ptr) break;
......@@ -372,7 +373,17 @@ SET_OF__encode_sorted(const asn_TYPE_member_t *elm,
switch(method) {
case SOES_DER:
erval = elm->type->op->der_encoder(elm->type, memb_ptr, 0, elm->tag,
_el_addbytes, encoded_el);
_el_addbytes, encoding_el);
break;
case SOES_CUPER:
erval = uper_encode(elm->type,
elm->encoding_constraints.per_constraints,
memb_ptr, _el_addbytes, encoding_el);
if(erval.encoded != -1) {
size_t extra_bits = erval.encoded % 8;
assert(encoding_el->length == (size_t)(erval.encoded + 7) / 8);
encoding_el->bits_unused = (8 - extra_bits) & 0x7;
}
break;
default:
assert(!"Unreachable");
......@@ -883,6 +894,8 @@ SET_OF_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
return 0;
}
#ifndef ASN_DISABLE_PER_SUPPORT
asn_dec_rval_t
SET_OF_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *td,
......@@ -936,9 +949,9 @@ SET_OF_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
int i;
if(nelems < 0) {
nelems = uper_get_length(pd, -1, 0, &repeat);
ASN_DEBUG("Got to decode %d elements (eff %d)",
(int)nelems, (int)(ct ? ct->effective_bits : -1));
if(nelems < 0) ASN__DECODE_STARVED;
ASN_DEBUG("Got to decode %" ASN_PRI_SSIZE " elements (eff %d)",
nelems, (int)(ct ? ct->effective_bits : -1));
if(nelems < 0) ASN__DECODE_STARVED;
}
for(i = 0; i < nelems; i++) {
......@@ -973,13 +986,173 @@ SET_OF_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
return rv;
}
asn_enc_rval_t
SET_OF_encode_uper(const asn_TYPE_descriptor_t *td,
const asn_per_constraints_t *constraints, const void *sptr,
asn_per_outp_t *po) {
const asn_anonymous_set_ *list;
const asn_per_constraint_t *ct;
const asn_TYPE_member_t *elm = td->elements;
struct _el_buffer *encoded_els;
asn_enc_rval_t er;
size_t encoded_edx;
if(!sptr) ASN__ENCODE_FAILED;
list = _A_CSET_FROM_VOID(sptr);
er.encoded = 0;
ASN_DEBUG("Encoding %s as SEQUENCE OF (%d)", td->name, list->count);
if(constraints) ct = &constraints->size;
else if(td->encoding_constraints.per_constraints)
ct = &td->encoding_constraints.per_constraints->size;
else ct = 0;
/* If extensible constraint, check if size is in root */
if(ct) {
int not_in_root =
(list->count < ct->lower_bound || list->count > ct->upper_bound);
ASN_DEBUG("lb %ld ub %ld %s", ct->lower_bound, ct->upper_bound,
ct->flags & APC_EXTENSIBLE ? "ext" : "fix");
if(ct->flags & APC_EXTENSIBLE) {
/* Declare whether size is in extension root */
if(per_put_few_bits(po, not_in_root, 1)) ASN__ENCODE_FAILED;
if(not_in_root) ct = 0;
} else if(not_in_root && ct->effective_bits >= 0) {
ASN__ENCODE_FAILED;
}
if(ct && ct->effective_bits >= 0) {
/* X.691, #19.5: No length determinant */
if(per_put_few_bits(po, list->count - ct->lower_bound,
ct->effective_bits))
ASN__ENCODE_FAILED;
}
}
/*
* Canonical UPER #22.1 mandates dynamic sorting of the SET OF elements
* according to their encodings. Build an array of the encoded elements.
*/
encoded_els = SET_OF__encode_sorted(elm, list, SOES_CUPER);
for(encoded_edx = 0; (ssize_t)encoded_edx < list->count;) {
ssize_t may_encode;
ssize_t edx;
int need_eom = 0;
if(ct && ct->effective_bits >= 0) {
may_encode = list->count;
} else {
may_encode =
uper_put_length(po, list->count - encoded_edx, &need_eom);
if(may_encode < 0) ASN__ENCODE_FAILED;
}
for(edx = 0; edx < may_encode; edx++) {
const struct _el_buffer *el = &encoded_els[edx];
if(asn_put_many_bits(po, el->buf,
(8 * el->length) - el->bits_unused) < 0) {
break;
}
}
if(need_eom && uper_put_length(po, 0, 0))
ASN__ENCODE_FAILED; /* End of Message length */
encoded_edx += may_encode;
}
SET_OF__encode_sorted_free(encoded_els, list->count);
if((ssize_t)encoded_edx == list->count) {
ASN__ENCODED_OK(er);
} else {
ASN__ENCODE_FAILED;
}
}
#endif /* ASN_DISABLE_PER_SUPPORT */
struct comparable_ptr {
const asn_TYPE_descriptor_t *td;
const void *sptr;
};
static int
SET_OF__compare_cb(const void *aptr, const void *bptr) {
const struct comparable_ptr *a = aptr;
const struct comparable_ptr *b = bptr;
assert(a->td == b->td);
return a->td->op->compare_struct(a->td, a->sptr, b->sptr);
}
int
SET_OF_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
const void *bptr) {
(void)td;
(void)aptr;
(void)bptr;
/* Not implemented yet. */
const asn_anonymous_set_ *a = _A_CSET_FROM_VOID(aptr);
const asn_anonymous_set_ *b = _A_CSET_FROM_VOID(bptr);
if(a && b) {
struct comparable_ptr *asorted;
struct comparable_ptr *bsorted;
ssize_t common_length;
ssize_t idx;
if(a->count == 0) {
if(b->count) return -1;
return 0;
} else if(b->count == 0) {
return 1;
}
asorted = MALLOC(a->count * sizeof(asorted[0]));
bsorted = MALLOC(b->count * sizeof(bsorted[0]));
if(!asorted || !bsorted) {
FREEMEM(asorted);
FREEMEM(bsorted);
return -1;
}
for(idx = 0; idx < a->count; idx++) {
asorted[idx].td = td->elements->type;
asorted[idx].sptr = a->array[idx];
}
for(idx = 0; idx < b->count; idx++) {
bsorted[idx].td = td->elements->type;
bsorted[idx].sptr = b->array[idx];
}
qsort(asorted, a->count, sizeof(asorted[0]), SET_OF__compare_cb);
qsort(bsorted, b->count, sizeof(bsorted[0]), SET_OF__compare_cb);
common_length = (a->count < b->count ? a->count : b->count);
for(idx = 0; idx < common_length; idx++) {
int ret = td->elements->type->op->compare_struct(
td->elements->type, asorted[idx].sptr, bsorted[idx].sptr);
if(ret) {
FREEMEM(asorted);
FREEMEM(bsorted);
return ret;
}
}
FREEMEM(asorted);
FREEMEM(bsorted);
if(idx < b->count) /* more elements in b */
return -1; /* a is shorter, so put it first */
if(idx < a->count) return 1;
} else if(!a) {
return -1;
} else if(!b) {
return 1;
}
return 0;
}
......@@ -1004,7 +1177,7 @@ asn_TYPE_operation_t asn_OP_SET_OF = {
0,
#else
SET_OF_decode_uper,
0, /* SET_OF_encode_uper */
SET_OF_encode_uper,
#endif /* ASN_DISABLE_PER_SUPPORT */
SET_OF_random_fill,
0 /* Use generic outmost tag fetcher */
......@@ -1022,8 +1195,9 @@ SET_OF_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
const asn_TYPE_member_t *elm = td->elements;
void *st = *sptr;
long max_elements = 5;
long slb = 0; /* Lower size bound */
long sub = 5; /* Upper size bound */
long sub = 0; /* Upper size bound */
size_t rnd_len;
if(max_length == 0) return result_skipped;
......@@ -1035,21 +1209,56 @@ SET_OF_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
}
}
switch(asn_random_between(0, 6)) {
case 0: max_elements = 0; break;
case 1: max_elements = 1; break;
case 2: max_elements = 5; break;
case 3: max_elements = max_length; break;
case 4: max_elements = max_length / 2; break;
case 5: max_elements = max_length / 4; break;
default: break;
}
sub = slb + max_elements;
if(!constraints || !constraints->per_constraints)
constraints = &td->encoding_constraints;
if(constraints->per_constraints) {
const asn_per_constraint_t *pc = &constraints->per_constraints->size;
if(pc->flags & APC_SEMI_CONSTRAINED) {
slb = pc->lower_bound;
sub = pc->lower_bound + 5;
sub = pc->lower_bound + max_elements;
} else if(pc->flags & APC_CONSTRAINED) {
slb = pc->lower_bound;
sub = pc->upper_bound;
if(sub - slb > 5) sub = slb + 5;
if(sub - slb > max_elements) sub = slb + max_elements;
}
}
/* Bias towards edges of allowed space */
switch(asn_random_between(0, 4)) {
case 0:
rnd_len = asn_random_between(slb, sub);
break;
case 1:
if(slb < sub) {
rnd_len = asn_random_between(slb + 1, sub);
break;
}
/* Fall through */
case 2:
rnd_len = asn_random_between(slb, slb);
break;
case 3:
if(slb < sub) {
rnd_len = asn_random_between(slb, sub - 1);
break;
}
/* Fall through */
case 4:
rnd_len = asn_random_between(sub, sub);
break;
}
rnd_len = asn_random_between(slb, sub);
for(; rnd_len > 0; rnd_len--) {
asn_anonymous_set_ *list = _A_SET_FROM_VOID(st);
void *ptr = 0;
......@@ -1060,7 +1269,7 @@ SET_OF_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
switch(tmpres.code) {
case ARFILL_OK:
ASN_SET_ADD(list, ptr);
res_ok.length += tmpres.code;
res_ok.length += tmpres.length;
break;
case ARFILL_SKIPPED:
break;
......
......@@ -153,7 +153,6 @@ SET_OF_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
case -1:
RETURN(RC_FAIL);
default:
ASN_DEBUG("ptr[] = %02x, advancing %" ASN_PRI_SIZE ", length=%" ASN_PRI_SIZE "", *(const uint8_t *)ptr, len_size, length);
ADVANCE(len_size);
ctx->left = length;
}
......@@ -164,6 +163,8 @@ SET_OF_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
/* Decode components of the extension root */
asn_TYPE_member_t *elm = td->elements;
asn_anonymous_set_ *list = _A_SET_FROM_VOID(st);
const void *base_ptr = ptr;
ber_tlv_len_t base_ctx_left = ctx->left;
assert(td->elements_count == 1);
......@@ -181,6 +182,15 @@ SET_OF_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
RETURN(RC_FAIL);
} else {
ctx->ptr = 0;
/*
* This check is to avoid compression bomb with
* specs like SEQUENCE/SET OF NULL which don't
* consume data at all.
*/
if(rv.consumed == 0 && base_ptr == ptr
&& (base_ctx_left - ctx->left) > 200) {
ASN__DECODE_FAILED;
}
break;
}
case RC_WMORE:
......
......@@ -32,6 +32,7 @@ uper_get_length(asn_per_data_t *pd, int ebits, size_t lower_bound,
value = ((value & 0x3f) << 8) | per_get_few_bits(pd, 8);
return value; /* potential -1 from per_get_few_bits passes through. */
} else if(value < 0) {
ASN_DEBUG("END of stream reached for PER");
return -1;
}
value &= 0x3f; /* this is "m" from X.691, #11.9.3.8 */
......
......@@ -42,6 +42,7 @@ TESTS += bundles/14-GeneralizedTime-bundle.txt
TESTS += bundles/15-CHOICE-bundle.txt
TESTS += bundles/16-SEQUENCE-bundle.txt
TESTS += bundles/17-SEQUENCE-OF-bundle.txt
TESTS += bundles/19-SET-OF-bundle.txt
EXTRA_DIST = \
random-test-driver.c \
......
......@@ -77,3 +77,4 @@ SEQUENCE { ..., null NULL, ..., one [1] NULL, two BOOLEAN, three BIT STRING (SIZ
SEQUENCE { one BOOLEAN OPTIONAL, two PrintableString (SIZE(1)), three VisibleString (SIZE(1)) DEFAULT "Z" }
SEQUENCE { one [1] BOOLEAN OPTIONAL, two [2] BOOLEAN, three [3] BOOLEAN DEFAULT TRUE, four PrintableString (SIZE(1)), five VisibleString (SIZE(1)) DEFAULT "Z" }
SEQUENCE { list SEQUENCE OF PrintableString (SIZE(1)), guard OCTET STRING (SIZE(1)) } -- RMAX=16385
......@@ -27,3 +27,8 @@ SEQUENCE (SIZE(1..2)) OF PrintableString (FROM("A".."Z"))
SEQUENCE (SIZE(1..MAX)) OF PrintableString (FROM("A".."Z"))
SEQUENCE OF PrintableString (FROM("A".."Z"))
SEQUENCE OF NULL -- RMAX=70000
SEQUENCE OF BOOLEAN -- RMAX=70000
SEQUENCE (SIZE(2..MAX)) OF BOOLEAN -- RMAX=70000
SEQUENCE OF PrintableString (SIZE(1)) --RMAX=16384
SET OF NULL
SET (SIZE(0)) OF NULL
SET (SIZE(1)) OF NULL
SET (SIZE(0..2)) OF NULL
SET (SIZE(1..2)) OF NULL
SET (SIZE(1..MAX)) OF NULL
SET OF BOOLEAN
SET (SIZE(0)) OF BOOLEAN
SET (SIZE(1)) OF BOOLEAN
SET (SIZE(0..2)) OF BOOLEAN
SET (SIZE(1..2)) OF BOOLEAN
SET (SIZE(1..MAX)) OF BOOLEAN
SET OF PrintableString (SIZE(1))
SET (SIZE(0)) OF PrintableString (SIZE(1))
SET (SIZE(1)) OF PrintableString (SIZE(1))
SET (SIZE(0..2)) OF PrintableString (SIZE(1))
SET (SIZE(1..2)) OF PrintableString (SIZE(1))
SET (SIZE(1..MAX)) OF PrintableString (SIZE(1))
SET OF PrintableString (FROM("A".."Z"))
SET (SIZE(0)) OF PrintableString (FROM("A".."Z"))
SET (SIZE(1)) OF PrintableString (FROM("A".."Z"))
SET (SIZE(0..2)) OF PrintableString (FROM("A".."Z"))
SET (SIZE(1..2)) OF PrintableString (FROM("A".."Z"))
SET (SIZE(1..MAX)) OF PrintableString (FROM("A".."Z"))
SET OF PrintableString (FROM("A".."Z"))
SET OF NULL -- RMAX=70000
SET OF BOOLEAN -- RMAX=70000
SET (SIZE(2..MAX)) OF BOOLEAN -- RMAX=70000
SET OF PrintableString (SIZE(1)) --RMAX=16384
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