X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/46b0747592074017ff0ea4b33d4a7194235886e5..1cb912e4f90473f78d2f0f10ab5c9b2c5bd36440:/libs/smux/OCTET_STRING.c diff --git a/libs/smux/OCTET_STRING.c b/libs/smux/OCTET_STRING.c index 9e9694b5..a6928516 100644 --- a/libs/smux/OCTET_STRING.c +++ b/libs/smux/OCTET_STRING.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * Copyright (c) 2003-2017 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -11,39 +11,53 @@ /* * OCTET STRING basic type description. */ -static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { +static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) }; -static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { +asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs = { sizeof(OCTET_STRING_t), offsetof(OCTET_STRING_t, _asn_ctx), - 0 + ASN_OSUBV_STR }; -static asn_per_constraint_t asn_DEF_OCTET_STRING_constraint = { - APC_SEMI_CONSTRAINED, -1, -1, 0, 0 -}; -asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { - "OCTET STRING", /* Canonical name */ - "OCTET_STRING", /* XML tag name */ + +asn_TYPE_operation_t asn_OP_OCTET_STRING = { OCTET_STRING_free, - OCTET_STRING_print, /* non-ascii stuff, generally */ - asn_generic_no_constraint, + OCTET_STRING_print, /* OCTET STRING generally means a non-ascii sequence */ + OCTET_STRING_compare, OCTET_STRING_decode_ber, OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + OCTET_STRING_decode_oer, + OCTET_STRING_encode_oer, +#endif /* ASN_DISABLE_OER_SUPPORT */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else OCTET_STRING_decode_uper, /* Unaligned PER decoder */ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ - 0, /* Use generic outmost tag fetcher */ +#endif /* ASN_DISABLE_PER_SUPPORT */ + OCTET_STRING_random_fill, + 0 /* Use generic outmost tag fetcher */ +}; +asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { + "OCTET STRING", /* Canonical name */ + "OCTET_STRING", /* XML tag name */ + &asn_OP_OCTET_STRING, asn_DEF_OCTET_STRING_tags, sizeof(asn_DEF_OCTET_STRING_tags) / sizeof(asn_DEF_OCTET_STRING_tags[0]), asn_DEF_OCTET_STRING_tags, /* Same as above */ sizeof(asn_DEF_OCTET_STRING_tags) / sizeof(asn_DEF_OCTET_STRING_tags[0]), - 0, /* No PER visible constraints */ + { 0, 0, asn_generic_no_constraint }, 0, 0, /* No members */ - &asn_DEF_OCTET_STRING_specs + &asn_SPC_OCTET_STRING_specs }; #undef _CH_PHASE @@ -102,15 +116,6 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { st->size = _es; \ } while(0) -/* - * Internal variant of the OCTET STRING. - */ -typedef enum OS_type { - _TT_GENERIC = 0, /* Just a random OCTET STRING */ - _TT_BIT_STRING = 1, /* BIT STRING type, a special case */ - _TT_ANY = 2 /* ANY type, a special case too */ -} OS_type_e; - /* * The main reason why ASN.1 is still alive is that too much time and effort * is necessary for learning it more or less adequately, thus creating a gut @@ -118,14 +123,14 @@ typedef enum OS_type { * No, I am not going to explain what the following stuff is. */ struct _stack_el { - ber_tlv_len_t left; /* What's left to read (or -1) */ - ber_tlv_len_t got; /* What was actually processed */ - int cont_level; /* Depth of subcontainment */ - int want_nulls; /* Want null "end of content" octets? */ - int bits_chopped; /* Flag in BIT STRING mode */ - ber_tlv_tag_t tag; /* For debugging purposes */ - struct _stack_el *prev; - struct _stack_el *next; + ber_tlv_len_t left; /* What's left to read (or -1) */ + ber_tlv_len_t got; /* What was actually processed */ + unsigned cont_level; /* Depth of subcontainment */ + int want_nulls; /* Want null "end of content" octets? */ + int bits_chopped; /* Flag in BIT STRING mode */ + ber_tlv_tag_t tag; /* For debugging purposes */ + struct _stack_el *prev; + struct _stack_el *next; }; struct _stack { struct _stack_el *tail; @@ -164,7 +169,7 @@ OS__add_stack_el(struct _stack *st) { } static struct _stack * -_new_stack() { +_new_stack(void) { return (struct _stack *)CALLOC(1, sizeof(struct _stack)); } @@ -172,12 +177,12 @@ _new_stack() { * Decode OCTET STRING type. */ asn_dec_rval_t -OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, - asn_TYPE_descriptor_t *td, - void **sptr, const void *buf_ptr, size_t size, int tag_mode) { - asn_OCTET_STRING_specifics_t *specs = td->specifics - ? (asn_OCTET_STRING_specifics_t *)td->specifics - : &asn_DEF_OCTET_STRING_specs; +OCTET_STRING_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const void *buf_ptr, size_t size, int tag_mode) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; BIT_STRING_t *st = (BIT_STRING_t *)*sptr; asn_dec_rval_t rval; asn_struct_ctx_t *ctx; @@ -185,11 +190,11 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, struct _stack *stck; /* Expectations stack structure */ struct _stack_el *sel = 0; /* Stack element */ int tlv_constr; - OS_type_e type_variant = (OS_type_e)specs->subvariant; + enum asn_OS_Subvariant type_variant = specs->subvariant; ASN_DEBUG("Decoding %s as %s (frame %ld)", td->name, - (type_variant == _TT_GENERIC) ? + (type_variant == ASN_OSUBV_STR) ? "OCTET STRING" : "OS-SpecialCase", (long)size); @@ -220,9 +225,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, * Complex operation, requires stack of expectations. */ ctx->ptr = _new_stack(); - if(ctx->ptr) { - stck = (struct _stack *)ctx->ptr; - } else { + if(!ctx->ptr) { RETURN(RC_FAIL); } } else { @@ -230,7 +233,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, * Jump into stackless primitive decoding. */ _CH_PHASE(ctx, 3); - if(type_variant == _TT_ANY && tag_mode != 1) + if(type_variant == ASN_OSUBV_ANY && tag_mode != 1) APPEND(buf_ptr, rval.consumed); ADVANCE(rval.consumed); goto phase3; @@ -251,11 +254,11 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, ber_tlv_tag_t expected_tag; ssize_t tl, ll, tlvl; /* This one works even if (sel->left == -1) */ - ssize_t Left = ((!sel||(size_t)sel->left >= size) - ?(ssize_t)size:sel->left); + size_t Left = ((!sel||(size_t)sel->left >= size) + ?size:(size_t)sel->left); - ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel, + ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", (void *)sel, (long)(sel?sel->left:0), (long)(sel?sel->want_nulls:0), (long)(sel?sel->got:0) @@ -309,7 +312,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); - if(type_variant == _TT_ANY + if(type_variant == ASN_OSUBV_ANY && (tag_mode != 1 || sel->cont_level)) APPEND("\0\0", 2); @@ -334,13 +337,13 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, * depending on ASN.1 type being decoded. */ switch(type_variant) { - case _TT_BIT_STRING: + case ASN_OSUBV_BIT: /* X.690: 8.6.4.1, NOTE 2 */ /* Fall through */ - case _TT_GENERIC: + case ASN_OSUBV_STR: default: if(sel) { - int level = sel->cont_level; + unsigned level = sel->cont_level; if(level < td->all_tags_count) { expected_tag = td->all_tags[level]; break; @@ -352,7 +355,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, /* else, Fall through */ } /* Fall through */ - case _TT_ANY: + case ASN_OSUBV_ANY: expected_tag = tlv_tag; break; } @@ -397,13 +400,13 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, } else { sel->left = tlv_len; } - if(type_variant == _TT_ANY + if(type_variant == ASN_OSUBV_ANY && (tag_mode != 1 || sel->cont_level)) APPEND(buf_ptr, tlvl); sel->got += tlvl; ADVANCE(tlvl); - ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d", + ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%u", (long)sel->got, (long)sel->left, sel->want_nulls, sel->cont_level); @@ -431,7 +434,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, len = ((ber_tlv_len_t)size < sel->left) ? (ber_tlv_len_t)size : sel->left; if(len > 0) { - if(type_variant == _TT_BIT_STRING + if(type_variant == ASN_OSUBV_BIT && sel->bits_chopped == 0) { /* Put the unused-bits-octet away */ st->bits_unused = *(const uint8_t *)buf_ptr; @@ -464,7 +467,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, if(size < (size_t)ctx->left) { if(!size) RETURN(RC_WMORE); - if(type_variant == _TT_BIT_STRING && !ctx->context) { + if(type_variant == ASN_OSUBV_BIT && !ctx->context) { st->bits_unused = *(const uint8_t *)buf_ptr; ctx->left--; ADVANCE(1); @@ -475,7 +478,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, ADVANCE(size); RETURN(RC_WMORE); } else { - if(type_variant == _TT_BIT_STRING + if(type_variant == ASN_OSUBV_BIT && !ctx->context && ctx->left) { st->bits_unused = *(const uint8_t *)buf_ptr; ctx->left--; @@ -492,7 +495,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, if(sel) { ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld", - sel->prev, sel->want_nulls, + (void *)sel->prev, sel->want_nulls, (long)sel->left, (long)sel->got, (long)size); if(sel->prev || sel->want_nulls > 1 || sel->left > 0) { RETURN(RC_WMORE); @@ -502,14 +505,23 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, /* * BIT STRING-specific processing. */ - if(type_variant == _TT_BIT_STRING && st->size) { - /* Finalize BIT STRING: zero out unused bits. */ - st->buf[st->size-1] &= 0xff << st->bits_unused; + if(type_variant == ASN_OSUBV_BIT) { + if(st->size) { + if(st->bits_unused < 0 || st->bits_unused > 7) { + RETURN(RC_FAIL); + } + /* Finalize BIT STRING: zero out unused bits. */ + st->buf[st->size-1] &= 0xff << st->bits_unused; + } else { + if(st->bits_unused) { + RETURN(RC_FAIL); + } + } } ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", (long)consumed_myself, td->name, - (type_variant == _TT_GENERIC) ? (char *)st->buf : "", + (type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "", (long)st->size); @@ -520,15 +532,15 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, * Encode OCTET STRING type using DER. */ asn_enc_rval_t -OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, - int tag_mode, ber_tlv_tag_t tag, - asn_app_consume_bytes_f *cb, void *app_key) { - asn_enc_rval_t er; - asn_OCTET_STRING_specifics_t *specs = td->specifics - ? (asn_OCTET_STRING_specifics_t *)td->specifics - : &asn_DEF_OCTET_STRING_specs; - BIT_STRING_t *st = (BIT_STRING_t *)sptr; - OS_type_e type_variant = (OS_type_e)specs->subvariant; +OCTET_STRING_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + enum asn_OS_Subvariant type_variant = specs->subvariant; int fix_last_byte = 0; ASN_DEBUG("%s %s as OCTET STRING", @@ -537,10 +549,11 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, /* * Write tags. */ - if(type_variant != _TT_ANY || tag_mode == 1) { + if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) { er.encoded = der_write_tags(td, - (type_variant == _TT_BIT_STRING) + st->size, - tag_mode, type_variant == _TT_ANY, tag, cb, app_key); + (type_variant == ASN_OSUBV_BIT) + st->size, + tag_mode, type_variant == ASN_OSUBV_ANY, tag, + cb, app_key); if(er.encoded == -1) { er.failed_type = td; er.structure_ptr = sptr; @@ -548,54 +561,53 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, } } else { /* Disallow: [] IMPLICIT ANY */ - assert(type_variant != _TT_ANY || tag_mode != -1); + assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1); er.encoded = 0; } if(!cb) { - er.encoded += (type_variant == _TT_BIT_STRING) + st->size; - _ASN_ENCODED_OK(er); + er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size; + ASN__ENCODED_OK(er); } /* * Prepare to deal with the last octet of BIT STRING. */ - if(type_variant == _TT_BIT_STRING) { + if(type_variant == ASN_OSUBV_BIT) { uint8_t b = st->bits_unused & 0x07; if(b && st->size) fix_last_byte = 1; - _ASN_CALLBACK(&b, 1); - er.encoded++; + ASN__CALLBACK(&b, 1); } /* Invoke callback for the main part of the buffer */ - _ASN_CALLBACK(st->buf, st->size - fix_last_byte); + ASN__CALLBACK(st->buf, st->size - fix_last_byte); /* The last octet should be stripped off the unused bits */ if(fix_last_byte) { uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused); - _ASN_CALLBACK(&b, 1); + ASN__CALLBACK(&b, 1); } - er.encoded += st->size; - _ASN_ENCODED_OK(er); + ASN__ENCODED_OK(er); cb_failed: - _ASN_ENCODE_FAILED; + ASN__ENCODE_FAILED; } asn_enc_rval_t -OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, - int ilevel, enum xer_encoder_flags_e flags, - asn_app_consume_bytes_f *cb, void *app_key) { - static const char *h2c = "0123456789ABCDEF"; +OCTET_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; asn_enc_rval_t er; char scratch[16 * 3 + 4]; char *p = scratch; uint8_t *buf; uint8_t *end; + size_t i; - if(!st || !st->buf) - _ASN_ENCODE_FAILED; + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; er.encoded = 0; @@ -608,24 +620,20 @@ OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, char *scend = scratch + (sizeof(scratch) - 2); for(; buf < end; buf++) { if(p >= scend) { - _ASN_CALLBACK(scratch, p - scratch); - er.encoded += p - scratch; + ASN__CALLBACK(scratch, p - scratch); p = scratch; } *p++ = h2c[(*buf >> 4) & 0x0F]; *p++ = h2c[*buf & 0x0F]; } - _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ - er.encoded += p - scratch; + ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */ } else { - size_t i; for(i = 0; buf < end; buf++, i++) { if(!(i % 16) && (i || st->size > 16)) { - _ASN_CALLBACK(scratch, p-scratch); - er.encoded += (p-scratch); + ASN__CALLBACK(scratch, p-scratch); p = scratch; - _i_ASN_TEXT_INDENT(1, ilevel); + ASN__TEXT_INDENT(1, ilevel); } *p++ = h2c[(*buf >> 4) & 0x0F]; *p++ = h2c[*buf & 0x0F]; @@ -633,20 +641,19 @@ OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, } if(p - scratch) { p--; /* Remove the tail space */ - _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ - er.encoded += p - scratch; + ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */ if(st->size > 16) - _i_ASN_TEXT_INDENT(1, ilevel-1); + ASN__TEXT_INDENT(1, ilevel-1); } } - _ASN_ENCODED_OK(er); + ASN__ENCODED_OK(er); cb_failed: - _ASN_ENCODE_FAILED; + ASN__ENCODE_FAILED; } -static struct OCTET_STRING__xer_escape_table_s { - char *string; +static const struct OCTET_STRING__xer_escape_table_s { + const char *string; int size; } OCTET_STRING__xer_escape_table[] = { #define OSXET(s) { s, sizeof(s) - 1 } @@ -708,7 +715,7 @@ OS__check_escaped_control_char(const void *buf, int size) { * nested table lookups). */ for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { - struct OCTET_STRING__xer_escape_table_s *el; + const struct OCTET_STRING__xer_escape_table_s *el; el = &OCTET_STRING__xer_escape_table[i]; if(el->size == size && memcmp(buf, el->string, size) == 0) return i; @@ -739,10 +746,10 @@ OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size } asn_enc_rval_t -OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, - int ilevel, enum xer_encoder_flags_e flags, - asn_app_consume_bytes_f *cb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; +OCTET_STRING_encode_xer_utf8(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; asn_enc_rval_t er; uint8_t *buf, *end; uint8_t *ss; /* Sequence start */ @@ -751,8 +758,8 @@ OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, (void)ilevel; /* Unused argument */ (void)flags; /* Unused argument */ - if(!st || !st->buf) - _ASN_ENCODE_FAILED; + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; buf = st->buf; end = buf + st->size; @@ -769,7 +776,7 @@ OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, if(((buf - ss) && cb(ss, buf - ss, app_key) < 0) || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, app_key) < 0) - _ASN_ENCODE_FAILED; + ASN__ENCODE_FAILED; encoded_len += (buf - ss) + s_len; ss = buf + 1; } @@ -777,10 +784,10 @@ OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, encoded_len += (buf - ss); if((buf - ss) && cb(ss, buf - ss, app_key) < 0) - _ASN_ENCODE_FAILED; + ASN__ENCODE_FAILED; er.encoded = encoded_len; - _ASN_ENCODED_OK(er); + ASN__ENCODED_OK(er); } /* @@ -796,8 +803,8 @@ static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_b uint8_t *buf; /* Reallocate buffer according to high cap estimation */ - ssize_t _ns = st->size + (chunk_size + 1) / 2; - void *nptr = REALLOC(st->buf, _ns + 1); + size_t new_size = st->size + (chunk_size + 1) / 2; + void *nptr = REALLOC(st->buf, new_size + 1); if(!nptr) return -1; st->buf = (uint8_t *)nptr; buf = st->buf + st->size; @@ -854,7 +861,7 @@ static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_b } st->size = buf - st->buf; /* Adjust the buffer size */ - assert(st->size <= _ns); + assert(st->size <= new_size); st->buf[st->size] = 0; /* Courtesy termination */ return (chunk_stop - (const char *)chunk_buf); /* Converted size */ @@ -871,8 +878,8 @@ static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, s uint8_t *buf; /* Reallocate buffer according to high cap estimation */ - ssize_t _ns = st->size + (chunk_size + 7) / 8; - void *nptr = REALLOC(st->buf, _ns + 1); + size_t new_size = st->size + (chunk_size + 7) / 8; + void *nptr = REALLOC(st->buf, new_size + 1); if(!nptr) return -1; st->buf = (uint8_t *)nptr; buf = st->buf + st->size; @@ -916,7 +923,7 @@ static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, s st->bits_unused = bits_unused; } - assert(st->size <= _ns); + assert(st->size <= new_size); st->buf[st->size] = 0; /* Courtesy termination */ return chunk_size; /* Converted in full */ @@ -927,16 +934,13 @@ static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, s */ static int OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { + const int32_t last_unicode_codepoint = 0x10ffff; int32_t val = 0; const char *p; for(p = buf; p < end; p++) { int ch = *p; - /* Strange huge value */ - if((val * base + base) < 0) - return -1; - switch(ch) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ @@ -956,6 +960,11 @@ OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { default: return -1; /* Character set error */ } + + /* Value exceeds the Unicode range. */ + if(val > last_unicode_codepoint) { + return -1; + } } *ret_value = -1; @@ -965,15 +974,17 @@ OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { /* * Convert from the plain UTF-8 format, expanding entity references: "2 < 3" */ -static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { - OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; +static ssize_t +OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, + size_t chunk_size, int have_more) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; const char *p = (const char *)chunk_buf; const char *pend = p + chunk_size; uint8_t *buf; /* Reallocate buffer */ - ssize_t _ns = st->size + chunk_size; - void *nptr = REALLOC(st->buf, _ns + 1); + size_t new_size = st->size + chunk_size; + void *nptr = REALLOC(st->buf, new_size + 1); if(!nptr) return -1; st->buf = (uint8_t *)nptr; buf = st->buf + st->size; @@ -1096,7 +1107,7 @@ static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, } st->size = buf - st->buf; - assert(st->size <= _ns); + assert(st->size <= new_size); st->buf[st->size] = 0; /* Courtesy termination */ return chunk_size; /* Converted in full */ @@ -1106,19 +1117,17 @@ static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, * Decode OCTET STRING from the XML element's body. */ static asn_dec_rval_t -OCTET_STRING__decode_xer(asn_codec_ctx_t *opt_codec_ctx, - asn_TYPE_descriptor_t *td, void **sptr, - const char *opt_mname, const void *buf_ptr, size_t size, - int (*opt_unexpected_tag_decoder) - (void *struct_ptr, const void *chunk_buf, size_t chunk_size), - ssize_t (*body_receiver) - (void *struct_ptr, const void *chunk_buf, size_t chunk_size, - int have_more) -) { - OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; - asn_OCTET_STRING_specifics_t *specs = td->specifics - ? (asn_OCTET_STRING_specifics_t *)td->specifics - : &asn_DEF_OCTET_STRING_specs; +OCTET_STRING__decode_xer( + const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td, + void **sptr, const char *opt_mname, const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder)(void *struct_ptr, const void *chunk_buf, + size_t chunk_size), + ssize_t (*body_receiver)(void *struct_ptr, const void *chunk_buf, + size_t chunk_size, int have_more)) { + OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; asn_struct_ctx_t *ctx; /* Per-structure parser context */ asn_dec_rval_t rval; /* Return value from the decoder */ @@ -1166,10 +1175,11 @@ sta_failed: * Decode OCTET STRING from the hexadecimal data. */ asn_dec_rval_t -OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx, - asn_TYPE_descriptor_t *td, void **sptr, - const char *opt_mname, const void *buf_ptr, size_t size) { - return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, +OCTET_STRING_decode_xer_hex(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, + size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal); } @@ -1177,10 +1187,11 @@ OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx, * Decode OCTET STRING from the binary (0/1) data. */ asn_dec_rval_t -OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx, - asn_TYPE_descriptor_t *td, void **sptr, - const char *opt_mname, const void *buf_ptr, size_t size) { - return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, +OCTET_STRING_decode_xer_binary(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, + size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, buf_ptr, size, 0, OCTET_STRING__convert_binary); } @@ -1188,61 +1199,245 @@ OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx, * Decode OCTET STRING from the string (ASCII/UTF-8) data. */ asn_dec_rval_t -OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx, - asn_TYPE_descriptor_t *td, void **sptr, - const char *opt_mname, const void *buf_ptr, size_t size) { - return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, +OCTET_STRING_decode_xer_utf8(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, + size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, buf_ptr, size, OCTET_STRING__handle_control_chars, OCTET_STRING__convert_entrefs); } +#ifndef ASN_DISABLE_PER_SUPPORT + +static int +OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, + long lb, long ub, const asn_per_constraints_t *pc) { + uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", + (int)units, lb, ub, unit_bits); + + /* X.691: 27.5.4 */ + if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + /* Decode without translation */ + lb = 0; + } else if(pc && pc->code2value) { + if(unit_bits > 16) + return 1; /* FATAL: can't have constrained + * UniversalString with more than + * 16 million code points */ + for(; buf < end; buf += bpc) { + int value; + int code = per_get_few_bits(po, unit_bits); + if(code < 0) return -1; /* WMORE */ + value = pc->code2value(code); + if(value < 0) { + ASN_DEBUG("Code %d (0x%02x) is" + " not in map (%ld..%ld)", + code, code, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = value; break; + case 2: buf[0] = value >> 8; buf[1] = value; break; + case 4: buf[0] = value >> 24; buf[1] = value >> 16; + buf[2] = value >> 8; buf[3] = value; break; + } + } + return 0; + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_get_many_bits(po, buf, 0, unit_bits * units); + } + + for(; buf < end; buf += bpc) { + int32_t code = per_get_few_bits(po, unit_bits); + int32_t ch = code + lb; + if(code < 0) return -1; /* WMORE */ + if(ch > ub) { + ASN_DEBUG("Code %d is out of range (%ld..%ld)", + ch, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = ch; break; + case 2: buf[0] = ch >> 8; buf[1] = ch; break; + case 4: buf[0] = ch >> 24; buf[1] = ch >> 16; + buf[2] = ch >> 8; buf[3] = ch; break; + } + } + + return 0; +} + +static int +OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, + long lb, long ub, const asn_per_constraints_t *pc) { + const uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)", + (int)units, lb, ub, unit_bits, bpc); + + /* X.691: 27.5.4 */ + if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + /* Encode as is */ + lb = 0; + } else if(pc && pc->value2code) { + for(; buf < end; buf += bpc) { + int code; + uint32_t value; + switch(bpc) { + case 1: value = *(const uint8_t *)buf; break; + case 2: value = (buf[0] << 8) | buf[1]; break; + case 4: value = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; break; + default: return -1; + } + code = pc->value2code(value); + if(code < 0) { + ASN_DEBUG("Character %d (0x%02x) is" + " not in map (%ld..%ld)", + *buf, *buf, lb, ub); + return -1; + } + if(per_put_few_bits(po, code, unit_bits)) + return -1; + } + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_put_many_bits(po, buf, unit_bits * units); + } + + for(ub -= lb; buf < end; buf += bpc) { + int ch; + uint32_t value; + switch(bpc) { + case 1: + value = *(const uint8_t *)buf; + break; + case 2: + value = (buf[0] << 8) | buf[1]; + break; + case 4: + value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + break; + default: + return -1; + } + ch = value - lb; + if(ch < 0 || ch > ub) { + ASN_DEBUG("Character %d (0x%02x) is out of range (%ld..%ld)", *buf, + value, lb, ub + lb); + return -1; + } + if(per_put_few_bits(po, ch, unit_bits)) return -1; + } + + return 0; +} + +static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = { + { APC_CONSTRAINED, 8, 8, 0, 255 }, + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, + 0, 0 +}; + asn_dec_rval_t -OCTET_STRING_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_OCTET_STRING_specifics_t *specs = td->specifics - ? (asn_OCTET_STRING_specifics_t *)td->specifics - : &asn_DEF_OCTET_STRING_specs; - asn_per_constraint_t *ct = constraints ? &constraints->size - : (td->per_constraints - ? &td->per_constraints->size - : &asn_DEF_OCTET_STRING_constraint); +OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const asn_per_constraints_t *pc = + constraints ? constraints : td->encoding_constraints.per_constraints; + const asn_per_constraint_t *cval; + const asn_per_constraint_t *csiz; asn_dec_rval_t rval = { RC_OK, 0 }; - BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; ssize_t consumed_myself = 0; int repeat; - int unit_bits = (specs->subvariant != 1) * 7 + 1; + enum { + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + unsigned int unit_bits; + unsigned int canonical_unit_bits; (void)opt_codec_ctx; + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + } + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + case ASN_OSUBV_BIT: + ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant); + RETURN(RC_FAIL); + break; + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_CHAR; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + break; + } + /* * Allocate the string. */ if(!st) { - st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); if(!st) RETURN(RC_FAIL); } - ASN_DEBUG("PER Decoding %s %ld .. %ld bits %d", - ct->flags & APC_EXTENSIBLE ? "extensible" : "fixed", - ct->lower_bound, ct->upper_bound, ct->effective_bits); + ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", + csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", + csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); - if(ct->flags & APC_EXTENSIBLE) { + if(csiz->flags & APC_EXTENSIBLE) { int inext = per_get_few_bits(pd, 1); if(inext < 0) RETURN(RC_WMORE); - if(inext) ct = &asn_DEF_OCTET_STRING_constraint; - consumed_myself = 0; + if(inext) { + csiz = &asn_DEF_OCTET_STRING_constraints.size; + unit_bits = canonical_unit_bits; + } } - if(ct->effective_bits >= 0 - && (!st->buf || st->size < ct->upper_bound)) { + if(csiz->effective_bits >= 0) { FREEMEM(st->buf); - if(unit_bits == 1) { - st->size = (ct->upper_bound + 7) >> 3; + if(bpc) { + st->size = csiz->upper_bound * bpc; } else { - st->size = ct->upper_bound; + st->size = (csiz->upper_bound + 7) >> 3; } st->buf = (uint8_t *)MALLOC(st->size + 1); if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } @@ -1251,46 +1446,52 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, /* X.691, #16.5: zero-length encoding */ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ - if(ct->effective_bits == 0) { - int ret = per_get_many_bits(pd, st->buf, 0, - unit_bits * ct->upper_bound); + if(csiz->effective_bits == 0) { + int ret; + if(bpc) { + ASN_DEBUG("Encoding OCTET STRING size %ld", + csiz->upper_bound); + ret = OCTET_STRING_per_get_characters(pd, st->buf, + csiz->upper_bound, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + } else { + ASN_DEBUG("Encoding BIT STRING size %ld", + csiz->upper_bound); + ret = per_get_many_bits(pd, st->buf, 0, + unit_bits * csiz->upper_bound); + } if(ret < 0) RETURN(RC_WMORE); - consumed_myself += unit_bits * ct->upper_bound; + consumed_myself += unit_bits * csiz->upper_bound; st->buf[st->size] = 0; - if(unit_bits == 1 && (ct->upper_bound & 0x7)) - st->bits_unused = 8 - (ct->upper_bound & 0x7); RETURN(RC_OK); } st->size = 0; do { + ssize_t raw_len; ssize_t len_bytes; - ssize_t len_bits; void *p; int ret; /* Get the PER length */ - len_bits = uper_get_length(pd, ct->effective_bits, &repeat); - if(len_bits < 0) RETURN(RC_WMORE); - len_bits += ct->lower_bound; + raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound, + &repeat); + 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)", - (long)ct->effective_bits, (long)len_bits, + (long)csiz->effective_bits, (long)raw_len, repeat ? "repeat" : "once", td->name); - if(unit_bits == 1) { - len_bytes = (len_bits + 7) >> 3; - if(len_bits & 0x7) - st->bits_unused = 8 - (len_bits & 0x7); - /* len_bits be multiple of 16K if repeat is set */ - } else { - len_bytes = len_bits; - len_bits = len_bytes << 3; - } + len_bytes = raw_len * bpc; p = REALLOC(st->buf, st->size + len_bytes + 1); if(!p) RETURN(RC_FAIL); st->buf = (uint8_t *)p; - ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits); + ret = OCTET_STRING_per_get_characters(pd, &st->buf[st->size], raw_len, + bpc, unit_bits, cval->lower_bound, + cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); if(ret < 0) RETURN(RC_WMORE); st->size += len_bytes; } while(repeat); @@ -1300,110 +1501,154 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, } asn_enc_rval_t -OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { - - asn_OCTET_STRING_specifics_t *specs = td->specifics - ? (asn_OCTET_STRING_specifics_t *)td->specifics - : &asn_DEF_OCTET_STRING_specs; - asn_per_constraint_t *ct = constraints ? &constraints->size - : (td->per_constraints - ? &td->per_constraints->size - : &asn_DEF_OCTET_STRING_constraint); - const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; - int unit_bits = (specs->subvariant != 1) * 7 + 1; - asn_enc_rval_t er; - int ct_extensible = ct->flags & APC_EXTENSIBLE; +OCTET_STRING_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, asn_per_outp_t *po) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const asn_per_constraints_t *pc = constraints ? constraints + : td->encoding_constraints.per_constraints; + const asn_per_constraint_t *cval; + const asn_per_constraint_t *csiz; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er = { 0, 0, 0 }; int inext = 0; /* Lies not within extension root */ - int sizeinunits = 0; + unsigned int unit_bits; + unsigned int canonical_unit_bits; + size_t size_in_units; const uint8_t *buf; int ret; - - if(!st || !st->buf) - _ASN_ENCODE_FAILED; - sizeinunits = st->size; - - if(unit_bits == 1) { - ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", - sizeinunits, st->bits_unused); - sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07); + enum { + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + int ct_extensible; + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; } - - ASN_DEBUG("Encoding %s into %d units of %d bits" - " (%d..%d, effective %d)%s", - td->name, sizeinunits, unit_bits, - ct->lower_bound, ct->upper_bound, - ct->effective_bits, ct_extensible ? " EXT" : ""); - - /* Figure out wheter size lies within PER visible consrtaint */ - - if(ct->effective_bits >= 0) { - if(sizeinunits < ct->lower_bound - || sizeinunits > ct->upper_bound) { - if(ct_extensible) { - ct = &asn_DEF_OCTET_STRING_constraint; - inext = 1; - } else - _ASN_ENCODE_FAILED; + ct_extensible = csiz->flags & APC_EXTENSIBLE; + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + case ASN_OSUBV_BIT: + ASN__ENCODE_FAILED; + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_CHAR; + size_in_units = st->size; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + size_in_units = st->size >> 1; + if(st->size & 1) { + ASN_DEBUG("%s string size is not modulo 2", td->name); + ASN__ENCODE_FAILED; } - } else { - inext = 0; + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + size_in_units = st->size >> 2; + if(st->size & 3) { + ASN_DEBUG("%s string size is not modulo 4", td->name); + ASN__ENCODE_FAILED; + } + break; } - if(ct_extensible) { + ASN_DEBUG("Encoding %s into %" ASN_PRI_SIZE " units of %d bits" + " (%ld..%ld, effective %d)%s", + td->name, size_in_units, unit_bits, + csiz->lower_bound, csiz->upper_bound, + csiz->effective_bits, ct_extensible ? " EXT" : ""); + + /* Figure out whether size lies within PER visible constraint */ + + if(csiz->effective_bits >= 0) { + if((ssize_t)size_in_units < csiz->lower_bound + || (ssize_t)size_in_units > csiz->upper_bound) { + if(ct_extensible) { + csiz = &asn_DEF_OCTET_STRING_constraints.size; + unit_bits = canonical_unit_bits; + inext = 1; + } else { + ASN__ENCODE_FAILED; + } + } + } else { + inext = 0; + } + + if(ct_extensible) { /* Declare whether length is [not] within extension root */ if(per_put_few_bits(po, inext, 1)) - _ASN_ENCODE_FAILED; - } - - /* X.691, #16.5: zero-length encoding */ - /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ - /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ - if(ct->effective_bits >= 0) { - ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", - st->size, sizeinunits - ct->lower_bound, - ct->effective_bits); - ret = per_put_few_bits(po, sizeinunits - ct->lower_bound, - ct->effective_bits); - if(ret) _ASN_ENCODE_FAILED; - ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits); - if(ret) _ASN_ENCODE_FAILED; - _ASN_ENCODED_OK(er); + ASN__ENCODE_FAILED; } - ASN_DEBUG("Encoding %d bytes", st->size); - - if(sizeinunits == 0) { - if(uper_put_length(po, 0)) - _ASN_ENCODE_FAILED; - _ASN_ENCODED_OK(er); - } - - buf = st->buf; - while(sizeinunits) { - ssize_t maySave = uper_put_length(po, sizeinunits); - if(maySave < 0) _ASN_ENCODE_FAILED; - - ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits); - - ret = per_put_many_bits(po, buf, maySave * unit_bits); - if(ret) _ASN_ENCODE_FAILED; - - if(unit_bits == 1) - buf += maySave >> 3; - else - buf += maySave; - sizeinunits -= maySave; - assert(!(maySave & 0x07) || !sizeinunits); - } - - _ASN_ENCODED_OK(er); + if(csiz->effective_bits >= 0 && !inext) { + ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes (%ld), length in %d bits", st->size, + size_in_units - csiz->lower_bound, csiz->effective_bits); + ret = per_put_few_bits(po, size_in_units - csiz->lower_bound, + csiz->effective_bits); + if(ret) ASN__ENCODE_FAILED; + ret = OCTET_STRING_per_put_characters(po, st->buf, size_in_units, bpc, + unit_bits, cval->lower_bound, + cval->upper_bound, pc); + if(ret) ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } + + ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes", st->size); + + buf = st->buf; + ASN_DEBUG("Encoding %" ASN_PRI_SIZE " in units", size_in_units); + do { + 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 %" ASN_PRI_SSIZE " of %" ASN_PRI_SIZE "%s", may_save, size_in_units, + need_eom ? ",+EOM" : ""); + + ret = OCTET_STRING_per_put_characters(po, buf, may_save, bpc, unit_bits, + cval->lower_bound, + cval->upper_bound, pc); + if(ret) ASN__ENCODE_FAILED; + + buf += may_save * bpc; + size_in_units -= may_save; + 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); } +#endif /* ASN_DISABLE_PER_SUPPORT */ + int -OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, - asn_app_consume_bytes_f *cb, void *app_key) { - static const char *h2c = "0123456789ABCDEF"; +OCTET_STRING_print(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; char scratch[16 * 3 + 4]; char *p = scratch; @@ -1413,7 +1658,8 @@ OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, (void)td; /* Unused argument */ - if(!st || !st->buf) return (cb("", 8, app_key) < 0) ? -1 : 0; + if(!st || (!st->buf && st->size)) + return (cb("", 8, app_key) < 0) ? -1 : 0; /* * Dump the contents of the buffer in hexadecimal. @@ -1442,14 +1688,15 @@ OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, } int -OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, - int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; +OCTET_STRING_print_utf8(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, asn_app_consume_bytes_f *cb, + void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; (void)td; /* Unused argument */ (void)ilevel; /* Unused argument */ - if(st && st->buf) { + if(st && (st->buf || !st->size)) { return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; } else { return (cb("", 8, app_key) < 0) ? -1 : 0; @@ -1457,22 +1704,26 @@ OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, } void -OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { +OCTET_STRING_free(const asn_TYPE_descriptor_t *td, void *sptr, + enum asn_struct_free_method method) { OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; - asn_OCTET_STRING_specifics_t *specs = td && td->specifics - ? (asn_OCTET_STRING_specifics_t *)td->specifics - : &asn_DEF_OCTET_STRING_specs; - asn_struct_ctx_t *ctx = (asn_struct_ctx_t *) - ((char *)st + specs->ctx_offset); + const asn_OCTET_STRING_specifics_t *specs; + asn_struct_ctx_t *ctx; struct _stack *stck; if(!td || !st) return; + specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + ASN_DEBUG("Freeing %s as OCTET STRING", td->name); if(st->buf) { FREEMEM(st->buf); + st->buf = 0; } /* @@ -1488,9 +1739,20 @@ OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { FREEMEM(stck); } - if(!contents_only) { - FREEMEM(st); - } + switch(method) { + case ASFM_FREE_EVERYTHING: + FREEMEM(sptr); + break; + case ASFM_FREE_UNDERLYING: + break; + case ASFM_FREE_UNDERLYING_AND_RESET: + memset(sptr, 0, + td->specifics + ? ((const asn_OCTET_STRING_specifics_t *)(td->specifics)) + ->struct_size + : sizeof(OCTET_STRING_t)); + break; + } } /* @@ -1534,11 +1796,12 @@ OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { } OCTET_STRING_t * -OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) { - asn_OCTET_STRING_specifics_t *specs = td->specifics - ? (asn_OCTET_STRING_specifics_t *)td->specifics - : &asn_DEF_OCTET_STRING_specs; - OCTET_STRING_t *st; +OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td, const char *str, + int len) { + const asn_OCTET_STRING_specifics_t *specs = + td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + OCTET_STRING_t *st; st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); if(st && str && OCTET_STRING_fromBuf(st, str, len)) { @@ -1549,3 +1812,232 @@ OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) { return st; } +/* + * Lexicographically compare the common prefix of both strings, + * and if it is the same return -1 for the smallest string. + */ +int +OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr, + const void *bptr) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics; + const OCTET_STRING_t *a = aptr; + const OCTET_STRING_t *b = bptr; + + assert(!specs || specs->subvariant != ASN_OSUBV_BIT); + + if(a && b) { + size_t common_prefix_size = a->size <= b->size ? a->size : b->size; + int ret = memcmp(a->buf, b->buf, common_prefix_size); + if(ret == 0) { + /* Figure out which string with equal prefixes is longer. */ + if(a->size < b->size) { + return -1; + } else if(a->size > b->size) { + return 1; + } else { + return 0; + } + } else { + return ret < 0 ? -1 : 1; + } + } else if(!a && !b) { + return 0; + } else if(!a) { + return -1; + } else { + return 1; + } + +} + +/* + * Biased function for randomizing character values around their limits. + */ +static uint32_t +OCTET_STRING__random_char(unsigned long lb, unsigned long ub) { + assert(lb <= ub); + switch(asn_random_between(0, 16)) { + case 0: + if(lb < ub) return lb + 1; + /* Fall through */ + case 1: + return lb; + case 2: + if(lb < ub) return ub - 1; + /* Fall through */ + case 3: + return ub; + default: + return asn_random_between(lb, ub); + } +} + + +size_t +OCTET_STRING_random_length_constrained( + const asn_TYPE_descriptor_t *td, + const asn_encoding_constraints_t *constraints, size_t max_length) { + const unsigned lengths[] = {0, 1, 2, 3, 4, 8, + 126, 127, 128, 16383, 16384, 16385, + 65534, 65535, 65536, 65537}; + size_t rnd_len; + + /* Figure out how far we should go */ + rnd_len = lengths[asn_random_between( + 0, sizeof(lengths) / sizeof(lengths[0]) - 1)]; + + 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_CONSTRAINED) { + long suggested_upper_bound = pc->upper_bound < (ssize_t)max_length + ? pc->upper_bound + : (ssize_t)max_length; + if(max_length <= (size_t)pc->lower_bound) { + return pc->lower_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 { + rnd_len = asn_random_between(0, max_length); + } + } else if(rnd_len > max_length) { + rnd_len = asn_random_between(0, max_length); + } + + return rnd_len; +} + +asn_random_fill_result_t +OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constraints, + size_t max_length) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + unsigned int unit_bytes = 1; + unsigned long clb = 0; /* Lower bound on char */ + unsigned long cub = 255; /* Higher bound on char value */ + uint8_t *buf; + uint8_t *bend; + uint8_t *b; + size_t rnd_len; + OCTET_STRING_t *st; + + if(max_length == 0 && !*sptr) return result_skipped; + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + return result_failed; + case ASN_OSUBV_BIT: + /* Handled by BIT_STRING itself. */ + return result_failed; + case ASN_OSUBV_STR: + unit_bytes = 1; + clb = 0; + cub = 255; + break; + case ASN_OSUBV_U16: + unit_bytes = 2; + clb = 0; + cub = 65535; + break; + case ASN_OSUBV_U32: + unit_bytes = 4; + clb = 0; + cub = 0x10FFFF; + break; + } + + if(!constraints || !constraints->per_constraints) + constraints = &td->encoding_constraints; + if(constraints->per_constraints) { + const asn_per_constraint_t *pc = &constraints->per_constraints->value; + if(pc->flags & APC_SEMI_CONSTRAINED) { + clb = pc->lower_bound; + } else if(pc->flags & APC_CONSTRAINED) { + clb = pc->lower_bound; + cub = pc->upper_bound; + } + } + + rnd_len = + OCTET_STRING_random_length_constrained(td, constraints, max_length); + + buf = CALLOC(unit_bytes, rnd_len + 1); + if(!buf) return result_failed; + + bend = &buf[unit_bytes * rnd_len]; + + switch(unit_bytes) { + case 1: + for(b = buf; b < bend; b += unit_bytes) { + *(uint8_t *)b = OCTET_STRING__random_char(clb, cub); + } + *(uint8_t *)b = 0; + break; + case 2: + for(b = buf; b < bend; b += unit_bytes) { + uint32_t code = OCTET_STRING__random_char(clb, cub); + b[0] = code >> 8; + b[1] = code; + } + *(uint16_t *)b = 0; + break; + case 4: + for(b = buf; b < bend; b += unit_bytes) { + uint32_t code = OCTET_STRING__random_char(clb, cub); + b[0] = code >> 24; + b[1] = code >> 16; + b[2] = code >> 8; + b[3] = code; + } + *(uint32_t *)b = 0; + break; + } + + if(*sptr) { + st = *sptr; + FREEMEM(st->buf); + } else { + st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) { + FREEMEM(buf); + return result_failed; + } + } + + st->buf = buf; + st->size = unit_bytes * rnd_len; + + result_ok.length = st->size; + return result_ok; +}