X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/4271ab433cd55bbd2612292bcf39e4dc3d7274f1..9e321f1d39023f4ba86cd354eda0c347ac15fca2:/libs/smux/OCTET_STRING.c

diff --git a/libs/smux/OCTET_STRING.c b/libs/smux/OCTET_STRING.c
index 5420dede..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 <vlm@lionet.info>.
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
@@ -14,38 +14,50 @@
 static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
 };
-static const 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),
 	ASN_OSUBV_STR
 };
-static const 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_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
@@ -111,14 +123,14 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
  * 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;
@@ -157,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));
 }
 
@@ -165,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;
@@ -213,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 {
@@ -244,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)
@@ -333,7 +343,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 		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;
@@ -396,7 +406,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 		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);
 
@@ -485,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);
@@ -495,9 +505,18 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 	/*
 	 * BIT STRING-specific processing.
 	 */
-	if(type_variant == ASN_OSUBV_BIT && 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",
@@ -513,14 +532,14 @@ 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;
+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;
 
@@ -558,7 +577,6 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
 		uint8_t b = st->bits_unused & 0x07;
 		if(b && st->size) fix_last_byte = 1;
 		ASN__CALLBACK(&b, 1);
-		er.encoded++;
 	}
 
 	/* Invoke callback for the main part of the buffer */
@@ -570,17 +588,16 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
 		ASN__CALLBACK(&b, 1);
 	}
 
-	er.encoded += st->size;
 	ASN__ENCODED_OK(er);
 cb_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) {
-	const char * const 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];
@@ -604,7 +621,6 @@ OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
 		for(; buf < end; buf++) {
 			if(p >= scend) {
 				ASN__CALLBACK(scratch, p - scratch);
-				er.encoded += p - scratch;
 				p = scratch;
 			}
 			*p++ = h2c[(*buf >> 4) & 0x0F];
@@ -612,12 +628,10 @@ OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
 		}
 
 		ASN__CALLBACK(scratch, p-scratch);	/* Dump the rest */
-		er.encoded += p - scratch;
 	} else {
 		for(i = 0; buf < end; buf++, i++) {
 			if(!(i % 16) && (i || st->size > 16)) {
 				ASN__CALLBACK(scratch, p-scratch);
-				er.encoded += (p-scratch);
 				p = scratch;
 				ASN__TEXT_INDENT(1, ilevel);
 			}
@@ -628,7 +642,6 @@ 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;
 			if(st->size > 16)
 				ASN__TEXT_INDENT(1, ilevel-1);
 		}
@@ -733,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 */
@@ -790,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;
@@ -848,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 */
@@ -865,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;
@@ -910,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 */
@@ -921,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*/
@@ -950,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;
@@ -959,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 &lt; 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;
@@ -1090,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 */
@@ -1100,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 */
@@ -1160,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);
 }
 
@@ -1171,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);
 }
 
@@ -1182,19 +1199,22 @@ 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, asn_per_constraints_t *pc) {
+		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",
@@ -1236,8 +1256,8 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,
 	}
 
 	for(; buf < end; buf += bpc) {
-		int code = per_get_few_bits(po, unit_bits);
-		int ch = code + lb;
+		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)",
@@ -1258,7 +1278,7 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,
 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, asn_per_constraints_t *pc) {
+		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)",
@@ -1296,48 +1316,57 @@ OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf,
 		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, *buf, lb, ub + lb);
-			return -1;
-		}
-		if(per_put_few_bits(po, ch, unit_bits))
-			return -1;
-	}
-
-	return 0;
+    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_constraints_t *pc = constraints ? constraints
-				: td->per_constraints;
-	asn_per_constraint_t *cval;
-	asn_per_constraint_t *csiz;
+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;
 	enum {
-		OS__BPC_BIT	= 0,
 		OS__BPC_CHAR	= 1,
 		OS__BPC_U16	= 2,
 		OS__BPC_U32	= 4
@@ -1358,11 +1387,9 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 	switch(specs->subvariant) {
 	default:
 	case ASN_OSUBV_ANY:
+	case ASN_OSUBV_BIT:
 		ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant);
 		RETURN(RC_FAIL);
-	case ASN_OSUBV_BIT:
-		canonical_unit_bits = unit_bits = 1;
-		bpc = OS__BPC_BIT;
 		break;
 	case ASN_OSUBV_STR:
 		canonical_unit_bits = unit_bits = 8;
@@ -1388,7 +1415,7 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 	 * 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);
 	}
 
@@ -1401,7 +1428,6 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 		if(inext < 0) RETURN(RC_WMORE);
 		if(inext) {
 			csiz = &asn_DEF_OCTET_STRING_constraints.size;
-			cval = &asn_DEF_OCTET_STRING_constraints.value;
 			unit_bits = canonical_unit_bits;
 		}
 	}
@@ -1438,10 +1464,6 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 		if(ret < 0) RETURN(RC_WMORE);
 		consumed_myself += unit_bits * csiz->upper_bound;
 		st->buf[st->size] = 0;
-		if(bpc == 0) {
-			int ubs = (csiz->upper_bound & 0x7);
-			st->bits_unused = ubs ? 8 - ubs : 0;
-		}
 		RETURN(RC_OK);
 	}
 
@@ -1449,41 +1471,27 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 	do {
 		ssize_t raw_len;
 		ssize_t len_bytes;
-		ssize_t len_bits;
 		void *p;
 		int ret;
 
 		/* Get the PER length */
-		raw_len = uper_get_length(pd, csiz->effective_bits, &repeat);
+		raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
+		                          &repeat);
 		if(raw_len < 0) RETURN(RC_WMORE);
-		raw_len += csiz->lower_bound;
+		if(raw_len == 0 && st->buf) break;
 
 		ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
 			(long)csiz->effective_bits, (long)raw_len,
 			repeat ? "repeat" : "once", td->name);
-		if(bpc) {
-			len_bytes = raw_len * bpc;
-			len_bits = len_bytes * unit_bits;
-		} else {
-			len_bits = raw_len;
-			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 */
-		}
+        len_bytes = raw_len * bpc;
 		p = REALLOC(st->buf, st->size + len_bytes + 1);
 		if(!p) RETURN(RC_FAIL);
 		st->buf = (uint8_t *)p;
 
-		if(bpc) {
-			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);
-		} else {
-			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);
@@ -1493,26 +1501,25 @@ 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_constraints_t *pc = constraints ? constraints
-				: td->per_constraints;
-	asn_per_constraint_t *cval;
-	asn_per_constraint_t *csiz;
-	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+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 */
 	unsigned int unit_bits;
 	unsigned int canonical_unit_bits;
-	unsigned int sizeinunits;
+	size_t size_in_units;
 	const uint8_t *buf;
 	int ret;
 	enum {
-		OS__BPC_BIT	= 0,
 		OS__BPC_CHAR	= 1,
 		OS__BPC_U16	= 2,
 		OS__BPC_U32	= 4
@@ -1534,128 +1541,114 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
 	switch(specs->subvariant) {
 	default:
 	case ASN_OSUBV_ANY:
-		ASN__ENCODE_FAILED;
 	case ASN_OSUBV_BIT:
-		canonical_unit_bits = unit_bits = 1;
-		bpc = OS__BPC_BIT;
-		sizeinunits = st->size * 8 - (st->bits_unused & 0x07);
-		ASN_DEBUG("BIT STRING of %d bytes, %d bits unused",
-				sizeinunits, st->bits_unused);
-		break;
+		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;
-		sizeinunits = st->size;
+		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;
-		sizeinunits = st->size / 2;
+		size_in_units = st->size >> 1;
+		if(st->size & 1) {
+			ASN_DEBUG("%s string size is not modulo 2", td->name);
+			ASN__ENCODE_FAILED;
+		}
 		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;
-		sizeinunits = st->size / 4;
+		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;
 	}
 
-	ASN_DEBUG("Encoding %s into %d units of %d bits"
+	ASN_DEBUG("Encoding %s into %" ASN_PRI_SIZE " units of %d bits"
 		" (%ld..%ld, effective %d)%s",
-		td->name, sizeinunits, unit_bits,
+		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((int)sizeinunits < csiz->lower_bound
-		|| (int)sizeinunits > csiz->upper_bound) {
-			if(ct_extensible) {
-				cval = &asn_DEF_OCTET_STRING_constraints.value;
-				csiz = &asn_DEF_OCTET_STRING_constraints.size;
-				unit_bits = canonical_unit_bits;
-				inext = 1;
-			} else
-				ASN__ENCODE_FAILED;
-		}
-	} else {
-		inext = 0;
-	}
-
-	if(ct_extensible) {
+    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(csiz->effective_bits >= 0) {
-		ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits",
-				st->size, sizeinunits - csiz->lower_bound,
-				csiz->effective_bits);
-		ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound,
-				csiz->effective_bits);
-		if(ret) ASN__ENCODE_FAILED;
-		if(bpc) {
-			ret = OCTET_STRING_per_put_characters(po, st->buf,
-				sizeinunits, bpc, unit_bits,
-				cval->lower_bound, cval->upper_bound, pc);
-		} else {
-			ret = per_put_many_bits(po, st->buf,
-				sizeinunits * unit_bits);
-		}
-		if(ret) ASN__ENCODE_FAILED;
-		ASN__ENCODED_OK(er);
-	}
-
-	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 %ld of %ld",
-			(long)maySave, (long)sizeinunits);
-
-		if(bpc) {
-			ret = OCTET_STRING_per_put_characters(po, buf,
-				maySave, bpc, unit_bits,
-				cval->lower_bound, cval->upper_bound, pc);
-		} else {
-			ret = per_put_many_bits(po, buf, maySave * unit_bits);
-		}
-		if(ret) ASN__ENCODE_FAILED;
-
-		if(bpc)
-			buf += maySave * bpc;
-		else
-			buf += maySave >> 3;
-		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) {
-	const char * const 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;
@@ -1695,9 +1688,10 @@ 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 */
@@ -1710,9 +1704,10 @@ 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;
+	const asn_OCTET_STRING_specifics_t *specs;
 	asn_struct_ctx_t *ctx;
 	struct _stack *stck;
 
@@ -1720,8 +1715,8 @@ OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) {
 		return;
 
 	specs = td->specifics
-		    ? (asn_OCTET_STRING_specifics_t *)td->specifics
-		    : &asn_DEF_OCTET_STRING_specs;
+		    ? (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);
@@ -1744,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;
+    }
 }
 
 /*
@@ -1790,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)) {
@@ -1805,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;
+}