/* * Copyright (c) 2017 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef ASN_DISABLE_OER_SUPPORT #include #include #include #include /* * This macro "eats" the part of the buffer which is definitely "consumed", * i.e. was correctly converted into local representation or rightfully skipped. */ #undef ADVANCE #define ADVANCE(num_bytes) \ do { \ size_t num = num_bytes; \ ptr = ((const char *)ptr) + num; \ size -= num; \ consumed_myself += num; \ } while(0) /* * Switch to the next phase of parsing. */ #undef NEXT_PHASE #undef PHASE_OUT #define NEXT_PHASE(ctx) \ do { \ ctx->phase++; \ ctx->step = 0; \ } while(0) /* * Check whether we are inside the extensions group. */ #define IN_EXTENSION_GROUP(specs, memb_idx) \ ((specs)->first_extension >= 0 \ && (unsigned)(specs)->first_extension <= (memb_idx)) #define IN_ROOT_GROUP_PRED(edx) \ edx < (specs->first_extension < 0 ? td->elements_count \ : (size_t)specs->first_extension) #define FOR_IN_ROOT_GROUP(edx) for(edx = 0; IN_ROOT_GROUP_PRED(edx); edx++) /* * Return a standardized complex structure. */ #undef RETURN #define RETURN(_code) do { \ rval.code = _code; \ rval.consumed = consumed_myself;\ return rval; \ } while(0) /* * Return pointer to a member. */ static void ** element_ptrptr(void *struct_ptr, asn_TYPE_member_t *elm, void **tmp_save_ptr) { if(elm->flags & ATF_POINTER) { /* Member is a pointer to another structure */ return (void **)((char *)struct_ptr + elm->memb_offset); } else { assert(tmp_save_ptr); *tmp_save_ptr = (void *)((char *)struct_ptr + elm->memb_offset); return tmp_save_ptr; } } static const void * element_ptr(const void *struct_ptr, const asn_TYPE_member_t *elm) { if(elm->flags & ATF_POINTER) { /* Member is a pointer to another structure */ return *(const void *const *)((const char *)struct_ptr + elm->memb_offset); } else { return (const void *)((const char *)struct_ptr + elm->memb_offset); } } asn_dec_rval_t SEQUENCE_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td, const asn_oer_constraints_t *constraints, void **struct_ptr, const void *ptr, size_t size) { const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics; asn_dec_rval_t rval = {RC_OK, 0}; void *st = *struct_ptr; /* Target structure */ asn_struct_ctx_t *ctx; /* Decoder context */ size_t consumed_myself = 0; /* Consumed bytes from ptr. */ (void)constraints; 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: { /* * Fetch preamble. */ asn_bit_data_t *preamble; int has_extensions_bit = (specs->first_extension >= 0); size_t preamble_bits = (has_extensions_bit + specs->roms_count); size_t preamble_bytes = ((7 + preamble_bits) >> 3); ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 0", td->name); ASN_DEBUG( "Expecting preamble bits %" ASN_PRI_SIZE " for %s (including %d extension bits)", preamble_bits, td->name, has_extensions_bit); if(preamble_bytes > size) { ASN__DECODE_STARVED; } preamble = asn_bit_data_new_contiguous(ptr, preamble_bits); if(!preamble) { RETURN(RC_FAIL); } preamble->nboff = has_extensions_bit; ctx->ptr = preamble; ADVANCE(preamble_bytes); } NEXT_PHASE(ctx); /* FALL THROUGH */ case 1: { /* Decode components of the extension root */ asn_bit_data_t *preamble = ctx->ptr; size_t edx; ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 1 (Root)", td->name); assert(preamble); for(edx = (ctx->step >> 1); IN_ROOT_GROUP_PRED(edx); edx++, ctx->step = (ctx->step & ~1) + 2) { asn_TYPE_member_t *elm = &td->elements[edx]; ASN_DEBUG("Decoding %s->%s", td->name, elm->name); assert(!IN_EXTENSION_GROUP(specs, edx)); if(ctx->step & 1) { goto microphase2_decode_continues; } if(elm->optional) { int32_t present = asn_get_few_bits(preamble, 1); if(present < 0) { ASN_DEBUG("Presence map ended prematurely: %d", present); RETURN(RC_FAIL); } else if(present == 0) { if(elm->default_value_set) { /* Fill-in DEFAULT */ void *tmp; if(elm->default_value_set( element_ptrptr(st, elm, &tmp))) { RETURN(RC_FAIL); } } /* The member is not present. */ continue; } /* Present OPTIONAL or DEFAULT component. */ } /* * MICROPHASE 2: Invoke the member-specific decoder. */ ctx->step |= 1; /* Confirm entering next microphase */ microphase2_decode_continues: if(elm->flags & ATF_OPEN_TYPE) { rval = OPEN_TYPE_oer_get(opt_codec_ctx, td, st, elm, ptr, size); } else { void *save_memb_ptr; /* Temporary reference. */ void **memb_ptr2; /* Pointer to a pointer to a memmber */ memb_ptr2 = element_ptrptr(st, elm, &save_memb_ptr); rval = elm->type->op->oer_decoder( opt_codec_ctx, elm->type, elm->encoding_constraints.oer_constraints, memb_ptr2, ptr, size); } switch(rval.code) { case RC_OK: ADVANCE(rval.consumed); break; case RC_WMORE: ASN_DEBUG("More bytes needed at element %s \"%s\"", td->name, elm->name); ADVANCE(rval.consumed); RETURN(RC_WMORE); case RC_FAIL: ASN_DEBUG("Decoding failed at element %s \"%s\"", td->name, elm->name); RETURN(RC_FAIL); } } /* for(all root members) */ } NEXT_PHASE(ctx); /* FALL THROUGH */ case 2: assert(ctx->ptr); { /* Cleanup preamble. */ asn_bit_data_t *preamble = ctx->ptr; asn_bit_data_t *extadds; int has_extensions_bit = (specs->first_extension >= 0); int extensions_present = has_extensions_bit && (preamble->buffer == NULL || (((const uint8_t *)preamble->buffer)[0] & 0x80)); uint8_t unused_bits; size_t len = 0; ssize_t len_len; ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 2", td->name); preamble->buffer = 0; /* Will do extensions_present==1 next time. */ if(!extensions_present) { ctx->phase = 10; RETURN(RC_OK); } /* * X.696 (08/2015) #16.1 (c), #16.4 * Read in the extension addition presence bitmap. */ len_len = oer_fetch_length(ptr, size, &len); if(len_len > 0) { ADVANCE(len_len); } else if(len_len < 0) { RETURN(RC_FAIL); } else { RETURN(RC_WMORE); } if(len == 0) { /* 16.4.1-2 */ RETURN(RC_FAIL); } else if(len > size) { RETURN(RC_WMORE); } /* Account for unused bits */ unused_bits = 0x7 & *(const uint8_t *)ptr; ADVANCE(1); len--; if(unused_bits && len == 0) { RETURN(RC_FAIL); } /* Get the extensions map */ extadds = asn_bit_data_new_contiguous(ptr, len * 8 - unused_bits); if(!extadds) { RETURN(RC_FAIL); } FREEMEM(preamble); ctx->ptr = extadds; ADVANCE(len); } NEXT_PHASE(ctx); ctx->step = (specs->first_extension < 0 ? td->elements_count : (size_t)specs->first_extension); /* Fall through */ case 3: ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 3 (Extensions)", td->name); for(; ctx->step < (signed)td->elements_count; ctx->step++) { asn_bit_data_t *extadds = ctx->ptr; size_t edx = ctx->step; asn_TYPE_member_t *elm = &td->elements[edx]; void *tmp_memb_ptr; void **memb_ptr2 = element_ptrptr(st, elm, &tmp_memb_ptr); switch(asn_get_few_bits(extadds, 1)) { case -1: /* * Not every one of our extensions is known to the remote side. * Continue filling in their defaults though. */ /* Fall through */ case 0: /* Fill-in DEFAULT */ if(elm->default_value_set && elm->default_value_set(memb_ptr2)) { RETURN(RC_FAIL); } continue; case 1: { /* Read OER open type */ ssize_t ot_size = oer_open_type_get(opt_codec_ctx, elm->type, elm->encoding_constraints.oer_constraints, memb_ptr2, ptr, size); assert(ot_size <= (ssize_t)size); if(ot_size > 0) { ADVANCE(ot_size); } else if(ot_size < 0) { RETURN(RC_FAIL); } else { /* Roll back open type parsing */ asn_get_undo(extadds, 1); RETURN(RC_WMORE); } break; } default: RETURN(RC_FAIL); } } NEXT_PHASE(ctx); /* Fall through */ case 4: ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 4", td->name); /* Read in the rest of Open Types while ignoring them */ for(;;) { asn_bit_data_t *extadds = ctx->ptr; switch(asn_get_few_bits(extadds, 1)) { case 0: continue; case 1: { ssize_t skipped = oer_open_type_skip(ptr, size); if(skipped > 0) { ADVANCE(skipped); } else if(skipped < 0) { RETURN(RC_FAIL); } else { asn_get_undo(extadds, 1); RETURN(RC_WMORE); } continue; } case -1: /* No more Open Type encoded components */ break; default: RETURN(RC_FAIL); } break; } } RETURN(RC_OK); } /* * Encode as Canonical OER. */ asn_enc_rval_t SEQUENCE_encode_oer(const asn_TYPE_descriptor_t *td, const asn_oer_constraints_t *constraints, const void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics; size_t computed_size = 0; int has_extensions_bit = (specs->first_extension >= 0); size_t preamble_bits = (has_extensions_bit + specs->roms_count); uint32_t has_extensions = 0; size_t edx; int ret; (void)constraints; if(preamble_bits) { asn_bit_outp_t preamble; memset(&preamble, 0, sizeof(preamble)); preamble.output = cb; preamble.op_key = app_key; if(has_extensions_bit) { for(edx = specs->first_extension; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; const void *memb_ptr = element_ptr(sptr, elm); if(memb_ptr) { if(elm->default_value_cmp && elm->default_value_cmp(memb_ptr) == 0) { /* Do not encode default values in extensions */ } else { has_extensions = 1; break; } } } ret = asn_put_few_bits(&preamble, has_extensions, 1); assert(ret == 0); if(ret < 0) { ASN__ENCODE_FAILED; } } /* * Encode optional components bitmap. */ if(specs->roms_count) { FOR_IN_ROOT_GROUP(edx) { asn_TYPE_member_t *elm = &td->elements[edx]; if(IN_EXTENSION_GROUP(specs, edx)) break; if(elm->optional) { const void *memb_ptr = element_ptr(sptr, elm); uint32_t has_component = memb_ptr != NULL; if(has_component && elm->default_value_cmp && elm->default_value_cmp(memb_ptr) == 0) { has_component = 0; } ret = asn_put_few_bits(&preamble, has_component, 1); if(ret < 0) { ASN__ENCODE_FAILED; } } } } asn_put_aligned_flush(&preamble); computed_size += preamble.flushed_bytes; } /* if(preamble_bits) */ /* * Put root components and extensions root. */ for(edx = 0; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; asn_enc_rval_t er = {0,0,0}; const void *memb_ptr; if(IN_EXTENSION_GROUP(specs, edx)) break; memb_ptr = element_ptr(sptr, elm); if(memb_ptr) { if(elm->default_value_cmp && elm->default_value_cmp(memb_ptr) == 0) { /* Skip default values in encoding */ continue; } } else { if(elm->optional) continue; /* Mandatory element is missing */ ASN__ENCODE_FAILED; } if(!elm->type->op->oer_encoder) { ASN_DEBUG("OER encoder is not defined for type %s", elm->type->name); ASN__ENCODE_FAILED; } er = elm->type->op->oer_encoder( elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb, app_key); if(er.encoded == -1) { ASN_DEBUG("... while encoding %s member \"%s\"\n", td->name, elm->name); return er; } computed_size += er.encoded; } /* * Before encode extensions, encode extensions additions presense bitmap # X.696 (08/2015) #16.4. */ if(has_extensions) { asn_bit_outp_t extadds; /* Special case allowing us to use exactly one byte for #8.6 */ size_t aoms_length_bits = specs->aoms_count; size_t aoms_length_bytes = (7 + aoms_length_bits) >> 3; uint8_t unused_bits = 0x07 & (8 - (aoms_length_bits & 0x07)); assert(1 + aoms_length_bytes <= 127); memset(&extadds, 0, sizeof(extadds)); extadds.output = cb; extadds.op_key = app_key; /* #8.6 length determinant */ ret = asn_put_few_bits(&extadds, (1 + aoms_length_bytes), 8); if(ret < 0) ASN__ENCODE_FAILED; /* Number of unused bytes, #16.4.2 */ ret = asn_put_few_bits(&extadds, unused_bits, 8); if(ret < 0) ASN__ENCODE_FAILED; /* Encode presence bitmap #16.4.3 */ for(edx = specs->first_extension; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; const void *memb_ptr = element_ptr(sptr, elm); if(memb_ptr && elm->default_value_cmp && elm->default_value_cmp(memb_ptr) == 0) { memb_ptr = 0; /* Do not encode default value. */ } ret |= asn_put_few_bits(&extadds, memb_ptr ? 1 : 0, 1); } if(ret < 0) ASN__ENCODE_FAILED; asn_put_aligned_flush(&extadds); computed_size += extadds.flushed_bytes; /* Now, encode extensions */ for(edx = specs->first_extension; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; const void *memb_ptr = element_ptr(sptr, elm); if(memb_ptr) { if(elm->default_value_cmp && elm->default_value_cmp(memb_ptr) == 0) { /* Do not encode default value. */ } else { ssize_t wrote = oer_open_type_put( elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb, app_key); if(wrote == -1) { ASN__ENCODE_FAILED; } computed_size += wrote; } } else if(!elm->optional) { ASN__ENCODE_FAILED; } } } /* if(has_extensions) */ { asn_enc_rval_t er = {0, 0, 0}; er.encoded = computed_size; ASN__ENCODED_OK(er); } } #endif /* ASN_DISABLE_OER_SUPPORT */