[Freeipa-devel] [PATCH 2/3] ASN1: Fix warning Wpointer-to-int-cast

Lukas Slebodnik lslebodn at redhat.com
Fri Jan 29 11:48:36 UTC 2016


On (29/01/16 12:17), Martin Kosek wrote:
>On 01/29/2016 12:15 PM, Lukas Slebodnik wrote:
>> ehlo,
>> 
>> the first patch is very simple and it just suppress warning.
>> The second patch is either bug or dead code. I fixed it as a bug.
>> I'm not sure how to test 2nd patch.
>> 
>> LS
>
>Thanks. But isn't this the code generated by asn1 tool? Maybe it would be
>better to fix the tool, or maybe regenerate it with a newer version of the
>tool? Otherwise the improvements will get lost.
>
As you wish.

Updated patch is attached.

LS
-------------- next part --------------
>From 47ca1fddb778c9aa68fb82f70458364a77d66aea Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lslebodn at redhat.com>
Date: Fri, 29 Jan 2016 12:44:19 +0100
Subject: [PATCH 2/2] ASN1: Regenerate code with new tool asn1c-0.9.27

asn1c-0.9.27 generates code without compiler warning
and fixes dead-code/bug

constr_SET_OF.c: In function 'SET_OF_decode_uper':
constr_SET_OF.c:907:18: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     (int)nelems, (int)ct ? ct->effective_bits : -1);
                  ^
constr_SET_OF.c:924:5: warning: statement with no effect [-Wunused-value]
     rv.code == RC_FAIL;
     ^
---
 asn1/asn1c/BIT_STRING.c       |   9 +-
 asn1/asn1c/GKCurrentKeys.c    |   6 +-
 asn1/asn1c/GKCurrentKeys.h    |   3 +-
 asn1/asn1c/GKNewKeys.c        |  12 +-
 asn1/asn1c/GKNewKeys.h        |   3 +-
 asn1/asn1c/GKReply.c          |   8 +-
 asn1/asn1c/GKReply.h          |   3 +-
 asn1/asn1c/GetKeytabControl.c |  10 +-
 asn1/asn1c/GetKeytabControl.h |   3 +-
 asn1/asn1c/INTEGER.c          | 466 +++++++++++++++++++++++++++++-------------
 asn1/asn1c/INTEGER.h          |  17 ++
 asn1/asn1c/Int32.c            |   7 +-
 asn1/asn1c/Int32.h            |   3 +-
 asn1/asn1c/KrbKey.c           |  10 +-
 asn1/asn1c/KrbKey.h           |   3 +-
 asn1/asn1c/NativeEnumerated.c |  11 +-
 asn1/asn1c/NativeInteger.c    |  32 ++-
 asn1/asn1c/OCTET_STRING.c     | 449 +++++++++++++++++++++++++++++++---------
 asn1/asn1c/OCTET_STRING.h     |   8 +-
 asn1/asn1c/TypeValuePair.c    |   8 +-
 asn1/asn1c/TypeValuePair.h    |   3 +-
 asn1/asn1c/asn_codecs.h       |   4 +-
 asn1/asn1c/asn_codecs_prim.c  |  43 ++--
 asn1/asn1c/asn_internal.h     |  27 ++-
 asn1/asn1c/asn_system.h       |  35 +++-
 asn1/asn1c/ber_decoder.c      |   2 +-
 asn1/asn1c/ber_decoder.h      |   1 +
 asn1/asn1c/constr_CHOICE.c    |  70 ++++---
 asn1/asn1c/constr_SEQUENCE.c  | 253 +++++++++++++++++++----
 asn1/asn1c/constr_SET_OF.c    |  17 +-
 asn1/asn1c/der_encoder.h      |   1 +
 asn1/asn1c/per_decoder.c      |  38 ++++
 asn1/asn1c/per_decoder.h      |  14 +-
 asn1/asn1c/per_encoder.c      | 136 ++++++++----
 asn1/asn1c/per_encoder.h      |  24 ++-
 asn1/asn1c/per_opentype.c     | 378 ++++++++++++++++++++++++++++++++++
 asn1/asn1c/per_opentype.h     |  22 ++
 asn1/asn1c/per_support.c      | 207 +++++++++++++++++--
 asn1/asn1c/per_support.h      |  38 +++-
 asn1/asn1c/xer_decoder.c      |  14 +-
 asn1/asn1c/xer_decoder.h      |   7 +-
 41 files changed, 1931 insertions(+), 474 deletions(-)
 create mode 100644 asn1/asn1c/per_opentype.c
 create mode 100644 asn1/asn1c/per_opentype.h

diff --git a/asn1/asn1c/BIT_STRING.c b/asn1/asn1c/BIT_STRING.c
index 6469d4fd2c8782048e228c19e67950f3b2dc1305..9b9827127b7ba438676630efef975e0e80ac45aa 100644
--- a/asn1/asn1c/BIT_STRING.c
+++ b/asn1/asn1c/BIT_STRING.c
@@ -15,7 +15,7 @@ static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = {
 static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = {
 	sizeof(BIT_STRING_t),
 	offsetof(BIT_STRING_t, _asn_ctx),
-	1,	/* Special indicator that this is a BIT STRING type */
+	ASN_OSUBV_BIT
 };
 asn_TYPE_descriptor_t asn_DEF_BIT_STRING = {
 	"BIT STRING",
@@ -50,14 +50,15 @@ BIT_STRING_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
 
 	if(st && st->buf) {
-		if(st->size == 1 && st->bits_unused) {
-			_ASN_CTFAIL(app_key, td,
+		if((st->size == 0 && st->bits_unused)
+		|| st->bits_unused < 0 || st->bits_unused > 7) {
+			_ASN_CTFAIL(app_key, td, sptr,
 				"%s: invalid padding byte (%s:%d)",
 				td->name, __FILE__, __LINE__);
 			return -1;
 		}
 	} else {
-		_ASN_CTFAIL(app_key, td,
+		_ASN_CTFAIL(app_key, td, sptr,
 			"%s: value not given (%s:%d)",
 			td->name, __FILE__, __LINE__);
 		return -1;
diff --git a/asn1/asn1c/GKCurrentKeys.c b/asn1/asn1c/GKCurrentKeys.c
index abcc53130d64259d0f2947b04412b4b769bb4360..bc7c1aacabdad433abeab83ddb43ba405aaff14b 100644
--- a/asn1/asn1c/GKCurrentKeys.c
+++ b/asn1/asn1c/GKCurrentKeys.c
@@ -1,12 +1,10 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
  */
 
-#include <asn_internal.h>
-
 #include "GKCurrentKeys.h"
 
 static asn_TYPE_member_t asn_MBR_GKCurrentKeys_1[] = {
@@ -24,7 +22,7 @@ static ber_tlv_tag_t asn_DEF_GKCurrentKeys_tags_1[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
 };
 static asn_TYPE_tag2member_t asn_MAP_GKCurrentKeys_tag2el_1[] = {
-    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* serviceIdentity at 19 */
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* serviceIdentity */
 };
 static asn_SEQUENCE_specifics_t asn_SPC_GKCurrentKeys_specs_1 = {
 	sizeof(struct GKCurrentKeys),
diff --git a/asn1/asn1c/GKCurrentKeys.h b/asn1/asn1c/GKCurrentKeys.h
index 7ec4e4c60dd5c605bec311f713e33630dedaca58..d1c318630bc2eaab8a21cfd8393c1e6936bec2f7 100644
--- a/asn1/asn1c/GKCurrentKeys.h
+++ b/asn1/asn1c/GKCurrentKeys.h
@@ -1,5 +1,5 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
@@ -35,3 +35,4 @@ extern asn_TYPE_descriptor_t asn_DEF_GKCurrentKeys;
 #endif
 
 #endif	/* _GKCurrentKeys_H_ */
+#include <asn_internal.h>
diff --git a/asn1/asn1c/GKNewKeys.c b/asn1/asn1c/GKNewKeys.c
index 35ebcf245c25c02572377381ba3418f3f8488fd7..a3001ac93eba492a38c610e04485bccf7c90ac16 100644
--- a/asn1/asn1c/GKNewKeys.c
+++ b/asn1/asn1c/GKNewKeys.c
@@ -1,12 +1,10 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
  */
 
-#include <asn_internal.h>
-
 #include "GKNewKeys.h"
 
 static asn_TYPE_member_t asn_MBR_enctypes_3[] = {
@@ -66,7 +64,7 @@ static asn_TYPE_member_t asn_MBR_GKNewKeys_1[] = {
 		},
 	{ ATF_NOFLAGS, 0, offsetof(struct GKNewKeys, enctypes),
 		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
-		+1,	/* EXPLICIT tag at current level */
+		0,
 		&asn_DEF_enctypes_3,
 		0,	/* Defer constraints checking to the member type */
 		0,	/* PER is not compiled, use -gen-PER */
@@ -87,9 +85,9 @@ static ber_tlv_tag_t asn_DEF_GKNewKeys_tags_1[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
 };
 static asn_TYPE_tag2member_t asn_MAP_GKNewKeys_tag2el_1[] = {
-    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* serviceIdentity at 13 */
-    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* enctypes at 14 */
-    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* password at 15 */
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* serviceIdentity */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* enctypes */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* password */
 };
 static asn_SEQUENCE_specifics_t asn_SPC_GKNewKeys_specs_1 = {
 	sizeof(struct GKNewKeys),
diff --git a/asn1/asn1c/GKNewKeys.h b/asn1/asn1c/GKNewKeys.h
index 2cd158dff9c36cd6f632448235e889f3c8ab937f..6b2a0df59fd34c27f24968639aff964b369bbdc9 100644
--- a/asn1/asn1c/GKNewKeys.h
+++ b/asn1/asn1c/GKNewKeys.h
@@ -1,5 +1,5 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
@@ -45,3 +45,4 @@ extern asn_TYPE_descriptor_t asn_DEF_GKNewKeys;
 #endif
 
 #endif	/* _GKNewKeys_H_ */
+#include <asn_internal.h>
diff --git a/asn1/asn1c/GKReply.c b/asn1/asn1c/GKReply.c
index 220c791e2d84b2ea9d889307403bc2b64781f3ce..85fdfa37903feb1f2e8888f8a696982c2286df81 100644
--- a/asn1/asn1c/GKReply.c
+++ b/asn1/asn1c/GKReply.c
@@ -1,12 +1,10 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
  */
 
-#include <asn_internal.h>
-
 #include "GKReply.h"
 
 static asn_TYPE_member_t asn_MBR_keys_3[] = {
@@ -77,8 +75,8 @@ static ber_tlv_tag_t asn_DEF_GKReply_tags_1[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
 };
 static asn_TYPE_tag2member_t asn_MAP_GKReply_tag2el_1[] = {
-    { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 0 }, /* newkvno at 23 */
-    { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 1, 0, 0 } /* keys at 25 */
+    { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 0 }, /* newkvno */
+    { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 1, 0, 0 } /* keys */
 };
 static asn_SEQUENCE_specifics_t asn_SPC_GKReply_specs_1 = {
 	sizeof(struct GKReply),
diff --git a/asn1/asn1c/GKReply.h b/asn1/asn1c/GKReply.h
index 7f058f6bf481ee2e570138f06fdef3d913949e9f..70a9c9698e86a1582dd7687f931d6b1af1bf0bdf 100644
--- a/asn1/asn1c/GKReply.h
+++ b/asn1/asn1c/GKReply.h
@@ -1,5 +1,5 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
@@ -49,3 +49,4 @@ extern asn_TYPE_descriptor_t asn_DEF_GKReply;
 #include "KrbKey.h"
 
 #endif	/* _GKReply_H_ */
+#include <asn_internal.h>
diff --git a/asn1/asn1c/GetKeytabControl.c b/asn1/asn1c/GetKeytabControl.c
index 65b55d1ef34e31b81ef7b751608da4cc6c12020c..8ce4750cbe3114b6456ca4044221f3d90225b742 100644
--- a/asn1/asn1c/GetKeytabControl.c
+++ b/asn1/asn1c/GetKeytabControl.c
@@ -1,12 +1,10 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
  */
 
-#include <asn_internal.h>
-
 #include "GetKeytabControl.h"
 
 static asn_TYPE_member_t asn_MBR_GetKeytabControl_1[] = {
@@ -39,9 +37,9 @@ static asn_TYPE_member_t asn_MBR_GetKeytabControl_1[] = {
 		},
 };
 static asn_TYPE_tag2member_t asn_MAP_GetKeytabControl_tag2el_1[] = {
-    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* newkeys at 7 */
-    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* curkeys at 8 */
-    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* reply at 10 */
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* newkeys */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* curkeys */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* reply */
 };
 static asn_CHOICE_specifics_t asn_SPC_GetKeytabControl_specs_1 = {
 	sizeof(struct GetKeytabControl),
diff --git a/asn1/asn1c/GetKeytabControl.h b/asn1/asn1c/GetKeytabControl.h
index 5f5fcd22e74f65e9356be886520b8ddd3cac348c..fc012c8461052b7225db148e40e46de314468cb0 100644
--- a/asn1/asn1c/GetKeytabControl.h
+++ b/asn1/asn1c/GetKeytabControl.h
@@ -1,5 +1,5 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
@@ -50,3 +50,4 @@ extern asn_TYPE_descriptor_t asn_DEF_GetKeytabControl;
 #endif
 
 #endif	/* _GetKeytabControl_H_ */
+#include <asn_internal.h>
diff --git a/asn1/asn1c/INTEGER.c b/asn1/asn1c/INTEGER.c
index 9c8b9ed3a5d778c30185842ca04cc5d8f9ca058b..38ddb60bd19bf59e491636d53e01df24aef6be58 100644
--- a/asn1/asn1c/INTEGER.c
+++ b/asn1/asn1c/INTEGER.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm at lionet.info>.
+ * Copyright (c) 2003-2014 Lev Walkin <vlm at lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
@@ -24,8 +24,13 @@ asn_TYPE_descriptor_t asn_DEF_INTEGER = {
 	INTEGER_encode_der,
 	INTEGER_decode_xer,
 	INTEGER_encode_xer,
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+#else
 	INTEGER_decode_uper,	/* Unaligned PER decoder */
 	INTEGER_encode_uper,	/* Unaligned PER encoder */
+#endif	/* ASN_DISABLE_PER_SUPPORT */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_INTEGER_tags,
 	sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),
@@ -106,47 +111,30 @@ INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_by
 	char scratch[32];	/* Enough for 64-bit integer */
 	uint8_t *buf = st->buf;
 	uint8_t *buf_end = st->buf + st->size;
-	signed long accum;
+	signed long value;
 	ssize_t wrote = 0;
 	char *p;
 	int ret;
 
-	/*
-	 * Advance buf pointer until the start of the value's body.
-	 * This will make us able to process large integers using simple case,
-	 * when the actual value is small
-	 * (0x0000000000abcdef would yield a fine 0x00abcdef)
-	 */
-	/* Skip the insignificant leading bytes */
-	for(; buf < buf_end-1; buf++) {
-		switch(*buf) {
-		case 0x00: if((buf[1] & 0x80) == 0) continue; break;
-		case 0xff: if((buf[1] & 0x80) != 0) continue; break;
-		}
-		break;
-	}
+	if(specs && specs->field_unsigned)
+		ret = asn_INTEGER2ulong(st, (unsigned long *)&value);
+	else
+		ret = asn_INTEGER2long(st, &value);
 
 	/* Simple case: the integer size is small */
-	if((size_t)(buf_end - buf) <= sizeof(accum)) {
+	if(ret == 0) {
 		const asn_INTEGER_enum_map_t *el;
 		size_t scrsize;
 		char *scr;
 
-		if(buf == buf_end) {
-			accum = 0;
-		} else {
-			accum = (*buf & 0x80) ? -1 : 0;
-			for(; buf < buf_end; buf++)
-				accum = (accum << 8) | *buf;
-		}
-
-		el = INTEGER_map_value2enum(specs, accum);
+		el = (value >= 0 || !specs || !specs->field_unsigned)
+			? INTEGER_map_value2enum(specs, value) : 0;
 		if(el) {
 			scrsize = el->enum_len + 32;
 			scr = (char *)alloca(scrsize);
 			if(plainOrXER == 0)
 				ret = snprintf(scr, scrsize,
-					"%ld (%s)", accum, el->enum_name);
+					"%ld (%s)", value, el->enum_name);
 			else
 				ret = snprintf(scr, scrsize,
 					"<%s/>", el->enum_name);
@@ -158,7 +146,9 @@ INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_by
 		} else {
 			scrsize = sizeof(scratch);
 			scr = scratch;
-			ret = snprintf(scr, scrsize, "%ld", accum);
+			ret = snprintf(scr, scrsize,
+				(specs && specs->field_unsigned)
+				?"%lu":"%ld", value);
 		}
 		assert(ret > 0 && (size_t)ret < scrsize);
 		return (cb(scr, ret, app_key) < 0) ? -1 : ret;
@@ -317,57 +307,71 @@ INTEGER_st_prealloc(INTEGER_t *st, int min_size) {
 static enum xer_pbd_rval
 INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	INTEGER_t *st = (INTEGER_t *)sptr;
-	long sign = 1;
-	long value;
+	long dec_value;
+	long hex_value = 0;
 	const char *lp;
 	const char *lstart = (const char *)chunk_buf;
 	const char *lstop = lstart + chunk_size;
 	enum {
-		ST_SKIPSPACE,
+		ST_LEADSPACE,
 		ST_SKIPSPHEX,
 		ST_WAITDIGITS,
 		ST_DIGITS,
+		ST_DIGITS_TRAILSPACE,
 		ST_HEXDIGIT1,
 		ST_HEXDIGIT2,
+		ST_HEXDIGITS_TRAILSPACE,
 		ST_HEXCOLON,
-		ST_EXTRASTUFF
-	} state = ST_SKIPSPACE;
+		ST_END_ENUM,
+		ST_UNEXPECTED
+	} state = ST_LEADSPACE;
+	const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */
+	const char *dec_value_end = 0;
 
 	if(chunk_size)
-		ASN_DEBUG("INTEGER body %d 0x%2x..0x%2x",
-			chunk_size, *lstart, lstop[-1]);
+		ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x",
+			(long)chunk_size, *lstart, lstop[-1]);
+
+	if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
+		return XPBD_SYSTEM_FAILURE;
 
 	/*
 	 * We may have received a tag here. It will be processed inline.
 	 * Use strtoul()-like code and serialize the result.
 	 */
-	for(value = 0, lp = lstart; lp < lstop; lp++) {
+	for(lp = lstart; lp < lstop; lp++) {
 		int lv = *lp;
 		switch(lv) {
 		case 0x09: case 0x0a: case 0x0d: case 0x20:
 			switch(state) {
-			case ST_SKIPSPACE:
+			case ST_LEADSPACE:
+			case ST_DIGITS_TRAILSPACE:
+			case ST_HEXDIGITS_TRAILSPACE:
 			case ST_SKIPSPHEX:
 				continue;
+			case ST_DIGITS:
+				dec_value_end = lp;
+				state = ST_DIGITS_TRAILSPACE;
+				continue;
 			case ST_HEXCOLON:
-				if(xer_is_whitespace(lp, lstop - lp)) {
-					lp = lstop - 1;
-					continue;
-				}
-				break;
+				state = ST_HEXDIGITS_TRAILSPACE;
+				continue;
 			default:
 				break;
 			}
 			break;
 		case 0x2d:	/* '-' */
-			if(state == ST_SKIPSPACE) {
-				sign = -1;
+			if(state == ST_LEADSPACE) {
+				dec_value = 0;
+				dec_value_start = lp;
 				state = ST_WAITDIGITS;
 				continue;
 			}
 			break;
 		case 0x2b:	/* '+' */
-			if(state == ST_SKIPSPACE) {
+			if(state == ST_LEADSPACE) {
+				dec_value = 0;
+				dec_value_start = lp;
 				state = ST_WAITDIGITS;
 				continue;
 			}
@@ -375,48 +379,32 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun
 		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
 		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
 			switch(state) {
-			case ST_DIGITS: break;
+			case ST_DIGITS: continue;
 			case ST_SKIPSPHEX:	/* Fall through */
 			case ST_HEXDIGIT1:
-				value = (lv - 0x30) << 4;
+				hex_value = (lv - 0x30) << 4;
 				state = ST_HEXDIGIT2;
 				continue;
 			case ST_HEXDIGIT2:
-				value += (lv - 0x30);
+				hex_value += (lv - 0x30);
 				state = ST_HEXCOLON;
-				st->buf[st->size++] = value;
+				st->buf[st->size++] = (uint8_t)hex_value;
 				continue;
 			case ST_HEXCOLON:
 				return XPBD_BROKEN_ENCODING;
-			default:
+			case ST_LEADSPACE:
+				dec_value = 0;
+				dec_value_start = lp;
+				/* FALL THROUGH */
+			case ST_WAITDIGITS:
 				state = ST_DIGITS;
+				continue;
+			default:
 				break;
 			}
-
-		    {
-			long new_value = value * 10;
-
-			if(new_value / 10 != value)
-				/* Overflow */
-				return XPBD_DECODER_LIMIT;
-
-			value = new_value + (lv - 0x30);
-			/* Check for two's complement overflow */
-			if(value < 0) {
-				/* Check whether it is a LONG_MIN */
-				if(sign == -1
-				&& (unsigned long)value
-						== ~((unsigned long)-1 >> 1)) {
-					sign = 1;
-				} else {
-					/* Overflow */
-					return XPBD_DECODER_LIMIT;
-				}
-			}
-		    }
-			continue;
-		case 0x3c:	/* '<' */
-			if(state == ST_SKIPSPACE) {
+			break;
+		case 0x3c:	/* '<', start of XML encoded enumeration */
+			if(state == ST_LEADSPACE) {
 				const asn_INTEGER_enum_map_t *el;
 				el = INTEGER_map_enum2value(
 					(asn_INTEGER_specifics_t *)
@@ -424,8 +412,8 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun
 				if(el) {
 					ASN_DEBUG("Found \"%s\" => %ld",
 						el->enum_name, el->nat_value);
-					state = ST_DIGITS;
-					value = el->nat_value;
+					dec_value = el->nat_value;
+					state = ST_END_ENUM;
 					lp = lstop - 1;
 					continue;
 				}
@@ -443,13 +431,12 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun
 				 * places as a decimal value.
 				 * Switch decoding mode. */
 				ASN_DEBUG("INTEGER re-evaluate as hex form");
-				if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
-					return XPBD_SYSTEM_FAILURE;
 				state = ST_SKIPSPHEX;
+				dec_value_start = 0;
 				lp = lstart - 1;
 				continue;
 			} else {
-				ASN_DEBUG("state %d at %d", state, lp - lstart);
+				ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart));
 				break;
 			}
 		/* [A-Fa-f] */
@@ -457,24 +444,23 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun
 		case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:
 			switch(state) {
 			case ST_SKIPSPHEX:
-			case ST_SKIPSPACE: /* Fall through */
+			case ST_LEADSPACE: /* Fall through */
 			case ST_HEXDIGIT1:
-				value = lv - ((lv < 0x61) ? 0x41 : 0x61);
-				value += 10;
-				value <<= 4;
+				hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61);
+				hex_value += 10;
+				hex_value <<= 4;
 				state = ST_HEXDIGIT2;
 				continue;
 			case ST_HEXDIGIT2:
-				value += lv - ((lv < 0x61) ? 0x41 : 0x61);
-				value += 10;
-				st->buf[st->size++] = value;
+				hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61);
+				hex_value += 10;
+				st->buf[st->size++] = (uint8_t)hex_value;
 				state = ST_HEXCOLON;
 				continue;
 			case ST_DIGITS:
 				ASN_DEBUG("INTEGER re-evaluate as hex form");
-				if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
-					return XPBD_SYSTEM_FAILURE;
 				state = ST_SKIPSPHEX;
+				dec_value_start = 0;
 				lp = lstart - 1;
 				continue;
 			default:
@@ -484,39 +470,54 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun
 		}
 
 		/* Found extra non-numeric stuff */
-		ASN_DEBUG("Found non-numeric 0x%2x at %d",
-			lv, lp - lstart);
-		state = ST_EXTRASTUFF;
+		ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld",
+			lv, (long)(lp - lstart));
+		state = ST_UNEXPECTED;
 		break;
 	}
 
 	switch(state) {
+	case ST_END_ENUM:
+		/* Got a complete and valid enumeration encoded as a tag. */
+		break;
 	case ST_DIGITS:
-		/* Everything is cool */
+		dec_value_end = lstop;
+		/* FALL THROUGH */
+	case ST_DIGITS_TRAILSPACE:
+		/* The last symbol encountered was a digit. */
+		switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) {
+		case ASN_STRTOL_OK:
+			break;
+		case ASN_STRTOL_ERROR_RANGE:
+			return XPBD_DECODER_LIMIT;
+		case ASN_STRTOL_ERROR_INVAL:
+		case ASN_STRTOL_EXPECT_MORE:
+		case ASN_STRTOL_EXTRA_DATA:
+			return XPBD_BROKEN_ENCODING;
+		}
 		break;
 	case ST_HEXCOLON:
+	case ST_HEXDIGITS_TRAILSPACE:
 		st->buf[st->size] = 0;	/* Just in case termination */
 		return XPBD_BODY_CONSUMED;
 	case ST_HEXDIGIT1:
 	case ST_HEXDIGIT2:
 	case ST_SKIPSPHEX:
 		return XPBD_BROKEN_ENCODING;
-	default:
-		if(xer_is_whitespace(lp, lstop - lp)) {
-			if(state != ST_EXTRASTUFF)
-				return XPBD_NOT_BODY_IGNORE;
-			break;
-		} else {
-			ASN_DEBUG("INTEGER: No useful digits (state %d)",
-				state);
-			return XPBD_BROKEN_ENCODING;	/* No digits */
-		}
-		break;
+	case ST_LEADSPACE:
+		/* Content not found */
+		return XPBD_NOT_BODY_IGNORE;
+	case ST_WAITDIGITS:
+	case ST_UNEXPECTED:
+		ASN_DEBUG("INTEGER: No useful digits (state %d)", state);
+		return XPBD_BROKEN_ENCODING;	/* No digits */
 	}
 
-	value *= sign;	/* Change sign, if needed */
-
-	if(asn_long2INTEGER(st, value))
+	/*
+	 * Convert the result of parsing of enumeration or a straight
+	 * decimal value into a BER representation.
+	 */
+	if(asn_long2INTEGER(st, dec_value))
 		return XPBD_SYSTEM_FAILURE;
 
 	return XPBD_BODY_CONSUMED;
@@ -551,9 +552,12 @@ INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
 	_ASN_ENCODED_OK(er);
 }
 
+#ifndef	ASN_DISABLE_PER_SUPPORT
+
 asn_dec_rval_t
 INTEGER_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_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	asn_dec_rval_t rval = { RC_OK, 0 };
 	INTEGER_t *st = (INTEGER_t *)*sptr;
 	asn_per_constraint_t *ct;
@@ -576,6 +580,8 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	}
 
 	FREEMEM(st->buf);
+	st->buf = 0;
+	st->size = 0;
 	if(ct) {
 		if(ct->flags & APC_SEMI_CONSTRAINED) {
 			st->buf = (uint8_t *)CALLOC(1, 2);
@@ -586,25 +592,38 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 			st->buf = (uint8_t *)MALLOC(1 + size + 1);
 			if(!st->buf) _ASN_DECODE_FAILED;
 			st->size = size;
-		} else {
-			st->size = 0;
 		}
-	} else {
-		st->size = 0;
 	}
 
-	/* X.691, #12.2.2 */
+	/* X.691-2008/11, #13.2.2, constrained whole number */
 	if(ct && ct->flags != APC_UNCONSTRAINED) {
-		/* #10.5.6 */
+		/* #11.5.6 */
 		ASN_DEBUG("Integer with range %d bits", ct->range_bits);
 		if(ct->range_bits >= 0) {
-			long value = per_get_few_bits(pd, ct->range_bits);
-			if(value < 0) _ASN_DECODE_STARVED;
-			ASN_DEBUG("Got value %ld + low %ld",
-				value, ct->lower_bound);
-			value += ct->lower_bound;
-			if(asn_long2INTEGER(st, value))
+			if((size_t)ct->range_bits > 8 * sizeof(unsigned long))
 				_ASN_DECODE_FAILED;
+
+			if(specs && specs->field_unsigned) {
+				unsigned long uvalue;
+				if(uper_get_constrained_whole_number(pd,
+					&uvalue, ct->range_bits))
+					_ASN_DECODE_STARVED;
+				ASN_DEBUG("Got value %lu + low %ld",
+					uvalue, ct->lower_bound);
+				uvalue += ct->lower_bound;
+				if(asn_ulong2INTEGER(st, uvalue))
+					_ASN_DECODE_FAILED;
+			} else {
+				unsigned long svalue;
+				if(uper_get_constrained_whole_number(pd,
+					&svalue, ct->range_bits))
+					_ASN_DECODE_STARVED;
+				ASN_DEBUG("Got value %ld + low %ld",
+					svalue, ct->lower_bound);
+				svalue += ct->lower_bound;
+				if(asn_long2INTEGER(st, svalue))
+					_ASN_DECODE_FAILED;
+			}
 			return rval;
 		}
 	} else {
@@ -649,6 +668,7 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 asn_enc_rval_t
 INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	asn_enc_rval_t er;
 	INTEGER_t *st = (INTEGER_t *)sptr;
 	const uint8_t *buf;
@@ -665,21 +685,41 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
 
 	if(ct) {
 		int inext = 0;
-		if(asn_INTEGER2long(st, &value))
-			_ASN_ENCODE_FAILED;
-		/* Check proper range */
-		if(ct->flags & APC_SEMI_CONSTRAINED) {
-			if(value < ct->lower_bound)
-				inext = 1;
-		} else if(ct->range_bits >= 0) {
-			if(value < ct->lower_bound
-			|| value > ct->upper_bound)
-				inext = 1;
+		if(specs && specs->field_unsigned) {
+			unsigned long uval;
+			if(asn_INTEGER2ulong(st, &uval))
+				_ASN_ENCODE_FAILED;
+			/* Check proper range */
+			if(ct->flags & APC_SEMI_CONSTRAINED) {
+				if(uval < (unsigned long)ct->lower_bound)
+					inext = 1;
+			} else if(ct->range_bits >= 0) {
+				if(uval < (unsigned long)ct->lower_bound
+				|| uval > (unsigned long)ct->upper_bound)
+					inext = 1;
+			}
+			ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s",
+				uval, st->buf[0], st->size,
+				ct->lower_bound, ct->upper_bound,
+				inext ? "ext" : "fix");
+			value = uval;
+		} else {
+			if(asn_INTEGER2long(st, &value))
+				_ASN_ENCODE_FAILED;
+			/* Check proper range */
+			if(ct->flags & APC_SEMI_CONSTRAINED) {
+				if(value < ct->lower_bound)
+					inext = 1;
+			} else if(ct->range_bits >= 0) {
+				if(value < ct->lower_bound
+				|| value > ct->upper_bound)
+					inext = 1;
+			}
+			ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s",
+				value, st->buf[0], st->size,
+				ct->lower_bound, ct->upper_bound,
+				inext ? "ext" : "fix");
 		}
-		ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s",
-			value, st->buf[0], st->size,
-			ct->lower_bound, ct->upper_bound,
-			inext ? "ext" : "fix");
 		if(ct->flags & APC_EXTENSIBLE) {
 			if(per_put_few_bits(po, inext, 1))
 				_ASN_ENCODE_FAILED;
@@ -690,13 +730,13 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
 	}
 
 
-	/* X.691, #12.2.2 */
+	/* X.691-11/2008, #13.2.2, test if constrained whole number */
 	if(ct && ct->range_bits >= 0) {
-		/* #10.5.6 */
-		ASN_DEBUG("Encoding integer with range %d bits",
-			ct->range_bits);
-		if(per_put_few_bits(po, value - ct->lower_bound,
-				ct->range_bits))
+		/* #11.5.6 -> #11.3 */
+		ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits",
+			value, value - ct->lower_bound, ct->range_bits);
+		unsigned long v = value - ct->lower_bound;
+		if(uper_put_constrained_whole_number_u(po, v, ct->range_bits))
 			_ASN_ENCODE_FAILED;
 		_ASN_ENCODED_OK(er);
 	}
@@ -719,6 +759,8 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
 	_ASN_ENCODED_OK(er);
 }
 
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+
 int
 asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
 	uint8_t *b, *end;
@@ -780,6 +822,63 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
 }
 
 int
+asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) {
+	uint8_t *b, *end;
+	unsigned long l;
+	size_t size;
+
+	if(!iptr || !iptr->buf || !lptr) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	b = iptr->buf;
+	size = iptr->size;
+	end = b + size;
+
+	/* If all extra leading bytes are zeroes, ignore them */
+	for(; size > sizeof(unsigned long); b++, size--) {
+		if(*b) {
+			/* Value won't fit unsigned long */
+			errno = ERANGE;
+			return -1;
+		}
+	}
+
+	/* Conversion engine */
+	for(l = 0; b < end; b++)
+		l = (l << 8) | *b;
+
+	*lptr = l;
+	return 0;
+}
+
+int
+asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) {
+	uint8_t *buf;
+	uint8_t *end;
+	uint8_t *b;
+	int shr;
+
+	if(value <= LONG_MAX)
+		return asn_long2INTEGER(st, value);
+
+	buf = (uint8_t *)MALLOC(1 + sizeof(value));
+	if(!buf) return -1;
+
+	end = buf + (sizeof(value) + 1);
+	buf[0] = 0;
+	for(b = buf + 1, shr = (sizeof(long)-1)*8; b < end; shr -= 8, b++)
+		*b = (uint8_t)(value >> shr);
+
+	if(st->buf) FREEMEM(st->buf);
+	st->buf = buf;
+	st->size = 1 + sizeof(value);
+
+	return 0;
+}
+
+int
 asn_long2INTEGER(INTEGER_t *st, long value) {
 	uint8_t *buf, *bp;
 	uint8_t *p;
@@ -833,3 +932,92 @@ asn_long2INTEGER(INTEGER_t *st, long value) {
 
 	return 0;
 }
+
+/*
+ * This function is going to be DEPRECATED soon.
+ */
+enum asn_strtol_result_e
+asn_strtol(const char *str, const char *end, long *lp) {
+    const char *endp = end;
+
+    switch(asn_strtol_lim(str, &endp, lp)) {
+    case ASN_STRTOL_ERROR_RANGE:
+        return ASN_STRTOL_ERROR_RANGE;
+    case ASN_STRTOL_ERROR_INVAL:
+        return ASN_STRTOL_ERROR_INVAL;
+    case ASN_STRTOL_EXPECT_MORE:
+        return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+    case ASN_STRTOL_OK:
+        return ASN_STRTOL_OK;
+    case ASN_STRTOL_EXTRA_DATA:
+        return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+    }
+
+    return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+}
+
+/*
+ * Parse the number in the given string until the given *end position,
+ * returning the position after the last parsed character back using the
+ * same (*end) pointer.
+ * WARNING: This behavior is different from the standard strtol(3).
+ */
+enum asn_strtol_result_e
+asn_strtol_lim(const char *str, const char **end, long *lp) {
+	int sign = 1;
+	long l;
+
+	const long upper_boundary = LONG_MAX / 10;
+	long last_digit_max = LONG_MAX % 10;
+
+	if(str >= *end) return ASN_STRTOL_ERROR_INVAL;
+
+	switch(*str) {
+	case '-':
+		last_digit_max++;
+		sign = -1;
+	case '+':
+		str++;
+		if(str >= *end) {
+			*end = str;
+			return ASN_STRTOL_EXPECT_MORE;
+		}
+	}
+
+	for(l = 0; str < (*end); str++) {
+		switch(*str) {
+		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
+			int d = *str - '0';
+			if(l < upper_boundary) {
+				l = l * 10 + d;
+			} else if(l == upper_boundary) {
+				if(d <= last_digit_max) {
+					if(sign > 0) {
+						l = l * 10 + d;
+					} else {
+						sign = 1;
+						l = -l * 10 - d;
+					}
+				} else {
+					*end = str;
+					return ASN_STRTOL_ERROR_RANGE;
+				}
+			} else {
+				*end = str;
+				return ASN_STRTOL_ERROR_RANGE;
+			}
+		    }
+		    continue;
+		default:
+		    *end = str;
+		    *lp = sign * l;
+		    return ASN_STRTOL_EXTRA_DATA;
+		}
+	}
+
+	*end = str;
+	*lp = sign * l;
+	return ASN_STRTOL_OK;
+}
+
diff --git a/asn1/asn1c/INTEGER.h b/asn1/asn1c/INTEGER.h
index 62832b12e1271e1f27a5edd5b4a0f82986ff2fc3..fe08b038167e6a002f0da0d98ef0444c800c8318 100644
--- a/asn1/asn1c/INTEGER.h
+++ b/asn1/asn1c/INTEGER.h
@@ -30,6 +30,8 @@ typedef struct asn_INTEGER_specifics_s {
 	int map_count;				/* Elements in either map */
 	int extension;				/* This map is extensible */
 	int strict_enumeration;			/* Enumeration set is fixed */
+	int field_width;			/* Size of native integer */
+	int field_unsigned;			/* Signed=0, unsigned=1 */
 } asn_INTEGER_specifics_t;
 
 asn_struct_print_f INTEGER_print;
@@ -51,7 +53,22 @@ per_type_encoder_f INTEGER_encode_uper;
  * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()).
  */
 int asn_INTEGER2long(const INTEGER_t *i, long *l);
+int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l);
 int asn_long2INTEGER(INTEGER_t *i, long l);
+int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l);
+
+/* A a reified version of strtol(3) with nicer error reporting. */
+enum asn_strtol_result_e {
+    ASN_STRTOL_ERROR_RANGE = -3,  /* Input outside of numeric range for long type */
+    ASN_STRTOL_ERROR_INVAL = -2,  /* Invalid data encountered (e.g., "+-") */
+    ASN_STRTOL_EXPECT_MORE = -1,  /* More data expected (e.g. "+") */
+    ASN_STRTOL_OK          =  0,  /* Conversion succeded, number ends at (*end) */
+    ASN_STRTOL_EXTRA_DATA  =  1,  /* Conversion succeded, but the string has extra stuff */
+};
+enum asn_strtol_result_e asn_strtol_lim(const char *str, const char **end, long *l);
+
+/* The asn_strtol is going to be DEPRECATED soon */
+enum asn_strtol_result_e asn_strtol(const char *str, const char *end, long *l);
 
 /*
  * Convert the integer value into the corresponding enumeration map entry.
diff --git a/asn1/asn1c/Int32.c b/asn1/asn1c/Int32.c
index 600934beed3fcff4527de4969c1d3effd272355e..7c11ea5fb197a855398d51d0f6808d267229b032 100644
--- a/asn1/asn1c/Int32.c
+++ b/asn1/asn1c/Int32.c
@@ -1,12 +1,10 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
  */
 
-#include <asn_internal.h>
-
 #include "Int32.h"
 
 int
@@ -23,7 +21,7 @@ Int32_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 	
 	value = *(const long *)sptr;
 	
-	if((value >= -2147483648 && value <= 2147483647)) {
+	if((value >= (-2147483647L - 1) && value <= 2147483647)) {
 		/* Constraint check succeeded */
 		return 0;
 	} else {
@@ -42,6 +40,7 @@ static void
 Int32_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) {
 	td->free_struct    = asn_DEF_NativeInteger.free_struct;
 	td->print_struct   = asn_DEF_NativeInteger.print_struct;
+	td->check_constraints = asn_DEF_NativeInteger.check_constraints;
 	td->ber_decoder    = asn_DEF_NativeInteger.ber_decoder;
 	td->der_encoder    = asn_DEF_NativeInteger.der_encoder;
 	td->xer_decoder    = asn_DEF_NativeInteger.xer_decoder;
diff --git a/asn1/asn1c/Int32.h b/asn1/asn1c/Int32.h
index 9ee672ec9b5d49cfaddd2bf0bfb5ab2c5015d498..2f1a673d26de54919840efa169dbd3897d77caed 100644
--- a/asn1/asn1c/Int32.h
+++ b/asn1/asn1c/Int32.h
@@ -1,5 +1,5 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
@@ -36,3 +36,4 @@ xer_type_encoder_f Int32_encode_xer;
 #endif
 
 #endif	/* _Int32_H_ */
+#include <asn_internal.h>
diff --git a/asn1/asn1c/KrbKey.c b/asn1/asn1c/KrbKey.c
index 3abbdf1b6e42ee759c149b6cbfa4b53695a2f0a3..0454ea6422fd23f1223bd038a8bfe3ed1093bacb 100644
--- a/asn1/asn1c/KrbKey.c
+++ b/asn1/asn1c/KrbKey.c
@@ -1,12 +1,10 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
  */
 
-#include <asn_internal.h>
-
 #include "KrbKey.h"
 
 static asn_TYPE_member_t asn_MBR_KrbKey_1[] = {
@@ -42,9 +40,9 @@ static ber_tlv_tag_t asn_DEF_KrbKey_tags_1[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
 };
 static asn_TYPE_tag2member_t asn_MAP_KrbKey_tag2el_1[] = {
-    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* key at 28 */
-    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* salt at 29 */
-    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* s2kparams at 30 */
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* key */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* salt */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* s2kparams */
 };
 static asn_SEQUENCE_specifics_t asn_SPC_KrbKey_specs_1 = {
 	sizeof(struct KrbKey),
diff --git a/asn1/asn1c/KrbKey.h b/asn1/asn1c/KrbKey.h
index 3134be528d1b9848b17d5eaee941aeef6fbd91b6..ac517e33b2c3064825820792720f6e8d8d110f92 100644
--- a/asn1/asn1c/KrbKey.h
+++ b/asn1/asn1c/KrbKey.h
@@ -1,5 +1,5 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
@@ -44,3 +44,4 @@ extern asn_TYPE_descriptor_t asn_DEF_KrbKey;
 #include "TypeValuePair.h"
 
 #endif	/* _KrbKey_H_ */
+#include <asn_internal.h>
diff --git a/asn1/asn1c/NativeEnumerated.c b/asn1/asn1c/NativeEnumerated.c
index e3af1ca49b2c722513876e70219bb0ac8e74cbd9..1554220f87ab7f5ba230b939343b989a33bab0bf 100644
--- a/asn1/asn1c/NativeEnumerated.c
+++ b/asn1/asn1c/NativeEnumerated.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2004 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Copyright (c) 2004, 2007 Lev Walkin <vlm at lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 /*
@@ -177,9 +177,9 @@ NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td,
 			inext = 1;
 	}
 	if(ct->flags & APC_EXTENSIBLE) {
-		if(per_put_few_bits(po, inext, 0))
+		if(per_put_few_bits(po, inext, 1))
 			_ASN_ENCODE_FAILED;
-		ct = 0;
+		if(inext) ct = 0;
 	} else if(inext) {
 		_ASN_ENCODE_FAILED;
 	}
@@ -196,7 +196,10 @@ NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td,
 	/*
 	 * X.691, #10.6: normally small non-negative whole number;
 	 */
-	if(uper_put_nsnnwn(po, value - (specs->extension - 1)))
+	ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld",
+		value, specs->extension, inext,
+		value - (inext ? (specs->extension - 1) : 0));
+	if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0)))
 		_ASN_ENCODE_FAILED;
 
 	_ASN_ENCODED_OK(er);
diff --git a/asn1/asn1c/NativeInteger.c b/asn1/asn1c/NativeInteger.c
index 34599f6186cd77d38106e171ec3b24cb29638afa..cffd0be8e6b0451de80bff13252f7100a4009bda 100644
--- a/asn1/asn1c/NativeInteger.c
+++ b/asn1/asn1c/NativeInteger.c
@@ -48,6 +48,7 @@ asn_dec_rval_t
 NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 	asn_TYPE_descriptor_t *td,
 	void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	long *native = (long *)*nint_ptr;
 	asn_dec_rval_t rval;
 	ber_tlv_len_t length;
@@ -105,7 +106,9 @@ NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 		tmp.buf = (uint8_t *)unconst_buf.nonconstbuf;
 		tmp.size = length;
 
-		if(asn_INTEGER2long(&tmp, &l)) {
+		if((specs&&specs->field_unsigned)
+			? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */
+			: asn_INTEGER2long(&tmp, &l)) {
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
 			return rval;
@@ -145,7 +148,7 @@ NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr,
 
 	/* Prepare a fake INTEGER */
 	for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8)
-		*p = native;
+		*p = (uint8_t)native;
 
 	tmp.buf = buf;
 	tmp.size = sizeof(buf);
@@ -167,6 +170,7 @@ asn_dec_rval_t
 NativeInteger_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) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	asn_dec_rval_t rval;
 	INTEGER_t st;
 	void *st_ptr = (void *)&st;
@@ -182,7 +186,9 @@ NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx,
 		opt_mname, buf_ptr, size);
 	if(rval.code == RC_OK) {
 		long l;
-		if(asn_INTEGER2long(&st, &l)) {
+		if((specs&&specs->field_unsigned)
+			? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */
+			: asn_INTEGER2long(&st, &l)) {
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
 		} else {
@@ -205,6 +211,7 @@ asn_enc_rval_t
 NativeInteger_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) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	char scratch[32];	/* Enough for 64-bit int */
 	asn_enc_rval_t er;
 	const long *native = (const long *)sptr;
@@ -214,7 +221,9 @@ NativeInteger_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
 
 	if(!native) _ASN_ENCODE_FAILED;
 
-	er.encoded = snprintf(scratch, sizeof(scratch), "%ld", *native);
+	er.encoded = snprintf(scratch, sizeof(scratch),
+			(specs && specs->field_unsigned)
+			? "%lu" : "%ld", *native);
 	if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch)
 		|| cb(scratch, er.encoded, app_key) < 0)
 		_ASN_ENCODE_FAILED;
@@ -227,6 +236,7 @@ NativeInteger_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_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	asn_dec_rval_t rval;
 	long *native = (long *)*sptr;
 	INTEGER_t tmpint;
@@ -244,7 +254,9 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 	rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints,
 				   &tmpintptr, pd);
 	if(rval.code == RC_OK) {
-		if(asn_INTEGER2long(&tmpint, native))
+		if((specs&&specs->field_unsigned)
+			? asn_INTEGER2ulong(&tmpint, (unsigned long *)native)
+			: asn_INTEGER2long(&tmpint, native))
 			rval.code = RC_FAIL;
 		else
 			ASN_DEBUG("NativeInteger %s got value %ld",
@@ -258,6 +270,7 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 asn_enc_rval_t
 NativeInteger_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	asn_enc_rval_t er;
 	long native;
 	INTEGER_t tmpint;
@@ -269,7 +282,9 @@ NativeInteger_encode_uper(asn_TYPE_descriptor_t *td,
 	ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native);
 
 	memset(&tmpint, 0, sizeof(tmpint));
-	if(asn_long2INTEGER(&tmpint, native))
+	if((specs&&specs->field_unsigned)
+		? asn_ulong2INTEGER(&tmpint, native)
+		: asn_long2INTEGER(&tmpint, native))
 		_ASN_ENCODE_FAILED;
 	er = INTEGER_encode_uper(td, constraints, &tmpint, po);
 	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
@@ -282,6 +297,7 @@ NativeInteger_encode_uper(asn_TYPE_descriptor_t *td,
 int
 NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	const long *native = (const long *)sptr;
 	char scratch[32];	/* Enough for 64-bit int */
 	int ret;
@@ -290,7 +306,9 @@ NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	(void)ilevel;	/* Unused argument */
 
 	if(native) {
-		ret = snprintf(scratch, sizeof(scratch), "%ld", *native);
+		ret = snprintf(scratch, sizeof(scratch),
+			(specs && specs->field_unsigned)
+			? "%lu" : "%ld", *native);
 		assert(ret > 0 && (size_t)ret < sizeof(scratch));
 		return (cb(scratch, ret, app_key) < 0) ? -1 : 0;
 	} else {
diff --git a/asn1/asn1c/OCTET_STRING.c b/asn1/asn1c/OCTET_STRING.c
index 3a83bd98c5b30a10b5fb12b78bd4f317e8abb27a..f2eec13aa4dfe1eca3e618eff9d57939ed34bf0d 100644
--- a/asn1/asn1c/OCTET_STRING.c
+++ b/asn1/asn1c/OCTET_STRING.c
@@ -17,10 +17,12 @@ static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
 static asn_OCTET_STRING_specifics_t asn_DEF_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
+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_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
 	"OCTET STRING",		/* Canonical name */
@@ -103,15 +105,6 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
 	} 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
  * necessity to demonstrate that aquired skill everywhere afterwards.
@@ -185,11 +178,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);
 
@@ -230,7 +223,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;
@@ -309,7 +302,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,10 +327,10 @@ 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;
@@ -352,7 +345,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,7 +390,7 @@ 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;
@@ -431,7 +424,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 +457,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 +468,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--;
@@ -502,14 +495,14 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 	/*
 	 * BIT STRING-specific processing.
 	 */
-	if(type_variant == _TT_BIT_STRING && st->size) {
+	if(type_variant == ASN_OSUBV_BIT && st->size) {
 		/* Finalize BIT STRING: zero out unused bits. */
 		st->buf[st->size-1] &= 0xff << st->bits_unused;
 	}
 
 	ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld",
 		(long)consumed_myself, td->name,
-		(type_variant == _TT_GENERIC) ? (char *)st->buf : "<data>",
+		(type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "<data>",
 		(long)st->size);
 
 
@@ -528,7 +521,7 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
 				? (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;
+	enum asn_OS_Subvariant type_variant = specs->subvariant;
 	int fix_last_byte = 0;
 
 	ASN_DEBUG("%s %s as OCTET STRING",
@@ -537,10 +530,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,19 +542,19 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
 		}
 	} else {
 		/* Disallow: [<tag>] 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;
+		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);
@@ -595,7 +589,7 @@ OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
 	uint8_t *end;
 	size_t i;
 
-	if(!st || !st->buf)
+	if(!st || (!st->buf && st->size))
 		_ASN_ENCODE_FAILED;
 
 	er.encoded = 0;
@@ -751,7 +745,7 @@ OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr,
 	(void)ilevel;	/* Unused argument */
 	(void)flags;	/* Unused argument */
 
-	if(!st || !st->buf)
+	if(!st || (!st->buf && st->size))
 		_ASN_ENCODE_FAILED;
 
 	buf = st->buf;
@@ -1197,6 +1191,135 @@ OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx,
 		OCTET_STRING__convert_entrefs);
 }
 
+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) {
+	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) {
+		int code = per_get_few_bits(po, unit_bits);
+		int 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, 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, *buf, lb, ub + lb);
+			return -1;
+		}
+		if(per_put_few_bits(po, ch, unit_bits))
+			return -1;
+	}
+
+	return 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,
@@ -1205,18 +1328,62 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 	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);
+	asn_per_constraints_t *pc = constraints ? constraints
+				: td->per_constraints;
+	asn_per_constraint_t *cval;
+	asn_per_constraint_t *csiz;
 	asn_dec_rval_t rval = { RC_OK, 0 };
 	BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
 	ssize_t consumed_myself = 0;
 	int repeat;
-	int unit_bits = (specs->subvariant != 1) * 7 + 1;
+	enum {
+		OS__BPC_BIT	= 0,
+		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:
+		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;
+		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.
 	 */
@@ -1225,24 +1392,26 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 		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;
+			cval = &asn_DEF_OCTET_STRING_constraints.value;
+			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 +1420,70 @@ 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);
+		if(bpc == 0) {
+			int ubs = (csiz->upper_bound & 0x7);
+			st->bits_unused = ubs ? 8 - ubs : 0;
+		}
 		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, &repeat);
+		if(raw_len < 0) RETURN(RC_WMORE);
+		raw_len += csiz->lower_bound;
 
 		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) {
+		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 */
-		} else {
-			len_bytes = len_bits;
-			len_bits = len_bytes << 3;
 		}
 		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);
+		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);
+		}
 		if(ret < 0) RETURN(RC_WMORE);
 		st->size += len_bytes;
 	} while(repeat);
@@ -1306,41 +1499,87 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
 	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);
+	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;
-	int unit_bits = (specs->subvariant != 1) * 7 + 1;
-	asn_enc_rval_t er;
-	int ct_extensible = ct->flags & APC_EXTENSIBLE;
+	asn_enc_rval_t er = { 0, 0, 0 };
 	int inext = 0;		/* Lies not within extension root */
-	int sizeinunits = st->size;
+	unsigned int unit_bits;
+	unsigned int canonical_unit_bits;
+	unsigned int sizeinunits;
 	const uint8_t *buf;
 	int ret;
+	enum {
+		OS__BPC_BIT	= 0,
+		OS__BPC_CHAR	= 1,
+		OS__BPC_U16	= 2,
+		OS__BPC_U32	= 4
+	} bpc;	/* Bytes per character */
+	int ct_extensible;
 
-	if(!st || !st->buf)
+	if(!st || (!st->buf && st->size))
 		_ASN_ENCODE_FAILED;
 
-	if(unit_bits == 1) {
+	if(pc) {
+		cval = &pc->value;
+		csiz = &pc->size;
+	} else {
+		cval = &asn_DEF_OCTET_STRING_constraints.value;
+		csiz = &asn_DEF_OCTET_STRING_constraints.size;
+	}
+	ct_extensible = csiz->flags & APC_EXTENSIBLE;
+
+	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);
-		sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07);
+		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;
+		sizeinunits = 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;
+		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;
+		break;
 	}
 
 	ASN_DEBUG("Encoding %s into %d units of %d bits"
-		" (%d..%d, effective %d)%s",
+		" (%ld..%ld, effective %d)%s",
 		td->name, sizeinunits, unit_bits,
-		ct->lower_bound, ct->upper_bound,
-		ct->effective_bits, ct_extensible ? " EXT" : "");
+		csiz->lower_bound, csiz->upper_bound,
+		csiz->effective_bits, ct_extensible ? " EXT" : "");
 
-	/* Figure out wheter size lies within PER visible consrtaint */
+	/* Figure out whether size lies within PER visible constraint */
 
-	if(ct->effective_bits >= 0) {
-		if(sizeinunits < ct->lower_bound
-		|| sizeinunits > ct->upper_bound) {
+	if(csiz->effective_bits >= 0) {
+		if((int)sizeinunits < csiz->lower_bound
+		|| (int)sizeinunits > csiz->upper_bound) {
 			if(ct_extensible) {
-				ct = &asn_DEF_OCTET_STRING_constraint;
+				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;
@@ -1358,14 +1597,21 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
 	/* 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) {
+	if(csiz->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);
+				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;
-		ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits);
+		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);
 	}
@@ -1383,15 +1629,22 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
 		ssize_t maySave = uper_put_length(po, sizeinunits);
 		if(maySave < 0) _ASN_ENCODE_FAILED;
 
-		ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits);
+		ASN_DEBUG("Encoding %ld of %ld",
+			(long)maySave, (long)sizeinunits);
 
-		ret = per_put_many_bits(po, buf, maySave * unit_bits);
+		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(unit_bits == 1)
-			buf += maySave >> 3;
+		if(bpc)
+			buf += maySave * bpc;
 		else
-			buf += maySave;
+			buf += maySave >> 3;
 		sizeinunits -= maySave;
 		assert(!(maySave & 0x07) || !sizeinunits);
 	}
@@ -1412,7 +1665,8 @@ OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 
 	(void)td;	/* Unused argument */
 
-	if(!st || !st->buf) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
+	if(!st || (!st->buf && st->size))
+		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
 
 	/*
 	 * Dump the contents of the buffer in hexadecimal.
@@ -1448,7 +1702,7 @@ OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *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("<absent>", 8, app_key) < 0) ? -1 : 0;
@@ -1472,6 +1726,7 @@ OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) {
 
 	if(st->buf) {
 		FREEMEM(st->buf);
+		st->buf = 0;
 	}
 
 	/*
diff --git a/asn1/asn1c/OCTET_STRING.h b/asn1/asn1c/OCTET_STRING.h
index 5150161a7a1a19e8e7c123776684e66c1cd429cf..8df9a182d36345c5deb5a0cdc608fe77287cfa08 100644
--- a/asn1/asn1c/OCTET_STRING.h
+++ b/asn1/asn1c/OCTET_STRING.h
@@ -70,7 +70,13 @@ typedef struct asn_OCTET_STRING_specifics_s {
 	int struct_size;	/* Size of the structure */
 	int ctx_offset;		/* Offset of the asn_struct_ctx_t member */
 
-	int subvariant;		/* {0,1,2} for O-S, BIT STRING or ANY */
+	enum asn_OS_Subvariant {
+		ASN_OSUBV_ANY,	/* The open type (ANY) */
+		ASN_OSUBV_BIT,	/* BIT STRING */
+		ASN_OSUBV_STR,	/* String types, not {BMP,Universal}String  */
+		ASN_OSUBV_U16,	/* 16-bit character (BMPString) */
+		ASN_OSUBV_U32	/* 32-bit character (UniversalString) */
+	} subvariant;
 } asn_OCTET_STRING_specifics_t;
 
 #ifdef __cplusplus
diff --git a/asn1/asn1c/TypeValuePair.c b/asn1/asn1c/TypeValuePair.c
index 707eef3f65c4bf0a64b4864391e64865cc19d7ca..3e78d530aa3d71925278edd38ae25221e7bfc603 100644
--- a/asn1/asn1c/TypeValuePair.c
+++ b/asn1/asn1c/TypeValuePair.c
@@ -1,12 +1,10 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
  */
 
-#include <asn_internal.h>
-
 #include "TypeValuePair.h"
 
 static asn_TYPE_member_t asn_MBR_TypeValuePair_1[] = {
@@ -33,8 +31,8 @@ static ber_tlv_tag_t asn_DEF_TypeValuePair_tags_1[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
 };
 static asn_TYPE_tag2member_t asn_MAP_TypeValuePair_tag2el_1[] = {
-    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* type at 34 */
-    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* value at 35 */
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* type */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* value */
 };
 static asn_SEQUENCE_specifics_t asn_SPC_TypeValuePair_specs_1 = {
 	sizeof(struct TypeValuePair),
diff --git a/asn1/asn1c/TypeValuePair.h b/asn1/asn1c/TypeValuePair.h
index 538b4609c5f0fe051988885c84c3caf6d8b85452..39997cded703511c09868f968fac64236cb97124 100644
--- a/asn1/asn1c/TypeValuePair.h
+++ b/asn1/asn1c/TypeValuePair.h
@@ -1,5 +1,5 @@
 /*
- * Generated by asn1c-0.9.21 (http://lionet.info/asn1c)
+ * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "KeytabModule"
  * 	found in "ipa.asn1"
  * 	`asn1c -fskeletons-copy`
@@ -37,3 +37,4 @@ extern asn_TYPE_descriptor_t asn_DEF_TypeValuePair;
 #endif
 
 #endif	/* _TypeValuePair_H_ */
+#include <asn_internal.h>
diff --git a/asn1/asn1c/asn_codecs.h b/asn1/asn1c/asn_codecs.h
index 4a251d940880a03b24dc9f3fe41f2febb9b49211..e5600142aaa2125259236a23bb5451f0e41bcad7 100644
--- a/asn1/asn1c/asn_codecs.h
+++ b/asn1/asn1c/asn_codecs.h
@@ -62,7 +62,7 @@ typedef struct asn_enc_rval_s {
 	tmp_error.encoded = -1;					\
 	tmp_error.failed_type = td;				\
 	tmp_error.structure_ptr = sptr;				\
-	ASN_DEBUG("Failed to encode element %s", td->name);	\
+	ASN_DEBUG("Failed to encode element %s", td ? td->name : "");	\
 	return tmp_error;					\
 } while(0)
 #define	_ASN_ENCODED_OK(rval) do {				\
@@ -92,7 +92,7 @@ typedef struct asn_dec_rval_s {
 	asn_dec_rval_t tmp_error;				\
 	tmp_error.code = RC_FAIL;				\
 	tmp_error.consumed = 0;					\
-	ASN_DEBUG("Failed to decode element %s", td->name);	\
+	ASN_DEBUG("Failed to decode element %s", td ? td->name : "");	\
 	return tmp_error;					\
 } while(0)
 #define	_ASN_DECODE_STARVED do {				\
diff --git a/asn1/asn1c/asn_codecs_prim.c b/asn1/asn1c/asn_codecs_prim.c
index 4e5c63937adafc40a56b67fe5b3d9482220907d5..8e604a492a4d199bed6bf107513028c53136efdb 100644
--- a/asn1/asn1c/asn_codecs_prim.c
+++ b/asn1/asn1c/asn_codecs_prim.c
@@ -15,7 +15,7 @@ ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
 	void **sptr, const void *buf_ptr, size_t size, int tag_mode) {
 	ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
 	asn_dec_rval_t rval;
-	ber_tlv_len_t length;
+	ber_tlv_len_t length = 0; // =0 to avoid [incorrect] warning.
 
 	/*
 	 * If the structure is not there, allocate it.
@@ -143,20 +143,26 @@ struct xdp_arg_s {
 	int want_more;
 };
 
-
+/*
+ * Since some kinds of primitive values can be encoded using value-specific
+ * tags (<MINUS-INFINITY>, <enum-element>, etc), the primitive decoder must
+ * be supplied with such tags to parse them as needed.
+ */
 static int
 xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
 	enum xer_pbd_rval bret;
 
-	if(arg->decoded_something) {
-		if(xer_is_whitespace(chunk_buf, chunk_size))
-			return 0;	/* Skip it. */
-		/*
-		 * Decoding was done once already. Prohibit doing it again.
-		 */
+	/*
+	 * The chunk_buf is guaranteed to start at '<'.
+	 */
+	assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c);
+
+	/*
+	 * Decoding was performed once already. Prohibit doing it again.
+	 */
+	if(arg->decoded_something)
 		return -1;
-	}
 
 	bret = arg->prim_body_decoder(arg->type_descriptor,
 		arg->struct_key, chunk_buf, chunk_size);
@@ -177,13 +183,20 @@ xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size)
 }
 
 static ssize_t
-xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
+xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
 	enum xer_pbd_rval bret;
+	size_t lead_wsp_size;
 
 	if(arg->decoded_something) {
-		if(xer_is_whitespace(chunk_buf, chunk_size))
+		if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) {
+			/*
+			 * Example:
+			 * "<INTEGER>123<!--/--> </INTEGER>"
+			 *                      ^- chunk_buf position.
+			 */
 			return chunk_size;
+		}
 		/*
 		 * Decoding was done once already. Prohibit doing it again.
 		 */
@@ -203,6 +216,10 @@ xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_m
 		return -1;
 	}
 
+	lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size);
+	chunk_buf = (const char *)chunk_buf + lead_wsp_size;
+	chunk_size -= lead_wsp_size;
+
 	bret = arg->prim_body_decoder(arg->type_descriptor,
 		arg->struct_key, chunk_buf, chunk_size);
 	switch(bret) {
@@ -215,7 +232,7 @@ xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_m
 		arg->decoded_something = 1;
 		/* Fall through */
 	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
-		return chunk_size;
+		return lead_wsp_size + chunk_size;
 	}
 
 	return -1;
@@ -253,7 +270,7 @@ xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
 
 	rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
 		xml_tag, buf_ptr, size,
-		xer_decode__unexpected_tag, xer_decode__body);
+		xer_decode__unexpected_tag, xer_decode__primitive_body);
 	switch(rc.code) {
 	case RC_OK:
 		if(!s_arg.decoded_something) {
diff --git a/asn1/asn1c/asn_internal.h b/asn1/asn1c/asn_internal.h
index 67f055a62fbf74c397d2c108469549291ef9e6af..7e0f71be08a40835b85ad4e4ac12106f6dbacd97 100644
--- a/asn1/asn1c/asn_internal.h
+++ b/asn1/asn1c/asn_internal.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm at lionet.info>.
+ * Copyright (c) 2003, 2004, 2005, 2007 Lev Walkin <vlm at lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
@@ -20,7 +20,7 @@ extern "C" {
 #endif
 
 /* Environment version might be used to avoid running with the old library */
-#define	ASN1C_ENVIRONMENT_VERSION	920	/* Compile-time version */
+#define	ASN1C_ENVIRONMENT_VERSION	923	/* Compile-time version */
 int get_asn1c_environment_version(void);	/* Run-time version */
 
 #define	CALLOC(nmemb, size)	calloc(nmemb, size)
@@ -28,6 +28,9 @@ int get_asn1c_environment_version(void);	/* Run-time version */
 #define	REALLOC(oldptr, size)	realloc(oldptr, size)
 #define	FREEMEM(ptr)		free(ptr)
 
+#define	asn_debug_indent	0
+#define ASN_DEBUG_INDENT_ADD(i) do{}while(0)
+
 /*
  * A macro for debugging the ASN.1 internals.
  * You may enable or override it.
@@ -35,10 +38,21 @@ int get_asn1c_environment_version(void);	/* Run-time version */
 #ifndef	ASN_DEBUG	/* If debugging code is not defined elsewhere... */
 #if	EMIT_ASN_DEBUG == 1	/* And it was asked to emit this code... */
 #ifdef	__GNUC__
-#define	ASN_DEBUG(fmt, args...)	do {		\
-		fprintf(stderr, fmt, ##args);	\
-		fprintf(stderr, " (%s:%d)\n",	\
-			__FILE__, __LINE__);	\
+#ifdef	ASN_THREAD_SAFE
+/* Thread safety requires sacrifice in output indentation:
+ * Retain empty definition of ASN_DEBUG_INDENT_ADD. */
+#else	/* !ASN_THREAD_SAFE */
+#undef  ASN_DEBUG_INDENT_ADD
+#undef  asn_debug_indent
+int asn_debug_indent;
+#define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0)
+#endif	/* ASN_THREAD_SAFE */
+#define	ASN_DEBUG(fmt, args...)	do {			\
+		int adi = asn_debug_indent;		\
+		while(adi--) fprintf(stderr, " ");	\
+		fprintf(stderr, fmt, ##args);		\
+		fprintf(stderr, " (%s:%d)\n",		\
+			__FILE__, __LINE__);		\
 	} while(0)
 #else	/* !__GNUC__ */
 void ASN_DEBUG_f(const char *fmt, ...);
@@ -70,6 +84,7 @@ static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; }
 	int __nl = ((nl) != 0);						\
 	int __i;							\
 	if(__nl) _ASN_CALLBACK("\n", 1);				\
+	if(__level < 0) __level = 0;					\
 	for(__i = 0; __i < __level; __i++)				\
 		_ASN_CALLBACK("    ", 4);				\
 	er.encoded += __nl + 4 * __level;				\
diff --git a/asn1/asn1c/asn_system.h b/asn1/asn1c/asn_system.h
index d7ebdaa4e16a2636184db6ba4fe34fda5860a6bc..e420ad2da679eeea8fd0175bb865cc211a8e26cd 100644
--- a/asn1/asn1c/asn_system.h
+++ b/asn1/asn1c/asn_system.h
@@ -1,5 +1,6 @@
 /*-
- * Copyright (c) 2003, 2004 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004, 2007 Lev Walkin <vlm at lionet.info>.
+ * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 /*
@@ -16,20 +17,27 @@
 #include <stdlib.h>	/* For *alloc(3) */
 #include <string.h>	/* For memcpy(3) */
 #include <sys/types.h>	/* For size_t */
+#include <limits.h>	/* For LONG_MAX */
 #include <stdarg.h>	/* For va_start */
 #include <stddef.h>	/* for offsetof and ptrdiff_t */
 
-#ifdef	WIN32
+#ifdef	_WIN32
 
 #include <malloc.h>
-#include <stdint.h>
 #define	 snprintf	_snprintf
 #define	 vsnprintf	_vsnprintf
 
+/* To avoid linking with ws2_32.lib, here's the definition of ntohl() */
+#define sys_ntohl(l)	((((l) << 24)  & 0xff000000)	\
+			| (((l) << 8) & 0xff0000)	\
+			| (((l) >> 8)  & 0xff00)	\
+			| ((l >> 24) & 0xff))
+
 #ifdef _MSC_VER			/* MSVS.Net */
 #ifndef __cplusplus
 #define inline __inline
 #endif
+#ifndef	ASSUMESTDTYPES	/* Standard types have been defined elsewhere */
 #define	ssize_t		SSIZE_T
 typedef	char		int8_t;
 typedef	short		int16_t;
@@ -37,6 +45,7 @@ typedef	int		int32_t;
 typedef	unsigned char	uint8_t;
 typedef	unsigned short	uint16_t;
 typedef	unsigned int	uint32_t;
+#endif	/* ASSUMESTDTYPES */
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <float.h>
@@ -44,9 +53,11 @@ typedef	unsigned int	uint32_t;
 #define finite _finite
 #define copysign _copysign
 #define	ilogb	_logb
+#else	/* !_MSC_VER */
+#include <stdint.h>
 #endif	/* _MSC_VER */
 
-#else	/* !WIN32 */
+#else	/* !_WIN32 */
 
 #if defined(__vxworks)
 #include <types/vxTypes.h>
@@ -74,19 +85,33 @@ typedef	unsigned int	uint32_t;
 #endif	/* defined(sun) */
 #endif
 
+#include <netinet/in.h> /* for ntohl() */
+#define	sys_ntohl(foo)	ntohl(foo)
+
 #endif	/* defined(__vxworks) */
 
-#endif	/* WIN32 */
+#endif	/* _WIN32 */
 
 #if	__GNUC__ >= 3
 #ifndef	GCC_PRINTFLIKE
 #define	GCC_PRINTFLIKE(fmt,var)	__attribute__((format(printf,fmt,var)))
 #endif
+#ifndef	GCC_NOTUSED
+#define	GCC_NOTUSED		__attribute__((unused))
+#endif
 #else
 #ifndef	GCC_PRINTFLIKE
 #define	GCC_PRINTFLIKE(fmt,var)	/* nothing */
 #endif
+#ifndef	GCC_NOTUSED
+#define	GCC_NOTUSED
 #endif
+#endif
+
+/* Figure out if thread safety is requested */
+#if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT))
+#define	ASN_THREAD_SAFE
+#endif	/* Thread safety */
 
 #ifndef	offsetof	/* If not defined by <stddef.h> */
 #define	offsetof(s, m)	((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0))
diff --git a/asn1/asn1c/ber_decoder.c b/asn1/asn1c/ber_decoder.c
index 601f66c0b0274b74dcb56e7eca469ded9b076b2c..0f994009079996ef4aedb219bd0d003e308c0fb6 100644
--- a/asn1/asn1c/ber_decoder.c
+++ b/asn1/asn1c/ber_decoder.c
@@ -206,7 +206,7 @@ ber_check_tags(asn_codec_ctx_t *opt_codec_ctx,
 		 */
 		len_len = ber_fetch_length(tlv_constr,
 			(const char *)ptr + tag_len, size - tag_len, &tlv_len);
-		ASN_DEBUG("Fetchinig len = %ld", (long)len_len);
+		ASN_DEBUG("Fetching len = %ld", (long)len_len);
 		switch(len_len) {
 		case -1: RETURN(RC_FAIL);
 		case 0: RETURN(RC_WMORE);
diff --git a/asn1/asn1c/ber_decoder.h b/asn1/asn1c/ber_decoder.h
index 768133b67e75b4eb18e523e1943245e17ce9b3aa..9fe2e895dfb65375948b83a893629959d5c576b1 100644
--- a/asn1/asn1c/ber_decoder.h
+++ b/asn1/asn1c/ber_decoder.h
@@ -17,6 +17,7 @@ struct asn_codec_ctx_s;		/* Forward declaration */
 /*
  * The BER decoder of any type.
  * This function may be invoked directly from the application.
+ * The der_encode() function (der_encoder.h) is an opposite to ber_decode().
  */
 asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx,
 	struct asn_TYPE_descriptor_s *type_descriptor,
diff --git a/asn1/asn1c/constr_CHOICE.c b/asn1/asn1c/constr_CHOICE.c
index b8d6fa9a7f210585e851f8f1ab3cadf1d8fe4923..5a1e0d3862aa6c3eed8d17d5505764961a970274 100644
--- a/asn1/asn1c/constr_CHOICE.c
+++ b/asn1/asn1c/constr_CHOICE.c
@@ -1,10 +1,11 @@
 /*
- * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm at lionet.info>.
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm at lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
 #include <constr_CHOICE.h>
+#include <per_opentype.h>
 
 /*
  * Number of bytes left for this structure.
@@ -482,7 +483,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 	int present;
 
 	if(!sptr) {
-		_ASN_CTFAIL(app_key, td,
+		_ASN_CTFAIL(app_key, td, sptr,
 			"%s: value not given (%s:%d)",
 			td->name, __FILE__, __LINE__);
 		return -1;
@@ -501,7 +502,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 			if(!memb_ptr) {
 				if(elm->optional)
 					return 0;
-				_ASN_CTFAIL(app_key, td,
+				_ASN_CTFAIL(app_key, td, sptr,
 					"%s: mandatory CHOICE element %s absent (%s:%d)",
 					td->name, elm->name, __FILE__, __LINE__);
 				return -1;
@@ -524,7 +525,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 			return ret;
 		}
 	} else {
-		_ASN_CTFAIL(app_key, td,
+		_ASN_CTFAIL(app_key, td, sptr,
 			"%s: no CHOICE element given (%s:%d)",
 			td->name, __FILE__, __LINE__);
 		return -1;
@@ -534,7 +535,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 #undef	XER_ADVANCE
 #define	XER_ADVANCE(num_bytes)	do {			\
 		size_t num = num_bytes;			\
-		buf_ptr = ((const char *)buf_ptr) + num;\
+		buf_ptr = (const void *)(((const char *)buf_ptr) + num); \
 		size -= num;				\
 		consumed_myself += num;			\
 	} while(0)
@@ -871,8 +872,6 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 		value += specs->ext_start;
 		if(value >= td->elements_count)
 			_ASN_DECODE_FAILED;
-		ASN_DEBUG("NOT IMPLEMENTED YET");
-		_ASN_DECODE_FAILED;
 	}
 
 	/* Adjust if canonical order is different from natural order */
@@ -892,11 +891,17 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	}
 	ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name);
 
-	rv = elm->type->uper_decoder(opt_codec_ctx, elm->type,
+	if(ct && ct->range_bits >= 0) {
+		rv = elm->type->uper_decoder(opt_codec_ctx, elm->type,
 			elm->per_constraints, memb_ptr2, pd);
+	} else {
+		rv = uper_open_type_get(opt_codec_ctx, elm->type,
+			elm->per_constraints, memb_ptr2, pd);
+	}
+
 	if(rv.code != RC_OK)
-		ASN_DEBUG("Failed to decode %s in %s (CHOICE)",
-			elm->name, td->name);
+		ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d",
+			elm->name, td->name, rv.code);
 	return rv;
 }
    
@@ -908,6 +913,7 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraint_t *ct;
 	void *memb_ptr;
 	int present;
+	int present_enc;
 
 	if(!sptr) _ASN_ENCODE_FAILED;
 
@@ -929,15 +935,17 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td,
 	else
 		present--;
 
-	/* Adjust if canonical order is different from natural order */
-	if(specs->canonical_order)
-		present = specs->canonical_order[present];
-
 	ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
 
+	/* Adjust if canonical order is different from natural order */
+	if(specs->canonical_order)
+		present_enc = specs->canonical_order[present];
+	else
+		present_enc = present;
+
 	if(ct && ct->range_bits >= 0) {
-		if(present < ct->lower_bound
-		|| present > ct->upper_bound) {
+		if(present_enc < ct->lower_bound
+		|| present_enc > ct->upper_bound) {
 			if(ct->flags & APC_EXTENSIBLE) {
 				if(per_put_few_bits(po, 1, 1))
 					_ASN_ENCODE_FAILED;
@@ -951,18 +959,6 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td,
 		if(per_put_few_bits(po, 0, 1))
 			_ASN_ENCODE_FAILED;
 
-	if(ct && ct->range_bits >= 0) {
-		if(per_put_few_bits(po, present, ct->range_bits))
-			_ASN_ENCODE_FAILED;
-	} else {
-		if(specs->ext_start == -1)
-			_ASN_ENCODE_FAILED;
-		if(uper_put_nsnnwn(po, present - specs->ext_start))
-			_ASN_ENCODE_FAILED;
-		ASN_DEBUG("NOT IMPLEMENTED YET");
-		_ASN_ENCODE_FAILED;
-	}
-
 	elm = &td->elements[present];
 	if(elm->flags & ATF_POINTER) {
 		/* Member is a pointer to another structure */
@@ -972,8 +968,24 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td,
 		memb_ptr = (char *)sptr + elm->memb_offset;
 	}
 
-	return elm->type->uper_encoder(elm->type, elm->per_constraints,
+	if(ct && ct->range_bits >= 0) {
+		if(per_put_few_bits(po, present_enc, ct->range_bits))
+			_ASN_ENCODE_FAILED;
+
+		return elm->type->uper_encoder(elm->type, elm->per_constraints,
 			memb_ptr, po);
+	} else {
+		asn_enc_rval_t rval;
+		if(specs->ext_start == -1)
+			_ASN_ENCODE_FAILED;
+		if(uper_put_nsnnwn(po, present_enc - specs->ext_start))
+			_ASN_ENCODE_FAILED;
+		if(uper_open_type_put(elm->type, elm->per_constraints,
+			memb_ptr, po))
+			_ASN_ENCODE_FAILED;
+		rval.encoded = 0;
+		_ASN_ENCODED_OK(rval);
+	}
 }
    
 
diff --git a/asn1/asn1c/constr_SEQUENCE.c b/asn1/asn1c/constr_SEQUENCE.c
index b769434345763a454777a89458155f5debea73c8..c405a18f0ceedc9cebae7fce392d37299a992daf 100644
--- a/asn1/asn1c/constr_SEQUENCE.c
+++ b/asn1/asn1c/constr_SEQUENCE.c
@@ -1,10 +1,11 @@
 /*-
- * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm at lionet.info>.
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm at lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
 #include <constr_SEQUENCE.h>
+#include <per_opentype.h>
 
 /*
  * Number of bytes left for this structure.
@@ -33,7 +34,7 @@
 #undef	ADVANCE
 #define	ADVANCE(num_bytes)	do {		\
 		size_t num = num_bytes;		\
-		ptr = ((const char *)ptr) + num;\
+		ptr = ((const char *)ptr) + num; \
 		size -= num;			\
 		if(ctx->left >= 0)		\
 			ctx->left -= num;	\
@@ -346,7 +347,8 @@ SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 			 * or an extension (...),
 			 * or an end of the indefinite-length structure.
 			 */
-			if(!IN_EXTENSION_GROUP(specs, edx)) {
+			if(!IN_EXTENSION_GROUP(specs,
+				edx + elements[edx].optional)) {
 				ASN_DEBUG("Unexpected tag %s (at %d)",
 					ber_tlv_tag_string(tlv_tag), edx);
 				ASN_DEBUG("Expected tag %s (%s)%s",
@@ -358,7 +360,10 @@ SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 			} else {
 				/* Skip this tag */
 				ssize_t skip;
+				edx += elements[edx].optional;
 
+				ASN_DEBUG("Skipping unexpected %s (at %d)",
+					ber_tlv_tag_string(tlv_tag), edx);
 				skip = ber_skip_length(opt_codec_ctx,
 					BER_TLV_CONSTRUCTED(ptr),
 					(const char *)ptr + tag_len,
@@ -662,8 +667,7 @@ SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 
 			if(elm->flags & ATF_POINTER) {
 				/* Member is a pointer to another structure */
-				memb_ptr2 = (void **)((char *)st
-					+ elm->memb_offset);
+				memb_ptr2 = (void **)((char *)st + elm->memb_offset);
 			} else {
 				memb_ptr = (char *)st + elm->memb_offset;
 				memb_ptr2 = &memb_ptr;
@@ -976,7 +980,7 @@ SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 	int edx;
 
 	if(!sptr) {
-		_ASN_CTFAIL(app_key, td,
+		_ASN_CTFAIL(app_key, td, sptr,
 			"%s: value not given (%s:%d)",
 			td->name, __FILE__, __LINE__);
 		return -1;
@@ -994,7 +998,7 @@ SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 			if(!memb_ptr) {
 				if(elm->optional)
 					continue;
-				_ASN_CTFAIL(app_key, td,
+				_ASN_CTFAIL(app_key, td, sptr,
 				"%s: mandatory element %s absent (%s:%d)",
 				td->name, elm->name, __FILE__, __LINE__);
 				return -1;
@@ -1027,7 +1031,7 @@ SEQUENCE_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_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics;
 	void *st = *sptr;	/* Target structure. */
-	int extpresent = 0;	/* Extension additions are present */
+	int extpresent;		/* Extension additions are present */
 	uint8_t *opres;		/* Presence of optional root members */
 	asn_per_data_t opmd;
 	asn_dec_rval_t rv;
@@ -1049,9 +1053,12 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	if(specs->ext_before >= 0) {
 		extpresent = per_get_few_bits(pd, 1);
 		if(extpresent < 0) _ASN_DECODE_STARVED;
+	} else {
+		extpresent = 0;
 	}
 
 	/* Prepare a place and read-in the presence bitmap */
+	memset(&opmd, 0, sizeof(opmd));
 	if(specs->roms_count) {
 		opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1);
 		if(!opres) _ASN_DECODE_FAILED;
@@ -1061,24 +1068,24 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 			_ASN_DECODE_STARVED;
 		}
 		opmd.buffer = opres;
-		opmd.nboff = 0;
 		opmd.nbits = specs->roms_count;
 		ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)",
 			td->name, specs->roms_count, *opres);
 	} else {
 		opres = 0;
-		memset(&opmd, 0, sizeof opmd);
 	}
 
 	/*
 	 * Get the sequence ROOT elements.
 	 */
-	for(edx = 0; edx < ((specs->ext_before < 0)
-			? td->elements_count : specs->ext_before + 1); edx++) {
+	for(edx = 0; edx < td->elements_count; edx++) {
 		asn_TYPE_member_t *elm = &td->elements[edx];
 		void *memb_ptr;		/* Pointer to the member */
 		void **memb_ptr2;	/* Pointer to that pointer */
 
+		if(IN_EXTENSION_GROUP(specs, edx))
+			continue;
+
 		/* Fetch the pointer to this member */
 		if(elm->flags & ATF_POINTER) {
 			memb_ptr2 = (void **)((char *)st + elm->memb_offset);
@@ -1101,6 +1108,7 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 						FREEMEM(opres);
 						_ASN_DECODE_FAILED;
 					}
+					ASN_DEBUG("Filled-in default");
 				}
 				/* The member is just not present */
 				continue;
@@ -1120,50 +1128,176 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 		}
 	}
 
+	/* Optionality map is not needed anymore */
+	FREEMEM(opres);
+
 	/*
 	 * Deal with extensions.
 	 */
 	if(extpresent) {
-		ASN_DEBUG("Extensibility for %s: NOT IMPLEMENTED", td->name);
-		_ASN_DECODE_FAILED;
-	} else {
-		for(edx = specs->roms_count; edx < specs->roms_count
-				+ specs->aoms_count; edx++) {
-			asn_TYPE_member_t *elm = &td->elements[edx];
-			void *memb_ptr;		/* Pointer to the member */
-			void **memb_ptr2;	/* Pointer to that pointer */
-
-			if(!elm->default_value) continue;
-
-			/* Fetch the pointer to this member */
-			if(elm->flags & ATF_POINTER) {
-				memb_ptr2 = (void **)((char *)st
-						+ elm->memb_offset);
-			} else {
-				memb_ptr = (char *)st + elm->memb_offset;
-				memb_ptr2 = &memb_ptr;
-			}
+		ssize_t bmlength;
+		uint8_t *epres;		/* Presence of extension members */
+		asn_per_data_t epmd;
+
+		bmlength = uper_get_nslength(pd);
+		if(bmlength < 0) _ASN_DECODE_STARVED;
+
+		ASN_DEBUG("Extensions %ld present in %s", (long)bmlength, td->name);
+
+		epres = (uint8_t *)MALLOC((bmlength + 15) >> 3);
+		if(!epres) _ASN_DECODE_STARVED;
+
+		/* Get the extensions map */
+		if(per_get_many_bits(pd, epres, 0, bmlength))
+			_ASN_DECODE_STARVED;
+
+		memset(&epmd, 0, sizeof(epmd));
+		epmd.buffer = epres;
+		epmd.nbits = bmlength;
+		ASN_DEBUG("Read in extensions bitmap for %s of %ld bits (%x..)",
+			td->name, (long)bmlength, *epres);
+
+	    /* Go over extensions and read them in */
+	    for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;		/* Pointer to the member */
+		void **memb_ptr2;	/* Pointer to that pointer */
+		int present;
+
+		if(!IN_EXTENSION_GROUP(specs, edx)) {
+			ASN_DEBUG("%d is not extension", edx);
+			continue;
+		}
 
-			/* Set default value */
-			if(elm->default_value(1, memb_ptr2)) {
-				FREEMEM(opres);
-				_ASN_DECODE_FAILED;
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+		} else {
+			memb_ptr = (void *)((char *)st + elm->memb_offset);
+			memb_ptr2 = &memb_ptr;
+		}
+
+		present = per_get_few_bits(&epmd, 1);
+		if(present <= 0) {
+			if(present < 0) break;	/* No more extensions */
+			continue;
+		}
+
+		ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, *memb_ptr2);
+		rv = uper_open_type_get(opt_codec_ctx, elm->type,
+			elm->per_constraints, memb_ptr2, pd);
+		if(rv.code != RC_OK) {
+			FREEMEM(epres);
+			return rv;
+		}
+	    }
+
+		/* Skip over overflow extensions which aren't present
+		 * in this system's version of the protocol */
+		for(;;) {
+			ASN_DEBUG("Getting overflow extensions");
+			switch(per_get_few_bits(&epmd, 1)) {
+			case -1: break;
+			case 0: continue;
+			default:
+				if(uper_open_type_skip(opt_codec_ctx, pd)) {
+					FREEMEM(epres);
+					_ASN_DECODE_STARVED;
+				}
 			}
+			break;
+		}
+
+		FREEMEM(epres);
+	}
+
+	/* Fill DEFAULT members in extensions */
+	for(edx = specs->roms_count; edx < specs->roms_count
+			+ specs->aoms_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void **memb_ptr2;	/* Pointer to member pointer */
+
+		if(!elm->default_value) continue;
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)st
+					+ elm->memb_offset);
+			if(*memb_ptr2) continue;
+		} else {
+			continue;	/* Extensions are all optionals */
+		}
+
+		/* Set default value */
+		if(elm->default_value(1, memb_ptr2)) {
+			_ASN_DECODE_FAILED;
 		}
 	}
 
 	rv.consumed = 0;
 	rv.code = RC_OK;
-	FREEMEM(opres);
 	return rv;
 }
 
+static int
+SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr,
+		asn_per_outp_t *po1, asn_per_outp_t *po2) {
+	asn_SEQUENCE_specifics_t *specs
+		= (asn_SEQUENCE_specifics_t *)td->specifics;
+	int exts_present = 0;
+	int exts_count = 0;
+	int edx;
+
+	if(specs->ext_before < 0)
+		return 0;
+
+	/* Find out which extensions are present */
+	for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;		/* Pointer to the member */
+		void **memb_ptr2;	/* Pointer to that pointer */
+		int present;
+
+		if(!IN_EXTENSION_GROUP(specs, edx)) {
+			ASN_DEBUG("%s (@%d) is not extension", elm->type->name, edx);
+			continue;
+		}
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+			present = (*memb_ptr2 != 0);
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+			memb_ptr2 = &memb_ptr;
+			present = 1;
+		}
+
+		ASN_DEBUG("checking %s (@%d) present => %d",
+			elm->type->name, edx, present);
+		exts_count++;
+		exts_present += present;
+
+		/* Encode as presence marker */
+		if(po1 && per_put_few_bits(po1, present, 1))
+			return -1;
+		/* Encode as open type field */
+		if(po2 && present && uper_open_type_put(elm->type,
+				elm->per_constraints, *memb_ptr2, po2))
+			return -1;
+
+	}
+
+	return exts_present ? exts_count : 0;
+}
+
 asn_enc_rval_t
 SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
 	asn_SEQUENCE_specifics_t *specs
 		= (asn_SEQUENCE_specifics_t *)td->specifics;
 	asn_enc_rval_t er;
+	int n_extensions;
 	int edx;
 	int i;
 
@@ -1175,8 +1309,18 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
 	er.encoded = 0;
 
 	ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name);
-	if(specs->ext_before >= 0)
-		_ASN_ENCODE_FAILED;	/* We don't encode extensions yet */
+
+
+	/*
+	 * X.691#18.1 Whether structure is extensible
+	 * and whether to encode extensions
+	 */
+	if(specs->ext_before >= 0) {
+		n_extensions = SEQUENCE_handle_extensions(td, sptr, 0, 0);
+		per_put_few_bits(po, n_extensions ? 1 : 0, 1);
+	} else {
+		n_extensions = 0;	/* There are no extensions to encode */
+	}
 
 	/* Encode a presence bitmap */
 	for(i = 0; i < specs->roms_count; i++) {
@@ -1212,14 +1356,21 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
 	}
 
 	/*
-	 * Get the sequence ROOT elements.
+	 * Encode the sequence ROOT elements.
 	 */
-	for(edx = 0; edx < ((specs->ext_before < 0)
-			? td->elements_count : specs->ext_before + 1); edx++) {
+	ASN_DEBUG("ext_after = %d, ec = %d, eb = %d", specs->ext_after, td->elements_count, specs->ext_before);
+	for(edx = 0; edx < ((specs->ext_after < 0)
+		? td->elements_count : specs->ext_before - 1); edx++) {
+
 		asn_TYPE_member_t *elm = &td->elements[edx];
 		void *memb_ptr;		/* Pointer to the member */
 		void **memb_ptr2;	/* Pointer to that pointer */
 
+		if(IN_EXTENSION_GROUP(specs, edx))
+			continue;
+
+		ASN_DEBUG("About to encode %s", elm->type->name);
+
 		/* Fetch the pointer to this member */
 		if(elm->flags & ATF_POINTER) {
 			memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
@@ -1240,12 +1391,32 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
 		if(elm->default_value && elm->default_value(0, memb_ptr2) == 1)
 			continue;
 
+		ASN_DEBUG("Encoding %s->%s", td->name, elm->name);
 		er = elm->type->uper_encoder(elm->type, elm->per_constraints,
 			*memb_ptr2, po);
 		if(er.encoded == -1)
 			return er;
 	}
 
+	/* No extensions to encode */
+	if(!n_extensions) _ASN_ENCODED_OK(er);
+
+	ASN_DEBUG("Length of %d bit-map", n_extensions);
+	/* #18.8. Write down the presence bit-map length. */
+	if(uper_put_nslength(po, n_extensions))
+		_ASN_ENCODE_FAILED;
+
+	ASN_DEBUG("Bit-map of %d elements", n_extensions);
+	/* #18.7. Encoding the extensions presence bit-map. */
+	/* TODO: act upon NOTE in #18.7 for canonical PER */
+	if(SEQUENCE_handle_extensions(td, sptr, po, 0) != n_extensions)
+		_ASN_ENCODE_FAILED;
+
+	ASN_DEBUG("Writing %d extensions", n_extensions);
+	/* #18.9. Encode extensions as open type fields. */
+	if(SEQUENCE_handle_extensions(td, sptr, 0, po) != n_extensions)
+		_ASN_ENCODE_FAILED;
+
 	_ASN_ENCODED_OK(er);
 }
 
diff --git a/asn1/asn1c/constr_SET_OF.c b/asn1/asn1c/constr_SET_OF.c
index 09f27db53dada6869accd8dbb3aba0f56b49e00b..b68d7ca1b2f852cbe7188e5166555f9ec2b35f63 100644
--- a/asn1/asn1c/constr_SET_OF.c
+++ b/asn1/asn1c/constr_SET_OF.c
@@ -227,6 +227,8 @@ SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 			}
 			/* Fall through */
 		case RC_FAIL: /* Fatal error */
+			ASN_STRUCT_FREE(*elm->type, ctx->ptr);
+			ctx->ptr = 0;
 			RETURN(RC_FAIL);
 		} /* switch(rval) */
 		
@@ -787,8 +789,10 @@ SET_OF_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 void
 SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
 	if(td && ptr) {
+		asn_SET_OF_specifics_t *specs;
 		asn_TYPE_member_t *elm = td->elements;
 		asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr);
+		asn_struct_ctx_t *ctx;	/* Decoder context */
 		int i;
 
 		/*
@@ -804,6 +808,13 @@ SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
 
 		asn_set_empty(list);	/* Remove (list->array) */
 
+		specs = (asn_SET_OF_specifics_t *)td->specifics;
+		ctx = (asn_struct_ctx_t *)((char *)ptr + specs->ctx_offset);
+		if(ctx->ptr) {
+			ASN_STRUCT_FREE(*elm->type, ctx->ptr);
+			ctx->ptr = 0;
+		}
+
 		if(!contents_only) {
 			FREEMEM(ptr);
 		}
@@ -819,7 +830,7 @@ SET_OF_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 	int i;
 
 	if(!sptr) {
-		_ASN_CTFAIL(app_key, td,
+		_ASN_CTFAIL(app_key, td, sptr,
 			"%s: value not given (%s:%d)",
 			td->name, __FILE__, __LINE__);
 		return -1;
@@ -904,7 +915,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 			nelems = uper_get_length(pd,
 				ct ? ct->effective_bits : -1, &repeat);
 			ASN_DEBUG("Got to decode %d elements (eff %d)",
-				(int)nelems, (int)ct ? ct->effective_bits : -1);
+				(int)nelems, (int)(ct ? ct->effective_bits : -1));
 			if(nelems < 0) _ASN_DECODE_STARVED;
 		}
 
@@ -921,7 +932,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 				ASN_DEBUG("Failed to add element into %s",
 					td->name);
 				/* Fall through */
-				rv.code == RC_FAIL;
+				rv.code = RC_FAIL;
 			} else {
 				ASN_DEBUG("Failed decoding %s of %s (SET OF)",
 					elm->type->name, td->name);
diff --git a/asn1/asn1c/der_encoder.h b/asn1/asn1c/der_encoder.h
index 4e2fb06c28194510c6434f4829e56b2436d8f092..61431c6dbdc87e98de8b7804d438476bca86caa5 100644
--- a/asn1/asn1c/der_encoder.h
+++ b/asn1/asn1c/der_encoder.h
@@ -15,6 +15,7 @@ struct asn_TYPE_descriptor_s;	/* Forward declaration */
 
 /*
  * The DER encoder of any type. May be invoked by the application.
+ * The ber_decode() function (ber_decoder.h) is an opposite of der_encode().
  */
 asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor,
 		void *struct_ptr,	/* Structure to be encoded */
diff --git a/asn1/asn1c/per_decoder.c b/asn1/asn1c/per_decoder.c
index 16dee369624bbf28bb8957e222abe77059980d9f..220d7f9f7f2307b5c5256afe3c92df1f1413c486 100644
--- a/asn1/asn1c/per_decoder.c
+++ b/asn1/asn1c/per_decoder.c
@@ -2,6 +2,40 @@
 #include <asn_internal.h>
 #include <per_decoder.h>
 
+/*
+ * Decode a "Production of a complete encoding", X.691#10.1.
+ * The complete encoding contains at least one byte, and is an integral
+ * multiple of 8 bytes.
+ */
+asn_dec_rval_t
+uper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) {
+	asn_dec_rval_t rval;
+
+	rval = uper_decode(opt_codec_ctx, td, sptr, buffer, size, 0, 0);
+	if(rval.consumed) {
+		/*
+		 * We've always given 8-aligned data,
+		 * so convert bits to integral bytes.
+		 */
+		rval.consumed += 7;
+		rval.consumed >>= 3;
+	} else if(rval.code == RC_OK) {
+		if(size) {
+			if(((const uint8_t *)buffer)[0] == 0) {
+				rval.consumed = 1;	/* 1 byte */
+			} else {
+				ASN_DEBUG("Expecting single zeroed byte");
+				rval.code = RC_FAIL;
+			}
+		} else {
+			/* Must contain at least 8 bits. */
+			rval.code = RC_WMORE;
+		}
+	}
+
+	return rval;
+}
+
 asn_dec_rval_t
 uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) {
 	asn_codec_ctx_t s_codec_ctx;
@@ -30,6 +64,7 @@ uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sp
 	}
 
 	/* Fill in the position indicator */
+	memset(&pd, 0, sizeof(pd));
 	pd.buffer = (const uint8_t *)buffer;
 	pd.nboff = skip_bits;
 	pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from <limits.h> */
@@ -46,6 +81,9 @@ uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sp
 		/* Return the number of consumed bits */
 		rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3)
 					+ pd.nboff - skip_bits;
+		ASN_DEBUG("PER decoding consumed %ld, counted %ld",
+			(long)rval.consumed, (long)pd.moved);
+		assert(rval.consumed == pd.moved);
 	} else {
 		/* PER codec is not a restartable */
 		rval.consumed = 0;
diff --git a/asn1/asn1c/per_decoder.h b/asn1/asn1c/per_decoder.h
index 26aaf59400445aff62fb007370fc35c0cfa9b1b2..8397a545fb9b2e950942aae892a32385730989e7 100644
--- a/asn1/asn1c/per_decoder.h
+++ b/asn1/asn1c/per_decoder.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2005 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Copyright (c) 2005, 2007 Lev Walkin <vlm at lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #ifndef	_PER_DECODER_H_
@@ -15,7 +15,19 @@ extern "C" {
 struct asn_TYPE_descriptor_s;	/* Forward declaration */
 
 /*
+ * Unaligned PER decoder of a "complete encoding" as per X.691#10.1.
+ * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3.
+ */
+asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx,
+	struct asn_TYPE_descriptor_s *type_descriptor,	/* Type to decode */
+	void **struct_ptr,	/* Pointer to a target structure's pointer */
+	const void *buffer,	/* Data to be decoded */
+	size_t size		/* Size of data buffer */
+	);
+
+/*
  * Unaligned PER decoder of any ASN.1 type. May be invoked by the application.
+ * WARNING: This call returns the number of BITS read from the stream. Beware.
  */
 asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx,
 	struct asn_TYPE_descriptor_s *type_descriptor,	/* Type to decode */
diff --git a/asn1/asn1c/per_encoder.c b/asn1/asn1c/per_encoder.c
index 614dd23331d482a05b973f790449359e7f503768..e76ef74a95a3d055aa65e3253d0121c8fb0410e6 100644
--- a/asn1/asn1c/per_encoder.c
+++ b/asn1/asn1c/per_encoder.c
@@ -2,41 +2,11 @@
 #include <asn_internal.h>
 #include <per_encoder.h>
 
-/* Flush partially filled buffer */
-static int _uper_encode_flush_outp(asn_per_outp_t *po);
+static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key);
 
 asn_enc_rval_t
 uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
-	asn_per_outp_t po;
-	asn_enc_rval_t er;
-
-	/*
-	 * Invoke type-specific encoder.
-	 */
-	if(!td || !td->uper_encoder)
-		_ASN_ENCODE_FAILED;	/* PER is not compiled in */
-
-	po.buffer = po.tmpspace;
-	po.nboff = 0;
-	po.nbits = 8 * sizeof(po.tmpspace);
-	po.outper = cb;
-	po.op_key = app_key;
-	po.flushed_bytes = 0;
-
-	er = td->uper_encoder(td, 0, sptr, &po);
-	if(er.encoded != -1) {
-		size_t bits_to_flush;
-
-		bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
-
-		/* Set number of bits encoded to a firm value */
-		er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
-
-		if(_uper_encode_flush_outp(&po))
-			_ASN_ENCODE_FAILED;
-	}
-
-	return er;
+	return uper_encode_internal(td, 0, sptr, cb, app_key);
 }
 
 /*
@@ -63,20 +33,71 @@ asn_enc_rval_t
 uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) {
 	enc_to_buf_arg key;
 
-	/*
-	 * Invoke type-specific encoder.
-	 */
-	if(!td || !td->uper_encoder)
-		_ASN_ENCODE_FAILED;	/* PER is not compiled in */
-
 	key.buffer = buffer;
 	key.left = buffer_size;
 
-	ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name);
+	if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name);
 
-	return uper_encode(td, sptr, encode_to_buffer_cb, &key);
+	return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key);
 }
 
+typedef struct enc_dyn_arg {
+	void *buffer;
+	size_t length;
+	size_t allocated;
+} enc_dyn_arg;
+static int
+encode_dyn_cb(const void *buffer, size_t size, void *key) {
+	enc_dyn_arg *arg = key;
+	if(arg->length + size >= arg->allocated) {
+		void *p;
+		arg->allocated = arg->allocated ? (arg->allocated << 2) : size;
+		p = REALLOC(arg->buffer, arg->allocated);
+		if(!p) {
+			FREEMEM(arg->buffer);
+			memset(arg, 0, sizeof(*arg));
+			return -1;
+		}
+		arg->buffer = p;
+	}
+	memcpy(((char *)arg->buffer) + arg->length, buffer, size);
+	arg->length += size;
+	return 0;
+}
+ssize_t
+uper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) {
+	asn_enc_rval_t er;
+	enc_dyn_arg key;
+
+	memset(&key, 0, sizeof(key));
+
+	er = uper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key);
+	switch(er.encoded) {
+	case -1:
+		FREEMEM(key.buffer);
+		return -1;
+	case 0:
+		FREEMEM(key.buffer);
+		key.buffer = MALLOC(1);
+		if(key.buffer) {
+			*(char *)key.buffer = '\0';
+			*buffer_r = key.buffer;
+			return 1;
+		} else {
+			return -1;
+		}
+	default:
+		*buffer_r = key.buffer;
+		ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
+		return ((er.encoded + 7) >> 3);
+	}
+}
+
+/*
+ * Internally useful functions.
+ */
+
+/* Flush partially filled buffer */
 static int
 _uper_encode_flush_outp(asn_per_outp_t *po) {
 	uint8_t *buf;
@@ -93,3 +114,38 @@ _uper_encode_flush_outp(asn_per_outp_t *po) {
 
 	return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key);
 }
+
+static asn_enc_rval_t
+uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_per_outp_t po;
+	asn_enc_rval_t er;
+
+	/*
+	 * Invoke type-specific encoder.
+	 */
+	if(!td || !td->uper_encoder)
+		_ASN_ENCODE_FAILED;	/* PER is not compiled in */
+
+	po.buffer = po.tmpspace;
+	po.nboff = 0;
+	po.nbits = 8 * sizeof(po.tmpspace);
+	po.outper = cb;
+	po.op_key = app_key;
+	po.flushed_bytes = 0;
+
+	er = td->uper_encoder(td, constraints, sptr, &po);
+	if(er.encoded != -1) {
+		size_t bits_to_flush;
+
+		bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
+
+		/* Set number of bits encoded to a firm value */
+		er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
+
+		if(_uper_encode_flush_outp(&po))
+			_ASN_ENCODE_FAILED;
+	}
+
+	return er;
+}
+
diff --git a/asn1/asn1c/per_encoder.h b/asn1/asn1c/per_encoder.h
index 9ac130b7373cc354effd24058027ea85ca3a9e59..95a6506e47b54695ad1eab616dbe02cded6f6338 100644
--- a/asn1/asn1c/per_encoder.h
+++ b/asn1/asn1c/per_encoder.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2006 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Copyright (c) 2006, 2007 Lev Walkin <vlm at lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #ifndef	_PER_ENCODER_H_
@@ -16,6 +16,9 @@ struct asn_TYPE_descriptor_s;	/* Forward declaration */
 
 /*
  * Unaligned PER encoder of any ASN.1 type. May be invoked by the application.
+ * WARNING: This function returns the number of encoded bits in the .encoded
+ * field of the return value. Use the following formula to convert to bytes:
+ * 	bytes = ((.encoded + 7) / 8)
  */
 asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor,
 	void *struct_ptr,	/* Structure to be encoded */
@@ -23,7 +26,11 @@ asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor,
 	void *app_key		/* Arbitrary callback argument */
 );
 
-/* A variant of uper_encode() which encodes data into the existing buffer */
+/*
+ * A variant of uper_encode() which encodes data into the existing buffer
+ * WARNING: This function returns the number of encoded bits in the .encoded
+ * field of the return value.
+ */
 asn_enc_rval_t uper_encode_to_buffer(
 	struct asn_TYPE_descriptor_s *type_descriptor,
 	void *struct_ptr,	/* Structure to be encoded */
@@ -31,6 +38,19 @@ asn_enc_rval_t uper_encode_to_buffer(
 	size_t buffer_size	/* Initial buffer size (max) */
 );
 
+/*
+ * A variant of uper_encode_to_buffer() which allocates buffer itself.
+ * Returns the number of bytes in the buffer or -1 in case of failure.
+ * WARNING: This function produces a "Production of the complete encoding",
+ * with length of at least one octet. Contrast this to precise bit-packing
+ * encoding of uper_encode() and uper_encode_to_buffer().
+ */
+ssize_t uper_encode_to_new_buffer(
+	struct asn_TYPE_descriptor_s *type_descriptor,
+	asn_per_constraints_t *constraints,
+	void *struct_ptr,	/* Structure to be encoded */
+	void **buffer_r		/* Buffer allocated and returned */
+);
 
 /*
  * Type of the generic PER encoder function.
diff --git a/asn1/asn1c/per_opentype.c b/asn1/asn1c/per_opentype.c
new file mode 100644
index 0000000000000000000000000000000000000000..ec404cf9b07b7005ddc93c66df1bd4775ed4811d
--- /dev/null
+++ b/asn1/asn1c/per_opentype.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2007 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <per_support.h>
+#include <constr_TYPE.h>
+#include <per_opentype.h>
+
+typedef struct uper_ugot_key {
+	asn_per_data_t oldpd;	/* Old per data source */
+	size_t unclaimed;
+	size_t ot_moved;	/* Number of bits moved by OT processing */
+	int repeat;
+} uper_ugot_key;
+
+static int uper_ugot_refill(asn_per_data_t *pd);
+static int per_skip_bits(asn_per_data_t *pd, int skip_nbits);
+static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd);
+
+/*
+ * Encode an "open type field".
+ * #10.1, #10.2
+ */
+int
+uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	void *buf;
+	void *bptr;
+	ssize_t size;
+	size_t toGo;
+
+	ASN_DEBUG("Open type put %s ...", td->name);
+
+	size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
+	if(size <= 0) return -1;
+
+	for(bptr = buf, toGo = size; toGo;) {
+		ssize_t maySave = uper_put_length(po, toGo);
+		ASN_DEBUG("Prepending length %d to %s and allowing to save %d",
+			(int)size, td->name, (int)maySave);
+		if(maySave < 0) break;
+		if(per_put_many_bits(po, bptr, maySave * 8)) break;
+		bptr = (char *)bptr + maySave;
+		toGo -= maySave;
+	}
+
+	FREEMEM(buf);
+	if(toGo) return -1;
+
+	ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",
+		td->name, (long)size);
+
+	return 0;
+}
+
+static asn_dec_rval_t
+uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_dec_rval_t rv;
+	ssize_t chunk_bytes;
+	int repeat;
+	uint8_t *buf = 0;
+	size_t bufLen = 0;
+	size_t bufSize = 0;
+	asn_per_data_t spd;
+	size_t padding;
+
+	_ASN_STACK_OVERFLOW_CHECK(ctx);
+
+	ASN_DEBUG("Getting open type %s...", td->name);
+
+	do {
+		chunk_bytes = uper_get_length(pd, -1, &repeat);
+		if(chunk_bytes < 0) {
+			FREEMEM(buf);
+			_ASN_DECODE_STARVED;
+		}
+		if(bufLen + chunk_bytes > bufSize) {
+			void *ptr;
+			bufSize = chunk_bytes + (bufSize << 2);
+			ptr = REALLOC(buf, bufSize);
+			if(!ptr) {
+				FREEMEM(buf);
+				_ASN_DECODE_FAILED;
+			}
+			buf = ptr;
+		}
+		if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) {
+			FREEMEM(buf);
+			_ASN_DECODE_STARVED;
+		}
+		bufLen += chunk_bytes;
+	} while(repeat);
+
+	ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name,
+		(long)bufLen);
+
+	memset(&spd, 0, sizeof(spd));
+	spd.buffer = buf;
+	spd.nbits = bufLen << 3;
+
+	ASN_DEBUG_INDENT_ADD(+4);
+	rv = td->uper_decoder(ctx, td, constraints, sptr, &spd);
+	ASN_DEBUG_INDENT_ADD(-4);
+
+	if(rv.code == RC_OK) {
+		/* Check padding validity */
+		padding = spd.nbits - spd.nboff;
+                if ((padding < 8 ||
+		/* X.691#10.1.3 */
+		(spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) &&
+                    per_get_few_bits(&spd, padding) == 0) {
+			/* Everything is cool */
+			FREEMEM(buf);
+			return rv;
+		}
+		FREEMEM(buf);
+		if(padding >= 8) {
+			ASN_DEBUG("Too large padding %d in open type", (int)padding);
+			_ASN_DECODE_FAILED;
+		} else {
+			ASN_DEBUG("Non-zero padding");
+			_ASN_DECODE_FAILED;
+		}
+	} else {
+		FREEMEM(buf);
+		/* rv.code could be RC_WMORE, nonsense in this context */
+		rv.code = RC_FAIL; /* Noone would give us more */
+	}
+
+	return rv;
+}
+
+static asn_dec_rval_t GCC_NOTUSED
+uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	uper_ugot_key arg;
+	asn_dec_rval_t rv;
+	ssize_t padding;
+
+	_ASN_STACK_OVERFLOW_CHECK(ctx);
+
+	ASN_DEBUG("Getting open type %s from %s", td->name,
+		per_data_string(pd));
+	arg.oldpd = *pd;
+	arg.unclaimed = 0;
+	arg.ot_moved = 0;
+	arg.repeat = 1;
+	pd->refill = uper_ugot_refill;
+	pd->refill_key = &arg;
+	pd->nbits = pd->nboff;	/* 0 good bits at this point, will refill */
+	pd->moved = 0;	/* This now counts the open type size in bits */
+
+	ASN_DEBUG_INDENT_ADD(+4);
+	rv = td->uper_decoder(ctx, td, constraints, sptr, pd);
+	ASN_DEBUG_INDENT_ADD(-4);
+
+#define	UPDRESTOREPD	do {						\
+	/* buffer and nboff are valid, preserve them. */		\
+	pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved);	\
+	pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved);	\
+	pd->refill = arg.oldpd.refill;					\
+	pd->refill_key = arg.oldpd.refill_key;				\
+  } while(0)
+
+	if(rv.code != RC_OK) {
+		UPDRESTOREPD;
+		return rv;
+	}
+
+	ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name,
+		per_data_string(pd),
+		per_data_string(&arg.oldpd),
+		(int)arg.unclaimed, (int)arg.repeat);
+
+	padding = pd->moved % 8;
+	if(padding) {
+		int32_t pvalue;
+		if(padding > 7) {
+			ASN_DEBUG("Too large padding %d in open type",
+				(int)padding);
+			rv.code = RC_FAIL;
+			UPDRESTOREPD;
+			return rv;
+		}
+		padding = 8 - padding;
+		ASN_DEBUG("Getting padding of %d bits", (int)padding);
+		pvalue = per_get_few_bits(pd, padding);
+		switch(pvalue) {
+		case -1:
+			ASN_DEBUG("Padding skip failed");
+			UPDRESTOREPD;
+			_ASN_DECODE_STARVED;
+		case 0: break;
+		default:
+			ASN_DEBUG("Non-blank padding (%d bits 0x%02x)",
+				(int)padding, (int)pvalue);
+			UPDRESTOREPD;
+			_ASN_DECODE_FAILED;
+		}
+	}
+	if(pd->nboff != pd->nbits) {
+		ASN_DEBUG("Open type %s overhead pd%s old%s", td->name,
+			per_data_string(pd), per_data_string(&arg.oldpd));
+		if(1) {
+			UPDRESTOREPD;
+			_ASN_DECODE_FAILED;
+		} else {
+			arg.unclaimed += pd->nbits - pd->nboff;
+		}
+	}
+
+	/* Adjust pd back so it points to original data */
+	UPDRESTOREPD;
+
+	/* Skip data not consumed by the decoder */
+	if(arg.unclaimed) {
+		ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed);
+		switch(per_skip_bits(pd, arg.unclaimed)) {
+		case -1:
+			ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed);
+			_ASN_DECODE_STARVED;
+		case 0:
+			ASN_DEBUG("Got claim of %d", (int)arg.unclaimed);
+			break;
+		default:
+			/* Padding must be blank */
+			ASN_DEBUG("Non-blank unconsumed padding");
+			_ASN_DECODE_FAILED;
+		}
+		arg.unclaimed = 0;
+	}
+
+	if(arg.repeat) {
+		ASN_DEBUG("Not consumed the whole thing");
+		rv.code = RC_FAIL;
+		return rv;
+	}
+
+	return rv;
+}
+
+
+asn_dec_rval_t
+uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+
+	return uper_open_type_get_simple(ctx, td, constraints, sptr, pd);
+}
+
+int
+uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) {
+	asn_TYPE_descriptor_t s_td;
+	asn_dec_rval_t rv;
+
+	s_td.name = "<unknown extension>";
+	s_td.uper_decoder = uper_sot_suck;
+
+	rv = uper_open_type_get(ctx, &s_td, 0, 0, pd);
+	if(rv.code != RC_OK)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * Internal functions.
+ */
+
+static asn_dec_rval_t
+uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_dec_rval_t rv;
+
+	(void)ctx;
+	(void)td;
+	(void)constraints;
+	(void)sptr;
+
+	while(per_get_few_bits(pd, 24) >= 0);
+
+	rv.code = RC_OK;
+	rv.consumed = pd->moved;
+
+	return rv;
+}
+
+static int
+uper_ugot_refill(asn_per_data_t *pd) {
+	uper_ugot_key *arg = pd->refill_key;
+	ssize_t next_chunk_bytes, next_chunk_bits;
+	ssize_t avail;
+
+	asn_per_data_t *oldpd = &arg->oldpd;
+
+	ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld",
+		(long)pd->moved, (long)oldpd->moved);
+
+	/* Advance our position to where pd is */
+	oldpd->buffer = pd->buffer;
+	oldpd->nboff  = pd->nboff;
+	oldpd->nbits -= pd->moved - arg->ot_moved;
+	oldpd->moved += pd->moved - arg->ot_moved;
+	arg->ot_moved = pd->moved;
+
+	if(arg->unclaimed) {
+		/* Refill the container */
+		if(per_get_few_bits(oldpd, 1))
+			return -1;
+		if(oldpd->nboff == 0) {
+			assert(0);
+			return -1;
+		}
+		pd->buffer = oldpd->buffer;
+		pd->nboff = oldpd->nboff - 1;
+		pd->nbits = oldpd->nbits;
+		ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)",
+			(long)pd->moved);
+		return 0;
+	}
+
+	if(!arg->repeat) {
+		ASN_DEBUG("Want more but refill doesn't have it");
+		return -1;
+	}
+
+	next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat);
+	ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",
+		(long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);
+	if(next_chunk_bytes < 0) return -1;
+	if(next_chunk_bytes == 0) {
+		pd->refill = 0;	/* No more refills, naturally */
+		assert(!arg->repeat);	/* Implementation guarantee */
+	}
+	next_chunk_bits = next_chunk_bytes << 3;
+	avail = oldpd->nbits - oldpd->nboff;
+	if(avail >= next_chunk_bits) {
+		pd->nbits = oldpd->nboff + next_chunk_bits;
+		arg->unclaimed = 0;
+		ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)",
+			(long)next_chunk_bits, (long)oldpd->moved,
+			(long)oldpd->nboff, (long)oldpd->nbits,
+			(long)(oldpd->nbits - oldpd->nboff));
+	} else {
+		pd->nbits = oldpd->nbits;
+		arg->unclaimed = next_chunk_bits - avail;
+		ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld",
+			(long)avail, (long)next_chunk_bits,
+			(long)arg->unclaimed);
+	}
+	pd->buffer = oldpd->buffer;
+	pd->nboff = oldpd->nboff;
+	ASN_DEBUG("Refilled pd%s old%s",
+		per_data_string(pd), per_data_string(oldpd));
+	return 0;
+}
+
+static int
+per_skip_bits(asn_per_data_t *pd, int skip_nbits) {
+	int hasNonZeroBits = 0;
+	while(skip_nbits > 0) {
+		int skip;
+
+		/* per_get_few_bits() is more efficient when nbits <= 24 */
+		if(skip_nbits < 24)
+			skip = skip_nbits;
+		else
+			skip = 24;
+		skip_nbits -= skip;
+
+		switch(per_get_few_bits(pd, skip)) {
+		case -1: return -1;	/* Starving */
+		case 0: continue;	/* Skipped empty space */
+		default: hasNonZeroBits = 1; continue;
+		}
+	}
+	return hasNonZeroBits;
+}
diff --git a/asn1/asn1c/per_opentype.h b/asn1/asn1c/per_opentype.h
new file mode 100644
index 0000000000000000000000000000000000000000..facfaa6377bddcc85e23ac8c511f3d047a56324b
--- /dev/null
+++ b/asn1/asn1c/per_opentype.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2007 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_PER_OPENTYPE_H_
+#define	_PER_OPENTYPE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd);
+
+int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd);
+
+int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _PER_OPENTYPE_H_ */
diff --git a/asn1/asn1c/per_support.c b/asn1/asn1c/per_support.c
index c83441931caf1fcc3a79c0062014833db3d141b5..0d089f495226347e6bb5f7ef5c04d5f7cdaa3d64 100644
--- a/asn1/asn1c/per_support.c
+++ b/asn1/asn1c/per_support.c
@@ -1,25 +1,67 @@
 /*
- * Copyright (c) 2005, 2006 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Copyright (c) 2005-2014 Lev Walkin <vlm at lionet.info>.
+ * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_system.h>
 #include <asn_internal.h>
 #include <per_support.h>
 
+char *
+per_data_string(asn_per_data_t *pd) {
+	static char buf[2][32];
+	static int n;
+	n = (n+1) % 2;
+	snprintf(buf[n], sizeof(buf),
+		"{m=%ld span %+ld[%d..%d] (%d)}",
+		(long)pd->moved,
+		(((long)pd->buffer) & 0xf),
+		(int)pd->nboff, (int)pd->nbits,
+		(int)(pd->nbits - pd->nboff));
+	return buf[n];
+}
+
+void
+per_get_undo(asn_per_data_t *pd, int nbits) {
+	if((ssize_t)pd->nboff < nbits) {
+		assert((ssize_t)pd->nboff < nbits);
+	} else {
+		pd->nboff -= nbits;
+		pd->moved -= nbits;
+	}
+}
+
 /*
  * Extract a small number of bits (<= 31) from the specified PER data pointer.
  */
 int32_t
 per_get_few_bits(asn_per_data_t *pd, int nbits) {
 	size_t off;	/* Next after last bit offset */
+	ssize_t nleft;	/* Number of bits left in this stream */
 	uint32_t accum;
 	const uint8_t *buf;
 
-	if(nbits < 0 || pd->nboff + nbits > pd->nbits)
+	if(nbits < 0)
 		return -1;
 
-	ASN_DEBUG("[PER get %d bits from %p+%d bits]",
-		nbits, pd->buffer, pd->nboff);
+	nleft = pd->nbits - pd->nboff;
+	if(nbits > nleft) {
+		int32_t tailv, vhead;
+		if(!pd->refill || nbits > 31) return -1;
+		/* Accumulate unused bytes before refill */
+		ASN_DEBUG("Obtain the rest %d bits (want %d)",
+			(int)nleft, (int)nbits);
+		tailv = per_get_few_bits(pd, nleft);
+		if(tailv < 0) return -1;
+		/* Refill (replace pd contents with new data) */
+		if(pd->refill(pd))
+			return -1;
+		nbits -= nleft;
+		vhead = per_get_few_bits(pd, nbits);
+		/* Combine the rest of previous pd with the head of new one */
+		tailv = (tailv << nbits) | vhead;  /* Could == -1 */
+		return tailv;
+	}
 
 	/*
 	 * Normalize position indicator.
@@ -29,7 +71,9 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) {
 		pd->nbits  -= (pd->nboff & ~0x07);
 		pd->nboff  &= 0x07;
 	}
-	off = (pd->nboff += nbits);
+	pd->moved += nbits;
+	pd->nboff += nbits;
+	off = pd->nboff;
 	buf = pd->buffer;
 
 	/*
@@ -47,15 +91,29 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) {
 	else if(nbits <= 31) {
 		asn_per_data_t tpd = *pd;
 		/* Here are we with our 31-bits limit plus 1..7 bits offset. */
-		tpd.nboff -= nbits;
+		per_get_undo(&tpd, nbits);
+		/* The number of available bits in the stream allow
+		 * for the following operations to take place without
+		 * invoking the ->refill() function */
 		accum  = per_get_few_bits(&tpd, nbits - 24) << 24;
 		accum |= per_get_few_bits(&tpd, 24);
 	} else {
-		pd->nboff -= nbits;	/* Oops, revert back */
+		per_get_undo(pd, nbits);
 		return -1;
 	}
 
-	return (accum & (((uint32_t)1 << nbits) - 1));
+	accum &= (((uint32_t)1 << nbits) - 1);
+
+	ASN_DEBUG("  [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]",
+		(int)nbits, (int)nleft,
+		(int)pd->moved,
+		(((long)pd->buffer) & 0xf),
+		(int)pd->nboff, (int)pd->nbits,
+		pd->buffer[0],
+		(int)(pd->nbits - pd->nboff),
+		(int)accum);
+
+	return accum;
 }
 
 /*
@@ -130,6 +188,30 @@ uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) {
 }
 
 /*
+ * Get the normally small length "n".
+ * This procedure used to decode length of extensions bit-maps
+ * for SET and SEQUENCE types.
+ */
+ssize_t
+uper_get_nslength(asn_per_data_t *pd) {
+	ssize_t length;
+
+	ASN_DEBUG("Getting normally small length");
+
+	if(per_get_few_bits(pd, 1) == 0) {
+		length = per_get_few_bits(pd, 6) + 1;
+		if(length <= 0) return -1;
+		ASN_DEBUG("l=%d", (int)length);
+		return length;
+	} else {
+		int repeat;
+		length = uper_get_length(pd, -1, &repeat);
+		if(length >= 0 && !repeat) return length;
+		return -1; /* Error, or do not support >16K extensions */
+	}
+}
+
+/*
  * Get the normally small non-negative whole number.
  * X.691, #10.6
  */
@@ -156,8 +238,8 @@ uper_get_nsnnwn(asn_per_data_t *pd) {
 }
 
 /*
- * Put the normally small non-negative whole number.
- * X.691, #10.6
+ * X.691-11/2008, #11.6
+ * Encoding of a normally small non-negative whole number
  */
 int
 uper_put_nsnnwn(asn_per_outp_t *po, int n) {
@@ -182,6 +264,58 @@ uper_put_nsnnwn(asn_per_outp_t *po, int n) {
 }
 
 
+/* X.691-2008/11, #11.5.6 -> #11.3 */
+int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) {
+	unsigned long lhalf;    /* Lower half of the number*/
+	long half;
+
+	if(nbits <= 31) {
+		half = per_get_few_bits(pd, nbits);
+		if(half < 0) return -1;
+		*out_value = half;
+		return 0;
+	}
+
+	if((size_t)nbits > 8 * sizeof(*out_value))
+		return -1;  /* RANGE */
+
+	half = per_get_few_bits(pd, 31);
+	if(half < 0) return -1;
+
+	if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31))
+		return -1;
+
+	*out_value = ((unsigned long)half << (nbits - 31)) | lhalf;
+	return 0;
+}
+
+
+/* X.691-2008/11, #11.5.6 -> #11.3 */
+int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) {
+	/*
+	 * Assume signed number can be safely coerced into
+	 * unsigned of the same range.
+	 * The following testing code will likely be optimized out
+	 * by compiler if it is true.
+	 */
+	unsigned long uvalue1 = ULONG_MAX;
+	         long svalue  = uvalue1;
+	unsigned long uvalue2 = svalue;
+	assert(uvalue1 == uvalue2);
+	return uper_put_constrained_whole_number_u(po, v, nbits);
+}
+
+int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) {
+	if(nbits <= 31) {
+		return per_put_few_bits(po, v, nbits);
+	} else {
+		/* Put higher portion first, followed by lower 31-bit */
+		if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31))
+			return -1;
+		return per_put_few_bits(po, v, 31);
+	}
+}
+
 /*
  * Put a small number of bits (<= 31).
  */
@@ -193,8 +327,8 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) {
 
 	if(obits <= 0 || obits >= 32) return obits ? -1 : 0;
 
-	ASN_DEBUG("[PER put %d bits to %p+%d bits]",
-			obits, po->buffer, po->nboff);
+	ASN_DEBUG("[PER put %d bits %x to %p+%d bits]",
+			obits, (int)bits, po->buffer, (int)po->nboff);
 
 	/*
 	 * Normalize position indicator.
@@ -210,7 +344,9 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) {
 	 */
 	if(po->nboff + obits > po->nbits) {
 		int complete_bytes = (po->buffer - po->tmpspace);
-		if(po->outper(po->buffer, complete_bytes, po->op_key) < 0)
+		ASN_DEBUG("[PER output %ld complete + %ld]",
+			(long)complete_bytes, (long)po->flushed_bytes);
+		if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0)
 			return -1;
 		if(po->nboff)
 			po->tmpspace[0] = po->buffer[0];
@@ -224,41 +360,47 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) {
 	 */
 	buf = po->buffer;
 	omsk = ~((1 << (8 - po->nboff)) - 1);
-	off = (po->nboff += obits);
+	off = (po->nboff + obits);
 
 	/* Clear data of debris before meaningful bits */
 	bits &= (((uint32_t)1 << obits) - 1);
 
-	ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, bits, bits,
-		po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk);
+	ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits,
+		(int)bits, (int)bits,
+		(int)po->nboff, (int)off,
+		buf[0], (int)(omsk&0xff),
+		(int)(buf[0] & omsk));
 
 	if(off <= 8)	/* Completely within 1 byte */
+		po->nboff = off,
 		bits <<= (8 - off),
 		buf[0] = (buf[0] & omsk) | bits;
 	else if(off <= 16)
+		po->nboff = off,
 		bits <<= (16 - off),
 		buf[0] = (buf[0] & omsk) | (bits >> 8),
 		buf[1] = bits;
 	else if(off <= 24)
+		po->nboff = off,
 		bits <<= (24 - off),
 		buf[0] = (buf[0] & omsk) | (bits >> 16),
 		buf[1] = bits >> 8,
 		buf[2] = bits;
 	else if(off <= 31)
+		po->nboff = off,
 		bits <<= (32 - off),
 		buf[0] = (buf[0] & omsk) | (bits >> 24),
 		buf[1] = bits >> 16,
 		buf[2] = bits >> 8,
 		buf[3] = bits;
 	else {
-		ASN_DEBUG("->[PER out split %d]", obits);
-		per_put_few_bits(po, bits >> 8, 24);
+		per_put_few_bits(po, bits >> (obits - 24), 24);
 		per_put_few_bits(po, bits, obits - 24);
-		ASN_DEBUG("<-[PER out split %d]", obits);
 	}
 
-	ASN_DEBUG("[PER out %u/%x => %02x buf+%d]",
-		bits, bits, buf[0], po->buffer - po->tmpspace);
+	ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]",
+		(int)bits, (int)bits, buf[0],
+		(long)(po->buffer - po->tmpspace));
 
 	return 0;
 }
@@ -316,3 +458,26 @@ uper_put_length(asn_per_outp_t *po, size_t length) {
 			? -1 : (ssize_t)(length << 14);
 }
 
+
+/*
+ * Put the normally small length "n" into the stream.
+ * This procedure used to encode length of extensions bit-maps
+ * for SET and SEQUENCE types.
+ */
+int
+uper_put_nslength(asn_per_outp_t *po, size_t length) {
+
+	if(length <= 64) {
+		/* #10.9.3.4 */
+		if(length == 0) return -1;
+		return per_put_few_bits(po, length-1, 7) ? -1 : 0;
+	} else {
+		if(uper_put_length(po, length) != (ssize_t)length) {
+			/* This might happen in case of >16K extensions */
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
diff --git a/asn1/asn1c/per_support.h b/asn1/asn1c/per_support.h
index 420bb83c58d081ba3949951b67709e3200e7192a..10c84ed0839100912db28219647fb7594c84a9b0 100644
--- a/asn1/asn1c/per_support.h
+++ b/asn1/asn1c/per_support.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2005, 2006 Lev Walkin <vlm at lionet.info>. All rights reserved.
+ * Copyright (c) 2005-2014 Lev Walkin <vlm at lionet.info>.
+ * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #ifndef	_PER_SUPPORT_H_
@@ -29,15 +30,20 @@ typedef struct asn_per_constraint_s {
 typedef struct asn_per_constraints_s {
 	asn_per_constraint_t value;
 	asn_per_constraint_t size;
+	int (*value2code)(unsigned int value);
+	int (*code2value)(unsigned int code);
 } asn_per_constraints_t;
 
 /*
  * This structure describes a position inside an incoming PER bit stream.
  */
 typedef struct asn_per_data_s {
- const uint8_t *buffer;	/* Pointer to the octet stream */
-        size_t  nboff;	/* Bit offset to the meaningful bit */
-        size_t  nbits;	/* Number of bits in the stream */
+  const uint8_t *buffer;  /* Pointer to the octet stream */
+         size_t  nboff;   /* Bit offset to the meaningful bit */
+         size_t  nbits;   /* Number of bits in the stream */
+         size_t  moved;   /* Number of bits moved through this bit stream */
+  int (*refill)(struct asn_per_data_s *);
+  void *refill_key;
 } asn_per_data_t;
 
 /*
@@ -47,6 +53,9 @@ typedef struct asn_per_data_s {
  */
 int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits);
 
+/* Undo the immediately preceeding "get_few_bits" operation */
+void per_get_undo(asn_per_data_t *per_data, int get_nbits);
+
 /*
  * Extract a large number of bits from the specified PER data pointer.
  * This function returns -1 if the specified number of bits could not be
@@ -63,10 +72,21 @@ ssize_t uper_get_length(asn_per_data_t *pd,
 			int *repeat);
 
 /*
+ * Get the normally small length "n".
+ */
+ssize_t uper_get_nslength(asn_per_data_t *pd);
+
+/*
  * Get the normally small non-negative whole number.
  */
 ssize_t uper_get_nsnnwn(asn_per_data_t *pd);
 
+/* X.691-2008/11, #11.5.6 */
+int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits);
+
+/* Non-thread-safe debugging function, don't use it */
+char *per_data_string(asn_per_data_t *pd);
+
 /*
  * This structure supports forming PER output.
  */
@@ -86,6 +106,10 @@ int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits);
 /* Output a large number of bits */
 int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits);
 
+/* X.691-2008/11, #11.5 */
+int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits);
+int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits);
+
 /*
  * Put the length "n" to the Unaligned PER stream.
  * This function returns the number of units which may be flushed
@@ -94,6 +118,12 @@ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits);
 ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length);
 
 /*
+ * Put the normally small length "n" to the Unaligned PER stream.
+ * Returns 0 or -1.
+ */
+int uper_put_nslength(asn_per_outp_t *po, size_t length);
+
+/*
  * Put the normally small non-negative whole number.
  */
 int uper_put_nsnnwn(asn_per_outp_t *po, int n);
diff --git a/asn1/asn1c/xer_decoder.c b/asn1/asn1c/xer_decoder.c
index 161dc78ce5320368d07c0cd9b01032d07997e0fb..cb4b5f87850c14b2bd93331250db2e342ba0a68a 100644
--- a/asn1/asn1c/xer_decoder.c
+++ b/asn1/asn1c/xer_decoder.c
@@ -109,7 +109,8 @@ xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
 
 	if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
 		if(size >= 2)
-		ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]);
+			ASN_DEBUG("Broken XML tag: \"%c...%c\"",
+			buf[0], buf[size - 1]);
 		return XCT_BROKEN;
 	}
 
@@ -315,8 +316,8 @@ xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
 }
 
 
-int
-xer_is_whitespace(const void *chunk_buf, size_t chunk_size) {
+size_t
+xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
 	const char *p = (const char *)chunk_buf;
 	const char *pend = p + chunk_size;
 
@@ -329,12 +330,13 @@ xer_is_whitespace(const void *chunk_buf, size_t chunk_size) {
 		 * SPACE (32)
 		 */
 		case 0x09: case 0x0a: case 0x0d: case 0x20:
+			continue;
+		default:
 			break;
-		default:
-			return 0;
 		}
+		break;
 	}
-	return 1;       /* All whitespace */
+	return (p - (const char *)chunk_buf);
 }
 
 /*
diff --git a/asn1/asn1c/xer_decoder.h b/asn1/asn1c/xer_decoder.h
index cf0d846fe72d66d0c03548e9f6f4b2c3ecab716d..6988648e8dcc28c73e9c405f78efcc33f4e9aff2 100644
--- a/asn1/asn1c/xer_decoder.h
+++ b/asn1/asn1c/xer_decoder.h
@@ -87,12 +87,11 @@ xer_check_tag_e xer_check_tag(const void *buf_ptr, int size,
 		const char *need_tag);
 
 /*
- * Check whether this buffer consists of entirely XER whitespace characters.
+ * Get the number of bytes consisting entirely of XER whitespace characters.
  * RETURN VALUES:
- * 1:	Whitespace or empty string
- * 0:	Non-whitespace
+ * >=0:	Number of whitespace characters in the string.
  */
-int xer_is_whitespace(const void *chunk_buf, size_t chunk_size);
+size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size);
 
 /*
  * Skip the series of anticipated extensions.
-- 
2.5.0



More information about the Freeipa-devel mailing list