egg: Rework how DER parsing works
authorStef Walter <stefw@gnome.org>
Wed, 20 Jun 2012 06:15:20 +0000 (08:15 +0200)
committerStef Walter <stefw@gnome.org>
Thu, 21 Jun 2012 14:14:59 +0000 (16:14 +0200)
 In particular fix things like
 * Indefinite parsing
 * Encoding of defaults
 * Ability to read values that haven't yet been encoded
 * Proper handling of ANY tags

21 files changed:
egg/egg-asn1x.c
egg/egg-asn1x.h
egg/egg-dn.c
egg/egg-dn.h
egg/egg-symkey.c
egg/egg-symkey.h
egg/tests/Makefile.am
egg/tests/files/test-personalname-1.der
egg/tests/files/test-personalname-invalid.der [new file with mode: 0644]
egg/tests/files/test-pkcs12-2.der [new file with mode: 0644]
egg/tests/test-asn1.c
egg/tests/test-asn1x.c
egg/tests/test-dn.c
egg/tests/test.asn
gcr/gcr-certificate-extensions.c
gcr/gcr-certificate-renderer.c
gcr/gcr-certificate-request.c
gcr/gcr-parser.c
gcr/gcr-subject-public-key.c
gcr/tests/files/usr0052-firefox.p12 [new file with mode: 0644]
gcr/tests/test-parser.c

index 0fabb74..6fcd48e 100644 (file)
 
 /* From libtasn1's libtasn.h */
 
-#define ASN1_CLASS_UNIVERSAL           0x00
-#define ASN1_CLASS_APPLICATION         0x40
-#define ASN1_CLASS_CONTEXT_SPECIFIC    0x80
-#define ASN1_CLASS_PRIVATE             0xC0
-#define ASN1_CLASS_STRUCTURED          0x20
-
-#define ASN1_TAG_BOOLEAN               0x01
-#define ASN1_TAG_INTEGER               0x02
-#define ASN1_TAG_SEQUENCE              0x10
-#define ASN1_TAG_SET                   0x11
-#define ASN1_TAG_OCTET_STRING          0x04
-#define ASN1_TAG_BIT_STRING            0x03
-#define ASN1_TAG_UTCTime               0x17
-#define ASN1_TAG_GENERALIZEDTime       0x18
-#define ASN1_TAG_OBJECT_ID             0x06
-#define ASN1_TAG_ENUMERATED            0x0A
-#define ASN1_TAG_NULL                  0x05
-#define ASN1_TAG_GENERALSTRING         0x1B
+enum {
+       ASN1_CLASS_UNIVERSAL = 0x00,
+       ASN1_CLASS_APPLICATION = 0x40,
+       ASN1_CLASS_CONTEXT_SPECIFIC = 0x80,
+       ASN1_CLASS_PRIVATE = 0xC0,
+       ASN1_CLASS_STRUCTURED = 0x20,
+};
 
+enum {
+       ASN1_TAG_BOOLEAN = 0x01,
+       ASN1_TAG_INTEGER = 0x02,
+       ASN1_TAG_SEQUENCE = 0x10,
+       ASN1_TAG_SET = 0x11,
+       ASN1_TAG_OCTET_STRING = 0x04,
+       ASN1_TAG_BIT_STRING = 0x03,
+       ASN1_TAG_UTC_TIME = 0x17,
+       ASN1_TAG_GENERALIZED_TIME = 0x18,
+       ASN1_TAG_OBJECT_ID = 0x06,
+       ASN1_TAG_ENUMERATED = 0x0A,
+       ASN1_TAG_NULL = 0x05,
+       ASN1_TAG_GENERALSTRING = 0x1B,
+};
 
 /* From libtasn1's int.h */
 
@@ -104,31 +107,30 @@ enum {
        FLAG_RIGHT = (1<<30),
 };
 
-typedef gboolean (*Aencoder) (gpointer data,
-                              GNode *node,
-                              guchar *buf,
-                              gsize n_buf);
-
-typedef struct _Aenc Aenc;
 typedef struct _Atlv Atlv;
 typedef struct _Anode Anode;
-typedef struct _Abuf Abuf;
-typedef struct _Abits Abits;
-
-struct _Aenc {
-       Aencoder encoder;
-       gpointer data;
-       GDestroyNotify destroy;
-};
 
 struct _Atlv {
        guchar cls;
        gulong tag;
        gint off;
-       gint oft;
        gint len;
-       const guchar *buf;
-       const guchar *end;
+
+       /* An actual value here */
+       GBytes *value;
+
+       /* Reference to what was decoded */
+       GBytes *decoded;
+
+       /* Chain this into a tree */
+       struct _Atlv *child;
+       struct _Atlv *next;
+
+       /* Used during encoding */
+       guint bits_empty : 3;
+       guint prefix_for_bit_string : 1;
+       guint prefix_with_zero_byte : 1;
+       guint sorted : 1;
 };
 
 struct _Anode {
@@ -136,31 +138,23 @@ struct _Anode {
        const EggAsn1xDef *join;
        GList *opts;
 
-       Atlv *tlv;
-       Aenc *enc;
+       GBytes *value;
+       Atlv *parsed;
 
-       GBytes *backing;
        gchar* failure;
 
-       gint chosen : 1;
-};
-
-struct _Abuf {
-       guchar* data;
-       gsize n_data;
-       gpointer user_data;
-};
-
-struct _Abits {
-       guint n_bits;
-       GBytes *bits;
+       guint chosen : 1;
+       guint bits_empty : 3;
+       guint guarantee_unsigned : 1;
 };
 
 /* Forward Declarations */
-static gboolean anode_decode_anything (GNode*, GBytes*, Atlv*);
-static gboolean anode_decode_anything_for_flags (GNode *, GBytes*, Atlv*, gint);
-static gboolean anode_validate_anything (GNode*, gboolean);
-static gboolean anode_encode_prepare (GNode*, gboolean want);
+static gboolean anode_decode_anything (GNode *, Atlv *);
+static gboolean anode_decode_one (GNode *, Atlv *);
+static GBytes * anode_default_boolean (GNode *node);
+static GBytes * anode_default_integer (GNode *node);
+static gboolean anode_validate_anything (GNode *, gboolean);
+static Atlv * anode_build_anything (GNode*, gboolean want);
 
 static gint
 atoin (const char *p, gint digits)
@@ -175,6 +169,55 @@ atoin (const char *p, gint digits)
        return ret;
 }
 
+static const guchar *
+bytes_get_end (GBytes *data)
+{
+       const guchar *beg;
+       gsize size;
+       beg = g_bytes_get_data (data, &size);
+       return beg + size;
+}
+
+typedef struct {
+       EggAllocator allocator;
+       gpointer allocated;
+} AllocatorClosure;
+
+static void
+allocator_closure_free (gpointer data)
+{
+       AllocatorClosure *closure = data;
+       g_assert (closure->allocator);
+       (closure->allocator) (closure->allocated, 0);
+       g_slice_free (AllocatorClosure, closure);
+}
+
+static GBytes *
+bytes_new_with_allocator (EggAllocator allocator,
+                          guchar **data,
+                          gsize length)
+{
+       AllocatorClosure *closure;
+
+       if (allocator == g_realloc)
+               allocator = NULL;
+
+       if (allocator) {
+               *data = (allocator) (NULL, length + 1);
+               if (allocator == NULL)
+                       return NULL;
+               closure = g_slice_new (AllocatorClosure);
+               closure->allocated = *data;
+               closure->allocator = allocator;
+               return g_bytes_new_with_free_func (*data, length,
+                                                  allocator_closure_free,
+                                                  closure);
+       } else {
+               *data = g_malloc (length);
+               return g_bytes_new_take (*data, length);
+       }
+}
+
 static GNode*
 anode_new (const EggAsn1xDef *def)
 {
@@ -357,110 +400,97 @@ anode_opts_lookup (GNode *node, gint type, const gchar *name)
        return g_list_reverse (res);
 }
 
-static gint
-compare_tlvs (Atlv *tlva, Atlv *tlvb)
+static Atlv *
+atlv_new (void)
 {
-       gint la = tlva->off + tlva->len;
-       gint lb = tlvb->off + tlvb->len;
-       gint res;
-
-       g_assert (tlva->buf);
-       g_assert (tlvb->buf);
-       res = memcmp (tlva->buf, tlvb->buf, MIN (la, lb));
-       if (la == lb || res != 0)
-               return res;
-       return la < lb ? -1 : 1;
+       return g_slice_new0 (Atlv);
 }
 
-static inline GBytes *
-anode_get_backing (GNode *node)
+static void
+atlv_free (Atlv *tlv)
 {
-       Anode *an = node->data;
-       return an->backing;
-}
+       if (!tlv)
+               return;
 
-static inline void
-anode_clr_backing (GNode *node)
-{
-       Anode *an = node->data;
-       if (an->backing)
-               g_bytes_unref (an->backing);
-       an->backing = NULL;
-}
+       /* Free attached TLVs */
+       atlv_free (tlv->child);
+       atlv_free (tlv->next);
 
-static inline void
-anode_set_backing (GNode *node,
-                   GBytes *backing)
-{
-       Anode *an = node->data;
-       if (backing)
-               g_bytes_ref (backing);
-       if (an->backing)
-               g_bytes_unref (an->backing);
-       an->backing = backing;
+       /* Free the TLV */
+       if (tlv->decoded)
+               g_bytes_unref (tlv->decoded);
+       if (tlv->value)
+               g_bytes_unref (tlv->value);
+
+       g_slice_free (Atlv, tlv);
 }
 
-static void
-anode_set_tlv_data (GNode *node,
-                    GBytes *backing,
-                    Atlv *tlv)
+static Atlv *
+atlv_dup (Atlv *tlv,
+          gboolean siblings)
 {
-       Anode *an = node->data;
-       g_assert (an->tlv == NULL);
-       g_assert (tlv->len >= 0);
-       anode_set_backing (node, backing);
-       an->tlv = g_slice_new0 (Atlv);
-       memcpy (an->tlv, tlv, sizeof (Atlv));
+       Atlv *copy;
+
+       if (!tlv)
+               return NULL;
+
+       copy = g_slice_new0 (Atlv);
+       memcpy (copy, tlv, sizeof (Atlv));
+
+       if (tlv->value != NULL)
+               copy->value = g_bytes_ref (tlv->value);
+       if (tlv->decoded != NULL)
+               copy->decoded = g_bytes_ref (tlv->decoded);
+
+       copy->child = atlv_dup (tlv->child, TRUE);
+       if (siblings)
+               copy->next = atlv_dup (tlv->next, TRUE);
+       else
+               copy->next = NULL;
+
+       return copy;
 }
 
-static inline Atlv *
-anode_get_tlv_data (GNode *node)
+static inline GBytes *
+anode_get_value (GNode *node)
 {
        Anode *an = node->data;
-       return an->tlv;
+       return an->value;
 }
 
-static void
-anode_clr_tlv_data (GNode *node)
+static inline void
+anode_clr_value (GNode *node)
 {
        Anode *an = node->data;
-       if (an->tlv);
-               g_slice_free (Atlv, an->tlv);
-       an->tlv = NULL;
+       if (an->value)
+               g_bytes_unref (an->value);
+       an->value = NULL;
+
+       atlv_free (an->parsed);
+       an->parsed = NULL;
 }
 
-static void
-anode_clr_enc_data (GNode *node)
+static inline void
+anode_take_value (GNode *node,
+                  GBytes *value)
 {
        Anode *an = node->data;
-       if (an->enc) {
-               if (an->enc->destroy)
-                       (an->enc->destroy) (an->enc->data);
-               g_slice_free (Aenc, an->enc);
-               an->enc = NULL;
-       }
+       anode_clr_value (node);
+       an->value = value;
 }
 
-static void
-anode_set_enc_data (GNode *node,
-                    Aencoder encoder,
-                    gpointer data,
-                    GDestroyNotify destroy)
+static inline void
+anode_set_value (GNode *node,
+                 GBytes *value)
 {
-       Anode *an = node->data;
-       g_assert (!an->enc);
-       an->enc = g_slice_new0 (Aenc);
-       an->enc->encoder = encoder;
-       an->enc->data = data;
-       an->enc->destroy = destroy;
-       anode_clr_backing (node);
+       anode_take_value (node, g_bytes_ref (value));
 }
 
-static Aenc*
-anode_get_enc_data (GNode *node)
+static inline Atlv *
+anode_get_parsed (GNode *node)
 {
        Anode *an = node->data;
-       return an->enc;
+       return an->parsed;
 }
 
 static gboolean
@@ -493,9 +523,7 @@ static void
 anode_clear (GNode *node)
 {
        Anode *an = node->data;
-       anode_clr_backing (node);
-       anode_clr_tlv_data (node);
-       anode_clr_enc_data (node);
+       anode_clr_value (node);
        g_free (an->failure);
        an->failure = NULL;
 }
@@ -511,16 +539,6 @@ anode_free_func (GNode *node, gpointer unused)
 }
 
 static void
-abits_destroy (gpointer data)
-{
-       Abits *ab = data;
-       g_assert (ab != NULL);
-       if (ab->bits)
-               g_bytes_unref (ab->bits);
-       g_slice_free (Abits, ab);
-}
-
-static void
 anode_destroy (GNode *node)
 {
        if (!G_NODE_IS_ROOT (node))
@@ -561,9 +579,9 @@ anode_calc_tag_for_flags (GNode *node, gint flags)
                return ASN1_TAG_GENERALSTRING;
        case EGG_ASN1X_TIME:
                if (flags & FLAG_GENERALIZED)
-                       return ASN1_TAG_GENERALIZEDTime;
+                       return ASN1_TAG_GENERALIZED_TIME;
                else if (flags & FLAG_UTC)
-                       return ASN1_TAG_UTCTime;
+                       return ASN1_TAG_UTC_TIME;
                else
                        g_return_val_if_reached (G_MAXULONG);
        case EGG_ASN1X_SEQUENCE:
@@ -625,47 +643,43 @@ anode_calc_explicit_for_flags (GNode *node,
        return TRUE;
 }
 
-static gboolean
-anode_calc_explicit (GNode *node,
-                     guchar *cls_type)
-{
-       return anode_calc_explicit_for_flags (node, anode_def_flags (node), cls_type);
-}
-
 /* -------------------------------------------------------------------------
- * DECODE
+ * PARSING
  */
 
 static gboolean
-anode_decode_cls_tag (const guchar *data, const guchar *end,
-                      guchar *cls, gulong *tag, gint *cb)
+atlv_parse_cls_tag (const guchar *at,
+                    const guchar *end,
+                    guchar *cls,
+                    gulong *tag,
+                    gint *off)
 {
        gint punt, ris, last;
        gint n_data;
 
-       g_assert (end >= data);
-       g_assert (cls);
-       g_assert (cb);
+       g_assert (end >= at);
+       g_assert (cls != NULL);
+       g_assert (off != NULL);
 
-       n_data = end - data;
+       n_data = end - at;
 
        if (n_data < 2)
                return FALSE;
 
-       *cls = data[0] & 0xE0;
+       *cls = at[0] & 0xE0;
 
        /* short form */
-       if ((data[0] & 0x1F) != 0x1F) {
-               *cb = 1;
-               ris = data[0] & 0x1F;
+       if ((at[0] & 0x1F) != 0x1F) {
+               *off = 1;
+               ris = at[0] & 0x1F;
 
        /* Long form */
        } else {
                punt = 1;
                ris = 0;
-               while (punt <= n_data && data[punt] & 128) {
+               while (punt <= n_data && at[punt] & 128) {
                        int last = ris;
-                       ris = ris * 128 + (data[punt++] & 0x7F);
+                       ris = ris * 128 + (at[punt++] & 0x7F);
 
                        /* wrapper around, and no bignums... */
                        if (ris < last)
@@ -676,13 +690,13 @@ anode_decode_cls_tag (const guchar *data, const guchar *end,
                        return FALSE;
 
                last = ris;
-               ris = ris * 128 + (data[punt++] & 0x7F);
+               ris = ris * 128 + (at[punt++] & 0x7F);
 
                /* wrapper around, and no bignums... */
                if (ris < last)
                        return FALSE;
 
-               *cb = punt;
+               *off = punt;
        }
 
        if (tag)
@@ -692,31 +706,33 @@ anode_decode_cls_tag (const guchar *data, const guchar *end,
 }
 
 static gint
-anode_decode_length (const guchar *data, const guchar *end, gint *cb)
+atlv_parse_length (const guchar *at,
+                   const guchar *end,
+                   gint *off)
 {
        gint ans, last;
        gint k, punt;
        gint n_data;
 
-       g_assert (data);
-       g_assert (end);
-       g_assert (end >= data);
-       g_assert (cb);
+       g_assert (at != NULL);
+       g_assert (end != NULL);
+       g_assert (end >= at);
+       g_assert (off != NULL);
 
-       *cb = 0;
-       n_data = end - data;
+       *off = 0;
+       n_data = end - at;
 
        if (n_data == 0)
                return 0;
 
        /* short form */
-       if (!(data[0] & 128)) {
-               *cb = 1;
-               return data[0];
+       if (!(at[0] & 128)) {
+               *off = 1;
+               return at[0];
 
        /* Long form */
        } else {
-               k = data[0] & 0x7F;
+               k = at[0] & 0x7F;
                punt = 1;
 
                /* definite length method */
@@ -724,7 +740,7 @@ anode_decode_length (const guchar *data, const guchar *end, gint *cb)
                        ans = 0;
                        while (punt <= k && punt < n_data) {
                                last = ans;
-                               ans = ans * 256 + data[punt++];
+                               ans = ans * 256 + at[punt++];
 
                                /* we wrapped around, no bignum support... */
                                if (ans < last)
@@ -736,142 +752,160 @@ anode_decode_length (const guchar *data, const guchar *end, gint *cb)
                        ans = -1;
                }
 
-               *cb = punt;
+               *off = punt;
                return ans;
        }
 }
 
 static gboolean
-anode_decode_cls_tag_len (const guchar *data, const guchar *end,
-                          guchar *cls, gulong *tag, gint *off, gint *len)
+atlv_parse_cls_tag_len (const guchar *at,
+                        const guchar *end,
+                        guchar *cls,
+                        gulong *tag,
+                        gint *off,
+                        gint *len)
 {
        gint cb1, cb2;
 
-       g_assert (data);
-       g_assert (end);
-       g_assert (end >= data);
-       g_assert (off);
-       g_assert (len);
+       g_assert (at != NULL);
+       g_assert (end != NULL);
+       g_assert (end >= at);
+       g_assert (off != NULL);
+       g_assert (len != NULL);
 
-       if (!anode_decode_cls_tag (data, end, cls, tag, &cb1))
+       if (!atlv_parse_cls_tag (at, end, cls, tag, &cb1))
                return FALSE;
-       *len = anode_decode_length (data + cb1, end, &cb2);
+       *len = atlv_parse_length (at + cb1, end, &cb2);
        if (*len < -1)
                return FALSE;
        *off = cb1 + cb2;
-       if (*len >= 0 && data + *off + *len > end)
+       if (*len >= 0 && at + *off + *len > end)
                return FALSE;
        return TRUE;
 }
 
-static gboolean
-anode_check_indefinite_end (guchar cls, gulong tag, gint len)
-{
-       return (cls == ASN1_CLASS_UNIVERSAL && tag == 0 && len == 0);
-}
-
-static gboolean
-anode_decode_indefinite_len (const guchar *data, const guchar *end, gint *rlen)
+static const gchar *
+atlv_parse_der_tag (guchar cls,
+                    gulong tag,
+                    gint off,
+                    gint len,
+                    GBytes *data,
+                    const guchar **at,
+                    Atlv *tlv)
 {
-       gint result = 0;
-       gint der_len;
-       gint len;
-       guchar cls;
-       gulong tag;
-       gint off;
-
-       g_assert (data <= end);
-       der_len = end - data;
-
-       while (result < der_len) {
-               if (!anode_decode_cls_tag_len (data + result, end, &cls, &tag, &off, &len))
-                       return FALSE;
-
-               /* The indefinite end */
-               if (anode_check_indefinite_end (cls, tag, len))
-                       break;
-
-               result += off;
+       const guchar *end;
+       const gchar *ret;
+       const guchar *beg;
+       guchar ccls;
+       gulong ctag;
+       gint clen;
+       gint coff;
+       Atlv *child;
+       Atlv *last;
+
+       g_assert (at != NULL);
+       g_assert (tlv != NULL);
+
+       end = bytes_get_end (data);
+       g_assert (*at <= end);
+
+       if (*at + off + len > end)
+               return "invalid length of tlv";
+       if (len < 0 && !(cls & ASN1_CLASS_STRUCTURED))
+               return "indefinite length on non-structured type";
+
+       beg = *at;
+
+       tlv->cls = cls;
+       tlv->tag = tag;
+       tlv->off = off;
+       tlv->len = len;
+       (*at) += off;
+
+       /* Structured TLV, with further TLVs inside */
+       if (cls & ASN1_CLASS_STRUCTURED) {
+               /* If not indefinite length, then calculate end up front */
+               if (len >= 0)
+                       end = (*at) + len;
+               last = NULL;
+               while (*at < end) {
+                       if (!atlv_parse_cls_tag_len (*at, end, &ccls, &ctag, &coff, &clen))
+                               return "content is not encoded properly";
+
+                       /* End if indefinite length? */
+                       if (len < 0 && ccls == ASN1_CLASS_UNIVERSAL && ctag == 0 && clen == 0) {
+                               (*at) += coff;
+                               break;
+                       }
 
-               /* Mid way check */
-               if (result > der_len)
-                       break;
+                       /* Parse the child */
+                       child = atlv_new ();
+                       ret = atlv_parse_der_tag (ccls, ctag, coff, clen, data, at, child);
+                       if (ret != NULL) {
+                               atlv_free (child);
+                               return ret;
+                       }
 
-               if (len < 0) {
-                       if (!anode_decode_indefinite_len (data + result, end, &len))
-                               return FALSE;
-                       g_assert (len >= 0);
+                       /* Add the child to the right place */
+                       if (last == NULL)
+                               tlv->child = child;
+                       else
+                               last->next = child;
+                       last = child;
                }
 
-               if (result + len > der_len)
-                       return FALSE;
-               result += len;
+       /* Non-structured TLV, just a value */
+       } else {
+               tlv->value = g_bytes_new_with_free_func (*at, len,
+                                                        (GDestroyNotify)g_bytes_unref,
+                                                        g_bytes_ref (data));
+               (*at) += len;
        }
 
-       if (result > der_len)
-               return FALSE;
-       *rlen = result;
-       return TRUE;
-}
+       /* Note the actual DER that we decoded */
+       tlv->decoded = g_bytes_new_with_free_func (beg, *at - beg,
+                                                  (GDestroyNotify)g_bytes_unref,
+                                                  g_bytes_ref (data));
 
-static gboolean
-anode_decode_tlv_for_data (const guchar *data, const guchar *end, Atlv *tlv)
-{
-       g_assert (data <= end);
-       if (!anode_decode_cls_tag_len (data, end, &tlv->cls,
-                                      &tlv->tag, &tlv->off, &tlv->len))
-               return FALSE;
-       tlv->buf = data;
-       if (tlv->len < 0)
-               tlv->end = end;
-       else
-               tlv->end = tlv->buf + tlv->len + tlv->off;
-       g_assert (tlv->end <= end);
-       return TRUE;
+       return NULL; /* Success */
 }
 
-static gboolean
-anode_decode_tlv_for_contents (Atlv *outer, gboolean first, Atlv *tlv)
+static const gchar *
+atlv_parse_der (GBytes *data,
+                Atlv *tlv)
 {
-       const guchar *data;
        const guchar *end;
+       const guchar *at;
+       const gchar *ret;
+       guchar cls;
+       gulong tag;
+       gint off;
+       gint len;
+       gsize size;
 
-       if (first) {
-               data = outer->buf + outer->off;
-               end = outer->end;
-       } else {
-               data = tlv->end;
-               end = outer->end;
-       }
+       at = g_bytes_get_data (data, &size);
+       g_return_val_if_fail (at != NULL, FALSE);
+       end = at + size;
 
-       /* The end */
-       if (end == data) {
-               tlv->cls = ASN1_CLASS_UNIVERSAL;
-               tlv->tag = 0;
-               tlv->len = 0;
-               tlv->off = 0;
-               tlv->buf = data;
-               tlv->end = end;
-               return TRUE;
-       }
+       if (!atlv_parse_cls_tag_len (at, end, &cls, &tag, &off, &len))
+               return "content is not encoded properly";
 
-       g_return_val_if_fail (end > data, FALSE);
-       if (!anode_decode_tlv_for_data (data, end, tlv))
-               return FALSE;
+       ret = atlv_parse_der_tag (cls, tag, off, len, data, &at, tlv);
+       if (ret != NULL)
+               return ret;
 
-       /* Caller should stop before indefinite end, and not consume */
-       if (anode_check_indefinite_end (tlv->cls, tlv->tag, tlv->len)) {
-               tlv->buf = data;
-               tlv->end = data;
-               tlv->off = 0;
-       }
+       if (at != end)
+               return "extra unexpected trailing data";
 
-       return TRUE;
+       return NULL; /* Success */
 }
 
+/* -------------------------------------------------------------------------
+ * DECODING
+ */
+
 static gboolean
 anode_decode_choice (GNode *node,
-                     GBytes *backing,
                      Atlv *tlv)
 {
        gboolean have = FALSE;
@@ -880,7 +914,7 @@ anode_decode_choice (GNode *node,
 
        for (child = node->children; child; child = child->next) {
                an = (Anode*)child->data;
-               if (!have && anode_decode_anything (child, backing, tlv)) {
+               if (anode_decode_one (child, tlv)) {
                        an->chosen = 1;
                        have = TRUE;
                } else {
@@ -895,82 +929,40 @@ anode_decode_choice (GNode *node,
 }
 
 static gboolean
-anode_decode_struct_string (GNode *node, Atlv *outer)
-{
-       gint i = 0;
-       Atlv tlv;
-
-       /* Recalculated below */
-       outer->len = 0;
-
-       for (i = 0; TRUE; ++i) {
-               if (!anode_decode_tlv_for_contents (outer, i == 0, &tlv))
-                       return anode_failure (node, "invalid encoding of child");
-               if (tlv.tag != outer->tag)
-                       return anode_failure (node, "contents have an invalid tag");
-               outer->len = (tlv.end - outer->buf) - outer->off;
-       }
-
-       g_assert (outer->len >= 0);
-       return TRUE;
-}
-
-static gboolean
-anode_decode_struct_any (GNode *node, Atlv *tlv)
-{
-       if (tlv->len < 0) {
-               if (!anode_decode_indefinite_len (tlv->buf + tlv->off, tlv->end, &tlv->len))
-                       return anode_failure (node, "could not find end of encoding");
-               tlv->end = tlv->buf + tlv->off + tlv->len;
-       }
-
-       return TRUE;
-}
-
-static gboolean
 anode_decode_sequence_or_set (GNode *node,
-                              GBytes *backing,
-                              Atlv *outer)
+                              Atlv *tlv)
 {
-       GNode *child;
-       Atlv tlv;
+       Atlv *ctlv;
+       gulong tag;
        gint i;
 
-       /* Recalculated below */
-       outer->len = 0;
-
        /*
         * The reason we can parse a set just like a sequence, is because in DER,
         * the order of the SET is predefined by the tags. In addition the definitions
         * we have are sorted.
         */
 
-       for (child = node->children, i = 0; child; child = child->next, ++i) {
-
-               if (!anode_decode_tlv_for_contents (outer, i == 0, &tlv))
-                       return anode_failure (node, "invalid encoding of child");
-
-               if (!anode_decode_anything (child, backing, &tlv))
-                       return FALSE;
-
-               outer->len = (tlv.end - outer->buf) - outer->off;
+       /* Tags must be in ascending order */
+       if (anode_def_type (node) == EGG_ASN1X_SET) {
+               for (ctlv = tlv->child, i = 0; ctlv != NULL; ctlv = ctlv->next, i++) {
+                       if (i > 0 && tag > ctlv->tag)
+                               return anode_failure (node, "content must be in ascending order");
+                       tag = ctlv->tag;
+               }
        }
 
-       g_assert (outer->len >= 0);
-       return TRUE;
+       return anode_decode_anything (node->children, tlv->child);
 }
 
 static gboolean
 anode_decode_sequence_or_set_of (GNode *node,
-                                 GBytes *backing,
-                                 Atlv *outer)
+                                 Atlv *tlv)
 {
+       Atlv *ctlv;
        GNode *child, *other;
-       Atlv tlv;
+       gulong tag;
        gint i;
 
-       outer->len = 0;
-
        /* The first child */
        child = node->children;
        g_return_val_if_fail (child, FALSE);
@@ -979,15 +971,15 @@ anode_decode_sequence_or_set_of (GNode *node,
        while (child->next)
                anode_destroy (child->next);
 
-       /* Try to dig out as many of them as possible */
-       for (i = 0; TRUE; ++i) {
+       for (ctlv = tlv->child, i = 0; ctlv != NULL; ctlv = ctlv->next, i++) {
 
-               if (!anode_decode_tlv_for_contents (outer, i == 0, &tlv))
-                       return anode_failure (node, "invalid encoding of child");
+               /* Tag must have same tag as top */
+               if (i == 0)
+                       tag = anode_calc_tag (child);
+               else if (tag != G_MAXULONG && ctlv->tag != tag)
+                       return anode_failure (node, "invalid mismatched content");
 
-               /* The end of the road for us */
-               if (tlv.off == 0)
-                       break;
+               /* TODO: Set of must be in ascending order in DER encoding */
 
                if (i == 0) {
                        other = child;
@@ -996,171 +988,154 @@ anode_decode_sequence_or_set_of (GNode *node,
                        g_node_append (node, other);
                }
 
-               if (!anode_decode_anything (other, backing, &tlv))
+               if (!anode_decode_one (other, ctlv))
                        return FALSE;
-
-               outer->len = (tlv.end - outer->buf) - outer->off;
        }
 
-       g_assert (outer->len >= 0);
+       return TRUE;
+}
+
+static gboolean
+anode_decode_bit_string (GNode *node,
+                         Atlv *tlv)
+{
+       Anode *an = node->data;
+       guchar empty, mask;
+       GBytes *value;
+       const guchar *buf;
+       gsize len;
+
+       buf = g_bytes_get_data (tlv->value, &len);
+       if (len == 0)
+               return anode_failure (node, "invalid length bit string");
+
+       /* The first byte is the number of empty bits */
+       empty = buf[0];
+       if (empty >= 8)
+               return anode_failure (node, "invalid number of empty bits");
+
+       /* Free bits at end must be zero */
+       mask = 0xFF >> (8 - empty);
+       if (len > 1 && buf[len - 1] & mask)
+               return anode_failure (node, "bit string has invalid trailing bits");
+
+       value = g_bytes_new_from_bytes (tlv->value, 1, len - 1);
+       anode_take_value (node, value);
+       an = node->data;
+       an->bits_empty = empty;
        return TRUE;
 }
 
 static gboolean
 anode_decode_primitive (GNode *node,
-                        GBytes *backing,
                         Atlv *tlv,
                         gint flags)
 {
-       gint type;
+       /* Must not have any tlv children */
+       g_assert (tlv->child == NULL);
 
-       /* Must have a definite length */
-       if (tlv->len < 0)
-               return anode_failure (node, "primitive value with an indefinite length");
+       switch (anode_def_type (node)) {
 
-       type = anode_def_type (node);
-       switch (type) {
+       /* Handle bit strings specially */
+       case EGG_ASN1X_BIT_STRING:
+               return anode_decode_bit_string (node, tlv);
 
        /* The primitive value types */
        case EGG_ASN1X_INTEGER:
        case EGG_ASN1X_ENUMERATED:
        case EGG_ASN1X_BOOLEAN:
-       case EGG_ASN1X_BIT_STRING:
        case EGG_ASN1X_OCTET_STRING:
        case EGG_ASN1X_OBJECT_ID:
        case EGG_ASN1X_NULL:
        case EGG_ASN1X_GENERALSTRING:
        case EGG_ASN1X_TIME:
-               anode_set_tlv_data (node, backing, tlv);
+               anode_set_value (node, tlv->value);
                return TRUE;
 
-       /* Transparent types */
+       /* Just use the 'parsed' which is automatically set */
        case EGG_ASN1X_ANY:
-               anode_set_tlv_data (node, backing, tlv);
                return TRUE;
 
        case EGG_ASN1X_CHOICE:
-               if (!anode_decode_choice (node, backing, tlv))
-                       return FALSE;
-               anode_set_tlv_data (node, backing, tlv);
-               return TRUE;
+               return anode_decode_choice (node, tlv);
 
        default:
                return anode_failure (node, "primitive value of an unexpected type");
        }
-
-       g_assert_not_reached ();
 }
 
 static gboolean
 anode_decode_structured (GNode *node,
-                         GBytes *backing,
                          Atlv *tlv,
                          gint flags)
 {
-       gboolean definite;
-       const guchar *end;
-       Atlv ctlv;
-       gint len;
-       gulong tag;
-       guchar cls;
-       gint off = 0;
+       switch (anode_def_type (node)) {
+
+       /* Just use the 'parsed' which is automatically set */
+       case EGG_ASN1X_ANY:
+       case EGG_ASN1X_GENERALSTRING:
+       case EGG_ASN1X_OCTET_STRING:
+               return TRUE;
+
+       case EGG_ASN1X_CHOICE:
+               return anode_decode_choice (node, tlv);
+
+       case EGG_ASN1X_SEQUENCE:
+       case EGG_ASN1X_SET:
+               return anode_decode_sequence_or_set (node, tlv);
+
+       case EGG_ASN1X_SEQUENCE_OF:
+       case EGG_ASN1X_SET_OF:
+               return anode_decode_sequence_or_set_of (node, tlv);
+
+       default:
+               return anode_failure (node, "structured value of an unexpected type");
+       }
+}
 
-       definite = (tlv->len >= 0);
-       end = tlv->end;
+static gboolean
+anode_decode_one_without_tag (GNode *node,
+                              Atlv *tlv,
+                              gint flags)
+{
+       gboolean ret;
+       Anode *an;
 
        /* An explicit, wrapped tag */
        if (anode_calc_explicit_for_flags (node, flags, NULL)) {
                if ((tlv->cls & ASN1_CLASS_CONTEXT_SPECIFIC) == 0)
                        return anode_failure (node, "missing context specific tag");
-               if (!anode_decode_tlv_for_contents (tlv, TRUE, &ctlv))
-                       return anode_failure (node, "invalid encoding of child");
+               if (tlv->child == NULL)
+                       return anode_failure (node, "missing context specific child");
+               if (tlv->child->next != NULL)
+                       return anode_failure (node, "multiple context specific children");
                flags &= ~FLAG_TAG;
-               if (!anode_decode_anything_for_flags (node, backing, &ctlv, flags))
-                       return FALSE;
+               ret = anode_decode_one_without_tag (node, tlv->child, flags);
 
-               /* Use most of the child's tlv */
-               tlv->cls = ctlv.cls;
-               tlv->tag = ctlv.tag;
-               tlv->off += ctlv.off;
-               tlv->oft = ctlv.off;
-               tlv->len = ctlv.len;
-               anode_clr_tlv_data (node);
+       /* Structured value */
+       } else if (tlv->cls & ASN1_CLASS_STRUCTURED) {
+               ret = anode_decode_structured (node, tlv, flags);
 
-       /* Other structured types */
+       /* A primitive simple value */
        } else {
-               switch (anode_def_type (node)) {
-               case EGG_ASN1X_ANY:
-                       if (!anode_decode_struct_any (node, tlv))
-                               return FALSE;
-                       break;
-               case EGG_ASN1X_CHOICE:
-                       if (!anode_decode_choice (node, backing, tlv))
-                               return FALSE;
-                       break;
-               case EGG_ASN1X_GENERALSTRING:
-               case EGG_ASN1X_OCTET_STRING:
-                       if (!anode_decode_struct_string (node, tlv))
-                               return FALSE;
-                       break;
-               case EGG_ASN1X_SEQUENCE:
-               case EGG_ASN1X_SET:
-                       if (!anode_decode_sequence_or_set (node, backing, tlv))
-                               return FALSE;
-                       break;
-               case EGG_ASN1X_SEQUENCE_OF:
-               case EGG_ASN1X_SET_OF:
-                       if (!anode_decode_sequence_or_set_of (node, backing, tlv))
-                               return FALSE;
-                       break;
-               default:
-                       return FALSE;
-               }
-       }
-
-       g_return_val_if_fail (tlv->len >= 0, FALSE);
-
-       /* Indefinite, needs to be terminated with zeros */
-       if (!definite) {
-               if (!anode_decode_cls_tag_len (tlv->buf + (tlv->off + tlv->len), end,
-                                              &cls, &tag, &off, &len))
-                       return anode_failure (node, "end of indefinite content is missing");
-               if (!anode_check_indefinite_end (cls, tag, len))
-                       return anode_failure (node, "end of indefinite content is invalid");
-               end = tlv->buf + tlv->off + tlv->len + off;
+               ret = anode_decode_primitive (node, tlv, flags);
        }
 
-       /* A structure must be filled up, no stuff ignored */
-       if (tlv->buf + tlv->off + tlv->len + off < end)
-               return anode_failure (node, "extra data at the end of the content");
-       g_return_val_if_fail (tlv->buf + tlv->off + tlv->len + off == end, FALSE);
-
-       tlv->end = end;
-       anode_set_tlv_data (node, backing, tlv);
-       return TRUE;
-}
-
-static gboolean
-anode_decode_option_or_default (GNode *node, Atlv *tlv, gint flags)
-{
-       if (flags & FLAG_OPTION || flags & FLAG_DEFAULT) {
-               tlv->len = 0;
-               tlv->end = tlv->buf;
-               tlv->off = 0;
-               anode_clr_tlv_data (node);
-               return TRUE;
+       /* Mark which tlv we used for this node */
+       if (ret) {
+               an = node->data;
+               atlv_free (an->parsed);
+               an->parsed = atlv_dup (tlv, FALSE);
        }
 
-       return FALSE;
+       return ret;
 }
 
 static gboolean
-anode_decode_anything_for_flags (GNode *node,
-                                 GBytes *bytes,
-                                 Atlv *tlv,
-                                 gint flags)
+anode_decode_one (GNode *node,
+                  Atlv *tlv)
 {
-       gboolean ret;
+       gint flags = anode_def_flags (node);
        gulong tag;
 
        tag = anode_calc_tag_for_flags (node, flags);
@@ -1169,87 +1144,130 @@ anode_decode_anything_for_flags (GNode *node,
        if (tag == G_MAXULONG)
                tag = tlv->tag;
 
-       /* Tag does not match, what do we do? */
-       if (tlv->off == 0 || tag != tlv->tag) {
-               if (anode_decode_option_or_default (node, tlv, flags))
-                       return TRUE;
+       /* We have no match */
+       if (tag != tlv->tag)
                return anode_failure (node, "decoded tag did not match expected");
-       }
 
-       /* Structured value */
-       if (tlv->cls & ASN1_CLASS_STRUCTURED)
-               ret = anode_decode_structured (node, bytes, tlv, flags);
+       return anode_decode_one_without_tag (node, tlv, flags);
+}
 
-       /* A primitive simple value */
-       else
-               ret = anode_decode_primitive (node, bytes, tlv, flags);
+static gboolean
+anode_decode_option_or_default (GNode *node)
+{
+       gint flags = anode_def_flags (node);
 
-       return ret;
+       if (flags & FLAG_OPTION || flags & FLAG_DEFAULT) {
+               anode_clr_value (node);
+               return TRUE;
+       }
+
+       return FALSE;
 }
 
 static gboolean
 anode_decode_anything (GNode *node,
-                       GBytes *bytes,
                        Atlv *tlv)
 {
-       gint flags = anode_def_flags (node);
+       GNode *next;
+       gulong tag;
+       gint flags;
 
-       if (!anode_decode_anything_for_flags (node, bytes, tlv, flags))
-               return anode_decode_option_or_default (node, tlv, flags);
+       while (tlv != NULL) {
+               flags = anode_def_flags (node);
+               tag = anode_calc_tag_for_flags (node, flags);
+
+               /* We don't know what the tag is supposed to be */
+               if (tag == G_MAXULONG)
+                       tag = tlv->tag;
+
+               /* We have no match */
+               if (tag != tlv->tag) {
+
+                       /* See if we can skip this node */
+                       if (anode_decode_option_or_default (node))
+                               next = g_node_next_sibling (node);
+                       else
+                               next = NULL;
+
+                       if (next == NULL)
+                               return anode_failure (node, "decoded tag did not match expected");
+
+                       node = next;
+                       continue;
+               }
+
+               if (!anode_decode_one_without_tag (node, tlv, flags))
+                       return FALSE;
+
+               /* Next node and tag */
+               node = g_node_next_sibling (node);
+               tlv = tlv->next;
+       }
+
+       /* We have no values for these nodes */
+       while (node != NULL) {
+               if (anode_decode_option_or_default (node))
+                       node = g_node_next_sibling (node);
+               else
+                       return anode_failure (node, "no decoded value");
+       }
 
        return TRUE;
 }
 
 gboolean
-egg_asn1x_decode_no_validate (GNode *asn,
-                              GBytes *data)
+egg_asn1x_decode_full (GNode *asn,
+                       GBytes *data,
+                       gint options)
 {
-       const guchar *dat;
-       gsize size;
-       Atlv tlv;
+       const gchar *msg;
+       gboolean ret;
+       Anode *an;
+       Atlv *tlv;
 
        g_return_val_if_fail (asn != NULL, FALSE);
        g_return_val_if_fail (data != NULL, FALSE);
 
        egg_asn1x_clear (asn);
 
-       dat = g_bytes_get_data (data, &size);
-       g_return_val_if_fail (dat != NULL, FALSE);
-
-       if (!anode_decode_tlv_for_data (dat, dat + size, &tlv))
-               return anode_failure (asn, "content is not encoded properly");
+       tlv = atlv_new ();
+       msg = atlv_parse_der (data, tlv);
+       if (msg == NULL) {
+               ret = anode_decode_anything (asn, tlv);
 
-       if (!anode_decode_anything (asn, data, &tlv))
-               return FALSE;
+       /* A failure, set the message manually so it doesn't get a prefix */
+       } else {
+               an = asn->data;
+               g_free (an->failure);
+               an->failure = g_strdup (msg);
+               ret = FALSE;
+       }
 
-       if (tlv.end - tlv.buf != size)
+       atlv_free (tlv);
+       if (ret == FALSE)
                return FALSE;
 
-       return TRUE;
+       return egg_asn1x_validate (asn, !(options & EGG_ASN1X_NO_STRICT));
 }
 
 gboolean
 egg_asn1x_decode (GNode *asn,
                   GBytes *data)
 {
-       gboolean ret;
-
        g_return_val_if_fail (asn != NULL, FALSE);
        g_return_val_if_fail (data != NULL, FALSE);
 
-       ret = egg_asn1x_decode_no_validate (asn, data);
-       if (!ret)
-               return ret;
-
-       return egg_asn1x_validate (asn, TRUE);
+       return egg_asn1x_decode_full (asn, data, 0);
 }
 
 /* -----------------------------------------------------------------------------------
- * ENCODING
+ * UNPARSE
  */
 
 static void
-anode_encode_length (gulong len, guchar *ans, gint *cb)
+atlv_unparse_len (gulong len,
+                  guchar *ans,
+                  gint *cb)
 {
        guchar temp[sizeof (gulong)];
        gint k;
@@ -1279,8 +1297,11 @@ anode_encode_length (gulong len, guchar *ans, gint *cb)
 }
 
 static gint
-anode_encode_cls_tag_len (guchar *data, gsize n_data, guchar cls,
-                          gulong tag, gint len)
+atlv_unparse_cls_tag_len (guchar *data,
+                          gsize n_data,
+                          guchar cls,
+                          gulong tag,
+                          gint len)
 {
        guchar temp[sizeof(gulong)];
        gint cb;
@@ -1313,7 +1334,7 @@ anode_encode_cls_tag_len (guchar *data, gsize n_data, guchar cls,
 
        /* And now the length */
        cb = n_data - off;
-       anode_encode_length (len, data ? data + off : NULL, &cb);
+       atlv_unparse_len (len, data ? data + off : NULL, &cb);
        off += cb;
 
        g_assert (!data || n_data >= off);
@@ -1321,422 +1342,311 @@ anode_encode_cls_tag_len (guchar *data, gsize n_data, guchar cls,
 }
 
 static void
-anode_encode_tlv_and_enc (GNode *node,
-                          gsize n_data,
-                          Aencoder encoder,
-                          gpointer user_data,
-                          GDestroyNotify destroy)
+atlv_unparse_der (Atlv *tlv,
+                  guchar **at,
+                  guchar *end)
 {
-       gboolean explicit = FALSE;
-       guchar cls_type;
-       gulong tag;
-       gint flags;
-       Atlv tlv;
-
-       g_assert (node);
-       g_assert (encoder);
-
-       /* The data length */
-       memset (&tlv, 0, sizeof (tlv));
-       tlv.len = n_data;
-
-       /* Figure out the basis if the class */
-       switch (anode_def_type (node)) {
-       case EGG_ASN1X_INTEGER:
-       case EGG_ASN1X_BOOLEAN:
-       case EGG_ASN1X_BIT_STRING:
-       case EGG_ASN1X_OCTET_STRING:
-       case EGG_ASN1X_OBJECT_ID:
-       case EGG_ASN1X_TIME:
-       case EGG_ASN1X_ENUMERATED:
-       case EGG_ASN1X_GENERALSTRING:
-       case EGG_ASN1X_NULL:
-               tlv.cls = ASN1_CLASS_UNIVERSAL;
-               break;
-       /* Container types */
-       case EGG_ASN1X_SEQUENCE:
-       case EGG_ASN1X_SET:
-       case EGG_ASN1X_SEQUENCE_OF:
-       case EGG_ASN1X_SET_OF:
-               tlv.cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_UNIVERSAL);
-               break;
+       const guchar *exp;
+       const guchar *buf;
+       guchar *p;
+       guchar mask;
+       Atlv *ctlv;
+       gint off;
+       gsize len;
 
-       /* Transparent types shouldn't get here */
-       case EGG_ASN1X_ANY:
-       case EGG_ASN1X_CHOICE:
-               g_return_if_reached ();
+       g_assert (*at <= end);
 
-       default:
-               g_return_if_reached ();
-       };
+       off = atlv_unparse_cls_tag_len (*at, end - *at, tlv->cls,
+                                       tlv->tag, tlv->len);
+       g_assert (off == tlv->off);
+       (*at) += off;
+
+       /* Write a value */
+       if (tlv->value) {
+               buf = g_bytes_get_data (tlv->value, &len);
+               p = *at;
+
+               /* Special behavior for bit strings */
+               if (tlv->prefix_for_bit_string) {
+                       g_assert (len + 1 == tlv->len);
+                       p[0] = (guchar)tlv->bits_empty;
+                       memcpy (p + 1, buf, len);
+
+                       /* Set the extra bits to zero */
+                       if (len && tlv->bits_empty) {
+                               mask = 0xFF >> (8 - tlv->bits_empty);
+                               p[len] &= ~mask;
+                       }
+                       p += len + 1;
 
-       /* Build up the class */
-       flags = anode_def_flags (node);
-       if (flags & FLAG_TAG) {
-               explicit = anode_calc_explicit_for_flags (node, flags, &cls_type);
-               if (explicit)
-                       flags &= ~FLAG_TAG;
-               else
-                       tlv.cls |= cls_type;
-       }
+               /* Special behavior for prefixed integers */
+               } else if (tlv->prefix_with_zero_byte) {
+                       g_assert (len + 1 == tlv->len);
+                       p[0] = 0;
+                       memcpy (p + 1, buf, len);
+                       p += len + 1;
 
-       /* And now the tag */
-       tlv.tag = anode_calc_tag_for_flags (node, flags);
+               /* Standard behavior */
+               } else {
+                       g_assert (len == tlv->len);
+                       memcpy (p, buf, len);
+                       p += len;
+               }
 
-       /* Calculate the length for the main thingy */
-       tlv.off = anode_encode_cls_tag_len (NULL, 0, tlv.cls, tlv.tag, tlv.len);
+               *at = p;
 
-       /* Wrap that in another explicit tag if necessary */
-       if (explicit) {
-               tag = anode_calc_tag (node);
-               g_return_if_fail (tag != G_MAXULONG);
-               tlv.oft = anode_encode_cls_tag_len (NULL, 0, 0, tag, tlv.off + tlv.len);
-               tlv.off += tlv.oft;
+       /* Write a bunch of child TLV's */
+       } else {
+               for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next) {
+                       exp = *at + ctlv->len + ctlv->off;
+                       atlv_unparse_der (ctlv, at, end);
+                       g_assert (exp == *at);
+               }
        }
 
-       /* Not completely filled in */
-       tlv.buf = tlv.end = NULL;
-
-       anode_clear (node);
-       anode_set_tlv_data (node, NULL, &tlv);
-       anode_set_enc_data (node, encoder, user_data, destroy);
+       g_assert (*at <= end);
 }
 
-static gboolean
-anode_encode_build (GNode *node,
-                    GBytes *backing,
-                    guchar *data,
-                    gsize n_data)
+static GBytes *
+atlv_unparse_to_bytes (Atlv *tlv,
+                       EggAllocator allocator)
 {
-       guchar cls_type;
-       gint type;
-       guchar cls;
-       gulong tag;
-       Aenc *enc;
-       Atlv *tlv;
-       gint off = 0;
-
-       type = anode_def_type (node);
-       tlv = anode_get_tlv_data (node);
-       g_return_val_if_fail (tlv, FALSE);
-
-       /* Should have an encoder */
-       enc = anode_get_enc_data (node);
-       g_return_val_if_fail (enc, FALSE);
-
-       /* If it's a choice node, use the choice for calculations */
-       if (type == EGG_ASN1X_CHOICE) {
-               node = egg_asn1x_get_choice (node);
-               g_return_val_if_fail (node, FALSE);
-       }
-
-       /* Encode any explicit tag */
-       if (anode_calc_explicit (node, &cls_type)) {
-               tag = anode_calc_tag (node);
-               g_return_val_if_fail (tag != G_MAXULONG, FALSE);
-               cls = (ASN1_CLASS_STRUCTURED | cls_type);
-               g_assert (tlv->oft > 0 && tlv->oft < tlv->off);
-               off = anode_encode_cls_tag_len (data, n_data, cls, tag, (tlv->off - tlv->oft) + tlv->len);
-               g_assert (off == tlv->oft);
-       }
+       GBytes *bytes;
+       guchar *data;
+       guchar *at;
+       gint len;
 
-       /* Now encode the main tag */
-       off += anode_encode_cls_tag_len (data + off, n_data - off, tlv->cls, tlv->tag, tlv->len);
-       g_assert (off == tlv->off);
+       /* Allocate enough memory for entire thingy */
+       len = tlv->off + tlv->len;
+       g_return_val_if_fail (len != 0, NULL);
 
-       /* Setup the remainder of the tlv */
-       g_assert (tlv->len + tlv->off == n_data);
-       tlv->buf = data;
-       tlv->end = data + n_data;
-       anode_set_backing (node, backing);
+       bytes = bytes_new_with_allocator (allocator, &data, len);
+       if (data == NULL)
+               return NULL;
 
-       /* Encode in the data */
-       if (!(enc->encoder) (enc->data, node, data + tlv->off, tlv->len))
-               return FALSE;
+       at = data;
+       atlv_unparse_der (tlv, &at, data + len);
+       g_assert (at == data + len);
 
-       return TRUE;
+       return bytes;
 }
 
-static void
-anode_encode_rollback (GNode *node)
-{
-       GNode *child;
-       Aenc *enc;
+typedef struct {
+       GBytes *bytes;
        Atlv *tlv;
-
-       /* Undo any references to our new buffer */
-       enc = anode_get_enc_data (node);
-       if (enc) {
-               tlv = anode_get_tlv_data (node);
-               g_return_if_fail (tlv);
-               tlv->buf = tlv->end = NULL;
-       }
-
-       for (child = node->children; child; child = child->next)
-               anode_encode_rollback (child);
-}
-
-static void
-anode_encode_commit (GNode *node)
-{
-       GNode *child;
-
-       /* Remove and free all the encoder stuff */
-       anode_clr_enc_data (node);
-
-       for (child = node->children; child; child = child->next)
-               anode_encode_commit (child);
-}
+} SortPair;
 
 static gint
-compare_bufs (gconstpointer a, gconstpointer b)
+compare_sort_pair (gconstpointer a,
+                   gconstpointer b)
 {
-       const Abuf *ba = a;
-       const Abuf *bb = b;
-       gint res = memcmp (ba->data, bb->data, MIN (ba->n_data, bb->n_data));
-       if (ba->n_data == bb->n_data || res != 0)
-               return res;
-       return ba->n_data < bb->n_data ? -1 : 1;
+       const SortPair *sa = a;
+       const SortPair *sb = b;
+       return g_bytes_compare (sa->bytes, sb->bytes);
 }
 
-static gboolean
-traverse_and_sort_set_of (GNode *node, gpointer user_data)
+static void
+atlv_sort_perform (Atlv *tlv,
+                   EggAllocator allocator)
 {
-       EggAllocator allocator = user_data;
-       GList *bufs, *l;
-       Abuf *buf;
-       guchar *data;
-       gsize n_data;
-       Atlv *tlv;
-       GNode *child;
-       GNode *next;
-
-       if (!allocator)
-               allocator = g_realloc;
-
-       /* We have to sort any SET OF :( */
-       if (anode_def_type (node) != EGG_ASN1X_SET_OF)
-               return FALSE;
+       GList *pairs, *l;
+       SortPair *pair;
+       GBytes *bytes;
+       Atlv *ctlv;
+       Atlv *last;
+       gboolean sort;
 
-       bufs = NULL;
-       for (child = node->children; child; child = next) {
-               next = child->next;
+       for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next)
+               atlv_sort_perform (ctlv, allocator);
 
-               tlv = anode_get_tlv_data (child);
-               if (!tlv)
-                       continue;
+       if (!tlv->sorted)
+               return;
 
-               /* Allocate enough memory */
-               n_data = tlv->len + tlv->off;
-               data = (allocator) (NULL, n_data + 1);
-               if (!data)
+       pairs = NULL;
+       for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next) {
+               bytes = atlv_unparse_to_bytes (ctlv, allocator);
+               if (bytes == NULL)
                        break;
 
-               if (!anode_encode_build (child, NULL, data, n_data)) {
-                       (allocator) (data, 0);
-                       continue;
-               }
-
-               buf = g_slice_new0 (Abuf);
-               buf->user_data = child;
-               buf->n_data = n_data;
-               buf->data = data;
-               bufs = g_list_prepend (bufs, buf);
-               g_node_unlink (child);
+               pair = g_slice_new0 (SortPair);
+               pair->bytes = bytes;
+               pair->tlv = ctlv;
+               pairs = g_list_prepend (pairs, pair);
        }
 
-       bufs = g_list_sort (bufs, compare_bufs);
+       /* Only sort of the above unparse completed for all */
+       sort = ctlv == NULL;
+       last = NULL;
+
+       pairs = g_list_sort (pairs, compare_sort_pair);
+       for (l = pairs; l != NULL; l = g_list_next (l)) {
+               pair = l->data;
+
+               /* Only if the sort completed */
+               if (sort) {
+                       if (last == NULL)
+                               tlv->child = pair->tlv;
+                       else
+                               last->next = pair->tlv;
+                       last = pair->tlv;
+               }
 
-       for (l = bufs; l; l = g_list_next (l)) {
-               buf = l->data;
-               g_node_append (node, buf->user_data);
-               (allocator) (buf->data, 0);
-               g_slice_free (Abuf, buf);
-       }
+               g_bytes_unref (pair->bytes);
+               g_slice_free (SortPair, pair);
+       }
 
-       anode_encode_rollback (node);
-       g_list_free (bufs);
-       return FALSE;
+       g_list_free (pairs);
 }
 
-static gboolean
-anode_encoder_bytes (gpointer user_data,
-                     GNode *node,
-                     guchar *data,
-                     gsize n_data)
+static void
+anode_build_cls_tag_len (GNode *node,
+                         Atlv *tlv,
+                         gint len)
 {
-       GBytes *bytes = user_data;
-       g_assert (g_bytes_get_size (bytes) >= n_data);
-       memcpy (data, g_bytes_get_data (bytes, NULL), n_data);
-       return TRUE;
-}
+       gboolean explicit = FALSE;
+       guchar cls_type;
+       gint flags;
 
-static gboolean
-anode_encoder_data (gpointer user_data,
-                    GNode *node,
-                    guchar *data,
-                    gsize n_data)
-{
-       memcpy (data, user_data, n_data);
-       return TRUE;
-}
+       /* One for the prefix character */
+       if (tlv->prefix_for_bit_string ||
+           tlv->prefix_with_zero_byte)
+               len += 1;
 
-static gboolean
-anode_encoder_unsigned (gpointer user_data,
-                        GNode *node,
-                        guchar *data,
-                        gsize n_data)
-{
-       GBytes *value = user_data;
-       gboolean sign;
-       const gchar *p;
+       /* Figure out the basis if the class */
+       switch (anode_def_type (node)) {
+       case EGG_ASN1X_INTEGER:
+       case EGG_ASN1X_BOOLEAN:
+       case EGG_ASN1X_BIT_STRING:
+       case EGG_ASN1X_OCTET_STRING:
+       case EGG_ASN1X_OBJECT_ID:
+       case EGG_ASN1X_TIME:
+       case EGG_ASN1X_ENUMERATED:
+       case EGG_ASN1X_GENERALSTRING:
+       case EGG_ASN1X_NULL:
+               tlv->cls = ASN1_CLASS_UNIVERSAL;
+               break;
+       /* Container types */
+       case EGG_ASN1X_SEQUENCE:
+       case EGG_ASN1X_SET:
+       case EGG_ASN1X_SEQUENCE_OF:
+       case EGG_ASN1X_SET_OF:
+               tlv->cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_UNIVERSAL);
+               break;
 
-       /*
-        * If top bit is set, the result would be negative in two's complement
-        * but since we want an unsigned integer, add a zero byte. That zero
-        * byte is already calculated into n_data, see egg_asn1x_set_integer_as_usg
-        */
+       /* Transparent types shouldn't get here */
+       case EGG_ASN1X_ANY:
+       case EGG_ASN1X_CHOICE:
+       default:
+               g_assert_not_reached ();
+       };
 
-       p = g_bytes_get_data (value, NULL);
-       g_return_val_if_fail (p != NULL, FALSE);
+       flags = anode_def_flags (node);
 
-       sign = !!(p[0] & 0x80);
-       if (sign) {
-               g_assert (n_data > 1);
-               data[0] = 0;
-               data++;
-               n_data--;
+       /* Build up the class */
+       if (flags & FLAG_TAG) {
+               explicit = anode_calc_explicit_for_flags (node, flags, &cls_type);
+               if (explicit)
+                       flags &= ~FLAG_TAG;
+               else
+                       tlv->cls |= cls_type;
        }
 
-       memcpy (data, p, n_data);
-       return TRUE;
+       /* Setup the class */
+       tlv->tag = anode_calc_tag_for_flags (node, flags);
+
+       /* The offset and length */
+       tlv->len = len;
+       tlv->off = atlv_unparse_cls_tag_len (NULL, 0, tlv->cls, tlv->tag, len);
 }
 
-static gboolean
-anode_encoder_structured (gpointer user_data,
-                          GNode *unused,
-                          guchar *data,
-                          gsize n_data)
+static Atlv *
+anode_build_value (GNode *node)
 {
-       GNode *node = user_data;
-       GNode *child;
-       gsize length;
+       Anode *an = node->data;
        Atlv *tlv;
+       gsize len;
 
-       for (child = node->children; child; child = child->next) {
-               tlv = anode_get_tlv_data (child);
-               if (tlv) {
-                       length = tlv->off + tlv->len;
-                       g_assert (length <= n_data);
-                       if (!anode_encode_build (child, anode_get_backing (node),
-                                                data, length))
-                               return FALSE;
-                       data += length;
-                       n_data -= length;
-               }
-       }
+       /* Fill this in based on the value */
+       if (an->value == NULL)
+               return NULL;
 
-       return TRUE;
+       tlv = atlv_new ();
+       tlv->value = g_bytes_ref (an->value);
+
+       len = g_bytes_get_size (an->value);
+       anode_build_cls_tag_len (node, tlv, len);
+       return tlv;
 }
 
-static gboolean
-anode_encoder_choice (gpointer user_data,
-                      GNode *unused,
-                      guchar *data,
-                      gsize n_data)
+static Atlv *
+anode_build_bit_string (GNode *node)
 {
-       GNode *node = user_data;
-       Aenc *enc = NULL;
-       GNode *child;
-       Atlv *tlv, *ctlv;
-
-       tlv = anode_get_tlv_data (node);
-       g_return_val_if_fail (tlv, FALSE);
-
-       child = egg_asn1x_get_choice (node);
-       g_return_val_if_fail (child, FALSE);
-
-       ctlv = anode_get_tlv_data (child);
-       g_assert (ctlv);
+       Anode *an = node->data;
+       Atlv *tlv;
+       gsize len;
 
-       enc = anode_get_enc_data (child);
-       g_return_val_if_fail (enc, FALSE);
-       if (!(enc->encoder) (enc->data, child, data, n_data))
-               return FALSE;
+       if (an->value == NULL)
+               return NULL;
 
-       /* Child's buffer matches ours */
-       ctlv->buf = tlv->buf;
-       ctlv->end = tlv->end;
+       tlv = atlv_new ();
+       tlv->value = g_bytes_ref (an->value);
+       tlv->bits_empty = an->bits_empty;
+       tlv->prefix_for_bit_string = 1;
 
-       return TRUE;
+       len = g_bytes_get_size (an->value);
+       anode_build_cls_tag_len (node, tlv, len);
+       return tlv;
 }
 
-static gboolean
-anode_encoder_bit_string (gpointer user_data,
-                          GNode *node,
-                          guchar *data,
-                          gsize n_data)
+static Atlv *
+anode_build_integer (GNode *node)
 {
-       Abits *ab = user_data;
-       guchar empty, mask;
+       Anode *an = node->data;
+       const guchar *buf;
+       gboolean sign;
        gsize len;
+       Atlv *tlv;
 
-       empty = ab->n_bits % 8;
-       if (empty > 0)
-               empty = 8 - empty;
-       len = (ab->n_bits / 8) + (empty ? 1 : 0);
-       g_assert (n_data == len + 1);
+       if (an->value == NULL)
+               return NULL;
 
-       /* Fill in the amount of empty */
-       data[0] = empty;
-       data += 1;
+       tlv = atlv_new ();
+       tlv->value = g_bytes_ref (an->value);
 
-       /* Fill in the actual data */
-       memcpy (data, g_bytes_get_data (ab->bits, NULL), len);
+       buf = g_bytes_get_data (an->value, &len);
+       if (an->guarantee_unsigned) {
 
-       /* Set the extra bits to zero */
-       if (len && empty) {
-               mask = 0xFF >> (8 - empty);
-               data[len - 1] &= ~mask;
+               /*
+                * In two's complement (which DER is) this would be negative, add a zero
+                * byte so that it isn't. Here we just note that the result will be one
+                * byte longer.
+                */
+               sign = !!(buf[0] & 0x80);
+               if (sign)
+                       tlv->prefix_with_zero_byte = 1;
        }
 
-       return TRUE;
+       anode_build_cls_tag_len (node, tlv, len);
+       return tlv;
 }
 
-static gboolean
-anode_encode_prepare_simple (GNode *node, gboolean want)
+static Atlv *
+anode_build_any (GNode *node)
 {
-       GBytes *backing;
-       GBytes *bytes;
-       Aenc *enc;
-       Atlv *tlv;
+       Atlv *parsed;
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL)
-               return FALSE;
-
-       /* Transfer the tlv data over to enc */
-       enc = anode_get_enc_data (node);
-       if (enc == NULL) {
-               backing = anode_get_backing (node);
-               if (backing == NULL)
-                       return FALSE;
+       /* Fill this in based on already parsed TLVs */
+       parsed = anode_get_parsed (node);
+       if (parsed != NULL)
+               return atlv_dup (parsed, FALSE);
 
-               bytes = g_bytes_new_with_free_func ((guchar *)tlv->buf + tlv->off, tlv->len,
-                                                   (GDestroyNotify)g_bytes_unref,
-                                                   g_bytes_ref (backing));
-               anode_set_enc_data (node, anode_encoder_bytes, bytes,
-                                   (GDestroyNotify)g_bytes_unref);
-       }
-
-       tlv->buf = tlv->end = NULL;
-       return TRUE;
+       return NULL;
 }
 
-static gboolean
-anode_encode_prepare_choice (GNode *node, gboolean want)
+static Atlv *
+anode_build_choice (GNode *node,
+                    gboolean want)
 {
-       Atlv *tlv;
        GNode *child;
 
        g_assert (anode_def_type (node) == EGG_ASN1X_CHOICE);
@@ -1745,127 +1655,143 @@ anode_encode_prepare_choice (GNode *node, gboolean want)
        if (!child)
                return FALSE;
 
-       if (!anode_encode_prepare (child, want))
-               return FALSE;
-
-       tlv = anode_get_tlv_data (child);
-       g_return_val_if_fail (tlv, FALSE);
-       anode_clr_tlv_data (node);
-       anode_set_tlv_data (node, NULL, tlv);
-       anode_set_enc_data (node, anode_encoder_choice, node, NULL);
-
-       return TRUE;
-
+       return anode_build_anything (child, want);
 }
 
-static gboolean
-anode_encode_prepare_structured (GNode *node, gboolean want)
+static Atlv *
+anode_build_structured (GNode *node,
+                        gboolean want)
 {
        gboolean child_want;
-       gsize length;
-       gboolean had;
+       Atlv *last;
+       Atlv *ctlv;
        Atlv *tlv;
        GNode *child;
        gint type;
+       gint len;
 
        type = anode_def_type (node);
        child_want = want;
-       had = FALSE;
-       length = 0;
+       last = NULL;
+       len = 0;
 
        if (type == EGG_ASN1X_SEQUENCE_OF || type == EGG_ASN1X_SET_OF)
                child_want = FALSE;
        if (anode_def_flags (node) & FLAG_OPTION)
                want = FALSE;
 
-       for (child = node->children; child; child = child->next) {
-               if (anode_encode_prepare (child, child_want)) {
-                       tlv = anode_get_tlv_data (child);
-                       g_return_val_if_fail (tlv, FALSE);
-                       length += tlv->off + tlv->len;
-                       had = TRUE;
+       tlv = atlv_new ();
+       for (child = node->children; child != NULL; child = child->next) {
+               ctlv = anode_build_anything (child, child_want);
+               if (ctlv != NULL) {
+                       if (last == NULL)
+                               tlv->child = ctlv;
+                       else
+                               last->next = ctlv;
+                       last = ctlv;
+                       len += ctlv->off + ctlv->len;
                }
        }
 
-       if (had == FALSE) {
+       if (last == NULL) {
                /* See if we should encode an empty set or seq of */
                if (type == EGG_ASN1X_SEQUENCE_OF || type == EGG_ASN1X_SET_OF) {
-                       if (!want)
-                               return FALSE;
+                       if (!want) {
+                               atlv_free (tlv);
+                               return NULL;
+                       }
                } else {
-                       return FALSE;
+                       atlv_free (tlv);
+                       return NULL;
                }
        }
 
-       anode_encode_tlv_and_enc (node, length, anode_encoder_structured, node, NULL);
-       return TRUE;
+       anode_build_cls_tag_len (node, tlv, len);
+
+       if (type == EGG_ASN1X_SET_OF)
+               tlv->sorted = 1;
+
+       return tlv;
 }
 
-static gboolean
-anode_encode_prepare (GNode *node, gboolean want)
+static Atlv *
+anode_build_maybe_explicit (GNode *node,
+                            Atlv *tlv,
+                            gint flags)
 {
+       guchar cls_type;
+       Atlv *wrap;
+
+       /* Now wrap in explicit tag if that's the case */
+       if (anode_calc_explicit_for_flags (node, flags, &cls_type)) {
+               wrap = atlv_new ();
+               wrap->cls = (ASN1_CLASS_STRUCTURED | cls_type);
+               wrap->tag = anode_calc_tag (node);
+               wrap->len = tlv->off + tlv->len;
+               wrap->off = atlv_unparse_cls_tag_len (NULL, 0, wrap->cls, wrap->tag, wrap->len);
+               wrap->child = tlv;
+               tlv = wrap;
+       }
+
+       return tlv;
+}
+
+static Atlv *
+anode_build_anything_for_flags (GNode *node,
+                                gboolean want,
+                                gint flags)
+{
+       Atlv *tlv;
+
        switch (anode_def_type (node)) {
+       case EGG_ASN1X_BIT_STRING:
+               tlv = anode_build_bit_string (node);
+               break;
        case EGG_ASN1X_INTEGER:
+               tlv = anode_build_integer (node);
+               break;
        case EGG_ASN1X_BOOLEAN:
-       case EGG_ASN1X_BIT_STRING:
        case EGG_ASN1X_OCTET_STRING:
        case EGG_ASN1X_OBJECT_ID:
        case EGG_ASN1X_TIME:
        case EGG_ASN1X_ENUMERATED:
        case EGG_ASN1X_GENERALSTRING:
-       case EGG_ASN1X_ANY:
        case EGG_ASN1X_NULL:
-               return anode_encode_prepare_simple (node, want);
+               tlv = anode_build_value (node);
                break;
+
+       /* Any should already have explicit tagging */
+       case EGG_ASN1X_ANY:
+               return anode_build_any (node);
+
        case EGG_ASN1X_SEQUENCE:
        case EGG_ASN1X_SEQUENCE_OF:
        case EGG_ASN1X_SET:
        case EGG_ASN1X_SET_OF:
-               return anode_encode_prepare_structured (node, want);
+               tlv = anode_build_structured (node, want);
                break;
+
        case EGG_ASN1X_CHOICE:
-               return anode_encode_prepare_choice (node, want);
+               tlv = anode_build_choice (node, want);
                break;
+
        default:
-               g_return_val_if_reached (FALSE);
-       };
-}
+               g_assert_not_reached ();
+       }
 
-typedef struct {
-       EggAllocator allocator;
-       gpointer allocated;
-} AllocatorClosure;
+       if (tlv == NULL)
+               return NULL;
 
-static void
-destroy_with_allocator (gpointer data)
-{
-       AllocatorClosure *closure = data;
-       g_assert (closure->allocator);
-       (closure->allocator) (closure->allocated, 0);
-       g_slice_free (AllocatorClosure, closure);
+       /* Now wrap in explicit tag if that's the case */
+       return anode_build_maybe_explicit (node, tlv, flags);
 }
 
-static GBytes *
-new_bytes_with_allocator (EggAllocator allocator,
-                          guchar **data,
-                          gsize length)
+static Atlv *
+anode_build_anything (GNode *node,
+                      gboolean want)
 {
-       AllocatorClosure *closure;
-
-       if (allocator) {
-               *data = (allocator) (NULL, length + 1);
-               if (allocator == NULL)
-                       return NULL;
-               closure = g_slice_new (AllocatorClosure);
-               closure->allocated = *data;
-               closure->allocator = allocator;
-               return g_bytes_new_with_free_func (*data, length,
-                                                    destroy_with_allocator,
-                                                    closure);
-       } else {
-               *data = g_malloc (length);
-               return g_bytes_new_take (*data, length);
-       }
+       return anode_build_anything_for_flags (node, want,
+                                              anode_def_flags (node));
 }
 
 GBytes *
@@ -1873,44 +1799,29 @@ egg_asn1x_encode (GNode *asn,
                   EggAllocator allocator)
 {
        GBytes *bytes;
-       guchar *data;
-       gsize length;
        Atlv *tlv;
 
        g_return_val_if_fail (asn != NULL, NULL);
        g_return_val_if_fail (anode_def_type_is_real (asn), NULL);
 
-       if (!anode_encode_prepare (asn, TRUE)) {
-               anode_failure (asn, "missing value(s)");
+       if (!egg_asn1x_validate (asn, TRUE))
                return NULL;
-       }
-
-       /* We must sort all the nasty SET OF nodes */
-       g_node_traverse (asn, G_POST_ORDER, G_TRAVERSE_ALL, -1,
-                        traverse_and_sort_set_of, allocator);
 
-       tlv = anode_get_tlv_data (asn);
-       g_return_val_if_fail (tlv, NULL);
-
-       /* Allocate enough memory for entire thingy */
-       length = tlv->off + tlv->len;
-       bytes = new_bytes_with_allocator (allocator, &data, length);
-       if (data == NULL)
+       tlv = anode_build_anything (asn, TRUE);
+       if (tlv == NULL) {
+               anode_failure (asn, "missing value(s)");
                return NULL;
-
-       if (anode_encode_build (asn, bytes, data, length) &&
-           anode_validate_anything (asn, TRUE)) {
-               anode_encode_commit (asn);
-               return bytes;
        }
 
-       g_bytes_unref (bytes);
-       anode_encode_rollback (asn);
-       return NULL;
+       atlv_sort_perform (tlv, allocator);
+
+       bytes = atlv_unparse_to_bytes (tlv, allocator);
+       atlv_free (tlv);
+       return bytes;
 }
 
-/* -----------------------------------------------------------------------------------
- * READING, WRITING, GETTING, SETTING
+/* ----------------------------------------------------------------------------
+ * VALUE READ/WRITE
  */
 
 static int
@@ -2167,23 +2078,28 @@ parse_general_time (const gchar *time, gsize n_time,
 }
 
 static gboolean
-anode_read_time (GNode *node, Atlv *tlv, struct tm *when, glong *value)
+anode_read_time (GNode *node,
+                 GBytes *data,
+                 struct tm *when,
+                 glong *value)
 {
-       const gchar *data;
+       const gchar *buf;
        gboolean ret;
        gint offset = 0;
        gint flags;
+       gsize len;
 
-       g_assert (when);
-       g_assert (value);
+       g_assert (data != NULL);
+       g_assert (when != NULL);
+       g_assert (value != NULL);
 
        flags = anode_def_flags (node);
-       data = (gchar*)(tlv->buf + tlv->off);
+       buf = g_bytes_get_data (data, &len);
 
        if (flags & FLAG_GENERALIZED)
-               ret = parse_general_time (data, tlv->len, when, &offset);
+               ret = parse_general_time (buf, len, when, &offset);
        else if (flags & FLAG_UTC)
-               ret = parse_utc_time (data, tlv->len, when, &offset);
+               ret = parse_utc_time (buf, len, when, &offset);
        else
                g_return_val_if_reached (FALSE);
 
@@ -2205,24 +2121,29 @@ anode_read_time (GNode *node, Atlv *tlv, struct tm *when, glong *value)
 }
 
 static gboolean
-anode_read_integer_as_ulong (GNode *node, Atlv *tlv, gulong *value)
+anode_read_integer_ulong (GNode *node,
+                          GBytes *data,
+                          gulong *value)
 {
        const guchar *p;
+       gsize len;
        gsize k;
 
-       if (tlv->len < 1 || tlv->len > sizeof (gulong))
+       p = g_bytes_get_data (data, &len);
+       if (len < 1 || len > sizeof (gulong))
                return FALSE;
 
-       p = tlv->buf + tlv->off;
        *value = 0;
-       for (k = 0; k < tlv->len; ++k)
-               *value |= p[k] << (8 * ((tlv->len - 1) - k));
+       for (k = 0; k < len; ++k)
+               *value |= p[k] << (8 * ((len - 1) - k));
 
        return TRUE;
 }
 
-static gboolean
-anode_write_integer_ulong (gulong value, guchar *data, gsize *n_data)
+static void
+anode_write_integer_ulong (gulong value,
+                           guchar *data,
+                           gsize *n_data)
 {
        guchar buf[sizeof (gulong)];
        gint bytes, i, off;
@@ -2234,99 +2155,158 @@ anode_write_integer_ulong (gulong value, guchar *data, gsize *n_data)
                buf[i] = (value >> (off * 8)) & 0xFF;
        }
 
-       for (bytes = sizeof (gulong) - 1; bytes >= 0; --bytes)
-               if (!buf[bytes])
-                       break;
+       for (bytes = sizeof (gulong) - 1; bytes >= 0; --bytes)
+               if (!buf[bytes])
+                       break;
+
+       bytes = sizeof (gulong) - (bytes + 1);
+       if (bytes == 0)
+               bytes = 1;
+
+       /* If the first byte would make this negative, then add a zero */
+       at = buf + (sizeof (gulong) - bytes);
+       sign = !!(at[0] & 0x80);
+
+       if (data) {
+               g_assert (*n_data >= bytes + 1);
+               if (sign) {
+                       data[0] = 0;
+                       data++;
+               }
+               memcpy (data, at, bytes);
+       }
+
+       *n_data = bytes + (sign ? 1 : 0);
+}
+
+static GBytes *
+anode_default_integer (GNode *node)
+{
+       const gchar *defval;
+       EggAsn1xDef *opt;
+       gchar *end;
+       gulong value;
+       guchar *data;
+       gsize len;
+
+       if (!(anode_def_flags (node) & FLAG_DEFAULT))
+               return NULL;
+
+       /* Try to get a default */
+       opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
+       g_return_val_if_fail (opt != NULL, NULL);
+       g_return_val_if_fail (opt->value != NULL, NULL);
+       defval = opt->value;
+
+       opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, defval);
+       if (opt != NULL) {
+               g_return_val_if_fail (opt->value != NULL, NULL);
+               defval = opt->value;
+       }
+
+       /* Parse out the default value */
+       value = strtoul (defval, &end, 10);
+       g_return_val_if_fail (end && !end[0], NULL);
 
-       bytes = sizeof (gulong) - (bytes + 1);
-       if (bytes == 0)
-               bytes = 1;
+       anode_write_integer_ulong (value, NULL, &len);
+       data = g_malloc (len);
+       anode_write_integer_ulong (value, data, &len);
+       return g_bytes_new_take (data, len);
+}
 
-       /* If the first byte would make this negative, then add a zero */
-       at = buf + (sizeof (gulong) - bytes);
-       sign = !!(at[0] & 0x80);
+static gboolean
+anode_read_string_struct (GNode *node,
+                          Atlv *tlv,
+                          gpointer value,
+                          gsize *n_value)
+{
+       const guchar *buf;
+       gsize len;
+       Atlv *ctlv;
+       guchar *at;
+       gint remaining;
 
-       if (data) {
-               g_assert (*n_data >= bytes + 1);
-               if (sign) {
-                       data[0] = 0;
-                       data++;
+       g_assert (tlv != NULL);
+       g_assert (tlv->cls & ASN1_CLASS_STRUCTURED);
+       g_assert (n_value != NULL);
+
+       at = value;
+       remaining = *n_value;
+       *n_value = 0;
+
+       for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next) {
+               if (ctlv->cls & ASN1_CLASS_STRUCTURED ||
+                   ctlv->value == NULL)
+                       return FALSE;
+               buf = g_bytes_get_data (ctlv->value, &len);
+               *n_value += len;
+               if (value) {
+                       if (remaining >= len)
+                               memcpy (at, buf, len);
+                       at += len;
+                       remaining -= len;
                }
-               memcpy (data, at, bytes);
        }
 
-       *n_data = bytes + (sign ? 1 : 0);
+       if (value && remaining < 0)
+               return FALSE;
+
        return TRUE;
 }
 
 static gboolean
-anode_read_string (GNode *node, Atlv *tlv, gpointer value, gsize *n_value)
+anode_read_string_simple (GNode *node,
+                          GBytes *data,
+                          gpointer value,
+                          gsize *n_value)
 {
-       Atlv ctlv;
-       guchar *buf;
-       gint n_buf;
-       gint i;
-
-       g_assert (tlv);
-       g_assert (n_value);
+       const guchar *buf;
+       gsize len;
 
-       buf = value;
-       n_buf = *n_value;
+       g_assert (data != NULL);
+       g_assert (n_value != NULL);
 
-       /* Is it constructed ? */
-       if (tlv->cls & ASN1_CLASS_STRUCTURED) {
-               *n_value = 0;
-               for (i = 0; TRUE; ++i) {
-                       if (!anode_decode_tlv_for_contents (tlv, i == 0, &ctlv))
-                               return anode_failure (node, "invalid encoding of child");
-                       if (ctlv.off == 0)
-                               break;
-                       if (ctlv.cls & ASN1_CLASS_STRUCTURED)
-                               return FALSE;
-                       *n_value += ctlv.len;
-                       if (buf) {
-                               if (n_buf >= ctlv.len)
-                                       memcpy (buf, ctlv.buf + ctlv.off, ctlv.len);
-                               buf += ctlv.len;
-                               n_buf -= ctlv.len;
-                       }
-               }
-               if (n_buf < 0)
+       buf = g_bytes_get_data (data, &len);
+       if (value) {
+               if (*n_value < len) {
+                       *n_value = len;
                        return FALSE;
-
-       /* Primitive, just return the contents */
-       } else {
-               *n_value = tlv->len;
-               if (buf) {
-                       if (n_buf < tlv->len)
-                               return FALSE;
-                       memcpy (buf, tlv->buf + tlv->off, tlv->len);
                }
+               memcpy (value, buf, len);
        }
 
+       *n_value = len;
        return TRUE;
 }
 
 static gboolean
-anode_read_boolean (GNode *node, Atlv *tlv, gboolean *value)
+anode_read_boolean (GNode *node,
+                    GBytes *data,
+                    gboolean *value)
 {
-       g_assert (node);
-       g_assert (tlv);
-       g_assert (value);
+       const guchar *buf;
+       gsize len;
+
+       g_assert (node != NULL);
+       g_assert (data != NULL);
+       g_assert (value != NULL);
 
-       if (tlv->len != 1)
+       buf = g_bytes_get_data (data, &len);
+       if (len != 1)
                return FALSE;
-       if (tlv->buf[tlv->off] == 0x00)
+       if (buf[0] == 0x00)
                *value = FALSE;
-       else if (tlv->buf[tlv->off] == 0xFF)
+       else if (buf[0] == 0xFF)
                *value = TRUE;
        else
                return FALSE;
        return TRUE;
 }
 
-static gboolean
-anode_write_boolean (gboolean value, guchar *data, gsize *n_data)
+static void
+anode_write_boolean (gboolean value,
+                     guchar *data,
+                     gsize *n_data)
 {
        if (data) {
                g_assert (*n_data >= 1);
@@ -2336,22 +2316,51 @@ anode_write_boolean (gboolean value, guchar *data, gsize *n_data)
                        data[0] = 0x00;
        }
        *n_data = 1;
-       return TRUE;
+}
+
+static GBytes *
+anode_default_boolean (GNode *node)
+{
+       EggAsn1xDef *opt;
+       gboolean value;
+       guchar *data;
+       gsize len;
+
+       if (!(anode_def_flags (node) & FLAG_DEFAULT))
+               return NULL;
+
+       /* Try to get a default */
+       opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
+       g_return_val_if_fail (opt != NULL, NULL);
+
+       /* Parse out the default value */
+       if ((opt->type & FLAG_TRUE) == FLAG_TRUE)
+               value = TRUE;
+       else if ((opt->type & FLAG_FALSE) == FLAG_FALSE)
+               value = FALSE;
+       else
+               g_return_val_if_reached (FALSE);
+
+       anode_write_boolean (value, NULL, &len);
+       data = g_malloc (len);
+       anode_write_boolean (value, data, &len);
+       return g_bytes_new_take (data, len);
 }
 
 static gboolean
-anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
+anode_read_object_id (GNode *node,
+                      GBytes *data,
+                      gchar **oid)
 {
        GString *result = NULL;
        const guchar *p;
        gboolean lead;
        guint val, pval;
+       gsize len;
        gint k;
 
-       g_assert (tlv);
-       if (tlv->len <= 0)
-               return FALSE;
-       p = tlv->buf + tlv->off;
+       g_assert (data != NULL);
+       p = g_bytes_get_data (data, &len);
 
        if (oid)
                result = g_string_sized_new (32);
@@ -2363,7 +2372,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
                g_string_append_printf (result, "%u.%u", pval, val);
 
        /* TODO: Validate first byte? */
-       for (k = 1, lead = 1, val = 0, pval = 0; k < tlv->len; ++k) {
+       for (k = 1, lead = 1, val = 0, pval = 0; k < len; ++k) {
                /* X.690: the leading byte must never be 0x80 */
                if (lead && p[k] == 0x80) {
                        anode_failure (node, "object id encoding is invalid");
@@ -2385,7 +2394,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
                }
        }
 
-       if (k < tlv->len) {
+       if (k < len) {
                if (result)
                        g_string_free (result, TRUE);
                return FALSE;
@@ -2397,7 +2406,9 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
 }
 
 static gboolean
-anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
+anode_write_object_id (const gchar *oid,
+                       guchar *data,
+                       gsize *n_data)
 {
        const gchar *p, *next;
        gint num, num1;
@@ -2452,6 +2463,10 @@ anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
        return TRUE;
 }
 
+/* -----------------------------------------------------------------------------------
+ * GETTING, SETTING
+ */
+
 GNode*
 egg_asn1x_node (GNode *asn, ...)
 {
@@ -2507,14 +2522,14 @@ egg_asn1x_node (GNode *asn, ...)
 const gchar*
 egg_asn1x_name (GNode *node)
 {
-       g_return_val_if_fail (node, NULL);
+       g_return_val_if_fail (node != NULL, NULL);
        return anode_def_name (node);
 }
 
 EggAsn1xType
 egg_asn1x_type (GNode *node)
 {
-       g_return_val_if_fail (node, 0);
+       g_return_val_if_fail (node != NULL, 0);
        return anode_def_type (node);
 }
 
@@ -2569,77 +2584,84 @@ egg_asn1x_append (GNode *node)
 gboolean
 egg_asn1x_have (GNode *node)
 {
-       Atlv *tlv;
+       GNode *child;
 
        g_return_val_if_fail (node, FALSE);
 
-       /* TODO: Handle default values */
+       if (anode_get_value (node) || anode_get_parsed (node))
+               return TRUE;
+
+       for (child = node->children; child != NULL; child = child->next) {
+               if (egg_asn1x_have (child))
+                       return TRUE;
+       }
 
-       tlv = anode_get_tlv_data (node);
-       return tlv != NULL && tlv->buf != NULL;
+       return FALSE;
 }
 
 gboolean
-egg_asn1x_get_boolean (GNode *node, gboolean *value)
+egg_asn1x_get_boolean (GNode *node,
+                       gboolean *value)
 {
-       EggAsn1xDef *opt;
-       Atlv *tlv;
+       gboolean ret;
+       GBytes *data;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (value, FALSE);
+       g_return_val_if_fail (node != NULL, FALSE);
+       g_return_val_if_fail (value != NULL, FALSE);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BOOLEAN, FALSE);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL) {
-
-               if ((anode_def_flags (node) & FLAG_DEFAULT) == 0)
-                       return FALSE;
-
-               /* Try to get a default */
-               opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
-               g_return_val_if_fail (opt, FALSE);
-
-               /* Parse out the default value */
-               if ((opt->type & FLAG_TRUE) == FLAG_TRUE)
-                       *value = TRUE;
-               else if ((opt->type & FLAG_FALSE) == FLAG_FALSE)
-                       *value = FALSE;
-               else
-                       g_return_val_if_reached (FALSE);
-               return TRUE;
-       }
+       data = anode_get_value (node);
+       if (data == NULL)
+               data = anode_default_boolean (node);
+       else
+               g_bytes_ref (data);
+       if (data == NULL)
+               return FALSE;
 
-       return anode_read_boolean (node, tlv, value);
+       ret = anode_read_boolean (node, data, value);
+       g_bytes_unref (data);
+       return ret;
 }
 
-gboolean
+void
 egg_asn1x_set_boolean (GNode *node, gboolean value)
 {
-       guchar *data;
-       gsize n_data;
-
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BOOLEAN, FALSE);
+       GBytes *data, *def;
+       guchar *buf;
+       gsize len;
 
-       /* TODO: Handle default values */
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_BOOLEAN);
+
+       len = 1;
+       buf = g_malloc0 (1);
+       anode_write_boolean (value, buf, &len);
+       data = g_bytes_new_take (buf, len);
+
+       /* If it's equal to default, then clear */
+       def = anode_default_boolean (node);
+       if (def) {
+               if (g_bytes_equal (def, data)) {
+                       anode_clr_value (node);
+                       g_bytes_unref (data);
+                       data = NULL;
+               }
+               g_bytes_unref (def);
+       }
 
-       n_data = 1;
-       data = g_malloc0 (1);
-       if (!anode_write_boolean (value, data, &n_data))
-               return FALSE;
-       anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
-       return TRUE;
+       if (data != NULL)
+               anode_take_value (node, data);
 }
 
-gboolean
+void
 egg_asn1x_set_null (GNode *node)
 {
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_NULL, FALSE);
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_NULL);
 
        /* Encode zero characters */
-       anode_encode_tlv_and_enc (node, 0, anode_encoder_data, "", NULL);
-       return TRUE;
+       anode_clr_value (node);
+       anode_set_value (node, g_bytes_new_static ("", 0));
 }
 
 GQuark
@@ -2648,21 +2670,18 @@ egg_asn1x_get_enumerated (GNode *node)
        gchar buf[sizeof (gulong) * 3];
        EggAsn1xDef *opt;
        gulong val;
-       Atlv *tlv;
+       GBytes *data;
 
-       g_return_val_if_fail (node, 0);
+       g_return_val_if_fail (node != NULL, 0);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED, 0);
 
-       tlv = anode_get_tlv_data (node);
-
-       /* TODO: Defaults */
-
-       if (tlv == NULL || tlv->buf == NULL)
+       data = anode_get_value (node);
+       if (data == NULL)
                return 0;
 
        /* TODO: Signed values */
 
-       if (!anode_read_integer_as_ulong (node, tlv, &val))
+       if (!anode_read_integer_ulong (node, data, &val))
                return 0;
 
        /* Format that as a string */
@@ -2677,8 +2696,9 @@ egg_asn1x_get_enumerated (GNode *node)
        return g_quark_from_static_string (opt->name);
 }
 
-gboolean
-egg_asn1x_set_enumerated (GNode *node, GQuark value)
+void
+egg_asn1x_set_enumerated (GNode *node,
+                          GQuark value)
 {
        EggAsn1xDef *opt;
        const gchar *name;
@@ -2686,156 +2706,143 @@ egg_asn1x_set_enumerated (GNode *node, GQuark value)
        gsize n_data;
        gulong val;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (value, FALSE);
-       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED, FALSE);
-
-       /* TODO: Handle default values */
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (value != 0);
+       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED);
 
        name = g_quark_to_string (value);
-       g_return_val_if_fail (name, FALSE);
+       g_return_if_fail (name != NULL);
 
        opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, name);
-       g_return_val_if_fail (opt && opt->value, FALSE);
+       g_return_if_fail (opt && opt->value);
 
        /* TODO: Signed values */
 
        val = anode_def_value_as_ulong (opt);
-       g_return_val_if_fail (val != G_MAXULONG, FALSE);
+       g_return_if_fail (val != G_MAXULONG);
 
        n_data = sizeof (gulong) + 1;
        data = g_malloc0 (n_data);
-       if (!anode_write_integer_ulong (val, data, &n_data))
-               return FALSE;
+       anode_write_integer_ulong (val, data, &n_data);
 
-       anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
-       return TRUE;
+       anode_clr_value (node);
+       anode_set_value (node, g_bytes_new_take (data, n_data));
 }
 
 gboolean
-egg_asn1x_get_integer_as_ulong (GNode *node, gulong *value)
+egg_asn1x_get_integer_as_ulong (GNode *node,
+                                gulong *value)
 {
-       const EggAsn1xDef *opt;
-       const gchar *defval;
-       Atlv *tlv;
-       gchar *end;
+       gboolean ret;
+       GBytes *data;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (value, FALSE);
+       g_return_val_if_fail (node != NULL, FALSE);
+       g_return_val_if_fail (value != NULL, FALSE);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL) {
-
-               if ((anode_def_flags (node) & FLAG_DEFAULT) == 0)
-                       return FALSE;
-
-               /* Try to get a default */
-               opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
-               g_return_val_if_fail (opt, FALSE);
-               g_return_val_if_fail (opt->value, FALSE);
-               defval = opt->value;
-
-               opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, defval);
-               if (opt != NULL) {
-                       g_return_val_if_fail (opt->value, FALSE);
-                       defval = opt->value;
-               }
-
-               /* Parse out the default value */
-               *value = strtoul (defval, &end, 10);
-               g_return_val_if_fail (end && !end[0], FALSE);
-               return TRUE;
-       }
+       data = anode_get_value (node);
+       if (data == NULL)
+               data = anode_default_integer (node);
+       else
+               g_bytes_ref (data);
+       if (data == NULL)
+               return FALSE;
 
-       return anode_read_integer_as_ulong (node, tlv, value);
+       ret = anode_read_integer_ulong (node, data, value);
+       g_bytes_unref (data);
+       return ret;
 }
 
-gboolean
-egg_asn1x_set_integer_as_ulong (GNode *node, gulong value)
+void
+egg_asn1x_set_integer_as_ulong (GNode *node,
+                                gulong value)
 {
-       guchar *data;
-       gsize n_data;
+       GBytes *data, *def;
+       guchar *buf;
+       gsize len;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
 
-       /* TODO: Handle default values */
+       len = sizeof (gulong) + 1;
+       buf = g_malloc0 (len);
+       anode_write_integer_ulong (value, buf, &len);
+       data = g_bytes_new_take (buf, len);
+
+       /* If it's equal to default, then clear */
+       def = anode_default_integer (node);
+       if (def) {
+               if (g_bytes_equal (def, data)) {
+                       anode_clr_value (node);
+                       g_bytes_unref (data);
+                       data = NULL;
+               }
+               g_bytes_unref (def);
+       }
 
-       n_data = sizeof (gulong) + 1;
-       data = g_malloc0 (n_data);
-       if (!anode_write_integer_ulong (value, data, &n_data))
-               return FALSE;
-       anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
-       return TRUE;
+       if (data != NULL)
+               anode_take_value (node, data);
 }
 
 GBytes *
 egg_asn1x_get_integer_as_raw (GNode *node)
 {
-       GBytes *backing;
-       Atlv *tlv;
-
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
+       Anode *an;
+       GBytes *raw;
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
-               return NULL;
+       g_return_val_if_fail (node != NULL, NULL);
+       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, NULL);
 
-       backing = anode_get_backing (node);
-       if (backing == NULL)
+       an = node->data;
+       if (an->guarantee_unsigned) {
+               g_warning ("cannot read integer set with egg_asn1x_set_integer_as_raw() "
+                          "via egg_asn1x_get_integer_as_raw()");
                return NULL;
+       }
 
-       return g_bytes_new_with_free_func (tlv->buf + tlv->off, tlv->len,
-                                          (GDestroyNotify)g_bytes_unref,
-                                          g_bytes_ref (backing));
+       raw = anode_get_value (node);
+       if (raw != NULL)
+               g_bytes_ref (raw);
+       return raw;
 }
 
 GBytes *
 egg_asn1x_get_integer_as_usg (GNode *node)
 {
-       GBytes *backing;
        const guchar *p;
+       Anode *an;
        gboolean sign;
-       Atlv *tlv;
-       gsize n_data;
        gsize len;
 
        g_return_val_if_fail (node != NULL, FALSE);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
-               return NULL;
-
-       backing = anode_get_backing (node);
-       if (backing == NULL)
-               return NULL;
-
-       p = tlv->buf + tlv->off;
-       len = tlv->len;
-
-       sign = !!(p[0] & 0x80);
-       if (sign) {
-               g_warning ("invalid two's complement integer is negative, but expected unsigned");
+       an = node->data;
+       if (an->value == NULL)
                return NULL;
-       }
 
-       n_data = len;
+       p = g_bytes_get_data (an->value, &len);
 
-       /* Strip off the extra zero byte that was preventing it from being negative */
-       if (p[0] == 0 && len > 1) {
-               sign = !!(p[1] & 0x80);
+       if (!an->guarantee_unsigned) {
+               sign = !!(p[0] & 0x80);
                if (sign) {
-                       p++;
-                       n_data = len - 1;
+                       g_warning ("invalid two's complement integer is negative, but expected unsigned");
+                       return NULL;
+               }
+
+               /* Strip off the extra zero byte that was preventing it from being negative */
+               if (p[0] == 0 && len > 1) {
+                       sign = !!(p[1] & 0x80);
+                       if (sign) {
+                               p++;
+                               len--;
+                       }
                }
        }
 
-       return g_bytes_new_with_free_func (p, n_data,
+       return g_bytes_new_with_free_func (p, len,
                                           (GDestroyNotify)g_bytes_unref,
-                                          g_bytes_ref (backing));
+                                          g_bytes_ref (an->value));
 }
 
 void
@@ -2852,183 +2859,244 @@ egg_asn1x_take_integer_as_raw (GNode *node,
 {
        gboolean sign;
        const guchar *p;
+       Anode *an;
+
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (value != NULL);
+       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+
+       /* Make sure the integer is properly encoded in twos complement*/
+       p = g_bytes_get_data (value, NULL);
+       g_return_if_fail (p != NULL);
+
+       sign = !!(p[0] & 0x80);
+       if (sign) {
+               g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement");
+               return;
+       }
+
+       anode_clr_value (node);
+       anode_set_value (node, value);
+
+       an = node->data;
+       an->guarantee_unsigned = 0;
+}
+
+void
+egg_asn1x_set_integer_as_usg (GNode *node,
+                              GBytes *value)
+{
+       g_return_if_fail (value != NULL);
+       egg_asn1x_take_integer_as_usg (node, g_bytes_ref (value));
+}
+
+void
+egg_asn1x_take_integer_as_usg (GNode *node,
+                               GBytes *value)
+{
+       Anode *an;
+
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (value != NULL);
+       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+
+       anode_set_value (node, value);
+       an = node->data;
+       an->guarantee_unsigned = 1;
+}
+
+GNode *
+egg_asn1x_get_any_as (GNode *node,
+                      const EggAsn1xDef *defs,
+                      const gchar *type)
+{
+       g_return_val_if_fail (node != NULL, NULL);
+       g_return_val_if_fail (type != NULL, NULL);
+       g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, NULL);
+
+       return egg_asn1x_get_any_as_full (node, defs, type, 0);
+}
+
+GNode *
+egg_asn1x_get_any_as_full (GNode *node,
+                           const EggAsn1xDef *defs,
+                           const gchar *type,
+                           gint options)
+{
+       GNode *asn;
+
+       g_return_val_if_fail (node != NULL, NULL);
+       g_return_val_if_fail (type != NULL, NULL);
+       g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, NULL);
+
+       asn = egg_asn1x_create (defs, type);
+       g_return_val_if_fail (asn != NULL, NULL);
+
+       if (!egg_asn1x_get_any_into_full (node, asn, options)) {
+               egg_asn1x_destroy (asn);
+               return NULL;
+       }
+
+       return asn;
+}
+
+gboolean
+egg_asn1x_get_any_into  (GNode *node,
+                         GNode *into)
+{
+       g_return_val_if_fail (node != NULL, FALSE);
+       g_return_val_if_fail (into != NULL, FALSE);
+       g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, FALSE);
+
+       return egg_asn1x_get_any_into_full (node, into, 0);
+}
+
+gboolean
+egg_asn1x_get_any_into_full (GNode *node,
+                             GNode *into,
+                             gint options)
+{
+       Atlv *tlv;
 
-       g_return_if_fail (node != NULL);
-       g_return_if_fail (value != NULL);
-       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+       g_return_val_if_fail (node != NULL, FALSE);
+       g_return_val_if_fail (into != NULL, FALSE);
+       g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, FALSE);
 
-       /* Make sure the integer is properly encoded in twos complement*/
-       p = g_bytes_get_data (value, NULL);
-       g_return_if_fail (p != NULL);
+       tlv = anode_get_parsed (node);
+       if (tlv == NULL)
+               return FALSE;
 
-       sign = !!(p[0] & 0x80);
-       if (sign) {
-               g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement");
-               return;
+       /* If this node is explicit, then just get the contents */
+       if (anode_calc_explicit_for_flags (node, anode_def_flags (node), NULL)) {
+               tlv = tlv->child;
+               if (tlv == NULL)
+                       return FALSE;
        }
 
-       anode_encode_tlv_and_enc (node, g_bytes_get_size (value), anode_encoder_bytes,
-                                 value, (GDestroyNotify)g_bytes_unref);
-}
+       if (!anode_decode_anything (into, tlv))
+               return FALSE;
 
-void
-egg_asn1x_set_integer_as_usg (GNode *node,
-                              GBytes *value)
-{
-       g_return_if_fail (value != NULL);
-       egg_asn1x_take_integer_as_usg (node, g_bytes_ref (value));
+       return egg_asn1x_validate (into, !(options & EGG_ASN1X_NO_STRICT));
 }
 
 void
-egg_asn1x_take_integer_as_usg (GNode *node,
-                               GBytes *value)
+egg_asn1x_set_any_from (GNode *node,
+                        GNode *from)
 {
-       gboolean sign;
-       const guchar *p;
-       gsize len;
+       Anode *an;
+       Atlv *tlv;
 
        g_return_if_fail (node != NULL);
-       g_return_if_fail (value != NULL);
-       g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+       g_return_if_fail (from != NULL);
+       g_return_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY);
 
-       /* Make sure the integer is properly encoded in twos complement*/
-       p = g_bytes_get_data (value, &len);
-       g_return_if_fail (p != NULL);
-
-       sign = !!(p[0] & 0x80);
+       tlv = anode_build_anything (from, TRUE);
+       g_return_if_fail (tlv != NULL);
 
-       /*
-        * If in two's complement this would be negative, add a zero byte so
-        * that it isn't. Here we just note that the result will be one byte
-        * longer. In anode_encoder_unsigned we actually add the zero byte.
-        */
-       if (sign)
-               len += 1;
+       /* Wrap this if necessary */
+       tlv = anode_build_maybe_explicit (node, tlv, anode_def_flags (node));
 
-       anode_encode_tlv_and_enc (node, len, anode_encoder_unsigned,
-                                 value, (GDestroyNotify)g_bytes_unref);
+       /* Mark down the tlvs for this node */
+       an = node->data;
+       atlv_free (an->parsed);
+       an->parsed = tlv;
 }
 
 GBytes *
-egg_asn1x_get_element_raw (GNode *node)
+egg_asn1x_get_any_raw (GNode *node,
+                       EggAllocator allocator)
 {
-       GBytes *backing;
-       const guchar *p;
-       gsize len;
+       GBytes *bytes;
        Atlv *tlv;
 
        g_return_val_if_fail (node != NULL, NULL);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
+       tlv = anode_build_anything (node, TRUE);
+       if (tlv == NULL) {
+               anode_failure (node, "missing value(s)");
                return NULL;
-
-       backing = anode_get_backing (node);
-       if (backing == NULL)
-               return NULL;
-
-       if (anode_calc_explicit (node, NULL)) {
-               len = (tlv->len + tlv->off) - tlv->oft;
-               p = tlv->buf + tlv->oft;
-       } else {
-               len = tlv->len + tlv->off;
-               p = tlv->buf;
        }
 
-       return g_bytes_new_with_free_func (p, len, (GDestroyNotify)g_bytes_unref,
-                                          g_bytes_ref (backing));
+       atlv_sort_perform (tlv, allocator);
+
+       bytes = atlv_unparse_to_bytes (tlv, allocator);
+       atlv_free (tlv);
+       return bytes;
 }
 
 gboolean
-egg_asn1x_set_element_raw (GNode *node,
-                           GBytes *element)
+egg_asn1x_set_any_raw (GNode *node,
+                       GBytes *raw)
 {
-       Atlv dtlv, *tlv;
-       gint oft, flags;
-       const guchar *data;
-       guchar cls_type;
-       GBytes *sub;
-       gsize size;
+       const gchar *msg;
+       Anode *an;
+       Atlv *tlv;
 
        g_return_val_if_fail (node != NULL, FALSE);
-       g_return_val_if_fail (element != NULL, FALSE);
-
-       anode_clear (node);
-       memset (&dtlv, 0, sizeof (dtlv));
+       g_return_val_if_fail (raw != NULL, FALSE);
 
-       data = g_bytes_get_data (element, &size);
-       g_return_val_if_fail (data != NULL, FALSE);
+       an = node->data;
+       tlv = atlv_new ();
+       msg = atlv_parse_der (raw, tlv);
+       if (msg == NULL) {
 
-       /* Decode the beginning TLV */
-       if (!anode_decode_tlv_for_data (data, data + size, &dtlv))
-               return FALSE;
+               /* Wrap this if necessary */
+               tlv = anode_build_maybe_explicit (node, tlv, anode_def_flags (node));
 
-       /*
-        * Decode the data into place properly, to make sure it fits. Note
-        * we are not decoding any explicit outer tagging, this is just
-        * the internal value. In addition we do not support optional
-        * and default values, which would decode successfully in
-        * unexpected ways.
-        */
-       flags = anode_def_flags (node);
-       flags &= ~(FLAG_TAG | FLAG_DEFAULT | FLAG_OPTION);
-       if (!anode_decode_anything_for_flags (node, element, &dtlv, flags))
-               return FALSE;
+               atlv_free (an->parsed);
+               an->parsed = tlv;
+               return TRUE;
 
-       /* There was extra data */
-       if (dtlv.end - dtlv.buf != size)
+       /* A failure, set the message manually so it doesn't get a prefix */
+       } else {
+               an = node->data;
+               g_free (an->failure);
+               an->failure = g_strdup (msg);
                return FALSE;
-
-       /* Clear buffer from TLV so it gets encoded */
-       tlv = anode_get_tlv_data (node);
-       g_assert (tlv);
-       tlv->buf = tlv->end = NULL;
-
-       /* Explicit tagging: leave space for the outer tag */
-       if (anode_calc_explicit (node, &cls_type)) {
-               oft = anode_encode_cls_tag_len (NULL, 0, (ASN1_CLASS_STRUCTURED | cls_type),
-                                               anode_calc_tag (node), size);
-
-               tlv->off += oft;
-               tlv->oft = oft;
        }
-
-       sub = g_bytes_new_with_free_func (dtlv.buf + dtlv.off, dtlv.len,
-                                         (GDestroyNotify)g_bytes_unref,
-                                         g_bytes_ref (element));
-
-       /* Setup encoding of the contents */
-       anode_set_enc_data (node, anode_encoder_bytes, sub, (GDestroyNotify)g_bytes_unref);
-       return TRUE;
 }
 
 GBytes *
-egg_asn1x_get_raw_value (GNode *node)
+egg_asn1x_get_element_raw (GNode *node)
 {
-       GBytes *backing;
+       Anode *an;
        Atlv *tlv;
 
-       g_return_val_if_fail (node, NULL);
+       g_return_val_if_fail (node != NULL, NULL);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
-               return NULL;
-       g_return_val_if_fail (!(tlv->cls & ASN1_CLASS_STRUCTURED), NULL);
+       an = node->data;
+       tlv = an->parsed;
+
+       /* If this node is explicit, then just get the contents */
+       if (tlv && anode_calc_explicit_for_flags (node, anode_def_flags (node), NULL))
+               tlv = tlv->child;
 
-       backing = anode_get_backing (node);
-       if (backing == NULL)
+       if (!tlv || !tlv->decoded)
                return NULL;
 
-       return g_bytes_new_with_free_func (tlv->buf + tlv->off, tlv->len,
-                                          (GDestroyNotify)g_bytes_unref,
-                                          g_bytes_ref (backing));
+       return g_bytes_ref (tlv->decoded);
+}
+
+GBytes *
+egg_asn1x_get_value_raw (GNode *node)
+{
+       GBytes *raw;
+
+       g_return_val_if_fail (node != NULL, NULL);
+       raw = anode_get_value (node);
+       if (raw != NULL)
+               g_bytes_ref (raw);
+       return raw;
 }
 
-guchar*
-egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_string)
+guchar *
+egg_asn1x_get_string_as_raw (GNode *node,
+                             EggAllocator allocator,
+                             gsize *n_string)
 {
        gsize length;
        guchar *string;
+       GBytes *data;
        Atlv *tlv;
        gint type;
 
@@ -3039,43 +3107,68 @@ egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_strin
                allocator = g_realloc;
 
        type = anode_def_type (node);
-       g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, NULL);
+       g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING ||
+                             type == EGG_ASN1X_GENERALSTRING, NULL);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
-               return NULL;
+       data = anode_get_value (node);
+       if (data != NULL) {
+               if (!anode_read_string_simple (node, data, NULL, &length))
+                       return NULL;
 
-       if (!anode_read_string (node, tlv, NULL, &length))
-               return NULL;
+               string = (allocator) (NULL, length + 1);
+               if (string == NULL)
+                       return NULL;
 
-       string = (allocator) (NULL, length + 1);
-       if (string == NULL)
-               return NULL;
+               if (!anode_read_string_simple (node, data, string, &length)) {
+                       (allocator) (string, 0);
+                       return NULL;
+               }
 
-       if (!anode_read_string (node, tlv, string, &length)) {
-               (allocator) (string, 0);
-               return NULL;
+               /* Courtesy null termination, string must however be validated! */
+               string[length] = 0;
+               *n_string = length;
+               return string;
        }
 
-       /* Courtesy null termination, string must however be validated! */
-       string[length] = 0;
-       *n_string = length;
-       return string;
+       tlv = anode_get_parsed (node);
+       if (tlv != NULL) {
+               if (!anode_read_string_struct (node, tlv, NULL, &length))
+                       return NULL;
+
+               string = (allocator) (NULL, length + 1);
+               if (string == NULL)
+                       return NULL;
+
+               if (!anode_read_string_struct (node, tlv, string, &length)) {
+                       (allocator) (string, 0);
+                       return NULL;
+               }
+
+               /* Courtesy null termination, string must however be validated! */
+               string[length] = 0;
+               *n_string = length;
+               return string;
+       }
+
+       return NULL;
 }
 
-gboolean
-egg_asn1x_set_string_as_raw (GNode *node, guchar *data, gsize n_data, GDestroyNotify destroy)
+void
+egg_asn1x_set_string_as_raw (GNode *node,
+                             guchar *data,
+                             gsize n_data,
+                             GDestroyNotify destroy)
 {
        gint type;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (data, FALSE);
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (data != NULL);
 
        type = anode_def_type (node);
-       g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, FALSE);
+       g_return_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING);
 
-       anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, destroy);
-       return TRUE;
+       anode_set_value (node, g_bytes_new_with_free_func (data, n_data,
+                                                          destroy, data));
 }
 
 GBytes *
@@ -3113,7 +3206,8 @@ egg_asn1x_get_bmpstring_as_utf8 (GNode *node)
 }
 
 gchar*
-egg_asn1x_get_string_as_utf8 (GNode *node, EggAllocator allocator)
+egg_asn1x_get_string_as_utf8 (GNode *node,
+                              EggAllocator allocator)
 {
        gchar *string;
        gsize n_string;
@@ -3136,47 +3230,44 @@ egg_asn1x_get_string_as_utf8 (GNode *node, EggAllocator allocator)
 }
 
 gboolean
-egg_asn1x_set_string_as_utf8 (GNode *node, gchar *data, GDestroyNotify destroy)
+egg_asn1x_set_string_as_utf8 (GNode *node,
+                              gchar *data,
+                              GDestroyNotify destroy)
 {
        gsize n_data;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (data, FALSE);
+       g_return_val_if_fail (node != NULL, FALSE);
+       g_return_val_if_fail (data != NULL, FALSE);
 
        n_data = strlen (data);
        if (!g_utf8_validate (data, n_data, NULL))
                return FALSE;
 
-       return egg_asn1x_set_string_as_raw (node, (guchar*)data, n_data, destroy);
+       egg_asn1x_set_string_as_raw (node, (guchar*)data, n_data, destroy);
+       return TRUE;
 }
 
 GBytes *
-egg_asn1x_get_bits_as_raw (GNode *node, guint *n_bits)
+egg_asn1x_get_bits_as_raw (GNode *node,
+                           guint *n_bits)
 {
-       GBytes *backing;
-       guchar padded;
-       Atlv *tlv;
-
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (n_bits, FALSE);
-       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, FALSE);
+       gsize len;
+       GBytes *data;
+       Anode *an;
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
-               return NULL;
+       g_return_val_if_fail (node != NULL, NULL);
+       g_return_val_if_fail (n_bits != NULL, NULL);
+       g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, NULL);
 
-       backing = anode_get_backing (node);
-       if (backing == NULL)
+       data = anode_get_value (node);
+       if (data == NULL)
                return NULL;
 
-       padded = *(tlv->buf + tlv->off);
-       g_return_val_if_fail (padded < 8, NULL);
-       g_return_val_if_fail (tlv->len > 1, NULL);
+       len = g_bytes_get_size (data);
+       an = node->data;
 
-       *n_bits = ((tlv->len - 1) * 8) - padded;
-       return g_bytes_new_with_free_func (tlv->buf + tlv->off + 1, tlv->len - 1,
-                                          (GDestroyNotify)g_bytes_unref,
-                                          g_bytes_ref (backing));
+       *n_bits = (len * 8) - an->bits_empty;
+       return g_bytes_ref (data);
 }
 
 void
@@ -3184,7 +3275,9 @@ egg_asn1x_set_bits_as_raw (GNode *node,
                            GBytes *value,
                            guint n_bits)
 {
+       g_return_if_fail (node != NULL);
        g_return_if_fail (value != NULL);
+
        egg_asn1x_take_bits_as_raw (node, g_bytes_ref (value), n_bits);
 }
 
@@ -3193,9 +3286,10 @@ egg_asn1x_take_bits_as_raw (GNode *node,
                             GBytes *value,
                             guint n_bits)
 {
+       Anode *an;
        gint type;
-       gsize length;
-       Abits *ab;
+       gsize len;
+       guchar empty;
 
        g_return_if_fail (node != NULL);
        g_return_if_fail (value != NULL);
@@ -3203,47 +3297,54 @@ egg_asn1x_take_bits_as_raw (GNode *node,
        type = anode_def_type (node);
        g_return_if_fail (type == EGG_ASN1X_BIT_STRING);
 
-       length = (n_bits / 8);
+       len = (n_bits / 8);
        if (n_bits % 8)
-               length += 1;
+               len += 1;
 
-       ab = g_slice_new0 (Abits);
-       ab->bits = value;
-       ab->n_bits = n_bits;
+       empty = n_bits % 8;
+       if (empty > 0)
+               empty = 8 - empty;
 
-       anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
+       anode_take_value (node, value);
+       an = node->data;
+       an->bits_empty = empty;
 }
 
 gboolean
-egg_asn1x_get_bits_as_ulong (GNode *node, gulong *bits, guint *n_bits)
+egg_asn1x_get_bits_as_ulong (GNode *node,
+                             gulong *bits,
+                             guint *n_bits)
 {
-       Atlv *tlv;
+       GBytes *data;
+       const guchar *buf;
+       gsize len;
        guint i, length;
        guchar empty;
        const guchar *p;
        gulong value;
+       Anode *an;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (bits, FALSE);
-       g_return_val_if_fail (n_bits, FALSE);
+       g_return_val_if_fail (node != NULL, FALSE);
+       g_return_val_if_fail (bits != NULL, FALSE);
+       g_return_val_if_fail (n_bits != NULL, FALSE);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, FALSE);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
+       data = anode_get_value (node);
+       if (data == NULL)
                return FALSE;
 
-       empty = *(tlv->buf + tlv->off);
-       g_return_val_if_fail (empty < 8, FALSE);
-       g_return_val_if_fail (tlv->len > 1, FALSE);
+       buf = g_bytes_get_data (data, &len);
+       an = node->data;
+       empty = an->bits_empty;
 
-       length = ((tlv->len - 1) * 8) - empty;
+       length = (len * 8) - empty;
        if (length > sizeof (gulong) * 8)
                return FALSE;
 
        value = 0;
-       p = tlv->buf + tlv->off + 1;
+       p = buf;
 
-       for (i = 0; i < tlv->len - 1; ++i)
+       for (i = 0; i < len; ++i)
                value = value << 8 | p[i];
 
        *bits = value >> empty;
@@ -3251,47 +3352,45 @@ egg_asn1x_get_bits_as_ulong (GNode *node, gulong *bits, guint *n_bits)
        return TRUE;
 }
 
-gboolean
-egg_asn1x_set_bits_as_ulong (GNode *node, gulong bits, guint n_bits)
+void
+egg_asn1x_set_bits_as_ulong (GNode *node,
+                             gulong bits,
+                             guint n_bits)
 {
        guchar *data;
        gulong value;
-       gint type;
-       gsize i, length;
+       gsize i, len;
        guchar empty;
-       Abits *ab;
+       Anode *an;
+       gint type;
 
-       g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (bits, FALSE);
-       g_return_val_if_fail (n_bits <= sizeof (gulong) * 8, FALSE);
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (n_bits <= sizeof (gulong) * 8);
 
        type = anode_def_type (node);
-       g_return_val_if_fail (type == EGG_ASN1X_BIT_STRING, FALSE);
+       g_return_if_fail (type == EGG_ASN1X_BIT_STRING);
 
        empty = n_bits % 8;
        if (empty > 0)
                empty = 8 - empty;
-       length = (n_bits / 8) + (empty ? 1 : 0);
+       len = (n_bits / 8) + (empty ? 1 : 0);
 
        data = g_malloc0 (sizeof (gulong));
        value = bits << empty;
 
-       for (i = 0; i < length; ++i)
-               data[(length - i) - 1] = (value >> i * 8) & 0xFF;
+       for (i = 0; i < len; ++i)
+               data[len - i - 1] = (value >> i * 8) & 0xFF;
 
-       ab = g_slice_new0 (Abits);
-       ab->bits = g_bytes_new_take (data, sizeof (gulong));
-       ab->n_bits = n_bits;
-
-       anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
-       return TRUE;
+       an = node->data;
+       an->bits_empty = empty;
+       anode_take_value (node, g_bytes_new_take (data, len));
 }
 
 glong
 egg_asn1x_get_time_as_long (GNode *node)
 {
        struct tm when;
-       Atlv *tlv;
+       GBytes *data;
        glong time;
        gint type;
 
@@ -3309,20 +3408,21 @@ egg_asn1x_get_time_as_long (GNode *node)
 
        g_return_val_if_fail (type == EGG_ASN1X_TIME, -1);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
+       data = anode_get_value (node);
+       if (data == NULL)
                return -1;
 
-       if (!anode_read_time (node, tlv, &when, &time))
+       if (!anode_read_time (node, data, &when, &time))
                return -1;
        return time;
 }
 
 gboolean
-egg_asn1x_get_time_as_date (GNode *node, GDate *date)
+egg_asn1x_get_time_as_date (GNode *node,
+                            GDate *date)
 {
        struct tm when;
-       Atlv *tlv;
+       GBytes *data;
        glong time;
        gint type;
 
@@ -3340,11 +3440,11 @@ egg_asn1x_get_time_as_date (GNode *node, GDate *date)
 
        g_return_val_if_fail (type == EGG_ASN1X_TIME, FALSE);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
+       data = anode_get_value (node);
+       if (data == NULL)
                return FALSE;
 
-       if (!anode_read_time (node, tlv, &when, &time))
+       if (!anode_read_time (node, data, &when, &time))
                return FALSE;
 
        g_date_set_dmy (date, when.tm_mday, when.tm_mon + 1, when.tm_year + 1900);
@@ -3354,42 +3454,43 @@ egg_asn1x_get_time_as_date (GNode *node, GDate *date)
 gchar*
 egg_asn1x_get_oid_as_string (GNode *node)
 {
+       GBytes *data;
        gchar *oid;
-       Atlv *tlv;
 
        g_return_val_if_fail (node, NULL);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_OBJECT_ID, NULL);
 
-       tlv = anode_get_tlv_data (node);
-       if (tlv == NULL || tlv->buf == NULL)
+       data = anode_get_value (node);
+       if (data == NULL)
                return NULL;
 
-       if (!anode_read_object_id (node, tlv, &oid))
+       if (!anode_read_object_id (node, data, &oid))
                return NULL;
 
        return oid;
 }
 
 gboolean
-egg_asn1x_set_oid_as_string (GNode *node, const gchar *oid)
+egg_asn1x_set_oid_as_string (GNode *node,
+                             const gchar *oid)
 {
        guchar *data;
        gsize n_data;
 
-       g_return_val_if_fail (oid, FALSE);
-       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (oid != NULL, FALSE);
+       g_return_val_if_fail (node != NULL, FALSE);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_OBJECT_ID, FALSE);
 
        /* Encoding will always be shorter than string */
        n_data = strlen (oid);
        data = g_malloc0 (n_data);
 
-       if (!anode_write_oid (oid, data, &n_data)) {
+       if (!anode_write_object_id (oid, data, &n_data)) {
                g_free (data);
                return FALSE;
        }
 
-       anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
+       anode_take_value (node, g_bytes_new_take (data, n_data));
        return TRUE;
 }
 
@@ -3408,13 +3509,15 @@ egg_asn1x_get_oid_as_quark (GNode *node)
 }
 
 gboolean
-egg_asn1x_set_oid_as_quark (GNode *node, GQuark oid)
+egg_asn1x_set_oid_as_quark (GNode *node,
+                            GQuark oid)
 {
        const gchar *str;
 
-       g_return_val_if_fail (oid, FALSE);
+       g_return_val_if_fail (oid != 0, FALSE);
+
        str = g_quark_to_string (oid);
-       g_return_val_if_fail (str, FALSE);
+       g_return_val_if_fail (str != NULL, FALSE);
 
        return egg_asn1x_set_oid_as_string (node, str);
 }
@@ -3438,12 +3541,13 @@ egg_asn1x_get_choice (GNode *node)
 }
 
 gboolean
-egg_asn1x_set_choice (GNode *node, GNode *choice)
+egg_asn1x_set_choice (GNode *node,
+                      GNode *choice)
 {
        GNode *child;
        Anode *an;
 
-       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (node != NULL, FALSE);
        g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_CHOICE, FALSE);
 
        /* One and only one of the children must be set */
@@ -3468,7 +3572,9 @@ egg_asn1x_set_choice (GNode *node, GNode *choice)
  */
 
 static gboolean
-anode_parse_size (GNode *node, const gchar *text, gulong *value)
+anode_parse_size (GNode *node,
+                  const gchar *text,
+                  gulong *value)
 {
        EggAsn1xDef *def;
        gchar *end = NULL;
@@ -3492,7 +3598,8 @@ anode_parse_size (GNode *node, const gchar *text, gulong *value)
 
 
 static gboolean
-anode_validate_size (GNode *node, gulong length)
+anode_validate_size (GNode *node,
+                     gulong length)
 {
        EggAsn1xDef *size;
        gulong value1 = 0;
@@ -3518,23 +3625,26 @@ anode_validate_size (GNode *node, gulong length)
 }
 
 static gboolean
-anode_validate_integer (GNode *node, Atlv *tlv)
+anode_validate_integer (GNode *node,
+                        GBytes *value)
 {
        GList *constants, *l;
-       gulong value, check;
+       gulong val, check;
+       gsize len;
        gboolean found;
        gint flags;
 
-       g_assert (tlv);
+       g_assert (value != NULL);
+       len = g_bytes_get_size (value);
 
        /* Integers must be at least one byte long */
-       if (tlv->len <= 0)
+       if (len == 0)
                return anode_failure (node, "zero length integer");
 
        flags = anode_def_flags (node);
        if (flags & FLAG_LIST) {
                /* Parse out the value, we only support small integers*/
-               if (!anode_read_integer_as_ulong (node, tlv, &value))
+               if (!anode_read_integer_ulong (node, value, &val))
                        return anode_failure (node, "integer not part of list");
 
                /* Look through the list of constants */
@@ -3543,7 +3653,7 @@ anode_validate_integer (GNode *node, Atlv *tlv)
                for (l = constants; l; l = g_list_next (l)) {
                        check = anode_def_value_as_ulong (l->data);
                        g_return_val_if_fail (check != G_MAXULONG, FALSE);
-                       if (check == value) {
+                       if (check == val) {
                                found = TRUE;
                                break;
                        }
@@ -3558,82 +3668,88 @@ anode_validate_integer (GNode *node, Atlv *tlv)
 }
 
 static gboolean
-anode_validate_enumerated (GNode *node, Atlv *tlv)
+anode_validate_enumerated (GNode *node,
+                           GBytes *value)
 {
-       g_assert (tlv);
+       const guchar *buf;
+       gsize length;
+
+       g_assert (value != NULL);
 
-       if (!anode_validate_integer (node, tlv))
+       if (!anode_validate_integer (node, value))
                return FALSE;
-       g_assert (tlv->len); /* Checked above */
+
+       buf = g_bytes_get_data (value, &length);
+       g_assert (length > 0); /* Checked above */
+
        /* Enumerated must be positive */
-       if (tlv->buf[tlv->off] & 0x80)
+       if (buf[0] & 0x80)
                return anode_failure (node, "enumerated must be positive");
        return TRUE;
 }
 
 static gboolean
-anode_validate_boolean (GNode *node, Atlv *tlv)
+anode_validate_boolean (GNode *node,
+                        GBytes *value)
 {
-       g_assert (tlv);
+       const guchar *buf;
+       gsize len;
+
+       g_assert (value != NULL);
+       buf = g_bytes_get_data (value, &len);
 
        /* Must one byte, and zero or all ones */
-       if (tlv->len != 1)
+       if (len != 1)
                return anode_failure (node, "invalid length boolean");
-       if (tlv->buf[tlv->off] != 0x00 && tlv->buf[tlv->off] != 0xFF)
+       if (buf[0] != 0x00 && buf[0] != 0xFF)
                return anode_failure (node, "boolean must be true or false");
        return TRUE;
 }
 
 static gboolean
-anode_validate_bit_string (GNode *node, Atlv *tlv)
+anode_validate_bit_string (GNode *node,
+                           GBytes *value)
 {
-       guchar empty, mask;
-       g_assert (tlv);
+       g_assert (value != NULL);
 
-       /* At least two bytes in length */
-       if (tlv->len < 1)
-               return anode_failure (node, "invalid length bit string");
-       /* First byte is the number of free bits at end */
-       empty = tlv->buf[tlv->off];
-       if (empty > 7)
-               return anode_failure (node, "bit string has invalid header");
-       /* Free bits at end must be zero */
-       mask = 0xFF >> (8 - empty);
-       if (tlv->len > 1 && tlv->buf[tlv->off + tlv->len - 1] & mask)
-               return anode_failure (node, "bit string has invalid trailing bits");
+       /* All the decode validation done in anode_decode_bit_string */
        return TRUE;
 }
 
 static gboolean
-anode_validate_string (GNode *node, Atlv *tlv)
+anode_validate_string (GNode *node,
+                       GBytes *value)
 {
        gsize length;
 
-       if (!anode_read_string (node, tlv, NULL, &length))
+       if (!anode_read_string_simple (node, value, NULL, &length))
                return anode_failure (node, "string content is invalid");
 
        return anode_validate_size (node, (gulong)length);
 }
 
 static gboolean
-anode_validate_object_id (GNode *node, Atlv *tlv)
+anode_validate_object_id (GNode *node,
+                          GBytes *value)
 {
-       return anode_read_object_id (node, tlv, NULL);
+       return anode_read_object_id (node, value, NULL);
 }
 
 static gboolean
-anode_validate_null (GNode *node, Atlv *tlv)
+anode_validate_null (GNode *node,
+                     GBytes *value)
 {
-       g_assert (tlv);
-       return (tlv->len == 0);
+       g_assert (value != NULL);
+       return (g_bytes_get_size (value) == 0);
 }
 
 static gboolean
-anode_validate_time (GNode *node, Atlv *tlv)
+anode_validate_time (GNode *node,
+                     GBytes *value)
 {
        glong time;
        struct tm when;
-       return anode_read_time (node, tlv, &when, &time);
+       return anode_read_time (node, value, &when, &time);
 }
 
 static gboolean
@@ -3667,25 +3783,12 @@ anode_validate_sequence_or_set (GNode *node,
                                 gboolean strict)
 {
        GNode *child;
-       gulong tag = 0;
-       gint count = 0;
-       gint type;
-       Atlv *tlv;
-
-       type = anode_def_type (node);
 
        /* All of the children must validate properly */
        for (child = node->children; child; child = child->next) {
-               if (!anode_validate_anything (child, strict))
-                       return FALSE;
-
-               /* Tags must be in ascending order */
-               tlv = anode_get_tlv_data (child);
-               if (tlv && type == EGG_ASN1X_SET) {
-                       if (count > 0 && tag > tlv->tag)
-                               return anode_failure (node, "content must be in ascending order");
-                       tag = tlv->tag;
-                       ++count;
+               if (egg_asn1x_have (child)) {
+                       if (!anode_validate_anything (child, strict))
+                               return FALSE;
                }
        }
 
@@ -3697,36 +3800,16 @@ anode_validate_sequence_or_set_of (GNode *node,
                                    gboolean strict)
 {
        GNode *child;
-       Atlv *tlv, *ptlv;
-       gulong tag;
        gulong count;
-       gint type;
 
-       tag = 0;
        count = 0;
-       ptlv = NULL;
-
-       type = anode_def_type (node);
 
        /* All the children must validate properly */
        for (child = node->children; child; child = child->next) {
-               tlv = anode_get_tlv_data (child);
-               if (tlv) {
+               if (egg_asn1x_have (child)) {
                        if (!anode_validate_anything (child, strict))
                                return FALSE;
-
-                       /* Tag must have same tag as top */
-                       if (count == 0)
-                               tag = anode_calc_tag (child);
-                       else if (tag != G_MAXULONG && tlv->tag != tag)
-                               return anode_failure (node, "invalid mismatched content");
-
-                       /* Set of must be in ascending order */
-                       if (strict && type == EGG_ASN1X_SET_OF &&
-                           ptlv != NULL && compare_tlvs (ptlv, tlv) > 0)
-                               return anode_failure (node, "content must be in ascending order");
-                       ptlv = tlv;
-                       ++count;
+                       count++;
                }
        }
 
@@ -3737,51 +3820,17 @@ static gboolean
 anode_validate_anything (GNode *node,
                          gboolean strict)
 {
+       GBytes *value;
        Atlv *tlv;
        gint type;
 
        type = anode_def_type (node);
-       tlv = anode_get_tlv_data (node);
-
-       if (!tlv) {
-               if (anode_def_flags (node) & FLAG_OPTION)
-                       return TRUE;
-               if (anode_def_flags (node) & FLAG_DEFAULT)
-                       return TRUE;
-               return anode_failure (node, "missing value");
-       }
-
-       g_return_val_if_fail (tlv->buf, FALSE);
 
+       /* Handle these specially */
        switch (type) {
-
-       /* The primitive value types */
-       case EGG_ASN1X_INTEGER:
-               return anode_validate_integer (node, tlv);
-       case EGG_ASN1X_ENUMERATED:
-               return anode_validate_enumerated (node, tlv);
-       case EGG_ASN1X_BOOLEAN:
-               return anode_validate_boolean (node, tlv);
-       case EGG_ASN1X_BIT_STRING:
-               return anode_validate_bit_string (node, tlv);
-       case EGG_ASN1X_OCTET_STRING:
-               return anode_validate_string (node, tlv);
-       case EGG_ASN1X_OBJECT_ID:
-               return anode_validate_object_id (node, tlv);
-       case EGG_ASN1X_NULL:
-               return anode_validate_null (node, tlv);
-       case EGG_ASN1X_GENERALSTRING:
-               return anode_validate_string (node, tlv);
-       case EGG_ASN1X_TIME:
-               return anode_validate_time (node, tlv);
-
-       /* Transparent types */
-       case EGG_ASN1X_ANY:
-               return TRUE;
        case EGG_ASN1X_CHOICE:
                return anode_validate_choice (node, strict);
 
-       /* Structured types */
        case EGG_ASN1X_SEQUENCE:
        case EGG_ASN1X_SET:
                return anode_validate_sequence_or_set (node, strict);
@@ -3791,8 +3840,54 @@ anode_validate_anything (GNode *node,
                return anode_validate_sequence_or_set_of (node, strict);
 
        default:
-               g_return_val_if_reached (FALSE);
+               break;
+       }
+
+       /* Values that have been configured */
+       value = anode_get_value (node);
+       if (value) {
+               switch (type) {
+               case EGG_ASN1X_INTEGER:
+                       return anode_validate_integer (node, value);
+               case EGG_ASN1X_ENUMERATED:
+                       return anode_validate_enumerated (node, value);
+               case EGG_ASN1X_BOOLEAN:
+                       return anode_validate_boolean (node, value);
+               case EGG_ASN1X_BIT_STRING:
+                       return anode_validate_bit_string (node, value);
+               case EGG_ASN1X_OCTET_STRING:
+                       return anode_validate_string (node, value);
+               case EGG_ASN1X_OBJECT_ID:
+                       return anode_validate_object_id (node, value);
+               case EGG_ASN1X_NULL:
+                       return anode_validate_null (node, value);
+               case EGG_ASN1X_GENERALSTRING:
+                       return anode_validate_string (node, value);
+               case EGG_ASN1X_TIME:
+                       return anode_validate_time (node, value);
+               default:
+                       g_assert_not_reached ();
+               }
        }
+
+       /* See if there's a tlv parsed */
+       tlv = anode_get_parsed (node);
+       if (tlv) {
+               switch (type) {
+               case EGG_ASN1X_ANY:
+               case EGG_ASN1X_GENERALSTRING:
+               case EGG_ASN1X_OCTET_STRING:
+                       return TRUE;
+               default:
+                       break;
+               }
+       }
+
+       if (anode_def_flags (node) & FLAG_OPTION)
+               return TRUE;
+       if (anode_def_flags (node) & FLAG_DEFAULT)
+               return TRUE;
+       return anode_failure (node, "missing value");
 }
 
 gboolean
@@ -4169,25 +4264,40 @@ egg_asn1x_create_quark (const EggAsn1xDef *defs,
        return egg_asn1x_create (defs, g_quark_to_string (type));
 }
 
-GNode*
-egg_asn1x_create_and_decode (const EggAsn1xDef *defs,
-                             const gchar *identifier,
-                             GBytes *data)
+GNode *
+egg_asn1x_create_and_decode_full (const EggAsn1xDef *defs,
+                                  const gchar *identifier,
+                                  GBytes *data,
+                                  gint options)
 {
        GNode *asn;
 
-       g_return_val_if_fail (defs, NULL);
-       g_return_val_if_fail (identifier, NULL);
+       g_return_val_if_fail (defs != NULL, NULL);
+       g_return_val_if_fail (identifier != NULL, NULL);
+       g_return_val_if_fail (data != NULL, NULL);
 
        asn = egg_asn1x_create (defs, identifier);
        g_return_val_if_fail (asn, NULL);
 
-       if (!egg_asn1x_decode (asn, data)) {
+       if (!egg_asn1x_decode_full (asn, data, options)) {
                egg_asn1x_destroy (asn);
                return NULL;
        }
 
        return asn;
+
+}
+
+GNode*
+egg_asn1x_create_and_decode (const EggAsn1xDef *defs,
+                             const gchar *identifier,
+                             GBytes *data)
+{
+       g_return_val_if_fail (defs != NULL, NULL);
+       g_return_val_if_fail (identifier != NULL, NULL);
+       g_return_val_if_fail (data != NULL, NULL);
+
+       return egg_asn1x_create_and_decode_full (defs, identifier, data, 0);
 }
 
 /* -----------------------------------------------------------------------------------
@@ -4225,7 +4335,6 @@ traverse_and_dump (GNode *node, gpointer unused)
        guint i, depth;
        GString *output;
        gchar *string;
-       Atlv *tlv;
        Anode *an;
        GList *l;
 
@@ -4233,18 +4342,17 @@ traverse_and_dump (GNode *node, gpointer unused)
        for (i = 0; i < depth - 1; ++i)
                g_printerr ("    ");
 
-       tlv = anode_get_tlv_data (node);
+       an = node->data;
        output = g_string_new ("");
        dump_append_type (output, anode_def_type (node));
        dump_append_flags (output, anode_def_flags (node));
        string = g_utf8_casefold (output->str, output->len - 1);
        g_string_free (output, TRUE);
        g_printerr ("+ %s: %s [%s]%s\n", anode_def_name (node), anode_def_value (node),
-                   string, tlv && tlv->buf ? " *" : "");
+                   string, an->parsed || an->value ? " *" : "");
        g_free (string);
 
        /* Print out all the options */
-       an = node->data;
        for (l = an->opts; l; l = g_list_next (l)) {
                for (i = 0; i < depth; ++i)
                        g_printerr ("    ");
@@ -4416,9 +4524,9 @@ egg_asn1x_element_length (const guchar *data,
        int cb, len;
        gulong tag;
 
-       if (anode_decode_cls_tag (data, data + n_data, &cls, &tag, &cb)) {
+       if (atlv_parse_cls_tag (data, data + n_data, &cls, &tag, &cb)) {
                counter += cb;
-               len = anode_decode_length (data + cb, data + n_data, &cb);
+               len = atlv_parse_length (data + cb, data + n_data, &cb);
                counter += cb;
                if (len >= 0) {
                        len += counter;
@@ -4444,11 +4552,11 @@ egg_asn1x_element_content (const guchar *data,
        g_return_val_if_fail (n_content != NULL, NULL);
 
        /* Now get the data out of this element */
-       if (!anode_decode_cls_tag (data, (const guchar*)data + n_data, &cls, &tag, &cb))
+       if (!atlv_parse_cls_tag (data, data + n_data, &cls, &tag, &cb))
                return NULL;
 
        counter += cb;
-       len = anode_decode_length ((const guchar*)data + cb, (const guchar*)data + n_data, &cb);
+       len = atlv_parse_length (data + cb, data + n_data, &cb);
        if (len < 0)
                return NULL;
        counter += cb;
index 036b9ce..bca01e0 100644 (file)
@@ -58,6 +58,10 @@ typedef enum {
        EGG_ASN1X_GENERALSTRING = 27
 } EggAsn1xType;
 
+enum {
+       EGG_ASN1X_NO_STRICT = 0x01,
+} EggAsn1xFlags;
+
 GNode*              egg_asn1x_create                 (const EggAsn1xDef *defs,
                                                       const gchar *type);
 
@@ -68,6 +72,11 @@ GNode*              egg_asn1x_create_and_decode      (const EggAsn1xDef *defs,
                                                       const gchar *type,
                                                       GBytes *data);
 
+GNode*              egg_asn1x_create_and_decode_full (const EggAsn1xDef *defs,
+                                                      const gchar *type,
+                                                      GBytes *data,
+                                                      gint options);
+
 void                egg_asn1x_dump                   (GNode *asn);
 
 void                egg_asn1x_clear                  (GNode *asn);
@@ -75,13 +84,39 @@ void                egg_asn1x_clear                  (GNode *asn);
 gboolean            egg_asn1x_decode                 (GNode *asn,
                                                       GBytes *data);
 
-gboolean            egg_asn1x_decode_no_validate     (GNode *asn,
-                                                      GBytes *data);
+gboolean            egg_asn1x_decode_full            (GNode *asn,
+                                                      GBytes *data,
+                                                      gint options);
+
+void                egg_asn1x_set_any_from           (GNode *node,
+                                                      GNode *from);
+
+gboolean            egg_asn1x_set_any_raw            (GNode *node,
+                                                      GBytes *raw);
+
+gboolean            egg_asn1x_get_any_into           (GNode *node,
+                                                      GNode *into);
+
+gboolean            egg_asn1x_get_any_into_full      (GNode *node,
+                                                      GNode *into,
+                                                      gint options);
+
+GNode *             egg_asn1x_get_any_as             (GNode *node,
+                                                      const EggAsn1xDef *defs,
+                                                      const gchar *type);
+
+GNode *             egg_asn1x_get_any_as_full        (GNode *node,
+                                                      const EggAsn1xDef *defs,
+                                                      const gchar *type,
+                                                      gint options);
+
+GBytes *            egg_asn1x_get_any_raw            (GNode *node,
+                                                      EggAllocator allocator);
 
 gboolean            egg_asn1x_validate               (GNode *asn,
                                                       gboolean strict);
 
-GBytes *          egg_asn1x_encode                 (GNode *asn,
+GBytes *            egg_asn1x_encode                 (GNode *asn,
                                                       EggAllocator allocator);
 
 const gchar*        egg_asn1x_message                (GNode *asn);
@@ -107,23 +142,23 @@ gboolean            egg_asn1x_set_choice             (GNode *node,
 gboolean            egg_asn1x_get_boolean            (GNode *node,
                                                       gboolean *value);
 
-gboolean            egg_asn1x_set_boolean            (GNode *node,
+void                egg_asn1x_set_boolean            (GNode *node,
                                                       gboolean value);
 
-gboolean            egg_asn1x_set_null               (GNode *node);
+void                egg_asn1x_set_null               (GNode *node);
 
 GQuark              egg_asn1x_get_enumerated         (GNode *node);
 
-gboolean            egg_asn1x_set_enumerated         (GNode *node,
+void                egg_asn1x_set_enumerated         (GNode *node,
                                                       GQuark value);
 
 gboolean            egg_asn1x_get_integer_as_ulong   (GNode *node,
                                                       gulong *value);
 
-gboolean            egg_asn1x_set_integer_as_ulong   (GNode *node,
+void                egg_asn1x_set_integer_as_ulong   (GNode *node,
                                                       gulong value);
 
-GBytes *          egg_asn1x_get_integer_as_raw     (GNode *node);
+GBytes *            egg_asn1x_get_integer_as_raw     (GNode *node);
 
 void                egg_asn1x_set_integer_as_raw     (GNode *node,
                                                       GBytes *value);
@@ -131,7 +166,7 @@ void                egg_asn1x_set_integer_as_raw     (GNode *node,
 void                egg_asn1x_take_integer_as_raw    (GNode *node,
                                                       GBytes *value);
 
-GBytes *          egg_asn1x_get_integer_as_usg     (GNode *node);
+GBytes *            egg_asn1x_get_integer_as_usg     (GNode *node);
 
 void                egg_asn1x_set_integer_as_usg     (GNode *node,
                                                       GBytes *value);
@@ -139,25 +174,22 @@ void                egg_asn1x_set_integer_as_usg     (GNode *node,
 void                egg_asn1x_take_integer_as_usg    (GNode *node,
                                                       GBytes *value);
 
-GBytes *          egg_asn1x_get_raw_value          (GNode *node);
+GBytes *            egg_asn1x_get_value_raw          (GNode *node);
 
-GBytes *          egg_asn1x_get_element_raw        (GNode *node);
-
-gboolean            egg_asn1x_set_element_raw        (GNode *node,
-                                                      GBytes *value);
+GBytes *            egg_asn1x_get_element_raw        (GNode *node);
 
 guchar*             egg_asn1x_get_string_as_raw      (GNode *node,
                                                       EggAllocator allocator,
                                                       gsize *n_string);
 
-gboolean            egg_asn1x_set_string_as_raw      (GNode *node,
+void                egg_asn1x_set_string_as_raw      (GNode *node,
                                                       guchar *data,
                                                       gsize n_data,
                                                       GDestroyNotify destroy);
 
-GBytes *          egg_asn1x_get_string_as_bytes    (GNode *node);
+GBytes *            egg_asn1x_get_string_as_bytes    (GNode *node);
 
-GBytes *          egg_asn1x_get_bits_as_raw        (GNode *node,
+GBytes *            egg_asn1x_get_bits_as_raw        (GNode *node,
                                                       guint *n_bits);
 
 void                egg_asn1x_set_bits_as_raw        (GNode *node,
@@ -172,7 +204,7 @@ gboolean            egg_asn1x_get_bits_as_ulong      (GNode *node,
                                                       gulong *value,
                                                       guint *n_bits);
 
-gboolean            egg_asn1x_set_bits_as_ulong      (GNode *node,
+void                egg_asn1x_set_bits_as_ulong      (GNode *node,
                                                       gulong value,
                                                       guint n_bits);
 
index e3b092e..43bd772 100644 (file)
@@ -52,7 +52,7 @@ dn_print_hex_value (GBytes *val)
 static gchar*
 dn_print_oid_value_parsed (GQuark oid,
                            guint flags,
-                           GBytes *val)
+                           GNode *val)
 {
        GNode *asn1, *node;
        GBytes *value;
@@ -65,7 +65,7 @@ dn_print_oid_value_parsed (GQuark oid,
        asn1 = egg_asn1x_create_quark (pkix_asn1_tab, oid);
        g_return_val_if_fail (asn1, NULL);
 
-       if (!egg_asn1x_decode (asn1, val)) {
+       if (!egg_asn1x_get_any_into (val, asn1)) {
                g_message ("couldn't decode value for OID: %s: %s",
                           g_quark_to_string (oid), egg_asn1x_message (asn1));
                egg_asn1x_destroy (asn1);
@@ -81,7 +81,7 @@ dn_print_oid_value_parsed (GQuark oid,
        else
                node = asn1;
 
-       value = egg_asn1x_get_raw_value (node);
+       value = egg_asn1x_get_value_raw (node);
        data = g_bytes_get_data (value, &size);
 
        /*
@@ -108,8 +108,9 @@ dn_print_oid_value_parsed (GQuark oid,
 static gchar*
 dn_print_oid_value (GQuark oid,
                     guint flags,
-                    GBytes *val)
+                    GNode *val)
 {
+       GBytes *der;
        gchar *value;
 
        g_assert (val != NULL);
@@ -120,7 +121,11 @@ dn_print_oid_value (GQuark oid,
                        return value;
        }
 
-       return dn_print_hex_value (val);
+       der = egg_asn1x_get_element_raw (val);
+       value = dn_print_hex_value (der);
+       g_bytes_unref (der);
+
+       return value;
 }
 
 static gchar*
@@ -129,7 +134,7 @@ dn_parse_rdn (GNode *asn)
        const gchar *name;
        guint flags;
        GQuark oid;
-       GBytes *value;
+       GNode *value;
        gchar *display;
        gchar *result;
 
@@ -141,7 +146,7 @@ dn_parse_rdn (GNode *asn)
        flags = egg_oid_get_flags (oid);
        name = egg_oid_get_name (oid);
 
-       value = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "value", NULL));
+       value = egg_asn1x_node (asn, "value", NULL);
        g_return_val_if_fail (value, NULL);
 
        display = dn_print_oid_value (oid, flags, value);
@@ -149,7 +154,6 @@ dn_parse_rdn (GNode *asn)
                              "=", display, NULL);
        g_free (display);
 
-       g_bytes_unref (value);
        return result;
 }
 
@@ -200,11 +204,9 @@ egg_dn_read_part (GNode *asn, const gchar *match)
 {
        gboolean done = FALSE;
        const gchar *name;
-       GBytes *value;
        GNode *node;
        GQuark oid;
        gint i, j;
-       gchar *result;
 
        g_return_val_if_fail (asn, NULL);
        g_return_val_if_fail (match, NULL);
@@ -233,12 +235,7 @@ egg_dn_read_part (GNode *asn, const gchar *match)
                        node = egg_asn1x_node (asn, i, j, "value", NULL);
                        g_return_val_if_fail (node, NULL);
 
-                       value = egg_asn1x_get_element_raw (node);
-                       g_return_val_if_fail (value, NULL);
-
-                       result = dn_print_oid_value (oid, egg_oid_get_flags (oid), value);
-                       g_bytes_unref (value);
-                       return result;
+                       return dn_print_oid_value (oid, egg_oid_get_flags (oid), node);
                }
        }
 
@@ -250,7 +247,6 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
 {
        gboolean done = FALSE;
        GNode *node;
-       GBytes *value;
        GQuark oid;
        guint i, j;
 
@@ -279,12 +275,8 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
                                break;
                        }
 
-                       value = egg_asn1x_get_element_raw (node);
-
                        if (callback)
-                               (callback) (i, oid, value, user_data);
-
-                       g_bytes_unref (value);
+                               (callback) (i, oid, node, user_data);
                }
        }
 
@@ -293,7 +285,7 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
 
 gchar *
 egg_dn_print_value (GQuark oid,
-                    GBytes *value)
+                    GNode *value)
 {
        g_return_val_if_fail (oid != 0, NULL);
        g_return_val_if_fail (value != NULL, NULL);
@@ -336,7 +328,6 @@ egg_dn_add_string_part (GNode *asn,
                         GQuark oid,
                         const gchar *string)
 {
-       GBytes *bytes;
        GNode *node;
        GNode *value;
        GNode *val;
@@ -373,15 +364,6 @@ egg_dn_add_string_part (GNode *asn,
 
        egg_asn1x_set_string_as_utf8 (val, g_strdup (string), g_free);
 
-       bytes = egg_asn1x_encode (value, NULL);
-       if (bytes == NULL) {
-               g_warning ("couldn't build dn string value: %s", egg_asn1x_message (value));
-               return;
-       }
-
-       if (!egg_asn1x_set_element_raw (egg_asn1x_node (node, "value", NULL), bytes))
-               g_return_if_reached ();
-
+       egg_asn1x_set_any_from (egg_asn1x_node (node, "value", NULL), value);
        egg_asn1x_destroy (value);
-       g_bytes_unref (bytes);
 }
index a75e73d..bdf6b92 100644 (file)
@@ -33,7 +33,7 @@ gchar*             egg_dn_read_part                       (GNode *node,
 
 typedef void       (*EggDnCallback)                       (guint index,
                                                            GQuark oid,
-                                                           GBytes *value,
+                                                           GNode *value,
                                                            gpointer user_data);
 
 gboolean           egg_dn_parse                           (GNode *node,
@@ -41,7 +41,7 @@ gboolean           egg_dn_parse                           (GNode *node,
                                                            gpointer user_data);
 
 gchar*             egg_dn_print_value                     (GQuark oid,
-                                                           GBytes *value);
+                                                           GNode *value);
 
 void               egg_dn_add_string_part                 (GNode *node,
                                                            GQuark oid,
index d5459a5..54592d9 100644 (file)
@@ -662,7 +662,7 @@ read_cipher_pkcs5_pbe (int cipher_algo,
                        int hash_algo,
                        const gchar *password,
                        gsize n_password,
-                       GBytes *data,
+                       GNode *data,
                        gcry_cipher_hd_t *cih)
 {
        GNode *asn = NULL;
@@ -689,10 +689,10 @@ read_cipher_pkcs5_pbe (int cipher_algo,
        asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBE-params");
        g_return_val_if_fail (asn, FALSE);
 
-       if (!egg_asn1x_decode (asn, data))
+       if (!egg_asn1x_get_any_into (data, asn))
                goto done;
 
-       salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL));
+       salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", NULL));
        if (!salt)
                goto done;
        if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
@@ -730,7 +730,7 @@ done:
 }
 
 static gboolean
-setup_pkcs5_rc2_params (GBytes *data,
+setup_pkcs5_rc2_params (GNode *any,
                         gcry_cipher_hd_t cih)
 {
        GNode *asn = NULL;
@@ -739,18 +739,16 @@ setup_pkcs5_rc2_params (GBytes *data,
        gulong version;
        gboolean ret = FALSE;
 
-       g_assert (data);
+       g_assert (any != NULL);
 
-       asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-rc2-CBC-params");
-       g_return_val_if_fail (asn, FALSE);
-
-       if (!egg_asn1x_decode (asn, data))
+       asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-rc2-CBC-params");
+       if (asn == NULL)
                goto done;
 
        if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "rc2ParameterVersion", NULL), &version))
                goto done;
 
-       iv = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "iv", NULL));
+       iv = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "iv", NULL));
        if (!iv)
                goto done;
 
@@ -770,7 +768,7 @@ done:
 }
 
 static gboolean
-setup_pkcs5_des_params (GBytes *data,
+setup_pkcs5_des_params (GNode *any,
                         gcry_cipher_hd_t cih)
 {
        GNode *asn = NULL;
@@ -778,15 +776,15 @@ setup_pkcs5_des_params (GBytes *data,
        GBytes *iv;
        gboolean ret;
 
-       g_assert (data);
+       g_assert (any != NULL);
 
-       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params", data);
+       asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params");
        if (!asn)
-               asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-CBC-params", data);
+               asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-des-CBC-params");
        if (!asn)
                return FALSE;
 
-       iv = egg_asn1x_get_raw_value (asn);
+       iv = egg_asn1x_get_string_as_bytes (asn);
        egg_asn1x_destroy (asn);
 
        if (!iv)
@@ -807,7 +805,7 @@ setup_pkcs5_des_params (GBytes *data,
 static gboolean
 setup_pkcs5_pbkdf2_params (const gchar *password,
                            gsize n_password,
-                           GBytes *data,
+                           GNode *any,
                            int cipher_algo,
                            gcry_cipher_hd_t cih)
 {
@@ -820,17 +818,17 @@ setup_pkcs5_pbkdf2_params (const gchar *password,
        gulong iterations;
 
        g_assert (cipher_algo);
-       g_assert (data != NULL);
+       g_assert (any != NULL);
 
        ret = FALSE;
 
-       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBKDF2-params", data);
+       asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-PBKDF2-params");
        if (!asn)
                goto done;
 
        if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
                iterations = 1;
-       salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", "specified", NULL));
+       salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", "specified", NULL));
        if (!salt)
                goto done;
 
@@ -861,13 +859,13 @@ done:
 static gboolean
 read_cipher_pkcs5_pbes2 (const gchar *password,
                          gsize n_password,
-                         GBytes *data,
+                         GNode *data,
                          gcry_cipher_hd_t *cih)
 {
        GNode *asn = NULL;
        gboolean r, ret;
        GQuark key_deriv_algo, enc_oid;
-       GBytes *params = NULL;
+       GNode *params = NULL;
        gcry_error_t gcry;
        int algo, mode;
 
@@ -879,7 +877,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password,
        *cih = NULL;
        ret = FALSE;
 
-       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBES2-params", data);
+       asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-5-PBES2-params");
        if (!asn)
                goto done;
 
@@ -910,7 +908,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password,
        }
 
        /* Read out the parameters */
-       params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL));
+       params = egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL);
        if (!params)
                goto done;
 
@@ -941,8 +939,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password,
                goto done;
        }
 
-       g_bytes_unref (params);
-       params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL));
+       params = egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL);
        if (!params)
                goto done;
 
@@ -954,8 +951,6 @@ done:
                *cih = NULL;
        }
 
-       if (params != NULL)
-               g_bytes_unref (params);
        egg_asn1x_destroy (asn);
        return ret;
 }
@@ -965,7 +960,7 @@ read_cipher_pkcs12_pbe (int cipher_algo,
                         int cipher_mode,
                         const gchar *password,
                         gsize n_password,
-                        GBytes *data,
+                        GNode *data,
                         gcry_cipher_hd_t *cih)
 {
        GNode *asn = NULL;
@@ -988,11 +983,11 @@ read_cipher_pkcs12_pbe (int cipher_algo,
        if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
                goto done;
 
-       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PbeParams", data);
+       asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-12-PbeParams");
        if (!asn)
                goto done;
 
-       salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL));
+       salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", NULL));
        if (!salt)
                goto done;
        if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
@@ -1037,7 +1032,7 @@ static gboolean
 read_mac_pkcs12_pbe (int hash_algo,
                      const gchar *password,
                      gsize n_password,
-                     GBytes *data,
+                     GNode *data,
                      gcry_md_hd_t *mdh,
                      gsize *digest_len)
 {
@@ -1060,14 +1055,17 @@ read_mac_pkcs12_pbe (int hash_algo,
        if (gcry_md_algo_info (hash_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
                goto done;
 
-       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-MacData", data);
-       if (!asn)
-               goto done;
+       if (egg_asn1x_type (data) == EGG_ASN1X_ANY) {
+               asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-12-MacData");
+               if (!asn)
+                       goto done;
+               data = asn;
+       }
 
-       salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "macSalt", NULL));
+       salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (data, "macSalt", NULL));
        if (!salt)
                goto done;
-       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
+       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (data, "iterations", NULL), &iterations))
                goto done;
 
        n_key = gcry_md_get_algo_dlen (hash_algo);
@@ -1107,7 +1105,7 @@ gboolean
 egg_symkey_read_cipher (GQuark oid_scheme,
                         const gchar *password,
                         gsize n_password,
-                        GBytes *data,
+                        GNode *data,
                         gcry_cipher_hd_t *cih)
 {
        gboolean ret = FALSE;
@@ -1175,7 +1173,7 @@ gboolean
 egg_symkey_read_mac (GQuark oid_scheme,
                      const gchar *password,
                      gsize n_password,
-                     GBytes *data,
+                     GNode *data,
                      gcry_md_hd_t *mdh,
                      gsize *digest_len)
 {
index 8498613..f4938f6 100644 (file)
@@ -77,13 +77,13 @@ gboolean                 egg_symkey_generate_pbkdf2             (int cipher_algo
 gboolean                 egg_symkey_read_cipher                 (GQuark oid_scheme,
                                                                  const gchar *password,
                                                                  gsize n_password,
-                                                                 GBytes *data,
+                                                                 GNode *params,
                                                                  gcry_cipher_hd_t *cih);
 
 gboolean                 egg_symkey_read_mac                    (GQuark oid_scheme,
                                                                  const gchar *password,
                                                                  gsize n_password,
-                                                                 GBytes *data,
+                                                                 GNode *params,
                                                                  gcry_md_hd_t *mdh,
                                                                  gsize *digest_len);
 
index e736f85..0f47a06 100644 (file)
@@ -22,6 +22,7 @@ LDADD =  \
 
 TEST_PROGS = \
        test-asn1 \
+       test-asn1x \
        test-dn \
        test-decimal \
        test-hex \
@@ -54,15 +55,3 @@ EXTRA_DIST = \
 
 CLEANFILES = \
        $(ASN_SRCS)
-
-# ------------------------------------------------------------------------------
-
-noinst_PROGRAMS = \
-       test-asn1x
-
-test_asn1x_SOURCES = \
-       test-asn1x.c
-
-test_asn1x_LDADD = \
-       $(top_builddir)/egg/libegg-asn1x.la \
-       $(LDADD)
index 60d5d8c..13ba718 100644 (file)
@@ -1 +1 @@
-1\17\80\aTuranga\81\ 5Leela\83\ 5Alien
\ No newline at end of file
+1\14\80\aTuranga\81\ 5Leela\83\ 2II
\ No newline at end of file
diff --git a/egg/tests/files/test-personalname-invalid.der b/egg/tests/files/test-personalname-invalid.der
new file mode 100644 (file)
index 0000000..60d5d8c
--- /dev/null
@@ -0,0 +1 @@
+1\17\80\aTuranga\81\ 5Leela\83\ 5Alien
\ No newline at end of file
diff --git a/egg/tests/files/test-pkcs12-2.der b/egg/tests/files/test-pkcs12-2.der
new file mode 100644 (file)
index 0000000..eff8c1e
Binary files /dev/null and b/egg/tests/files/test-pkcs12-2.der differ
index 95667de..1313099 100644 (file)
@@ -114,8 +114,7 @@ test_null (void)
 
        g_assert_cmpint (EGG_ASN1X_NULL, ==, egg_asn1x_type (asn));
 
-       if (!egg_asn1x_set_null (asn))
-               g_assert_not_reached ();
+       egg_asn1x_set_null (asn);
 
        data = egg_asn1x_encode (asn, g_realloc);
        egg_assert_cmpmem (NULL_TEST, XL (NULL_TEST), ==, g_bytes_get_data (data, NULL), g_bytes_get_size (data));
@@ -187,8 +186,7 @@ test_unsigned (void)
 
        egg_asn1x_clear (asn);
 
-       if (!egg_asn1x_set_integer_as_ulong (asn, 253))
-               g_assert_not_reached ();
+       egg_asn1x_set_integer_as_ulong (asn, 253);
 
        check = egg_asn1x_encode (asn, NULL);
        egg_assert_cmpmem (I253, XL (I253), ==, g_bytes_get_data (check, NULL), g_bytes_get_size (check));
@@ -533,9 +531,7 @@ test_bit_string_encode_decode_ulong (void)
        asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
        g_assert (asn);
 
-       if (!egg_asn1x_set_bits_as_ulong (asn, bits, n_bits))
-               g_assert_not_reached ();
-
+       egg_asn1x_set_bits_as_ulong (asn, bits, n_bits);
        data = egg_asn1x_encode (asn, NULL);
        g_assert (data);
 
@@ -584,10 +580,9 @@ test_have (void)
 
        g_assert (!egg_asn1x_have (asn));
 
-       if (!egg_asn1x_set_boolean (asn, TRUE))
-               g_assert_not_reached ();
+       egg_asn1x_set_boolean (asn, TRUE);
 
-       g_assert (!egg_asn1x_have (asn));
+       g_assert (egg_asn1x_have (asn));
 
        data = egg_asn1x_encode (asn, NULL);
        g_assert (data);
@@ -627,7 +622,7 @@ test_any_set_raw (void)
 
        bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH),
                                              test_is_freed, NULL);
-       if (!egg_asn1x_set_element_raw (node, bytes))
+       if (!egg_asn1x_set_any_raw (node, bytes))
                g_assert_not_reached ();
        g_bytes_unref (bytes);
 
@@ -653,7 +648,6 @@ test_any_set_raw_explicit (void)
        GBytes *bytes;
        GNode *asn, *node;
        GBytes *data;
-       GBytes *check;
 
        /* ENCODED SEQUENCE [89] ANY with OCTET STRING */
        const gchar SEQ_ENCODING[] =  "\x30\x0F\xBF\x59\x0C\x04\x0A""farnsworth";
@@ -666,7 +660,7 @@ test_any_set_raw_explicit (void)
        g_assert (node);
 
        bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), test_is_freed, NULL);
-       if (!egg_asn1x_set_element_raw (node, bytes))
+       if (!egg_asn1x_set_any_raw (node, bytes))
                g_assert_not_reached ();
        g_bytes_unref (bytes);
 
@@ -675,13 +669,7 @@ test_any_set_raw_explicit (void)
 
        egg_assert_cmpbytes (data, ==, SEQ_ENCODING, XL (SEQ_ENCODING));
 
-       check = egg_asn1x_get_element_raw (node);
-       g_assert (check);
-
-       egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH));
-
        g_bytes_unref (data);
-       g_bytes_unref (check);
        egg_asn1x_destroy (asn);
        g_assert (is_freed);
 }
@@ -702,7 +690,7 @@ test_choice_not_chosen (void)
        g_assert (node);
 
        bytes = g_bytes_new_static (SFARNSWORTH, XL (SFARNSWORTH));
-       if (!egg_asn1x_set_element_raw (node, bytes))
+       if (!egg_asn1x_set_any_raw (node, bytes))
                g_assert_not_reached ();
        g_bytes_unref (bytes);
 
@@ -736,7 +724,7 @@ perform_asn1_any_choice_set_raw (const gchar *choice, const gchar *encoding, gsi
                g_assert_not_reached ();
 
        bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), test_is_freed, NULL);
-       if (!egg_asn1x_set_element_raw (node, bytes))
+       if (!egg_asn1x_set_any_raw (node, bytes))
                g_assert_not_reached ();
        g_bytes_unref (bytes);
 
@@ -799,8 +787,7 @@ test_append (void)
        g_assert (child);
 
        /* Second integer is 2 */
-       if (!egg_asn1x_set_integer_as_ulong (child, 2))
-               g_assert_not_reached ();
+       egg_asn1x_set_integer_as_ulong (child, 2);
 
        data = egg_asn1x_encode (asn, NULL);
        g_assert (data != NULL);
@@ -822,12 +809,10 @@ test_append_and_clear (void)
 
        g_assert_cmpuint (egg_asn1x_count (asn), ==, 0);
 
-       if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 2))
-               g_assert_not_reached ();
-       if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 3))
-               g_assert_not_reached ();
+       egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 2);
+       egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 3);
 
-       g_assert_cmpuint (egg_asn1x_count (asn), ==, 0);
+       g_assert_cmpuint (egg_asn1x_count (asn), ==, 2);
 
        data = egg_asn1x_encode (asn, NULL);
        g_assert (data != NULL);
@@ -862,12 +847,10 @@ test_setof (void)
        g_assert_cmpint (EGG_ASN1X_SET_OF, ==, egg_asn1x_type (asn));
 
        /* Add integer 1, in SET OF DER should sort to front */
-       if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 1))
-               g_assert_not_reached ();
+       egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 1);
 
        /* Add integer 8, in SET OF DER should sort to back */
-       if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 8))
-               g_assert_not_reached ();
+       egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 8);
 
        data = egg_asn1x_encode (asn, NULL);
        if (data == NULL) {
@@ -924,8 +907,7 @@ test_enumerated (void)
        g_assert (value);
        g_assert_cmpstr (g_quark_to_string (value), ==, "valueTwo");
 
-       if (!egg_asn1x_set_enumerated (asn, g_quark_from_static_string ("valueThree")))
-               g_assert_not_reached ();
+       egg_asn1x_set_enumerated (asn, g_quark_from_static_string ("valueThree"));
 
        data = egg_asn1x_encode (asn, NULL);
        g_assert (data != NULL);
@@ -984,14 +966,9 @@ test_asn1_integers (Test* test, gconstpointer unused)
        asn = egg_asn1x_create (test_asn1_tab, "TestIntegers");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), 35);
-       g_assert ("couldn't write integer" && ret);
-
-       ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), 23456);
-       g_assert ("couldn't write integer" && ret);
-
-       ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), 209384022);
-       g_assert ("couldn't write integer" && ret);
+       egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), 35);
+       egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), 23456);
+       egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), 209384022);
 
        /* Now encode the whole caboodle */
        data = egg_asn1x_encode (asn, NULL);
@@ -1027,6 +1004,10 @@ test_boolean_seq (Test* test, gconstpointer unused)
        GNode *asn = NULL;
        gboolean value, ret;
 
+       /* The first boolean has a default of FALSE, so doesn't get encoded if FALSE */
+       const gchar SEQ_BOOLEAN_TRUE_FALSE[] = "\x30\x06\x01\x01\xFF\x01\x01\x00";
+       const gchar SEQ_BOOLEAN_FALSE_FALSE[] = "\x30\x03\x01\x01\x00";
+
        asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq");
        g_assert ("asn test structure is null" && asn != NULL);
 
@@ -1036,22 +1017,23 @@ test_boolean_seq (Test* test, gconstpointer unused)
        g_assert (ret == TRUE);
        g_assert (value == FALSE);
 
-       ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), TRUE);
-       g_assert (ret == TRUE);
+       egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), TRUE);
+       egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean2", NULL), FALSE);
 
        data = egg_asn1x_encode (asn, NULL);
        g_assert (data != NULL);
+       egg_assert_cmpbytes (data, ==, SEQ_BOOLEAN_TRUE_FALSE, XL (SEQ_BOOLEAN_TRUE_FALSE));
+       g_bytes_unref (data);
 
        ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
        g_assert (ret);
        g_assert (value == TRUE);
 
-       ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), FALSE);
-       g_assert (ret == TRUE);
+       egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), FALSE);
 
-       g_bytes_unref (data);
        data = egg_asn1x_encode (asn, NULL);
        g_assert (data != NULL);
+       egg_assert_cmpbytes (data, ==, SEQ_BOOLEAN_FALSE_FALSE, XL (SEQ_BOOLEAN_FALSE_FALSE));
 
        ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
        g_assert (ret);
@@ -1072,8 +1054,7 @@ test_write_value (Test* test, gconstpointer unused)
        asn = egg_asn1x_create (test_asn1_tab, "TestData");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
-               g_assert_not_reached ();
+       egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL);
 
        encoded = egg_asn1x_encode (asn, NULL);
        g_assert (encoded);
@@ -1100,8 +1081,7 @@ test_element_length_content (Test* test, gconstpointer unused)
        asn = egg_asn1x_create (test_asn1_tab, "TestData");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
-               g_assert_not_reached ();
+       egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL);
 
        buffer = egg_asn1x_encode (asn, NULL);
        g_assert (buffer != NULL);
@@ -1143,19 +1123,22 @@ test_read_element (Test* test, gconstpointer unused)
        asn = egg_asn1x_create (test_asn1_tab, "TestData");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
-               g_assert_not_reached ();
+       egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL);
 
        buffer = egg_asn1x_encode (asn, NULL);
        g_assert (buffer != NULL);
 
+       /* Have to decode before we can get raw elements */
+       if (!egg_asn1x_decode (asn, buffer))
+               g_assert_not_reached ();
+
        /* Now the real test */
        data = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "data", NULL));
        g_assert (data != NULL);
        g_assert_cmpint (g_bytes_get_size (data), ==, 11);
        g_bytes_unref (data);
 
-       data = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "data", NULL));
+       data = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "data", NULL));
        g_assert (data != NULL);
        egg_assert_cmpbytes (data, ==, "SOME DATA", 9);
        g_bytes_unref (data);
index 4581756..ad75e62 100644 (file)
@@ -32,6 +32,7 @@
 #include <unistd.h>
 
 #if 0
+#include <libtasn1.h>
 static void
 build_personal_name (void)
 {
@@ -39,7 +40,7 @@ build_personal_name (void)
        guchar buffer[10024];
        int res, len;
 
-       res = asn1_array2tree (pkix_asn1_tab, &asn1_pkix, NULL);
+       res = asn1_array2tree ((ASN1_ARRAY_TYPE*)pkix_asn1_tab, &asn1_pkix, NULL);
        g_assert (res == ASN1_SUCCESS);
 
        res = asn1_create_element (asn1_pkix, "PKIX1.PersonalName", &asn);
@@ -48,7 +49,7 @@ build_personal_name (void)
        asn1_write_value (asn, "surname", "Turanga", 7);
        asn1_write_value (asn, "given-name", "Leela", 5);
        asn1_write_value (asn, "initials", NULL, 0);
-       asn1_write_value (asn, "generation-qualifier", "Alien", 5);
+       asn1_write_value (asn, "generation-qualifier", "II", 2);
 
        len = sizeof (buffer);
        res = asn1_der_coding (asn, "", buffer, &len, NULL);
@@ -63,55 +64,136 @@ build_personal_name (void)
 }
 #endif
 
+typedef struct {
+       GBytes *data;
+} Test;
+
+typedef struct {
+       const EggAsn1xDef *defs;
+       const gchar *filename;
+       const gchar *identifier;
+} Fixture;
+
+static const Fixture parse_test_fixtures[] = {
+       { pkix_asn1_tab, SRCDIR "/files/test-certificate-1.der", "Certificate" },
+       { pkix_asn1_tab, SRCDIR "/files/test-pkcs8-1.der", "pkcs-8-PrivateKeyInfo" },
+       { pk_asn1_tab, SRCDIR "/files/test-rsakey-1.der", "RSAPrivateKey" },
+       { pkix_asn1_tab, SRCDIR "/files/test-personalname-1.der", "PersonalName" },
+       { pkix_asn1_tab, SRCDIR "/files/test-pkcs7-1.der", "pkcs-7-ContentInfo" },
+       { pkix_asn1_tab, SRCDIR "/files/test-pkcs7-2.der", "pkcs-7-ContentInfo" },
+};
+
+static void
+setup (Test *test,
+       gconstpointer data)
+{
+       const gchar *filename = data;
+       GError *error = NULL;
+       gchar *contents;
+       gsize length;
+
+       g_file_get_contents (filename, (gchar**)&contents, &length, &error);
+       g_assert_no_error (error);
+
+       test->data = g_bytes_new_take (contents, length);
+}
+
+static void
+setup_parsing (Test *test,
+               gconstpointer data)
+{
+       const Fixture *fixture = data;
+       setup (test, fixture->filename);
+}
+
 static void
-test_some_asn1_stuff (const EggAsn1xDef *defs,
-                      const gchar *file,
-                      const gchar *identifier)
+teardown (Test *test,
+          gconstpointer unused)
 {
+       g_bytes_unref (test->data);
+}
+
+static void
+test_decode_encode (Test *test,
+                    gconstpointer data)
+{
+       const Fixture *fixture = data;
        GNode *asn;
        GBytes *encoded;
-       gpointer data;
-       gsize n_data;
-       GBytes *bytes;
 
-       if (!g_file_get_contents (file, (gchar**)&data, &n_data, NULL))
-               g_assert_not_reached ();
-       bytes = g_bytes_new_take (data, n_data);
-       asn = egg_asn1x_create (defs, identifier);
-       egg_asn1x_dump (asn);
+       asn = egg_asn1x_create (fixture->defs, fixture->identifier);
 
-       if (!egg_asn1x_decode (asn, bytes))
-               g_warning ("decode of %s failed: %s", identifier, egg_asn1x_message (asn));
+       if (g_test_verbose ())
+               egg_asn1x_dump (asn);
+
+       if (!egg_asn1x_decode (asn, test->data)) {
+               g_warning ("decode of %s failed: %s", fixture->identifier,
+                          egg_asn1x_message (asn));
+               g_assert_not_reached ();
+       }
 
        encoded = egg_asn1x_encode (asn, NULL);
-       if (encoded == NULL)
-               g_warning ("encode of %s failed: %s", identifier, egg_asn1x_message (asn));
+       if (encoded == NULL) {
+               g_warning ("encode of %s failed: %s", fixture->identifier,
+                          egg_asn1x_message (asn));
+               g_assert_not_reached ();
+       }
 
        /* Decode the encoding */
-       if (!egg_asn1x_decode (asn, encoded))
-               g_warning ("decode of encoded %s failed: %s", identifier, egg_asn1x_message (asn));
+       if (!egg_asn1x_decode (asn, encoded)) {
+               g_warning ("decode of encoded %s failed: %s", fixture->identifier,
+                          egg_asn1x_message (asn));
+               g_assert_not_reached ();
+       }
 
        egg_asn1x_clear (asn);
        egg_asn1x_destroy (asn);
-       g_bytes_unref (bytes);
        g_bytes_unref (encoded);
 }
 
+static void
+test_pkcs12_decode (Test *test,
+                    gconstpointer unused)
+{
+       GNode *asn;
+
+       asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-12-PFX");
+
+       if (g_test_verbose ())
+               egg_asn1x_dump (asn);
+
+       if (!egg_asn1x_decode (asn, test->data)) {
+               g_warning ("decode of indefinite pkcs-12-PFX failed: %s",
+                          egg_asn1x_message (asn));
+               g_assert_not_reached ();
+       }
+
+       egg_asn1x_destroy (asn);
+}
+
 int
 main (int argc, char **argv)
 {
-       /* Build up a personal name, which is a set */
+       gchar *name;
+       gint i;
+
+       g_test_init (&argc, &argv, NULL);
+
 #if 0
+       /* Build up a personal name, which is a set */
        build_personal_name ();
 #endif
 
-       test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-certificate-1.der", "Certificate");
-       test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs8-1.der", "pkcs-8-PrivateKeyInfo");
-       test_some_asn1_stuff (pk_asn1_tab, SRCDIR "/files/test-rsakey-1.der", "RSAPrivateKey");
-       test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-personalname-1.der", "PersonalName");
-       test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs7-1.der", "pkcs-7-ContentInfo");
-       test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs7-2.der", "pkcs-7-ContentInfo");
-       test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs12-1.der", "pkcs-12-PFX");
+       for (i = 0; i < G_N_ELEMENTS (parse_test_fixtures); i++) {
+               name = g_strdup_printf ("/asn1x/encode-decode-%s", parse_test_fixtures[i].identifier);
+               g_test_add (name, Test, &parse_test_fixtures[i], setup_parsing, test_decode_encode, teardown);
+               g_free (name);
+       }
+
+       g_test_add ("/asn1x/pkcs12-decode/1", Test, SRCDIR "/files/test-pkcs12-1.der",
+                   setup, test_pkcs12_decode, teardown);
+       g_test_add ("/asn1x/pkcs12-decode/2", Test, SRCDIR "/files/test-pkcs12-2.der",
+                   setup, test_pkcs12_decode, teardown);
 
-       return 0;
+       return g_test_run ();
 }
index cf83dcb..6494679 100644 (file)
@@ -85,24 +85,30 @@ test_dn_value (Test* test, gconstpointer unused)
        const guchar value[] = { 0x13, 0x1a, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x43, 0x41 };
        gsize n_value = 28;
        GBytes *bytes;
+       GNode *asn;
        GQuark oid;
        gchar *text;
 
+       bytes = g_bytes_new_static (value, n_value);
+
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "AttributeValue", bytes);
+       g_assert (asn != NULL);
+
        /* Some printable strings */
        oid = g_quark_from_static_string ("2.5.4.3");
-       bytes = g_bytes_new_static (value, n_value);
-       text = egg_dn_print_value (oid, bytes);
-       g_bytes_unref (bytes);
+       text = egg_dn_print_value (oid, asn);
        g_assert_cmpstr (text, ==, "Thawte Personal Premium CA");
        g_free (text);
 
        /* Unknown oid */
        oid = g_quark_from_static_string ("1.1.1.1.1.1");
        bytes = g_bytes_new_static (value, n_value);
-       text = egg_dn_print_value (oid, bytes);
-       g_bytes_unref (bytes);
+       text = egg_dn_print_value (oid, asn);
        g_assert_cmpstr (text, ==, "#131A54686177746520506572736F6E616C205072656D69756D204341");
        g_free (text);
+
+       egg_asn1x_destroy (asn);
+       g_bytes_unref (bytes);
 }
 
 static int last_index = 0;
@@ -110,7 +116,7 @@ static int last_index = 0;
 static void
 concatenate_dn (guint index,
                 GQuark oid,
-                GBytes *value,
+                GNode *value,
                 gpointer user_data)
 {
        GString *dn = user_data;
@@ -118,7 +124,6 @@ concatenate_dn (guint index,
 
        g_assert (oid);
        g_assert (value != NULL);
-       g_assert (g_bytes_get_size (value) != 0);
 
        g_assert (index == last_index);
        ++last_index;
index 5412a63..0465328 100644 (file)
@@ -33,7 +33,8 @@ TestData ::= SEQUENCE {
 }
 
 TestBooleanSeq ::= SEQUENCE {
-       boolean                 BOOLEAN DEFAULT FALSE
+       boolean                 BOOLEAN DEFAULT FALSE,
+       boolean2                BOOLEAN
 }
 
 TestOid ::= SEQUENCE {
index ba16907..6b8033c 100644 (file)
@@ -56,7 +56,7 @@ _gcr_certificate_extension_find (GNode *cert,
                        }
 
                        /* Extension value */
-                       return egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL));
+                       return egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
                }
        }
 
@@ -172,28 +172,28 @@ general_name_parse_other (GNode *node, GcrGeneralName *general)
 {
        GNode *decode = NULL;
        GQuark oid;
-       GBytes *value;
+       GNode *any;
 
        general->type = GCR_GENERAL_NAME_OTHER;
        general->description = _("Other Name");
+       general->display = NULL;
 
        oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "type-id", NULL));
-       value = egg_asn1x_get_element_raw (egg_asn1x_node (node, "value", NULL));
+       any = egg_asn1x_node (node, "value", NULL);
 
-       if (value == NULL)
+       if (any == NULL)
                return;
 
        if (oid == GCR_OID_ALT_NAME_XMPP_ADDR) {
                general->description = _("XMPP Addr");
-               decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "UTF8String", value);
+               decode = egg_asn1x_get_any_as (any, pkix_asn1_tab, "UTF8String");
                general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
        } else if (oid == GCR_OID_ALT_NAME_DNS_SRV) {
                general->description = _("DNS SRV");
-               decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "IA5String", value);
+               decode = egg_asn1x_get_any_as (any, pkix_asn1_tab, "IA5String");
                general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
        }
 
-       g_bytes_unref (value);
        egg_asn1x_destroy (decode);
 }
 
index 631267c..d4e05f4 100644 (file)
@@ -789,7 +789,7 @@ typedef struct {
 static void
 on_parsed_dn_part (guint index,
                    GQuark oid,
-                   GBytes *value,
+                   GNode *value,
                    gpointer user_data)
 {
        GcrRenderer *renderer = ((AppendDnClosure *)user_data)->renderer;
@@ -935,7 +935,7 @@ _gcr_certificate_renderer_append_extension (GcrRenderer *renderer,
        g_return_if_fail (oid);
 
        /* Extension value */
-       value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL));
+       value = egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
 
        /* The custom parsers */
        if (oid == GCR_OID_BASIC_CONSTRAINTS)
index 81a510a..686ed06 100644 (file)
@@ -420,7 +420,7 @@ prepare_subject_public_key_and_mechanisms (GcrCertificateRequest *self,
        }
 
        node = egg_asn1x_node (self->asn, "certificationRequestInfo", "subjectPKInfo", NULL);
-       if (!egg_asn1x_set_element_raw (node, encoded))
+       if (!egg_asn1x_decode (node, encoded))
                g_return_val_if_reached (FALSE);
 
        g_bytes_unref (encoded);
@@ -434,7 +434,6 @@ encode_take_signature_into_request (GcrCertificateRequest *self,
                                     guchar *result,
                                     gsize n_result)
 {
-       GBytes *data;
        GNode *params;
        GNode *node;
 
@@ -446,9 +445,7 @@ encode_take_signature_into_request (GcrCertificateRequest *self,
 
        node = egg_asn1x_node (self->asn, "signatureAlgorithm", "parameters", NULL);
        params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
-       data = egg_asn1x_encode (params, NULL);
-       egg_asn1x_set_element_raw (node, data);
-       g_bytes_unref (data);
+       egg_asn1x_set_any_from (node, params);
 }
 
 /**
index 0dc32b7..b617a24 100644 (file)
@@ -566,7 +566,7 @@ done:
 static gint
 parse_der_private_key_dsa_parts (GcrParser *self,
                                  GBytes *keydata,
-                                 GBytes *params)
+                                 GNode *params)
 {
        gint ret = GCR_ERROR_UNRECOGNIZED;
        GNode *asn_params = NULL;
@@ -575,7 +575,7 @@ parse_der_private_key_dsa_parts (GcrParser *self,
 
        parsed = push_parsed (self, TRUE);
 
-       asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
+       asn_params = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
        asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata);
        if (!asn_params || !asn_key)
                goto done;
@@ -629,7 +629,7 @@ static gint
 handle_subject_public_key_rsa (GcrParser *self,
                                GcrParsed *parsed,
                                GBytes *key,
-                               GBytes *params)
+                               GNode *params)
 {
        gint res = GCR_ERROR_FAILURE;
        GNode *asn = NULL;
@@ -656,14 +656,14 @@ static gint
 handle_subject_public_key_dsa (GcrParser *self,
                                GcrParsed *parsed,
                                GBytes *key,
-                               GBytes *params)
+                               GNode *params)
 {
        gint res = GCR_ERROR_FAILURE;
        GNode *key_asn = NULL;
        GNode *param_asn = NULL;
 
        key_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicPart", key);
-       param_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
+       param_asn = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
 
        if (!key_asn || !param_asn)
                goto done;
@@ -690,7 +690,7 @@ parse_der_subject_public_key (GcrParser *self,
                               GBytes *data)
 {
        GcrParsed *parsed;
-       GBytes *params;
+       GNode *params;
        GBytes *key;
        GNode *asn = NULL;
        GNode *node;
@@ -708,8 +708,7 @@ parse_der_subject_public_key (GcrParser *self,
        node = egg_asn1x_node (asn, "algorithm", "algorithm", NULL);
        oid = egg_asn1x_get_oid_as_quark (node);
 
-       node = egg_asn1x_node (asn, "algorithm", "parameters", NULL);
-       params = egg_asn1x_get_element_raw (node);
+       params = egg_asn1x_node (asn, "algorithm", "parameters", NULL);
 
        node = egg_asn1x_node (asn, "subjectPublicKey", NULL);
        key = egg_asn1x_get_bits_as_raw (node, &bits);
@@ -724,7 +723,6 @@ parse_der_subject_public_key (GcrParser *self,
                ret = GCR_ERROR_UNRECOGNIZED;
 
        g_bytes_unref (key);
-       g_bytes_unref (params);
 
        if (ret == SUCCESS)
                parsed_fire (self, parsed);
@@ -747,7 +745,7 @@ parse_der_pkcs8_plain (GcrParser *self,
        CK_KEY_TYPE key_type;
        GQuark key_algo;
        GBytes *keydata = NULL;
-       GBytes *params = NULL;
+       GNode *params = NULL;
        GNode *asn = NULL;
        GcrParsed *parsed;
 
@@ -775,11 +773,11 @@ parse_der_pkcs8_plain (GcrParser *self,
                goto done;
        }
 
-       keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL));
+       keydata = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL));
        if (!keydata)
                goto done;
 
-       params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL));
+       params = egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL);
 
        ret = SUCCESS;
 
@@ -809,8 +807,6 @@ done:
 
        if (keydata)
                g_bytes_unref (keydata);
-       if (params)
-               g_bytes_unref (params);
        egg_asn1x_destroy (asn);
        pop_parsed (self, parsed);
        return ret;
@@ -827,7 +823,7 @@ parse_der_pkcs8_encrypted (GcrParser *self,
        gint ret, r;
        GQuark scheme;
        guchar *crypted = NULL;
-       GBytes *params = NULL;
+       GNode *params = NULL;
        GBytes *cbytes;
        gsize n_crypted;
        const gchar *password;
@@ -849,7 +845,7 @@ parse_der_pkcs8_encrypted (GcrParser *self,
        if (!scheme)
                goto done;
 
-       params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL));
+       params = egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL);
 
        /* Loop to try different passwords */
        for (;;) {
@@ -901,8 +897,6 @@ parse_der_pkcs8_encrypted (GcrParser *self,
        }
 
 done:
-       if (params)
-               g_bytes_unref (params);
        if (cih)
                gcry_cipher_close (cih);
        egg_asn1x_destroy (asn);
@@ -977,7 +971,7 @@ parse_der_certificate (GcrParser *self,
 
 static gint
 handle_pkcs7_signed_data (GcrParser *self,
-                          GBytes *data)
+                          GNode *content)
 {
        GNode *asn = NULL;
        GNode *node;
@@ -987,7 +981,7 @@ handle_pkcs7_signed_data (GcrParser *self,
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data);
+       asn = egg_asn1x_get_any_as (content, pkix_asn1_tab, "pkcs-7-SignedData");
        if (!asn)
                goto done;
 
@@ -1023,7 +1017,7 @@ parse_der_pkcs7 (GcrParser *self,
        GNode *asn = NULL;
        GNode *node;
        gint ret;
-       GBytes *content = NULL;
+       GNode *content = NULL;
        GQuark oid;
        GcrParsed *parsed;
 
@@ -1050,15 +1044,13 @@ parse_der_pkcs7 (GcrParser *self,
                goto done;
        }
 
-       content = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "content", NULL));
+       content = egg_asn1x_node (asn, "content", NULL);
        if (!content)
                goto done;
 
        ret = handle_pkcs7_signed_data (self, content);
 
 done:
-       if (content)
-               g_bytes_unref (content);
        egg_asn1x_destroy (asn);
        pop_parsed (self, parsed);
        return ret;
@@ -1068,37 +1060,6 @@ done:
  * PKCS12
  */
 
-static GNode *
-decode_pkcs12_asn1_accepting_invalid_crap (const EggAsn1xDef *defs,
-                                           const gchar *identifier,
-                                           GBytes *data)
-{
-       GNode *asn;
-
-       /*
-        * Because PKCS#12 files, the bags specifically, are notorious for
-        * being crappily constructed and are often break rules such as DER
-        * sorting order etc.. we parse the DER in a non-strict fashion.
-        *
-        * The rules in DER are designed for X.509 certificates, so there is
-        * only one way to represent a given certificate (although they fail
-        * at that as well). But with PKCS#12 we don't have such high
-        * requirements, and we can slack off on our validation.
-        */
-
-       asn = egg_asn1x_create (defs, identifier);
-       g_return_val_if_fail (asn != NULL, NULL);
-
-       /* Passing FALSE as the strictness argument */
-       if (!egg_asn1x_decode_no_validate (asn, data) ||
-           !egg_asn1x_validate (asn, FALSE)) {
-               egg_asn1x_destroy (asn);
-               asn = NULL;
-       }
-
-       return asn;
-}
-
 static gint
 handle_pkcs12_cert_bag (GcrParser *self,
                         GBytes *data)
@@ -1106,25 +1067,24 @@ handle_pkcs12_cert_bag (GcrParser *self,
        GNode *asn = NULL;
        GNode *asn_content = NULL;
        guchar *certificate = NULL;
-       GBytes *element = NULL;
+       GNode *element = NULL;
        gsize n_certificate;
        GBytes *bytes;
        gint ret;
 
        ret = GCR_ERROR_UNRECOGNIZED;
-       asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
-                                                        "pkcs-12-CertBag",
-                                                        data);
+       asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-CertBag",
+                                               data, EGG_ASN1X_NO_STRICT);
        if (!asn)
                goto done;
 
        ret = GCR_ERROR_FAILURE;
 
-       element = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "certValue", NULL));
+       element = egg_asn1x_node (asn, "certValue", NULL);
        if (!element)
                goto done;
 
-       asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element);
+       asn_content = egg_asn1x_get_any_as (element, pkix_asn1_tab, "pkcs-7-Data");
        if (!asn_content)
                goto done;
 
@@ -1137,8 +1097,6 @@ handle_pkcs12_cert_bag (GcrParser *self,
        g_bytes_unref (bytes);
 
 done:
-       if (element)
-               g_bytes_unref (element);
        egg_asn1x_destroy (asn_content);
        egg_asn1x_destroy (asn);
        return ret;
@@ -1150,7 +1108,6 @@ parse_pkcs12_bag_friendly_name (GNode *asn)
        guint count, i;
        GQuark oid;
        GNode *node;
-       GBytes *element;
        GNode *asn_str;
        gchar *result;
 
@@ -1163,10 +1120,7 @@ parse_pkcs12_bag_friendly_name (GNode *asn)
                if (oid == GCR_OID_PKCS9_ATTRIBUTE_FRIENDLY) {
                        node = egg_asn1x_node (asn, i, "values", 1, NULL);
                        if (node != NULL) {
-                               element = egg_asn1x_get_element_raw (node);
-                               asn_str = egg_asn1x_create_and_decode (pkix_asn1_tab, "BMPString",
-                                                                      element);
-                               g_bytes_unref (element);
+                               asn_str = egg_asn1x_get_any_as (node, pkix_asn1_tab, "BMPString");
                                if (asn_str) {
                                        result = egg_asn1x_get_bmpstring_as_utf8 (asn_str);
                                        egg_asn1x_destroy (asn_str);
@@ -1187,6 +1141,7 @@ handle_pkcs12_bag (GcrParser *self,
        gint ret, r;
        guint count = 0;
        GQuark oid;
+       GNode *value;
        GBytes *element = NULL;
        gchar *friendly;
        guint i;
@@ -1194,9 +1149,8 @@ handle_pkcs12_bag (GcrParser *self,
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
-                                                        "pkcs-12-SafeContents",
-                                                        data);
+       asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-SafeContents",
+                                               data, EGG_ASN1X_NO_STRICT);
        if (!asn)
                goto done;
 
@@ -1215,10 +1169,11 @@ handle_pkcs12_bag (GcrParser *self,
                if (!oid)
                        goto done;
 
-               element = egg_asn1x_get_element_raw (egg_asn1x_node (asn, i, "bagValue", NULL));
-               if (!element)
+               value = egg_asn1x_node (asn, i, "bagValue", NULL);
+               if (!value)
                        goto done;
 
+               element = egg_asn1x_get_element_raw (value);
                parsed = push_parsed (self, FALSE);
 
                friendly = parse_pkcs12_bag_friendly_name (egg_asn1x_node (asn, i, "bagAttributes", NULL));
@@ -1266,14 +1221,14 @@ done:
 
 static gint
 handle_pkcs12_encrypted_bag (GcrParser *self,
-                             GBytes *data)
+                             GNode *bag)
 {
        PasswordState pstate = PASSWORD_STATE_INIT;
        GNode *asn = NULL;
        gcry_cipher_hd_t cih = NULL;
        gcry_error_t gcry;
        guchar *crypted = NULL;
-       GBytes *params = NULL;
+       GNode *params = NULL;
        gsize n_crypted;
        const gchar *password;
        GBytes *cbytes;
@@ -1283,9 +1238,8 @@ handle_pkcs12_encrypted_bag (GcrParser *self,
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
-                                                        "pkcs-7-EncryptedData",
-                                                        data);
+       asn = egg_asn1x_get_any_as_full (bag, pkix_asn1_tab, "pkcs-7-EncryptedData",
+                                        EGG_ASN1X_NO_STRICT);
        if (!asn)
                goto done;
 
@@ -1296,7 +1250,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self,
        if (!scheme)
                goto done;
 
-       params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL));
+       params = egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL);
        if (!params)
                goto done;
 
@@ -1352,8 +1306,6 @@ handle_pkcs12_encrypted_bag (GcrParser *self,
        }
 
 done:
-       if (params)
-               g_bytes_unref (params);
        if (cih)
                gcry_cipher_close (cih);
        egg_asn1x_destroy (asn);
@@ -1368,7 +1320,7 @@ handle_pkcs12_safe (GcrParser *self,
        GNode *asn = NULL;
        GNode *asn_content = NULL;
        gint ret, r;
-       GBytes *bag = NULL;
+       GNode *bag;
        GBytes *content;
        GQuark oid;
        guint i;
@@ -1376,9 +1328,8 @@ handle_pkcs12_safe (GcrParser *self,
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
-                                                        "pkcs-12-AuthenticatedSafe",
-                                                        data);
+       asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-AuthenticatedSafe",
+                                               data, EGG_ASN1X_NO_STRICT);
        if (!asn)
                goto done;
 
@@ -1396,20 +1347,16 @@ handle_pkcs12_safe (GcrParser *self,
 
                oid = egg_asn1x_get_oid_as_quark (node);
 
-               node = egg_asn1x_node (asn, i + 1, "content", NULL);
-               if (!node)
+               bag = egg_asn1x_node (asn, i + 1, "content", NULL);
+               if (!bag)
                        goto done;
 
-               bag = egg_asn1x_get_element_raw (node);
-               g_return_val_if_fail (bag != NULL, ret);
-
                /* A non encrypted bag, just parse */
                if (oid == GCR_OID_PKCS7_DATA) {
 
                        egg_asn1x_destroy (asn_content);
-                       asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
-                                                                                "pkcs-7-Data",
-                                                                                bag);
+                       asn_content = egg_asn1x_get_any_as_full (bag, pkix_asn1_tab,
+                                                                "pkcs-7-Data", EGG_ASN1X_NO_STRICT);
                        if (!asn_content)
                                goto done;
 
@@ -1430,9 +1377,6 @@ handle_pkcs12_safe (GcrParser *self,
                        r = GCR_ERROR_UNRECOGNIZED;
                }
 
-               g_bytes_unref (bag);
-               bag = NULL;
-
                if (r == GCR_ERROR_FAILURE ||
                    r == GCR_ERROR_CANCELLED ||
                    r == GCR_ERROR_LOCKED) {
@@ -1444,8 +1388,6 @@ handle_pkcs12_safe (GcrParser *self,
        ret = SUCCESS;
 
 done:
-       if (bag != NULL)
-               g_bytes_unref (bag);
        egg_asn1x_destroy (asn);
        egg_asn1x_destroy (asn_content);
        return ret;
@@ -1465,7 +1407,6 @@ verify_pkcs12_safe (GcrParser *self,
        gsize n_digest;
        GQuark algorithm;
        GNode *mac_data;
-       GBytes *params = NULL;
        int ret, r;
 
        ret = GCR_ERROR_FAILURE;
@@ -1484,10 +1425,6 @@ verify_pkcs12_safe (GcrParser *self,
        if (!algorithm)
                goto done;
 
-       params = egg_asn1x_get_element_raw (mac_data);
-       if (!params)
-               goto done;
-
        digest = egg_asn1x_get_string_as_raw (egg_asn1x_node (mac_data, "mac", "digest", NULL), NULL, &n_digest);
        if (!digest)
                goto done;
@@ -1503,7 +1440,7 @@ verify_pkcs12_safe (GcrParser *self,
                }
 
                /* Parse the encryption stuff into a cipher. */
-               if (!egg_symkey_read_mac (algorithm, password, -1, params, &mdh, &mac_len)) {
+               if (!egg_symkey_read_mac (algorithm, password, -1, mac_data, &mdh, &mac_len)) {
                        ret = GCR_ERROR_FAILURE;
                        goto done;
                }
@@ -1529,8 +1466,6 @@ verify_pkcs12_safe (GcrParser *self,
        }
 
 done:
-       if (params)
-               g_bytes_unref (params);
        if (mdh)
                gcry_md_close (mdh);
        g_free (digest);
@@ -1543,17 +1478,28 @@ parse_der_pkcs12 (GcrParser *self,
                   GBytes *data)
 {
        GNode *asn = NULL;
-       GNode *asn_content = NULL;
        gint ret;
-       GBytes *element = NULL;
-       GBytes *content = NULL;
+       GNode *content = NULL;
+       GBytes *string = NULL;
        GQuark oid;
        GcrParsed *parsed;
 
        parsed = push_parsed (self, FALSE);
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-12-PFX", data);
+       /*
+        * Because PKCS#12 files, the bags specifically, are notorious for
+        * being crappily constructed and are often break rules such as DER
+        * sorting order etc.. we parse the DER in a non-strict fashion.
+        *
+        * The rules in DER are designed for X.509 certificates, so there is
+        * only one way to represent a given certificate (although they fail
+        * at that as well). But with PKCS#12 we don't have such high
+        * requirements, and we can slack off on our validation.
+        */
+
+       asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-PFX",
+                                               data, EGG_ASN1X_NO_STRICT);
        if (!asn)
                goto done;
 
@@ -1569,28 +1515,24 @@ parse_der_pkcs12 (GcrParser *self,
                goto done;
        }
 
-       element = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "authSafe", "content", NULL));
-       if (!element)
-               goto done;
-
-       asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-7-Data", element);
-       if (!asn_content)
+       content = egg_asn1x_get_any_as (egg_asn1x_node (asn, "authSafe", "content", NULL),
+                                       pkix_asn1_tab, "pkcs-7-Data");
+       if (!content)
                goto done;
 
-       content = egg_asn1x_get_string_as_bytes (asn_content);
-       if (!content)
+       string = egg_asn1x_get_string_as_bytes (content);
+       if (!string)
                goto done;
 
-       ret = verify_pkcs12_safe (self, asn, content);
+       ret = verify_pkcs12_safe (self, asn, string);
        if (ret == SUCCESS)
-               ret = handle_pkcs12_safe (self, content);
+               ret = handle_pkcs12_safe (self, string);
 
 done:
-       if (element)
-               g_bytes_unref (element);
        if (content)
-               g_bytes_unref (content);
-       egg_asn1x_destroy (asn_content);
+               egg_asn1x_destroy (content);
+       if (string)
+               g_bytes_unref (string);
        egg_asn1x_destroy (asn);
        pop_parsed (self, parsed);
        return ret;
index f41b127..46c8d42 100644 (file)
@@ -528,7 +528,6 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs,
        GNode *key_asn;
        GNode *params_asn;
        GBytes *key;
-       GBytes *params;
        GBytes *usg;
 
        _gcr_oids_init ();
@@ -562,17 +561,14 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs,
 
        egg_asn1x_set_null (params_asn);
 
-       params = egg_asn1x_encode (params_asn, g_realloc);
-       egg_asn1x_destroy (params_asn);
-
        egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
                                   key, g_bytes_get_size (key) * 8);
 
        egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA);
-       egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
+       egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
 
+       egg_asn1x_destroy (params_asn);
        g_bytes_unref (key);
-       g_bytes_unref (params);
        return TRUE;
 }
 
@@ -627,7 +623,6 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
        const GckAttribute *value, *g, *q, *p;
        GNode *key_asn, *params_asn;
        GBytes *key;
-       GBytes *params;
 
        _gcr_oids_init ();
 
@@ -680,17 +675,14 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
        key = egg_asn1x_encode (key_asn, NULL);
        egg_asn1x_destroy (key_asn);
 
-       params = egg_asn1x_encode (params_asn, NULL);
-       egg_asn1x_destroy (params_asn);
-
        egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
                                   key, g_bytes_get_size (key) * 8);
-       egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
+       egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
 
        egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA);
 
        g_bytes_unref (key);
-       g_bytes_unref (params);
+       egg_asn1x_destroy (params_asn);
        return TRUE;
 }
 
@@ -785,7 +777,7 @@ calculate_rsa_key_size (GBytes *data)
        asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
        g_return_val_if_fail (asn, 0);
 
-       content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL));
+       content = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "modulus", NULL));
        if (!content)
                g_return_val_if_reached (0);
 
@@ -799,16 +791,16 @@ calculate_rsa_key_size (GBytes *data)
 }
 
 static guint
-calculate_dsa_params_size (GBytes *data)
+calculate_dsa_params_size (GNode *params)
 {
        GNode *asn;
        GBytes *content;
        guint key_size;
 
-       asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data);
+       asn = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
        g_return_val_if_fail (asn, 0);
 
-       content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL));
+       content = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "p", NULL));
        if (!content)
                g_return_val_if_reached (0);
 
@@ -825,6 +817,7 @@ guint
 _gcr_subject_public_key_calculate_size (GNode *subject_public_key)
 {
        GBytes *key;
+       GNode *params;
        guint key_size = 0;
        guint n_bits;
        GQuark oid;
@@ -843,9 +836,8 @@ _gcr_subject_public_key_calculate_size (GNode *subject_public_key)
 
        /* The DSA key size is discovered by the prime in params */
        } else if (oid == GCR_OID_PKIX1_DSA) {
-               key = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL));
-               key_size = calculate_dsa_params_size (key);
-               g_bytes_unref (key);
+               params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
+               key_size = calculate_dsa_params_size (params);
 
        } else {
                g_message ("unsupported key algorithm: %s", g_quark_to_string (oid));
diff --git a/gcr/tests/files/usr0052-firefox.p12 b/gcr/tests/files/usr0052-firefox.p12
new file mode 100644 (file)
index 0000000..eff8c1e
Binary files /dev/null and b/gcr/tests/files/usr0052-firefox.p12 differ
index b022fe3..18164a0 100644 (file)
@@ -124,6 +124,9 @@ authenticate (GcrParser *par, gint state, gpointer user_data)
        case 0:
                gcr_parser_add_password (test->parser, "booo");
                return TRUE;
+       case 1:
+               gcr_parser_add_password (test->parser, "usr0052");
+               return TRUE;
        default:
                g_printerr ("decryption didn't work for: %s", test->filedesc);
                g_assert_not_reached ();