asn_dec_rval_t SEQUENCE_decode_uper(Allocator * allocator, asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; void *st = *sptr; /* Target structure. */ int extpresent; /* Extension additions are present */ uint8_t *opres; /* Presence of optional root members */ asn_per_data_t opmd; asn_dec_rval_t rv; int edx; (void)constraints; if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) _ASN_DECODE_FAILED; if(!st) { st = *sptr = CXX_ALLOC_WRAP CALLOC(1, specs->struct_size); if(!st) _ASN_DECODE_FAILED; } ASN_DEBUG("Decoding %s as SEQUENCE (UPER)", td->name); /* Handle extensions */ if(specs->ext_before >= 0) { extpresent = per_get_few_bits(pd, 1); if(extpresent < 0) _ASN_DECODE_STARVED; } else { extpresent = 0; } /* Prepare a place and read-in the presence bitmap */ memset(&opmd, 0, sizeof(opmd)); if(specs->roms_count) { opres = (uint8_t *)CXX_ALLOC_WRAP MALLOC(((specs->roms_count + 7) >> 3) + 1); if(!opres) _ASN_DECODE_FAILED; /* Get the presence map */ if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { CXX_ALLOC_WRAP FREEMEM(opres); _ASN_DECODE_STARVED; } opmd.buffer = opres; opmd.nbits = specs->roms_count; ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", td->name, specs->roms_count, *opres); } else {
asn_dec_rval_t SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { asn_dec_rval_t rv; asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; asn_TYPE_member_t *elm = td->elements; /* Single one */ void *st = *sptr; asn_anonymous_set_ *list; asn_per_constraint_t *ct; int repeat = 0; ssize_t nelems; if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) _ASN_DECODE_FAILED; /* * Create the target structure if it is not present already. */ if(!st) { st = *sptr = CALLOC(1, specs->struct_size); if(!st) _ASN_DECODE_FAILED; } list = _A_SET_FROM_VOID(st); /* Figure out which constraints to use */ if(constraints) ct = &constraints->size; else if(td->per_constraints) ct = &td->per_constraints->size; else ct = 0; if(ct && ct->flags & APC_EXTENSIBLE) { int value = per_get_few_bits(pd, 1); if(value < 0) _ASN_DECODE_STARVED; if(value) ct = 0; /* Not restricted! */ } if(ct && ct->effective_bits >= 0) { /* X.691, #19.5: No length determinant */ nelems = per_get_few_bits(pd, ct->effective_bits); ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", (long)nelems, ct->lower_bound, td->name); if(nelems < 0) _ASN_DECODE_STARVED; nelems += ct->lower_bound; } else { nelems = -1; } do { int i; if(nelems < 0) { nelems = uper_get_length(pd, ct ? ct->effective_bits : -1, &repeat); ASN_DEBUG("Got to decode %d elements (eff %d)", (int)nelems, (int)ct ? ct->effective_bits : -1); if(nelems < 0) _ASN_DECODE_STARVED; } for(i = 0; i < nelems; i++) { void *ptr = 0; ASN_DEBUG("SET OF %s decoding", elm->type->name); rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, elm->per_constraints, &ptr, pd); ASN_DEBUG("%s SET OF %s decoded %d, %p", td->name, elm->type->name, rv.code, ptr); if(rv.code == RC_OK) { if(ASN_SET_ADD(list, ptr) == 0) continue; ASN_DEBUG("Failed to add element into %s", td->name); /* Fall through */ rv.code = RC_FAIL; } else { ASN_DEBUG("Failed decoding %s of %s (SET OF)", elm->type->name, td->name); } if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); return rv; } nelems = -1; /* Allow uper_get_length() */ } while(repeat); ASN_DEBUG("Decoded %s as SET OF", td->name); rv.code = RC_OK; rv.consumed = 0; return rv; }
static asn_dec_rval_t uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { asn_dec_rval_t rv; ssize_t chunk_bytes; int repeat; uint8_t *buf = 0; size_t bufLen = 0; size_t bufSize = 0; asn_per_data_t spd; size_t padding; _ASN_STACK_OVERFLOW_CHECK(ctx); ASN_DEBUG("Getting open type %s...", td->name); do { chunk_bytes = uper_get_length(pd, -1, &repeat); if(chunk_bytes < 0) { FREEMEM(buf); _ASN_DECODE_STARVED; } if(bufLen + chunk_bytes > bufSize) { void *ptr; bufSize = chunk_bytes + (bufSize << 2); ptr = REALLOC(buf, bufSize); if(!ptr) { FREEMEM(buf); _ASN_DECODE_FAILED; } buf = ptr; } if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { FREEMEM(buf); _ASN_DECODE_STARVED; } bufLen += chunk_bytes; } while(repeat); ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name, (long)bufLen); memset(&spd, 0, sizeof(spd)); spd.buffer = buf; spd.nbits = bufLen << 3; ASN_DEBUG_INDENT_ADD(+4); rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); ASN_DEBUG_INDENT_ADD(-4); if(rv.code == RC_OK) { /* Check padding validity */ padding = spd.nbits - spd.nboff; if ((padding < 8 || /* X.691#10.1.3 */ (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) && per_get_few_bits(&spd, padding) == 0) { /* Everything is cool */ FREEMEM(buf); return rv; } FREEMEM(buf); if(padding >= 8) { ASN_DEBUG("Too large padding %d in open type", (int)padding); _ASN_DECODE_FAILED; } else { ASN_DEBUG("Non-zero padding"); _ASN_DECODE_FAILED; } } else { FREEMEM(buf); /* rv.code could be RC_WMORE, nonsense in this context */ rv.code = RC_FAIL; /* Noone would give us more */ } return rv; }
static asn_dec_rval_t GCC_NOTUSED uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { uper_ugot_key arg; asn_dec_rval_t rv; ssize_t padding; _ASN_STACK_OVERFLOW_CHECK(ctx); ASN_DEBUG("Getting open type %s from %s", td->name, per_data_string(pd)); arg.oldpd = *pd; arg.unclaimed = 0; arg.ot_moved = 0; arg.repeat = 1; pd->refill = uper_ugot_refill; pd->refill_key = &arg; pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ pd->moved = 0; /* This now counts the open type size in bits */ ASN_DEBUG_INDENT_ADD(+4); rv = td->uper_decoder(ctx, td, constraints, sptr, pd); ASN_DEBUG_INDENT_ADD(-4); #define UPDRESTOREPD do { \ /* buffer and nboff are valid, preserve them. */ \ pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ pd->refill = arg.oldpd.refill; \ pd->refill_key = arg.oldpd.refill_key; \ } while(0) if(rv.code != RC_OK) { UPDRESTOREPD; return rv; } ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name, per_data_string(pd), per_data_string(&arg.oldpd), (int)arg.unclaimed, (int)arg.repeat); padding = pd->moved % 8; if(padding) { int32_t pvalue; if(padding > 7) { ASN_DEBUG("Too large padding %d in open type", (int)padding); rv.code = RC_FAIL; UPDRESTOREPD; return rv; } padding = 8 - padding; ASN_DEBUG("Getting padding of %d bits", (int)padding); pvalue = per_get_few_bits(pd, padding); switch(pvalue) { case -1: ASN_DEBUG("Padding skip failed"); UPDRESTOREPD; _ASN_DECODE_STARVED; case 0: break; default: ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", (int)padding, (int)pvalue); UPDRESTOREPD; _ASN_DECODE_FAILED; } } if(pd->nboff != pd->nbits) { ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, per_data_string(pd), per_data_string(&arg.oldpd)); if(1) { UPDRESTOREPD; _ASN_DECODE_FAILED; } else { arg.unclaimed += pd->nbits - pd->nboff; } } /* Adjust pd back so it points to original data */ UPDRESTOREPD; /* Skip data not consumed by the decoder */ if(arg.unclaimed) { ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed); switch(per_skip_bits(pd, arg.unclaimed)) { case -1: ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed); _ASN_DECODE_STARVED; case 0: ASN_DEBUG("Got claim of %d", (int)arg.unclaimed); break; default: /* Padding must be blank */ ASN_DEBUG("Non-blank unconsumed padding"); _ASN_DECODE_FAILED; } arg.unclaimed = 0; } if(arg.repeat) { ASN_DEBUG("Not consumed the whole thing"); rv.code = RC_FAIL; return rv; } return rv; }
/* * The decoder of the SET type. */ asn_dec_rval_t SET_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **struct_ptr, const void *ptr, size_t size, int tag_mode) { /* * Bring closer parts of structure description. */ asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics; asn_TYPE_member_t *elements = td->elements; /* * Parts of the structure being constructed. */ void *st = *struct_ptr; /* Target structure. */ asn_struct_ctx_t *ctx; /* Decoder context */ ber_tlv_tag_t tlv_tag; /* T from TLV */ asn_dec_rval_t rval; /* Return code from subparsers */ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ int edx; /* SET element's index */ ASN_DEBUG("Decoding %s as SET", td->name); if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) _ASN_DECODE_FAILED; /* * Create the target structure if it is not present already. */ if(st == 0) { st = *struct_ptr = CALLOC(1, specs->struct_size); if(st == 0) { RETURN(RC_FAIL); } } /* * Restore parsing context. */ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); /* * Start to parse where left previously */ switch(ctx->phase) { case 0: /* * PHASE 0. * Check that the set of tags associated with given structure * perfectly fits our expectations. */ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, tag_mode, 1, &ctx->left, 0); if(rval.code != RC_OK) { ASN_DEBUG("%s tagging check failed: %d", td->name, rval.code); return rval; } if(ctx->left >= 0) ctx->left += rval.consumed; /* ?Substracted below! */ ADVANCE(rval.consumed); NEXT_PHASE(ctx); ASN_DEBUG("Structure advertised %ld bytes, " "buffer contains %ld", (long)ctx->left, (long)size); /* Fall through */ case 1: /* * PHASE 1. * From the place where we've left it previously, * try to decode the next member from the list of * this structure's elements. * Note that elements in BER may arrive out of * order, yet DER mandates that they shall arive in the * canonical order of their tags. So, there is a room * for optimization. */ for(;; ctx->step = 0) { const asn_TYPE_tag2member_t *t2m; asn_TYPE_tag2member_t key; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ ssize_t tag_len; /* Length of TLV's T */ if(ctx->step & 1) { edx = ctx->step >> 1; goto microphase2; } /* * MICROPHASE 1: Synchronize decoding. */ if(ctx->left == 0) /* * No more things to decode. * Exit out of here and check whether all mandatory * elements have been received (in the next phase). */ break; /* * Fetch the T from TLV. */ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); switch(tag_len) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { if(LEFT < 2) { if(SIZE_VIOLATION) RETURN(RC_FAIL); else RETURN(RC_WMORE); } else if(((const uint8_t *)ptr)[1] == 0) { /* * Found the terminator of the * indefinite length structure. * Invoke the generic finalization function. */ goto phase3; } } key.el_tag = tlv_tag; t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, specs->tag2el, specs->tag2el_count, sizeof(specs->tag2el[0]), _t2e_cmp); if(t2m) { /* * Found the element corresponding to the tag. */ edx = t2m->el_no; ctx->step = (edx << 1) + 1; ASN_DEBUG("Got tag %s (%s), edx %d", ber_tlv_tag_string(tlv_tag), td->name, edx); } else if(specs->extensible == 0) { ASN_DEBUG("Unexpected tag %s " "in non-extensible SET %s", ber_tlv_tag_string(tlv_tag), td->name); RETURN(RC_FAIL); } else { /* Skip this tag */ ssize_t skip; ASN_DEBUG("Skipping unknown tag %s", ber_tlv_tag_string(tlv_tag)); skip = ber_skip_length(opt_codec_ctx, BER_TLV_CONSTRUCTED(ptr), (const char *)ptr + tag_len, LEFT - tag_len); switch(skip) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } ADVANCE(skip + tag_len); continue; /* Try again with the next tag */ } /* * MICROPHASE 2: Invoke the member-specific decoder. */ microphase2: /* * Check for duplications: must not overwrite * already decoded elements. */ if(ASN_SET_ISPRESENT2((char *)st + specs->pres_offset, edx)) { ASN_DEBUG("SET %s: Duplicate element %s (%d)", td->name, elements[edx].name, edx); RETURN(RC_FAIL); } /* * Compute the position of the member inside a structure, * and also a type of containment (it may be contained * as pointer or using inline inclusion). */ if(elements[edx].flags & ATF_POINTER) { /* Member is a pointer to another structure */ memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset); } else { /* * A pointer to a pointer * holding the start of the structure */ memb_ptr = (char *)st + elements[edx].memb_offset; memb_ptr2 = &memb_ptr; } /* * Invoke the member fetch routine according to member's type */ rval = elements[edx].type->ber_decoder(opt_codec_ctx, elements[edx].type, memb_ptr2, ptr, LEFT, elements[edx].tag_mode); switch(rval.code) { case RC_OK: ASN_SET_MKPRESENT((char *)st + specs->pres_offset, edx); break; case RC_WMORE: /* More data expected */ if(!SIZE_VIOLATION) { ADVANCE(rval.consumed); RETURN(RC_WMORE); } /* Fail through */ case RC_FAIL: /* Fatal error */ RETURN(RC_FAIL); } /* switch(rval) */ ADVANCE(rval.consumed); } /* for(all structure members) */ phase3: ctx->phase = 3; /* Fall through */ case 3: case 4: /* Only 00 is expected */ ASN_DEBUG("SET %s Leftover: %ld, size = %ld", td->name, (long)ctx->left, (long)size); /* * Skip everything until the end of the SET. */ while(ctx->left) { ssize_t tl, ll; tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); switch(tl) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } /* * If expected <0><0>... */ if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { if(LEFT < 2) { if(SIZE_VIOLATION) RETURN(RC_FAIL); else RETURN(RC_WMORE); } else if(((const uint8_t *)ptr)[1] == 0) { /* * Correctly finished with <0><0>. */ ADVANCE(2); ctx->left++; ctx->phase = 4; continue; } } if(specs->extensible == 0 || ctx->phase == 4) { ASN_DEBUG("Unexpected continuation " "of a non-extensible type %s " "(ptr=%02x)", td->name, *(const uint8_t *)ptr); RETURN(RC_FAIL); } ll = ber_skip_length(opt_codec_ctx, BER_TLV_CONSTRUCTED(ptr), (const char *)ptr + tl, LEFT - tl); switch(ll) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } ADVANCE(tl + ll); } ctx->phase = 5; case 5: /* Check that all mandatory elements are present. */ if(!_SET_is_populated(td, st)) RETURN(RC_FAIL); NEXT_PHASE(ctx); }
asn_dec_rval_t CHOICE_decode_uper(Allocator * allocator, asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; asn_dec_rval_t rv; asn_per_constraint_t *ct; asn_TYPE_member_t *elm; /* CHOICE's element */ void *memb_ptr; void **memb_ptr2; void *st = *sptr; int value; if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) _ASN_DECODE_FAILED; /* * Create the target structure if it is not present already. */ if(!st) { st = *sptr = CXX_ALLOC_WRAP CALLOC(1, specs->struct_size); if(!st) _ASN_DECODE_FAILED; } if(constraints) ct = &constraints->value; else if(td->per_constraints) ct = &td->per_constraints->value; else ct = 0; if(ct && ct->flags & asn_per_constraint_s::APC_EXTENSIBLE) { value = per_get_few_bits(pd, 1); if(value < 0) _ASN_DECODE_STARVED; if(value) ct = 0; /* Not restricted */ } if(ct && ct->range_bits >= 0) { value = per_get_few_bits(pd, ct->range_bits); if(value < 0) _ASN_DECODE_STARVED; ASN_DEBUG("CHOICE %s got index %d in range %d", td->name, value, ct->range_bits); if(value > ct->upper_bound) _ASN_DECODE_FAILED; } else { if(specs->ext_start == -1) _ASN_DECODE_FAILED; value = uper_get_nsnnwn(pd); if(value < 0) _ASN_DECODE_STARVED; value += specs->ext_start; if(value >= td->elements_count) _ASN_DECODE_FAILED; } /* Adjust if canonical order is different from natural order */ if(specs->canonical_order) value = specs->canonical_order[value]; /* Set presence to be able to free it later */ _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); elm = &td->elements[value]; if(elm->flags & ATF_POINTER) { /* Member is a pointer to another structure */ memb_ptr2 = (void **)((char *)st + elm->memb_offset); } else { memb_ptr = (char *)st + elm->memb_offset; memb_ptr2 = &memb_ptr; } ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); if(ct && ct->range_bits >= 0) { rv = elm->type->uper_decoder(allocator, opt_codec_ctx, elm->type, elm->per_constraints, memb_ptr2, pd); } else { rv = uper_open_type_get(allocator, opt_codec_ctx, elm->type, elm->per_constraints, memb_ptr2, pd); } if(rv.code != RC_OK) ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d", elm->name, td->name, rv.code); return rv; }
/* * Check the set of <TL<TL<TL...>>> tags matches the definition. */ asn_dec_rval_t ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, const void *ptr, size_t size, int tag_mode, int last_tag_form, ber_tlv_len_t *last_length, int *opt_tlv_form) { ssize_t consumed_myself = 0; ssize_t tag_len; ssize_t len_len; ber_tlv_tag_t tlv_tag; ber_tlv_len_t tlv_len; ber_tlv_len_t limit_len = -1; int expect_00_terminators = 0; int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */ int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */ int tagno; /* * Make sure we didn't exceed the maximum stack size. */ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) RETURN(RC_FAIL); /* * So what does all this implicit skip stuff mean? * Imagine two types, * A ::= [5] IMPLICIT T * B ::= [2] EXPLICIT T * Where T is defined as * T ::= [4] IMPLICIT SEQUENCE { ... } * * Let's say, we are starting to decode type A, given the * following TLV stream: <5> <0>. What does this mean? * It means that the type A contains type T which is, * in turn, empty. * Remember though, that we are still in A. We cannot * just pass control to the type T decoder. Why? Because * the type T decoder expects <4> <0>, not <5> <0>. * So, we must make sure we are going to receive <5> while * still in A, then pass control to the T decoder, indicating * that the tag <4> was implicitly skipped. The decoder of T * hence will be prepared to treat <4> as valid tag, and decode * it appropriately. */ tagno = step /* Continuing where left previously */ + (tag_mode==1?-1:0) ; /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */ if(tag_mode == 0 && tagno == td->tags_count) { /* * This must be the _untagged_ ANY type, * which outermost tag isn't known in advance. * Fetch the tag and length separately. */ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); switch(tag_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } tlv_constr = BER_TLV_CONSTRUCTED(ptr); len_len = ber_fetch_length(tlv_constr, (const char *)ptr + tag_len, size - tag_len, &tlv_len); switch(len_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } ADVANCE(tag_len + len_len); } else { assert(tagno < td->tags_count); /* At least one loop */ } for((void)tagno; tagno < td->tags_count; tagno++, step++) { /* * Fetch and process T from TLV. */ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); switch(tag_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } tlv_constr = BER_TLV_CONSTRUCTED(ptr); /* * If {I}, don't check anything. * If {I,B,C}, check B and C unless we're at I. */ if(tag_mode != 0 && step == 0) { /* * We don't expect tag to match here. * It's just because we don't know how the tag * is supposed to look like. */ } else { assert(tagno >= 0); /* Guaranteed by the code above */ if(tlv_tag != td->tags[tagno]) { /* * Unexpected tag. Too bad. */ RETURN(RC_FAIL); } } /* * Attention: if there are more tags expected, * ensure that the current tag is presented * in constructed form (it contains other tags!). * If this one is the last one, check that the tag form * matches the one given in descriptor. */ if(tagno < (td->tags_count - 1)) { if(tlv_constr == 0) { RETURN(RC_FAIL); } } else { if(last_tag_form != tlv_constr && last_tag_form != -1) { RETURN(RC_FAIL); } } /* * Fetch and process L from TLV. */ len_len = ber_fetch_length(tlv_constr, (const char *)ptr + tag_len, size - tag_len, &tlv_len); switch(len_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } /* * FIXME * As of today, the chain of tags * must either contain several indefinite length TLVs, * or several definite length ones. * No mixing is allowed. */ if(tlv_len == -1) { /* * Indefinite length. */ if(limit_len == -1) { expect_00_terminators++; } else { RETURN(RC_FAIL); } ADVANCE(tag_len + len_len); continue; } else { if(expect_00_terminators) { RETURN(RC_FAIL); } } /* * Check that multiple TLVs specify ever decreasing length, * which is consistent. */ if(limit_len == -1) { limit_len = tlv_len + tag_len + len_len; if(limit_len < 0) { /* Too great tlv_len value? */ RETURN(RC_FAIL); } } else if(limit_len != tlv_len + tag_len + len_len) { /* * Inner TLV specifies length which is inconsistent * with the outer TLV's length value. */ RETURN(RC_FAIL); } ADVANCE(tag_len + len_len); limit_len -= (tag_len + len_len); if((ssize_t)size > limit_len) { /* * Make sure that we won't consume more bytes * from the parent frame than the inferred limit. */ size = limit_len; } } if(opt_tlv_form) *opt_tlv_form = tlv_constr; if(expect_00_terminators) *last_length = -expect_00_terminators; else *last_length = tlv_len; RETURN(RC_OK); }