[gnome-keyring] Use new DER decoding and encoding routines.



commit 8d7e551b8575e4916542f17ba3a5185816400f0e
Author: Stef Walter <stef memberwebs com>
Date:   Fri Jul 9 16:57:20 2010 +0000

    Use new DER decoding and encoding routines.
    
     * Benefits are less copies of sensitive data in memory.
     * More insightful parsing and API.

 egg/.gitignore                           |    2 +-
 egg/Makefile.am                          |   19 +-
 egg/egg-asn1-defs.h                      |   32 +
 egg/egg-asn1.c                           |  817 --------------------------
 egg/egg-asn1.h                           |   80 ---
 egg/egg-asn1x.c                          |  921 +++++++++++++++++++++++++++---
 egg/egg-asn1x.h                          |   79 +++-
 egg/egg-dn.c                             |  179 +++----
 egg/egg-dn.h                             |   29 +-
 egg/egg-symkey.c                         |  166 +++---
 egg/tests/Makefile.am                    |   13 +-
 egg/tests/test-asn1.c                    |  229 +++++++-
 egg/tests/test-asn1x.c                   |    6 +-
 egg/tests/test-data/test-pkcs7-2.der     |  Bin 0 -> 1002 bytes
 egg/tests/test-dn.c                      |   45 +-
 egg/tests/test.asn                       |   29 +-
 egg/tests/tests.asn                      |   19 -
 egg/tests/unit-test-asn1.c               |  341 ++++++-----
 gcr/gcr-certificate-details-widget.c     |  122 ++--
 gcr/gcr-certificate.c                    |  107 ++--
 gcr/gcr-parser.c                         |  414 +++++++-------
 gcr/gcr-simple-certificate.c             |    1 -
 pkcs11/gkm/gkm-certificate-trust.c       |    2 +-
 pkcs11/gkm/gkm-certificate.c             |   66 +--
 pkcs11/gkm/gkm-data-asn1.c               |   48 +--
 pkcs11/gkm/gkm-data-asn1.h               |    9 +-
 pkcs11/gkm/gkm-data-der.c                |  449 +++++++--------
 pkcs11/gkm/gkm-data-der.h                |   11 +-
 pkcs11/gkm/tests/unit-test-data-asn1.c   |   51 +--
 pkcs11/gkm/tests/unit-test-data-der.c    |   65 ++-
 pkcs11/ssh-store/gkm-ssh-openssh.c       |    3 +-
 pkcs11/user-store/gkm-user-private-key.c |   17 +-
 pkcs11/user-store/gkm-user-storage.c     |   10 +-
 po/POTFILES.in                           |    1 -
 34 files changed, 2225 insertions(+), 2157 deletions(-)
---
diff --git a/egg/.gitignore b/egg/.gitignore
index 7061f83..2d6c41b 100644
--- a/egg/.gitignore
+++ b/egg/.gitignore
@@ -1,3 +1,3 @@
-asn1-def-*.h
+asn1-def-*.[ch]
 /tests/test-asn1x
 
diff --git a/egg/Makefile.am b/egg/Makefile.am
index e47c560..527d80e 100644
--- a/egg/Makefile.am
+++ b/egg/Makefile.am
@@ -10,7 +10,7 @@ noinst_LTLIBRARIES = \
 	libegg-entry-buffer.la
 
 BUILT_SOURCES = \
-	asn1-def-pk.h asn1-def-pkix.h
+	asn1-def-pk.c asn1-def-pkix.c
 
 INCLUDES = \
 	-I$(top_srcdir) 
@@ -21,7 +21,6 @@ libegg_la_CFLAGS = \
 	$(GLIB_CFLAGS)
 
 libegg_la_SOURCES = \
-	egg-asn1.c egg-asn1.h \
 	egg-asn1x.c egg-asn1x.h \
 	egg-buffer.c egg-buffer.h \
 	egg-cleanup.c egg-cleanup.h \
@@ -38,13 +37,14 @@ libegg_la_SOURCES = \
 	egg-secure-memory.c egg-secure-memory.h \
 	egg-spawn.c egg-spawn.h \
 	egg-symkey.c egg-symkey.h \
+	egg-asn1-defs.h \
 	$(BUILT_SOURCES)
-	
-asn1-def-pk.h: pk.asn
-	$(ASN1PARSER) -o asn1-def-pk.h $(srcdir)/pk.asn 
-	
-asn1-def-pkix.h: pkix.asn
-	$(ASN1PARSER) -o asn1-def-pkix.h $(srcdir)/pkix.asn 
+
+asn1-def-pk.c: pk.asn
+	$(ASN1PARSER) -o asn1-def-pk.c $(srcdir)/pk.asn
+
+asn1-def-pkix.c: pkix.asn
+	$(ASN1PARSER) -o asn1-def-pkix.c $(srcdir)/pkix.asn
 
 EXTRA_DIST = \
 	pkix.asn \
@@ -57,7 +57,8 @@ DISTCLEANFILES = \
 # COMMON STUFF COMPILED INTO SMALLER COMPONENTS
 
 libegg_asn1x_la_SOURCES = \
-	egg-asn1x.c egg-asn1x.h
+	egg-asn1x.c egg-asn1x.h \
+	$(BUILT_SOURCES)
 
 libegg_asn1x_la_CFLAGS = \
 	$(LIBTASN1_CFLAGS) \
diff --git a/egg/egg-asn1-defs.h b/egg/egg-asn1-defs.h
new file mode 100644
index 0000000..02fe427
--- /dev/null
+++ b/egg/egg-asn1-defs.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-asn1-defs.h - ASN.1 definitions
+
+   Copyright (C) 2010 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef EGG_ASN1_DEFS_H_
+#define EGG_ASN1_DEFS_H_
+
+#include <libtasn1.h>
+
+extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
+extern const ASN1_ARRAY_TYPE pk_asn1_tab[];
+
+#endif /*EGG_ASN1_DEFS_H_*/
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index 1c71e8f..3a46ddf 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -86,11 +86,11 @@ typedef struct _Aenc Aenc;
 typedef struct _Atlv Atlv;
 typedef struct _Anode Anode;
 typedef struct _Abuf Abuf;
+typedef struct _Abits Abits;
 
 struct _Aenc {
 	EggAsn1xEncoder encoder;
-	gpointer user_data;
-	GDestroyNotify destroy;
+	gpointer data;
 };
 
 struct _Atlv {
@@ -109,6 +109,8 @@ struct _Anode {
 	GList *opts;
 	Atlv *tlv;
 	Aenc *enc;
+	gpointer user_data;
+	GDestroyNotify destroy;
 	gchar* failure;
 };
 
@@ -118,6 +120,12 @@ struct _Abuf {
 	gpointer user_data;
 };
 
+struct _Abits {
+	guint n_bits;
+	guchar *bits;
+	GDestroyNotify destroy;
+};
+
 /* Forward Declarations */
 static gboolean anode_decode_anything (GNode*, Atlv*);
 static gboolean anode_decode_anything_for_flags (GNode *, Atlv*, gint);
@@ -229,7 +237,7 @@ anode_def_value (GNode *node)
 }
 
 static gulong
-anode_def_value_as_ulong (ASN1_ARRAY_TYPE *def)
+anode_def_value_as_ulong (const ASN1_ARRAY_TYPE *def)
 {
 	gchar *end = NULL;
 	gulong lval;
@@ -342,23 +350,31 @@ anode_clr_enc_data (GNode *node)
 {
 	Anode *an = node->data;
 	if (an->enc) {
-		if (an->enc->destroy)
-			(an->enc->destroy) (an->enc->user_data);
 		g_slice_free (Aenc, an->enc);
 		an->enc = NULL;
 	}
 }
 
 static void
-anode_set_enc_data (GNode *node, EggAsn1xEncoder encoder,
-                    gpointer user_data, GDestroyNotify destroy)
+anode_set_enc_data (GNode *node, EggAsn1xEncoder encoder, gpointer enc_data)
 {
 	Anode *an = node->data;
 	g_assert (!an->enc);
 	an->enc = g_slice_new0 (Aenc);
 	an->enc->encoder = encoder;
-	an->enc->user_data = user_data;
-	an->enc->destroy = destroy;
+	an->enc->data = enc_data;
+}
+
+static void
+anode_set_user_data (GNode *node, gpointer user_data, GDestroyNotify destroy)
+{
+	Anode *an;
+	g_assert (node && node->data);
+	an = node->data;
+	if (an->destroy)
+		(an->destroy) (an->user_data);
+	an->user_data = user_data;
+	an->destroy = destroy;
 }
 
 static Aenc*
@@ -384,7 +400,7 @@ anode_failure (GNode *node, const gchar *failure)
 
 	g_free (an->failure);
 	an->failure = g_strdup_printf ("%s: %s", prefix, failure);
-	return FALSE; /* So this can be changed */
+	return FALSE; /* So this can be chained */
 }
 
 static const gchar*
@@ -400,6 +416,7 @@ anode_clear (GNode *node)
 	Anode *an = node->data;
 	anode_clr_tlv_data (node);
 	anode_clr_enc_data (node);
+	anode_set_user_data (node, NULL, NULL);
 	g_free (an->failure);
 	an->failure = NULL;
 }
@@ -415,6 +432,16 @@ anode_free_func (GNode *node, gpointer unused)
 }
 
 static void
+abits_destroy (gpointer data)
+{
+	Abits *ab = data;
+	g_assert (ab);
+	if (ab->destroy)
+		(ab->destroy) (ab->bits);
+	g_slice_free (Abits, ab);
+}
+
+static void
 anode_destroy (GNode *node)
 {
 	if (!G_NODE_IS_ROOT (node))
@@ -494,6 +521,25 @@ anode_calc_tag (GNode *node)
 	return anode_calc_tag_for_flags (node, anode_def_flags (node));
 }
 
+static gboolean
+anode_calc_explicit_for_flags (GNode *node, gint flags)
+{
+	const ASN1_ARRAY_TYPE *opt;
+	if ((flags & FLAG_TAG) != FLAG_TAG)
+		return FALSE;
+	opt = anode_opt_lookup (node, TYPE_TAG, NULL);
+	g_return_val_if_fail (opt, FALSE);
+	if ((opt->type & FLAG_IMPLICIT) == FLAG_IMPLICIT)
+		return FALSE;
+	return TRUE;
+}
+
+static gboolean
+anode_calc_explicit (GNode *node)
+{
+	return anode_calc_explicit_for_flags (node, anode_def_flags (node));
+}
+
 /* -------------------------------------------------------------------------
  * DECODE
  */
@@ -801,7 +847,7 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 	end = tlv->end;
 
 	/* An explicit, wrapped tag */
-	if (flags & FLAG_TAG && !(flags & FLAG_IMPLICIT)) {
+	if (anode_calc_explicit_for_flags (node, flags)) {
 		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))
@@ -820,8 +866,6 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 
 	/* Other structured types */
 	} else {
-		if ((tlv->cls & ASN1_CLASS_CONTEXT_SPECIFIC) != 0)
-			return anode_failure (node, "invalid context specific tag");
 		switch (anode_def_type (node)) {
 		case TYPE_ANY:
 			if (!anode_decode_struct_any (node, tlv))
@@ -886,16 +930,8 @@ anode_decode_anything_for_flags (GNode *node, Atlv *tlv, gint flags)
 		tag = tlv->tag;
 
 	/* Tag does not match, what do we do? */
-	if (tlv->off == 0 || tag != tlv->tag) {
-		if (flags & FLAG_OPTION || flags & FLAG_DEFAULT) {
-			tlv->len = 0;
-			tlv->end = tlv->buf;
-			tlv->off = 0;
-			return TRUE;
-		} else {
-			return FALSE;
-		}
-	}
+	if (tlv->off == 0 || tag != tlv->tag)
+		return FALSE;
 
 	/* Structured value */
 	if (tlv->cls & ASN1_CLASS_STRUCTURED)
@@ -911,7 +947,21 @@ anode_decode_anything_for_flags (GNode *node, Atlv *tlv, gint flags)
 static gboolean
 anode_decode_anything (GNode *node, Atlv *tlv)
 {
-	return anode_decode_anything_for_flags (node, tlv, anode_def_flags (node));
+	gint flags = anode_def_flags (node);
+
+	if (!anode_decode_anything_for_flags (node, tlv, 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;
+		}
+
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 gboolean
@@ -1031,7 +1081,7 @@ anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
 	/* Build up the class */
 	flags = anode_def_flags (node);
 	if (flags & FLAG_TAG) {
-		explicit = !(flags & FLAG_IMPLICIT);
+		explicit = anode_calc_explicit_for_flags (node, flags);
 		if (explicit)
 			flags &= ~FLAG_TAG;
 		else
@@ -1053,11 +1103,12 @@ anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
 	}
 
 	/* Not completely filled in */
-	tlv.buf = tlv.end = 0;
+	tlv.buf = tlv.end = NULL;
 
 	anode_clear (node);
 	anode_set_tlv_data (node, &tlv);
-	anode_set_enc_data (node, encoder, user_data, destroy);
+	anode_set_enc_data (node, encoder, user_data);
+	anode_set_user_data (node, user_data, destroy);
 }
 
 static gboolean
@@ -1081,7 +1132,7 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
 
 	/* Encode any explicit tag */
 	flags = anode_def_flags (node);
-	if (flags & FLAG_TAG && !(flags & FLAG_IMPLICIT)) {
+	if (anode_calc_explicit_for_flags (node, flags)) {
 		tag = anode_calc_tag (node);
 		g_return_val_if_fail (tag != G_MAXULONG, FALSE);
 		cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_CONTEXT_SPECIFIC);
@@ -1100,7 +1151,7 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
 	tlv->end = data + n_data;
 
 	/* Encode in the data */
-	if (!(enc->encoder) (enc->user_data, data + tlv->off, tlv->len))
+	if (!(enc->encoder) (enc->data, data + tlv->off, tlv->len))
 		return FALSE;
 
 	return TRUE;
@@ -1159,6 +1210,8 @@ traverse_and_sort_set_of (GNode *node, gpointer user_data)
 	Atlv *tlv;
 	GNode *child;
 
+	g_assert (allocator);
+
 	/* We have to sort any SET OF :( */
 	if (anode_def_type (node) != TYPE_SET_OF)
 		return FALSE;
@@ -1248,7 +1301,7 @@ anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
 		if (ctlv) {
 			enc = anode_get_enc_data (child);
 			g_return_val_if_fail (enc, FALSE);
-			if (!(enc->encoder) (enc->user_data, data, n_data))
+			if (!(enc->encoder) (enc->data, data, n_data))
 				return FALSE;
 
 			/* Child's buffer matches ours */
@@ -1262,19 +1315,49 @@ anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
 }
 
 static gboolean
+anode_encoder_bit_string (gpointer user_data, guchar *data, gsize n_data)
+{
+	Abits *ab = user_data;
+	guchar empty, mask;
+	gsize len;
+
+	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);
+
+	/* Fill in the amount of empty */
+	data[0] = empty;
+	data += 1;
+
+	/* Fill in the actual data */
+	memcpy (data, ab->bits, len);
+
+	/* Set the extra bits to zero */
+	if (len && empty) {
+		mask = 0xFF >> (8 - empty);
+		data[len - 1] &= ~mask;
+	}
+
+	return TRUE;
+}
+
+static gboolean
 anode_encode_prepare_simple (GNode *node)
 {
 	Aenc *enc;
 	Atlv *tlv;
 
-	enc = anode_get_enc_data (node);
 	tlv = anode_get_tlv_data (node);
-	if (enc != NULL || tlv == NULL)
+	if (tlv == NULL)
 		return FALSE;
 
 	/* Transfer the tlv data over to enc */
-	anode_set_enc_data (node, anode_encoder_simple,
-	                    (guchar*)tlv->buf + tlv->off, NULL);
+	enc = anode_get_enc_data (node);
+	if (enc == NULL)
+		anode_set_enc_data (node, anode_encoder_simple, (guchar*)tlv->buf + tlv->off);
+
 	tlv->buf = tlv->end = NULL;
 	return TRUE;
 }
@@ -1314,7 +1397,7 @@ anode_encode_prepare_structured (GNode *node)
 			g_return_val_if_fail (tlv, had);
 			anode_clr_tlv_data (node);
 			anode_set_tlv_data (node, tlv);
-			anode_set_enc_data (node, anode_encoder_choice, node, NULL);
+			anode_set_enc_data (node, anode_encoder_choice, node);
 		}
 
 	/* Other container types */
@@ -1366,7 +1449,8 @@ egg_asn1x_encode (GNode *asn, EggAllocator allocator, gsize *n_data)
 	if (!allocator)
 		allocator = g_realloc;
 
-	anode_encode_prepare (asn);
+	if (!anode_encode_prepare (asn))
+		return NULL;
 
 	/* We must sort all the nasty SET OF nodes */
 	g_node_traverse (asn, G_POST_ORDER, G_TRAVERSE_ALL, -1,
@@ -1865,7 +1949,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
 	val = p[0] - pval * 40;
 
 	if (result)
-		g_string_append_printf (result, "%u.%u.", pval, val);
+		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) {
@@ -1884,7 +1968,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
 		pval = val;
 		if (!(p[k] & 0x80)) {
 			if (result)
-				g_string_append_printf (result, "%u.", val);
+				g_string_append_printf (result, ".%u", val);
 			pval = val = 0;
 			lead = 1;
 		}
@@ -1904,7 +1988,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
 static gboolean
 anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
 {
-	const gchar *p;
+	const gchar *p, *next;
 	gint num, num1;
 	guchar bit7;
 	gboolean had;
@@ -1913,10 +1997,12 @@ anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
 	p = oid;
 	at = 0;
 
-	for (i = 0; oid[0]; ++i, oid = p) {
+	for (i = 0; oid[0]; ++i, oid = next) {
 		p = strchr (oid, '.');
 		if (p == NULL)
-			p = oid + strlen (oid);
+			next = p = oid + strlen (oid);
+		else
+			next = p + 1;
 		if (p == oid)
 			return FALSE;
 		num = atoin (oid, p - oid);
@@ -1975,7 +2061,18 @@ egg_asn1x_node (GNode *asn, ...)
 			index = va_arg (va, gint);
 			if (index == 0)
 				return node;
-			node = g_node_nth_child (node, index);
+
+			/* Only consider nodes that have data */
+			node = g_node_nth_child (node, 0);
+			while (node) {
+				if (egg_asn1x_have (node)) {
+					--index;
+					if (index == 0)
+						break;
+				}
+				node = g_node_next_sibling (node);
+			}
+
 			if (node == NULL)
 				return NULL;
 
@@ -1996,9 +2093,46 @@ egg_asn1x_node (GNode *asn, ...)
 	}
 }
 
+const gchar*
+egg_asn1x_name (GNode *node)
+{
+	g_return_val_if_fail (node, NULL);
+	return anode_def_name (node);
+}
+
+guint
+egg_asn1x_count (GNode *node)
+{
+	gint type;
+
+	g_return_val_if_fail (node, 0);
+
+	type = anode_def_type (node);
+	if (type != TYPE_SEQUENCE_OF && type != TYPE_SET_OF) {
+		g_warning ("node passed to egg_asn1x_count was not a sequence of or set of");
+		return 0;
+	}
+
+	return g_node_n_children (node);
+}
+
+gboolean
+egg_asn1x_have (GNode *node)
+{
+	Atlv *tlv;
+
+	g_return_val_if_fail (node, FALSE);
+
+	/* TODO: Handle default values */
+
+	tlv = anode_get_tlv_data (node);
+	return tlv != NULL && tlv->buf != NULL;
+}
+
 gboolean
 egg_asn1x_get_boolean (GNode *node, gboolean *value)
 {
+	ASN1_ARRAY_TYPE *opt;
 	Atlv *tlv;
 
 	g_return_val_if_fail (node, FALSE);
@@ -2006,8 +2140,24 @@ egg_asn1x_get_boolean (GNode *node, gboolean *value)
 	g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
 
 	tlv = anode_get_tlv_data (node);
-	if (tlv == NULL)
-		return FALSE;
+	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, TYPE_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;
+	}
 
 	return anode_read_boolean (node, tlv, value);
 }
@@ -2021,6 +2171,8 @@ egg_asn1x_set_boolean (GNode *node, gboolean value)
 	g_return_val_if_fail (node, FALSE);
 	g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
 
+	/* TODO: Handle default values */
+
 	n_data = 1;
 	data = g_malloc0 (1);
 	if (!anode_write_boolean (value, data, &n_data))
@@ -2032,16 +2184,44 @@ egg_asn1x_set_boolean (GNode *node, gboolean value)
 gboolean
 egg_asn1x_get_integer_as_ulong (GNode *node, gulong *value)
 {
+	const ASN1_ARRAY_TYPE *opt;
+	const gchar *defval;
 	Atlv *tlv;
+	gchar *end;
 
 	g_return_val_if_fail (node, FALSE);
 	g_return_val_if_fail (value, FALSE);
 	g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
 
 	tlv = anode_get_tlv_data (node);
-	if (tlv == NULL)
+	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, TYPE_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, TYPE_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;
+	}
+
+	if (tlv == NULL || tlv->buf == NULL)
 		return FALSE;
 
+	/* TODO: Default integer values */
+
 	return anode_read_integer_as_ulong(node, tlv, value);
 }
 
@@ -2052,7 +2232,9 @@ egg_asn1x_set_integer_as_ulong (GNode *node, gulong value)
 	gsize n_data;
 
 	g_return_val_if_fail (node, FALSE);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
+
+	/* TODO: Handle default values */
 
 	n_data = 8;
 	data = g_malloc0 (8);
@@ -2062,6 +2244,115 @@ egg_asn1x_set_integer_as_ulong (GNode *node, gulong value)
 	return TRUE;
 }
 
+gpointer
+egg_asn1x_get_integer_as_raw (GNode *node, EggAllocator allocator, gsize *n_data)
+{
+	Atlv *tlv;
+	gpointer data;
+
+	g_return_val_if_fail (node, FALSE);
+	g_return_val_if_fail (n_data, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
+
+	if (!allocator)
+		allocator = g_realloc;
+
+	tlv = anode_get_tlv_data (node);
+	if (tlv == NULL || tlv->buf == NULL)
+		return NULL;
+
+	data = (allocator) (NULL, tlv->len);
+	if (data == NULL)
+		return NULL;
+
+	memcpy (data, tlv->buf + tlv->off, tlv->len);
+	*n_data = tlv->len;
+	return data;
+}
+
+gboolean
+egg_asn1x_set_integer_as_raw (GNode *node, gpointer data, gsize n_data, GDestroyNotify destroy)
+{
+	gboolean sign;
+	guchar *p;
+
+	g_return_val_if_fail (node, FALSE);
+	g_return_val_if_fail (data, FALSE);
+	g_return_val_if_fail (n_data > 0, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
+
+	/* Make sure the integer is properly encoded in twos complement*/
+	p = (guchar*)data;
+	sign = !!(p[0] & 0x80);
+	if (sign) {
+		g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement");
+		return FALSE;
+	}
+
+	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, destroy);
+	return TRUE;
+}
+
+gconstpointer
+egg_asn1x_get_raw_element (GNode *node, gsize *n_element)
+{
+	Atlv *tlv;
+
+	g_return_val_if_fail (node, NULL);
+	g_return_val_if_fail (n_element, NULL);
+
+	tlv = anode_get_tlv_data (node);
+	if (tlv == NULL || tlv->buf == NULL)
+		return NULL;
+
+	if (anode_calc_explicit (node)) {
+		*n_element = (tlv->len + tlv->off) - tlv->oft;
+		return tlv->buf + tlv->oft;
+	} else {
+		*n_element = tlv->len + tlv->off;
+		return tlv->buf;
+	}
+}
+
+gboolean
+egg_asn1x_set_raw_element (GNode *node, gpointer data,
+                           gsize n_data, GDestroyNotify destroy)
+{
+	Atlv tlv;
+
+	g_return_val_if_fail (node, FALSE);
+	g_return_val_if_fail (data, FALSE);
+	g_return_val_if_fail (n_data, FALSE);
+
+	anode_clear (node);
+	memset (&tlv, 0, sizeof (tlv));
+
+	/* TODO: This needs implementation */
+	if (anode_calc_explicit (node)) {
+		g_warning ("egg_asn1x_set_raw_element does not yet work with explicit tagging");
+		return FALSE;
+	}
+
+	/* Decode the beginning TLV */
+	if (!anode_decode_tlv_for_data (data, (const guchar*)data + n_data, &tlv))
+		return FALSE;
+
+	/* Decode the data into place properly */
+	if (!anode_decode_anything (node, &tlv))
+		return FALSE;
+
+	/* There was extra data */
+	if (tlv.end - tlv.buf != n_data)
+		return FALSE;
+
+	/* Should have been set above */
+	g_assert (anode_get_tlv_data (node) != NULL);
+
+	/* We set this so the data is properly destroyed */
+	anode_set_user_data (node, data, destroy);
+	return TRUE;
+}
+
 gconstpointer
 egg_asn1x_get_raw_value (GNode *node, gsize *n_content)
 {
@@ -2071,8 +2362,8 @@ egg_asn1x_get_raw_value (GNode *node, gsize *n_content)
 	g_return_val_if_fail (n_content, NULL);
 
 	tlv = anode_get_tlv_data (node);
-	if (tlv == NULL)
-		return FALSE;
+	if (tlv == NULL || tlv->buf == NULL)
+		return NULL;
 	g_return_val_if_fail (!(tlv->cls & ASN1_CLASS_STRUCTURED), NULL);
 
 	*n_content = tlv->len;
@@ -2101,11 +2392,14 @@ egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_strin
 	g_return_val_if_fail (node, NULL);
 	g_return_val_if_fail (n_string, NULL);
 
+	if (!allocator)
+		allocator = g_realloc;
+
 	type = anode_def_type (node);
 	g_return_val_if_fail (type == TYPE_OCTET_STRING || type == TYPE_GENERALSTRING, NULL);
 
 	tlv = anode_get_tlv_data (node);
-	if (tlv == NULL)
+	if (tlv == NULL || tlv->buf == NULL)
 		return NULL;
 
 	if (!anode_read_string (node, tlv, NULL, &length))
@@ -2179,17 +2473,160 @@ egg_asn1x_set_string_as_utf8 (GNode *node, gchar *data, GDestroyNotify destroy)
 	return egg_asn1x_set_string_as_raw (node, (guchar*)data, n_data, destroy);
 }
 
+guchar*
+egg_asn1x_get_bits_as_raw (GNode *node, EggAllocator allocator, guint *n_bits)
+{
+	Atlv *tlv;
+	gpointer bits;
+	guchar padded;
+
+	g_return_val_if_fail (node, FALSE);
+	g_return_val_if_fail (n_bits, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == TYPE_BIT_STRING, FALSE);
+
+	if (!allocator)
+		allocator = g_realloc;
+
+	tlv = anode_get_tlv_data (node);
+	if (tlv == NULL || tlv->buf == 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);
+
+	bits = (allocator) (NULL, tlv->len);
+	if (bits == NULL)
+		return NULL;
+
+	memcpy (bits, tlv->buf + tlv->off + 1, tlv->len - 1);
+	*n_bits = ((tlv->len - 1) * 8) - padded;
+	return bits;
+}
+
+gboolean
+egg_asn1x_set_bits_as_raw (GNode *node, guchar *bits, guint n_bits, GDestroyNotify destroy)
+{
+	gint type;
+	gsize length;
+	Abits *ab;
+
+	g_return_val_if_fail (node, FALSE);
+	g_return_val_if_fail (bits, FALSE);
+
+	type = anode_def_type (node);
+	g_return_val_if_fail (type == TYPE_BIT_STRING, FALSE);
+
+	length = (n_bits / 8);
+	if (n_bits % 8)
+		length += 1;
+
+	ab = g_slice_new0 (Abits);
+	ab->bits = bits;
+	ab->n_bits = n_bits;
+	ab->destroy = destroy;
+
+	anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
+	return TRUE;
+}
+
+gboolean
+egg_asn1x_get_bits_as_ulong (GNode *node, gulong *bits, guint *n_bits)
+{
+	Atlv *tlv;
+	guint i, length;
+	guchar empty;
+	const guchar *p;
+	gulong value;
+
+	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 (anode_def_type (node) == TYPE_BIT_STRING, FALSE);
+
+	tlv = anode_get_tlv_data (node);
+	if (tlv == NULL || tlv->buf == 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);
+
+	length = ((tlv->len - 1) * 8) - empty;
+	if (length > sizeof (gulong) * 8)
+		return FALSE;
+
+	value = 0;
+	p = tlv->buf + tlv->off + 1;
+
+	for (i = 0; i < tlv->len - 1; ++i)
+		value = value << 8 | p[i];
+
+	*bits = value >> empty;
+	*n_bits = length;
+	return TRUE;
+}
+
+gboolean
+egg_asn1x_set_bits_as_ulong (GNode *node, gulong bits, guint n_bits)
+{
+	guchar *data;
+	gulong value;
+	gint type;
+	gsize i, length;
+	guchar empty;
+	Abits *ab;
+
+	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);
+
+	type = anode_def_type (node);
+	g_return_val_if_fail (type == TYPE_BIT_STRING, FALSE);
+
+	empty = n_bits % 8;
+	if (empty > 0)
+		empty = 8 - empty;
+	length = (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;
+
+	ab = g_slice_new0 (Abits);
+	ab->bits = data;
+	ab->n_bits = n_bits;
+	ab->destroy = g_free;
+
+	anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
+	return TRUE;
+}
+
 glong
 egg_asn1x_get_time_as_long (GNode *node)
 {
 	Atlv *tlv;
 	glong time;
+	gint type;
 
 	g_return_val_if_fail (node, -1);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_TIME, -1);
+	type = anode_def_type (node);
+
+	/* Time is often represented as a choice, so work than in here */
+	if (type == TYPE_CHOICE) {
+		node = egg_asn1x_get_choice (node);
+		if (node == NULL)
+			return -1;
+		g_return_val_if_fail (anode_def_type (node) == TYPE_TIME, -1);
+		return egg_asn1x_get_time_as_long (node);
+	}
+
+	g_return_val_if_fail (type == TYPE_TIME, -1);
 
 	tlv = anode_get_tlv_data (node);
-	if (tlv == NULL)
+	if (tlv == NULL || tlv->buf == NULL)
 		return -1;
 
 	if (!anode_read_time (node, tlv, &time))
@@ -2197,6 +2634,23 @@ egg_asn1x_get_time_as_long (GNode *node)
 	return time;
 }
 
+gboolean
+egg_asn1x_get_time_as_date (GNode *node, GDate *date)
+{
+	GTimeVal tv;
+
+	g_return_val_if_fail (node, FALSE);
+	g_return_val_if_fail (date, FALSE);
+
+	tv.tv_sec = egg_asn1x_get_time_as_long (node);
+	if (tv.tv_sec < 0)
+		return FALSE;
+	tv.tv_usec = 0;
+
+	g_date_set_time_val (date, &tv);
+	return TRUE;
+}
+
 gchar*
 egg_asn1x_get_oid_as_string (GNode *node)
 {
@@ -2207,7 +2661,7 @@ egg_asn1x_get_oid_as_string (GNode *node)
 	g_return_val_if_fail (anode_def_type (node) == TYPE_OBJECT_ID, NULL);
 
 	tlv = anode_get_tlv_data (node);
-	if (tlv == NULL)
+	if (tlv == NULL || tlv->buf == NULL)
 		return NULL;
 
 	if (!anode_read_object_id (node, tlv, &oid))
@@ -2265,6 +2719,22 @@ egg_asn1x_set_oid_as_quark (GNode *node, GQuark oid)
 	return egg_asn1x_set_oid_as_string (node, str);
 }
 
+GNode*
+egg_asn1x_get_choice (GNode *node)
+{
+	GNode *child;
+
+	g_return_val_if_fail (node, NULL);
+
+	/* One and only one of the children must be set */
+	for (child = node->children; child; child = child->next) {
+		if (anode_get_tlv_data (child))
+			return child;
+	}
+
+	return NULL;
+}
+
 /* -----------------------------------------------------------------------------------
  * VALIDATION
  */
@@ -2302,9 +2772,6 @@ anode_validate_size (GNode *node, gulong length)
 
 	if (anode_def_flags (node) & FLAG_SIZE) {
 		size = anode_opt_lookup (node, TYPE_SIZE, NULL);
-		if (size == NULL) {
-			egg_asn1x_dump (g_node_get_root (node));
-		}
 		g_return_val_if_fail (size, FALSE);
 		if (!anode_parse_size (node, size->value, &value1))
 			g_return_val_if_reached (FALSE);
@@ -2396,7 +2863,7 @@ anode_validate_bit_string (GNode *node, Atlv *tlv)
 	g_assert (tlv);
 
 	/* At least two bytes in length */
-	if (tlv->len < 2)
+	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];
@@ -2404,7 +2871,7 @@ anode_validate_bit_string (GNode *node, Atlv *tlv)
 		return anode_failure (node, "bit string has invalid header");
 	/* Free bits at end must be zero */
 	mask = 0xFF >> (8 - empty);
-	if (tlv->buf[tlv->off + tlv->len - 1] & mask)
+	if (tlv->len > 1 && tlv->buf[tlv->off + tlv->len - 1] & mask)
 		return anode_failure (node, "bit string has invalid trailing bits");
 	return TRUE;
 }
@@ -2507,11 +2974,11 @@ anode_validate_sequence_or_set_of (GNode *node)
 
 	/* All the children must validate properly */
 	for (child = node->children; child; child = child->next) {
-		if (!anode_validate_anything (child))
-			return FALSE;
-
 		tlv = anode_get_tlv_data (child);
 		if (tlv) {
+			if (!anode_validate_anything (child))
+				return FALSE;
+
 			/* Tag must have same tag as top */
 			if (count == 0)
 				tag = anode_calc_tag (child);
@@ -2541,6 +3008,8 @@ anode_validate_anything (GNode *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");
 	}
 
@@ -2629,14 +3098,58 @@ join_each_child (GNode *child, gpointer data)
 }
 
 static const ASN1_ARRAY_TYPE*
-lookup_def (const ASN1_ARRAY_TYPE *defs, const gchar *identifier, gint type)
+adef_next_sibling (const ASN1_ARRAY_TYPE *def)
+{
+	int depth = 0;
+
+	g_assert (def);
+	g_assert (def->value || def->type || def->name);
+
+	if ((def->type & FLAG_RIGHT) == 0)
+		return NULL;
+
+	/* Skip past any children */
+	if ((def->type & FLAG_DOWN) == FLAG_DOWN) {
+		depth += 1;
+		while (depth > 0) {
+			++def;
+			if ((def->type & FLAG_DOWN) == FLAG_DOWN)
+				depth += 1;
+			if ((def->type & FLAG_RIGHT) == 0)
+				depth -= 1;
+		}
+	}
+
+	++def;
+	g_return_val_if_fail (def->value || def->type || def->name, NULL);
+	return def;
+}
+
+static const ASN1_ARRAY_TYPE*
+adef_first_child (const ASN1_ARRAY_TYPE *def)
 {
-	/* Find the one we're interested in */
-	while (defs && (defs->value || defs->type || defs->name)) {
-		if ((defs->type & 0xFF) == type &&
-		    defs->name && g_str_equal (identifier, defs->name))
-			return defs;
-		++defs;
+	g_assert (def);
+	g_assert (def->value || def->type || def->name);
+
+	if ((def->type & FLAG_DOWN) == 0)
+		return NULL;
+
+	++def;
+	g_return_val_if_fail (def->value || def->type || def->name, NULL);
+	return def;
+}
+
+static const ASN1_ARRAY_TYPE*
+lookup_def_of_type (const ASN1_ARRAY_TYPE *defs, const gchar *name, gint type)
+{
+	const ASN1_ARRAY_TYPE *def;
+
+	g_assert (defs);
+	g_assert (defs->value || defs->type || defs->name);
+
+	for (def = adef_first_child (defs); def; def = adef_next_sibling (def)) {
+		if ((def->type & 0xFF) == type && def->name && g_str_equal (name, def->name))
+			return def;
 	}
 
 	return NULL;
@@ -2673,7 +3186,7 @@ traverse_and_prepare (GNode *node, gpointer data)
 		identifier = anode_def_name (node);
 		if (identifier && !g_str_equal (identifier, "MAX") &&
 		    g_ascii_isalpha (identifier[0])) {
-			def = lookup_def (defs, identifier, TYPE_INTEGER);
+			def = lookup_def_of_type (defs, identifier, TYPE_INTEGER);
 			g_return_val_if_fail (def, TRUE);
 			anode_opt_add (node, def);
 		}
@@ -2719,26 +3232,123 @@ traverse_and_prepare (GNode *node, gpointer data)
 	return FALSE;
 }
 
+static const ASN1_ARRAY_TYPE*
+match_oid_in_definition (const ASN1_ARRAY_TYPE *def, GHashTable *names,
+                          const gchar *match, const gchar **problem)
+{
+	const ASN1_ARRAY_TYPE *result = NULL;
+	const ASN1_ARRAY_TYPE *odef;
+	const gchar *value;
+	GString *oid = NULL;
+
+	g_assert (match);
+	g_assert (problem);
+	g_assert (names);
+
+	for (odef = adef_first_child (def); odef; odef = adef_next_sibling (odef)) {
+		if ((odef->type & 0xFF) != TYPE_CONSTANT)
+			continue;
+
+		g_return_val_if_fail (odef->value, NULL);
+		if (strspn (odef->value, "01234567890") == strlen (odef->value)) {
+			value = odef->value;
+
+		} else {
+			value = g_hash_table_lookup (names, odef->value);
+
+			/* A name resolution problem */
+			if (!value) {
+				if (oid)
+					g_string_free (oid, TRUE);
+				*problem = odef->value;
+				return NULL;
+			}
+		}
+
+		if (oid) {
+			g_string_append_c (oid, '.');
+			g_string_append (oid, value);
+		} else {
+			oid = g_string_new (value);
+		}
+	}
+
+	if (oid != NULL) {
+		if (g_str_equal (oid->str, match))
+			result = adef_next_sibling (def);
+		g_assert (def->name);
+		g_hash_table_insert (names, (gchar*)def->name, g_string_free (oid, FALSE));
+	}
+
+	return result;
+}
+
+static const ASN1_ARRAY_TYPE*
+match_oid_in_definitions (const ASN1_ARRAY_TYPE *defs, const gchar *match)
+{
+	const ASN1_ARRAY_TYPE *def;
+	const ASN1_ARRAY_TYPE *result;
+	GHashTable *names;
+	gboolean progress;
+	const gchar *problem;
+
+	names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+	for (;;) {
+		progress = FALSE;
+		problem = NULL;
+
+		for (def = adef_first_child (defs); def; def = adef_next_sibling (def)) {
+
+			/* Only work with object ids, and ones with names */
+			if ((def->type & 0xFF) != TYPE_OBJECT_ID || !def->name)
+				continue;
+
+			/* If we've already seen this one, skip */
+			if (g_hash_table_lookup (names, def->name))
+				continue;
+
+			progress = TRUE;
+			result = match_oid_in_definition (def, names, match, &problem);
+			if (result != NULL)
+				break;
+		}
+
+		if (!problem || result) {
+			break;
+		} else if (problem && !progress) {
+			g_warning ("couldn't find oid definition in ASN.1 for: %s", problem);
+			g_return_val_if_reached (NULL);
+		}
+	}
+
+	g_hash_table_destroy (names);
+	return result;
+}
+
 GNode*
-egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *identifier)
+egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *type)
 {
 	const ASN1_ARRAY_TYPE *def;
 	GNode *root, *parent, *node;
 	int flags;
 
 	g_return_val_if_fail (defs, NULL);
-	g_return_val_if_fail (identifier, NULL);
+	g_return_val_if_fail (type, NULL);
 
-	def = defs;
+	/* An OID */
+	if (strspn (type, "0123456789.") == strlen (type)) {
+		def = match_oid_in_definitions (defs, type);
 
-	/* Find the one we're interested in */
-	while (def && (def->value || def->type || def->name)) {
-		if (def->name && g_str_equal (identifier, def->name))
-			break;
-		++def;
+	/* An Identifier */
+	} else {
+		for (def = adef_first_child (defs); def; def = adef_next_sibling (def)) {
+			if (def->name && g_str_equal (type, def->name))
+				break;
+		}
 	}
 
-	if (!def->name || !def->type)
+	if (def == NULL || !def->name || !def->type)
 		return NULL;
 
 	/* The node for this item */
@@ -2779,6 +3389,33 @@ egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *identifier)
 	return root;
 }
 
+GNode*
+egg_asn1x_create_quark (const ASN1_ARRAY_TYPE *defs, GQuark type)
+{
+	g_return_val_if_fail (type, NULL);
+	return egg_asn1x_create (defs, g_quark_to_string (type));
+}
+
+GNode*
+egg_asn1x_create_and_decode (const ASN1_ARRAY_TYPE *defs, const gchar *identifier,
+                             gconstpointer data, gsize n_data)
+{
+	GNode *asn;
+
+	g_return_val_if_fail (defs, NULL);
+	g_return_val_if_fail (identifier, NULL);
+
+	asn = egg_asn1x_create (defs, identifier);
+	g_return_val_if_fail (asn, NULL);
+
+	if (!egg_asn1x_decode (asn, data, n_data)) {
+		egg_asn1x_destroy (asn);
+		return NULL;
+	}
+
+	return asn;
+}
+
 /* -----------------------------------------------------------------------------------
  * DUMPING and MESSAGES
  */
@@ -2814,6 +3451,7 @@ traverse_and_dump (GNode *node, gpointer unused)
 	guint i, depth;
 	GString *output;
 	gchar *string;
+	Atlv *tlv;
 	Anode *an;
 	GList *l;
 
@@ -2821,12 +3459,14 @@ traverse_and_dump (GNode *node, gpointer unused)
 	for (i = 0; i < depth - 1; ++i)
 		g_printerr ("    ");
 
+	tlv = anode_get_tlv_data (node);
 	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]\n", anode_def_name (node), anode_def_value (node), string);
+	g_printerr ("+ %s: %s [%s]%s\n", anode_def_name (node), anode_def_value (node),
+	            string, tlv && tlv->buf ? " *" : "");
 	g_free (string);
 
 	/* Print out all the options */
@@ -2915,6 +3555,127 @@ egg_asn1x_clear (GNode *asn)
 void
 egg_asn1x_destroy (gpointer data)
 {
-	if (data)
-		anode_destroy (data);
+	GNode *node = data;
+
+	if (node != NULL) {
+		g_return_if_fail (G_NODE_IS_ROOT (node));
+		anode_destroy (node);
+	}
+}
+
+/* --------------------------------------------------------------------------------
+ * TIME PARSING
+ */
+
+glong
+egg_asn1x_parse_time_general (const gchar *time, gssize n_time)
+{
+	gboolean ret;
+	glong value;
+	struct tm when;
+	gint offset = 0;
+
+	g_return_val_if_fail (time, -1);
+
+	if (n_time < 0)
+		n_time = strlen (time);
+
+	ret = parse_general_time (time, n_time, &when, &offset);
+	if (!ret)
+		return -1;
+
+	/* In order to work with 32 bit time_t. */
+	if (sizeof (time_t) <= 4 && when.tm_year >= 2038) {
+		value = (time_t)2145914603;  /* 2037-12-31 23:23:23 */
+
+	/* Convert to seconds since epoch */
+	} else {
+		value = timegm (&when);
+		g_return_val_if_fail (*time >= 0, FALSE);
+		value += offset;
+	}
+
+	return value;
+}
+
+glong
+egg_asn1x_parse_time_utc (const gchar *time, gssize n_time)
+{
+	gboolean ret;
+	glong value;
+	struct tm when;
+	gint offset = 0;
+
+	g_return_val_if_fail (time, -1);
+
+	if (n_time < 0)
+		n_time = strlen (time);
+
+	ret = parse_utc_time (time, n_time, &when, &offset);
+	if (!ret)
+		return -1;
+
+	/* In order to work with 32 bit time_t. */
+	if (sizeof (time_t) <= 4 && when.tm_year >= 2038) {
+		value = (time_t)2145914603;  /* 2037-12-31 23:23:23 */
+
+	/* Convert to seconds since epoch */
+	} else {
+		value = timegm (&when);
+		g_return_val_if_fail (*time >= 0, FALSE);
+		value += offset;
+	}
+
+	return value;
+}
+
+/* --------------------------------------------------------------------------------
+ * BASIC RAW ELEMENT INFO
+ */
+
+gssize
+egg_asn1x_element_length (gconstpointer data, gsize n_data)
+{
+	guchar cls;
+	int counter = 0;
+	int cb, len;
+	gulong tag;
+
+	if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) == ASN1_SUCCESS) {
+		counter += cb;
+		len = asn1_get_length_der ((const guchar*)data + cb, n_data - cb, &cb);
+		counter += cb;
+		if (len >= 0) {
+			len += counter;
+			if (n_data >= len)
+				return len;
+		}
+	}
+
+	return -1;
+}
+
+gconstpointer
+egg_asn1x_element_content (gconstpointer data, gsize n_data, gsize *n_content)
+{
+	int counter = 0;
+	guchar cls;
+	gulong tag;
+	int cb, len;
+
+	g_return_val_if_fail (data != NULL, NULL);
+	g_return_val_if_fail (n_content != NULL, NULL);
+
+	/* Now get the data out of this element */
+	if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) != ASN1_SUCCESS)
+		return NULL;
+
+	counter += cb;
+	len = asn1_get_length_der ((const guchar*)data + cb, n_data - cb, &cb);
+	if (len < 0)
+		return NULL;
+	counter += cb;
+
+	*n_content = len;
+	return (const guchar*)data + counter;
 }
diff --git a/egg/egg-asn1x.h b/egg/egg-asn1x.h
index 6d69b0a..705e226 100644
--- a/egg/egg-asn1x.h
+++ b/egg/egg-asn1x.h
@@ -26,9 +26,6 @@
 
 #include <glib.h>
 
-#include <libtasn1.h>
-
-
 #ifndef HAVE_EGG_ALLOCATOR
 typedef void* (*EggAllocator) (void* p, gsize);
 #define HAVE_EGG_ALLOCATOR
@@ -36,9 +33,19 @@ typedef void* (*EggAllocator) (void* p, gsize);
 
 typedef gboolean (*EggAsn1xEncoder) (gpointer data, guchar *buf, gsize n_buf);
 
-GNode*              egg_asn1x_create                 (const ASN1_ARRAY_TYPE *defs,
+struct static_struct_asn;
+
+GNode*              egg_asn1x_create                 (const struct static_struct_asn *defs,
                                                       const gchar *type);
 
+GNode*              egg_asn1x_create_quark           (const struct static_struct_asn *defs,
+                                                      GQuark type);
+
+GNode*              egg_asn1x_create_and_decode      (const struct static_struct_asn *defs,
+                                                      const gchar *type,
+                                                      gconstpointer data,
+                                                      gsize n_data);
+
 void                egg_asn1x_dump                   (GNode *asn);
 
 void                egg_asn1x_clear                  (GNode *asn);
@@ -58,6 +65,14 @@ const gchar*        egg_asn1x_message                (GNode *asn);
 GNode*              egg_asn1x_node                   (GNode *asn,
                                                       ...) G_GNUC_NULL_TERMINATED;
 
+const gchar*        egg_asn1x_name                   (GNode *asn);
+
+guint               egg_asn1x_count                  (GNode *node);
+
+gboolean            egg_asn1x_have                   (GNode *node);
+
+GNode*              egg_asn1x_get_choice             (GNode *node);
+
 gboolean            egg_asn1x_get_boolean            (GNode *node,
                                                       gboolean *value);
 
@@ -70,6 +85,15 @@ gboolean            egg_asn1x_get_integer_as_ulong   (GNode *node,
 gboolean            egg_asn1x_set_integer_as_ulong   (GNode *node,
                                                       gulong value);
 
+gpointer            egg_asn1x_get_integer_as_raw     (GNode *node,
+                                                      EggAllocator allocator,
+                                                      gsize *n_data);
+
+gboolean            egg_asn1x_set_integer_as_raw     (GNode *node,
+                                                      gpointer data,
+                                                      gsize n_data,
+                                                      GDestroyNotify destroy);
+
 gconstpointer       egg_asn1x_get_raw_value          (GNode *node,
                                                       gsize *n_content);
 
@@ -79,6 +103,14 @@ gboolean            egg_asn1x_set_raw_value          (GNode *node,
                                                       gpointer user_data,
                                                       GDestroyNotify destroy);
 
+gconstpointer       egg_asn1x_get_raw_element        (GNode *node,
+                                                      gsize *n_data);
+
+gboolean            egg_asn1x_set_raw_element        (GNode *node,
+                                                      gpointer user_data,
+                                                      gsize n_data,
+                                                      GDestroyNotify destroy);
+
 guchar*             egg_asn1x_get_string_as_raw      (GNode *node,
                                                       EggAllocator allocator,
                                                       gsize *n_string);
@@ -88,6 +120,23 @@ gboolean            egg_asn1x_set_string_as_raw      (GNode *node,
                                                       gsize n_data,
                                                       GDestroyNotify destroy);
 
+guchar*             egg_asn1x_get_bits_as_raw        (GNode *node,
+                                                      EggAllocator allocator,
+                                                      guint *n_bits);
+
+gboolean            egg_asn1x_set_bits_as_raw        (GNode *node,
+                                                      guchar *data,
+                                                      guint n_bits,
+                                                      GDestroyNotify destroy);
+
+gboolean            egg_asn1x_get_bits_as_ulong      (GNode *node,
+                                                      gulong *value,
+                                                      guint *n_bits);
+
+gboolean            egg_asn1x_set_bits_as_ulong      (GNode *node,
+                                                      gulong value,
+                                                      guint n_bits);
+
 gchar*              egg_asn1x_get_string_as_utf8     (GNode *node,
                                                       EggAllocator allocator);
 
@@ -97,7 +146,14 @@ gboolean            egg_asn1x_set_string_as_utf8     (GNode *node,
 
 glong               egg_asn1x_get_time_as_long       (GNode *node);
 
-glong               egg_asn1x_set_time_as_long       (GNode *node);
+gboolean            egg_asn1x_set_time_as_long       (GNode *node,
+                                                      glong time);
+
+gboolean            egg_asn1x_get_time_as_date       (GNode *node,
+                                                      GDate *date);
+
+gboolean            egg_asn1x_set_time_as_date       (GNode *node,
+                                                      GDate *date);
 
 GQuark              egg_asn1x_get_oid_as_quark       (GNode *node);
 
@@ -111,4 +167,17 @@ gboolean            egg_asn1x_set_oid_as_string      (GNode *node,
 
 void                egg_asn1x_destroy                (gpointer asn);
 
+glong               egg_asn1x_parse_time_general     (const gchar *time,
+                                                      gssize n_time);
+
+glong               egg_asn1x_parse_time_utc         (const gchar *time,
+                                                      gssize n_time);
+
+gssize              egg_asn1x_element_length         (gconstpointer data,
+                                                      gsize n_data);
+
+gconstpointer       egg_asn1x_element_content        (gconstpointer data,
+                                                      gsize n_data,
+                                                      gsize *n_content);
+
 #endif /*EGG_ASN1X_H_*/
diff --git a/egg/egg-dn.c b/egg/egg-dn.c
index 199cb6a..b41844e 100644
--- a/egg/egg-dn.c
+++ b/egg/egg-dn.c
@@ -23,27 +23,15 @@
 
 #include "config.h"
 
-#include "egg-asn1.h"
+#include "egg-asn1-defs.h"
+#include "egg-asn1x.h"
 #include "egg-dn.h"
 #include "egg-oid.h"
 
-#include <libtasn1.h>
-
 #include <string.h>
 
 static const char HEXC[] = "0123456789ABCDEF";
 
-static gboolean
-ascii_length_equals (const gchar *str, gconstpointer data, gsize n_data)
-{
-	g_assert (str);
-	if (!data)
-		return FALSE;
-	if (strlen (str) != n_data)
-		return FALSE;
-	return strncmp (str, data, n_data) == 0;
-}
-
 static gchar*
 dn_print_hex_value (const guchar *data, gsize len)
 {
@@ -62,63 +50,53 @@ dn_print_hex_value (const guchar *data, gsize len)
 static gchar*
 dn_print_oid_value_parsed (GQuark oid, guint flags, const guchar *data, gsize len)
 {
-	const gchar *asn_name;
-	ASN1_TYPE asn1;
-	gchar *part;
-	gchar *value;
+	GNode *asn1, *node;
+	gconstpointer value;
 	gsize n_value;
+	gchar *result;
 
 	g_assert (data);
 	g_assert (len);
 
-	asn_name = asn1_find_structure_from_oid (egg_asn1_get_pkix_asn1type (),
-	                                         g_quark_to_string (oid));
-	g_return_val_if_fail (asn_name, NULL);
-
-	part = g_strdup_printf ("PKIX1.%s", asn_name);
-	asn1 = egg_asn1_decode (part, data, len);
-	g_free (part);
+	asn1 = egg_asn1x_create_quark (pkix_asn1_tab, oid);
+	g_return_val_if_fail (asn1, NULL);
 
-	if (!asn1) {
-		g_message ("couldn't decode value for OID: %s", g_quark_to_string (oid));
+	if (!egg_asn1x_decode (asn1, data, len)) {
+		g_message ("couldn't decode value for OID: %s: %s",
+		           g_quark_to_string (oid), egg_asn1x_message (asn1));
+		egg_asn1x_destroy (asn1);
 		return NULL;
 	}
 
-	value = (gchar*)egg_asn1_read_value (asn1, "", &n_value, NULL);
-
 	/*
 	 * If it's a choice element, then we have to read depending
 	 * on what's there.
 	 */
-	if (value && (flags & EGG_OID_IS_CHOICE)) {
-		if (ascii_length_equals ("printableString", value, n_value - 1) ||
-			ascii_length_equals ("ia5String", value, n_value - 1 ) ||
-			ascii_length_equals ("utf8String", value, n_value - 1) ||
-			ascii_length_equals ("teletexString", value, n_value - 1)) {
-			part = value;
-			value = (gchar*)egg_asn1_read_value (asn1, part, &n_value, NULL);
-			g_free (part);
-		} else {
-			g_free (value);
-			return NULL;
-		}
-	}
+	if (flags & EGG_OID_IS_CHOICE)
+		node = egg_asn1x_get_choice (asn1);
+	else
+		node = asn1;
 
-	if (!value) {
-		g_message ("couldn't read value for OID: %s", g_quark_to_string (oid));
-		return NULL;
-	}
+	value = egg_asn1x_get_raw_value (node, &n_value);
 
 	/*
 	 * Now we make sure it's UTF-8.
 	 */
-	if (!g_utf8_validate (value, n_value, NULL)) {
-		gchar *hex = dn_print_hex_value ((guchar*)value, n_value);
-		g_free (value);
-		value = hex;
+
+	if (!value) {
+		g_message ("couldn't read value for OID: %s", g_quark_to_string (oid));
+		result = NULL;
+
+	} else if (!g_utf8_validate (value, n_value, NULL)) {
+		result = dn_print_hex_value ((guchar*)value, n_value);
+
+	} else {
+		result = g_strndup (value, n_value);
 	}
 
-	return value;
+	egg_asn1x_destroy (asn1);
+
+	return result;
 }
 
 static gchar*
@@ -139,55 +117,45 @@ dn_print_oid_value (GQuark oid, guint flags, const guchar *data, gsize len)
 }
 
 static gchar*
-dn_parse_rdn (ASN1_TYPE asn, const gchar *part)
+dn_parse_rdn (GNode *asn)
 {
 	const gchar *name;
 	guint flags;
 	GQuark oid;
-	gchar *path;
-	guchar *value;
+	gconstpointer value;
 	gsize n_value;
 	gchar *display;
 	gchar *result;
 
 	g_assert (asn);
-	g_assert (part);
 
-	path = g_strdup_printf ("%s.type", part);
-	oid = egg_asn1_read_oid (asn, path);
-	g_free (path);
-
-	if (!oid)
-		return NULL;
-
-	path = g_strdup_printf ("%s.value", part);
-	value = egg_asn1_read_value (asn, path, &n_value, NULL);
-	g_free (path);
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "type", NULL));
+	g_return_val_if_fail (oid, NULL);
 
 	flags = egg_oid_get_flags (oid);
 	name = egg_oid_get_name (oid);
 
+	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "value", NULL), &n_value);
 	g_return_val_if_fail (value, NULL);
-	display = dn_print_oid_value (oid, flags, value, n_value);
 
+	display = dn_print_oid_value (oid, flags, value, n_value);
 	result = g_strconcat ((flags & EGG_OID_PRINTABLE) ? name : g_quark_to_string (oid),
-			      "=", display, NULL);
+	                      "=", display, NULL);
 	g_free (display);
 
 	return result;
 }
 
 gchar*
-egg_dn_read (ASN1_TYPE asn, const gchar *part)
+egg_dn_read (GNode* asn)
 {
 	gboolean done = FALSE;
 	GString *result;
-	gchar *path;
+	GNode *node;
 	gchar *rdn;
 	gint i, j;
 
 	g_return_val_if_fail (asn, NULL);
-	g_return_val_if_fail (part, NULL);
 
 	result = g_string_sized_new (64);
 
@@ -196,16 +164,15 @@ egg_dn_read (ASN1_TYPE asn, const gchar *part)
 
 		/* Each type=value pair of an RDN */
 		for (j = 1; TRUE; ++j) {
-			path = g_strdup_printf ("%s%s?%u.?%u", part ? part : "",
-			                        part ? "." : "", i, j);
-			rdn = dn_parse_rdn (asn, path);
-			g_free (path);
-
-			if (!rdn) {
+			node = egg_asn1x_node (asn, i, j, NULL);
+			if (!node) {
 				done = j == 1;
 				break;
 			}
 
+			rdn = dn_parse_rdn (node);
+			g_return_val_if_fail (rdn, NULL);
+
 			/* Account for multi valued RDNs */
 			if (j > 1)
 				g_string_append (result, "+");
@@ -222,18 +189,17 @@ egg_dn_read (ASN1_TYPE asn, const gchar *part)
 }
 
 gchar*
-egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
+egg_dn_read_part (GNode *asn, const gchar *match)
 {
 	gboolean done = FALSE;
 	const gchar *name;
-	guchar *value;
+	gconstpointer value;
 	gsize n_value;
-	gchar *path;
+	GNode *node;
 	GQuark oid;
 	gint i, j;
 
 	g_return_val_if_fail (asn, NULL);
-	g_return_val_if_fail (part, NULL);
 	g_return_val_if_fail (match, NULL);
 
 	/* Each (possibly multi valued) RDN */
@@ -241,17 +207,15 @@ egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
 
 		/* Each type=value pair of an RDN */
 		for (j = 1; TRUE; ++j) {
-			path = g_strdup_printf ("%s%s?%u.?%u.type",
-			                        part ? part : "",
-			                        part ? "." : "", i, j);
-			oid = egg_asn1_read_oid (asn, path);
-			g_free (path);
-
-			if (!oid) {
+			node = egg_asn1x_node (asn, i, j, "type", NULL);
+			if (!node) {
 				done = j == 1;
 				break;
 			}
 
+			oid = egg_asn1x_get_oid_as_quark (node);
+			g_return_val_if_fail (oid, NULL);
+
 			/* Does it match either the OID or the displayable? */
 			if (g_ascii_strcasecmp (g_quark_to_string (oid), match) != 0) {
 				name = egg_oid_get_name (oid);
@@ -259,13 +223,12 @@ egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
 					continue;
 			}
 
-			path = g_strdup_printf ("%s%s?%u.?%u.value",
-			                        part ? part : "",
-			                        part ? "." : "", i, j);
-			value = egg_asn1_read_value (asn, path, &n_value, NULL);
-			g_free (path);
+			node = egg_asn1x_node (asn, i, j, "value", NULL);
+			g_return_val_if_fail (node, NULL);
 
+			value = egg_asn1x_get_raw_element (node, &n_value);
 			g_return_val_if_fail (value, NULL);
+
 			return dn_print_oid_value (oid, egg_oid_get_flags (oid), value, n_value);
 		}
 	}
@@ -274,12 +237,11 @@ egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
 }
 
 gboolean
-egg_dn_parse (ASN1_TYPE asn, const gchar *part,
-              EggDnCallback callback, gpointer user_data)
+egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
 {
 	gboolean done = FALSE;
-	gchar *path;
-	guchar *value;
+	GNode *node;
+	gconstpointer value;
 	gsize n_value;
 	GQuark oid;
 	guint i, j;
@@ -293,33 +255,26 @@ egg_dn_parse (ASN1_TYPE asn, const gchar *part,
 		for (j = 1; TRUE; ++j) {
 
 			/* Dig out the type */
-			path = g_strdup_printf ("%s%s?%u.?%u.type",
-			                        part ? part : "",
-			                        part ? "." : "", i, j);
-			oid = egg_asn1_read_oid (asn, path);
-			g_free (path);
-
-			if (!oid) {
+			node = egg_asn1x_node (asn, i, j, "type", NULL);
+			if (!node) {
 				done = j == 1;
 				break;
 			}
 
-			/* Print the value as nicely as we can */
-			path = g_strdup_printf ("%s%s?%u.?%u.value",
-			                        part ? part : "",
-			                        part ? "." : "", i, j);
-			value = egg_asn1_read_value (asn, path, &n_value, NULL);
-			g_free (path);
+			oid = egg_asn1x_get_oid_as_quark (node);
+			g_return_val_if_fail (oid, FALSE);
 
-			if (!value) {
+			/* Dig out the value */
+			node = egg_asn1x_node (asn, i, j, "value", NULL);
+			if (!node) {
 				done = j == 1;
 				break;
 			}
 
+			value = egg_asn1x_get_raw_element (node, &n_value);
+
 			if (callback)
 				(callback) (i, oid, value, n_value, user_data);
-
-			g_free (value);
 		}
 	}
 
diff --git a/egg/egg-dn.h b/egg/egg-dn.h
index c205ba7..96fe5ff 100644
--- a/egg/egg-dn.h
+++ b/egg/egg-dn.h
@@ -1,7 +1,7 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* egg-asn1.h - ASN.1 helper routines
+/* egg-dn.h - ASN.1 helper routines
 
-   Copyright (C) 2007 Stefan Walter
+   Copyright (C) 2010 Stefan Walter
 
    The Gnome Keyring Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -26,18 +26,23 @@
 
 #include <glib.h>
 
-#include <libtasn1.h>
+gchar*             egg_dn_read                            (GNode *node);
 
-gchar*             egg_dn_read                            (ASN1_TYPE asn, const gchar *part);
+gchar*             egg_dn_read_part                       (GNode *node,
+                                                           const gchar *match);
 
-gchar*             egg_dn_read_part                       (ASN1_TYPE asn, const gchar *part, const gchar *match);
+typedef void       (*EggDnCallback)                       (guint index,
+                                                           GQuark oid,
+                                                           const guchar *value,
+                                                           gsize n_value,
+                                                           gpointer user_data);
 
-typedef void       (*EggDnCallback)                       (guint index, GQuark oid, const guchar *value,
-                                                           gsize n_value, gpointer user_data);
+gboolean           egg_dn_parse                           (GNode *node,
+                                                           EggDnCallback callback,
+                                                           gpointer user_data);
 
-gboolean           egg_dn_parse                           (ASN1_TYPE asn, const gchar *part,
-                                                           EggDnCallback callback, gpointer user_data);
+gchar*             egg_dn_print_value                     (GQuark oid,
+                                                           const guchar *value,
+                                                           gsize n_value);
 
-gchar*             egg_dn_print_value                     (GQuark oid, const guchar *value, gsize n_value);
-
-#endif /*EGG_DN_H_*/
+#endif /* EGG_DN_H_ */
diff --git a/egg/egg-symkey.c b/egg/egg-symkey.c
index 426c763..a69100f 100644
--- a/egg/egg-symkey.c
+++ b/egg/egg-symkey.c
@@ -21,7 +21,8 @@
 
 #include "config.h"
 
-#include "egg-asn1.h"
+#include "egg-asn1-defs.h"
+#include "egg-asn1x.h"
 #include "egg-secure-memory.h"
 #include "egg-symkey.h"
 
@@ -613,12 +614,12 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
                        const gchar *password, gsize n_password, const guchar *data, 
                        gsize n_data, gcry_cipher_hd_t *cih)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_error_t gcry;
-	const guchar *salt;
+	gconstpointer salt;
 	gsize n_salt;
 	gsize n_block, n_key;
-	guint iterations;
+	gulong iterations;
 	guchar *key = NULL;
 	guchar *iv = NULL;
 	gboolean ret;
@@ -634,17 +635,19 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
 	if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0 ||
 	    gcry_md_test_algo (hash_algo) != 0)
 		goto done;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-5-PBE-params", data, n_data);
-	if (!asn) 
+
+	asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBE-params");
+	g_return_val_if_fail (asn, FALSE);
+
+	if (!egg_asn1x_decode (asn, data, n_data))
 		goto done;
-		
-	salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt);
+
+	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL), &n_salt);
 	if (!salt)
 		goto done;
-	if (!egg_asn1_read_uint (asn, "iterationCount", &iterations))
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
 		iterations = 1;
-		
+
 	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
 	g_return_val_if_fail (n_key > 0, FALSE);
 	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
@@ -668,65 +671,67 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
 done:
 	g_free (iv);
 	egg_secure_free (key);
-	
-	if (asn)
-		asn1_delete_structure (&asn);
-		
+	egg_asn1x_destroy (asn);
+
 	return ret;
 }
 
 static gboolean
 setup_pkcs5_rc2_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_error_t gcry;
 	const guchar *iv;
 	gsize n_iv;
-	guint version;
-	
+	gulong version;
+	gboolean ret = FALSE;
+
 	g_assert (data);
 
-	asn = egg_asn1_decode ("PKIX1.pkcs-5-rc2-CBC-params", data, n_data);
-	if (!asn) 
-		return FALSE;
-		
-	if (!egg_asn1_read_uint (asn, "rc2ParameterVersion", &version))
-		return FALSE;
-	
-	iv = egg_asn1_read_content (asn, data, n_data, "iv", &n_iv);
-	asn1_delete_structure (&asn);
+	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, n_data))
+		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), &n_iv);
 	if (!iv)
-		return FALSE;
-		
+		goto done;
+
 	gcry = gcry_cipher_setiv (cih, iv, n_iv);
-			
 	if (gcry != 0) {
 		g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv);
-		return FALSE;
+		goto done;
 	}
-	
-	return TRUE;
+
+	ret = TRUE;
+
+done:
+	egg_asn1x_destroy (asn);
+	return ret;
 }
 
 static gboolean
 setup_pkcs5_des_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_error_t gcry;
-	const guchar *iv;
+	gconstpointer iv;
 	gsize n_iv;
-	
+
 	g_assert (data);
 
-	asn = egg_asn1_decode ("PKIX1.pkcs-5-des-EDE3-CBC-params", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params", data, n_data);
 	if (!asn)
-		asn = egg_asn1_decode ("PKIX1.pkcs-5-des-CBC-params", data, n_data);
+		asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-CBC-params", data, n_data);
 	if (!asn) 
 		return FALSE;
-	
-	iv = egg_asn1_read_content (asn, data, n_data, "", &n_iv);
-	asn1_delete_structure (&asn);
+
+	iv = egg_asn1x_get_raw_value (asn, &n_iv);
+	egg_asn1x_destroy (asn);
 
 	if (!iv)
 		return FALSE;
@@ -745,29 +750,29 @@ static gboolean
 setup_pkcs5_pbkdf2_params (const gchar *password, gsize n_password, const guchar *data, 
                            gsize n_data, int cipher_algo, gcry_cipher_hd_t cih)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gboolean ret;
 	gcry_error_t gcry;
 	guchar *key = NULL; 
 	const guchar *salt;
 	gsize n_salt, n_key;
-	guint iterations;
-	
+	gulong iterations;
+
 	g_assert (cipher_algo);
 	g_assert (data);
 	
 	ret = FALSE;
 
-	asn = egg_asn1_decode ("PKIX1.pkcs-5-PBKDF2-params", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBKDF2-params", data, n_data);
 	if (!asn)
 		goto done;
-		
-	if (!egg_asn1_read_uint (asn, "iterationCount", &iterations))
+
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
 		iterations = 1;
-	salt = egg_asn1_read_content (asn, data, n_data, "salt.specified", &n_salt);
+	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", "specified", NULL), &n_salt);
 	if (!salt)
 		goto done;
-				
+
 	if (!egg_symkey_generate_pbkdf2 (cipher_algo, GCRY_MD_SHA1, password, n_password, 
 	                                 salt, n_salt, iterations, &key, NULL))
 		goto done;
@@ -785,8 +790,7 @@ setup_pkcs5_pbkdf2_params (const gchar *password, gsize n_password, const guchar
 	                                         
 done:
 	egg_secure_free (key);
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -794,12 +798,13 @@ static gboolean
 read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *data, 
                          gsize n_data, gcry_cipher_hd_t *cih)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gboolean r, ret;
 	GQuark key_deriv_algo, enc_oid;
 	gcry_error_t gcry;
 	int algo, mode;
-	int beg, end;
+	gconstpointer params;
+	gsize n_params;
 
 	g_return_val_if_fail (cih != NULL, FALSE);
 	g_return_val_if_fail (data != NULL && n_data != 0, FALSE);
@@ -808,17 +813,17 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 	
 	*cih = NULL;
 	ret = FALSE;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-5-PBES2-params", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBES2-params", data, n_data);
 	if (!asn)
 		goto done;
-		
+
 	algo = mode = 0;
 	
 	/* Read in all the encryption type */
-	enc_oid = egg_asn1_read_oid (asn, "encryptionScheme.algorithm");
+	enc_oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionScheme", "algorithm", NULL));
 	if (!enc_oid)
-		goto done;	
+		goto done;
 	if (enc_oid == OID_DES_EDE3_CBC)
 		algo = GCRY_CIPHER_3DES;
 	else if (enc_oid == OID_DES_CBC)
@@ -840,17 +845,17 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 	}
 		
 	/* Read out the parameters */
-	if (asn1_der_decoding_startEnd (asn, data, n_data, "encryptionScheme.parameters",
-	                                &beg, &end) != ASN1_SUCCESS)
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL), &n_params);
+	if (!params)
 		goto done;
-		
+
 	switch (algo) {
 	case GCRY_CIPHER_3DES:
 	case GCRY_CIPHER_DES:
-		r = setup_pkcs5_des_params (data + beg, end - beg + 1, *cih);
+		r = setup_pkcs5_des_params (params, n_params, *cih);
 		break;
 	case GCRY_CIPHER_RFC2268_128:
-		r = setup_pkcs5_rc2_params (data + beg, end - beg + 1, *cih);
+		r = setup_pkcs5_rc2_params (params, n_params, *cih);
 		break;
 	default:
 		/* Should have been caught on the oid check above */
@@ -863,7 +868,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 		goto done;
 
 	/* Read out the key creation paramaters */
-	key_deriv_algo = egg_asn1_read_oid (asn, "keyDerivationFunc.algorithm");
+	key_deriv_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "keyDerivationFunc", "algorithm", NULL));
 	if (!key_deriv_algo)
 		goto done;
 	if (key_deriv_algo != OID_PBKDF2) {
@@ -871,21 +876,19 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 		goto done;
 	}
 
-	if (asn1_der_decoding_startEnd (asn, data, n_data, "keyDerivationFunc.parameters",
-	                                &beg, &end) != ASN1_SUCCESS)
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL), &n_params);
+	if (!params)
 		goto done;
-	
-	ret = setup_pkcs5_pbkdf2_params (password, n_password, data + beg, end - beg + 1, algo, *cih);
+
+	ret = setup_pkcs5_pbkdf2_params (password, n_password, params, n_params, algo, *cih);
 
 done:
 	if (ret != TRUE && *cih) {
 		gcry_cipher_close (*cih);
 		*cih = NULL;
 	}
-	
-	if (asn)
-		asn1_delete_structure (&asn);
-	
+
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -894,16 +897,16 @@ read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password,
                         gsize n_password, const guchar *data, gsize n_data, 
                         gcry_cipher_hd_t *cih)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_error_t gcry;
 	gboolean ret;
 	const guchar *salt;
 	gsize n_salt;
 	gsize n_block, n_key;
-	guint iterations;
+	gulong iterations;
 	guchar *key = NULL;
 	guchar *iv = NULL;
-	
+
 	g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, FALSE);
 	g_return_val_if_fail (cih != NULL, FALSE);
 	g_return_val_if_fail (data != NULL && n_data != 0, FALSE);
@@ -914,15 +917,15 @@ read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password,
 	/* Check if we can use this algorithm */
 	if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
 		goto done;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-12-PbeParams", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PbeParams", data, n_data);
 	if (!asn)
 		goto done;
 
-	salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt);
+	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL), &n_salt);
 	if (!salt)
 		goto done;
-	if (!egg_asn1_read_uint (asn, "iterations", &iterations))
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
 		goto done;
 	
 	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
@@ -954,10 +957,7 @@ done:
 	
 	g_free (iv);
 	egg_secure_free (key);
-	
-	if (asn)
-		asn1_delete_structure (&asn);
-	
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
diff --git a/egg/tests/Makefile.am b/egg/tests/Makefile.am
index eddb066..2e7e692 100644
--- a/egg/tests/Makefile.am
+++ b/egg/tests/Makefile.am
@@ -1,8 +1,5 @@
-asn1-def-test.h: test.asn
-	$(ASN1PARSER) -o asn1-def-test.h $(srcdir)/test.asn
-
-asn1-def-tests.h: tests.asn
-	$(ASN1PARSER) -o asn1-def-tests.h $(srcdir)/tests.asn
+asn1-def-test.c: test.asn
+	$(ASN1PARSER) -o asn1-def-test.c $(srcdir)/test.asn
 
 # Test files should be listed in order they need to run
 TESTING_FILES = \
@@ -18,8 +15,7 @@ TESTING_FILES = \
 	unit-test-openssl.c \
 	unit-test-dh.c \
 	unit-test-spawn.c \
-	asn1-def-test.h \
-	asn1-def-tests.h
+	asn1-def-test.c
 
 UNIT_PROMPT = 
 
@@ -28,13 +24,12 @@ TESTING_LIBS =  \
 
 EXTRA_DIST = \
 	test.asn \
-	tests.asn \
 	test-data
 
 include $(top_srcdir)/testing/testing.make
 
 BUILT_SOURCES += \
-	asn1-def-test.h
+	asn1-def-test.c
 
 # ------------------------------------------------------------------------------
 
diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c
index d550984..57d4aac 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -28,12 +28,13 @@
 #include "egg/egg-asn1x.h"
 
 #include <glib.h>
+#include <libtasn1.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "asn1-def-tests.h"
+extern const ASN1_ARRAY_TYPE test_asn1_tab[];
 
 const gchar I33[] =           "\x02\x01\x2A";
 const gchar BFALSE[] =        "\x01\x01\x00";
@@ -42,6 +43,9 @@ const gchar SFARNSWORTH[] =   "\x04\x0A""farnsworth";
 const gchar SIMPLICIT[] =     "\x85\x08""implicit";
 const gchar SEXPLICIT[] =     "\xE5\x0A\x04\x08""explicit";
 const gchar TGENERALIZED[] =  "\x18\x0F""20070725130528Z";
+const gchar BITS_TEST[] =  "\x03\x04\x06\x6e\x5d\xc0";
+const gchar BITS_BAD[] =  "\x03\x04\x06\x6e\x5d\xc1";
+const gchar BITS_ZERO[] =  "\x03\x01\x00";
 
 #define XL(x) G_N_ELEMENTS (x) - 1
 
@@ -50,7 +54,7 @@ DEFINE_TEST(asn1_boolean)
 	GNode *asn;
 	gboolean value;
 
-	asn = egg_asn1x_create (tests_asn1_tab, "TestBoolean");
+	asn = egg_asn1x_create (test_asn1_tab, "TestBoolean");
 	g_assert (asn);
 
 	/* Shouldn't succeed */
@@ -87,7 +91,7 @@ DEFINE_TEST(asn1_integer)
 	GNode *asn;
 	gulong value;
 
-	asn = egg_asn1x_create (tests_asn1_tab, "TestInteger");
+	asn = egg_asn1x_create (test_asn1_tab, "TestInteger");
 	g_assert (asn);
 
 	/* Shouldn't succeed */
@@ -115,7 +119,7 @@ DEFINE_TEST(asn1_octet_string)
 	GNode *asn;
 	gchar *value;
 
-	asn = egg_asn1x_create (tests_asn1_tab, "TestOctetString");
+	asn = egg_asn1x_create (test_asn1_tab, "TestOctetString");
 	g_assert (asn);
 
 	/* Shouldn't succeed */
@@ -143,7 +147,7 @@ DEFINE_TEST(asn1_generalized_time)
 	GNode *asn;
 	glong value;
 
-	asn = egg_asn1x_create (tests_asn1_tab, "TestGeneralized");
+	asn = egg_asn1x_create (test_asn1_tab, "TestGeneralized");
 	g_assert (asn);
 
 	/* Shouldn't succeed */
@@ -170,7 +174,7 @@ DEFINE_TEST(asn1_implicit)
 	GNode *asn;
 	gchar *value;
 
-	asn = egg_asn1x_create (tests_asn1_tab, "TestImplicit");
+	asn = egg_asn1x_create (test_asn1_tab, "TestImplicit");
 	g_assert (asn);
 
 	/* Should work */
@@ -188,7 +192,7 @@ DEFINE_TEST(asn1_explicit)
 	GNode *asn;
 	gchar *value;
 
-	asn = egg_asn1x_create (tests_asn1_tab, "TestExplicit");
+	asn = egg_asn1x_create (test_asn1_tab, "TestExplicit");
 	g_assert (asn);
 
 	/* Should work */
@@ -200,3 +204,214 @@ DEFINE_TEST(asn1_explicit)
 
 	egg_asn1x_destroy (asn);
 }
+
+DEFINE_TEST(asn1_bit_string_decode)
+{
+	GNode *asn;
+	guchar *bits;
+	guint n_bits;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+	g_assert (asn);
+
+	/* Should work */
+	if (!egg_asn1x_decode (asn, BITS_TEST, XL (BITS_TEST)))
+		g_assert_not_reached ();
+
+	bits = egg_asn1x_get_bits_as_raw (asn, NULL, &n_bits);
+	g_assert (bits);
+	g_assert_cmpuint (n_bits, ==, 18);
+	g_assert_cmpint (bits[0], ==, 0x6e);
+	g_assert_cmpint (bits[1], ==, 0x5d);
+	g_assert_cmpint (bits[2], ==, 0xc0);
+
+	g_free (bits);
+	egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_decode_bad)
+{
+	GNode *asn;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+	g_assert (asn);
+
+	/* Should not work */
+	if (egg_asn1x_decode (asn, BITS_BAD, XL (BITS_BAD)))
+		g_assert_not_reached ();
+
+	egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_decode_ulong)
+{
+	GNode *asn;
+	gulong bits;
+	guint n_bits;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+	g_assert (asn);
+
+	/* Should work */
+	if (!egg_asn1x_decode (asn, BITS_TEST, XL (BITS_TEST)))
+		g_assert_not_reached ();
+
+	if (!egg_asn1x_get_bits_as_ulong (asn, &bits, &n_bits))
+		g_assert_not_reached ();
+
+	g_assert_cmpuint (n_bits, ==, 18);
+	g_assert_cmphex (bits, ==, 0x1b977);
+
+	egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_encode_decode)
+{
+	GNode *asn;
+	guchar bits[] = { 0x5d, 0x6e, 0x83 };
+	guchar *check;
+	guint n_check, n_bits = 17;
+	gpointer data;
+	gsize n_data;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_bits_as_raw (asn, bits, n_bits, NULL))
+		g_assert_not_reached ();
+
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (data);
+
+	if (!egg_asn1x_decode (asn, data, n_data))
+		g_assert_not_reached ();
+
+	check = egg_asn1x_get_bits_as_raw (asn, NULL, &n_check);
+	g_assert (check);
+	g_assert_cmpuint (n_check, ==, 17);
+	g_assert_cmpint (check[0], ==, 0x5d);
+	g_assert_cmpint (check[1], ==, 0x6e);
+	g_assert_cmpint (check[2], ==, 0x80);
+
+	g_free (check);
+
+	g_free (data);
+	egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_encode_decode_ulong)
+{
+	GNode *asn;
+	gulong check, bits = 0x0101b977;
+	guint n_check, n_bits = 18;
+	gpointer data;
+	gsize n_data;
+
+	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 ();
+
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (data);
+
+	if (!egg_asn1x_decode (asn, data, n_data))
+		g_assert_not_reached ();
+
+	if (!egg_asn1x_get_bits_as_ulong (asn, &check, &n_check))
+		g_assert_not_reached ();
+
+	g_assert_cmpuint (n_check, ==, 18);
+	g_assert_cmphex (check, ==, 0x1b977);
+
+	g_free (data);
+	egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_encode_decode_zero)
+{
+	GNode *asn;
+	gpointer data;
+	gsize n_data;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_bits_as_raw (asn, (guchar*)"", 0, NULL))
+		g_assert_not_reached ();
+
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (data);
+
+	g_assert_cmpsize (n_data, ==, XL (BITS_ZERO));
+	g_assert (memcmp (data, BITS_ZERO, n_data) == 0);
+
+	g_free (data);
+	egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_have)
+{
+	GNode *asn;
+	guchar *data;
+	gsize n_data;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestBoolean");
+	g_assert (asn);
+
+	g_assert (!egg_asn1x_have (asn));
+
+	if (!egg_asn1x_set_boolean (asn, TRUE))
+		g_assert_not_reached ();
+
+	g_assert (!egg_asn1x_have (asn));
+
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (data);
+
+	g_assert (egg_asn1x_have (asn));
+
+	g_free (data);
+	egg_asn1x_destroy (asn);
+}
+
+static gboolean is_freed = FALSE;
+
+static void
+test_is_freed (gpointer unused)
+{
+	g_assert (!is_freed);
+	is_freed = TRUE;
+}
+
+DEFINE_TEST(asn1_any_set_raw)
+{
+	GNode *asn, *node;
+	guchar *data;
+	const guchar *check;
+	gsize n_data, n_check;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestAnySeq");
+	g_assert (asn);
+
+	is_freed = FALSE;
+	node = egg_asn1x_node (asn, "contents", NULL);
+	g_assert (node);
+
+	if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
+		g_assert_not_reached ();
+
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (data);
+
+	check = egg_asn1x_get_raw_element (node, &n_check);
+	g_assert (check);
+
+	g_assert (n_check == XL (SFARNSWORTH));
+	g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+
+	g_free (data);
+	egg_asn1x_destroy (asn);
+	g_assert (is_freed);
+}
diff --git a/egg/tests/test-asn1x.c b/egg/tests/test-asn1x.c
index c71a29f..b397754 100644
--- a/egg/tests/test-asn1x.c
+++ b/egg/tests/test-asn1x.c
@@ -6,10 +6,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#define extern
-#include "egg/asn1-def-pkix.h"
-#include "egg/asn1-def-pk.h"
-#undef extern
+#include "egg/egg-asn1-defs.h"
 
 #if 0
 static void
@@ -86,6 +83,7 @@ run (void)
 	test_some_asn1_stuff (pk_asn1_tab, "test-rsakey-1.der", "RSAPrivateKey");
 	test_some_asn1_stuff (pkix_asn1_tab, "test-personalname-1.der", "PersonalName");
 	test_some_asn1_stuff (pkix_asn1_tab, "test-pkcs7-1.der", "pkcs-7-ContentInfo");
+	test_some_asn1_stuff (pkix_asn1_tab, "test-pkcs7-2.der", "pkcs-7-ContentInfo");
 	test_some_asn1_stuff (pkix_asn1_tab, "test-pkcs12-1.der", "pkcs-12-PFX");
 
 	return 0;
diff --git a/egg/tests/test-data/test-pkcs7-2.der b/egg/tests/test-data/test-pkcs7-2.der
new file mode 100755
index 0000000..d45b9e0
Binary files /dev/null and b/egg/tests/test-data/test-pkcs7-2.der differ
diff --git a/egg/tests/test-dn.c b/egg/tests/test-dn.c
index 6ad3811..aa0a61c 100644
--- a/egg/tests/test-dn.c
+++ b/egg/tests/test-dn.c
@@ -25,7 +25,8 @@
 
 #include "test-suite.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-asn1x.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-oid.h"
 
@@ -37,31 +38,24 @@
 #include <stdio.h>
 #include <string.h>
 
-static ASN1_TYPE asn1_cert = NULL;
+static GNode* asn1_cert = NULL;
 static guchar *data_cert = NULL;
 static gsize n_data_cert = 0;
 
 DEFINE_SETUP(dn_cert)
 {
-	ASN1_TYPE pkix;
-	int res;
-
 	data_cert = testing_data_read ("test-certificate-1.der", &n_data_cert);
 
-	/* We'll be catching this error later */
-	pkix = egg_asn1_get_pkix_asn1type ();
-	if (!pkix) return;
-
-	res = asn1_create_element (pkix, "PKIX1.Certificate", &asn1_cert);
-	g_assert (res == ASN1_SUCCESS);
+	asn1_cert = egg_asn1x_create (pkix_asn1_tab, "Certificate");
+	g_assert (asn1_cert != NULL);
 
-	res = asn1_der_decoding (&asn1_cert, data_cert, n_data_cert, NULL);
-	g_assert (res == ASN1_SUCCESS);
+	if (!egg_asn1x_decode (asn1_cert, data_cert, n_data_cert))
+		g_assert_not_reached ();
 }
 
 DEFINE_TEARDOWN(dn_cert)
 {
-	asn1_delete_structure (&asn1_cert);
+	egg_asn1x_destroy (asn1_cert);
 	g_free (data_cert);
 	data_cert = NULL;
 }
@@ -70,14 +64,11 @@ DEFINE_TEST(read_dn)
 {
 	gchar *dn;
 
-	dn = egg_dn_read (asn1_cert, "tbsCertificate.issuer.rdnSequence");
+	dn = egg_dn_read (egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL));
 	g_assert (dn != NULL);
 	g_assert_cmpstr (dn, ==, "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Premium CA, EMAIL=personal-premium thawte com");
 
 	g_free (dn);
-
-	dn = egg_dn_read (asn1_cert, "tbsCertificate.nonExistant");
-	g_assert (dn == NULL);
 }
 
 DEFINE_TEST(dn_value)
@@ -132,7 +123,7 @@ DEFINE_TEST(parse_dn)
 	GString *dn = g_string_new ("");
 	last_index = 1;
 
-	if (!egg_dn_parse (asn1_cert, "tbsCertificate.issuer.rdnSequence", concatenate_dn, dn))
+	if (!egg_dn_parse (egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL), concatenate_dn, dn))
 		g_assert_not_reached ();
 
 	g_assert_cmpstr (dn->str, ==, "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Premium CA, EMAIL=personal-premium thawte com");
@@ -141,27 +132,27 @@ DEFINE_TEST(parse_dn)
 
 DEFINE_TEST(read_dn_part)
 {
+	GNode *node;
 	gchar *value;
 
-	value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "CN");
+	node = egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL);
+
+	value = egg_dn_read_part (node, "CN");
 	g_assert (value != NULL);
 	g_assert_cmpstr (value, ==, "Thawte Personal Premium CA");
 	g_free (value);
 
-	value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "2.5.4.8");
+	value = egg_dn_read_part (node, "2.5.4.8");
 	g_assert (value != NULL);
 	g_assert_cmpstr (value, ==, "Western Cape");
 	g_free (value);
 
-	value = egg_dn_read_part (asn1_cert, "tbsCertificate.nonExistant", "CN");
-	g_assert (value == NULL);
-
-	value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "DC");
+	value = egg_dn_read_part (node, "DC");
 	g_assert (value == NULL);
 
-	value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "0.0.0.0");
+	value = egg_dn_read_part (node, "0.0.0.0");
 	g_assert (value == NULL);
 
-	value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "2.5.4.9");
+	value = egg_dn_read_part (node, "2.5.4.9");
 	g_assert (value == NULL);
 }
diff --git a/egg/tests/test.asn b/egg/tests/test.asn
index 0a9c7d1..f5f3053 100644
--- a/egg/tests/test.asn
+++ b/egg/tests/test.asn
@@ -1,9 +1,23 @@
-TEST { }
+TESTS { }
 
 DEFINITIONS EXPLICIT TAGS ::=
 
 BEGIN
 
+TestInteger ::= INTEGER
+
+TestBoolean ::= BOOLEAN
+
+TestOctetString ::= OCTET STRING
+
+TestGeneralized ::= GeneralizedTime
+
+TestImplicit ::= [5] IMPLICIT OCTET STRING
+
+TestExplicit ::= [5] EXPLICIT OCTET STRING
+
+TestBitString ::= BIT STRING
+
 TestIntegers ::= SEQUENCE {
 	uint1                   INTEGER,
 	uint2			INTEGER,
@@ -11,8 +25,19 @@ TestIntegers ::= SEQUENCE {
 }
 
 TestData ::= SEQUENCE {
-	data			OCTET STRING,
+	data                    OCTET STRING
+}
+
+TestBooleanSeq ::= SEQUENCE {
 	boolean                 BOOLEAN DEFAULT FALSE
 }
 
+TestOid ::= SEQUENCE {
+	oid                     OBJECT IDENTIFIER
+}
+
+TestAnySeq ::= SEQUENCE {
+	contents                ANY
+}
+
 END
diff --git a/egg/tests/unit-test-asn1.c b/egg/tests/unit-test-asn1.c
index 61fd605..63c835d 100644
--- a/egg/tests/unit-test-asn1.c
+++ b/egg/tests/unit-test-asn1.c
@@ -25,7 +25,8 @@
 
 #include "test-suite.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-asn1x.h"
 #include "egg/egg-oid.h"
 
 #include <glib.h>
@@ -36,260 +37,249 @@
 #include <stdio.h>
 #include <string.h>
 
-#define extern 
-#include "asn1-def-test.h"
-#undef extern
+extern const ASN1_ARRAY_TYPE test_asn1_tab[];
 
-static ASN1_TYPE asn1_test = NULL;
-
-static ASN1_TYPE asn1_cert = NULL;
+static GNode *asn1_cert = NULL;
 static guchar *data_cert = NULL;
 static gsize n_data_cert = 0;
 
 DEFINE_SETUP(asn1_tree)
 {
-	ASN1_TYPE pkix;
-	
-	int res = asn1_array2tree (test_asn1_tab, &asn1_test, NULL);
-	g_assert (res == ASN1_SUCCESS);
-
-	/* -------- */
-	
 	data_cert = testing_data_read ("test-certificate-1.der", &n_data_cert);
 
-	/* We'll be catching this error later */
-	pkix = egg_asn1_get_pkix_asn1type ();
-	if (!pkix) return;
-	
-	res = asn1_create_element (pkix, "PKIX1.Certificate", &asn1_cert); 
-	g_assert (res == ASN1_SUCCESS);
-	
-	res = asn1_der_decoding (&asn1_cert, data_cert, n_data_cert, NULL);
-	g_assert (res == ASN1_SUCCESS);
+	asn1_cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data_cert, n_data_cert);
+	g_assert (asn1_cert != NULL);
 }
 
 DEFINE_TEARDOWN(asn1_tree)
 {
-	asn1_delete_structure (&asn1_test);
-	asn1_delete_structure (&asn1_cert);
+	egg_asn1x_destroy (asn1_cert);
 	g_free (data_cert);
 	data_cert = NULL;
 }
 
-DEFINE_TEST(asn1_types)
+DEFINE_TEST(node_name)
 {
-	ASN1_TYPE asn;
-	
-	asn = egg_asn1_get_pk_asn1type ();
-	g_assert ("pk asn type is null" && asn != NULL);
-
-	asn = egg_asn1_get_pkix_asn1type ();
-	g_assert ("pkix asn type is null" && asn != NULL);
+	g_assert_cmpstr (egg_asn1x_name (asn1_cert), ==, "Certificate");
 }
 
 DEFINE_TEST(asn1_integers)
 {
-	ASN1_TYPE asn;
+	GNode *asn;
 	guchar *data;
 	gsize n_data;
 	gboolean ret;
-	guint val;
-	int res;
-	
-	res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn);
+	gulong val;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestIntegers");
 	g_assert ("asn test structure is null" && asn != NULL);
 
-	ret = egg_asn1_write_uint (asn, "uint1", 35);
+	ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), 35);
 	g_assert ("couldn't write integer" && ret);
-	
-	ret = egg_asn1_write_uint (asn, "uint2", 23456);
+
+	ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), 23456);
 	g_assert ("couldn't write integer" && ret);
-	
-	ret = egg_asn1_write_uint (asn, "uint3", 209384022);
+
+	ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), 209384022);
 	g_assert ("couldn't write integer" && ret);
 	
 	/* Now encode the whole caboodle */
-	data = egg_asn1_encode (asn, "", &n_data, NULL);
+	data = egg_asn1x_encode (asn, NULL, &n_data);
 	g_assert ("encoding asn1 didn't work" && data != NULL);
-	
-	asn1_delete_structure (&asn);
-	
+
+	egg_asn1x_destroy (asn);
+
 	/* Now decode it all nicely */
-	res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn); 
-	g_return_if_fail (res == ASN1_SUCCESS);
-	
-	res = asn1_der_decoding (&asn, data, n_data, NULL);
-	g_assert ("decoding asn didn't work" && res == ASN1_SUCCESS);
-	
+	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestIntegers", data, n_data);
+	g_return_if_fail (asn != NULL);
+
 	/* And get out the values */
-	ret = egg_asn1_read_uint (asn, "uint1", &val);
+	ret = egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), &val);
 	g_assert ("couldn't read integer from asn1" && ret);
 	g_assert_cmpuint (val, ==, 35);
-	
-	ret = egg_asn1_read_uint (asn, "uint2", &val);
+
+	ret = egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), &val);
 	g_assert ("couldn't read integer from asn1" && ret);
 	g_assert_cmpuint (val, ==, 23456);
 
-	ret = egg_asn1_read_uint (asn, "uint3", &val);
+	ret = egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), &val);
 	g_assert ("couldn't read integer from asn1" && ret);
 	g_assert_cmpuint (val, ==, 209384022);
+
+	g_free (data);
 }
 
 DEFINE_TEST(boolean)
 {
-	ASN1_TYPE asn = NULL;
+	GNode *asn = NULL;
 	gboolean value, ret;
-	int res;
-	
-	res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+	gpointer data;
+	gsize n_data;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq");
 	g_assert ("asn test structure is null" && asn != NULL);
-	
-	res = asn1_write_value (asn, "boolean", "TRUE", 4);
-	g_assert (res == ASN1_SUCCESS);
-	
-	ret = egg_asn1_read_boolean (asn, "boolean", &value);
+
+	/* Get the default value */
+	value = TRUE;
+	ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
+	g_assert (ret == TRUE);
+	g_assert (value == FALSE);
+
+	ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), TRUE);
+	g_assert (ret == TRUE);
+
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (data);
+
+	ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
 	g_assert (ret);
 	g_assert (value == TRUE);
-	
-	res = asn1_write_value (asn, "boolean", "FALSE", 5);
-	g_assert (res == ASN1_SUCCESS);
 
-	ret = egg_asn1_read_boolean (asn, "boolean", &value);
+	ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), FALSE);
+	g_assert (ret == TRUE);
+
+	g_free (data);
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (data);
+
+	ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
 	g_assert (ret);
 	g_assert (value == FALSE);
-	
-	ret = egg_asn1_read_boolean (asn, "nonExistant", &value);
-	g_assert (!ret);
-	
-	asn1_delete_structure (&asn);
+
+	g_free (data);
+	egg_asn1x_destroy (asn);
 }
 
 DEFINE_TEST(write_value)
 {
-	ASN1_TYPE asn = NULL;
+	GNode *asn = NULL;
 	guchar *data;
 	gsize n_data;
-	int res;
-		
-	res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+	guchar *encoded;
+	gsize n_encoded;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestData");
 	g_assert ("asn test structure is null" && asn != NULL);
-		
-	if (!egg_asn1_write_value (asn, "data", (const guchar*)"SOME DATA", 9))
+
+	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
 		g_assert_not_reached ();
 
-	data = egg_asn1_read_value (asn, "data", &n_data, NULL);
+	encoded = egg_asn1x_encode (asn, NULL, &n_encoded);
+	g_assert (encoded);
+
+	data = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "data", NULL), NULL, &n_data);
 	g_assert (data != NULL);
 	g_assert_cmpuint (n_data, ==, 9);
 	g_assert (memcmp (data, "SOME DATA", 9) == 0);
 	g_free (data);
-	
-	asn1_delete_structure (&asn); 
+
+	g_free (encoded);
+	egg_asn1x_destroy (asn);
 }
 
 DEFINE_TEST(element_length_content)
 {
-	ASN1_TYPE asn = NULL;
-	guchar buffer[1024];
+	GNode *asn = NULL;
+	gchar *buffer;
 	const guchar *content;
 	gsize n_content;
-	gint length;
-	int res;
-	
-	res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+	gsize n_buffer;
+	gssize length;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestData");
 	g_assert ("asn test structure is null" && asn != NULL);
-	
-	res = asn1_write_value (asn, "data", "SOME DATA", 9);
-	g_assert (res == ASN1_SUCCESS);
-	
-	length = 1024;
-	res = asn1_der_coding (asn, "", buffer, &length, NULL);
-	g_assert (res == ASN1_SUCCESS);
-	
+
+	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
+		g_assert_not_reached ();
+
+	buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+	g_assert (buffer != NULL);
+
 	/* Now the real test */
-	length = egg_asn1_element_length (buffer, 1024);
+	length = egg_asn1x_element_length (buffer, n_buffer + 1024);
 	g_assert_cmpint (length, ==, 13);
-	
-	content = egg_asn1_element_content (buffer, length, &n_content);
+
+	content = egg_asn1x_element_content (buffer, length, &n_content);
 	g_assert (content);
 	g_assert_cmpuint (n_content, ==, 11);
 	
-	content = egg_asn1_element_content (content, n_content, &n_content);
+	content = egg_asn1x_element_content (content, n_content, &n_content);
 	g_assert (content);
 	g_assert_cmpuint (n_content, ==, 9);	
 	g_assert (memcmp (content, "SOME DATA", 9) == 0);
-	
-	asn1_delete_structure (&asn);
+
+	egg_asn1x_destroy (asn);
+	g_free (buffer);
 }
 
 DEFINE_TEST(read_element)
 {
-	ASN1_TYPE asn = NULL;
-	guchar buffer[1024];
-	const guchar *data;
+	GNode *asn = NULL;
+	guchar *buffer;
+	gconstpointer data;
 	gsize n_data;
-	gint length;
-	int res;
-	
-	res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+	gsize n_buffer;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestData");
 	g_assert ("asn test structure is null" && asn != NULL);
-	
-	res = asn1_write_value (asn, "data", "SOME DATA", 9);
-	g_assert (res == ASN1_SUCCESS);
-	
-	length = 1024;
-	res = asn1_der_coding (asn, "", buffer, &length, NULL);
-	g_assert (res == ASN1_SUCCESS);
-	
+
+	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
+		g_assert_not_reached ();
+
+	buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+	g_assert (buffer != NULL);
+
 	/* Now the real test */
-	data = egg_asn1_read_element (asn, buffer, length, "data", &n_data);
+	data = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "data", NULL), &n_data);
 	g_assert (data != NULL);
 	g_assert_cmpint (n_data, ==, 11);
 
-	data = egg_asn1_read_content (asn, buffer, length, "data", &n_data);
+	data = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "data", NULL), &n_data);
 	g_assert (data);
-	g_assert_cmpuint (n_data, ==, 9);	
+	g_assert_cmpuint (n_data, ==, 9);
 	g_assert (memcmp (data, "SOME DATA", 9) == 0);
-	
-	/* Invalid should return null for both those */
-	data = egg_asn1_read_element (asn, buffer, length, "nonExistant", &n_data);
-	g_assert (data == NULL);
-	data = egg_asn1_read_content (asn, buffer, length, "nonExistant", &n_data);
-	g_assert (data == NULL);
-	
-	asn1_delete_structure (&asn);
+
+	egg_asn1x_destroy (asn);
+	g_free (buffer);
 }
 
 DEFINE_TEST(oid)
 {
-	ASN1_TYPE asn = NULL;
+	GNode *asn = NULL;
 	GQuark oid, check;
-	int res;
-	
-	res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+	guchar *buffer;
+	gsize n_buffer;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestOid");
 	g_assert ("asn test structure is null" && asn != NULL);
-	
-	res = asn1_write_value (asn, "data", "SOME DATA", 9);
-	g_assert (res == ASN1_SUCCESS);
 
-	/* No such element, should return 0 */
-	oid = egg_asn1_read_oid (asn, "nonExistant");
-	g_assert (oid == 0);
+	if (!egg_asn1x_set_oid_as_string (egg_asn1x_node (asn, "oid", NULL), "1.2.34567.89"))
+		g_assert_not_reached ();
+
+	buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+	g_assert (buffer != NULL);
 
 	/* Now a quark has been defined */
-	check = g_quark_from_static_string ("SOME DATA");
-	oid = egg_asn1_read_oid (asn, "data");
+	check = g_quark_from_static_string ("1.2.34567.89");
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "oid", NULL));
+	g_assert (oid);
 	g_assert (check == oid);
-	g_assert_cmpstr (g_quark_to_string (oid), ==, "SOME DATA");
-	
+	g_assert_cmpstr (g_quark_to_string (oid), ==, "1.2.34567.89");
+
 	/* Write a different OID */ 
-	if (!egg_asn1_write_oid (asn, "data", g_quark_from_static_string ("ANOTHER")))
+	if (!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "oid", NULL), g_quark_from_static_string ("5.4.3.2.1678")))
 		g_assert_not_reached ();
-	
-	oid = egg_asn1_read_oid (asn, "data");
+
+	g_free (buffer);
+	buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+	g_assert (buffer != NULL);
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "oid", NULL));
 	g_assert (oid);
-	g_assert_cmpstr (g_quark_to_string (oid), ==, "ANOTHER");
-	
-	asn1_delete_structure (&asn);
+	g_assert_cmpstr (g_quark_to_string (oid), ==, "5.4.3.2.1678");
+
+	g_free (buffer);
+	egg_asn1x_destroy (asn);
 }
 
 typedef struct _TimeTestData {
@@ -332,7 +322,7 @@ DEFINE_TEST(general_time)
 	const TimeTestData *data;
 	
 	for (data = generalized_time_test_data; data->value; ++data) {
-		when = egg_asn1_time_parse_general (data->value, -1);
+		when = egg_asn1x_parse_time_general (data->value, -1);
 		if (data->ref != when) {
 			printf ("%s", data->value);
 			printf ("%s != ", ctime (&when));
@@ -350,7 +340,7 @@ DEFINE_TEST(utc_time)
 	const TimeTestData *data;
 	
 	for (data = utc_time_test_data; data->value; ++data) {
-		when = egg_asn1_time_parse_utc (data->value, -1);
+		when = egg_asn1x_parse_time_utc (data->value, -1);
 		if (data->ref != when) {
 			printf ("%s", data->value);
 			printf ("%s != ", ctime (&when));
@@ -364,19 +354,56 @@ DEFINE_TEST(utc_time)
 
 DEFINE_TEST(read_time)
 {
-	time_t time;
-	
-	if (!egg_asn1_read_time (asn1_cert, "tbsCertificate.validity.notBefore", &time))
-		g_assert_not_reached ();
+	glong time;
+
+	time = egg_asn1x_get_time_as_long (egg_asn1x_node (asn1_cert, "tbsCertificate", "validity", "notBefore", NULL));
 	g_assert_cmpint (time, ==, 820454400);
 }
 
 DEFINE_TEST(read_date)
 {
 	GDate date;
-	if (!egg_asn1_read_date (asn1_cert, "tbsCertificate.validity.notAfter", &date))
+	if (!egg_asn1x_get_time_as_date (egg_asn1x_node (asn1_cert, "tbsCertificate", "validity", "notAfter", NULL), &date))
 		g_assert_not_reached ();
 	g_assert_cmpint (date.day, ==, 31);
 	g_assert_cmpint (date.month, ==, 12);
 	g_assert_cmpint (date.year, ==, 2020);
 }
+
+DEFINE_TEST(create_by_oid)
+{
+	/* id-at-initials = X520initials */
+	GNode *node = egg_asn1x_create (pkix_asn1_tab, "2.5.4.43");
+	g_assert (node != NULL);
+	g_assert_cmpstr (egg_asn1x_name (node), ==, "X520initials");
+	egg_asn1x_destroy (node);
+}
+
+DEFINE_TEST(create_by_oid_invalid)
+{
+	GNode *node = egg_asn1x_create (pkix_asn1_tab, "23.23.23.23");
+	g_assert (node == NULL);
+}
+
+DEFINE_TEST(create_by_bad_order)
+{
+	/*
+	 * In pkix.asn the definition for parts of this oid
+	 * come in the wrong order. However this should still work.
+	 */
+
+	/* id-pe-authorityInfoAccess = AuthorityInfoAccessSyntax */
+	GNode *node = egg_asn1x_create (pkix_asn1_tab, "1.3.6.1.5.5.7.1.1");
+	g_assert (node != NULL);
+	g_assert_cmpstr (egg_asn1x_name (node), ==, "AuthorityInfoAccessSyntax");
+	egg_asn1x_destroy (node);
+}
+
+DEFINE_TEST(count)
+{
+	GNode *node;
+
+	node = egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL);
+	g_assert (node);
+	g_assert_cmpuint (egg_asn1x_count (node), ==, 7);
+}
diff --git a/gcr/gcr-certificate-details-widget.c b/gcr/gcr-certificate-details-widget.c
index 48e6fba..4178e30 100644
--- a/gcr/gcr-certificate-details-widget.c
+++ b/gcr/gcr-certificate-details-widget.c
@@ -22,7 +22,8 @@
 #include "gcr-certificate.h"
 #include "gcr-certificate-details-widget.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-oid.h"
 #include "egg/egg-hex.h"
@@ -178,58 +179,51 @@ append_fingerprint (GcrCertificateDetailsWidget *self, const guchar *data,
 }
 
 static gboolean
-append_extension (GcrCertificateDetailsWidget *self, ASN1_TYPE asn, 
+append_extension (GcrCertificateDetailsWidget *self, GNode *asn,
                   const guchar *data, gsize n_data, gint index)
 {
 	GQuark oid;
-	gchar *name, *display;
+	gchar *display;
 	gsize n_value;
 	const guchar *value;
 	const gchar *text;
 	gboolean critical;
-	int len, res;
-	
+	GNode *node;
+
 	/* Make sure it is present */
-	len = 0;
-	name = g_strdup_printf ("tbsCertificate.extensions.?%u", index);
-	res = asn1_read_value (asn, name, NULL, &len);
-	g_free (name);
-	
-	if (res == ASN1_ELEMENT_NOT_FOUND)
+	asn = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
+	if (asn == NULL)
 		return FALSE;
 
 	/* Dig out the OID */
-	name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnID", index);
-	oid = egg_asn1_read_oid (asn, name);
-	g_free (name);
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "extnID", NULL));
 	g_return_val_if_fail (oid, FALSE);
-	
-	
+
+
 	append_heading (self, _("Extension"));
-	
-	
+
+
 	/* Extension type */
 	text = egg_oid_get_description (oid);
 	append_field_and_value (self, _("Identifier"), text, FALSE);
-	
-	
+
+
 	/* Extension value */
-	name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnValue", index);
-	value = egg_asn1_read_content (asn, data, n_data, name, &n_value);
-	g_free (name);
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "extnValue", NULL), &n_value);
 
 	/* TODO: Parsing of extensions that we understand */
 	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
 	append_field_and_value (self, _("Value"), display, TRUE);
 	g_free (display);
 
-	
+
 	/* Critical */
-	name = g_strdup_printf ("tbsCertificate.extensions.?%u.critical", index);
-	if (egg_asn1_read_boolean (asn, name, &critical))
-		append_field_and_value (self, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
-	g_free (name);
-	
+	node = egg_asn1x_node (asn, "critical", NULL);
+	if (node != NULL) {
+		if (egg_asn1x_get_boolean (node, &critical))
+			append_field_and_value (self, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
+	}
+
 	return TRUE;
 }
 
@@ -280,13 +274,14 @@ refresh_display (GcrCertificateDetailsWidget *self)
 	const guchar *data, *value;
 	gsize n_data, n_value;
 	const gchar *text;
-	guint version, size;
-	guint index;
+	gulong version;
+	guint index, size, n_bits;
 	gchar *display;
-	ASN1_TYPE asn;
+	guchar *bits;
+	GNode *asn;
 	GQuark oid;
 	GDate date;
-	
+
 	gtk_text_buffer_get_start_iter (self->pv->buffer, &start);
 	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
 	gtk_text_buffer_delete (self->pv->buffer, &start, &iter);
@@ -296,40 +291,40 @@ refresh_display (GcrCertificateDetailsWidget *self)
 	
 	data = gcr_certificate_get_der_data (self->pv->certificate, &n_data);
 	g_return_if_fail (data);
-	
-	asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
 	g_return_if_fail (asn);
-	
+
 	/* The subject */
 	append_heading (self, _("Subject Name"));
-	egg_dn_parse (asn, "tbsCertificate.subject.rdnSequence", on_parsed_dn_part, self);
-	
+	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, self);
+
 	/* The Issuer */
 	append_heading (self, _("Issuer Name"));
-	egg_dn_parse (asn, "tbsCertificate.issuer.rdnSequence", on_parsed_dn_part, self);
-	
+	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, self);
+
 	/* The Issued Parameters */
 	append_heading (self, _("Issued Certificate"));
-	
-	if (!egg_asn1_read_uint (asn, "tbsCertificate.version", &version))
+
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version))
 		g_return_if_reached ();
-	display = g_strdup_printf ("%u", version + 1);
+	display = g_strdup_printf ("%lu", version + 1);
 	append_field_and_value (self, _("Version"), display, FALSE);
 	g_free (display);
-	
-	value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.serialNumber", &n_value);
+
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), &n_value);
 	g_return_if_fail (value);
 	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
 	append_field_and_value (self, _("Serial Number"), display, TRUE);
 	g_free (display);
 	
 	display = g_malloc0 (128);
-	if (egg_asn1_read_date (asn, "tbsCertificate.validity.notBefore", &date)) {
+	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) {
 		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
 			g_return_if_reached ();
 		append_field_and_value (self, _("Not Valid Before"), display, FALSE);
 	}
-	if (egg_asn1_read_date (asn, "tbsCertificate.validity.notAfter", &date)) {
+	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
 		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
 			g_return_if_reached ();
 		append_field_and_value (self, _("Not Valid After"), display, FALSE);
@@ -338,19 +333,19 @@ refresh_display (GcrCertificateDetailsWidget *self)
 	
 	/* Signature */
 	append_heading (self, _("Signature"));
-	
-	oid = egg_asn1_read_oid (asn, "signatureAlgorithm.algorithm");
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
 	text = egg_oid_get_description (oid);
 	append_field_and_value (self, _("Signature Algorithm"), text, FALSE);
-	
-	value = egg_asn1_read_content (asn, data, n_data, "signatureAlgorithm.parameters", &n_value);
+
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value);
 	if (value && n_value) {
 		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
 		append_field_and_value (self, _("Signature Parameters"), display, TRUE);
 		g_free (display);
 	}
 	
-	value = egg_asn1_read_content (asn, data, n_data, "signature", &n_value);
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "signature", NULL), &n_value);
 	g_return_if_fail (value);
 	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
 	append_field_and_value (self, _("Signature"), display, TRUE);
@@ -358,12 +353,12 @@ refresh_display (GcrCertificateDetailsWidget *self)
 
 	/* Public Key Info */
 	append_heading (self, _("Public Key Info"));
-	
-	oid = egg_asn1_read_oid (asn, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm");
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", "algorithm", "algorithm", NULL));
 	text = egg_oid_get_description (oid);
 	append_field_and_value (self, _("Key Algorithm"), text, FALSE);
-	
-	value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters", &n_value);
+
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", "algorithm", "parameters", NULL), &n_value);
 	if (value && n_value) {
 		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
 		append_field_and_value (self, _("Key Parameters"), display, TRUE);
@@ -376,13 +371,14 @@ refresh_display (GcrCertificateDetailsWidget *self)
 		append_field_and_value (self, _("Key Size"), display, FALSE);
 		g_free (display);
 	}
-	
-	value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", &n_value);
-	g_return_if_fail (value);
-	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+
+	bits = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", "subjectPublicKey", NULL), NULL, &n_bits);
+	g_return_if_fail (bits);
+	display = egg_hex_encode_full (bits, n_bits / 8, TRUE, ' ', 1);
 	append_field_and_value (self, _("Public Key"), display, TRUE);
 	g_free (display);
-	
+	g_free (bits);
+
 	/* Fingerprints */
 	append_heading (self, _("Fingerprints"));
 	
@@ -394,8 +390,8 @@ refresh_display (GcrCertificateDetailsWidget *self)
 		if (!append_extension (self, asn, data, n_data, index))
 			break;
 	}
-	
-	asn1_delete_structure (&asn);
+
+	egg_asn1x_destroy (asn);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c
index 5d8d6c8..8a8abd7 100644
--- a/gcr/gcr-certificate.c
+++ b/gcr/gcr-certificate.c
@@ -24,7 +24,8 @@
 #include "gcr-internal.h"
 #include "gcr-certificate.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-hex.h"
 
@@ -56,7 +57,7 @@
 typedef struct _GcrCertificateInfo {
 	const guchar *der;
 	gsize n_der;
-	ASN1_TYPE asn1;
+	GNode *asn1;
 	guint key_size;
 } GcrCertificateInfo;
 
@@ -74,7 +75,7 @@ certificate_info_free (gpointer data)
 	GcrCertificateInfo *info = data;
 	if (info) {
 		g_assert (info->asn1);
-		asn1_delete_structure (&info->asn1);
+		egg_asn1x_destroy (info->asn1);
 		g_free (info);
 	}
 }
@@ -83,7 +84,7 @@ static GcrCertificateInfo*
 certificate_info_load (GcrCertificate *cert)
 {
 	GcrCertificateInfo *info;
-	ASN1_TYPE asn1;
+	GNode *asn1;
 	const guchar *der;
 	gsize n_der;
 	
@@ -99,7 +100,7 @@ certificate_info_load (GcrCertificate *cert)
 	}
 	
 	/* Cache is invalid or non existent */
-	asn1 = egg_asn1_decode ("PKIX1.Certificate", der, n_der);
+	asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", der, n_der);
 	if (asn1 == NULL) {
 		g_warning ("a derived class provided an invalid or unparseable X509 DER certificate data.");
 		return NULL;
@@ -109,7 +110,7 @@ certificate_info_load (GcrCertificate *cert)
 	info->der = der;
 	info->n_der = n_der;
 	info->asn1 = asn1;
-	
+
 	g_object_set_qdata_full (G_OBJECT (cert), CERTIFICATE_INFO, info, certificate_info_free);
 	return info;
 }
@@ -117,17 +118,17 @@ certificate_info_load (GcrCertificate *cert)
 static guint
 calculate_rsa_key_size (const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn;
+	GNode *asn;
 	gsize n_content;
-	
-	asn = egg_asn1_decode ("PK.RSAPublicKey", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data, n_data);
 	g_return_val_if_fail (asn, 0);
-    
-	if (!egg_asn1_read_content (asn, data, n_data, "modulus", &n_content))
+
+	if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL), &n_content))
 		g_return_val_if_reached (0);
-	
-	asn1_delete_structure (&asn);
-	
+
+	egg_asn1x_destroy (asn);
+
 	/* Removes the complement */
 	return (n_content / 2) * 2 * 8;
 }
@@ -135,17 +136,17 @@ calculate_rsa_key_size (const guchar *data, gsize n_data)
 static guint
 calculate_dsa_params_size (const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn;
+	GNode *asn;
 	gsize n_content;
-	
-	asn = egg_asn1_decode ("PK.DSAParameters", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data, n_data);
 	g_return_val_if_fail (asn, 0);
 
-	if (!egg_asn1_read_content (asn, data, n_data, "p", &n_content))
+	if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL), &n_content))
 		g_return_val_if_reached (0);
-		
-	asn1_delete_structure (&asn);
-	
+
+	egg_asn1x_destroy (asn);
+
 	/* Removes the complement */
 	return (n_content / 2) * 2 * 8;
 }
@@ -153,43 +154,43 @@ calculate_dsa_params_size (const guchar *data, gsize n_data)
 static guint
 calculate_key_size (GcrCertificateInfo *info)
 {
-	ASN1_TYPE asn;
+	GNode *asn;
 	const guchar *data, *params;
-	gsize n_data, n_params, n_key;
-	guint key_size = 0;
+	gsize n_data, n_params;
+	guint key_size = 0, n_bits;
 	guchar *key;
 	GQuark oid;
-	
-	data = egg_asn1_read_element (info->asn1, info->der, info->n_der, "tbsCertificate.subjectPublicKeyInfo", &n_data);
+
+	data = egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_data);
 	g_return_val_if_fail (data != NULL, 0);
-	
-	asn = egg_asn1_decode ("PKIX1.SubjectPublicKeyInfo", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data, n_data);
 	g_return_val_if_fail (asn, 0);
-	
+
 	/* Figure out the algorithm */
-	oid = egg_asn1_read_oid (asn, "algorithm.algorithm");
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "algorithm", "algorithm", NULL));
 	g_return_val_if_fail (oid, 0);
-		
+
 	/* RSA keys are stored in the main subjectPublicKey field */
 	if (oid == OID_RSA_KEY) {
-		
+
 		/* A bit string so we cannot process in place */
-		key = egg_asn1_read_value (asn, "subjectPublicKey", &n_key, NULL);
+		key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), NULL, &n_bits);
 		g_return_val_if_fail (key, 0);
-		key_size = calculate_rsa_key_size (key, n_key / 8);
+		key_size = calculate_rsa_key_size (key, n_bits / 8);
 
 	/* The DSA key size is discovered by the prime in params */
 	} else if (oid == OID_DSA_KEY) {
-		params = egg_asn1_read_element (asn, data, n_data, "algorithm.parameters", &n_params);
+		params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "algorithm", "parameters", NULL), &n_params);
 		key_size = calculate_dsa_params_size (params, n_params);
-		
+
 	} else {
 		g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid));
 	}
-	
-	asn1_delete_structure (&asn);
+
+	egg_asn1x_destroy (asn);
 	g_free (key);
-	
+
 	return key_size;
 }
 
@@ -319,8 +320,8 @@ gcr_certificate_get_issuer_part (GcrCertificate *self, const char *part)
 	
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
-	
-	return egg_dn_read_part (info->asn1, "tbsCertificate.issuer.rdnSequence", part);
+
+	return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL), part);
 }
 
 /**
@@ -344,8 +345,8 @@ gcr_certificate_get_issuer_dn (GcrCertificate *self)
 	
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
-	
-	return egg_dn_read (info->asn1, "tbsCertificate.issuer.rdnSequence");
+
+	return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL));
 }
 
 /**
@@ -390,8 +391,8 @@ gcr_certificate_get_subject_part (GcrCertificate *self, const char *part)
 	
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
-	
-	return egg_dn_read_part (info->asn1, "tbsCertificate.subject.rdnSequence", part);
+
+	return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL), part);
 }
 
 /**
@@ -415,8 +416,8 @@ gcr_certificate_get_subject_dn (GcrCertificate *self)
 	
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
-	
-	return egg_dn_read (info->asn1, "tbsCertificate.issuer.rdnSequence");
+
+	return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL));
 }
 
 /**
@@ -442,7 +443,7 @@ gcr_certificate_get_issued_date (GcrCertificate *self)
 	g_return_val_if_fail (info, NULL);
 	
 	date = g_date_new ();
-	if (!egg_asn1_read_date (info->asn1, "tbsCertificate.validity.notBefore", date)) {
+	if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notBefore", NULL), date)) {
 		g_date_free (date);
 		return NULL;
 	}
@@ -473,7 +474,7 @@ gcr_certificate_get_expiry_date (GcrCertificate *self)
 	g_return_val_if_fail (info, NULL);
 	
 	date = g_date_new ();
-	if (!egg_asn1_read_date (info->asn1, "tbsCertificate.validity.notAfter", date)) {
+	if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notAfter", NULL), date)) {
 		g_date_free (date);
 		return NULL;
 	}
@@ -600,14 +601,16 @@ guchar*
 gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
 {
 	GcrCertificateInfo *info;
-	
+	gconstpointer serial;
+
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
 	g_return_val_if_fail (n_length, NULL);
 	
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
-	
-	return egg_asn1_read_value (info->asn1, "tbsCertificate.serialNumber", n_length, g_realloc); 
+
+	serial = egg_asn1x_get_raw_value (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL), n_length);
+	return g_memdup (serial, *n_length);
 }
 
 /**
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index f3b597c..2a052e7 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -28,7 +28,8 @@
 #include "gcr-parser.h"
 #include "gcr-types.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-openssl.h"
 #include "egg/egg-secure-memory.h"
@@ -158,7 +159,7 @@ init_quarks (void)
  */
 
 static gboolean
-parsed_asn1_attribute (GcrParser *self, ASN1_TYPE asn, const guchar *data, gsize n_data, 
+parsed_asn1_attribute (GcrParser *self, GNode *asn, const guchar *data, gsize n_data,
                        const gchar *part, CK_ATTRIBUTE_TYPE type)
 {
 	const guchar *value;
@@ -167,13 +168,13 @@ parsed_asn1_attribute (GcrParser *self, ASN1_TYPE asn, const guchar *data, gsize
 	g_assert (GCR_IS_PARSER (self));
 	g_assert (asn);
 	g_assert (data);
-	g_assert (part);
 	g_assert (self->pv->parsed_attrs);
-	
-	value = egg_asn1_read_content (asn, data, n_data, part, &n_value);
+
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, part, NULL), &n_value);
 	if (value == NULL)
 		return FALSE;
-	
+
+	/* TODO: Convert to USG FROM STD */
 	gp11_attributes_add_data (self->pv->parsed_attrs, type, value, n_value);
 	return TRUE;
 }
@@ -295,27 +296,27 @@ static gint
 parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
 {
 	gint res = GCR_ERROR_UNRECOGNIZED;
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
-	guint version;
-	
-	asn = egg_asn1_decode ("PK.RSAPrivateKey", data, n_data);
+	GNode *asn = NULL;
+	gulong version;
+
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data, n_data);
 	if (!asn)
 		goto done;
-	
+
 	parsed_clear (self, CKO_PRIVATE_KEY);
 	parsed_ulong (self, CKA_KEY_TYPE, CKK_RSA);
 	res = GCR_ERROR_FAILURE;
 
-	if (!egg_asn1_read_uint (asn, "version", &version))
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version))
 		goto done;
-	
+
 	/* We only support simple version */
 	if (version != 0) {
 		res = GCR_ERROR_UNRECOGNIZED;
-		g_message ("unsupported version of RSA key: %u", version);
+		g_message ("unsupported version of RSA key: %lu", version);
 		goto done;
 	}
-	
+
 	if (!parsed_asn1_attribute (self, asn, data, n_data, "modulus", CKA_MODULUS) || 
 	    !parsed_asn1_attribute (self, asn, data, n_data, "publicExponent", CKA_PUBLIC_EXPONENT) ||
 	    !parsed_asn1_attribute (self, asn, data, n_data, "privateExponent", CKA_PRIVATE_EXPONENT) ||
@@ -328,9 +329,7 @@ parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
 	res = SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-
+	egg_asn1x_destroy (asn);
 	if (res == GCR_ERROR_FAILURE)
 		g_message ("invalid RSA key");
 	
@@ -345,16 +344,15 @@ static gint
 parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
 {
 	gint ret = GCR_ERROR_UNRECOGNIZED;
-	int res;
-	ASN1_TYPE asn;
+	GNode *asn = NULL;
 
-	asn = egg_asn1_decode ("PK.DSAPrivateKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data, n_data);
 	if (!asn)
 		goto done;
-	
+
 	parsed_clear (self, CKO_PRIVATE_KEY);
 	parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
-	res = GCR_ERROR_FAILURE;
+	ret = GCR_ERROR_FAILURE;
 
 	if (!parsed_asn1_attribute (self, asn, data, n_data, "p", CKA_PRIME) ||
 	    !parsed_asn1_attribute (self, asn, data, n_data, "q", CKA_SUBPRIME) ||
@@ -366,9 +364,7 @@ parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
 	ret = SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-	
+	egg_asn1x_destroy (asn);
 	if (ret == GCR_ERROR_FAILURE) 
 		g_message ("invalid DSA key");
 		
@@ -380,34 +376,30 @@ parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n
                                  const guchar *params, gsize n_params)
 {
 	gint ret = GCR_ERROR_UNRECOGNIZED;
-	int res;
-	ASN1_TYPE asn_params = ASN1_TYPE_EMPTY;
-	ASN1_TYPE asn_key = ASN1_TYPE_EMPTY;
+	GNode *asn_params = NULL;
+	GNode *asn_key = NULL;
 
-	asn_params = egg_asn1_decode ("PK.DSAParameters", params, n_params);
-	asn_key = egg_asn1_decode ("PK.DSAPrivatePart", keydata, n_keydata);
+	asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params, n_params);
+	asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata, n_keydata);
 	if (!asn_params || !asn_key)
 		goto done;
-	
+
 	parsed_clear (self, CKO_PRIVATE_KEY);
 	parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
-	res = GCR_ERROR_FAILURE;
-    
+	ret = GCR_ERROR_FAILURE;
+
 	if (!parsed_asn1_attribute (self, asn_params, params, n_params, "p", CKA_PRIME) ||
 	    !parsed_asn1_attribute (self, asn_params, params, n_params, "q", CKA_SUBPRIME) ||
 	    !parsed_asn1_attribute (self, asn_params, params, n_params, "g", CKA_BASE) ||
-	    !parsed_asn1_attribute (self, asn_key, keydata, n_keydata, "", CKA_VALUE))
+	    !parsed_asn1_attribute (self, asn_key, keydata, n_keydata, NULL, CKA_VALUE))
 		goto done;
 
 	parsed_fire (self);
 	ret = SUCCESS;
 	
 done:
-	if (asn_key)
-		asn1_delete_structure (&asn_key);
-	if (asn_params)
-		asn1_delete_structure (&asn_params);
-	
+	egg_asn1x_destroy (asn_key);
+	egg_asn1x_destroy (asn_params);
 	if (ret == GCR_ERROR_FAILURE) 
 		g_message ("invalid DSA key");
 		
@@ -437,7 +429,6 @@ parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data)
 static gint
 parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
 	gint ret;
 	CK_KEY_TYPE key_type;
 	GQuark key_algo;
@@ -445,17 +436,18 @@ parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
 	gsize n_keydata;
 	const guchar *params;
 	gsize n_params;
-	
+	GNode *asn = NULL;
+
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-8-PrivateKeyInfo", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GCR_ERROR_FAILURE;
 	key_type = GP11_INVALID;
-		
-	key_algo = egg_asn1_read_oid (asn, "privateKeyAlgorithm.algorithm");
+
+	key_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL));
   	if (!key_algo)
   		goto done;
   	else if (key_algo == OID_PKIX1_RSA)
@@ -468,13 +460,12 @@ parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
   		goto done;
   	}
 
-	keydata = egg_asn1_read_content (asn, data, n_data, "privateKey", &n_keydata);
+	keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL), &n_keydata);
 	if (!keydata)
 		goto done;
-		
-	params = egg_asn1_read_element (asn, data, n_data, "privateKeyAlgorithm.parameters", 
-	                                     &n_params);
-		
+
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL), &n_params);
+
 	ret = SUCCESS;
 	
 done:
@@ -501,9 +492,8 @@ done:
 	} else if (ret == GCR_ERROR_FAILURE) {
 		g_message ("invalid PKCS#8 key");
 	}
-	
-	if (asn)
-		asn1_delete_structure (&asn);
+
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -511,7 +501,7 @@ static gint
 parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 {
 	PasswordState pstate = PASSWORD_STATE_INIT;
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_cipher_hd_t cih = NULL;
 	gcry_error_t gcry;
 	gint ret, r;
@@ -523,20 +513,20 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 	gint l;
 
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GCR_ERROR_FAILURE;
 
 	/* Figure out the type of encryption */
-	scheme = egg_asn1_read_oid (asn, "encryptionAlgorithm.algorithm");
+	scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL));
 	if (!scheme)
 		goto done;
-		
-	params = egg_asn1_read_element (asn, data, n_data, "encryptionAlgorithm.parameters", &n_params);
-	
+
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params);
+
 	parsed_clear (self, CKO_PRIVATE_KEY);
 
 	/* Loop to try different passwords */                       
@@ -553,11 +543,11 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 		/* Parse the encryption stuff into a cipher. */
 		if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih))
 			break;
-			
-		crypted = egg_asn1_read_value (asn, "encryptedData", &n_crypted, (EggAllocator)egg_secure_realloc);
+
+		crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL), egg_secure_realloc, &n_crypted);
 		if (!crypted)
 			break;
-	
+
 		gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0);
 		gcry_cipher_close (cih);
 		cih = NULL;
@@ -568,13 +558,12 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 		}
 		
 		/* Unpad the DER data */
-		l = egg_asn1_element_length (crypted, n_crypted);
+		l = egg_asn1x_element_length (crypted, n_crypted);
 		if (l > 0)
 			n_crypted = l;
 		
 		/* Try to parse the resulting key */
 		r = parse_der_pkcs8_plain (self, crypted, n_crypted);
-		egg_secure_free (crypted);
 		crypted = NULL;
 		
 		if (r != GCR_ERROR_UNRECOGNIZED) {
@@ -588,10 +577,9 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 done:
 	if (cih)
 		gcry_cipher_close (cih);
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	egg_secure_free (crypted);
-		
+
 	return ret;
 }
 
@@ -614,19 +602,19 @@ parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data)
 static gint
 parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn;
+	GNode *asn;
 	gchar *name;
-	
-	asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
 	if (asn == NULL)
 		return GCR_ERROR_UNRECOGNIZED;
 
 	parsed_clear (self, CKO_CERTIFICATE);
 	parsed_ulong (self, CKA_CERTIFICATE_TYPE, CKC_X_509);
 
-	name = egg_dn_read_part (asn, "tbsCertificate.subject.rdnSequence", "CN");
-	asn1_delete_structure (&asn);
-		
+	name = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
+	egg_asn1x_destroy (asn);
+
 	if (name != NULL) {
 		parsed_label (self, name);
 		g_free (name);
@@ -645,30 +633,30 @@ parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
 static gint
 handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
+	GNode *node;
 	gint ret;
-	gchar *part;
 	const guchar *certificate;
 	gsize n_certificate;
 	int i;
-	
+
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-7-SignedData", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GCR_ERROR_FAILURE;
 	
 	for (i = 0; TRUE; ++i) {
-			
-		part = g_strdup_printf ("certificates.?%u", i + 1);
-		certificate = egg_asn1_read_element (asn, data, n_data, part, &n_certificate);
-		g_free (part);
-		
+
+		node = egg_asn1x_node (asn, "certificates", i + 1, NULL);
+
 		/* No more certificates? */
-		if (!certificate)
+		if (node == NULL)
 			break;
+
+		certificate = egg_asn1x_get_raw_element (node, &n_certificate);
 	
 		ret = parse_der_certificate (self, certificate, n_certificate);
 		if (ret != SUCCESS)
@@ -678,50 +666,51 @@ handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
 	/* TODO: Parse out all the CRLs */
 	
 	ret = SUCCESS;
-	
+
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-	
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
 static gint
 parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
+	GNode *node;
 	gint ret;
 	const guchar* content = NULL;
 	gsize n_content;
 	GQuark oid;
-	
+
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-7-ContentInfo", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-ContentInfo", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GCR_ERROR_FAILURE;
 
-	oid = egg_asn1_read_oid (asn, "contentType");
-	if (!oid)
+	node = egg_asn1x_node (asn, "contentType", NULL);
+	if (!node)
 		goto done;
 
+	oid = egg_asn1x_get_oid_as_quark (node);
+	g_return_val_if_fail (oid, GCR_ERROR_FAILURE);
+
 	/* Outer most one must just be plain data */
 	if (oid != OID_PKCS7_SIGNED_DATA) {
 		g_message ("unsupported outer content type in pkcs7: %s", g_quark_to_string (oid));
 		goto done;
 	}
-	
-	content = egg_asn1_read_content (asn, data, n_data, "content", &n_content);
+
+	content = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "content", NULL), &n_content);
 	if (!content) 
 		goto done;
-		
+
 	ret = handle_pkcs7_signed_data (self, content, n_content);
-			
+
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -732,63 +721,62 @@ done:
 static gint
 handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
-	const guchar *certificate;
-	gsize n_certificate;
+	GNode *asn = NULL;
+	GNode *asn_content = NULL;
+	guchar *certificate;
+	const guchar *element;
+	gsize n_certificate, n_element;
 	gint ret;
 
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-12-CertBag", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-CertBag", data, n_data);
 	if (!asn)
 		goto done;
-		
+
 	ret = GCR_ERROR_FAILURE;
-	
-	certificate = egg_asn1_read_content (asn, data, n_data, "certValue", &n_certificate);
-	if (!certificate)
+
+	element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "certValue", NULL), &n_element);
+	if (!element)
 		goto done;
 
-	/* 
-	 * Wrapped in an OCTET STRING, so unwrap here, rather than allocating 
-	 * a whole bunch more memory for a full ASN.1 parsing context.
-	 */ 
-	certificate = egg_asn1_element_content (certificate, n_certificate, &n_certificate);
+	asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element);
+	if (!asn_content)
+		goto done;
+
+	certificate = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_certificate);
 	if (!certificate)
 		goto done;
-	
+
 	ret = parse_der_certificate (self, certificate, n_certificate);
-		
+
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-		
+	egg_asn1x_destroy (asn_content);
+	egg_asn1x_destroy (asn);
+	g_free (certificate);
 	return ret;
 }
 
 static gint
 handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gint ret, r;
-	int res, count = 0;
+	guint count = 0;
 	GQuark oid;
 	const guchar *element;
 	gsize n_element;
-	
+
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-12-SafeContents", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-SafeContents", data, n_data);
 	if (!asn)
 		goto done;
-		
+
 	ret = GCR_ERROR_FAILURE;
-	
+
 	/* Get the number of elements in this bag */
-	res = asn1_number_of_elements (asn, "", &count);
-	if (res != ASN1_SUCCESS)
-		goto done;	
-	
+	count = egg_asn1x_count (asn);
+
 	/* 
 	 * Now inside each bag are multiple elements. Who comes up 
 	 * with this stuff?
@@ -801,11 +789,11 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
 	 */
 	if (count >= 1) {
 
-		oid = egg_asn1_read_oid (asn, "?1.bagId");
+		oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, 1, "bagId", NULL));
 		if (!oid)
 			goto done;
-		
-		element = egg_asn1_read_content (asn, data, n_data, "?1.bagValue", &n_element); 	
+
+		element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, 1, "bagValue", NULL), &n_element);
 		if (!element)
 			goto done;
 
@@ -835,9 +823,7 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
 	ret = SUCCESS;	
 		
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-		
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -845,7 +831,7 @@ static gint
 handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 {
 	PasswordState pstate = PASSWORD_STATE_INIT;
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_cipher_hd_t cih = NULL;
 	gcry_error_t gcry;
 	guchar *crypted = NULL;
@@ -855,24 +841,24 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 	GQuark scheme;
 	gint ret, r;
 	gint l;
-	
+
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-7-EncryptedData", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-EncryptedData", data, n_data);
 	if (!asn)
 		goto done;
-	
+
 	ret = GCR_ERROR_FAILURE;
-		
+
 	/* Check the encryption schema OID */
-	scheme = egg_asn1_read_oid (asn, "encryptedContentInfo.contentEncryptionAlgorithm.algorithm");
+	scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "algorithm", NULL));
 	if (!scheme) 
-		goto done;	
+		goto done;
 
-	params = egg_asn1_read_element (asn, data, n_data, "encryptedContentInfo.contentEncryptionAlgorithm.parameters", &n_params);
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL), &n_params);
 	if (!params)
 		goto done;
-	
+
 	parsed_clear (self, 0);
 
 	/* Loop to try different passwords */
@@ -891,9 +877,9 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 			ret = GCR_ERROR_FAILURE;
 			goto done;
 		}
-			
-		crypted = egg_asn1_read_value (asn, "encryptedContentInfo.encryptedContent", 
-		                               &n_crypted, (EggAllocator)egg_secure_realloc);
+
+		crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedContentInfo", "encryptedContent", NULL),
+		                                       egg_secure_realloc, &n_crypted);
 		if (!crypted)
 			goto done;
 	
@@ -905,9 +891,9 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 			g_warning ("couldn't decrypt pkcs7 data: %s", gcry_strerror (gcry));
 			goto done;
 		}
-		
+
 		/* Unpad the DER data */
-		l = egg_asn1_element_length (crypted, n_crypted);
+		l = egg_asn1x_element_length (crypted, n_crypted);
 		if (l > 0)
 			n_crypted = l;
 
@@ -927,64 +913,65 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 done:
 	if (cih)
 		gcry_cipher_close (cih);
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	egg_secure_free (crypted);
-	
 	return ret;
 }
 
 static gint
 handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
+	GNode *asn_content = NULL;
 	gint ret, r;
 	const guchar *bag;
-	gsize n_bag;
-	gchar *part;
+	guchar *content = NULL;
+	gsize n_bag, n_content;
 	GQuark oid;
 	guint i;
-	
+	GNode *node;
+
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-12-AuthenticatedSafe", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-AuthenticatedSafe", data, n_data);
 	if (!asn)
 		goto done;
-		
+
 	ret = GCR_ERROR_FAILURE;
 	
 	/*
 	 * Inside each PKCS12 safe there are multiple bags. 
 	 */
 	for (i = 0; TRUE; ++i) {
-		
-		part = g_strdup_printf ("?%u.contentType", i + 1);
-		oid = egg_asn1_read_oid (asn, part);
-		g_free (part);
-		
+		node = egg_asn1x_node (asn, i + 1, "contentType", NULL);
+
 		/* All done? no more bags */
-		if (!oid) 
+		if (!node)
 			break;
-		
-		part = g_strdup_printf ("?%u.content", i + 1);
-		bag = egg_asn1_read_content (asn, data, n_data, part, &n_bag);
-		g_free (part);
-		
-		if (!bag) /* A parse error */
+
+		oid = egg_asn1x_get_oid_as_quark (node);
+
+		node = egg_asn1x_node (asn, i + 1, "content", NULL);
+		if (!node)
 			goto done;
-			
+
+		bag = egg_asn1x_get_raw_element (node, &n_bag);
+		g_return_val_if_fail (bag, ret);
+
 		/* A non encrypted bag, just parse */
 		if (oid == OID_PKCS7_DATA) {
-			
-			/* 
-		 	 * Wrapped in an OCTET STRING, so unwrap here, rather than allocating 
-		 	 * a whole bunch more memory for a full ASN.1 parsing context.
-		 	 */ 
-			bag = egg_asn1_element_content (bag, n_bag, &n_bag);
-			if (!bag)
-				goto done;	
-			
-			r = handle_pkcs12_bag (self, bag, n_bag);
+
+			egg_asn1x_destroy (asn_content);
+			asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", bag, n_bag);
+			if (!asn_content)
+				goto done;
+
+			g_free (content);
+			content = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_content);
+			if (!content)
+				goto done;
+
+			r = handle_pkcs12_bag (self, content, n_content);
 
 		/* Encrypted data first needs decryption */
 		} else if (oid == OID_PKCS7_ENCRYPTED_DATA) {
@@ -1005,54 +992,59 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 	ret = SUCCESS;
 	
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-		
+	egg_asn1x_destroy (asn);
+	egg_asn1x_destroy (asn_content);
+	g_free (content);
 	return ret;
 }
 
 static gint
 parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
+	GNode *asn_content = NULL;
 	gint ret;
-	const guchar* content = NULL;
-	gsize n_content;
+	const guchar* element = NULL;
+	guchar *content = NULL;
+	gsize n_element, n_content;
 	GQuark oid;
-	
+
 	ret = GCR_ERROR_UNRECOGNIZED;
-	
-	asn = egg_asn1_decode ("PKIX1.pkcs-12-PFX", data, n_data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PFX", data, n_data);
 	if (!asn)
 		goto done;
 
-	oid = egg_asn1_read_oid (asn, "authSafe.contentType");
+	ret = GCR_ERROR_FAILURE;
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "authSafe", "contentType", NULL));
 	if (!oid)
 		goto done;
-		
+
 	/* Outer most one must just be plain data */
 	if (oid != OID_PKCS7_DATA) {
 		g_message ("unsupported safe content type in pkcs12: %s", g_quark_to_string (oid));
 		goto done;
 	}
-	
-	content = egg_asn1_read_content (asn, data, n_data, "authSafe.content", &n_content);
-	if (!content)
+
+	element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "authSafe", "content", NULL), &n_element);
+	if (!element)
 		goto done;
-		
-	/* 
-	 * Wrapped in an OCTET STRING, so unwrap here, rather than allocating 
-	 * a whole bunch more memory for a full ASN.1 parsing context.
-	 */ 
-	content = egg_asn1_element_content (content, n_content, &n_content);
+
+	asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element);
+	if (!asn_content)
+		goto done;
+
+	content = egg_asn1x_get_string_as_raw (asn_content, g_realloc, &n_content);
 	if (!content)
 		goto done;
-				
+
 	ret = handle_pkcs12_safe (self, content, n_content);
-	
+
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	g_free (content);
+	egg_asn1x_destroy (asn_content);
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -1168,7 +1160,7 @@ handle_encrypted_pem (GcrParser *self, GQuark type, gint subformat,
 		g_assert (decrypted);
 		
 		/* Unpad the DER data */
-		l = egg_asn1_element_length (decrypted, n_decrypted);
+		l = egg_asn1x_element_length (decrypted, n_decrypted);
 		if (l > 0)
 			n_decrypted = l;
 	
diff --git a/gcr/gcr-simple-certificate.c b/gcr/gcr-simple-certificate.c
index 0bac622..d9bf516 100644
--- a/gcr/gcr-simple-certificate.c
+++ b/gcr/gcr-simple-certificate.c
@@ -25,7 +25,6 @@
 #include "gcr-internal.h"
 #include "gcr-simple-certificate.h"
 
-#include "egg/egg-asn1.h"
 #include "egg/egg-hex.h"
 
 #include <string.h>
diff --git a/pkcs11/gkm/gkm-certificate-trust.c b/pkcs11/gkm/gkm-certificate-trust.c
index cbcd7c2..97df501 100644
--- a/pkcs11/gkm/gkm-certificate-trust.c
+++ b/pkcs11/gkm/gkm-certificate-trust.c
@@ -83,7 +83,7 @@ has_key_usage (GkmCertificateTrust *self, guint check, CK_ULONG *val)
 	GkmDataResult res;
 	const guchar *extension;
 	gsize n_extension;
-	guint usage;
+	gulong usage;
 
 	g_return_val_if_fail (self->pv->certificate, CKR_GENERAL_ERROR);
 	*val = CKT_NETSCAPE_TRUST_UNKNOWN;
diff --git a/pkcs11/gkm/gkm-certificate.c b/pkcs11/gkm/gkm-certificate.c
index 0db7327..7f3dfd9 100644
--- a/pkcs11/gkm/gkm-certificate.c
+++ b/pkcs11/gkm/gkm-certificate.c
@@ -37,6 +37,7 @@
 #include "gkm-util.h"
 
 #include "egg/egg-dn.h"
+#include "egg/egg-asn1x.h"
 
 #include "pkcs11/pkcs11.h"
 #include "pkcs11/pkcs11g.h"
@@ -53,7 +54,7 @@ enum {
 
 struct _GkmCertificatePrivate {
 	GkmCertificateKey *key;
-	ASN1_TYPE asn1;
+	GNode *asn1;
 	guchar *data;
 	gsize n_data;
 	gchar *label;
@@ -215,9 +216,8 @@ static gint
 find_certificate_extension (GkmCertificate *self, GQuark oid)
 {
 	GQuark exoid;
-	gchar *name;
+	GNode *node;
 	guint index;
-	int res, len;
 
 	g_assert (oid);
 	g_assert (GKM_IS_CERTIFICATE (self));
@@ -226,17 +226,12 @@ find_certificate_extension (GkmCertificate *self, GQuark oid)
 	for (index = 1; TRUE; ++index) {
 
 		/* Make sure it is present */
-		len = 0;
-		name = g_strdup_printf ("tbsCertificate.extensions.?%u", index);
-		res = asn1_read_value (self->pv->asn1, name, NULL, &len);
-		g_free (name);
-		if (res == ASN1_ELEMENT_NOT_FOUND)
+		node = egg_asn1x_node (self->pv->asn1, "tbsCertificate", "extensions", index, NULL);
+		if (node == NULL)
 			break;
 
 		/* See if it's the same */
-		name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnID", index);
-		exoid = egg_asn1_read_oid (self->pv->asn1, name);
-		g_free (name);
+		exoid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (self->pv->asn1, "extnID", NULL));
 
 		if(exoid == oid)
 			return index;
@@ -332,18 +327,18 @@ gkm_certificate_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATT
 	case CKA_START_DATE:
 	case CKA_END_DATE:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
-		if (!egg_asn1_read_time (self->pv->asn1,
-		                              attr->type == CKA_START_DATE ?
-		                                       "tbsCertificate.validity.notBefore" :
-		                                       "tbsCertificate.validity.notAfter",
-		                              &when))
+		when = egg_asn1x_get_time_as_long (egg_asn1x_node (self->pv->asn1,
+		                                                 attr->type == CKA_START_DATE ?
+		                                                       "tbsCertificate.validity.notBefore" :
+		                                                       "tbsCertificate.validity.notAfter",
+		                                                 NULL));
+		if (when < 0)
 			return CKR_FUNCTION_FAILED;
 		return gkm_attribute_set_date (attr, when);
 
 	case CKA_SUBJECT:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
-		cdata = egg_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data,
-		                                    "tbsCertificate.subject", &n_data);
+		cdata = egg_asn1x_get_raw_element (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "subject", NULL), &n_data);
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
 		return gkm_attribute_set_data (attr, cdata, n_data);
 
@@ -354,15 +349,13 @@ gkm_certificate_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATT
 
 	case CKA_ISSUER:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
-		cdata = egg_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data,
-		                                    "tbsCertificate.issuer", &n_data);
+		cdata = egg_asn1x_get_raw_element (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "issuer", NULL), &n_data);
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
 		return gkm_attribute_set_data (attr, cdata, n_data);
 
 	case CKA_SERIAL_NUMBER:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
-		cdata = egg_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data,
-		                                    "tbsCertificate.serialNumber", &n_data);
+		cdata = egg_asn1x_get_raw_element (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "serialNumber", NULL), &n_data);
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
 		return gkm_attribute_set_data (attr, cdata, n_data);
 
@@ -455,7 +448,7 @@ gkm_certificate_finalize (GObject *obj)
 	g_assert (!self->pv->key);
 	g_free (self->pv->data);
 	g_free (self->pv->label);
-	asn1_delete_structure (&self->pv->asn1);
+	egg_asn1x_destroy (self->pv->asn1);
 
 	G_OBJECT_CLASS (gkm_certificate_parent_class)->finalize (obj);
 }
@@ -527,7 +520,7 @@ static gboolean
 gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, const guchar *data, gsize n_data)
 {
 	GkmCertificate *self = GKM_CERTIFICATE (base);
-	ASN1_TYPE asn1 = ASN1_TYPE_EMPTY;
+	GNode *asn1 = NULL;
 	GkmDataResult res;
 	guchar *copy, *keydata;
 	gsize n_keydata;
@@ -549,7 +542,7 @@ gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, const guchar
 	}
 
 	/* Generate a raw public key from our certificate */
-	keydata = egg_asn1_encode (asn1, "tbsCertificate.subjectPublicKeyInfo", &n_keydata, NULL);
+	keydata = egg_asn1x_encode (egg_asn1x_node (asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), NULL, &n_keydata);
 	g_return_val_if_fail (keydata, FALSE);
 
 	/* Now create us a nice public key with that identifier */
@@ -581,7 +574,7 @@ gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, const guchar
 	case GKM_DATA_LOCKED:
 		g_warning ("couldn't parse certificate key data");
 		g_free (copy);
-		asn1_delete_structure (&asn1);
+		egg_asn1x_destroy (asn1);
 		return FALSE;
 
 	default:
@@ -593,7 +586,7 @@ gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, const guchar
 	self->pv->data = copy;
 	self->pv->n_data = n_data;
 
-	asn1_delete_structure (&self->pv->asn1);
+	egg_asn1x_destroy (self->pv->asn1);
 	self->pv->asn1 = asn1;
 
 	return TRUE;
@@ -679,8 +672,6 @@ const guchar*
 gkm_certificate_get_extension (GkmCertificate *self, GQuark oid,
                                gsize *n_extension, gboolean *critical)
 {
-	const guchar *result;
-	gchar *name;
 	guchar *val;
 	gsize n_val;
 	gint index;
@@ -696,9 +687,8 @@ gkm_certificate_get_extension (GkmCertificate *self, GQuark oid,
 
 	/* Read the critical status */
 	if (critical) {
-		name = g_strdup_printf ("tbsCertificate.extensions.?%u.critical", index);
-		val = egg_asn1_read_value (self->pv->asn1, name, &n_val, NULL);
-		g_free (name);
+		val = egg_asn1x_get_string_as_raw (egg_asn1x_node (self->pv->asn1, "tbsCertificate",
+		                                   "extensions", index, "critical", NULL), NULL, &n_val);
 
 		/*
 		 * We're pretty liberal in what we accept as critical. The goal
@@ -713,12 +703,8 @@ gkm_certificate_get_extension (GkmCertificate *self, GQuark oid,
 	}
 
 	/* And the extension value */
-	name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnValue", index);
-	result = egg_asn1_read_content (self->pv->asn1, self->pv->data, self->pv->n_data,
-	                                     name, n_extension);
-	g_free (name);
-
-	return result;
+	return egg_asn1x_get_raw_value (egg_asn1x_node (self->pv->asn1, "tbsCertificate",
+	                                "extensions", index, "extnValue", NULL), n_extension);
 }
 
 const gchar*
@@ -732,11 +718,11 @@ gkm_certificate_get_label (GkmCertificate *self)
 		g_return_val_if_fail (self->pv->asn1, "");
 
 		/* Look for the CN in the certificate */
-		label = egg_dn_read_part (self->pv->asn1, "tbsCertificate.subject.rdnSequence", "cn");
+		label = egg_dn_read_part (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "subject", "rdnSequence", NULL), "cn");
 
 		/* Otherwise use the full DN */
 		if (!label)
-			label = egg_dn_read (self->pv->asn1, "tbsCertificate.subject.rdnSequence");
+			label = egg_dn_read (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "subject", "rdnSequence", NULL));
 
 		if (!label)
 			label = g_strdup (_("Unnamed Certificate"));
diff --git a/pkcs11/gkm/gkm-data-asn1.c b/pkcs11/gkm/gkm-data-asn1.c
index 4a6bd7b..6641395 100644
--- a/pkcs11/gkm/gkm-data-asn1.c
+++ b/pkcs11/gkm/gkm-data-asn1.c
@@ -25,40 +25,24 @@
 
 #include "gkm-data-asn1.h"
 
-gboolean
-gkm_data_asn1_read_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t *mpi)
-{
-	gcry_error_t gcry;
-	gsize sz;
-	guchar *buf;
-
-	buf = egg_asn1_read_value (asn, part, &sz, (EggAllocator)g_realloc);
-	if (!buf)
-		return FALSE;
-
-	gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_STD, buf, sz, &sz);
-	g_free (buf);
-
-	if (gcry != 0)
-		return FALSE;
-
-	return TRUE;
-}
+#include "egg/egg-asn1x.h"
 
 gboolean
-gkm_data_asn1_read_secure_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t *mpi)
+gkm_data_asn1_read_mpi (GNode *asn, gcry_mpi_t *mpi)
 {
 	gcry_error_t gcry;
 	gsize sz;
-	guchar *buf;
+	const guchar *buf;
+
+	g_return_val_if_fail (asn, FALSE);
+	g_return_val_if_fail (mpi, FALSE);
 
-	buf = egg_asn1_read_value (asn, part, &sz, (EggAllocator)gcry_realloc);
+	buf = egg_asn1x_get_raw_value (asn, &sz);
 	if (!buf)
 		return FALSE;
 
+	/* Automatically stores in secure memory if DER data is secure */
 	gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_STD, buf, sz, &sz);
-	gcry_free (buf);
-
 	if (gcry != 0)
 		return FALSE;
 
@@ -66,16 +50,14 @@ gkm_data_asn1_read_secure_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t *mpi
 }
 
 gboolean
-gkm_data_asn1_write_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t mpi)
+gkm_data_asn1_write_mpi (GNode *asn, gcry_mpi_t mpi)
 {
 	gcry_error_t gcry;
 	gsize len;
 	guchar *buf;
-	int res;
 
-	g_assert (asn);
-	g_assert (part);
-	g_assert (mpi);
+	g_return_val_if_fail (asn, FALSE);
+	g_return_val_if_fail (mpi, FALSE);
 
 	/* Get the size */
 	gcry = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &len, mpi);
@@ -87,11 +69,5 @@ gkm_data_asn1_write_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t mpi)
 	gcry = gcry_mpi_print (GCRYMPI_FMT_STD, buf, len, &len, mpi);
 	g_return_val_if_fail (gcry == 0, FALSE);
 
-	res = asn1_write_value (asn, part, buf, len);
-	gcry_free (buf);
-
-	if (res != ASN1_SUCCESS)
-		return FALSE;
-
-	return TRUE;
+	return egg_asn1x_set_integer_as_raw (asn, buf, len, gcry_free);
 }
diff --git a/pkcs11/gkm/gkm-data-asn1.h b/pkcs11/gkm/gkm-data-asn1.h
index 77886d2..3fe9d6b 100644
--- a/pkcs11/gkm/gkm-data-asn1.h
+++ b/pkcs11/gkm/gkm-data-asn1.h
@@ -24,16 +24,13 @@
 #ifndef GKM_DATA_ASN_H_
 #define GKM_DATA_ASN_H_
 
-#include "egg/egg-asn1.h"
+#include <glib.h>
 #include <gcrypt.h>
 
-gboolean           gkm_data_asn1_read_mpi                      (ASN1_TYPE asn, const gchar *part,
+gboolean           gkm_data_asn1_read_mpi                      (GNode *asn,
                                                                 gcry_mpi_t *mpi);
 
-gboolean           gkm_data_asn1_read_secure_mpi               (ASN1_TYPE asn, const gchar *part,
-                                                                gcry_mpi_t *mpi);
-
-gboolean           gkm_data_asn1_write_mpi                     (ASN1_TYPE asn, const gchar *part,
+gboolean           gkm_data_asn1_write_mpi                     (GNode *asn,
                                                                 gcry_mpi_t mpi);
 
 #endif /*GKM_DATA_ASN_H_*/
diff --git a/pkcs11/gkm/gkm-data-der.c b/pkcs11/gkm/gkm-data-der.c
index e2a5403..dbfef24 100644
--- a/pkcs11/gkm/gkm-data-der.c
+++ b/pkcs11/gkm/gkm-data-der.c
@@ -28,6 +28,8 @@
 #include "gkm-data-types.h"
 #include "gkm-sexp.h"
 
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-secure-memory.h"
 #include "egg/egg-symkey.h"
 
@@ -77,20 +79,20 @@ GkmDataResult
 gkm_data_der_read_public_key_rsa (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t n, e;
 	int res;
 
 	n = e = NULL;
 
-	asn = egg_asn1_decode ("PK.RSAPublicKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
-	if (!gkm_data_asn1_read_mpi (asn, "modulus", &n) ||
-	    !gkm_data_asn1_read_mpi (asn, "publicExponent", &e))
+	if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "modulus", NULL), &n) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "publicExponent", NULL), &e))
 		goto done;
 
 	res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_RSA, n, e);
@@ -101,8 +103,7 @@ gkm_data_der_read_public_key_rsa (const guchar *data, gsize n_data, gcry_sexp_t
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (n);
 	gcry_mpi_release (e);
 
@@ -128,34 +129,34 @@ gkm_data_der_read_private_key_rsa (const guchar *data, gsize n_data, gcry_sexp_t
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	gcry_mpi_t n, e, d, p, q, u;
 	gcry_mpi_t tmp;
-	guint version;
+	gulong version;
+	GNode *asn = NULL;
 	int res;
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
 
 	n = e = d = p = q = u = NULL;
 
-	asn = egg_asn1_decode ("PK.RSAPrivateKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
-	if (!egg_asn1_read_uint (asn, "version", &version))
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version))
 		goto done;
 
 	/* We only support simple version */
 	if (version != 0) {
 		ret = GKM_DATA_UNRECOGNIZED;
-		g_message ("unsupported version of RSA key: %u", version);
+		g_message ("unsupported version of RSA key: %lu", version);
 		goto done;
 	}
 
-	if (!gkm_data_asn1_read_secure_mpi (asn, "modulus", &n) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "publicExponent", &e) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "privateExponent", &d) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "prime1", &p) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "prime2", &q) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "coefficient", &u))
+	if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "modulus", NULL), &n) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "publicExponent", NULL), &e) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "privateExponent", NULL), &d) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "prime1", NULL), &p) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "prime2", NULL), &q) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "coefficient", NULL), &u))
 		goto done;
 
 	/* Fix up the incoming key so gcrypt likes it */
@@ -177,8 +178,7 @@ gkm_data_der_read_private_key_rsa (const guchar *data, gsize n_data, gcry_sexp_t
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (n);
 	gcry_mpi_release (e);
 	gcry_mpi_release (d);
@@ -204,22 +204,22 @@ GkmDataResult
 gkm_data_der_read_public_key_dsa (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t p, q, g, y;
 	int res;
 
 	p = q = g = y = NULL;
 
-	asn = egg_asn1_decode ("PK.DSAPublicKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicKey", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
-	if (!gkm_data_asn1_read_mpi (asn, "p", &p) ||
-	    !gkm_data_asn1_read_mpi (asn, "q", &q) ||
-	    !gkm_data_asn1_read_mpi (asn, "g", &g) ||
-	    !gkm_data_asn1_read_mpi (asn, "Y", &y))
+	if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "p", NULL), &p) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "q", NULL), &q) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "g", NULL), &g) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "Y", NULL), &y))
 		goto done;
 
 	res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
@@ -230,8 +230,7 @@ gkm_data_der_read_public_key_dsa (const guchar *data, gsize n_data, gcry_sexp_t
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (p);
 	gcry_mpi_release (q);
 	gcry_mpi_release (g);
@@ -250,25 +249,25 @@ gkm_data_der_read_public_key_dsa_parts (const guchar *keydata, gsize n_keydata,
 {
 	gcry_mpi_t p, q, g, y;
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
-	ASN1_TYPE asn_params = ASN1_TYPE_EMPTY;
-	ASN1_TYPE asn_key = ASN1_TYPE_EMPTY;
+	GNode *asn_params = NULL;
+	GNode *asn_key = NULL;
 	int res;
 
 	p = q = g = y = NULL;
 
-	asn_params = egg_asn1_decode ("PK.DSAParameters", params, n_params);
-	asn_key = egg_asn1_decode ("PK.DSAPublicPart", keydata, n_keydata);
+	asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params, n_params);
+	asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicPart", keydata, n_keydata);
 	if (!asn_params || !asn_key)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
-	if (!gkm_data_asn1_read_mpi (asn_params, "p", &p) ||
-	    !gkm_data_asn1_read_mpi (asn_params, "q", &q) ||
-	    !gkm_data_asn1_read_mpi (asn_params, "g", &g))
+	if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "p", NULL), &p) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "q", NULL), &q) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "g", NULL), &g))
 		goto done;
 
-	if (!gkm_data_asn1_read_mpi (asn_key, "", &y))
+	if (!gkm_data_asn1_read_mpi (asn_key, &y))
 		goto done;
 
 	res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
@@ -279,10 +278,8 @@ gkm_data_der_read_public_key_dsa_parts (const guchar *keydata, gsize n_keydata,
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn_key)
-		asn1_delete_structure (&asn_key);
-	if (asn_params)
-		asn1_delete_structure (&asn_params);
+	egg_asn1x_destroy (asn_key);
+	egg_asn1x_destroy (asn_params);
 	gcry_mpi_release (p);
 	gcry_mpi_release (q);
 	gcry_mpi_release (g);
@@ -309,21 +306,21 @@ gkm_data_der_read_private_key_dsa (const guchar *data, gsize n_data, gcry_sexp_t
 	gcry_mpi_t p, q, g, y, x;
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	int res;
-	ASN1_TYPE asn;
+	GNode *asn = NULL;
 
 	p = q = g = y = x = NULL;
 
-	asn = egg_asn1_decode ("PK.DSAPrivateKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
-	if (!gkm_data_asn1_read_secure_mpi (asn, "p", &p) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "q", &q) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "g", &g) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "Y", &y) ||
-	    !gkm_data_asn1_read_secure_mpi (asn, "priv", &x))
+	if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "p", NULL), &p) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "q", NULL), &q) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "g", NULL), &g) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "Y", NULL), &y) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "priv", NULL), &x))
 		goto done;
 
 	res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_DSA, p, q, g, y, x);
@@ -334,8 +331,7 @@ gkm_data_der_read_private_key_dsa (const guchar *data, gsize n_data, gcry_sexp_t
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (p);
 	gcry_mpi_release (q);
 	gcry_mpi_release (g);
@@ -356,24 +352,24 @@ gkm_data_der_read_private_key_dsa_parts (const guchar *keydata, gsize n_keydata,
 	gcry_mpi_t p, q, g, y, x;
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	int res;
-	ASN1_TYPE asn_params = ASN1_TYPE_EMPTY;
-	ASN1_TYPE asn_key = ASN1_TYPE_EMPTY;
+	GNode *asn_params = NULL;
+	GNode *asn_key = NULL;
 
 	p = q = g = y = x = NULL;
 
-	asn_params = egg_asn1_decode ("PK.DSAParameters", params, n_params);
-	asn_key = egg_asn1_decode ("PK.DSAPrivatePart", keydata, n_keydata);
+	asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params, n_params);
+	asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata, n_keydata);
 	if (!asn_params || !asn_key)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
-	if (!gkm_data_asn1_read_secure_mpi (asn_params, "p", &p) ||
-	    !gkm_data_asn1_read_secure_mpi (asn_params, "q", &q) ||
-	    !gkm_data_asn1_read_secure_mpi (asn_params, "g", &g))
+	if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "p", NULL), &p) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "q", NULL), &q) ||
+	    !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "g", NULL), &g))
 		goto done;
 
-	if (!gkm_data_asn1_read_secure_mpi (asn_key, "", &x))
+	if (!gkm_data_asn1_read_mpi (asn_key, &x))
 		goto done;
 
 	/* Now we calculate y */
@@ -388,10 +384,8 @@ gkm_data_der_read_private_key_dsa_parts (const guchar *keydata, gsize n_keydata,
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn_key)
-		asn1_delete_structure (&asn_key);
-	if (asn_params)
-		asn1_delete_structure (&asn_params);
+	egg_asn1x_destroy (asn_key);
+	egg_asn1x_destroy (asn_params);
 	gcry_mpi_release (p);
 	gcry_mpi_release (q);
 	gcry_mpi_release (g);
@@ -421,40 +415,40 @@ gkm_data_der_read_public_key_info (const guchar* data, gsize n_data, gcry_sexp_t
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	GQuark oid;
-	ASN1_TYPE asn;
-	gsize n_key, n_params;
+	GNode *asn = NULL;
+	gsize n_params;
+	guint n_bits;
 	const guchar *params;
 	guchar *key = NULL;
 
 	init_quarks ();
 
-	asn = egg_asn1_decode ("PKIX1.SubjectPublicKeyInfo", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
 	/* Figure out the algorithm */
-	oid = egg_asn1_read_oid (asn, "algorithm.algorithm");
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "algorithm", "algorithm", NULL));
 	if (!oid)
 		goto done;
 
 	/* A bit string so we cannot process in place */
-	key = egg_asn1_read_value (asn, "subjectPublicKey", &n_key, NULL);
+	key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), NULL, &n_bits);
 	if (!key)
 		goto done;
-	n_key /= 8;
 
 	/* An RSA key is simple */
 	if (oid == OID_PKIX1_RSA) {
-		ret = gkm_data_der_read_public_key_rsa (key, n_key, s_key);
+		ret = gkm_data_der_read_public_key_rsa (key, n_bits / 8, s_key);
 
 	/* A DSA key paramaters are stored separately */
 	} else if (oid == OID_PKIX1_DSA) {
-		params = egg_asn1_read_element (asn, data, n_data, "algorithm.parameters", &n_params);
+		params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "algorithm", "parameters", NULL), &n_params);
 		if (!params)
 			goto done;
-		ret = gkm_data_der_read_public_key_dsa_parts (key, n_key, params, n_params, s_key);
+		ret = gkm_data_der_read_public_key_dsa_parts (key, n_bits / 8, params, n_params, s_key);
 
 	} else {
 		g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid));
@@ -463,9 +457,7 @@ gkm_data_der_read_public_key_info (const guchar* data, gsize n_data, gcry_sexp_t
 	}
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-
+	egg_asn1x_destroy (asn);
 	g_free (key);
 
 	if (ret == GKM_DATA_FAILURE)
@@ -489,7 +481,7 @@ gkm_data_der_read_private_key (const guchar *data, gsize n_data, gcry_sexp_t *s_
 GkmDataResult
 gkm_data_der_read_private_pkcs8_plain (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	GkmDataResult ret;
 	int algorithm;
 	GQuark key_algo;
@@ -502,14 +494,14 @@ gkm_data_der_read_private_pkcs8_plain (const guchar *data, gsize n_data, gcry_se
 
 	init_quarks ();
 
-	asn = egg_asn1_decode ("PKIX1.pkcs-8-PrivateKeyInfo", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 	algorithm = 0;
 
-	key_algo = egg_asn1_read_oid (asn, "privateKeyAlgorithm.algorithm");
+	key_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL));
 	if (!key_algo)
 		goto done;
 	else if (key_algo == OID_PKIX1_RSA)
@@ -522,12 +514,12 @@ gkm_data_der_read_private_pkcs8_plain (const guchar *data, gsize n_data, gcry_se
 		goto done;
 	}
 
-	keydata = egg_asn1_read_content (asn, data, n_data, "privateKey", &n_keydata);
+	keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL), &n_keydata);
 	if (!keydata)
 		goto done;
 
-	params = egg_asn1_read_element (asn, data, n_data, "privateKeyAlgorithm.parameters",
-	                                     &n_params);
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL),
+	                                    &n_params);
 
 	ret = GKM_DATA_SUCCESS;
 
@@ -556,9 +548,7 @@ done:
 		g_message ("invalid PKCS#8 key");
 	}
 
-	if (asn)
-		asn1_delete_structure (&asn);
-
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -566,7 +556,7 @@ GkmDataResult
 gkm_data_der_read_private_pkcs8_crypted (const guchar *data, gsize n_data, const gchar *password,
                                          gsize n_password, gcry_sexp_t *s_key)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_cipher_hd_t cih = NULL;
 	gcry_error_t gcry;
 	GkmDataResult ret, r;
@@ -580,18 +570,18 @@ gkm_data_der_read_private_pkcs8_crypted (const guchar *data, gsize n_data, const
 
 	ret = GKM_DATA_UNRECOGNIZED;
 
-	asn = egg_asn1_decode ("PKIX1.pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
 	/* Figure out the type of encryption */
-	scheme = egg_asn1_read_oid (asn, "encryptionAlgorithm.algorithm");
+	scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL));
 	if (!scheme)
 		goto done;
 
-	params = egg_asn1_read_element (asn, data, n_data, "encryptionAlgorithm.parameters", &n_params);
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params);
 	if (!params)
 		goto done;
 
@@ -607,7 +597,8 @@ gkm_data_der_read_private_pkcs8_crypted (const guchar *data, gsize n_data, const
 		goto done;
 	}
 
-	crypted = egg_asn1_read_value (asn, "encryptedData", &n_crypted, (EggAllocator)egg_secure_realloc);
+	crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL),
+	                                       egg_secure_realloc, &n_crypted);
 	if (!crypted)
 		goto done;
 
@@ -621,7 +612,7 @@ gkm_data_der_read_private_pkcs8_crypted (const guchar *data, gsize n_data, const
 	}
 
 	/* Unpad the DER data */
-	l = egg_asn1_element_length (crypted, n_crypted);
+	l = egg_asn1x_element_length (crypted, n_crypted);
 	if (l <= 0 || l > n_crypted) {
 		ret = GKM_DATA_LOCKED;
 		goto done;
@@ -640,8 +631,7 @@ gkm_data_der_read_private_pkcs8_crypted (const guchar *data, gsize n_data, const
 done:
 	if (cih)
 		gcry_cipher_close (cih);
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	egg_secure_free (crypted);
 
 	return ret;
@@ -663,30 +653,27 @@ gkm_data_der_read_private_pkcs8 (const guchar *data, gsize n_data, const gchar *
 guchar*
 gkm_data_der_write_public_key_rsa (gcry_sexp_t s_key, gsize *len)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t n, e;
 	guchar *result = NULL;
-	int res;
 
 	n = e = NULL;
 
-	res = asn1_create_element (egg_asn1_get_pk_asn1type (),
-	                           "PK.RSAPublicKey", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pk_asn1_tab, "RSAPublicKey");
+	g_return_val_if_fail (asn, NULL);
 
 	if (!gkm_sexp_extract_mpi (s_key, &n, "rsa", "n", NULL) ||
 	    !gkm_sexp_extract_mpi (s_key, &e, "rsa", "e", NULL))
 		goto done;
 
-	if (!gkm_data_asn1_write_mpi (asn, "modulus", n) ||
-	    !gkm_data_asn1_write_mpi (asn, "publicExponent", e))
+	if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "modulus", NULL), n) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "publicExponent", NULL), e))
 		goto done;
 
-	result = egg_asn1_encode (asn, "", len, NULL);
+	result = egg_asn1x_encode (asn, NULL, len);
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (n);
 	gcry_mpi_release (e);
 
@@ -696,16 +683,14 @@ done:
 guchar*
 gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key, gsize *n_key)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t n, e, d, p, q, u, e1, e2, tmp;
 	guchar *result = NULL;
-	int res;
 
 	n = e = d = p = q = u = e1 = e2 = tmp = NULL;
 
-	res = asn1_create_element (egg_asn1_get_pk_asn1type (),
-	                           "PK.RSAPrivateKey", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pk_asn1_tab, "RSAPrivateKey");
+	g_return_val_if_fail (asn, NULL);
 
 	if (!gkm_sexp_extract_mpi (s_key, &n, "rsa", "n", NULL) ||
 	    !gkm_sexp_extract_mpi (s_key, &e, "rsa", "e", NULL) ||
@@ -715,16 +700,12 @@ gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key, gsize *n_key)
 	    !gkm_sexp_extract_mpi (s_key, &u, "rsa", "u", NULL))
 		goto done;
 
-	if (!gkm_data_asn1_write_mpi (asn, "modulus", n) ||
-	    !gkm_data_asn1_write_mpi (asn, "publicExponent", e) ||
-	    !gkm_data_asn1_write_mpi (asn, "privateExponent", d) ||
-	    !gkm_data_asn1_write_mpi (asn, "prime1", p) ||
-	    !gkm_data_asn1_write_mpi (asn, "prime2", q) ||
-	    !gkm_data_asn1_write_mpi (asn, "coefficient", u))
-		goto done;
-
-	/* Have to write out a null to delete OPTIONAL */
-	if (!egg_asn1_write_value (asn, "otherPrimeInfos", NULL, 0))
+	if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "modulus", NULL), n) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "publicExponent", NULL), e) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "privateExponent", NULL), d) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "prime1", NULL), p) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "prime2", NULL), q) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "coefficient", NULL), u))
 		goto done;
 
 	/* Calculate e1 and e2 */
@@ -737,19 +718,18 @@ gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key, gsize *n_key)
 	gcry_mpi_mod (e2, d, tmp);
 
 	/* Write out calculated */
-	if (!gkm_data_asn1_write_mpi (asn, "exponent1", e1) ||
-	    !gkm_data_asn1_write_mpi (asn, "exponent2", e2))
+	if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "exponent1", NULL), e1) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "exponent2", NULL), e2))
 		goto done;
 
 	/* Write out the version */
-	if (!egg_asn1_write_uint (asn, "version", 0))
+	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0))
 		goto done;
 
-	result = egg_asn1_encode (asn, "", n_key, NULL);
+	result = egg_asn1x_encode (asn, egg_secure_realloc, n_key);
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (n);
 	gcry_mpi_release (e);
 	gcry_mpi_release (d);
@@ -767,16 +747,14 @@ done:
 guchar*
 gkm_data_der_write_public_key_dsa (gcry_sexp_t s_key, gsize *len)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t p, q, g, y;
 	guchar *result = NULL;
-	int res;
 
 	p = q = g = y = NULL;
 
-	res = asn1_create_element (egg_asn1_get_pk_asn1type (),
-	                           "PK.DSAPublicKey", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pk_asn1_tab, "DSAPublicKey");
+	g_return_val_if_fail (asn, NULL);
 
 	if (!gkm_sexp_extract_mpi (s_key, &p, "dsa", "p", NULL) ||
 	    !gkm_sexp_extract_mpi (s_key, &q, "dsa", "q", NULL) ||
@@ -784,20 +762,19 @@ gkm_data_der_write_public_key_dsa (gcry_sexp_t s_key, gsize *len)
 	    !gkm_sexp_extract_mpi (s_key, &y, "dsa", "y", NULL))
 		goto done;
 
-	if (!gkm_data_asn1_write_mpi (asn, "p", p) ||
-	    !gkm_data_asn1_write_mpi (asn, "q", q) ||
-	    !gkm_data_asn1_write_mpi (asn, "g", g) ||
-	    !gkm_data_asn1_write_mpi (asn, "Y", y))
+	if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "p", NULL), p) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "q", NULL), q) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "g", NULL), g) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "Y", NULL), y))
 		goto done;
 
-	if (!egg_asn1_write_uint (asn, "version", 0))
+	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0))
 		goto done;
 
-	result = egg_asn1_encode (asn, "", len, NULL);
+	result = egg_asn1x_encode (asn, NULL, len);
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (p);
 	gcry_mpi_release (q);
 	gcry_mpi_release (g);
@@ -809,28 +786,25 @@ done:
 guchar*
 gkm_data_der_write_private_key_dsa_part (gcry_sexp_t skey, gsize *n_key)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t x;
 	guchar *result = NULL;
-	int res;
 
 	x = NULL;
 
-	res = asn1_create_element (egg_asn1_get_pk_asn1type (),
-	                           "PK.DSAPrivatePart", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pk_asn1_tab, "DSAPrivatePart");
+	g_return_val_if_fail (asn, NULL);
 
 	if (!gkm_sexp_extract_mpi (skey, &x, "dsa", "x", NULL))
 		goto done;
 
-	if (!gkm_data_asn1_write_mpi (asn, "", x))
+	if (!gkm_data_asn1_write_mpi (asn, x))
 		goto done;
 
-	result = egg_asn1_encode (asn, "", n_key, NULL);
+	result = egg_asn1x_encode (asn, egg_secure_realloc, n_key);
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (x);
 
 	return result;
@@ -839,32 +813,29 @@ done:
 guchar*
 gkm_data_der_write_private_key_dsa_params (gcry_sexp_t skey, gsize *n_params)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t p, q, g;
 	guchar *result = NULL;
-	int res;
 
 	p = q = g = NULL;
 
-	res = asn1_create_element (egg_asn1_get_pk_asn1type (),
-	                           "PK.DSAParameters", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters");
+	g_return_val_if_fail (asn, NULL);
 
 	if (!gkm_sexp_extract_mpi (skey, &p, "dsa", "p", NULL) ||
 	    !gkm_sexp_extract_mpi (skey, &q, "dsa", "q", NULL) ||
 	    !gkm_sexp_extract_mpi (skey, &g, "dsa", "g", NULL))
 		goto done;
 
-	if (!gkm_data_asn1_write_mpi (asn, "p", p) ||
-	    !gkm_data_asn1_write_mpi (asn, "q", q) ||
-	    !gkm_data_asn1_write_mpi (asn, "g", g))
+	if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "p", NULL), p) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "q", NULL), q) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "g", NULL), g))
 		goto done;
 
-	result = egg_asn1_encode (asn, "", n_params, NULL);
+	result = egg_asn1x_encode (asn, egg_secure_realloc, n_params);
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (p);
 	gcry_mpi_release (q);
 	gcry_mpi_release (g);
@@ -875,16 +846,14 @@ done:
 guchar*
 gkm_data_der_write_private_key_dsa (gcry_sexp_t s_key, gsize *len)
 {
-	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GNode *asn = NULL;
 	gcry_mpi_t p, q, g, y, x;
 	guchar *result = NULL;
-	int res;
 
 	p = q = g = y = x = NULL;
 
-	res = asn1_create_element (egg_asn1_get_pk_asn1type (),
-	                           "PK.DSAPrivateKey", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pk_asn1_tab, "DSAPrivateKey");
+	g_return_val_if_fail (asn, NULL);
 
 	if (!gkm_sexp_extract_mpi (s_key, &p, "dsa", "p", NULL) ||
 	    !gkm_sexp_extract_mpi (s_key, &q, "dsa", "q", NULL) ||
@@ -893,21 +862,20 @@ gkm_data_der_write_private_key_dsa (gcry_sexp_t s_key, gsize *len)
 	    !gkm_sexp_extract_mpi (s_key, &x, "dsa", "x", NULL))
 		goto done;
 
-	if (!gkm_data_asn1_write_mpi (asn, "p", p) ||
-	    !gkm_data_asn1_write_mpi (asn, "q", q) ||
-	    !gkm_data_asn1_write_mpi (asn, "g", g) ||
-	    !gkm_data_asn1_write_mpi (asn, "Y", y) ||
-	    !gkm_data_asn1_write_mpi (asn, "priv", x))
+	if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "p", NULL), p) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "q", NULL), q) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "g", NULL), g) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "Y", NULL), y) ||
+	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "priv", NULL), x))
 		goto done;
 
-	if (!egg_asn1_write_uint (asn, "version", 0))
+	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0))
 		goto done;
 
-	result = egg_asn1_encode (asn, "", len, NULL);
+	result = egg_asn1x_encode (asn, egg_secure_realloc, len);
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	gcry_mpi_release (p);
 	gcry_mpi_release (q);
 	gcry_mpi_release (g);
@@ -964,16 +932,16 @@ gkm_data_der_write_private_key (gcry_sexp_t s_key, gsize *len)
 }
 
 static gcry_cipher_hd_t
-prepare_and_encode_pkcs8_cipher (ASN1_TYPE asn, const gchar *password,
+prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password,
                                  gsize n_password, gsize *n_block)
 {
-	ASN1_TYPE asn1_params;
+	GNode *asn1_params = NULL;
 	gcry_cipher_hd_t cih;
 	guchar salt[8];
 	gcry_error_t gcry;
 	guchar *key, *iv, *portion;
 	gsize n_key, n_portion;
-	int iterations, res;
+	int iterations;
 
 	init_quarks ();
 
@@ -982,8 +950,8 @@ prepare_and_encode_pkcs8_cipher (ASN1_TYPE asn, const gchar *password,
 	                                             GCRYCTL_TEST_ALGO, NULL, 0), NULL);
 
 	/* The encryption algorithm */
-	if(!egg_asn1_write_oid (asn, "encryptionAlgorithm.algorithm",
-	                             OID_PKCS12_PBE_3DES_SHA1))
+	if(!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL),
+	                                OID_PKCS12_PBE_3DES_SHA1))
 		g_return_val_if_reached (NULL);
 
 	/* Randomize some input for the password based secret */
@@ -1001,19 +969,18 @@ prepare_and_encode_pkcs8_cipher (ASN1_TYPE asn, const gchar *password,
 		g_return_val_if_reached (NULL);
 
 	/* Now write out the parameters */
-	res = asn1_create_element (egg_asn1_get_pkix_asn1type (),
-	                           "PKIX1.pkcs-12-PbeParams", &asn1_params);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
-	if (!egg_asn1_write_value (asn1_params, "salt", salt, sizeof (salt)))
+	asn1_params = egg_asn1x_create (pkix_asn1_tab, "pkcs-12-PbeParams");
+	g_return_val_if_fail (asn1_params, NULL);
+	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn1_params, "salt", NULL), salt, sizeof (salt), NULL))
 		g_return_val_if_reached (NULL);
-	if (!egg_asn1_write_uint (asn1_params, "iterations", iterations))
+	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn1_params, "iterations", NULL), iterations))
 		g_return_val_if_reached (NULL);
-	portion = egg_asn1_encode (asn1_params, "", &n_portion, NULL);
+	portion = egg_asn1x_encode (asn1_params, NULL, &n_portion);
 	g_return_val_if_fail (portion, NULL);
 
-	if (!egg_asn1_write_value (asn, "encryptionAlgorithm.parameters", portion, n_portion))
+	if (!egg_asn1x_set_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL),
+	                                portion, n_portion, g_free))
 		g_return_val_if_reached (NULL);
-	g_free (portion);
 
 	/* Now make a cipher that matches what we wrote out */
 	gcry = gcry_cipher_open (&cih, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
@@ -1025,7 +992,7 @@ prepare_and_encode_pkcs8_cipher (ASN1_TYPE asn, const gchar *password,
 
 	g_free (iv);
 	egg_secure_free (key);
-	asn1_delete_structure (&asn1_params);
+	egg_asn1x_destroy (asn1_params);
 
 	return cih;
 }
@@ -1033,8 +1000,8 @@ prepare_and_encode_pkcs8_cipher (ASN1_TYPE asn, const gchar *password,
 guchar*
 gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey, gsize *n_data)
 {
-	ASN1_TYPE asn;
-	int res, algorithm;
+	GNode *asn = NULL;
+	int algorithm;
 	gboolean is_priv;
 	GQuark oid;
 	guchar *params, *key, *data;
@@ -1047,12 +1014,11 @@ gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey, gsize *n_data)
 		g_return_val_if_reached (NULL);
 	g_return_val_if_fail (is_priv == TRUE, NULL);
 
-	res = asn1_create_element (egg_asn1_get_pkix_asn1type (),
-	                           "PKIX1.pkcs-8-PrivateKeyInfo", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo");
+	g_return_val_if_fail (asn, NULL);
 
 	/* Write out the version */
-	if (!egg_asn1_write_uint (asn, "version", 0))
+	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0))
 		g_return_val_if_reached (NULL);
 
 	/* Per algorithm differences */
@@ -1079,28 +1045,25 @@ gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey, gsize *n_data)
 	};
 
 	/* Write out the algorithm */
-	if (!egg_asn1_write_oid (asn, "privateKeyAlgorithm.algorithm", oid))
+	if (!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL), oid))
 		g_return_val_if_reached (NULL);
 
 	/* Write out the parameters */
-	if (!egg_asn1_write_value (asn, "privateKeyAlgorithm.parameters", params, n_params))
-		g_return_val_if_reached (NULL);
-	egg_secure_free (params);
+	if (params) {
+		if (!egg_asn1x_set_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL),
+		                                params, n_params, egg_secure_free))
+			g_return_val_if_reached (NULL);
+	}
 
 	/* Write out the key portion */
-	if (!egg_asn1_write_value (asn, "privateKey", key, n_key))
-		g_return_val_if_reached (NULL);
-	egg_secure_free (key);
-
-	/* Add an empty attributes field */
-	if (!egg_asn1_write_value (asn, "attributes", NULL, 0))
+	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "privateKey", NULL),
+	                                  key, n_key, egg_secure_free))
 		g_return_val_if_reached (NULL);
 
-	data = egg_asn1_encode (asn, "", n_data, NULL);
+	data = egg_asn1x_encode (asn, egg_secure_realloc, n_data);
 	g_return_val_if_fail (data, NULL);
 
-	asn1_delete_structure (&asn);
-
+	egg_asn1x_destroy (asn);
 	return data;
 }
 
@@ -1110,17 +1073,17 @@ gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *passwor
 {
 	gcry_error_t gcry;
 	gcry_cipher_hd_t cih;
-	ASN1_TYPE asn;
-	int res;
+	GNode *asn = NULL;
 	guchar *key, *data;
 	gsize n_key, block = 0;
 
 	/* Encode the key in normal pkcs8 fashion */
 	key = gkm_data_der_write_private_pkcs8_plain (skey, &n_key);
+	if (key == NULL)
+		return NULL;
 
-	res = asn1_create_element (egg_asn1_get_pkix_asn1type (),
-	                           "PKIX1.pkcs-8-EncryptedPrivateKeyInfo", &asn);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo");
+	g_return_val_if_fail (asn, NULL);
 
 	/* Create a and write out a cipher used for encryption */
 	cih = prepare_and_encode_pkcs8_cipher (asn, password, n_password, &block);
@@ -1134,7 +1097,7 @@ gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *passwor
 		pad = block - (n_key % block);
 		if (pad == 0)
 			pad = block;
-		padded = g_realloc (key, n_key + pad);
+		padded = egg_secure_realloc (key, n_key + pad);
 		memset (padded + n_key, pad, pad);
 		key = padded;
 		n_key += pad;
@@ -1145,14 +1108,14 @@ gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *passwor
 
 	gcry_cipher_close (cih);
 
-	res = asn1_write_value (asn, "encryptedData", key, n_key);
-	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL),
+	                                  key, n_key, egg_secure_free))
+		g_return_val_if_reached (NULL);
 
-	data = egg_asn1_encode (asn, "", n_data, NULL);
+	data = egg_asn1x_encode (asn, NULL, n_data);
 	g_return_val_if_fail (data, NULL);
 
-	asn1_delete_structure (&asn);
-
+	egg_asn1x_destroy (asn);
 	return data;
 }
 
@@ -1161,9 +1124,9 @@ gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *passwor
  */
 
 GkmDataResult
-gkm_data_der_read_certificate (const guchar *data, gsize n_data, ASN1_TYPE *asn1)
+gkm_data_der_read_certificate (const guchar *data, gsize n_data, GNode **asn1)
 {
-	*asn1 = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+	*asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
 	if (!*asn1)
 		return GKM_DATA_UNRECOGNIZED;
 
@@ -1175,33 +1138,38 @@ gkm_data_der_read_basic_constraints (const guchar *data, gsize n_data,
                                      gboolean *is_ca, gint *path_len)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
-	ASN1_TYPE asn;
-	guint value;
+	GNode *asn = NULL;
+	GNode *node;
+	gulong value;
 
-	asn = egg_asn1_decode ("PKIX1.BasicConstraints", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
 	if (path_len) {
-		if (!egg_asn1_read_uint (asn, "pathLenConstraint", &value))
+		node = egg_asn1x_node (asn, "pathLenConstraint", NULL);
+		if (!egg_asn1x_have (node))
 			*path_len = -1;
+		else if (!egg_asn1x_get_integer_as_ulong (node, &value))
+			goto done;
 		else
 			*path_len = value;
 	}
 
 	if (is_ca) {
-		if (!egg_asn1_read_boolean (asn, "cA", is_ca))
+		node = egg_asn1x_node (asn, "cA", NULL);
+		if (!egg_asn1x_have (node))
 			*is_ca = FALSE;
+		else if (!egg_asn1x_get_boolean (node, is_ca))
+			goto done;
 	}
 
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
-
+	egg_asn1x_destroy (asn);
 	if (ret == GKM_DATA_FAILURE)
 		g_message ("invalid basic constraints");
 
@@ -1209,31 +1177,25 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_key_usage (const guchar *data, gsize n_data, guint *key_usage)
+gkm_data_der_read_key_usage (const guchar *data, gsize n_data, gulong *key_usage)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
-	ASN1_TYPE asn;
-	guchar buf[4];
-	int res, len;
+	GNode *asn = NULL;
+	guint n_bits;
 
-	asn = egg_asn1_decode ("PKIX1.KeyUsage", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data, n_data);
 	if (!asn)
 		goto done;
 
 	ret = GKM_DATA_FAILURE;
 
-	memset (buf, 0, sizeof (buf));
-	len = sizeof (buf);
-	res = asn1_read_value (asn, "", buf, &len);
-	if (res != ASN1_SUCCESS || len < 1 || len > 2)
+	if (!egg_asn1x_get_bits_as_ulong (asn, key_usage, &n_bits))
 		goto done;
 
-	*key_usage = buf[0] | (buf[1] << 8);
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
@@ -1241,13 +1203,13 @@ GkmDataResult
 gkm_data_der_read_enhanced_usage (const guchar *data, gsize n_data, GQuark **usage_oids)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
-	ASN1_TYPE asn;
-	gchar *part;
+	GNode *asn = NULL;
+	GNode *node;
 	GArray *array;
 	GQuark oid;
 	int i;
 
-	asn = egg_asn1_decode ("PKIX1.ExtKeyUsageSyntax", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data, n_data);
 	if (!asn)
 		goto done;
 
@@ -1255,13 +1217,11 @@ gkm_data_der_read_enhanced_usage (const guchar *data, gsize n_data, GQuark **usa
 
 	array = g_array_new (TRUE, TRUE, sizeof (GQuark));
 	for (i = 0; TRUE; ++i) {
-		part = g_strdup_printf ("?%d", i + 1);
-		oid = egg_asn1_read_oid (asn, part);
-		g_free (part);
-
-		if (!oid)
+		node = egg_asn1x_node (asn, i + 1, NULL);
+		if (node == NULL)
 			break;
 
+		oid = egg_asn1x_get_oid_as_quark (node);
 		g_array_append_val (array, oid);
 	}
 
@@ -1269,17 +1229,16 @@ gkm_data_der_read_enhanced_usage (const guchar *data, gsize n_data, GQuark **usa
 	ret = GKM_DATA_SUCCESS;
 
 done:
-	if (asn)
-		asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 	return ret;
 }
 
 
 guchar*
-gkm_data_der_write_certificate (ASN1_TYPE asn1, gsize *n_data)
+gkm_data_der_write_certificate (GNode *asn1, gsize *n_data)
 {
 	g_return_val_if_fail (asn1, NULL);
 	g_return_val_if_fail (n_data, NULL);
 
-	return egg_asn1_encode (asn1, "", n_data, NULL);
+	return egg_asn1x_encode (asn1, NULL, n_data);
 }
diff --git a/pkcs11/gkm/gkm-data-der.h b/pkcs11/gkm/gkm-data-der.h
index f178a95..4a69091 100644
--- a/pkcs11/gkm/gkm-data-der.h
+++ b/pkcs11/gkm/gkm-data-der.h
@@ -30,6 +30,8 @@
 
 #include "gkm-data-types.h"
 
+#include "egg/egg-asn1x.h"
+
 /* -----------------------------------------------------------------------------
  * PRIVATE KEYS
  */
@@ -105,17 +107,18 @@ guchar*            gkm_data_der_write_public_key           (gcry_sexp_t s_key, g
  */
 
 GkmDataResult      gkm_data_der_read_certificate           (const guchar *data, gsize n_data,
-                                                            ASN1_TYPE *asn1);
+                                                            GNode **asn1);
 
 GkmDataResult      gkm_data_der_read_basic_constraints     (const guchar *data, gsize n_data,
                                                             gboolean *is_ca, gint *path_len);
 
-GkmDataResult      gkm_data_der_read_key_usage             (const guchar *data, gsize n_data,
-                                                            guint *key_usage);
+GkmDataResult      gkm_data_der_read_key_usage             (const guchar *data,
+                                                            gsize n_data,
+                                                            gulong *key_usage);
 
 GkmDataResult      gkm_data_der_read_enhanced_usage        (const guchar *data, gsize n_data,
                                                             GQuark **oids);
 
-guchar*            gkm_data_der_write_certificate          (ASN1_TYPE asn1, gsize *n_data);
+guchar*            gkm_data_der_write_certificate          (GNode *asn1, gsize *n_data);
 
 #endif /*GKRPKIXDER_H_*/
diff --git a/pkcs11/gkm/tests/unit-test-data-asn1.c b/pkcs11/gkm/tests/unit-test-data-asn1.c
index a7b6021..24c74e8 100644
--- a/pkcs11/gkm/tests/unit-test-data-asn1.c
+++ b/pkcs11/gkm/tests/unit-test-data-asn1.c
@@ -35,56 +35,38 @@
 #include <stdio.h>
 #include <string.h>
 
-#define extern
-#include "asn1-def-test.h"
-#undef extern
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 
-static ASN1_TYPE asn1_test = NULL;
+#include "asn1-def-test.h"
 
-static ASN1_TYPE asn1_cert = NULL;
+static GNode *asn1_cert = NULL;
 static guchar *data_cert = NULL;
 static gsize n_data_cert = 0;
 
 DEFINE_SETUP(asn1_tree)
 {
-	ASN1_TYPE pkix;
-
-	int res = asn1_array2tree (test_asn1_tab, &asn1_test, NULL);
-	g_assert (res == ASN1_SUCCESS);
-
-	/* -------- */
-
 	data_cert = testing_data_read ("test-certificate-1.der", &n_data_cert);
-
-	/* We'll be catching this error later */
-	pkix = egg_asn1_get_pkix_asn1type ();
-	if (!pkix) return;
-
-	res = asn1_create_element (pkix, "PKIX1.Certificate", &asn1_cert);
-	g_assert (res == ASN1_SUCCESS);
-
-	res = asn1_der_decoding (&asn1_cert, data_cert, n_data_cert, NULL);
-	g_assert (res == ASN1_SUCCESS);
+	asn1_cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data_cert, n_data_cert);
+	g_assert (asn1_cert);
 }
 
 DEFINE_TEARDOWN(asn1_tree)
 {
-	asn1_delete_structure (&asn1_test);
-	asn1_delete_structure (&asn1_cert);
+	egg_asn1x_destroy (asn1_cert);
 	g_free (data_cert);
 	data_cert = NULL;
 }
 
 DEFINE_TEST(asn1_integers)
 {
-	ASN1_TYPE asn;
+	GNode *asn;
 	gcry_mpi_t mpi, mpt;
 	guchar *data;
 	gsize n_data;
 	gboolean ret;
-	int res;
 
-	res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn);
+	asn = egg_asn1x_create (test_asn1_tab, "TestIntegers");
 	g_assert ("asn test structure is null" && asn != NULL);
 
 	/* Make a random number */
@@ -93,22 +75,19 @@ DEFINE_TEST(asn1_integers)
 	gcry_mpi_randomize (mpi, 512, GCRY_WEAK_RANDOM);
 
 	/* Write the mpi out */
-	ret = gkm_data_asn1_write_mpi (asn, "mpi", mpi);
+	ret = gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "mpi", NULL), mpi);
 
 	/* Now encode the whole caboodle */
-	data = egg_asn1_encode (asn, "", &n_data, NULL);
+	data = egg_asn1x_encode (asn, NULL, &n_data);
 	g_assert ("encoding asn1 didn't work" && data != NULL);
 
-	asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 
 	/* Now decode it all nicely */
-	res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn);
-	g_return_if_fail (res == ASN1_SUCCESS);
-
-	res = asn1_der_decoding (&asn, data, n_data, NULL);
-	g_assert ("decoding asn didn't work" && res == ASN1_SUCCESS);
+	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestIntegers", data, n_data);
+	g_assert (asn);
 
-	ret = gkm_data_asn1_read_mpi (asn, "mpi", &mpt);
+	ret = gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "mpi", NULL), &mpt);
 	g_assert ("couldn't read mpi from asn1" && ret);
 	g_assert ("mpi returned is null" && mpt != NULL);
 	g_assert ("mpi is wrong number" && gcry_mpi_cmp (mpi, mpt) == 0);
diff --git a/pkcs11/gkm/tests/unit-test-data-der.c b/pkcs11/gkm/tests/unit-test-data-der.c
index 405547c..3825f0f 100644
--- a/pkcs11/gkm/tests/unit-test-data-der.c
+++ b/pkcs11/gkm/tests/unit-test-data-der.c
@@ -30,7 +30,10 @@
 #include "gkm/gkm-data-der.h"
 #include "gkm/gkm-sexp.h"
 
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-openssl.h"
+#include "egg/egg-secure-memory.h"
 
 #include <glib.h>
 #include <gcrypt.h>
@@ -39,11 +42,11 @@
 #include <stdio.h>
 #include <string.h>
 
-static ASN1_TYPE certificate = NULL;
+static GNode *certificate = NULL;
 static guchar *certificate_data = NULL;
 static gsize n_certificate_data = 0;
 
-static ASN1_TYPE certificate2 = NULL;
+static GNode *certificate2 = NULL;
 static guchar *certificate2_data = NULL;
 static gsize n_certificate2_data = 0;
 
@@ -112,21 +115,21 @@ test_der_public (gcry_sexp_t key)
 DEFINE_SETUP(preload)
 {
 	certificate_data = testing_data_read ("test-certificate-1.der", &n_certificate_data);
-	certificate = egg_asn1_decode ("PKIX1.Certificate", certificate_data, n_certificate_data);
+	certificate = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", certificate_data, n_certificate_data);
 	g_assert (certificate);
 
 	certificate2_data = testing_data_read ("test-certificate-2.der", &n_certificate2_data);
-	certificate2 = egg_asn1_decode ("PKIX1.Certificate", certificate2_data, n_certificate2_data);
+	certificate2 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", certificate2_data, n_certificate2_data);
 	g_assert (certificate2);
 }
 
 DEFINE_TEARDOWN(preload)
 {
-	asn1_delete_structure (&certificate);
+	egg_asn1x_destroy (certificate);
 	g_free (certificate_data);
 	certificate_data = NULL;
 
-	asn1_delete_structure (&certificate2);
+	egg_asn1x_destroy (certificate2);
 	g_free (certificate2_data);
 	certificate2_data = NULL;
 }
@@ -173,6 +176,8 @@ test_der_private (gcry_sexp_t key)
 
 	/* Now compare them */
 	g_assert ("key parsed differently" && compare_keys (key, sexp));
+
+	egg_secure_free (data);
 }
 
 DEFINE_TEST(der_rsa_private)
@@ -221,6 +226,9 @@ DEFINE_TEST(der_dsa_private_parts)
 
 	/* Now compare them */
 	g_assert ("key parsed differently" && compare_keys (skey, pkey));
+
+	egg_secure_free (params);
+	egg_secure_free (key);
 }
 
 const gchar *certpub = "(public-key (rsa " \
@@ -236,7 +244,7 @@ DEFINE_TEST(read_public_key_info)
 	gcry_sexp_t sexp, match;
 	gcry_error_t gcry;
 
-	data = egg_asn1_read_element (certificate, certificate_data, n_certificate_data, "tbsCertificate.subjectPublicKeyInfo", &n_data);
+	data = egg_asn1x_get_raw_element (egg_asn1x_node (certificate, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_data);
 	g_assert (data);
 
 	res = gkm_data_der_read_public_key_info (data, n_data, &sexp);
@@ -257,14 +265,14 @@ DEFINE_TEST(read_public_key_info)
 
 DEFINE_TEST(read_certificate)
 {
-	ASN1_TYPE asn = NULL;
+	GNode *asn = NULL;
 	GkmDataResult res;
 
 	res = gkm_data_der_read_certificate (certificate_data, n_certificate_data, &asn);
 	g_assert (res == GKM_DATA_SUCCESS);
 	g_assert (asn != NULL);
 
-	asn1_delete_structure (&asn);
+	egg_asn1x_destroy (asn);
 }
 
 DEFINE_TEST(write_certificate)
@@ -283,7 +291,7 @@ static void
 on_ca_certificate_public_key_info (GQuark type, const guchar *data, gsize n_data,
                                    GHashTable *headers, gpointer user_data)
 {
-	ASN1_TYPE asn1 = ASN1_TYPE_EMPTY;
+	GNode *asn1 = NULL;
 	GkmDataResult res;
 	gpointer keydata;
 	gsize n_keydata;
@@ -296,7 +304,7 @@ on_ca_certificate_public_key_info (GQuark type, const guchar *data, gsize n_data
 	g_assert (res == GKM_DATA_SUCCESS);
 
 	/* Generate a raw public key from our certificate */
-	keydata = egg_asn1_encode (asn1, "tbsCertificate.subjectPublicKeyInfo", &n_keydata, NULL);
+	keydata = egg_asn1x_encode (egg_asn1x_node (asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), NULL, &n_keydata);
 	g_assert (keydata);
 
 	/* Now create us a nice public key with that identifier */
@@ -319,12 +327,11 @@ DEFINE_TEST(read_ca_certificates_public_key_info)
 }
 
 static const guchar*
-find_extension (ASN1_TYPE asn, const guchar *data, gsize n_data, const gchar *oid, gsize *n_extension)
+find_extension (GNode *asn, const guchar *data, gsize n_data, const gchar *oid, gsize *n_extension)
 {
 	const guchar *value;
-	gsize n_exoid;
-	guchar *exoid;
-	gchar *name;
+	GNode *node = NULL;
+	gchar *exoid;
 	guint index;
 	int len;
 
@@ -333,19 +340,18 @@ find_extension (ASN1_TYPE asn, const guchar *data, gsize n_data, const gchar *oi
 	for (index = 1; TRUE; ++index) {
 
 		/* Make sure it is present */
-		name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnID", index);
-		exoid = egg_asn1_read_value (asn, name, &n_exoid, NULL);
-		g_free (name);
-
-		if (!exoid)
+		node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, "extnID", NULL);
+		if (node == NULL)
 			return NULL;
 
-		if (n_exoid - 1 == strlen (oid) && strcmp ((gchar*)exoid, oid) == 0) {
+		exoid = egg_asn1x_get_oid_as_string (node);
+		g_assert (exoid);
+
+		if (strcmp (exoid, oid) == 0) {
 			g_free (exoid);
-			name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnValue", index);
-			value = egg_asn1_read_content (asn, data, n_data, name, n_extension);
+			node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, "extnValue", NULL);
+			value = egg_asn1x_get_raw_value (node, n_extension);
 			g_assert (value);
-			g_free (name);
 			return value;
 		}
 
@@ -363,7 +369,8 @@ DEFINE_TEST(read_basic_constraints)
 	gint path_len;
 	GkmDataResult res;
 
-	extension = egg_asn1_read_content (certificate, certificate_data, n_certificate_data, "tbsCertificate.extensions.?1.extnValue", &n_extension);
+	extension = egg_asn1x_get_raw_value (egg_asn1x_node (certificate, "tbsCertificate", "extensions", 1, "extnValue", NULL),
+	                                       &n_extension);
 	g_assert (extension);
 
 	res = gkm_data_der_read_basic_constraints (extension, n_extension, &is_ca, &path_len);
@@ -376,7 +383,7 @@ DEFINE_TEST(read_key_usage)
 {
 	const guchar *extension;
 	gsize n_extension;
-	guint key_usage;
+	gulong key_usage;
 	GkmDataResult res;
 
 	extension = find_extension (certificate2, certificate2_data, n_certificate2_data, "2.5.29.15", &n_extension);
@@ -384,7 +391,7 @@ DEFINE_TEST(read_key_usage)
 
 	res = gkm_data_der_read_key_usage (extension, n_extension, &key_usage);
 	g_assert (res == GKM_DATA_SUCCESS);
-	g_assert_cmpuint (key_usage, ==, 0x80);
+	g_assert_cmpuint (key_usage, ==, 0x01);
 }
 
 DEFINE_TEST(read_enhanced_usage)
@@ -467,7 +474,7 @@ DEFINE_TEST(write_pkcs8_plain)
 	g_assert (n_data);
 
 	res = gkm_data_der_read_private_pkcs8_plain (data, n_data, &check);
-	g_free (data);
+	egg_secure_free (data);
 	g_assert (res == GKM_DATA_SUCCESS);
 	g_assert (check);
 
@@ -486,7 +493,7 @@ DEFINE_TEST(write_pkcs8_plain)
 	g_assert (n_data);
 
 	res = gkm_data_der_read_private_pkcs8_plain (data, n_data, &check);
-	g_free (data);
+	egg_secure_free (data);
 	g_assert (res == GKM_DATA_SUCCESS);
 	g_assert (check);
 
diff --git a/pkcs11/ssh-store/gkm-ssh-openssh.c b/pkcs11/ssh-store/gkm-ssh-openssh.c
index 44953ea..c165cd2 100644
--- a/pkcs11/ssh-store/gkm-ssh-openssh.c
+++ b/pkcs11/ssh-store/gkm-ssh-openssh.c
@@ -5,6 +5,7 @@
 #include "gkm/gkm-data-der.h"
 #include "gkm/gkm-data-types.h"
 
+#include "egg/egg-asn1x.h"
 #include "egg/egg-buffer.h"
 #include "egg/egg-openssl.h"
 #include "egg/egg-secure-memory.h"
@@ -171,7 +172,7 @@ load_encrypted_key (const guchar *data, gsize n_data, const gchar *dekinfo,
 	g_assert (decrypted);
 
 	/* Unpad the DER data */
-	length = egg_asn1_element_length (decrypted, n_decrypted);
+	length = egg_asn1x_element_length (decrypted, n_decrypted);
 	if (length > 0)
 		n_decrypted = length;
 
diff --git a/pkcs11/user-store/gkm-user-private-key.c b/pkcs11/user-store/gkm-user-private-key.c
index 68f8705..eb7d156 100644
--- a/pkcs11/user-store/gkm-user-private-key.c
+++ b/pkcs11/user-store/gkm-user-private-key.c
@@ -35,6 +35,8 @@
 #include "gkm/gkm-sexp.h"
 #include "gkm/gkm-util.h"
 
+#include "egg/egg-secure-memory.h"
+
 #include <glib/gi18n.h>
 
 enum {
@@ -294,6 +296,7 @@ gkm_user_private_key_real_save (GkmSerializable *base, GkmSecret *login, guchar
 	const gchar *password;
 	gsize n_password;
 	GkmSexp *sexp;
+	guchar *key;
 
 	g_return_val_if_fail (GKM_IS_USER_PRIVATE_KEY (self), FALSE);
 	g_return_val_if_fail (data, FALSE);
@@ -303,11 +306,19 @@ gkm_user_private_key_real_save (GkmSerializable *base, GkmSecret *login, guchar
 	g_return_val_if_fail (sexp, FALSE);
 
 	password = gkm_secret_get_password (login, &n_password);
-	if (password == NULL)
-		*data = gkm_data_der_write_private_pkcs8_plain (gkm_sexp_get (sexp), n_data);
-	else
+	if (password == NULL) {
+		key = gkm_data_der_write_private_pkcs8_plain (gkm_sexp_get (sexp), n_data);
+
+		/*
+		 * Caller is expecting normal memory buffer, which makes sense since
+		 * this is being written to disk, and won't be 'secure' anyway.
+		 */
+		*data = g_memdup (key, *n_data);
+		egg_secure_free (key);
+	} else {
 		*data = gkm_data_der_write_private_pkcs8_crypted (gkm_sexp_get (sexp), password,
 		                                                  n_password, n_data);
+	}
 
 	gkm_sexp_unref (sexp);
 	return *data != NULL;
diff --git a/pkcs11/user-store/gkm-user-storage.c b/pkcs11/user-store/gkm-user-storage.c
index 6cd8399..ea97be3 100644
--- a/pkcs11/user-store/gkm-user-storage.c
+++ b/pkcs11/user-store/gkm-user-storage.c
@@ -34,6 +34,8 @@
 #include "gkm/gkm-serializable.h"
 #include "gkm/gkm-util.h"
 
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-error.h"
 #include "egg/egg-hex.h"
@@ -133,17 +135,17 @@ static int flock(int fd, int operation)
 static gchar*
 name_for_subject (const guchar *subject, gsize n_subject)
 {
-	ASN1_TYPE asn;
+	GNode *asn;
 	gchar *name;
 
 	g_assert (subject);
 	g_assert (n_subject);
 
-	asn = egg_asn1_decode ("PKIX1.Name", subject, n_subject);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Name", subject, n_subject);
 	g_return_val_if_fail (asn, NULL);
 
-	name = egg_dn_read_part (asn, "rdnSequence", "CN");
-	asn1_delete_structure (&asn);
+	name = egg_dn_read_part (egg_asn1x_node (asn, "rdnSequence", NULL), "CN");
+	egg_asn1x_destroy (asn);
 
 	return name;
 }
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 971184b..ad4e044 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,7 +11,6 @@ daemon/gnome-keyring-gpg.desktop.in.in
 daemon/gpg-agent/gkd-gpg-agent-ops.c
 daemon/login/gkd-login.c
 daemon/org.gnome.keyring.service.in
-egg/egg-asn1.c
 egg/egg-oid.c
 egg/egg-spawn.c
 gcr/gcr-certificate-basics-widget.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]