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
>From 47ca1fddb778c9aa68fb82f70458364a77d66aea Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lsleb...@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 <v...@lionet.info>.
+ * Copyright (c) 2003-2014 Lev Walkin <v...@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 <v...@lionet.info>. All rights reserved.
+ * Copyright (c) 2004, 2007 Lev Walkin <v...@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 <v...@lionet.info>.
+ * Copyright (c) 2003, 2004, 2005, 2007 Lev Walkin <v...@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 <v...@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004, 2007 Lev Walkin <v...@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 <v...@lionet.info>.
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <v...@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 <v...@lionet.info>.
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <v...@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 <v...@lionet.info>. All rights reserved.
+ * Copyright (c) 2005, 2007 Lev Walkin <v...@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 <v...@lionet.info>. All rights reserved.
+ * Copyright (c) 2006, 2007 Lev Walkin <v...@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 <v...@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 <v...@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 <v...@lionet.info>. All rights reserved.
+ * Copyright (c) 2005-2014 Lev Walkin <v...@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 <v...@lionet.info>. All rights reserved.
+ * Copyright (c) 2005-2014 Lev Walkin <v...@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

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to