[gnome-keyring] Bring over new egg'd components from gcr



commit 5c4a86255897206875d72fee0c41e657dce3e39f
Author: Stef Walter <stefw gnome org>
Date:   Sat Mar 10 07:57:41 2012 +0100

    Bring over new egg'd components from gcr
    
     * Updated ASN.1, armor, bytes, openssl, etc.

 .gitignore                                         |    1 +
 Makefile.decl                                      |   26 +-
 daemon/control/tests/frob-control-change.c         |    2 +-
 daemon/control/tests/frob-control-init.c           |    2 +-
 daemon/control/tests/frob-control-quit.c           |    2 +-
 daemon/control/tests/frob-control-unlock.c         |    2 +-
 daemon/gkd-main.c                                  |    8 +-
 daemon/gpg-agent/gkd-gpg-agent-standalone.c        |    2 +-
 daemon/ssh-agent/gkd-ssh-agent-standalone.c        |    2 +-
 egg/Makefile.am                                    |   22 +-
 egg/egg-armor.c                                    |   44 +-
 egg/egg-armor.h                                    |   11 +-
 egg/egg-asn1-defs.c                                |   33 +
 egg/egg-asn1-defs.h                                |   12 +-
 egg/egg-asn1x.c                                    | 1162 ++++++++++++-------
 egg/egg-asn1x.h                                    |  122 ++-
 egg/egg-bytes.c                                    |  454 ++++++++
 egg/egg-bytes.h                                    |  102 ++
 egg/egg-dn.c                                       |  167 +++-
 egg/egg-dn.h                                       |   12 +-
 egg/egg-openssl.c                                  |  147 ++--
 egg/egg-openssl.h                                  |   20 +-
 egg/egg-secure-memory.c                            |  184 ++--
 egg/egg-secure-memory.h                            |   38 +-
 egg/egg-symkey.c                                   |  489 ++++----
 egg/egg-symkey.h                                   |   62 +-
 egg/egg-testing.h                                  |    7 +
 egg/tests/Makefile.am                              |   16 +-
 egg/tests/test-asn1.c                              |  566 ++++++----
 egg/tests/test-asn1x.c                             |   21 +-
 egg/tests/test-dh.c                                |    2 +-
 egg/tests/test-dn.c                                |   66 +-
 egg/tests/test-hkdf.c                              |    2 +-
 egg/tests/test-openssl.c                           |   71 +-
 egg/tests/test-secmem.c                            |    2 +-
 egg/tests/test-symkey.c                            |    9 +-
 egg/tests/test.asn                                 |    2 +
 pam/gkr-pam-stubs.c                                |    8 +-
 pkcs11/gkm/Makefile.am                             |   14 +-
 pkcs11/gkm/gkm-attributes.c                        |    7 +
 pkcs11/gkm/gkm-attributes.h                        |    5 +
 pkcs11/gkm/gkm-certificate.c                       |  110 +-
 pkcs11/gkm/gkm-certificate.h                       |    5 +-
 pkcs11/gkm/gkm-data-asn1.c                         |   14 +-
 pkcs11/gkm/gkm-data-der.c                          |  328 +++---
 pkcs11/gkm/gkm-data-der.h                          |   69 +-
 pkcs11/gkm/gkm-serializable.c                      |   11 +-
 pkcs11/gkm/gkm-serializable.h                      |   18 +-
 pkcs11/gkm/pk.asn                                  |  103 --
 pkcs11/gkm/pkix.asn                                | 1230 --------------------
 pkcs11/gkm/tests/Makefile.am                       |   17 +-
 pkcs11/gkm/tests/mock-module.c                     |    2 +-
 pkcs11/gkm/tests/test-certificate.c                |   19 +-
 pkcs11/gkm/tests/test-data-asn1.c                  |   27 +-
 pkcs11/gkm/tests/test-data-der.c                   |  206 ++--
 pkcs11/gkm/tests/test-secret.c                     |    2 +-
 pkcs11/gkm/tests/test-sexp.c                       |    2 +-
 pkcs11/gnome2-store/gkm-gnome2-private-key.c       |   52 +-
 pkcs11/gnome2-store/gkm-gnome2-public-key.c        |   19 +-
 pkcs11/gnome2-store/gkm-gnome2-standalone.c        |    2 +-
 pkcs11/gnome2-store/gkm-gnome2-storage.c           |   52 +-
 pkcs11/gnome2-store/tests/check-gnome2-module.c    |    2 +-
 pkcs11/gnome2-store/tests/frob-gnome2-file.c       |    2 +-
 pkcs11/gnome2-store/tests/mock-gnome2-module.c     |    2 +-
 pkcs11/gnome2-store/tests/test-gnome2-file.c       |    2 +-
 .../gnome2-store/tests/test-gnome2-private-key.c   |   32 +-
 pkcs11/gnome2-store/tests/test-gnome2-storage.c    |    8 +-
 pkcs11/roots-store/gkm-roots-module.c              |   28 +-
 pkcs11/roots-store/gkm-roots-standalone.c          |    2 +-
 pkcs11/roots-store/gkm-roots-trust.c               |    9 +-
 pkcs11/roots-store/tests/check-roots-module.c      |    2 +-
 pkcs11/secret-store/gkm-secret-standalone.c        |    2 +-
 pkcs11/secret-store/tests/dump-keyring0-format.c   |    2 +-
 pkcs11/secret-store/tests/mock-secret-module.c     |    2 +-
 pkcs11/secret-store/tests/test-secret-data.c       |    2 +-
 pkcs11/ssh-store/gkm-ssh-openssh.c                 |   56 +-
 pkcs11/ssh-store/gkm-ssh-openssh.h                 |    8 +-
 pkcs11/ssh-store/gkm-ssh-private-key.c             |   30 +-
 pkcs11/ssh-store/gkm-ssh-standalone.c              |    2 +-
 pkcs11/ssh-store/tests/check-ssh-module.c          |    2 +-
 pkcs11/ssh-store/tests/mock-ssh-module.c           |    2 +-
 pkcs11/ssh-store/tests/test-ssh-openssh.c          |    9 +-
 pkcs11/wrap-layer/tests/mock-secret-store.c        |    2 +-
 pkcs11/xdg-store/Makefile.am                       |   18 +-
 pkcs11/xdg-store/gkm-xdg-asn1-defs.c               |   32 +
 pkcs11/xdg-store/gkm-xdg-asn1-defs.h               |   31 +
 pkcs11/xdg-store/gkm-xdg-module.c                  |   35 +-
 pkcs11/xdg-store/gkm-xdg-standalone.c              |    2 +-
 pkcs11/xdg-store/gkm-xdg-trust.c                   |  200 ++--
 pkcs11/xdg-store/tests/check-xdg-module.c          |    2 +-
 pkcs11/xdg-store/tests/dump-trust-file.c           |   43 +-
 pkcs11/xdg-store/tests/frob-trust-file.c           |   74 +-
 pkcs11/xdg-store/tests/mock-xdg-module.c           |    2 +-
 93 files changed, 3534 insertions(+), 3327 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 0a6df42..eecb8d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 *.la
 *.lo
 *.a
+*.asn.h
 *.bak
 *.Po
 *.Plo
diff --git a/Makefile.decl b/Makefile.decl
index 96900ec..cfbf716 100644
--- a/Makefile.decl
+++ b/Makefile.decl
@@ -1,5 +1,30 @@
 NULL =
 
+TEST_ARGS =
+
+TEST_SUPPRESSIONS = $(top_builddir)/build/valgrind-suppressions
+
+perform-memcheck: $(TEST_PROGS)
+	make -C $(top_builddir)/build all
+	@for test in $(TEST_PROGS); do \
+		G_SLICE=always-malloc libtool --mode=execute \
+			valgrind --trace-children=no --gen-suppressions=all \
+			--suppressions=$(TEST_SUPPRESSIONS) \
+			--leak-check=full --show-reachable=yes --num-callers=16 \
+			--quiet --error-exitcode=3 \
+			$(builddir)/$$test $(TEST_ARGS) || exit 3; \
+	done
+
+coverage:
+	mkdir -p $(top_builddir)/build/coverage
+	$(LCOV) --directory . --capture --output-file $(top_builddir)/build/coverage.info
+	$(GENHTML) --output-directory $(top_builddir)/build/coverage $(top_builddir)/build/coverage.info
+	$(LCOV) --directory . --zerocounters
+	@echo "file://$(abs_top_builddir)/build/coverage/index.html"
+
+clear-coverage:
+	$(LCOV) --directory . --zerocounters
+
 V_ASN1 = $(V_ASN1_$(V))
 V_ASN1_ = $(V_ASN1_$(AM_DEFAULT_VERBOSITY))
 V_ASN1_0 = @echo "  ASN1  " $@;
@@ -40,4 +65,3 @@ SED_SUBST = sed \
 	$(V_SED) $(SED_SUBST) $< > $@
 
 SUFFIXES = .asn .asn.h .conf .conf.in .desktop.in .desktop.in.in .service .service.in
-
diff --git a/daemon/control/tests/frob-control-change.c b/daemon/control/tests/frob-control-change.c
index 9b9c9ba..2fa6b4c 100644
--- a/daemon/control/tests/frob-control-change.c
+++ b/daemon/control/tests/frob-control-change.c
@@ -6,7 +6,7 @@
 #include <pwd.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 int
 main (int argc, char *argv[])
diff --git a/daemon/control/tests/frob-control-init.c b/daemon/control/tests/frob-control-init.c
index 3e83d03..88149be 100644
--- a/daemon/control/tests/frob-control-init.c
+++ b/daemon/control/tests/frob-control-init.c
@@ -7,7 +7,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 int
 main (int argc, char *argv[])
diff --git a/daemon/control/tests/frob-control-quit.c b/daemon/control/tests/frob-control-quit.c
index bf73a4e..66261d7 100644
--- a/daemon/control/tests/frob-control-quit.c
+++ b/daemon/control/tests/frob-control-quit.c
@@ -7,7 +7,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 int
 main (int argc, char *argv[])
diff --git a/daemon/control/tests/frob-control-unlock.c b/daemon/control/tests/frob-control-unlock.c
index b361066..6a44801 100644
--- a/daemon/control/tests/frob-control-unlock.c
+++ b/daemon/control/tests/frob-control-unlock.c
@@ -6,7 +6,7 @@
 #include <pwd.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 int
 main (int argc, char *argv[])
diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c
index e9f4392..9ff675f 100644
--- a/daemon/gkd-main.c
+++ b/daemon/gkd-main.c
@@ -206,19 +206,19 @@ static gboolean do_warning = TRUE;
 
 G_LOCK_DEFINE_STATIC (memory_mutex);
 
-void
+static void
 egg_memory_lock (void)
 {
 	G_LOCK (memory_mutex);
 }
 
-void
+static void
 egg_memory_unlock (void)
 {
 	G_UNLOCK (memory_mutex);
 }
 
-void*
+static void *
 egg_memory_fallback (void *p, size_t sz)
 {
 	const gchar *env;
@@ -254,6 +254,8 @@ egg_memory_fallback (void *p, size_t sz)
 	return g_realloc (p, sz);
 }
 
+EGG_SECURE_DEFINE_GLOBALS (egg_memory_lock, egg_memory_unlock, egg_memory_fallback);
+
 /* -----------------------------------------------------------------------------
  * LOGS
  */
diff --git a/daemon/gpg-agent/gkd-gpg-agent-standalone.c b/daemon/gpg-agent/gkd-gpg-agent-standalone.c
index a9a1c99..48220b1 100644
--- a/daemon/gpg-agent/gkd-gpg-agent-standalone.c
+++ b/daemon/gpg-agent/gkd-gpg-agent-standalone.c
@@ -36,7 +36,7 @@
 #include <string.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static gboolean
 accept_client (GIOChannel *channel, GIOCondition cond, gpointer unused)
diff --git a/daemon/ssh-agent/gkd-ssh-agent-standalone.c b/daemon/ssh-agent/gkd-ssh-agent-standalone.c
index a496a36..f5f3dc0 100644
--- a/daemon/ssh-agent/gkd-ssh-agent-standalone.c
+++ b/daemon/ssh-agent/gkd-ssh-agent-standalone.c
@@ -37,7 +37,7 @@
 #include <string.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static gboolean
 accept_client (GIOChannel *channel, GIOCondition cond, gpointer unused)
diff --git a/egg/Makefile.am b/egg/Makefile.am
index f067d05..f024ae0 100644
--- a/egg/Makefile.am
+++ b/egg/Makefile.am
@@ -1,3 +1,4 @@
+include $(top_srcdir)/Makefile.decl
 
 noinst_LTLIBRARIES = \
 	libegg.la \
@@ -11,8 +12,14 @@ noinst_LTLIBRARIES = \
 	libegg-hex.la \
 	libegg-test.la
 
+ASN_FILES = \
+	pk.asn \
+	pkix.asn
+
+ASN_SRCS = $(ASN_FILES:.asn=.asn.h)
+
 BUILT_SOURCES = \
-	asn1-def-pk.c asn1-def-pkix.c
+	$(ASN_SRCS)
 
 INCLUDES = \
 	-I$(top_srcdir) \
@@ -26,8 +33,10 @@ libegg_la_SOURCES = \
 	dotlock.c dotlock.h \
 	egg-armor.c egg-armor.h \
 	egg-asn1x.c egg-asn1x.h \
+	egg-asn1-defs.c egg-asn1-defs.h \
 	egg-buffer.c egg-buffer.h \
 	egg-byte-array.c egg-byte-array.h \
+	egg-bytes.c egg-bytes.h \
 	egg-cleanup.c egg-cleanup.h \
 	egg-dh.c egg-dh.h \
 	egg-dn.c egg-dn.h \
@@ -48,15 +57,8 @@ libegg_la_SOURCES = \
 	egg-asn1-defs.h \
 	$(BUILT_SOURCES)
 
-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 \
-	pk.asn
+	$(ASN_FILES)
 
 DISTCLEANFILES = \
 	$(BUILT_SOURCES)
@@ -66,6 +68,8 @@ DISTCLEANFILES = \
 
 libegg_asn1x_la_SOURCES = \
 	egg-asn1x.c egg-asn1x.h \
+	egg-asn1-defs.c egg-asn1-defs.h \
+	egg-bytes.c egg-bytes.h \
 	$(BUILT_SOURCES)
 
 libegg_asn1x_la_CFLAGS = \
diff --git a/egg/egg-armor.c b/egg/egg-armor.c
index 5a4b047..473e42e 100644
--- a/egg/egg-armor.c
+++ b/egg/egg-armor.c
@@ -162,14 +162,14 @@ armor_find_end (const gchar *data,
 	/* Next comes the type string */
 	stype = g_quark_to_string (type);
 	n_type = strlen (stype);
-	if (strncmp ((gchar*)data, stype, n_type) != 0)
+	if (n_type > n_data || strncmp ((gchar*)data, stype, n_type) != 0)
 		return NULL;
 
 	n_data -= n_type;
 	data += n_type;
 
 	/* Next comes the suffix */
-	if (strncmp ((gchar*)data, ARMOR_SUFF, ARMOR_SUFF_L) != 0)
+	if (ARMOR_SUFF_L > n_data && strncmp ((gchar*)data, ARMOR_SUFF, ARMOR_SUFF_L) != 0)
 		return NULL;
 
 	/*
@@ -269,48 +269,52 @@ egg_armor_headers_new (void)
 }
 
 guint
-egg_armor_parse (gconstpointer data,
-                 gsize n_data,
+egg_armor_parse (EggBytes *data,
                  EggArmorCallback callback,
                  gpointer user_data)
 {
-	const gchar *beg, *end;
+	const gchar *beg, *end, *at;
 	const gchar *outer_beg, *outer_end;
 	guint nfound = 0;
 	guchar *decoded = NULL;
 	gsize n_decoded = 0;
 	GHashTable *headers = NULL;
+	EggBytes *dec;
+	EggBytes *outer;
 	GQuark type;
+	gsize n_at;
 
-	g_return_val_if_fail (data, 0);
-	g_return_val_if_fail (n_data, 0);
+	g_return_val_if_fail (data != NULL, 0);
+	at = egg_bytes_get_data (data);
+	n_at = egg_bytes_get_size (data);
 
-	while (n_data > 0) {
+	while (n_at > 0) {
 
 		/* This returns the first character after the PEM BEGIN header */
-		beg = armor_find_begin ((const gchar*)data, n_data, &type, &outer_beg);
+		beg = armor_find_begin (at, n_at, &type, &outer_beg);
 		if (beg == NULL)
 			break;
 
 		g_assert (type);
 
 		/* This returns the character position before the PEM END header */
-		end = armor_find_end ((const gchar*)beg,
-		                      n_data - ((const gchar*)beg - (const gchar *)data),
-		                      type, &outer_end);
+		end = armor_find_end (beg, n_at - (beg - at), type, &outer_end);
 		if (end == NULL)
 			break;
 
 		if (beg != end) {
 			if (armor_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) {
 				g_assert (outer_end > outer_beg);
-				if (callback != NULL)
-					(callback) (type,
-					            decoded, n_decoded,
-					            outer_beg, outer_end - outer_beg,
-					            headers, user_data);
+				dec = egg_bytes_new_with_free_func (decoded, n_decoded,
+				                                    egg_secure_free, decoded);
+				if (callback != NULL) {
+					outer = egg_bytes_new_with_free_func (outer_beg, outer_end - outer_beg,
+					                                      egg_bytes_unref, egg_bytes_ref (data));
+					(callback) (type, dec, outer, headers, user_data);
+					egg_bytes_unref (outer);
+				}
+				egg_bytes_unref (dec);
 				++nfound;
-				egg_secure_free (decoded);
 				if (headers)
 					g_hash_table_remove_all (headers);
 			}
@@ -318,8 +322,8 @@ egg_armor_parse (gconstpointer data,
 
 		/* Try for another block */
 		end += ARMOR_SUFF_L;
-		n_data -= (const gchar*)end - (const gchar*)data;
-		data = end;
+		n_at -= (const gchar*)end - (const gchar*)at;
+		at = end;
 	}
 
 	if (headers)
diff --git a/egg/egg-armor.h b/egg/egg-armor.h
index e0f13d3..586a0d2 100644
--- a/egg/egg-armor.h
+++ b/egg/egg-armor.h
@@ -26,18 +26,17 @@
 
 #include <glib.h>
 
+#include <egg/egg-bytes.h>
+
 typedef void (*EggArmorCallback) (GQuark type,
-                                  const guchar *data,
-                                  gsize n_data,
-                                  const gchar *outer,
-                                  gsize n_outer,
+                                  EggBytes *data,
+                                  EggBytes *outer,
                                   GHashTable *headers,
                                   gpointer user_data);
 
 GHashTable*      egg_armor_headers_new   (void);
 
-guint            egg_armor_parse         (gconstpointer data,
-                                          gsize n_data,
+guint            egg_armor_parse         (EggBytes *data,
                                           EggArmorCallback callback,
                                           gpointer user_data);
 
diff --git a/egg/egg-asn1-defs.c b/egg/egg-asn1-defs.c
new file mode 100644
index 0000000..8295ec0
--- /dev/null
+++ b/egg/egg-asn1-defs.c
@@ -0,0 +1,33 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-asn1-defs.c - ASN.1 definitions
+
+   Copyright (C) 2011 Collabora Ltd.
+
+   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 <stefw collabora co uk>
+*/
+
+#include "config.h"
+
+#include "egg-asn1-defs.h"
+
+#include <stdlib.h>
+
+typedef struct _EggAsn1xDef ASN1_ARRAY_TYPE;
+
+#include "pk.asn.h"
+#include "pkix.asn.h"
diff --git a/egg/egg-asn1-defs.h b/egg/egg-asn1-defs.h
index 02fe427..ec47287 100644
--- a/egg/egg-asn1-defs.h
+++ b/egg/egg-asn1-defs.h
@@ -24,9 +24,13 @@
 #ifndef EGG_ASN1_DEFS_H_
 #define EGG_ASN1_DEFS_H_
 
-#include <libtasn1.h>
+struct _EggAsn1xDef {
+	const char *name;
+	unsigned int type;
+	const void *value;
+};
 
-extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
-extern const ASN1_ARRAY_TYPE pk_asn1_tab[];
+extern const struct _EggAsn1xDef pkix_asn1_tab[];
+extern const struct _EggAsn1xDef pk_asn1_tab[];
 
-#endif /*EGG_ASN1_DEFS_H_*/
+#endif /* EGG_ASN1_DEFS_H_ */
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index f2d4b42..c940a54 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -48,38 +48,35 @@
 #include "config.h"
 
 #include "egg-asn1x.h"
+#include "egg-asn1-defs.h"
 #include "egg-timegm.h"
 
-#include <libtasn1.h>
-
 #include <stdlib.h>
 #include <string.h>
 
+/* From libtasn1's libtasn.h */
+
+#define ASN1_CLASS_UNIVERSAL		0x00
+#define ASN1_CLASS_APPLICATION		0x40
+#define ASN1_CLASS_CONTEXT_SPECIFIC	0x80
+#define ASN1_CLASS_PRIVATE		0xC0
+#define ASN1_CLASS_STRUCTURED		0x20
+
+#define ASN1_TAG_BOOLEAN		0x01
+#define ASN1_TAG_INTEGER		0x02
+#define ASN1_TAG_SEQUENCE		0x10
+#define ASN1_TAG_SET			0x11
+#define ASN1_TAG_OCTET_STRING		0x04
+#define ASN1_TAG_BIT_STRING		0x03
+#define ASN1_TAG_UTCTime		0x17
+#define ASN1_TAG_GENERALIZEDTime	0x18
+#define ASN1_TAG_OBJECT_ID		0x06
+#define ASN1_TAG_ENUMERATED		0x0A
+#define ASN1_TAG_NULL			0x05
+#define ASN1_TAG_GENERALSTRING		0x1B
+
+
 /* From libtasn1's int.h */
-enum {
-	TYPE_CONSTANT = 1,
-	TYPE_IDENTIFIER = 2,
-	TYPE_INTEGER = 3,
-	TYPE_BOOLEAN = 4,
-	TYPE_SEQUENCE = 5,
-	TYPE_BIT_STRING = 6,
-	TYPE_OCTET_STRING = 7,
-	TYPE_TAG = 8,
-	TYPE_DEFAULT = 9,
-	TYPE_SIZE = 10,
-	TYPE_SEQUENCE_OF = 11,
-	TYPE_OBJECT_ID = 12,
-	TYPE_ANY = 13,
-	TYPE_SET = 14,
-	TYPE_SET_OF = 15,
-	TYPE_DEFINITIONS = 16,
-	TYPE_TIME = 17,
-	TYPE_CHOICE = 18,
-	TYPE_IMPORTS = 19,
-	TYPE_NULL = 20,
-	TYPE_ENUMERATED = 21,
-	TYPE_GENERALSTRING = 27
-};
 
 enum {
 	FLAG_UNIVERSAL = (1<<8),
@@ -107,6 +104,11 @@ enum {
 	FLAG_RIGHT = (1<<30),
 };
 
+typedef gboolean (*Aencoder) (gpointer data,
+                              GNode *node,
+                              guchar *buf,
+                              gsize n_buf);
+
 typedef struct _Aenc Aenc;
 typedef struct _Atlv Atlv;
 typedef struct _Anode Anode;
@@ -114,8 +116,9 @@ typedef struct _Abuf Abuf;
 typedef struct _Abits Abits;
 
 struct _Aenc {
-	EggAsn1xEncoder encoder;
+	Aencoder encoder;
 	gpointer data;
+	GDestroyNotify destroy;
 };
 
 struct _Atlv {
@@ -129,16 +132,14 @@ struct _Atlv {
 };
 
 struct _Anode {
-	const ASN1_ARRAY_TYPE *def;
-	const ASN1_ARRAY_TYPE *join;
+	const EggAsn1xDef *def;
+	const EggAsn1xDef *join;
 	GList *opts;
 
 	Atlv *tlv;
 	Aenc *enc;
 
-	gpointer user_data;
-	GDestroyNotify destroy;
-
+	EggBytes *backing;
 	gchar* failure;
 
 	gint chosen : 1;
@@ -152,13 +153,12 @@ struct _Abuf {
 
 struct _Abits {
 	guint n_bits;
-	guchar *bits;
-	GDestroyNotify destroy;
+	EggBytes *bits;
 };
 
 /* Forward Declarations */
-static gboolean anode_decode_anything (GNode*, Atlv*);
-static gboolean anode_decode_anything_for_flags (GNode *, Atlv*, gint);
+static gboolean anode_decode_anything (GNode*, EggBytes*, Atlv*);
+static gboolean anode_decode_anything_for_flags (GNode *, EggBytes*, Atlv*, gint);
 static gboolean anode_validate_anything (GNode*, gboolean);
 static gboolean anode_encode_prepare (GNode*, gboolean want);
 
@@ -176,7 +176,7 @@ atoin (const char *p, gint digits)
 }
 
 static GNode*
-anode_new (const ASN1_ARRAY_TYPE *def)
+anode_new (const EggAsn1xDef *def)
 {
 	Anode *an = g_slice_new0 (Anode);
 	an->def = def;
@@ -212,30 +212,30 @@ static gboolean
 anode_def_type_is_real (GNode *node)
 {
 	switch (anode_def_type (node)) {
-	case TYPE_INTEGER:
-	case TYPE_BOOLEAN:
-	case TYPE_BIT_STRING:
-	case TYPE_OCTET_STRING:
-	case TYPE_OBJECT_ID:
-	case TYPE_TIME:
-	case TYPE_NULL:
-	case TYPE_ENUMERATED:
-	case TYPE_GENERALSTRING:
+	case EGG_ASN1X_INTEGER:
+	case EGG_ASN1X_BOOLEAN:
+	case EGG_ASN1X_BIT_STRING:
+	case EGG_ASN1X_OCTET_STRING:
+	case EGG_ASN1X_OBJECT_ID:
+	case EGG_ASN1X_TIME:
+	case EGG_ASN1X_NULL:
+	case EGG_ASN1X_ENUMERATED:
+	case EGG_ASN1X_GENERALSTRING:
 		return TRUE;
-	case TYPE_SEQUENCE:
-	case TYPE_SEQUENCE_OF:
-	case TYPE_ANY:
-	case TYPE_SET:
-	case TYPE_SET_OF:
-	case TYPE_CHOICE:
+	case EGG_ASN1X_SEQUENCE:
+	case EGG_ASN1X_SEQUENCE_OF:
+	case EGG_ASN1X_ANY:
+	case EGG_ASN1X_SET:
+	case EGG_ASN1X_SET_OF:
+	case EGG_ASN1X_CHOICE:
 		return TRUE;
-	case TYPE_CONSTANT:
-	case TYPE_IDENTIFIER:
-	case TYPE_TAG:
-	case TYPE_DEFAULT:
-	case TYPE_SIZE:
-	case TYPE_DEFINITIONS:
-	case TYPE_IMPORTS:
+	case EGG_ASN1X_CONSTANT:
+	case EGG_ASN1X_IDENTIFIER:
+	case EGG_ASN1X_TAG:
+	case EGG_ASN1X_DEFAULT:
+	case EGG_ASN1X_SIZE:
+	case EGG_ASN1X_DEFINITIONS:
+	case EGG_ASN1X_IMPORTS:
 		return FALSE;
 	default:
 		g_return_val_if_reached (FALSE);
@@ -267,7 +267,7 @@ anode_def_value (GNode *node)
 }
 
 static gulong
-anode_def_value_as_ulong (const ASN1_ARRAY_TYPE *def)
+anode_def_value_as_ulong (const EggAsn1xDef *def)
 {
 	gchar *end = NULL;
 	gulong lval;
@@ -292,17 +292,20 @@ anode_child_with_name (GNode *node, const gchar *name)
 }
 
 static void
-anode_opt_add (GNode *node, const ASN1_ARRAY_TYPE *def)
+anode_opt_add (GNode *node,
+               const EggAsn1xDef *def)
 {
 	Anode *an = node->data;
 	an->opts = g_list_append (an->opts, (gpointer)def);
 }
 
-static ASN1_ARRAY_TYPE*
-anode_opt_lookup (GNode *node, gint type, const gchar *name)
+static EggAsn1xDef *
+anode_opt_lookup (GNode *node,
+                  gint type,
+                  const gchar *name)
 {
 	Anode *an = node->data;
-	ASN1_ARRAY_TYPE* def;
+	EggAsn1xDef *def;
 	GList *l;
 
 	for (l = an->opts; l; l = g_list_next (l)) {
@@ -316,11 +319,13 @@ anode_opt_lookup (GNode *node, gint type, const gchar *name)
 	return NULL;
 }
 
-static ASN1_ARRAY_TYPE*
-anode_opt_lookup_value (GNode *node, gint type, const gchar *value)
+static EggAsn1xDef *
+anode_opt_lookup_value (GNode *node,
+                        gint type,
+                        const gchar *value)
 {
 	Anode *an = node->data;
-	ASN1_ARRAY_TYPE* def;
+	EggAsn1xDef *def;
 	GList *l;
 
 	for (l = an->opts; l; l = g_list_next (l)) {
@@ -338,7 +343,7 @@ static GList*
 anode_opts_lookup (GNode *node, gint type, const gchar *name)
 {
 	Anode *an = node->data;
-	ASN1_ARRAY_TYPE* def;
+	EggAsn1xDef *def;
 	GList *l, *res = NULL;
 
 	for (l = an->opts; l; l = g_list_next (l)) {
@@ -367,17 +372,48 @@ compare_tlvs (Atlv *tlva, Atlv *tlvb)
 	return la < lb ? -1 : 1;
 }
 
+static inline EggBytes *
+anode_get_backing (GNode *node)
+{
+	Anode *an = node->data;
+	return an->backing;
+}
+
+static inline void
+anode_clr_backing (GNode *node)
+{
+	Anode *an = node->data;
+	if (an->backing)
+		egg_bytes_unref (an->backing);
+	an->backing = NULL;
+}
+
+static inline void
+anode_set_backing (GNode *node,
+                   EggBytes *backing)
+{
+	Anode *an = node->data;
+	if (backing)
+		egg_bytes_ref (backing);
+	if (an->backing)
+		egg_bytes_unref (an->backing);
+	an->backing = backing;
+}
+
 static void
-anode_set_tlv_data (GNode *node, Atlv *tlv)
+anode_set_tlv_data (GNode *node,
+                    EggBytes *backing,
+                    Atlv *tlv)
 {
 	Anode *an = node->data;
-	g_assert (!an->tlv);
+	g_assert (an->tlv == NULL);
 	g_assert (tlv->len >= 0);
+	anode_set_backing (node, backing);
 	an->tlv = g_slice_new0 (Atlv);
 	memcpy (an->tlv, tlv, sizeof (Atlv));
 }
 
-static Atlv*
+static inline Atlv *
 anode_get_tlv_data (GNode *node)
 {
 	Anode *an = node->data;
@@ -398,31 +434,26 @@ anode_clr_enc_data (GNode *node)
 {
 	Anode *an = node->data;
 	if (an->enc) {
+		if (an->enc->destroy)
+			(an->enc->destroy) (an->enc->data);
 		g_slice_free (Aenc, an->enc);
 		an->enc = NULL;
 	}
 }
 
 static void
-anode_set_enc_data (GNode *node, EggAsn1xEncoder encoder, gpointer enc_data)
+anode_set_enc_data (GNode *node,
+                    Aencoder encoder,
+                    gpointer data,
+                    GDestroyNotify destroy)
 {
 	Anode *an = node->data;
 	g_assert (!an->enc);
 	an->enc = g_slice_new0 (Aenc);
 	an->enc->encoder = encoder;
-	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;
+	an->enc->data = data;
+	an->enc->destroy = destroy;
+	anode_clr_backing (node);
 }
 
 static Aenc*
@@ -462,9 +493,9 @@ static void
 anode_clear (GNode *node)
 {
 	Anode *an = node->data;
+	anode_clr_backing (node);
 	anode_clr_tlv_data (node);
 	anode_clr_enc_data (node);
-	anode_set_user_data (node, NULL, NULL);
 	g_free (an->failure);
 	an->failure = NULL;
 }
@@ -483,9 +514,9 @@ static void
 abits_destroy (gpointer data)
 {
 	Abits *ab = data;
-	g_assert (ab);
-	if (ab->destroy)
-		(ab->destroy) (ab->bits);
+	g_assert (ab != NULL);
+	if (ab->bits)
+		egg_bytes_unref (ab->bits);
 	g_slice_free (Abits, ab);
 }
 
@@ -501,60 +532,60 @@ anode_destroy (GNode *node)
 static gulong
 anode_calc_tag_for_flags (GNode *node, gint flags)
 {
-	ASN1_ARRAY_TYPE *def;
+	EggAsn1xDef *def;
 
 	/* A context specific tag */
 	if (flags & FLAG_TAG) {
-		def = anode_opt_lookup (node, TYPE_TAG, NULL);
+		def = anode_opt_lookup (node, EGG_ASN1X_TAG, NULL);
 		g_return_val_if_fail (def, G_MAXULONG);
 		return anode_def_value_as_ulong (def);
 	}
 
 	/* A tag from the universal set */
 	switch (anode_def_type (node)) {
-	case TYPE_INTEGER:
+	case EGG_ASN1X_INTEGER:
 		return ASN1_TAG_INTEGER;
-	case TYPE_ENUMERATED:
+	case EGG_ASN1X_ENUMERATED:
 		return ASN1_TAG_ENUMERATED;
-	case TYPE_BOOLEAN:
+	case EGG_ASN1X_BOOLEAN:
 		return ASN1_TAG_BOOLEAN;
-	case TYPE_BIT_STRING:
+	case EGG_ASN1X_BIT_STRING:
 		return ASN1_TAG_BIT_STRING;
-	case TYPE_OCTET_STRING:
+	case EGG_ASN1X_OCTET_STRING:
 		return ASN1_TAG_OCTET_STRING;
-	case TYPE_OBJECT_ID:
+	case EGG_ASN1X_OBJECT_ID:
 		return ASN1_TAG_OBJECT_ID;
-	case TYPE_NULL:
+	case EGG_ASN1X_NULL:
 		return ASN1_TAG_NULL;
-	case TYPE_GENERALSTRING:
+	case EGG_ASN1X_GENERALSTRING:
 		return ASN1_TAG_GENERALSTRING;
-	case TYPE_TIME:
+	case EGG_ASN1X_TIME:
 		if (flags & FLAG_GENERALIZED)
 			return ASN1_TAG_GENERALIZEDTime;
 		else if (flags & FLAG_UTC)
 			return ASN1_TAG_UTCTime;
 		else
 			g_return_val_if_reached (G_MAXULONG);
-	case TYPE_SEQUENCE:
-	case TYPE_SEQUENCE_OF:
+	case EGG_ASN1X_SEQUENCE:
+	case EGG_ASN1X_SEQUENCE_OF:
 		return ASN1_TAG_SEQUENCE;
-	case TYPE_SET:
-	case TYPE_SET_OF:
+	case EGG_ASN1X_SET:
+	case EGG_ASN1X_SET_OF:
 		return ASN1_TAG_SET;
 
 	/* These should be handled specially */
-	case TYPE_ANY:
-	case TYPE_CHOICE:
+	case EGG_ASN1X_ANY:
+	case EGG_ASN1X_CHOICE:
 		return G_MAXULONG;
 
 	/* These are not real nodes */
-	case TYPE_CONSTANT:
-	case TYPE_IDENTIFIER:
-	case TYPE_TAG:
-	case TYPE_DEFAULT:
-	case TYPE_SIZE:
-	case TYPE_DEFINITIONS:
-	case TYPE_IMPORTS:
+	case EGG_ASN1X_CONSTANT:
+	case EGG_ASN1X_IDENTIFIER:
+	case EGG_ASN1X_TAG:
+	case EGG_ASN1X_DEFAULT:
+	case EGG_ASN1X_SIZE:
+	case EGG_ASN1X_DEFINITIONS:
+	case EGG_ASN1X_IMPORTS:
 		g_return_val_if_reached (G_MAXULONG);
 
 	/* Unknown value */
@@ -570,22 +601,35 @@ anode_calc_tag (GNode *node)
 }
 
 static gboolean
-anode_calc_explicit_for_flags (GNode *node, gint flags)
+anode_calc_explicit_for_flags (GNode *node,
+                               gint flags,
+                               guchar *cls_type)
 {
-	const ASN1_ARRAY_TYPE *opt;
+	const EggAsn1xDef *opt;
 	if ((flags & FLAG_TAG) != FLAG_TAG)
 		return FALSE;
-	opt = anode_opt_lookup (node, TYPE_TAG, NULL);
+	opt = anode_opt_lookup (node, EGG_ASN1X_TAG, NULL);
 	g_return_val_if_fail (opt, FALSE);
+	if (cls_type) {
+		if (opt->type & FLAG_UNIVERSAL)
+			*cls_type = ASN1_CLASS_UNIVERSAL;
+		else if (opt->type & FLAG_APPLICATION)
+			*cls_type = ASN1_CLASS_APPLICATION;
+		else if (opt->type & FLAG_PRIVATE)
+			*cls_type = ASN1_CLASS_PRIVATE;
+		else
+			*cls_type = ASN1_CLASS_CONTEXT_SPECIFIC;
+	}
 	if ((opt->type & FLAG_IMPLICIT) == FLAG_IMPLICIT)
 		return FALSE;
 	return TRUE;
 }
 
 static gboolean
-anode_calc_explicit (GNode *node)
+anode_calc_explicit (GNode *node,
+                     guchar *cls_type)
 {
-	return anode_calc_explicit_for_flags (node, anode_def_flags (node));
+	return anode_calc_explicit_for_flags (node, anode_def_flags (node), cls_type);
 }
 
 /* -------------------------------------------------------------------------
@@ -826,7 +870,9 @@ anode_decode_tlv_for_contents (Atlv *outer, gboolean first, Atlv *tlv)
 }
 
 static gboolean
-anode_decode_choice (GNode *node, Atlv *tlv)
+anode_decode_choice (GNode *node,
+                     EggBytes *backing,
+                     Atlv *tlv)
 {
 	gboolean have = FALSE;
 	GNode *child;
@@ -834,7 +880,7 @@ anode_decode_choice (GNode *node, Atlv *tlv)
 
 	for (child = node->children; child; child = child->next) {
 		an = (Anode*)child->data;
-		if (!have && anode_decode_anything (child, tlv)) {
+		if (!have && anode_decode_anything (child, backing, tlv)) {
 			an->chosen = 1;
 			have = TRUE;
 		} else {
@@ -882,7 +928,9 @@ anode_decode_struct_any (GNode *node, Atlv *tlv)
 }
 
 static gboolean
-anode_decode_sequence_or_set (GNode *node, Atlv *outer)
+anode_decode_sequence_or_set (GNode *node,
+                              EggBytes *backing,
+                              Atlv *outer)
 {
 	GNode *child;
 	Atlv tlv;
@@ -902,7 +950,7 @@ anode_decode_sequence_or_set (GNode *node, Atlv *outer)
 		if (!anode_decode_tlv_for_contents (outer, i == 0, &tlv))
 			return anode_failure (node, "invalid encoding of child");
 
-		if (!anode_decode_anything (child, &tlv))
+		if (!anode_decode_anything (child, backing, &tlv))
 			return FALSE;
 
 		outer->len = (tlv.end - outer->buf) - outer->off;
@@ -913,7 +961,9 @@ anode_decode_sequence_or_set (GNode *node, Atlv *outer)
 }
 
 static gboolean
-anode_decode_sequence_or_set_of (GNode *node, Atlv *outer)
+anode_decode_sequence_or_set_of (GNode *node,
+                                 EggBytes *backing,
+                                 Atlv *outer)
 {
 	GNode *child, *other;
 	Atlv tlv;
@@ -946,7 +996,7 @@ anode_decode_sequence_or_set_of (GNode *node, Atlv *outer)
 			g_node_append (node, other);
 		}
 
-		if (!anode_decode_anything (other, &tlv))
+		if (!anode_decode_anything (other, backing, &tlv))
 			return FALSE;
 
 		outer->len = (tlv.end - outer->buf) - outer->off;
@@ -957,7 +1007,10 @@ anode_decode_sequence_or_set_of (GNode *node, Atlv *outer)
 }
 
 static gboolean
-anode_decode_primitive (GNode *node, Atlv *tlv, gint flags)
+anode_decode_primitive (GNode *node,
+                        EggBytes *backing,
+                        Atlv *tlv,
+                        gint flags)
 {
 	gint type;
 
@@ -969,27 +1022,27 @@ anode_decode_primitive (GNode *node, Atlv *tlv, gint flags)
 	switch (type) {
 
 	/* The primitive value types */
-	case TYPE_INTEGER:
-	case TYPE_ENUMERATED:
-	case TYPE_BOOLEAN:
-	case TYPE_BIT_STRING:
-	case TYPE_OCTET_STRING:
-	case TYPE_OBJECT_ID:
-	case TYPE_NULL:
-	case TYPE_GENERALSTRING:
-	case TYPE_TIME:
-		anode_set_tlv_data (node, tlv);
+	case EGG_ASN1X_INTEGER:
+	case EGG_ASN1X_ENUMERATED:
+	case EGG_ASN1X_BOOLEAN:
+	case EGG_ASN1X_BIT_STRING:
+	case EGG_ASN1X_OCTET_STRING:
+	case EGG_ASN1X_OBJECT_ID:
+	case EGG_ASN1X_NULL:
+	case EGG_ASN1X_GENERALSTRING:
+	case EGG_ASN1X_TIME:
+		anode_set_tlv_data (node, backing, tlv);
 		return TRUE;
 
 	/* Transparent types */
-	case TYPE_ANY:
-		anode_set_tlv_data (node, tlv);
+	case EGG_ASN1X_ANY:
+		anode_set_tlv_data (node, backing, tlv);
 		return TRUE;
 
-	case TYPE_CHOICE:
-		if (!anode_decode_choice (node, tlv))
+	case EGG_ASN1X_CHOICE:
+		if (!anode_decode_choice (node, backing, tlv))
 			return FALSE;
-		anode_set_tlv_data (node, tlv);
+		anode_set_tlv_data (node, backing, tlv);
 		return TRUE;
 
 	default:
@@ -1000,7 +1053,10 @@ anode_decode_primitive (GNode *node, Atlv *tlv, gint flags)
 }
 
 static gboolean
-anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
+anode_decode_structured (GNode *node,
+                         EggBytes *backing,
+                         Atlv *tlv,
+                         gint flags)
 {
 	gboolean definite;
 	const guchar *end;
@@ -1014,13 +1070,13 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 	end = tlv->end;
 
 	/* An explicit, wrapped tag */
-	if (anode_calc_explicit_for_flags (node, flags)) {
+	if (anode_calc_explicit_for_flags (node, flags, NULL)) {
 		if ((tlv->cls & ASN1_CLASS_CONTEXT_SPECIFIC) == 0)
 			return anode_failure (node, "missing context specific tag");
 		if (!anode_decode_tlv_for_contents (tlv, TRUE, &ctlv))
 			return anode_failure (node, "invalid encoding of child");
 		flags &= ~FLAG_TAG;
-		if (!anode_decode_anything_for_flags (node, &ctlv, flags))
+		if (!anode_decode_anything_for_flags (node, backing, &ctlv, flags))
 			return FALSE;
 
 		/* Use most of the child's tlv */
@@ -1034,27 +1090,27 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 	/* Other structured types */
 	} else {
 		switch (anode_def_type (node)) {
-		case TYPE_ANY:
+		case EGG_ASN1X_ANY:
 			if (!anode_decode_struct_any (node, tlv))
 				return FALSE;
 			break;
-		case TYPE_CHOICE:
-			if (!anode_decode_choice (node, tlv))
+		case EGG_ASN1X_CHOICE:
+			if (!anode_decode_choice (node, backing, tlv))
 				return FALSE;
 			break;
-		case TYPE_GENERALSTRING:
-		case TYPE_OCTET_STRING:
+		case EGG_ASN1X_GENERALSTRING:
+		case EGG_ASN1X_OCTET_STRING:
 			if (!anode_decode_struct_string (node, tlv))
 				return FALSE;
 			break;
-		case TYPE_SEQUENCE:
-		case TYPE_SET:
-			if (!anode_decode_sequence_or_set (node, tlv))
+		case EGG_ASN1X_SEQUENCE:
+		case EGG_ASN1X_SET:
+			if (!anode_decode_sequence_or_set (node, backing, tlv))
 				return FALSE;
 			break;
-		case TYPE_SEQUENCE_OF:
-		case TYPE_SET_OF:
-			if (!anode_decode_sequence_or_set_of (node, tlv))
+		case EGG_ASN1X_SEQUENCE_OF:
+		case EGG_ASN1X_SET_OF:
+			if (!anode_decode_sequence_or_set_of (node, backing, tlv))
 				return FALSE;
 			break;
 		default:
@@ -1080,7 +1136,7 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 	g_return_val_if_fail (tlv->buf + tlv->off + tlv->len + off == end, FALSE);
 
 	tlv->end = end;
-	anode_set_tlv_data (node, tlv);
+	anode_set_tlv_data (node, backing, tlv);
 	return TRUE;
 }
 
@@ -1099,7 +1155,10 @@ anode_decode_option_or_default (GNode *node, Atlv *tlv, gint flags)
 }
 
 static gboolean
-anode_decode_anything_for_flags (GNode *node, Atlv *tlv, gint flags)
+anode_decode_anything_for_flags (GNode *node,
+                                 EggBytes *bytes,
+                                 Atlv *tlv,
+                                 gint flags)
 {
 	gboolean ret;
 	gulong tag;
@@ -1119,21 +1178,23 @@ anode_decode_anything_for_flags (GNode *node, Atlv *tlv, gint flags)
 
 	/* Structured value */
 	if (tlv->cls & ASN1_CLASS_STRUCTURED)
-		ret = anode_decode_structured (node, tlv, flags);
+		ret = anode_decode_structured (node, bytes, tlv, flags);
 
 	/* A primitive simple value */
 	else
-		ret = anode_decode_primitive (node, tlv, flags);
+		ret = anode_decode_primitive (node, bytes, tlv, flags);
 
 	return ret;
 }
 
 static gboolean
-anode_decode_anything (GNode *node, Atlv *tlv)
+anode_decode_anything (GNode *node,
+                       EggBytes *bytes,
+                       Atlv *tlv)
 {
 	gint flags = anode_def_flags (node);
 
-	if (!anode_decode_anything_for_flags (node, tlv, flags))
+	if (!anode_decode_anything_for_flags (node, bytes, tlv, flags))
 		return anode_decode_option_or_default (node, tlv, flags);
 
 	return TRUE;
@@ -1141,20 +1202,28 @@ anode_decode_anything (GNode *node, Atlv *tlv)
 
 gboolean
 egg_asn1x_decode_no_validate (GNode *asn,
-                              gconstpointer data,
-                              gsize n_data)
+                              EggBytes *data)
 {
+	const guchar *dat;
+	gsize size;
 	Atlv tlv;
 
+	g_return_val_if_fail (asn != NULL, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
+
 	egg_asn1x_clear (asn);
 
-	if (!anode_decode_tlv_for_data (data, (const guchar*)data + n_data, &tlv))
+	dat = egg_bytes_get_data (data);
+	g_return_val_if_fail (dat != NULL, FALSE);
+
+	size = egg_bytes_get_size (data);
+	if (!anode_decode_tlv_for_data (dat, dat + size, &tlv))
 		return anode_failure (asn, "content is not encoded properly");
 
-	if (!anode_decode_anything (asn, &tlv))
+	if (!anode_decode_anything (asn, data, &tlv))
 		return FALSE;
 
-	if (tlv.end - tlv.buf != n_data)
+	if (tlv.end - tlv.buf != size)
 		return FALSE;
 
 	return TRUE;
@@ -1162,16 +1231,14 @@ egg_asn1x_decode_no_validate (GNode *asn,
 
 gboolean
 egg_asn1x_decode (GNode *asn,
-                  gconstpointer data,
-                  gsize n_data)
+                  EggBytes *data)
 {
 	gboolean ret;
 
-	g_return_val_if_fail (asn, FALSE);
-	g_return_val_if_fail (data, FALSE);
-	g_return_val_if_fail (n_data, FALSE);
+	g_return_val_if_fail (asn != NULL, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	ret = egg_asn1x_decode_no_validate (asn, data, n_data);
+	ret = egg_asn1x_decode_no_validate (asn, data);
 	if (!ret)
 		return ret;
 
@@ -1255,10 +1322,14 @@ anode_encode_cls_tag_len (guchar *data, gsize n_data, guchar cls,
 }
 
 static void
-anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
-                          gpointer user_data, GDestroyNotify destroy)
+anode_encode_tlv_and_enc (GNode *node,
+                          gsize n_data,
+                          Aencoder encoder,
+                          gpointer user_data,
+                          GDestroyNotify destroy)
 {
 	gboolean explicit = FALSE;
+	guchar cls_type;
 	gulong tag;
 	gint flags;
 	Atlv tlv;
@@ -1272,28 +1343,28 @@ anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
 
 	/* Figure out the basis if the class */
 	switch (anode_def_type (node)) {
-	case TYPE_INTEGER:
-	case TYPE_BOOLEAN:
-	case TYPE_BIT_STRING:
-	case TYPE_OCTET_STRING:
-	case TYPE_OBJECT_ID:
-	case TYPE_TIME:
-	case TYPE_ENUMERATED:
-	case TYPE_GENERALSTRING:
-	case TYPE_NULL:
+	case EGG_ASN1X_INTEGER:
+	case EGG_ASN1X_BOOLEAN:
+	case EGG_ASN1X_BIT_STRING:
+	case EGG_ASN1X_OCTET_STRING:
+	case EGG_ASN1X_OBJECT_ID:
+	case EGG_ASN1X_TIME:
+	case EGG_ASN1X_ENUMERATED:
+	case EGG_ASN1X_GENERALSTRING:
+	case EGG_ASN1X_NULL:
 		tlv.cls = ASN1_CLASS_UNIVERSAL;
 		break;
 	/* Container types */
-	case TYPE_SEQUENCE:
-	case TYPE_SET:
-	case TYPE_SEQUENCE_OF:
-	case TYPE_SET_OF:
+	case EGG_ASN1X_SEQUENCE:
+	case EGG_ASN1X_SET:
+	case EGG_ASN1X_SEQUENCE_OF:
+	case EGG_ASN1X_SET_OF:
 		tlv.cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_UNIVERSAL);
 		break;
 
 	/* Transparent types shouldn't get here */
-	case TYPE_ANY:
-	case TYPE_CHOICE:
+	case EGG_ASN1X_ANY:
+	case EGG_ASN1X_CHOICE:
 		g_return_if_reached ();
 
 	default:
@@ -1303,11 +1374,11 @@ 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 = anode_calc_explicit_for_flags (node, flags);
+		explicit = anode_calc_explicit_for_flags (node, flags, &cls_type);
 		if (explicit)
 			flags &= ~FLAG_TAG;
 		else
-			tlv.cls |= ASN1_CLASS_CONTEXT_SPECIFIC;
+			tlv.cls |= cls_type;
 	}
 
 	/* And now the tag */
@@ -1328,14 +1399,17 @@ anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
 	tlv.buf = tlv.end = NULL;
 
 	anode_clear (node);
-	anode_set_tlv_data (node, &tlv);
-	anode_set_enc_data (node, encoder, user_data);
-	anode_set_user_data (node, user_data, destroy);
+	anode_set_tlv_data (node, NULL, &tlv);
+	anode_set_enc_data (node, encoder, user_data, destroy);
 }
 
 static gboolean
-anode_encode_build (GNode *node, guchar *data, gsize n_data)
+anode_encode_build (GNode *node,
+                    EggBytes *backing,
+                    guchar *data,
+                    gsize n_data)
 {
+	guchar cls_type;
 	gint type;
 	guchar cls;
 	gulong tag;
@@ -1352,16 +1426,16 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
 	g_return_val_if_fail (enc, FALSE);
 
 	/* If it's a choice node, use the choice for calculations */
-	if (type == TYPE_CHOICE) {
+	if (type == EGG_ASN1X_CHOICE) {
 		node = egg_asn1x_get_choice (node);
 		g_return_val_if_fail (node, FALSE);
 	}
 
 	/* Encode any explicit tag */
-	if (anode_calc_explicit (node)) {
+	if (anode_calc_explicit (node, &cls_type)) {
 		tag = anode_calc_tag (node);
 		g_return_val_if_fail (tag != G_MAXULONG, FALSE);
-		cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_CONTEXT_SPECIFIC);
+		cls = (ASN1_CLASS_STRUCTURED | cls_type);
 		g_assert (tlv->oft > 0 && tlv->oft < tlv->off);
 		off = anode_encode_cls_tag_len (data, n_data, cls, tag, (tlv->off - tlv->oft) + tlv->len);
 		g_assert (off == tlv->oft);
@@ -1375,9 +1449,10 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
 	g_assert (tlv->len + tlv->off == n_data);
 	tlv->buf = data;
 	tlv->end = data + n_data;
+	anode_set_backing (node, backing);
 
 	/* Encode in the data */
-	if (!(enc->encoder) (enc->data, data + tlv->off, tlv->len))
+	if (!(enc->encoder) (enc->data, node, data + tlv->off, tlv->len))
 		return FALSE;
 
 	return TRUE;
@@ -1437,10 +1512,11 @@ traverse_and_sort_set_of (GNode *node, gpointer user_data)
 	GNode *child;
 	GNode *next;
 
-	g_assert (allocator);
+	if (!allocator)
+		allocator = g_realloc;
 
 	/* We have to sort any SET OF :( */
-	if (anode_def_type (node) != TYPE_SET_OF)
+	if (anode_def_type (node) != EGG_ASN1X_SET_OF)
 		return FALSE;
 
 	bufs = NULL;
@@ -1457,7 +1533,7 @@ traverse_and_sort_set_of (GNode *node, gpointer user_data)
 		if (!data)
 			break;
 
-		if (!anode_encode_build (child, data, n_data)) {
+		if (!anode_encode_build (child, NULL, data, n_data)) {
 			(allocator) (data, 0);
 			continue;
 		}
@@ -1485,7 +1561,22 @@ traverse_and_sort_set_of (GNode *node, gpointer user_data)
 }
 
 static gboolean
-anode_encoder_simple (gpointer user_data, guchar *data, gsize n_data)
+anode_encoder_bytes (gpointer user_data,
+                     GNode *node,
+                     guchar *data,
+                     gsize n_data)
+{
+	EggBytes *bytes = user_data;
+	g_assert (egg_bytes_get_size (bytes) >= n_data);
+	memcpy (data, egg_bytes_get_data (bytes), n_data);
+	return TRUE;
+}
+
+static gboolean
+anode_encoder_data (gpointer user_data,
+                    GNode *node,
+                    guchar *data,
+                    gsize n_data)
 {
 	memcpy (data, user_data, n_data);
 	return TRUE;
@@ -1493,11 +1584,13 @@ anode_encoder_simple (gpointer user_data, guchar *data, gsize n_data)
 
 static gboolean
 anode_encoder_unsigned (gpointer user_data,
+                        GNode *node,
                         guchar *data,
                         gsize n_data)
 {
+	EggBytes *value = user_data;
 	gboolean sign;
-	gchar *p;
+	const gchar *p;
 
 	/*
 	 * If top bit is set, the result would be negative in two's complement
@@ -1505,7 +1598,9 @@ anode_encoder_unsigned (gpointer user_data,
 	 * byte is already calculated into n_data, see egg_asn1x_set_integer_as_usg
 	 */
 
-	p = user_data;
+	p = egg_bytes_get_data (value);
+	g_return_val_if_fail (p != NULL, FALSE);
+
 	sign = !!(p[0] & 0x80);
 	if (sign) {
 		g_assert (n_data > 1);
@@ -1519,7 +1614,10 @@ anode_encoder_unsigned (gpointer user_data,
 }
 
 static gboolean
-anode_encoder_structured (gpointer user_data, guchar *data, gsize n_data)
+anode_encoder_structured (gpointer user_data,
+                          GNode *unused,
+                          guchar *data,
+                          gsize n_data)
 {
 	GNode *node = user_data;
 	GNode *child;
@@ -1531,7 +1629,8 @@ anode_encoder_structured (gpointer user_data, guchar *data, gsize n_data)
 		if (tlv) {
 			length = tlv->off + tlv->len;
 			g_assert (length <= n_data);
-			if (!anode_encode_build (child, data, length))
+			if (!anode_encode_build (child, anode_get_backing (node),
+			                         data, length))
 				return FALSE;
 			data += length;
 			n_data -= length;
@@ -1542,7 +1641,10 @@ anode_encoder_structured (gpointer user_data, guchar *data, gsize n_data)
 }
 
 static gboolean
-anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
+anode_encoder_choice (gpointer user_data,
+                      GNode *unused,
+                      guchar *data,
+                      gsize n_data)
 {
 	GNode *node = user_data;
 	Aenc *enc = NULL;
@@ -1560,7 +1662,7 @@ anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
 
 	enc = anode_get_enc_data (child);
 	g_return_val_if_fail (enc, FALSE);
-	if (!(enc->encoder) (enc->data, data, n_data))
+	if (!(enc->encoder) (enc->data, child, data, n_data))
 		return FALSE;
 
 	/* Child's buffer matches ours */
@@ -1571,7 +1673,10 @@ 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)
+anode_encoder_bit_string (gpointer user_data,
+                          GNode *node,
+                          guchar *data,
+                          gsize n_data)
 {
 	Abits *ab = user_data;
 	guchar empty, mask;
@@ -1588,7 +1693,7 @@ anode_encoder_bit_string (gpointer user_data, guchar *data, gsize n_data)
 	data += 1;
 
 	/* Fill in the actual data */
-	memcpy (data, ab->bits, len);
+	memcpy (data, egg_bytes_get_data (ab->bits), len);
 
 	/* Set the extra bits to zero */
 	if (len && empty) {
@@ -1602,6 +1707,8 @@ anode_encoder_bit_string (gpointer user_data, guchar *data, gsize n_data)
 static gboolean
 anode_encode_prepare_simple (GNode *node, gboolean want)
 {
+	EggBytes *backing;
+	EggBytes *bytes;
 	Aenc *enc;
 	Atlv *tlv;
 
@@ -1611,8 +1718,15 @@ anode_encode_prepare_simple (GNode *node, gboolean want)
 
 	/* Transfer the tlv data over to enc */
 	enc = anode_get_enc_data (node);
-	if (enc == NULL)
-		anode_set_enc_data (node, anode_encoder_simple, (guchar*)tlv->buf + tlv->off);
+	if (enc == NULL) {
+		backing = anode_get_backing (node);
+		if (backing == NULL)
+			return FALSE;
+
+		bytes = egg_bytes_new_with_free_func ((guchar *)tlv->buf + tlv->off, tlv->len,
+		                                      egg_bytes_unref, egg_bytes_ref (backing));
+		anode_set_enc_data (node, anode_encoder_bytes, bytes, egg_bytes_unref);
+	}
 
 	tlv->buf = tlv->end = NULL;
 	return TRUE;
@@ -1624,7 +1738,7 @@ anode_encode_prepare_choice (GNode *node, gboolean want)
 	Atlv *tlv;
 	GNode *child;
 
-	g_assert (anode_def_type (node) == TYPE_CHOICE);
+	g_assert (anode_def_type (node) == EGG_ASN1X_CHOICE);
 
 	child = egg_asn1x_get_choice (node);
 	if (!child)
@@ -1636,8 +1750,8 @@ anode_encode_prepare_choice (GNode *node, gboolean want)
 	tlv = anode_get_tlv_data (child);
 	g_return_val_if_fail (tlv, FALSE);
 	anode_clr_tlv_data (node);
-	anode_set_tlv_data (node, tlv);
-	anode_set_enc_data (node, anode_encoder_choice, node);
+	anode_set_tlv_data (node, NULL, tlv);
+	anode_set_enc_data (node, anode_encoder_choice, node, NULL);
 
 	return TRUE;
 
@@ -1658,7 +1772,7 @@ anode_encode_prepare_structured (GNode *node, gboolean want)
 	had = FALSE;
 	length = 0;
 
-	if (type == TYPE_SEQUENCE_OF || type == TYPE_SET_OF)
+	if (type == EGG_ASN1X_SEQUENCE_OF || type == EGG_ASN1X_SET_OF)
 		child_want = FALSE;
 	if (anode_def_flags (node) & FLAG_OPTION)
 		want = FALSE;
@@ -1674,7 +1788,7 @@ anode_encode_prepare_structured (GNode *node, gboolean want)
 
 	if (had == FALSE) {
 		/* See if we should encode an empty set or seq of */
-		if (type == TYPE_SEQUENCE_OF || type == TYPE_SET_OF) {
+		if (type == EGG_ASN1X_SEQUENCE_OF || type == EGG_ASN1X_SET_OF) {
 			if (!want)
 				return FALSE;
 		} else {
@@ -1690,25 +1804,25 @@ static gboolean
 anode_encode_prepare (GNode *node, gboolean want)
 {
 	switch (anode_def_type (node)) {
-	case TYPE_INTEGER:
-	case TYPE_BOOLEAN:
-	case TYPE_BIT_STRING:
-	case TYPE_OCTET_STRING:
-	case TYPE_OBJECT_ID:
-	case TYPE_TIME:
-	case TYPE_ENUMERATED:
-	case TYPE_GENERALSTRING:
-	case TYPE_ANY:
-	case TYPE_NULL:
+	case EGG_ASN1X_INTEGER:
+	case EGG_ASN1X_BOOLEAN:
+	case EGG_ASN1X_BIT_STRING:
+	case EGG_ASN1X_OCTET_STRING:
+	case EGG_ASN1X_OBJECT_ID:
+	case EGG_ASN1X_TIME:
+	case EGG_ASN1X_ENUMERATED:
+	case EGG_ASN1X_GENERALSTRING:
+	case EGG_ASN1X_ANY:
+	case EGG_ASN1X_NULL:
 		return anode_encode_prepare_simple (node, want);
 		break;
-	case TYPE_SEQUENCE:
-	case TYPE_SEQUENCE_OF:
-	case TYPE_SET:
-	case TYPE_SET_OF:
+	case EGG_ASN1X_SEQUENCE:
+	case EGG_ASN1X_SEQUENCE_OF:
+	case EGG_ASN1X_SET:
+	case EGG_ASN1X_SET_OF:
 		return anode_encode_prepare_structured (node, want);
 		break;
-	case TYPE_CHOICE:
+	case EGG_ASN1X_CHOICE:
 		return anode_encode_prepare_choice (node, want);
 		break;
 	default:
@@ -1716,20 +1830,55 @@ anode_encode_prepare (GNode *node, gboolean want)
 	};
 }
 
-gpointer
-egg_asn1x_encode (GNode *asn, EggAllocator allocator, gsize *n_data)
+typedef struct {
+	EggAllocator allocator;
+	gpointer allocated;
+} AllocatorClosure;
+
+static void
+destroy_with_allocator (gpointer data)
+{
+	AllocatorClosure *closure = data;
+	g_assert (closure->allocator);
+	(closure->allocator) (closure->allocated, 0);
+	g_slice_free (AllocatorClosure, closure);
+}
+
+static EggBytes *
+new_bytes_with_allocator (EggAllocator allocator,
+                          guchar **data,
+                          gsize length)
+{
+	AllocatorClosure *closure;
+
+	if (allocator) {
+		*data = (allocator) (NULL, length + 1);
+		if (allocator == NULL)
+			return NULL;
+		closure = g_slice_new (AllocatorClosure);
+		closure->allocated = *data;
+		closure->allocator = allocator;
+		return egg_bytes_new_with_free_func (*data, length,
+		                                     destroy_with_allocator,
+		                                     closure);
+	} else {
+		*data = g_malloc (length);
+		return egg_bytes_new_take (*data, length);
+	}
+}
+
+EggBytes *
+egg_asn1x_encode (GNode *asn,
+                  EggAllocator allocator)
 {
+	EggBytes *bytes;
 	guchar *data;
 	gsize length;
 	Atlv *tlv;
 
-	g_return_val_if_fail (asn, NULL);
-	g_return_val_if_fail (n_data, NULL);
+	g_return_val_if_fail (asn != NULL, NULL);
 	g_return_val_if_fail (anode_def_type_is_real (asn), NULL);
 
-	if (!allocator)
-		allocator = g_realloc;
-
 	if (!anode_encode_prepare (asn, TRUE)) {
 		anode_failure (asn, "missing value(s)");
 		return NULL;
@@ -1744,18 +1893,17 @@ egg_asn1x_encode (GNode *asn, EggAllocator allocator, gsize *n_data)
 
 	/* Allocate enough memory for entire thingy */
 	length = tlv->off + tlv->len;
-	data = (allocator) (NULL, length + 1);
+	bytes = new_bytes_with_allocator (allocator, &data, length);
 	if (data == NULL)
 		return NULL;
 
-	if (anode_encode_build (asn, data, length) &&
+	if (anode_encode_build (asn, bytes, data, length) &&
 	    anode_validate_anything (asn, TRUE)) {
 		anode_encode_commit (asn);
-		*n_data = length;
-		return data;
+		return bytes;
 	}
 
-	(allocator) (data, 0);
+	egg_bytes_unref (bytes);
 	anode_encode_rollback (asn);
 	return NULL;
 }
@@ -2256,7 +2404,6 @@ anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
 	gboolean had;
 	gint i, k, at;
 
-	p = oid;
 	at = 0;
 	num1 = 0;
 
@@ -2320,7 +2467,7 @@ egg_asn1x_node (GNode *asn, ...)
 		type = anode_def_type (node);
 
 		/* Use integer indexes for these */
-		if (type == TYPE_SEQUENCE_OF || type == TYPE_SET_OF) {
+		if (type == EGG_ASN1X_SEQUENCE_OF || type == EGG_ASN1X_SET_OF) {
 			index = va_arg (va, gint);
 			if (index == 0)
 				return node;
@@ -2363,6 +2510,13 @@ egg_asn1x_name (GNode *node)
 	return anode_def_name (node);
 }
 
+EggAsn1xType
+egg_asn1x_type (GNode *node)
+{
+	g_return_val_if_fail (node, 0);
+	return anode_def_type (node);
+}
+
 guint
 egg_asn1x_count (GNode *node)
 {
@@ -2373,7 +2527,7 @@ egg_asn1x_count (GNode *node)
 	g_return_val_if_fail (node, 0);
 
 	type = anode_def_type (node);
-	if (type != TYPE_SEQUENCE_OF && type != TYPE_SET_OF) {
+	if (type != EGG_ASN1X_SEQUENCE_OF && type != EGG_ASN1X_SET_OF) {
 		g_warning ("node passed to egg_asn1x_count was not a sequence of or set of");
 		return 0;
 	}
@@ -2395,7 +2549,7 @@ egg_asn1x_append (GNode *node)
 	g_return_val_if_fail (node, NULL);
 
 	type = anode_def_type (node);
-	if (type != TYPE_SEQUENCE_OF && type != TYPE_SET_OF) {
+	if (type != EGG_ASN1X_SEQUENCE_OF && type != EGG_ASN1X_SET_OF) {
 		g_warning ("node passed to egg_asn1x_append was not a sequence of or set of");
 		return NULL;
 	}
@@ -2427,12 +2581,12 @@ egg_asn1x_have (GNode *node)
 gboolean
 egg_asn1x_get_boolean (GNode *node, gboolean *value)
 {
-	ASN1_ARRAY_TYPE *opt;
+	EggAsn1xDef *opt;
 	Atlv *tlv;
 
 	g_return_val_if_fail (node, FALSE);
 	g_return_val_if_fail (value, FALSE);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BOOLEAN, FALSE);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL) {
@@ -2441,7 +2595,7 @@ egg_asn1x_get_boolean (GNode *node, gboolean *value)
 			return FALSE;
 
 		/* Try to get a default */
-		opt = anode_opt_lookup (node, TYPE_DEFAULT, NULL);
+		opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
 		g_return_val_if_fail (opt, FALSE);
 
 		/* Parse out the default value */
@@ -2464,7 +2618,7 @@ egg_asn1x_set_boolean (GNode *node, gboolean 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) == EGG_ASN1X_BOOLEAN, FALSE);
 
 	/* TODO: Handle default values */
 
@@ -2472,7 +2626,7 @@ egg_asn1x_set_boolean (GNode *node, gboolean value)
 	data = g_malloc0 (1);
 	if (!anode_write_boolean (value, data, &n_data))
 		return FALSE;
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, g_free);
+	anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
 	return TRUE;
 }
 
@@ -2480,10 +2634,10 @@ gboolean
 egg_asn1x_set_null (GNode *node)
 {
 	g_return_val_if_fail (node, FALSE);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_NULL, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_NULL, FALSE);
 
 	/* Encode zero characters */
-	anode_encode_tlv_and_enc (node, 0, anode_encoder_simple, "", NULL);
+	anode_encode_tlv_and_enc (node, 0, anode_encoder_data, "", NULL);
 	return TRUE;
 }
 
@@ -2491,12 +2645,12 @@ GQuark
 egg_asn1x_get_enumerated (GNode *node)
 {
 	gchar buf[sizeof (gulong) * 3];
-	ASN1_ARRAY_TYPE *opt;
+	EggAsn1xDef *opt;
 	gulong val;
 	Atlv *tlv;
 
 	g_return_val_if_fail (node, 0);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_ENUMERATED, 0);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED, 0);
 
 	tlv = anode_get_tlv_data (node);
 
@@ -2515,7 +2669,7 @@ egg_asn1x_get_enumerated (GNode *node)
 		g_return_val_if_reached (0);
 
 	/* Lookup that value in our table */
-	opt = anode_opt_lookup_value (node, TYPE_CONSTANT, buf);
+	opt = anode_opt_lookup_value (node, EGG_ASN1X_CONSTANT, buf);
 	if (opt == NULL || opt->name == NULL)
 		return 0;
 
@@ -2525,7 +2679,7 @@ egg_asn1x_get_enumerated (GNode *node)
 gboolean
 egg_asn1x_set_enumerated (GNode *node, GQuark value)
 {
-	ASN1_ARRAY_TYPE *opt;
+	EggAsn1xDef *opt;
 	const gchar *name;
 	gpointer data;
 	gsize n_data;
@@ -2533,14 +2687,14 @@ egg_asn1x_set_enumerated (GNode *node, GQuark value)
 
 	g_return_val_if_fail (node, FALSE);
 	g_return_val_if_fail (value, FALSE);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_ENUMERATED, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED, FALSE);
 
 	/* TODO: Handle default values */
 
 	name = g_quark_to_string (value);
 	g_return_val_if_fail (name, FALSE);
 
-	opt = anode_opt_lookup (node, TYPE_CONSTANT, name);
+	opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, name);
 	g_return_val_if_fail (opt && opt->value, FALSE);
 
 	/* TODO: Signed values */
@@ -2553,21 +2707,21 @@ egg_asn1x_set_enumerated (GNode *node, GQuark value)
 	if (!anode_write_integer_ulong (val, data, &n_data))
 		return FALSE;
 
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, g_free);
+	anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
 	return TRUE;
 }
 
 gboolean
 egg_asn1x_get_integer_as_ulong (GNode *node, gulong *value)
 {
-	const ASN1_ARRAY_TYPE *opt;
+	const EggAsn1xDef *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);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL) {
@@ -2576,12 +2730,12 @@ egg_asn1x_get_integer_as_ulong (GNode *node, gulong *value)
 			return FALSE;
 
 		/* Try to get a default */
-		opt = anode_opt_lookup (node, TYPE_DEFAULT, NULL);
+		opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
 		g_return_val_if_fail (opt, FALSE);
 		g_return_val_if_fail (opt->value, FALSE);
 		defval = opt->value;
 
-		opt = anode_opt_lookup (node, TYPE_CONSTANT, defval);
+		opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, defval);
 		if (opt != NULL) {
 			g_return_val_if_fail (opt->value, FALSE);
 			defval = opt->value;
@@ -2603,7 +2757,7 @@ 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_INTEGER, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
 
 	/* TODO: Handle default values */
 
@@ -2611,100 +2765,136 @@ egg_asn1x_set_integer_as_ulong (GNode *node, gulong value)
 	data = g_malloc0 (n_data);
 	if (!anode_write_integer_ulong (value, data, &n_data))
 		return FALSE;
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, g_free);
+	anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
 	return TRUE;
 }
 
-gconstpointer
-egg_asn1x_get_integer_as_raw (GNode *node, gsize *n_data)
+EggBytes *
+egg_asn1x_get_integer_as_raw (GNode *node)
 {
+	EggBytes *backing;
 	Atlv *tlv;
 
 	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);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
 		return NULL;
 
-	*n_data = tlv->len;
-	return tlv->buf + tlv->off;
+	backing = anode_get_backing (node);
+	if (backing == NULL)
+		return NULL;
+
+	return egg_bytes_new_with_free_func (tlv->buf + tlv->off, tlv->len,
+	                                     egg_bytes_unref, egg_bytes_ref (backing));
 }
 
-gconstpointer
-egg_asn1x_get_integer_as_usg (GNode *node,
-                              gsize *n_data)
+EggBytes *
+egg_asn1x_get_integer_as_usg (GNode *node)
 {
+	EggBytes *backing;
 	const guchar *p;
 	gboolean sign;
+	Atlv *tlv;
+	gsize n_data;
 	gsize len;
 
-	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);
+	g_return_val_if_fail (node != NULL, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
+
+	tlv = anode_get_tlv_data (node);
+	if (tlv == NULL || tlv->buf == NULL)
+		return NULL;
+
+	backing = anode_get_backing (node);
+	if (backing == NULL)
+		return NULL;
+
+	p = tlv->buf + tlv->off;
+	len = tlv->len;
 
-	p = egg_asn1x_get_integer_as_raw (node, &len);
 	sign = !!(p[0] & 0x80);
 	if (sign) {
 		g_warning ("invalid two's complement integer is negative, but expected unsigned");
 		return NULL;
 	}
 
-	*n_data = len;
+	n_data = len;
 
 	/* Strip off the extra zero byte that was preventing it from being negative */
 	if (p[0] == 0 && len > 1) {
 		sign = !!(p[1] & 0x80);
 		if (sign) {
 			p++;
-			*n_data = len - 1;
+			n_data = len - 1;
 		}
 	}
 
-	return p;
+	return egg_bytes_new_with_free_func (p, n_data,
+	                                     egg_bytes_unref,
+	                                     egg_bytes_ref (backing));
 }
 
-gboolean
-egg_asn1x_set_integer_as_raw (GNode *node, gconstpointer data, gsize n_data, GDestroyNotify destroy)
+void
+egg_asn1x_set_integer_as_raw (GNode *node,
+                              EggBytes *value)
+{
+	g_return_if_fail (value != NULL);
+	egg_asn1x_take_integer_as_raw (node, egg_bytes_ref (value));
+}
+
+void
+egg_asn1x_take_integer_as_raw (GNode *node,
+                               EggBytes *value)
 {
 	gboolean sign;
-	guchar *p;
+	const 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);
+	g_return_if_fail (node != NULL);
+	g_return_if_fail (value != NULL);
+	g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
 
 	/* Make sure the integer is properly encoded in twos complement*/
-	p = (guchar*)data;
+	p = egg_bytes_get_data (value);
+	g_return_if_fail (p != NULL);
+
 	sign = !!(p[0] & 0x80);
 	if (sign) {
 		g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement");
-		return FALSE;
+		return;
 	}
 
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, (gpointer)data, destroy);
-	return TRUE;
+	anode_encode_tlv_and_enc (node, egg_bytes_get_size (value), anode_encoder_bytes,
+	                          value, egg_bytes_unref);
 }
 
-gboolean
+void
 egg_asn1x_set_integer_as_usg (GNode *node,
-                              gconstpointer data,
-                              gsize n_data,
-                              GDestroyNotify destroy)
+                              EggBytes *value)
+{
+	g_return_if_fail (value != NULL);
+	egg_asn1x_take_integer_as_usg (node, egg_bytes_ref (value));
+}
+
+void
+egg_asn1x_take_integer_as_usg (GNode *node,
+                               EggBytes *value)
 {
 	gboolean sign;
-	guchar *p;
+	const guchar *p;
+	gsize len;
 
-	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);
+	g_return_if_fail (node != NULL);
+	g_return_if_fail (value != NULL);
+	g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
 
 	/* Make sure the integer is properly encoded in twos complement*/
-	p = (guchar*)data;
+	p = egg_bytes_get_data (value);
+	g_return_if_fail (p != NULL);
+
 	sign = !!(p[0] & 0x80);
+	len = egg_bytes_get_size (value);
 
 	/*
 	 * If in two's complement this would be negative, add a zero byte so
@@ -2712,50 +2902,66 @@ egg_asn1x_set_integer_as_usg (GNode *node,
 	 * longer. In anode_encoder_unsigned we actually add the zero byte.
 	 */
 	if (sign)
-		n_data += 1;
+		len += 1;
 
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_unsigned,
-	                          (gpointer)data, destroy);
-	return TRUE;
+	anode_encode_tlv_and_enc (node, len, anode_encoder_unsigned,
+	                          value, egg_bytes_unref);
 }
 
-gconstpointer
-egg_asn1x_get_raw_element (GNode *node, gsize *n_element)
+EggBytes *
+egg_asn1x_get_element_raw (GNode *node)
 {
+	EggBytes *backing;
+	const guchar *p;
+	gsize len;
 	Atlv *tlv;
 
-	g_return_val_if_fail (node, NULL);
-	g_return_val_if_fail (n_element, NULL);
+	g_return_val_if_fail (node != NULL, 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;
+	backing = anode_get_backing (node);
+	if (backing == NULL)
+		return NULL;
+
+	if (anode_calc_explicit (node, NULL)) {
+		len = (tlv->len + tlv->off) - tlv->oft;
+		p = tlv->buf + tlv->oft;
 	} else {
-		*n_element = tlv->len + tlv->off;
-		return tlv->buf;
+		len = tlv->len + tlv->off;
+		p = tlv->buf;
 	}
+
+	return egg_bytes_new_with_free_func (p, len, egg_bytes_unref,
+	                                     egg_bytes_ref (backing));
 }
 
 gboolean
-egg_asn1x_set_raw_element (GNode *node, gpointer data,
-                           gsize n_data, GDestroyNotify destroy)
+egg_asn1x_set_element_raw (GNode *node,
+                           EggBytes *element)
 {
 	Atlv dtlv, *tlv;
 	gint oft, flags;
+	const guchar *data;
+	guchar cls_type;
+	EggBytes *sub;
+	gsize size;
 
-	g_return_val_if_fail (node, FALSE);
-	g_return_val_if_fail (data, FALSE);
-	g_return_val_if_fail (n_data, FALSE);
+	g_return_val_if_fail (node != NULL, FALSE);
+	g_return_val_if_fail (element != NULL, FALSE);
 
 	anode_clear (node);
 	memset (&dtlv, 0, sizeof (dtlv));
 
+	data = egg_bytes_get_data (element);
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	size = egg_bytes_get_size (element);
+
 	/* Decode the beginning TLV */
-	if (!anode_decode_tlv_for_data (data, (const guchar*)data + n_data, &dtlv))
+	if (!anode_decode_tlv_for_data (data, data + size, &dtlv))
 		return FALSE;
 
 	/*
@@ -2767,11 +2973,11 @@ egg_asn1x_set_raw_element (GNode *node, gpointer data,
 	 */
 	flags = anode_def_flags (node);
 	flags &= ~(FLAG_TAG | FLAG_DEFAULT | FLAG_OPTION);
-	if (!anode_decode_anything_for_flags (node, &dtlv, flags))
+	if (!anode_decode_anything_for_flags (node, element, &dtlv, flags))
 		return FALSE;
 
 	/* There was extra data */
-	if (dtlv.end - dtlv.buf != n_data)
+	if (dtlv.end - dtlv.buf != size)
 		return FALSE;
 
 	/* Clear buffer from TLV so it gets encoded */
@@ -2780,46 +2986,41 @@ egg_asn1x_set_raw_element (GNode *node, gpointer data,
 	tlv->buf = tlv->end = NULL;
 
 	/* Explicit tagging: leave space for the outer tag */
-	if (anode_calc_explicit (node)) {
-		oft = anode_encode_cls_tag_len (NULL, 0, (ASN1_CLASS_STRUCTURED | ASN1_CLASS_CONTEXT_SPECIFIC),
-		                                anode_calc_tag (node), n_data);
+	if (anode_calc_explicit (node, &cls_type)) {
+		oft = anode_encode_cls_tag_len (NULL, 0, (ASN1_CLASS_STRUCTURED | cls_type),
+		                                anode_calc_tag (node), size);
 
 		tlv->off += oft;
 		tlv->oft = oft;
 	}
 
+	sub = egg_bytes_new_with_free_func (dtlv.buf + dtlv.off, dtlv.len,
+	                                    egg_bytes_unref, egg_bytes_ref (element));
+
 	/* Setup encoding of the contents */
-	anode_set_enc_data (node, anode_encoder_simple, (gpointer)(dtlv.buf + dtlv.off));
-	anode_set_user_data (node, data, destroy);
+	anode_set_enc_data (node, anode_encoder_bytes, sub, egg_bytes_unref);
 	return TRUE;
 }
 
-gconstpointer
-egg_asn1x_get_raw_value (GNode *node, gsize *n_content)
+EggBytes *
+egg_asn1x_get_raw_value (GNode *node)
 {
+	EggBytes *backing;
 	Atlv *tlv;
 
 	g_return_val_if_fail (node, NULL);
-	g_return_val_if_fail (n_content, NULL);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
 		return NULL;
 	g_return_val_if_fail (!(tlv->cls & ASN1_CLASS_STRUCTURED), NULL);
 
-	*n_content = tlv->len;
-	return tlv->buf + tlv->off;
-}
-
-gboolean
-egg_asn1x_set_raw_value (GNode *node, gsize length, EggAsn1xEncoder encoder,
-                         gpointer user_data, GDestroyNotify destroy)
-{
-	g_return_val_if_fail (node, FALSE);
-	g_return_val_if_fail (encoder, FALSE);
+	backing = anode_get_backing (node);
+	if (backing == NULL)
+		return NULL;
 
-	anode_encode_tlv_and_enc (node, length, encoder, user_data, destroy);
-	return TRUE;
+	return egg_bytes_new_with_free_func (tlv->buf + tlv->off, tlv->len,
+	                                     egg_bytes_unref, egg_bytes_ref (backing));
 }
 
 guchar*
@@ -2837,7 +3038,7 @@ egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_strin
 		allocator = g_realloc;
 
 	type = anode_def_type (node);
-	g_return_val_if_fail (type == TYPE_OCTET_STRING || type == TYPE_GENERALSTRING, NULL);
+	g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, NULL);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
@@ -2870,9 +3071,41 @@ egg_asn1x_set_string_as_raw (GNode *node, guchar *data, gsize n_data, GDestroyNo
 	g_return_val_if_fail (data, FALSE);
 
 	type = anode_def_type (node);
-	g_return_val_if_fail (type == TYPE_OCTET_STRING || type == TYPE_GENERALSTRING, FALSE);
+	g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, FALSE);
 
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, destroy);
+	anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, destroy);
+	return TRUE;
+}
+
+EggBytes *
+egg_asn1x_get_string_as_bytes (GNode *node)
+{
+	gpointer raw;
+	gsize length;
+
+	g_return_val_if_fail (node != NULL, NULL);
+
+	raw = egg_asn1x_get_string_as_raw (node, NULL, &length);
+	if (raw == NULL)
+		return NULL;
+
+	return egg_bytes_new_take (raw, length);
+}
+
+gboolean
+egg_asn1x_set_string_as_bytes (GNode *node,
+                               EggBytes *data)
+{
+	gint type;
+
+	g_return_val_if_fail (node != NULL, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	type = anode_def_type (node);
+	g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, FALSE);
+
+	anode_encode_tlv_and_enc (node, egg_bytes_get_size (data), anode_encoder_bytes,
+	                          egg_bytes_ref (data), egg_bytes_unref);
 	return TRUE;
 }
 
@@ -2933,61 +3166,67 @@ 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)
+EggBytes *
+egg_asn1x_get_bits_as_raw (GNode *node, guint *n_bits)
 {
-	Atlv *tlv;
-	gpointer bits;
+	EggBytes *backing;
 	guchar padded;
+	Atlv *tlv;
 
 	g_return_val_if_fail (node, FALSE);
 	g_return_val_if_fail (n_bits, FALSE);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_BIT_STRING, FALSE);
-
-	if (!allocator)
-		allocator = g_realloc;
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, FALSE);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
 		return NULL;
 
+	backing = anode_get_backing (node);
+	if (backing == 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;
+	return egg_bytes_new_with_free_func (tlv->buf + tlv->off + 1, tlv->len - 1,
+	                                     egg_bytes_unref, egg_bytes_ref (backing));
 }
 
-gboolean
-egg_asn1x_set_bits_as_raw (GNode *node, guchar *bits, guint n_bits, GDestroyNotify destroy)
+void
+egg_asn1x_set_bits_as_raw (GNode *node,
+                           EggBytes *value,
+                           guint n_bits)
+{
+	g_return_if_fail (value != NULL);
+	egg_asn1x_take_bits_as_raw (node, egg_bytes_ref (value), n_bits);
+}
+
+void
+egg_asn1x_take_bits_as_raw (GNode *node,
+                            EggBytes *value,
+                            guint n_bits)
 {
 	gint type;
 	gsize length;
 	Abits *ab;
 
-	g_return_val_if_fail (node, FALSE);
-	g_return_val_if_fail (bits, FALSE);
+	g_return_if_fail (node != NULL);
+	g_return_if_fail (value != NULL);
 
 	type = anode_def_type (node);
-	g_return_val_if_fail (type == TYPE_BIT_STRING, FALSE);
+	g_return_if_fail (type == EGG_ASN1X_BIT_STRING);
 
 	length = (n_bits / 8);
 	if (n_bits % 8)
 		length += 1;
 
 	ab = g_slice_new0 (Abits);
-	ab->bits = bits;
+	ab->bits = value;
 	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
@@ -3002,7 +3241,7 @@ egg_asn1x_get_bits_as_ulong (GNode *node, gulong *bits, guint *n_bits)
 	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);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, FALSE);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
@@ -3042,7 +3281,7 @@ egg_asn1x_set_bits_as_ulong (GNode *node, gulong bits, guint n_bits)
 	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);
+	g_return_val_if_fail (type == EGG_ASN1X_BIT_STRING, FALSE);
 
 	empty = n_bits % 8;
 	if (empty > 0)
@@ -3056,9 +3295,8 @@ egg_asn1x_set_bits_as_ulong (GNode *node, gulong bits, guint n_bits)
 		data[(length - i) - 1] = (value >> i * 8) & 0xFF;
 
 	ab = g_slice_new0 (Abits);
-	ab->bits = data;
+	ab->bits = egg_bytes_new_take (data, sizeof (gulong));
 	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;
@@ -3076,15 +3314,15 @@ egg_asn1x_get_time_as_long (GNode *node)
 	type = anode_def_type (node);
 
 	/* Time is often represented as a choice, so work than in here */
-	if (type == TYPE_CHOICE) {
+	if (type == EGG_ASN1X_CHOICE) {
 		node = egg_asn1x_get_choice (node);
 		if (node == NULL)
 			return -1;
-		g_return_val_if_fail (anode_def_type (node) == TYPE_TIME, -1);
+		g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_TIME, -1);
 		return egg_asn1x_get_time_as_long (node);
 	}
 
-	g_return_val_if_fail (type == TYPE_TIME, -1);
+	g_return_val_if_fail (type == EGG_ASN1X_TIME, -1);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
@@ -3107,15 +3345,15 @@ egg_asn1x_get_time_as_date (GNode *node, GDate *date)
 	type = anode_def_type (node);
 
 	/* Time is often represented as a choice, so work than in here */
-	if (type == TYPE_CHOICE) {
+	if (type == EGG_ASN1X_CHOICE) {
 		node = egg_asn1x_get_choice (node);
 		if (node == NULL)
 			return FALSE;
-		g_return_val_if_fail (anode_def_type (node) == TYPE_TIME, FALSE);
+		g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_TIME, FALSE);
 		return egg_asn1x_get_time_as_date (node, date);
 	}
 
-	g_return_val_if_fail (type == TYPE_TIME, FALSE);
+	g_return_val_if_fail (type == EGG_ASN1X_TIME, FALSE);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
@@ -3135,7 +3373,7 @@ egg_asn1x_get_oid_as_string (GNode *node)
 	Atlv *tlv;
 
 	g_return_val_if_fail (node, NULL);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_OBJECT_ID, NULL);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_OBJECT_ID, NULL);
 
 	tlv = anode_get_tlv_data (node);
 	if (tlv == NULL || tlv->buf == NULL)
@@ -3155,7 +3393,7 @@ egg_asn1x_set_oid_as_string (GNode *node, const gchar *oid)
 
 	g_return_val_if_fail (oid, FALSE);
 	g_return_val_if_fail (node, FALSE);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_OBJECT_ID, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_OBJECT_ID, FALSE);
 
 	/* Encoding will always be shorter than string */
 	n_data = strlen (oid);
@@ -3166,7 +3404,7 @@ egg_asn1x_set_oid_as_string (GNode *node, const gchar *oid)
 		return FALSE;
 	}
 
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, g_free);
+	anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
 	return TRUE;
 }
 
@@ -3221,7 +3459,7 @@ egg_asn1x_set_choice (GNode *node, GNode *choice)
 	Anode *an;
 
 	g_return_val_if_fail (node, FALSE);
-	g_return_val_if_fail (anode_def_type (node) == TYPE_CHOICE, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_CHOICE, FALSE);
 
 	/* One and only one of the children must be set */
 	for (child = node->children; child; child = child->next) {
@@ -3247,7 +3485,7 @@ egg_asn1x_set_choice (GNode *node, GNode *choice)
 static gboolean
 anode_parse_size (GNode *node, const gchar *text, gulong *value)
 {
-	ASN1_ARRAY_TYPE *def;
+	EggAsn1xDef *def;
 	gchar *end = NULL;
 
 	if (text == NULL) {
@@ -3257,7 +3495,7 @@ anode_parse_size (GNode *node, const gchar *text, gulong *value)
 		*value = G_MAXULONG;
 		return TRUE;
 	} else if (g_ascii_isalpha (text[0])) {
-		def = anode_opt_lookup (node, TYPE_INTEGER, text);
+		def = anode_opt_lookup (node, EGG_ASN1X_INTEGER, text);
 		g_return_val_if_fail (def, FALSE);
 		return anode_parse_size (node, def->value, value);
 	}
@@ -3271,12 +3509,12 @@ anode_parse_size (GNode *node, const gchar *text, gulong *value)
 static gboolean
 anode_validate_size (GNode *node, gulong length)
 {
-	ASN1_ARRAY_TYPE *size;
+	EggAsn1xDef *size;
 	gulong value1 = 0;
 	gulong value2 = G_MAXULONG;
 
 	if (anode_def_flags (node) & FLAG_SIZE) {
-		size = anode_opt_lookup (node, TYPE_SIZE, NULL);
+		size = anode_opt_lookup (node, EGG_ASN1X_SIZE, NULL);
 		g_return_val_if_fail (size, FALSE);
 		if (!anode_parse_size (node, size->value, &value1))
 			g_return_val_if_reached (FALSE);
@@ -3316,7 +3554,7 @@ anode_validate_integer (GNode *node, Atlv *tlv)
 
 		/* Look through the list of constants */
 		found = FALSE;
-		constants = anode_opts_lookup (node, TYPE_CONSTANT, NULL);
+		constants = anode_opts_lookup (node, EGG_ASN1X_CONSTANT, NULL);
 		for (l = constants; l; l = g_list_next (l)) {
 			check = anode_def_value_as_ulong (l->data);
 			g_return_val_if_fail (check != G_MAXULONG, FALSE);
@@ -3458,7 +3696,7 @@ anode_validate_sequence_or_set (GNode *node,
 
 		/* Tags must be in ascending order */
 		tlv = anode_get_tlv_data (child);
-		if (tlv && type == TYPE_SET) {
+		if (tlv && type == EGG_ASN1X_SET) {
 			if (count > 0 && tag > tlv->tag)
 				return anode_failure (node, "content must be in ascending order");
 			tag = tlv->tag;
@@ -3481,7 +3719,7 @@ anode_validate_sequence_or_set_of (GNode *node,
 
 	tag = 0;
 	count = 0;
-	tlv = ptlv = NULL;
+	ptlv = NULL;
 
 	type = anode_def_type (node);
 
@@ -3499,7 +3737,7 @@ anode_validate_sequence_or_set_of (GNode *node,
 				return anode_failure (node, "invalid mismatched content");
 
 			/* Set of must be in ascending order */
-			if (strict && type == TYPE_SET_OF &&
+			if (strict && type == EGG_ASN1X_SET_OF &&
 			    ptlv != NULL && compare_tlvs (ptlv, tlv) > 0)
 				return anode_failure (node, "content must be in ascending order");
 			ptlv = tlv;
@@ -3533,38 +3771,38 @@ anode_validate_anything (GNode *node,
 	switch (type) {
 
 	/* The primitive value types */
-	case TYPE_INTEGER:
+	case EGG_ASN1X_INTEGER:
 		return anode_validate_integer (node, tlv);
-	case TYPE_ENUMERATED:
+	case EGG_ASN1X_ENUMERATED:
 		return anode_validate_enumerated (node, tlv);
-	case TYPE_BOOLEAN:
+	case EGG_ASN1X_BOOLEAN:
 		return anode_validate_boolean (node, tlv);
-	case TYPE_BIT_STRING:
+	case EGG_ASN1X_BIT_STRING:
 		return anode_validate_bit_string (node, tlv);
-	case TYPE_OCTET_STRING:
+	case EGG_ASN1X_OCTET_STRING:
 		return anode_validate_string (node, tlv);
-	case TYPE_OBJECT_ID:
+	case EGG_ASN1X_OBJECT_ID:
 		return anode_validate_object_id (node, tlv);
-	case TYPE_NULL:
+	case EGG_ASN1X_NULL:
 		return anode_validate_null (node, tlv);
-	case TYPE_GENERALSTRING:
+	case EGG_ASN1X_GENERALSTRING:
 		return anode_validate_string (node, tlv);
-	case TYPE_TIME:
+	case EGG_ASN1X_TIME:
 		return anode_validate_time (node, tlv);
 
 	/* Transparent types */
-	case TYPE_ANY:
+	case EGG_ASN1X_ANY:
 		return TRUE;
-	case TYPE_CHOICE:
+	case EGG_ASN1X_CHOICE:
 		return anode_validate_choice (node, strict);
 
 	/* Structured types */
-	case TYPE_SEQUENCE:
-	case TYPE_SET:
+	case EGG_ASN1X_SEQUENCE:
+	case EGG_ASN1X_SET:
 		return anode_validate_sequence_or_set (node, strict);
 
-	case TYPE_SEQUENCE_OF:
-	case TYPE_SET_OF:
+	case EGG_ASN1X_SEQUENCE_OF:
+	case EGG_ASN1X_SET_OF:
 		return anode_validate_sequence_or_set_of (node, strict);
 
 	default:
@@ -3605,8 +3843,8 @@ compare_nodes_by_tag (gconstpointer a, gconstpointer b)
 	return (taga < tagb) ? -1 : 1;
 }
 
-static const ASN1_ARRAY_TYPE*
-adef_next_sibling (const ASN1_ARRAY_TYPE *def)
+static const EggAsn1xDef *
+adef_next_sibling (const EggAsn1xDef *def)
 {
 	int depth = 0;
 
@@ -3633,8 +3871,8 @@ adef_next_sibling (const ASN1_ARRAY_TYPE *def)
 	return def;
 }
 
-static const ASN1_ARRAY_TYPE*
-adef_first_child (const ASN1_ARRAY_TYPE *def)
+static const EggAsn1xDef *
+adef_first_child (const EggAsn1xDef *def)
 {
 	g_assert (def);
 	g_assert (def->value || def->type || def->name);
@@ -3647,10 +3885,12 @@ adef_first_child (const ASN1_ARRAY_TYPE *def)
 	return def;
 }
 
-static const ASN1_ARRAY_TYPE*
-lookup_def_of_type (const ASN1_ARRAY_TYPE *defs, const gchar *name, gint type)
+static const EggAsn1xDef *
+lookup_def_of_type (const EggAsn1xDef *defs,
+                    const gchar *name,
+                    gint type)
 {
-	const ASN1_ARRAY_TYPE *def;
+	const EggAsn1xDef *def;
 
 	g_assert (defs);
 	g_assert (defs->value || defs->type || defs->name);
@@ -3666,8 +3906,8 @@ lookup_def_of_type (const ASN1_ARRAY_TYPE *defs, const gchar *name, gint type)
 static gboolean
 traverse_and_prepare (GNode *node, gpointer data)
 {
-	const ASN1_ARRAY_TYPE *defs = data;
-	const ASN1_ARRAY_TYPE *def;
+	const EggAsn1xDef *defs = data;
+	const EggAsn1xDef *def;
 	const gchar *identifier;
 	Anode *an, *anj;
 	GNode *join = NULL;
@@ -3675,7 +3915,7 @@ traverse_and_prepare (GNode *node, gpointer data)
 	GList *list = NULL, *l;
 
 	/* A while, because the stuff we join, could also be an identifier */
-	while (anode_def_type (node) == TYPE_IDENTIFIER) {
+	while (anode_def_type (node) == EGG_ASN1X_IDENTIFIER) {
 		an = node->data;
 		identifier = an->join ? an->join->value : an->def->value;
 		g_return_val_if_fail (identifier, TRUE);
@@ -3702,11 +3942,11 @@ traverse_and_prepare (GNode *node, gpointer data)
 	}
 
 	/* Lookup the max set size */
-	if (anode_def_type (node) == TYPE_SIZE) {
+	if (anode_def_type (node) == EGG_ASN1X_SIZE) {
 		identifier = anode_def_name (node);
 		if (identifier && !g_str_equal (identifier, "MAX") &&
 		    g_ascii_isalpha (identifier[0])) {
-			def = lookup_def_of_type (defs, identifier, TYPE_INTEGER);
+			def = lookup_def_of_type (defs, identifier, EGG_ASN1X_INTEGER);
 			g_return_val_if_fail (def, TRUE);
 			anode_opt_add (node, def);
 		}
@@ -3737,7 +3977,7 @@ traverse_and_prepare (GNode *node, gpointer data)
 	}
 
 	/* Sort the children of any sets */
-	if (anode_def_type (node) == TYPE_SET) {
+	if (anode_def_type (node) == EGG_ASN1X_SET) {
 		for (child = node->children; child; child = child->next)
 			list = g_list_prepend (list, child);
 		list = g_list_sort (list, compare_nodes_by_tag);
@@ -3753,12 +3993,14 @@ 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)
+static const EggAsn1xDef *
+match_oid_in_definition (const EggAsn1xDef *def,
+                         GHashTable *names,
+                         const gchar *match,
+                         const gchar **problem)
 {
-	const ASN1_ARRAY_TYPE *result = NULL;
-	const ASN1_ARRAY_TYPE *odef;
+	const EggAsn1xDef *result = NULL;
+	const EggAsn1xDef *odef;
 	const gchar *value;
 	GString *oid = NULL;
 
@@ -3767,7 +4009,7 @@ match_oid_in_definition (const ASN1_ARRAY_TYPE *def, GHashTable *names,
 	g_assert (names);
 
 	for (odef = adef_first_child (def); odef; odef = adef_next_sibling (odef)) {
-		if ((odef->type & 0xFF) != TYPE_CONSTANT)
+		if ((odef->type & 0xFF) != EGG_ASN1X_CONSTANT)
 			continue;
 
 		g_return_val_if_fail (odef->value, NULL);
@@ -3804,11 +4046,12 @@ match_oid_in_definition (const ASN1_ARRAY_TYPE *def, GHashTable *names,
 	return result;
 }
 
-static const ASN1_ARRAY_TYPE*
-match_oid_in_definitions (const ASN1_ARRAY_TYPE *defs, const gchar *match)
+static const EggAsn1xDef *
+match_oid_in_definitions (const EggAsn1xDef *defs,
+                          const gchar *match)
 {
-	const ASN1_ARRAY_TYPE *def;
-	const ASN1_ARRAY_TYPE *result;
+	const EggAsn1xDef *def;
+	const EggAsn1xDef *result;
 	GHashTable *names;
 	gboolean progress;
 	const gchar *problem;
@@ -3823,7 +4066,7 @@ match_oid_in_definitions (const ASN1_ARRAY_TYPE *defs, const gchar *match)
 		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)
+			if ((def->type & 0xFF) != EGG_ASN1X_OBJECT_ID || !def->name)
 				continue;
 
 			/* If we've already seen this one, skip */
@@ -3848,10 +4091,32 @@ match_oid_in_definitions (const ASN1_ARRAY_TYPE *defs, const gchar *match)
 	return result;
 }
 
+static gboolean
+is_oid_number (const gchar *p)
+{
+	gboolean must = TRUE;
+	gint i;
+
+	for (i = 0; p[i] != '\0'; i++) {
+		if (g_ascii_isdigit (p[i])) {
+			must = FALSE;
+		} else if (must) {
+			return FALSE;
+		} else {
+			if (p[i] != '.')
+				return FALSE;
+			must = TRUE;
+		}
+	}
+
+	return !must;
+}
+
 GNode*
-egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *type)
+egg_asn1x_create (const EggAsn1xDef *defs,
+                  const gchar *type)
 {
-	const ASN1_ARRAY_TYPE *def;
+	const EggAsn1xDef *def;
 	GNode *root, *parent, *node;
 	int flags;
 
@@ -3859,7 +4124,7 @@ egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *type)
 	g_return_val_if_fail (type, NULL);
 
 	/* An OID */
-	if (strspn (type, "0123456789.") == strlen (type)) {
+	if (is_oid_number (type)) {
 		def = match_oid_in_definitions (defs, type);
 
 	/* An Identifier */
@@ -3912,15 +4177,17 @@ egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *type)
 }
 
 GNode*
-egg_asn1x_create_quark (const ASN1_ARRAY_TYPE *defs, GQuark type)
+egg_asn1x_create_quark (const EggAsn1xDef *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)
+egg_asn1x_create_and_decode (const EggAsn1xDef *defs,
+                             const gchar *identifier,
+                             EggBytes *data)
 {
 	GNode *asn;
 
@@ -3930,7 +4197,7 @@ egg_asn1x_create_and_decode (const ASN1_ARRAY_TYPE *defs, const gchar *identifie
 	asn = egg_asn1x_create (defs, identifier);
 	g_return_val_if_fail (asn, NULL);
 
-	if (!egg_asn1x_decode (asn, data, n_data)) {
+	if (!egg_asn1x_decode (asn, data)) {
 		egg_asn1x_destroy (asn);
 		return NULL;
 	}
@@ -3945,7 +4212,7 @@ egg_asn1x_create_and_decode (const ASN1_ARRAY_TYPE *defs, const gchar *identifie
 static void
 dump_append_type (GString *output, gint type)
 {
-	#define XX(x) if (type == TYPE_##x) g_string_append (output, #x " ")
+	#define XX(x) if (type == EGG_ASN1X_##x) g_string_append (output, #x " ")
 	XX(CONSTANT); XX(IDENTIFIER); XX(INTEGER); XX(BOOLEAN); XX(SEQUENCE); XX(BIT_STRING);
 	XX(OCTET_STRING); XX(TAG); XX(DEFAULT); XX(SIZE); XX(SEQUENCE_OF); XX(OBJECT_ID); XX(ANY);
 	XX(SET); XX(SET_OF); XX(DEFINITIONS); XX(TIME); XX(CHOICE); XX(IMPORTS); XX(NULL);
@@ -3969,7 +4236,7 @@ dump_append_flags (GString *output, gint flags)
 static gboolean
 traverse_and_dump (GNode *node, gpointer unused)
 {
-	ASN1_ARRAY_TYPE *def;
+	EggAsn1xDef *def;
 	guint i, depth;
 	GString *output;
 	gchar *string;
@@ -4048,7 +4315,7 @@ traverse_and_clear (GNode *node, gpointer unused)
 	anode_clear (node);
 
 	type = anode_def_type (node);
-	if (type == TYPE_SET_OF || type == TYPE_SEQUENCE_OF) {
+	if (type == EGG_ASN1X_SET_OF || type == EGG_ASN1X_SEQUENCE_OF) {
 
 		/* The first 'real' child is the template */
 		child = node->children;
@@ -4156,16 +4423,17 @@ egg_asn1x_parse_time_utc (const gchar *time, gssize n_time)
  */
 
 gssize
-egg_asn1x_element_length (gconstpointer data, gsize n_data)
+egg_asn1x_element_length (const guchar *data,
+                          gsize n_data)
 {
 	guchar cls;
 	int counter = 0;
 	int cb, len;
 	gulong tag;
 
-	if (anode_decode_cls_tag (data, (const guchar*)data + n_data, &cls, &tag, &cb)) {
+	if (anode_decode_cls_tag (data, data + n_data, &cls, &tag, &cb)) {
 		counter += cb;
-		len = anode_decode_length ((const guchar*)data + cb, (const guchar*)data + n_data, &cb);
+		len = anode_decode_length (data + cb, data + n_data, &cb);
 		counter += cb;
 		if (len >= 0) {
 			len += counter;
@@ -4178,7 +4446,9 @@ egg_asn1x_element_length (gconstpointer data, gsize n_data)
 }
 
 gconstpointer
-egg_asn1x_element_content (gconstpointer data, gsize n_data, gsize *n_content)
+egg_asn1x_element_content (const guchar *data,
+                           gsize n_data,
+                           gsize *n_content)
 {
 	int counter = 0;
 	guchar cls;
diff --git a/egg/egg-asn1x.h b/egg/egg-asn1x.h
index 3f74655..50cdfe5 100644
--- a/egg/egg-asn1x.h
+++ b/egg/egg-asn1x.h
@@ -26,44 +26,65 @@
 
 #include <glib.h>
 
+#include "egg-bytes.h"
+
 #ifndef HAVE_EGG_ALLOCATOR
 typedef void* (*EggAllocator) (void* p, gsize);
 #define HAVE_EGG_ALLOCATOR
 #endif
 
-typedef gboolean (*EggAsn1xEncoder) (gpointer data, guchar *buf, gsize n_buf);
-
-struct static_struct_asn;
-
-GNode*              egg_asn1x_create                 (const struct static_struct_asn *defs,
+typedef struct _EggAsn1xDef EggAsn1xDef;
+
+typedef enum {
+	EGG_ASN1X_CONSTANT = 1,
+	EGG_ASN1X_IDENTIFIER = 2,
+	EGG_ASN1X_INTEGER = 3,
+	EGG_ASN1X_BOOLEAN = 4,
+	EGG_ASN1X_SEQUENCE = 5,
+	EGG_ASN1X_BIT_STRING = 6,
+	EGG_ASN1X_OCTET_STRING = 7,
+	EGG_ASN1X_TAG = 8,
+	EGG_ASN1X_DEFAULT = 9,
+	EGG_ASN1X_SIZE = 10,
+	EGG_ASN1X_SEQUENCE_OF = 11,
+	EGG_ASN1X_OBJECT_ID = 12,
+	EGG_ASN1X_ANY = 13,
+	EGG_ASN1X_SET = 14,
+	EGG_ASN1X_SET_OF = 15,
+	EGG_ASN1X_DEFINITIONS = 16,
+	EGG_ASN1X_TIME = 17,
+	EGG_ASN1X_CHOICE = 18,
+	EGG_ASN1X_IMPORTS = 19,
+	EGG_ASN1X_NULL = 20,
+	EGG_ASN1X_ENUMERATED = 21,
+	EGG_ASN1X_GENERALSTRING = 27
+} EggAsn1xType;
+
+GNode*              egg_asn1x_create                 (const EggAsn1xDef *defs,
                                                       const gchar *type);
 
-GNode*              egg_asn1x_create_quark           (const struct static_struct_asn *defs,
+GNode*              egg_asn1x_create_quark           (const EggAsn1xDef *defs,
                                                       GQuark type);
 
-GNode*              egg_asn1x_create_and_decode      (const struct static_struct_asn *defs,
+GNode*              egg_asn1x_create_and_decode      (const EggAsn1xDef *defs,
                                                       const gchar *type,
-                                                      gconstpointer data,
-                                                      gsize n_data);
+                                                      EggBytes *data);
 
 void                egg_asn1x_dump                   (GNode *asn);
 
 void                egg_asn1x_clear                  (GNode *asn);
 
 gboolean            egg_asn1x_decode                 (GNode *asn,
-                                                      gconstpointer data,
-                                                      gsize n_data);
+                                                      EggBytes *data);
 
 gboolean            egg_asn1x_decode_no_validate     (GNode *asn,
-                                                      gconstpointer data,
-                                                      gsize n_data);
+                                                      EggBytes *data);
 
 gboolean            egg_asn1x_validate               (GNode *asn,
                                                       gboolean strict);
 
-gpointer            egg_asn1x_encode                 (GNode *asn,
-                                                      EggAllocator allocator,
-                                                      gsize *n_data);
+EggBytes *          egg_asn1x_encode                 (GNode *asn,
+                                                      EggAllocator allocator);
 
 const gchar*        egg_asn1x_message                (GNode *asn);
 
@@ -72,6 +93,8 @@ GNode*              egg_asn1x_node                   (GNode *asn,
 
 const gchar*        egg_asn1x_name                   (GNode *asn);
 
+EggAsn1xType        egg_asn1x_type                   (GNode *asn);
+
 guint               egg_asn1x_count                  (GNode *node);
 
 GNode*              egg_asn1x_append                 (GNode *node);
@@ -102,38 +125,28 @@ gboolean            egg_asn1x_get_integer_as_ulong   (GNode *node,
 gboolean            egg_asn1x_set_integer_as_ulong   (GNode *node,
                                                       gulong value);
 
-gconstpointer       egg_asn1x_get_integer_as_raw     (GNode *node,
-                                                      gsize *n_data);
+EggBytes *          egg_asn1x_get_integer_as_raw     (GNode *node);
 
-gboolean            egg_asn1x_set_integer_as_raw     (GNode *node,
-                                                      gconstpointer data,
-                                                      gsize n_data,
-                                                      GDestroyNotify destroy);
+void                egg_asn1x_set_integer_as_raw     (GNode *node,
+                                                      EggBytes *value);
 
-gconstpointer       egg_asn1x_get_integer_as_usg     (GNode *node,
-                                                      gsize *n_data);
+void                egg_asn1x_take_integer_as_raw    (GNode *node,
+                                                      EggBytes *value);
 
-gboolean            egg_asn1x_set_integer_as_usg     (GNode *node,
-                                                      gconstpointer data,
-                                                      gsize n_data,
-                                                      GDestroyNotify destroy);
+EggBytes *          egg_asn1x_get_integer_as_usg     (GNode *node);
 
-gconstpointer       egg_asn1x_get_raw_value          (GNode *node,
-                                                      gsize *n_content);
+void                egg_asn1x_set_integer_as_usg     (GNode *node,
+                                                      EggBytes *value);
 
-gboolean            egg_asn1x_set_raw_value          (GNode *node,
-                                                      gsize length,
-                                                      EggAsn1xEncoder encoder,
-                                                      gpointer user_data,
-                                                      GDestroyNotify destroy);
+void                egg_asn1x_take_integer_as_usg    (GNode *node,
+                                                      EggBytes *value);
 
-gconstpointer       egg_asn1x_get_raw_element        (GNode *node,
-                                                      gsize *n_data);
+EggBytes *          egg_asn1x_get_raw_value          (GNode *node);
 
-gboolean            egg_asn1x_set_raw_element        (GNode *node,
-                                                      gpointer user_data,
-                                                      gsize n_data,
-                                                      GDestroyNotify destroy);
+EggBytes *          egg_asn1x_get_element_raw        (GNode *node);
+
+gboolean            egg_asn1x_set_element_raw        (GNode *node,
+                                                      EggBytes *value);
 
 guchar*             egg_asn1x_get_string_as_raw      (GNode *node,
                                                       EggAllocator allocator,
@@ -144,14 +157,21 @@ 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,
+EggBytes *          egg_asn1x_get_string_as_bytes    (GNode *node);
+
+gboolean            egg_asn1x_set_string_as_bytes    (GNode *node,
+                                                      EggBytes *data);
+
+EggBytes *          egg_asn1x_get_bits_as_raw        (GNode *node,
                                                       guint *n_bits);
 
-gboolean            egg_asn1x_set_bits_as_raw        (GNode *node,
-                                                      guchar *data,
-                                                      guint n_bits,
-                                                      GDestroyNotify destroy);
+void                egg_asn1x_set_bits_as_raw        (GNode *node,
+                                                      EggBytes *value,
+                                                      guint n_bits);
+
+void                egg_asn1x_take_bits_as_raw       (GNode *node,
+                                                      EggBytes *value,
+                                                      guint n_bits);
 
 gboolean            egg_asn1x_get_bits_as_ulong      (GNode *node,
                                                       gulong *value,
@@ -161,7 +181,7 @@ gboolean            egg_asn1x_set_bits_as_ulong      (GNode *node,
                                                       gulong value,
                                                       guint n_bits);
 
-gchar*              egg_asn1x_get_string_as_utf8     (GNode *node,
+gchar *             egg_asn1x_get_string_as_utf8     (GNode *node,
                                                       EggAllocator allocator);
 
 gboolean            egg_asn1x_set_string_as_utf8     (GNode *node,
@@ -186,7 +206,7 @@ GQuark              egg_asn1x_get_oid_as_quark       (GNode *node);
 gboolean            egg_asn1x_set_oid_as_quark       (GNode *node,
                                                       GQuark oid);
 
-gchar*              egg_asn1x_get_oid_as_string      (GNode *node);
+gchar *             egg_asn1x_get_oid_as_string      (GNode *node);
 
 gboolean            egg_asn1x_set_oid_as_string      (GNode *node,
                                                       const gchar *oid);
@@ -199,10 +219,10 @@ glong               egg_asn1x_parse_time_general     (const gchar *time,
 glong               egg_asn1x_parse_time_utc         (const gchar *time,
                                                       gssize n_time);
 
-gssize              egg_asn1x_element_length         (gconstpointer data,
+gssize              egg_asn1x_element_length         (const guchar *data,
                                                       gsize n_data);
 
-gconstpointer       egg_asn1x_element_content        (gconstpointer data,
+gconstpointer       egg_asn1x_element_content        (const guchar *data,
                                                       gsize n_data,
                                                       gsize *n_content);
 
diff --git a/egg/egg-bytes.c b/egg/egg-bytes.c
new file mode 100644
index 0000000..8f58da2
--- /dev/null
+++ b/egg/egg-bytes.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright  2009, 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include "egg-bytes.h"
+
+#include <glib.h>
+
+#include <string.h>
+
+struct _EggBytes
+{
+  gconstpointer data;
+  gsize size;
+  gint ref_count;
+  GDestroyNotify free_func;
+  gpointer user_data;
+};
+
+/**
+ * egg_bytes_new:
+ * @data: (array length=size): the data to be used for the bytes
+ * @size: the size of @data
+ *
+ * Creates a new #EggBytes from @data.
+ *
+ * @data is copied.
+ *
+ * Returns: (transfer full): a new #EggBytes
+ *
+ * Since: 2.32
+ */
+EggBytes *
+egg_bytes_new (gconstpointer data,
+             gsize         size)
+{
+  return egg_bytes_new_take (g_memdup (data, size), size);
+}
+
+/**
+ * egg_bytes_new_take:
+ * @data: (transfer full) (array length=size): the data to be used for the bytes
+ * @size: the size of @data
+ *
+ * Creates a new #EggBytes from @data.
+ *
+ * After this call, @data belongs to the bytes and may no longer be
+ * modified by the caller.  g_free() will be called on @data when the
+ * bytes is no longer in use. Because of this @data must have been created by
+ * a call to g_malloc(), g_malloc0() or g_realloc() or by one of the many
+ * functions that wrap these calls (such as g_new(), g_strdup(), etc).
+ *
+ * Returns: (transfer full): a new #EggBytes
+ *
+ * Since: 2.32
+ */
+EggBytes *
+egg_bytes_new_take (gpointer data,
+                  gsize    size)
+{
+  return egg_bytes_new_with_free_func (data, size, g_free, data);
+}
+
+
+/**
+ * egg_bytes_new_static:
+ * @data: (array length=size): the data to be used for the bytes
+ * @size: the size of @data
+ *
+ * Creates a new #EggBytes from static data.
+ *
+ * @data must be static (ie: never modified or freed).
+ *
+ * Returns: (transfer full): a new #EggBytes
+ *
+ * Since: 2.32
+ */
+EggBytes *
+egg_bytes_new_static (gconstpointer data,
+                    gsize         size)
+{
+  return egg_bytes_new_with_free_func (data, size, NULL, NULL);
+}
+
+/**
+ * egg_bytes_new_with_free_func:
+ * @data: (array length=size): the data to be used for the bytes
+ * @size: the size of @data
+ * @free_func: the function to call to release the data
+ * @user_data: data to pass to @free_func
+ *
+ * Creates a #EggBytes from @data.
+ *
+ * When the last reference is dropped, @free_func will be called with the
+ * @user_data argument.
+ *
+ * @data must not be modified after this call is made until @free_func has
+ * been called to indicate that the bytes is no longer in use.
+ *
+ * Returns: (transfer full): a new #EggBytes
+ *
+ * Since: 2.32
+ */
+EggBytes *
+egg_bytes_new_with_free_func (gconstpointer  data,
+                            gsize          size,
+                            GDestroyNotify free_func,
+                            gpointer       user_data)
+{
+  EggBytes *bytes;
+
+  bytes = g_slice_new (EggBytes);
+  bytes->data = data;
+  bytes->size = size;
+  bytes->free_func = free_func;
+  bytes->user_data = user_data;
+  bytes->ref_count = 1;
+
+  return (EggBytes *)bytes;
+}
+
+/**
+ * egg_bytes_new_from_bytes:
+ * @bytes: a #EggBytes
+ * @offset: offset which subsection starts at
+ * @length: length of subsucsection
+ *
+ * Creates a #EggBytes which is a subsection of another #EggBytes.
+ *
+ * A reference to @bytes will be held by the newly created #EggBytes until
+ * the byte data is no longer needed.
+ *
+ * Returns: (transfer full): a new #EggBytes
+ *
+ * Since: 2.32
+ */
+EggBytes *
+egg_bytes_new_from_bytes (EggBytes  *bytes,
+                        goffset  offset,
+                        gsize    length)
+{
+  g_return_val_if_fail (bytes != NULL, NULL);
+  g_return_val_if_fail (offset <= bytes->size, NULL);
+  g_return_val_if_fail (offset + length <= bytes->size, NULL);
+
+  return egg_bytes_new_with_free_func ((gchar *)bytes->data + offset, length,
+                                     egg_bytes_unref, egg_bytes_ref (bytes));
+}
+
+/**
+ * egg_bytes_get_data:
+ * @bytes: a #EggBytes
+ *
+ * Get the byte data in the #EggBytes. This data should not be modified.
+ *
+ * This function will always return the same pointer for a given #EggBytes.
+ *
+ * Returns: a pointer to the byte data
+ *
+ * Since: 2.32
+ */
+gconstpointer
+egg_bytes_get_data (EggBytes *bytes)
+{
+  g_return_val_if_fail (bytes != NULL, NULL);
+  return bytes->data;
+}
+
+/**
+ * egg_bytes_get_size:
+ * @bytes: a #EggBytes
+ *
+ * Get the size of the byte data in the #EggBytes.
+ *
+ * This function will always return the same value for a given #EggBytes.
+ *
+ * Returns: the size
+ *
+ * Since: 2.32
+ */
+gsize
+egg_bytes_get_size (EggBytes *bytes)
+{
+  g_return_val_if_fail (bytes != NULL, 0);
+  return bytes->size;
+}
+
+
+/**
+ * egg_bytes_ref:
+ * @bytes: a #EggBytes
+ *
+ * Increase the reference count on @bytes.
+ *
+ * Returns: (transfer full): the #EggBytes
+ *
+ * Since: 2.32
+ */
+EggBytes *
+egg_bytes_ref (EggBytes *bytes)
+{
+  g_return_val_if_fail (bytes != NULL, NULL);
+
+  g_atomic_int_inc (&bytes->ref_count);
+
+  return bytes;
+}
+
+/**
+ * egg_bytes_unref:
+ * @bytes: (transfer full) (type GLib.Bytes): a #EggBytes
+ *
+ * Releases a reference on @bytes.  This may result in the bytes being
+ * freed.
+ *
+ * Since: 2.32
+ */
+void
+egg_bytes_unref (gpointer bytes)
+{
+  EggBytes *bytes_ = bytes;
+
+  g_return_if_fail (bytes_ != NULL);
+
+  if (g_atomic_int_dec_and_test (&bytes_->ref_count))
+    {
+      if (bytes_->free_func != NULL)
+        bytes_->free_func (bytes_->user_data);
+      g_slice_free (EggBytes, bytes);
+    }
+}
+
+/**
+ * egg_bytes_equal:
+ * @bytes1: (type GLib.Bytes): a pointer to a #EggBytes
+ * @bytes2: (type GLib.Bytes): a pointer to a #EggBytes to compare with @bytes1
+ *
+ * Compares the two #EggBytes values being pointed to and returns
+ * %TRUE if they are equal.
+ *
+ * This function can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using non-%NULL #EggBytes pointers as keys in a #GHashTable.
+ *
+ * Returns: %TRUE if the two keys match.
+ *
+ * Since: 2.32
+ */
+gboolean
+egg_bytes_equal (gconstpointer bytes1,
+               gconstpointer bytes2)
+{
+  const EggBytes *b1 = bytes1;
+  const EggBytes *b2 = bytes2;
+
+  g_return_val_if_fail (bytes1 != NULL, FALSE);
+  g_return_val_if_fail (bytes2 != NULL, FALSE);
+
+  return b1->size == b2->size &&
+         memcmp (b1->data, b2->data, b1->size) == 0;
+}
+
+/**
+ * egg_bytes_hash:
+ * @bytes: (type GLib.Bytes): a pointer to a #EggBytes key
+ *
+ * Creates an integer hash code for the byte data in the #EggBytes.
+ *
+ * This function can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using non-%NULL #EggBytes pointers as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key.
+ *
+ * Since: 2.32
+ */
+guint
+egg_bytes_hash (gconstpointer bytes)
+{
+  const EggBytes *a = bytes;
+  const signed char *p, *e;
+  guint32 h = 5381;
+
+  g_return_val_if_fail (bytes != NULL, 0);
+
+  for (p = (signed char *)a->data, e = (signed char *)a->data + a->size; p != e; p++)
+    h = (h << 5) + h + *p;
+
+  return h;
+}
+
+/**
+ * egg_bytes_compare:
+ * @bytes1: (type GLib.Bytes): a pointer to a #EggBytes
+ * @bytes2: (type GLib.Bytes): a pointer to a #EggBytes to compare with @bytes1
+ *
+ * Compares the two #EggBytes values.
+ *
+ * This function can be passed to g_tree_new() when using non-%NULL #EggBytes
+ * pointers as keys in a #GTree.
+ *
+ * Returns: a negative value if bytes2 is lesser, a positive value if bytes2 is
+ *          greater, and zero if bytes2 is equal to bytes1
+ *
+ * Since: 2.32
+ */
+gint
+egg_bytes_compare (gconstpointer bytes1,
+                 gconstpointer bytes2)
+{
+  const EggBytes *b1 = bytes1;
+  const EggBytes *b2 = bytes2;
+  gint ret;
+
+  g_return_val_if_fail (bytes1 != NULL, 0);
+  g_return_val_if_fail (bytes2 != NULL, 0);
+
+  ret = memcmp (b1->data, b2->data, MIN (b1->size, b2->size));
+  if (ret == 0 && b1->size != b2->size)
+      ret = b1->size < b2->size ? -1 : 1;
+  return ret;
+}
+
+/**
+ * egg_bytes_unref_to_array:
+ * @bytes: (transfer full): a #EggBytes
+ *
+ * Unreferences the bytes, and returns a new mutable #GByteArray containing
+ * the same byte data.
+ *
+ * As an optimization, the byte data is transferred to the array without copying
+ * if: this was the last reference to bytes and bytes was created with
+ * egg_bytes_new(), egg_bytes_new_take() or g_byte_array_free_to_bytes(). In all
+ * other cases the data is copied.
+ *
+ * Returns: (transfer full): a new mutable #GByteArray containing the same byte data
+ *
+ * Since: 2.32
+ */
+GByteArray *
+egg_bytes_unref_to_array (EggBytes *bytes)
+{
+  GByteArray *result = NULL;
+#if 0
+  gpointer data;
+  gsize size;
+#endif
+
+  g_return_val_if_fail (bytes != NULL, NULL);
+
+#if 0
+  data = egg_bytes_try_steal_and_unref (bytes, NULL, &size);
+  if (data != NULL)
+    {
+      /*
+       * Optimal path: if this is was the last reference, then we can have
+       * the GByteArray assume the data from this EggBytes without copying.
+       */
+      result = g_byte_array_new_take (data, size);
+    }
+  else
+#endif
+    {
+      /*
+       * Copy: Non g_malloc (or compatible) allocator, or static memory,
+       * so we have to copy, and then unref.
+       */
+      result = g_byte_array_append (g_byte_array_new (), bytes->data, bytes->size);
+      egg_bytes_unref (bytes);
+    }
+
+  return result;
+}
+
+/*
+ * The behavior of this function with regards to references cannot be easily
+ * modeled by most gobject-introspection consumers, so we use (skip).
+ */
+
+/**
+ * egg_bytes_try_steal_and_unref: (skip)
+ * @bytes: a #EggBytes
+ * @free_func: the function data is freed with, or %NULL for default
+ * @size: location to return the length of the data
+ *
+ * This is an advanced function, and seldom used.
+ *
+ * Try to take ownership of the data in the byte array. This is only successful
+ * if this is the last reference and @free_func matches the function that would
+ * have been used to free the data. This is to demonstrate that the caller
+ * is aware of the how the data in the #EggBytes was allocated. If %NULL is passed
+ * for @free_func this represents the standard Glib allocation routines.
+ *
+ * You should use %NULL instead of passing g_free() for @free_func. This is
+ * because the actual address of g_free() varies depending on how the calling
+ * application and library was linked.
+ *
+ * If the attempt to take ownership of the byte data is successful according to
+ * the above criteria, then the data is returned and @size is set to the length
+ * of the data. The #EggBytes is unreferenced and is no longer valid.
+ *
+ * If the attempt to take ownership of the byte data is unsuccessful, %NULL is
+ * returned. The #EggBytes is not unreferenced, and the caller must unreference
+ * the #EggBytes elsewhere.
+ *
+ * It is always incorrect to ignore the return value from this function.
+ *
+ * Returns: the stolen data, or %NULL if attempt failed
+ *
+ * Since: 2.32
+ */
+gpointer
+egg_bytes_try_steal_and_unref (EggBytes         *bytes,
+                             GDestroyNotify  free_func,
+                             gsize          *size)
+{
+  gpointer result;
+
+  g_return_val_if_fail (bytes != NULL, NULL);
+  g_return_val_if_fail (size != NULL, NULL);
+
+  if (free_func == NULL)
+    free_func = g_free;
+  if (bytes->free_func != free_func)
+    return NULL;
+
+  /* Are we the only reference? */
+  if (g_atomic_int_get (&bytes->ref_count) == 1)
+    {
+      *size = bytes->size;
+      result = (gpointer)bytes->data;
+      g_slice_free (EggBytes, bytes);
+      return result;
+    }
+
+  return NULL;
+}
diff --git a/egg/egg-bytes.h b/egg/egg-bytes.h
new file mode 100644
index 0000000..d25432f
--- /dev/null
+++ b/egg/egg-bytes.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright  2009, 2010 Codethink Limited
+ * Copyright  2011 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ *         Stef Walter <stefw collabora co uk>
+ */
+
+#ifndef __EGG_BYTES_H__
+#define __EGG_BYTES_H__
+
+#include <glib.h>
+
+/**
+ * EggBytes:
+ *
+ * A simple refcounted data type representing an immutable byte sequence
+ * from an unspecified origin.
+ *
+ * The purpose of a #EggBytes is to keep the memory region that it holds
+ * alive for as long as anyone holds a reference to the bytes.  When
+ * the last reference count is dropped, the memory is released. Multiple
+ * unrelated callers can use byte data in the #EggBytes without coordinating
+ * their activities, resting assured that the byte data will not change or
+ * move while they hold a reference.
+ *
+ * A #EggBytes can come from many different origins that may have
+ * different procedures for freeing the memory region.  Examples are
+ * memory from g_malloc(), from memory slices, from a #GMappedFile or
+ * memory from other allocators.
+ *
+ * #EggBytes work well as keys in #GHashTable. Use egg_bytes_equal() and
+ * egg_bytes_hash() as parameters to g_hash_table_new() or g_hash_table_new_full().
+ * #EggBytes can also be used as keys in a #GTree by passing the egg_bytes_compare()
+ * function to g_tree_new().
+ *
+ * The data pointed to by this bytes must not be modified. For a mutable
+ * array of bytes see #GByteArray. Use egg_bytes_unref_to_array() to create a
+ * mutable array for a #EggBytes sequence. To create an immutable #EggBytes from
+ * a mutable #GByteArray, use the g_byte_array_free_to_bytes() function.
+ *
+ * Since: 2.32
+ **/
+
+typedef struct _EggBytes EggBytes;
+
+EggBytes *        egg_bytes_new                     (gconstpointer   data,
+                                                 gsize           size);
+
+EggBytes *        egg_bytes_new_take                (gpointer        data,
+                                                 gsize           size);
+
+EggBytes *        egg_bytes_new_static              (gconstpointer   data,
+                                                 gsize           size);
+
+EggBytes *        egg_bytes_new_with_free_func      (gconstpointer   data,
+                                                 gsize           size,
+                                                 GDestroyNotify  free_func,
+                                                 gpointer        user_data);
+
+EggBytes *        egg_bytes_new_from_bytes          (EggBytes         *bytes,
+                                                 goffset         offset,
+                                                 gsize           length);
+
+gconstpointer   egg_bytes_get_data                (EggBytes         *bytes);
+
+gsize           egg_bytes_get_size                (EggBytes         *bytes);
+
+EggBytes *        egg_bytes_ref                     (EggBytes         *bytes);
+
+void            egg_bytes_unref                   (gpointer        bytes);
+
+GByteArray *    egg_bytes_unref_to_array          (EggBytes         *bytes);
+
+gpointer        egg_bytes_try_steal_and_unref     (EggBytes         *bytes,
+                                                 GDestroyNotify  free_func,
+                                                 gsize          *size);
+
+guint           egg_bytes_hash                    (gconstpointer   bytes);
+
+gboolean        egg_bytes_equal                   (gconstpointer   bytes1,
+                                                 gconstpointer   bytes2);
+
+gint            egg_bytes_compare                 (gconstpointer   bytes1,
+                                                 gconstpointer   bytes2);
+
+#endif /* __EGG_BYTES_H__ */
diff --git a/egg/egg-dn.c b/egg/egg-dn.c
index b41844e..2ec5751 100644
--- a/egg/egg-dn.c
+++ b/egg/egg-dn.c
@@ -33,13 +33,15 @@
 static const char HEXC[] = "0123456789ABCDEF";
 
 static gchar*
-dn_print_hex_value (const guchar *data, gsize len)
+dn_print_hex_value (EggBytes *val)
 {
-	GString *result = g_string_sized_new (len * 2 + 1);
+	const gchar *data = egg_bytes_get_data (val);
+	gsize size = egg_bytes_get_size (val);
+	GString *result = g_string_sized_new (size * 2 + 1);
 	gsize i;
 
 	g_string_append_c (result, '#');
-	for (i = 0; i < len; ++i) {
+	for (i = 0; i < size; ++i) {
 		g_string_append_c (result, HEXC[data[i] >> 4 & 0xf]);
 		g_string_append_c (result, HEXC[data[i] & 0xf]);
 	}
@@ -48,20 +50,22 @@ 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)
+dn_print_oid_value_parsed (GQuark oid,
+                           guint flags,
+                           EggBytes *val)
 {
 	GNode *asn1, *node;
-	gconstpointer value;
-	gsize n_value;
+	EggBytes *value;
+	const gchar *data;
+	gsize size;
 	gchar *result;
 
-	g_assert (data);
-	g_assert (len);
+	g_assert (val != NULL);
 
 	asn1 = egg_asn1x_create_quark (pkix_asn1_tab, oid);
 	g_return_val_if_fail (asn1, NULL);
 
-	if (!egg_asn1x_decode (asn1, data, len)) {
+	if (!egg_asn1x_decode (asn1, val)) {
 		g_message ("couldn't decode value for OID: %s: %s",
 		           g_quark_to_string (oid), egg_asn1x_message (asn1));
 		egg_asn1x_destroy (asn1);
@@ -77,7 +81,9 @@ dn_print_oid_value_parsed (GQuark oid, guint flags, const guchar *data, gsize le
 	else
 		node = asn1;
 
-	value = egg_asn1x_get_raw_value (node, &n_value);
+	value = egg_asn1x_get_raw_value (node);
+	data = egg_bytes_get_data (value);
+	size = egg_bytes_get_size (value);
 
 	/*
 	 * Now we make sure it's UTF-8.
@@ -87,33 +93,35 @@ dn_print_oid_value_parsed (GQuark oid, guint flags, const guchar *data, gsize le
 		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 if (!g_utf8_validate (data, size, NULL)) {
+		result = dn_print_hex_value (value);
 
 	} else {
-		result = g_strndup (value, n_value);
+		result = g_strndup (data, size);
 	}
 
+	egg_bytes_unref (value);
 	egg_asn1x_destroy (asn1);
 
 	return result;
 }
 
 static gchar*
-dn_print_oid_value (GQuark oid, guint flags, const guchar *data, gsize len)
+dn_print_oid_value (GQuark oid,
+                    guint flags,
+                    EggBytes *val)
 {
 	gchar *value;
 
-	g_assert (data);
-	g_assert (len);
+	g_assert (val != NULL);
 
 	if (flags & EGG_OID_PRINTABLE) {
-		value = dn_print_oid_value_parsed (oid, flags, data, len);
+		value = dn_print_oid_value_parsed (oid, flags, val);
 		if (value != NULL)
 			return value;
 	}
 
-	return dn_print_hex_value (data, len);
+	return dn_print_hex_value (val);
 }
 
 static gchar*
@@ -122,8 +130,7 @@ dn_parse_rdn (GNode *asn)
 	const gchar *name;
 	guint flags;
 	GQuark oid;
-	gconstpointer value;
-	gsize n_value;
+	EggBytes *value;
 	gchar *display;
 	gchar *result;
 
@@ -135,14 +142,15 @@ dn_parse_rdn (GNode *asn)
 	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);
+	value = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "value", NULL));
 	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);
 	result = g_strconcat ((flags & EGG_OID_PRINTABLE) ? name : g_quark_to_string (oid),
 	                      "=", display, NULL);
 	g_free (display);
 
+	egg_bytes_unref (value);
 	return result;
 }
 
@@ -193,11 +201,11 @@ egg_dn_read_part (GNode *asn, const gchar *match)
 {
 	gboolean done = FALSE;
 	const gchar *name;
-	gconstpointer value;
-	gsize n_value;
+	EggBytes *value;
 	GNode *node;
 	GQuark oid;
 	gint i, j;
+	gchar *result;
 
 	g_return_val_if_fail (asn, NULL);
 	g_return_val_if_fail (match, NULL);
@@ -226,10 +234,12 @@ egg_dn_read_part (GNode *asn, const gchar *match)
 			node = egg_asn1x_node (asn, i, j, "value", NULL);
 			g_return_val_if_fail (node, NULL);
 
-			value = egg_asn1x_get_raw_element (node, &n_value);
+			value = egg_asn1x_get_element_raw (node);
 			g_return_val_if_fail (value, NULL);
 
-			return dn_print_oid_value (oid, egg_oid_get_flags (oid), value, n_value);
+			result = dn_print_oid_value (oid, egg_oid_get_flags (oid), value);
+			egg_bytes_unref (value);
+			return result;
 		}
 	}
 
@@ -241,8 +251,7 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
 {
 	gboolean done = FALSE;
 	GNode *node;
-	gconstpointer value;
-	gsize n_value;
+	EggBytes *value;
 	GQuark oid;
 	guint i, j;
 
@@ -271,21 +280,109 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
 				break;
 			}
 
-			value = egg_asn1x_get_raw_element (node, &n_value);
+			value = egg_asn1x_get_element_raw (node);
 
 			if (callback)
-				(callback) (i, oid, value, n_value, user_data);
+				(callback) (i, oid, value, user_data);
+
+			egg_bytes_unref (value);
 		}
 	}
 
 	return i > 1;
 }
 
-gchar*
-egg_dn_print_value (GQuark oid, const guchar *value, gsize n_value)
+gchar *
+egg_dn_print_value (GQuark oid,
+                    EggBytes *value)
 {
-	g_return_val_if_fail (oid, NULL);
-	g_return_val_if_fail (value || !n_value, NULL);
+	g_return_val_if_fail (oid != 0, NULL);
+	g_return_val_if_fail (value != NULL, NULL);
+
+	return dn_print_oid_value (oid, egg_oid_get_flags (oid), value);
+}
+
+static gboolean
+is_ascii_string (const gchar *string)
+{
+	const gchar *p = string;
+
+	g_return_val_if_fail (string != NULL, FALSE);
+
+	for (p = string; *p != '\0'; p++) {
+		if (!g_ascii_isspace (*p) && *p < ' ')
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+is_printable_string (const gchar *string)
+{
+	const gchar *p = string;
+
+	g_return_val_if_fail (string != NULL, FALSE);
+
+	for (p = string; *p != '\0'; p++) {
+		if (!g_ascii_isalnum (*p) && !strchr (" '()+,-./:=?", *p))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+void
+egg_dn_add_string_part (GNode *asn,
+                        GQuark oid,
+                        const gchar *string)
+{
+	EggBytes *bytes;
+	GNode *node;
+	GNode *value;
+	GNode *val;
+	guint flags;
+
+	g_return_if_fail (asn != NULL);
+	g_return_if_fail (oid != 0);
+	g_return_if_fail (string != NULL);
+
+	flags = egg_oid_get_flags (oid);
+	g_return_if_fail (flags & EGG_OID_PRINTABLE);
+
+	/* Add the RelativeDistinguishedName */
+	node = egg_asn1x_append (asn);
+
+	/* Add the AttributeTypeAndValue */
+	node = egg_asn1x_append (node);
+
+	egg_asn1x_set_oid_as_quark (egg_asn1x_node (node, "type", NULL), oid);
+
+	value = egg_asn1x_create_quark (pkix_asn1_tab, oid);
+
+	if (egg_asn1x_type (value) == EGG_ASN1X_CHOICE) {
+		if (is_printable_string (string))
+			val = egg_asn1x_node (value, "printableString", NULL);
+		else if (is_ascii_string (string))
+			val = egg_asn1x_node (value, "ia5String", NULL);
+		else
+			val = egg_asn1x_node (value, "utf8String", NULL);
+		egg_asn1x_set_choice (value, val);
+	} else {
+		val = value;
+	}
+
+	egg_asn1x_set_string_as_utf8 (val, g_strdup (string), g_free);
+
+	bytes = egg_asn1x_encode (value, NULL);
+	if (bytes == NULL) {
+		g_warning ("couldn't build dn string value: %s", egg_asn1x_message (value));
+		return;
+	}
+
+	if (!egg_asn1x_set_element_raw (egg_asn1x_node (node, "value", NULL), bytes))
+		g_return_if_reached ();
 
-	return dn_print_oid_value (oid, egg_oid_get_flags (oid), value, n_value);
+	egg_asn1x_destroy (value);
+	egg_bytes_unref (bytes);
 }
diff --git a/egg/egg-dn.h b/egg/egg-dn.h
index 96fe5ff..08251ec 100644
--- a/egg/egg-dn.h
+++ b/egg/egg-dn.h
@@ -26,6 +26,8 @@
 
 #include <glib.h>
 
+#include "egg/egg-bytes.h"
+
 gchar*             egg_dn_read                            (GNode *node);
 
 gchar*             egg_dn_read_part                       (GNode *node,
@@ -33,8 +35,7 @@ gchar*             egg_dn_read_part                       (GNode *node,
 
 typedef void       (*EggDnCallback)                       (guint index,
                                                            GQuark oid,
-                                                           const guchar *value,
-                                                           gsize n_value,
+                                                           EggBytes *value,
                                                            gpointer user_data);
 
 gboolean           egg_dn_parse                           (GNode *node,
@@ -42,7 +43,10 @@ gboolean           egg_dn_parse                           (GNode *node,
                                                            gpointer user_data);
 
 gchar*             egg_dn_print_value                     (GQuark oid,
-                                                           const guchar *value,
-                                                           gsize n_value);
+                                                           EggBytes *value);
+
+void               egg_dn_add_string_part                 (GNode *node,
+                                                           GQuark oid,
+                                                           const gchar *string);
 
 #endif /* EGG_DN_H_ */
diff --git a/egg/egg-openssl.c b/egg/egg-openssl.c
index 352451f..2433f07 100644
--- a/egg/egg-openssl.c
+++ b/egg/egg-openssl.c
@@ -55,8 +55,8 @@ static const struct {
 	/* DES-EDE-CFB1 */
 	/* DES-EDE-CFB8 */
 	/* DES-EDE-OFB */
-	/* DES-EDE3 */ 
-	{ "DES-EDE3-ECB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB }, 
+	/* DES-EDE3 */
+	{ "DES-EDE3-ECB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB },
 	{ "DES-EDE3-CFB64", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
 	{ "DES-EDE3-CFB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
 	/* DES-EDE3-CFB1 */
@@ -87,7 +87,7 @@ static const struct {
 	{ "CAST5-CFB64", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
 	{ "CAST5-CFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
 	{ "CAST5-OFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_OFB },
-	/* RC5-32-12-16-CBC */ 
+	/* RC5-32-12-16-CBC */
 	/* RC5-32-12-16-ECB */
 	/* RC5-32-12-16-CFB64  RC5-32-12-16-CFB */
 	/* RC5-32-12-16-OFB */
@@ -150,7 +150,7 @@ egg_openssl_parse_algo (const char *name, int *mode)
 			openssl_quarks[i] = g_quark_from_static_string (openssl_algos[i].desc);
 		g_once_init_leave (&openssl_quarks_inited, 1);
 	}
-	
+
 	q = g_quark_try_string (name);
 	if (q) {
 		for (i = 0; i < G_N_ELEMENTS(openssl_algos); ++i) {
@@ -160,7 +160,7 @@ egg_openssl_parse_algo (const char *name, int *mode)
 			}
 		}
 	}
-	
+
 	return 0;
 }
 
@@ -171,16 +171,16 @@ parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv)
 	gchar **parts = NULL;
 	gcry_error_t gcry;
 	gsize ivlen, len;
-	
+
 	parts = g_strsplit (dek, ",", 2);
-	if (!parts || !parts[0] || !parts[1]) 
+	if (!parts || !parts[0] || !parts[1])
 		goto done;
-		
+
 	/* Parse the algorithm name */
 	*algo = egg_openssl_parse_algo (parts[0], mode);
 	if (!*algo)
 		goto done;
-	
+
 	/* Make sure this is usable */
 	gcry = gcry_cipher_test_algo (*algo);
 	if (gcry)
@@ -188,13 +188,13 @@ parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv)
 
 	/* Parse the IV */
 	ivlen = gcry_cipher_get_algo_blklen (*algo);
-	
+
 	*iv = egg_hex_decode (parts[1], strlen(parts[1]), &len);
 	if (!*iv || ivlen != len) {
 		g_free (*iv);
 		goto done;
 	}
-		
+
 	success = TRUE;
 
 done:
@@ -202,10 +202,12 @@ done:
 	return success;
 }
 
-gboolean
-egg_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, 
-                           gssize n_password, const guchar *data, gsize n_data, 
-                           guchar **decrypted, gsize *n_decrypted)
+guchar *
+egg_openssl_decrypt_block (const gchar *dekinfo,
+                           const gchar *password,
+                           gssize n_password,
+                           EggBytes *data,
+                           gsize *n_decrypted)
 {
 	gcry_cipher_hd_t ch;
 	guchar *key = NULL;
@@ -213,54 +215,58 @@ egg_openssl_decrypt_block (const gchar *dekinfo, const gchar *password,
 	int gcry, ivlen;
 	int algo = 0;
 	int mode = 0;
-	
+	guchar *decrypted;
+
 	if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
 		return FALSE;
-		
+
 	ivlen = gcry_cipher_get_algo_blklen (algo);
 
 	/* We assume the iv is at least as long as at 8 byte salt */
 	g_return_val_if_fail (ivlen >= 8, FALSE);
-	
+
 	/* IV is already set from the DEK info */
-	if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password, 
-	                                        n_password, iv, 8, 1, &key, NULL)) {
+	if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password,
+	                                 n_password, iv, 8, 1, &key, NULL)) {
 		g_free (iv);
-		return FALSE;
+		return NULL;
 	}
-	
-	/* TODO: Use secure memory */
+
 	gcry = gcry_cipher_open (&ch, algo, mode, 0);
-	g_return_val_if_fail (!gcry, FALSE);
-		
+	g_return_val_if_fail (!gcry, NULL);
+
 	gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
-	g_return_val_if_fail (!gcry, FALSE);
+	g_return_val_if_fail (!gcry, NULL);
 	egg_secure_free (key);
 
 	/* 16 = 128 bits */
 	gcry = gcry_cipher_setiv (ch, iv, ivlen);
-	g_return_val_if_fail (!gcry, FALSE);
+	g_return_val_if_fail (!gcry, NULL);
 	g_free (iv);
-	
+
 	/* Allocate output area */
-	*n_decrypted = n_data;
-	*decrypted = egg_secure_alloc (n_data);
+	*n_decrypted = egg_bytes_get_size (data);
+	decrypted = egg_secure_alloc (*n_decrypted);
 
-	gcry = gcry_cipher_decrypt (ch, *decrypted, *n_decrypted, (void*)data, n_data);
+	gcry = gcry_cipher_decrypt (ch, decrypted, *n_decrypted,
+	                            egg_bytes_get_data (data),
+	                            egg_bytes_get_size (data));
 	if (gcry) {
-		egg_secure_free (*decrypted);
-		g_return_val_if_reached (FALSE);
+		egg_secure_free (decrypted);
+		g_return_val_if_reached (NULL);
 	}
-	
+
 	gcry_cipher_close (ch);
-	
-	return TRUE;
+
+	return decrypted;
 }
 
-gboolean
-egg_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, 
-                                gssize n_password, const guchar *data, gsize n_data,
-                                guchar **encrypted, gsize *n_encrypted)
+guchar *
+egg_openssl_encrypt_block (const gchar *dekinfo,
+                           const gchar *password,
+                           gssize n_password,
+                           EggBytes *data,
+                           gsize *n_encrypted)
 {
 	gsize n_overflow, n_batch, n_padding;
 	gcry_cipher_hd_t ch;
@@ -270,65 +276,71 @@ egg_openssl_encrypt_block (const gchar *dekinfo, const gchar *password,
 	int gcry, ivlen;
 	int algo = 0;
 	int mode = 0;
-	
+	gsize n_data;
+	guchar *encrypted;
+	const guchar *dat;
+
 	if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
-		g_return_val_if_reached (FALSE);
-		
+		g_return_val_if_reached (NULL);
+
 	ivlen = gcry_cipher_get_algo_blklen (algo);
 
 	/* We assume the iv is at least as long as at 8 byte salt */
-	g_return_val_if_fail (ivlen >= 8, FALSE);
-	
+	g_return_val_if_fail (ivlen >= 8, NULL);
+
 	/* IV is already set from the DEK info */
-	if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password, 
+	if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password,
 	                                        n_password, iv, 8, 1, &key, NULL))
-		g_return_val_if_reached (FALSE);
-	
+		g_return_val_if_reached (NULL);
+
 	gcry = gcry_cipher_open (&ch, algo, mode, 0);
-	g_return_val_if_fail (!gcry, FALSE);
-		
+	g_return_val_if_fail (!gcry, NULL);
+
 	gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
-	g_return_val_if_fail (!gcry, FALSE);
+	g_return_val_if_fail (!gcry, NULL);
 	egg_secure_free (key);
 
 	/* 16 = 128 bits */
 	gcry = gcry_cipher_setiv (ch, iv, ivlen);
-	g_return_val_if_fail (!gcry, FALSE);
+	g_return_val_if_fail (!gcry, NULL);
 	g_free (iv);
-	
+
+	dat = egg_bytes_get_data (data);
+	n_data = egg_bytes_get_size (data);
+
 	/* Allocate output area */
 	n_overflow = (n_data % ivlen);
 	n_padding = n_overflow ? (ivlen - n_overflow) : 0;
 	n_batch = n_data - n_overflow;
 	*n_encrypted = n_data + n_padding;
-	*encrypted = g_malloc0 (*n_encrypted);
-	
+	encrypted = g_malloc0 (*n_encrypted);
+
 	g_assert (*n_encrypted % ivlen == 0);
 	g_assert (*n_encrypted >= n_data);
 	g_assert (*n_encrypted == n_batch + n_overflow + n_padding);
 
 	/* Encrypt everything but the last bit */
-	gcry = gcry_cipher_encrypt (ch, *encrypted, n_batch, (void*)data, n_batch);
+	gcry = gcry_cipher_encrypt (ch, encrypted, n_batch, dat, n_batch);
 	if (gcry) {
-		g_free (*encrypted);
-		g_return_val_if_reached (FALSE);
+		g_free (encrypted);
+		g_return_val_if_reached (NULL);
 	}
-	
+
 	/* Encrypt the padded block */
 	if (n_overflow) {
 		padded = egg_secure_alloc (ivlen);
 		memset (padded, 0, ivlen);
-		memcpy (padded, data + n_batch, n_overflow);
-		gcry = gcry_cipher_encrypt (ch, *encrypted + n_batch, ivlen, padded, ivlen);
+		memcpy (padded, dat + n_batch, n_overflow);
+		gcry = gcry_cipher_encrypt (ch, encrypted + n_batch, ivlen, padded, ivlen);
 		egg_secure_free (padded);
 		if (gcry) {
-			g_free (*encrypted);
-			g_return_val_if_reached (FALSE);
+			g_free (encrypted);
+			g_return_val_if_reached (NULL);
 		}
 	}
 
 	gcry_cipher_close (ch);
-	return TRUE;
+	return encrypted;
 }
 
 const gchar*
@@ -351,21 +363,22 @@ egg_openssl_prep_dekinfo (GHashTable *headers)
 	gchar *dekinfo, *hex;
 	gsize ivlen;
 	guchar *iv;
-	
+
 	/* Create the iv */
 	ivlen = gcry_cipher_get_algo_blklen (GCRY_CIPHER_3DES);
 	g_return_val_if_fail (ivlen, NULL);
 	iv = g_malloc (ivlen);
 	gcry_create_nonce (iv, ivlen);
-	
+
 	/* And encode it into the string */
 	hex = egg_hex_encode (iv, ivlen);
 	g_return_val_if_fail (hex, NULL);
 	dekinfo = g_strdup_printf ("DES-EDE3-CBC,%s", hex);
 	g_free (hex);
+	g_free (iv);
 
 	g_hash_table_insert (headers, g_strdup ("DEK-Info"), (void*)dekinfo);
 	g_hash_table_insert (headers, g_strdup ("Proc-Type"), g_strdup ("4,ENCRYPTED"));
-	
+
 	return dekinfo;
 }
diff --git a/egg/egg-openssl.h b/egg/egg-openssl.h
index 7d4e4f0..642d906 100644
--- a/egg/egg-openssl.h
+++ b/egg/egg-openssl.h
@@ -26,15 +26,21 @@
 
 #include <glib.h>
 
-int              egg_openssl_parse_algo        (const gchar *name, int *mode);
+#include <egg/egg-bytes.h>
 
-gboolean         egg_openssl_encrypt_block     (const gchar *dekinfo, const gchar *password, 
-                                                gssize n_password, const guchar *data, gsize n_data,
-                                                guchar **encrypted, gsize *n_encrypted);
+int              egg_openssl_parse_algo        (const gchar *name, int *mode);
 
-gboolean         egg_openssl_decrypt_block     (const gchar *dekinfo, const gchar *password, 
-                                                gssize n_password, const guchar *data, gsize n_data, 
-                                                guchar **decrypted, gsize *n_decrypted);
+guchar *         egg_openssl_encrypt_block     (const gchar *dekinfo,
+                                                const gchar *password,
+                                                gssize n_password,
+                                                EggBytes *data,
+                                                gsize *n_encrypted);
+
+guchar *         egg_openssl_decrypt_block     (const gchar *dekinfo,
+                                                const gchar *password,
+                                                gssize n_password,
+                                                EggBytes *data,
+                                                gsize *n_decrypted);
 
 const gchar*     egg_openssl_get_dekinfo       (GHashTable *headers);
 
diff --git a/egg/egg-secure-memory.c b/egg/egg-secure-memory.c
index 7af4ac9..ca5e38d 100644
--- a/egg/egg-secure-memory.c
+++ b/egg/egg-secure-memory.c
@@ -46,12 +46,6 @@
 #include <valgrind/memcheck.h>
 #endif
 
-/*
- * Use this to force all memory through malloc
- * for use with valgrind and the like 
- */
-#define FORCE_FALLBACK_MEMORY 0
-
 #define DEBUG_SECURE_MEMORY 0
 
 #if DEBUG_SECURE_MEMORY 
@@ -72,12 +66,12 @@
 #endif
 
 #define DO_LOCK() \
-	egg_memory_lock (); 
-	
+	EGG_SECURE_GLOBALS.lock ();
+
 #define DO_UNLOCK() \
-	egg_memory_unlock ();
+	EGG_SECURE_GLOBALS.unlock ();
 
-static int lock_warning = 1;
+static int show_warning = 1;
 int egg_secure_warnings = 1;
 
 /* 
@@ -169,17 +163,25 @@ typedef struct _Pool {
 	Item items[1];         /* Actual items hang off here */
 } Pool;
 
-static Pool *all_pools = NULL;
-
-static void*
+static void *
 pool_alloc (void)
 {
 	Pool *pool;
 	void *pages, *item;
 	size_t len, i;
-	
+
+	if (!EGG_SECURE_GLOBALS.pool_version ||
+	    strcmp (EGG_SECURE_GLOBALS.pool_version, EGG_SECURE_POOL_VER_STR) != 0) {
+		if (show_warning && egg_secure_warnings)
+			fprintf (stderr, "the secure memory pool version does not match the code '%s' != '%s'\n",
+			         EGG_SECURE_GLOBALS.pool_version ? EGG_SECURE_GLOBALS.pool_version : "(null)",
+			         EGG_SECURE_POOL_VER_STR);
+		show_warning = 0;
+		return NULL;
+	}
+
 	/* A pool with an available item */
-	for (pool = all_pools; pool; pool = pool->next) {
+	for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
 		if (unused_peek (&pool->unused))
 			break;
 	}
@@ -193,8 +195,8 @@ pool_alloc (void)
 
 		/* Fill in the block header, and inlude in block list */
 		pool = pages;
-		pool->next = all_pools;
-		all_pools = pool;
+		pool->next = EGG_SECURE_GLOBALS.pool_data;
+		EGG_SECURE_GLOBALS.pool_data = pool;
 		pool->length = len;
 		pool->used = 0;
 		pool->unused = NULL;
@@ -212,11 +214,11 @@ pool_alloc (void)
 	++pool->used;
 	ASSERT (unused_peek (&pool->unused));
 	item = unused_pop (&pool->unused);
-	
+
 #ifdef WITH_VALGRIND
 	VALGRIND_MEMPOOL_ALLOC (pool, item, sizeof (Item));
 #endif
-	
+
 	return memset (item, 0, sizeof (Item));
 }
 
@@ -229,7 +231,8 @@ pool_free (void* item)
 	ptr = item;
 	
 	/* Find which block this one belongs to */
-	for (at = &all_pools, pool = *at; pool; at = &pool->next, pool = *at) {
+	for (at = (Pool **)&EGG_SECURE_GLOBALS.pool_data, pool = *at;
+	     pool != NULL; at = &pool->next, pool = *at) {
 		beg = (char*)pool->items;
 		end = (char*)pool + pool->length - sizeof (Item);
 		if (ptr >= beg && ptr <= end) {
@@ -246,20 +249,20 @@ pool_free (void* item)
 	/* No more meta cells used in this block, remove from list, destroy */
 	if (pool->used == 1) {
 		*at = pool->next;
-		
+
 #ifdef WITH_VALGRIND
 		VALGRIND_DESTROY_MEMPOOL (pool);
 #endif
-		
+
 		munmap (pool, pool->length);
 		return;
 	}
-	
+
 #ifdef WITH_VALGRIND
 	VALGRIND_MEMPOOL_FREE (pool, item);
 	VALGRIND_MAKE_MEM_UNDEFINED (item, sizeof (Item));
 #endif
-	
+
 	--pool->used;
 	memset (item, 0xCD, sizeof (Item));
 	unused_push (&pool->unused, item);
@@ -276,7 +279,7 @@ pool_valid (void* item)
 	ptr = item;
 	
 	/* Find which block this one belongs to */
-	for (pool = all_pools; pool; pool = pool->next) {
+	for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
 		beg = (char*)pool->items;
 		end = (char*)pool + pool->length - sizeof (Item);
 		if (ptr >= beg && ptr <= end) 
@@ -404,12 +407,33 @@ sec_is_valid_word (Block *block, word_t *word)
 	return (word >= block->words && word < block->words + block->n_words);
 }
 
-static inline void*
-sec_clear_memory (void *memory, size_t from, size_t to)
+static inline void
+sec_clear_undefined (void *memory,
+                     size_t from,
+                     size_t to)
 {
+	char *ptr = memory;
 	ASSERT (from <= to);
-	memset ((char*)memory + from, 0, to - from);
-	return memory;
+#ifdef WITH_VALGRIND
+	VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
+#endif
+	memset (ptr + from, 0, to - from);
+#ifdef WITH_VALGRIND
+	VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
+#endif
+}
+static inline void
+sec_clear_noaccess (void *memory, size_t from, size_t to)
+{
+	char *ptr = memory;
+	ASSERT (from <= to);
+#ifdef WITH_VALGRIND
+	VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
+#endif
+	memset (ptr + from, 0, to - from);
+#ifdef WITH_VALGRIND
+	VALGRIND_MAKE_MEM_NOACCESS (ptr + from, to - from);
+#endif
 }
 
 static Cell*
@@ -567,7 +591,7 @@ sec_free (Block *block, void *memory)
 #endif
 
 	sec_check_guards (cell);
-	sec_clear_memory (memory, 0, cell->requested);
+	sec_clear_noaccess (memory, 0, cell->requested);
 
 	sec_check_guards (cell);
 	ASSERT (cell->requested > 0);
@@ -611,6 +635,34 @@ sec_free (Block *block, void *memory)
         return NULL;
 }
 
+static void
+memcpy_with_vbits (void *dest,
+                   void *src,
+                   size_t length)
+{
+#ifdef WITH_VALGRIND
+	int vbits_setup = 0;
+	void *vbits = NULL;
+
+	if (RUNNING_ON_VALGRIND) {
+		vbits = malloc (length);
+		if (vbits != NULL)
+			vbits_setup = VALGRIND_GET_VBITS (src, vbits, length);
+		VALGRIND_MAKE_MEM_DEFINED (src, length);
+	}
+#endif
+
+	memcpy (dest, src, length);
+
+#ifdef WITH_VALGRIND
+	if (vbits_setup == 1) {
+		VALGRIND_SET_VBITS (dest, vbits, length);
+		VALGRIND_SET_VBITS (src, vbits, length);
+	}
+	free (vbits);
+#endif
+}
+
 static void*
 sec_realloc (Block *block,
              const char *tag,
@@ -658,19 +710,15 @@ sec_realloc (Block *block,
 		cell->requested = length;
 		alloc = sec_cell_to_memory (cell);
 
-#ifdef WITH_VALGRIND
-		VALGRIND_MAKE_MEM_DEFINED (alloc, length);
-#endif
-		
 		/* 
 		 * Even though we may be reusing the same cell, that doesn't
 		 * mean that the allocation is shrinking. It could have shrunk
 		 * and is now expanding back some. 
 		 */ 
 		if (length < valid)
-			return sec_clear_memory (alloc, length, valid);
-		else
-			return alloc;
+			sec_clear_undefined (alloc, length, valid);
+
+		return alloc;
 	}
 	
 	/* Need braaaaaiiiiiinsss... */
@@ -702,18 +750,14 @@ sec_realloc (Block *block,
 		cell->requested = length;
 		cell->tag = tag;
 		alloc = sec_cell_to_memory (cell);
-
-#ifdef WITH_VALGRIND
-		VALGRIND_MAKE_MEM_DEFINED (alloc, length);
-#endif
-		
-		return sec_clear_memory (alloc, valid, length);
+		sec_clear_undefined (alloc, valid, length);
+		return alloc;
 	}
 
 	/* That didn't work, try alloc/free */
 	alloc = sec_alloc (block, tag, length);
 	if (alloc) {
-		memcpy (alloc, memory, valid);
+		memcpy_with_vbits (alloc, memory, valid);
 		sec_free (block, memory);
 	}
 	
@@ -758,7 +802,12 @@ sec_validate (Block *block)
 {
 	Cell *cell;
 	word_t *word, *last;
-	
+
+#ifdef WITH_VALGRIND
+	if (RUNNING_ON_VALGRIND)
+		return;
+#endif
+
 	word = block->words;
 	last = word + block->n_words;
 
@@ -781,7 +830,7 @@ sec_validate (Block *block)
 			ASSERT (cell->prev->next == cell);
 			ASSERT (cell->requested <= (cell->n_words - 2) * sizeof (word_t));
 		
-			/* An unused block */
+		/* An unused block */
 		} else {
 			ASSERT (cell->tag == NULL);
 			ASSERT (cell->next != NULL);
@@ -818,18 +867,18 @@ sec_acquire_pages (size_t *sz,
 #if defined(HAVE_MLOCK)
 	pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (pages == MAP_FAILED) {
-		if (lock_warning && egg_secure_warnings)
+		if (show_warning && egg_secure_warnings)
 			fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n",
 			         (unsigned long)*sz, during_tag, strerror (errno));
-		lock_warning = 0;
+		show_warning = 0;
 		return NULL;
 	}
 	
 	if (mlock (pages, *sz) < 0) {
-		if (lock_warning && egg_secure_warnings && errno != EPERM) {
+		if (show_warning && egg_secure_warnings && errno != EPERM) {
 			fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n",
 			         (unsigned long)*sz, during_tag, strerror (errno));
-			lock_warning = 0;
+			show_warning = 0;
 		}
 		munmap (pages, *sz);
 		return NULL;
@@ -837,13 +886,13 @@ sec_acquire_pages (size_t *sz,
 	
 	DEBUG_ALLOC ("gkr-secure-memory: new block ", *sz);
 	
-	lock_warning = 1;
+	show_warning = 1;
 	return pages;
 	
 #else
-	if (lock_warning && egg_secure_warnings)
+	if (show_warning && egg_secure_warnings)
 		fprintf (stderr, "your system does not support private memory");
-	lock_warning = 0;
+	show_warning = 0;
 	return NULL;
 #endif
 
@@ -884,11 +933,10 @@ sec_block_create (size_t size,
 
 	ASSERT (during_tag);
 
-#if FORCE_FALLBACK_MEMORY
 	/* We can force all all memory to be malloced */
-	return NULL;
-#endif
-	
+	if (getenv ("SECMEM_FORCE_FALLBACK"))
+		return NULL;
+
 	block = pool_alloc ();
 	if (!block)
 		return NULL;
@@ -1011,8 +1059,8 @@ egg_secure_alloc_full (const char *tag,
 	
 	DO_UNLOCK ();
 
-	if (!memory && (flags & EGG_SECURE_USE_FALLBACK)) {
-		memory = egg_memory_fallback (NULL, length);
+	if (!memory && (flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback != NULL) {
+		memory = EGG_SECURE_GLOBALS.fallback (NULL, length);
 		if (memory) /* Our returned memory is always zeroed */
 			memset (memory, 0, length);
 	}
@@ -1085,17 +1133,17 @@ egg_secure_realloc_full (const char *tag,
 	DO_UNLOCK ();		
 	
 	if (!block) {
-		if ((flags & EGG_SECURE_USE_FALLBACK)) {
+		if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) {
 			/* 
 			 * In this case we can't zero the returned memory, 
 			 * because we don't know what the block size was.
 			 */
-			return egg_memory_fallback (memory, length);
+			return EGG_SECURE_GLOBALS.fallback (memory, length);
 		} else {
 			if (egg_secure_warnings)
-				fprintf (stderr, "memory does not belong to gnome-keyring: 0x%08lx\n", 
+				fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n",
 				         (unsigned long)memory);
-			ASSERT (0 && "memory does does not belong to gnome-keyring");
+			ASSERT (0 && "memory does does not belong to secure memory pool");
 			return NULL;
 		}
 	}
@@ -1103,7 +1151,7 @@ egg_secure_realloc_full (const char *tag,
 	if (donew) {
 		alloc = egg_secure_alloc_full (tag, length, flags);
 		if (alloc) {
-			memcpy (alloc, memory, previous);
+			memcpy_with_vbits (alloc, memory, previous);
 			egg_secure_free_full (memory, flags);
 		}
 	}
@@ -1151,13 +1199,13 @@ egg_secure_free_full (void *memory, int flags)
 	DO_UNLOCK ();
 	
 	if (!block) {
-		if ((flags & EGG_SECURE_USE_FALLBACK)) {
-			egg_memory_fallback (memory, 0);
+		if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) {
+			EGG_SECURE_GLOBALS.fallback (memory, 0);
 		} else {
 			if (egg_secure_warnings)
-				fprintf (stderr, "memory does not belong to gnome-keyring: 0x%08lx\n", 
+				fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n",
 				         (unsigned long)memory);
-			ASSERT (0 && "memory does does not belong to gnome-keyring");
+			ASSERT (0 && "memory does does not belong to secure memory pool");
 		}
 	}
 } 
diff --git a/egg/egg-secure-memory.h b/egg/egg-secure-memory.h
index 682811d..3ef0ab5 100644
--- a/egg/egg-secure-memory.h
+++ b/egg/egg-secure-memory.h
@@ -39,30 +39,32 @@
  * must be defined somewhere, and provide appropriate locking for 
  * secure memory between threads:
  */
- 
-extern void   egg_memory_lock (void);
-
-extern void   egg_memory_unlock (void);
-
-/*
- * Allocation Fallbacks
- * 
- * If we cannot allocate secure memory, then this function
- * (defined elsewhere) will be called which has a chance to 
- * allocate other memory abort or do whatever.
- * 
- * Same call semantics as realloc with regard to NULL and zeros 
- */
-extern void*  egg_memory_fallback (void *p, size_t length);
 
-#define EGG_SECURE_GLIB_DEFINITIONS() \
+typedef struct {
+	void       (* lock)        (void);
+	void       (* unlock)      (void);
+	void *     (* fallback)    (void *pointer,
+	                            size_t length);
+	void *        pool_data;
+	const char *  pool_version;
+} egg_secure_glob;
+
+#define EGG_SECURE_POOL_VER_STR             "1.0"
+#define EGG_SECURE_GLOBALS SECMEM_pool_data_v1_0
+
+#define EGG_SECURE_DEFINE_GLOBALS(lock, unlock, fallback) \
+	egg_secure_glob EGG_SECURE_GLOBALS = { \
+		lock, unlock, fallback, NULL, EGG_SECURE_POOL_VER_STR };
+
+#define EGG_SECURE_DEFINE_GLIB_GLOBALS() \
 	static GStaticMutex memory_mutex = G_STATIC_MUTEX_INIT; \
-	void egg_memory_lock (void) \
+	static void egg_memory_lock (void) \
 		{ g_static_mutex_lock (&memory_mutex); } \
-	void egg_memory_unlock (void) \
+	static void egg_memory_unlock (void) \
 		{ g_static_mutex_unlock (&memory_mutex); } \
-	void* egg_memory_fallback (void *p, size_t sz) \
-		{ return g_realloc (p, sz); } \
+	EGG_SECURE_DEFINE_GLOBALS (egg_memory_lock, egg_memory_unlock, g_realloc);
+
+extern egg_secure_glob EGG_SECURE_GLOBALS;
 
 /* 
  * Main functionality
diff --git a/egg/egg-symkey.c b/egg/egg-symkey.c
index 630f922..6af1751 100644
--- a/egg/egg-symkey.c
+++ b/egg/egg-symkey.c
@@ -1,13 +1,13 @@
-/* 
+/*
  * gnome-keyring
- * 
+ *
  * Copyright (C) 2008 Stefan Walter
  * 
  * This program is free software; you can redistribute it and/or modify 
  * it under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
- *  
+ *
  * This program 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
@@ -16,7 +16,7 @@
  * You should have received a copy of the GNU Lesser General 
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.  
+ * 02111-1307, USA.
  */
 
 #include "config.h"
@@ -71,16 +71,16 @@ init_quarks (void)
 		QUARK (OID_PBE_MD5_RC2_CBC, "1.2.840.113549.1.5.6");
 		QUARK (OID_PBE_SHA1_DES_CBC, "1.2.840.113549.1.5.10");
 		QUARK (OID_PBE_SHA1_RC2_CBC, "1.2.840.113549.1.5.11");
-		
+
 		QUARK (OID_PBES2, "1.2.840.113549.1.5.13");
-		
+
 		QUARK (OID_PBKDF2, "1.2.840.113549.1.5.12");
-		
+
 		QUARK (OID_DES_CBC, "1.3.14.3.2.7");
 		QUARK (OID_DES_RC2_CBC, "1.2.840.113549.3.2");
 		QUARK (OID_DES_EDE3_CBC, "1.2.840.113549.3.7");
 		QUARK (OID_DES_RC5_CBC, "1.2.840.113549.3.9");
-		
+
 		QUARK (OID_PKCS12_PBE_ARCFOUR_SHA1, "1.2.840.113549.1.12.1.1");
 		QUARK (OID_PKCS12_PBE_RC4_40_SHA1, "1.2.840.113549.1.12.1.2");
 		QUARK (OID_PKCS12_PBE_3DES_SHA1, "1.2.840.113549.1.12.1.3");
@@ -91,7 +91,7 @@ init_quarks (void)
 		QUARK (OID_SHA1, "1.3.14.3.2.26");
 
 		#undef QUARK
-		
+
 		g_once_init_leave (&quarks_inited, 1);
 	}
 }
@@ -101,9 +101,9 @@ init_quarks (void)
  */
 
 gboolean
-egg_symkey_generate_simple (int cipher_algo, int hash_algo, 
-                            const gchar *password, gssize n_password, 
-                            const guchar *salt, gsize n_salt, int iterations, 
+egg_symkey_generate_simple (int cipher_algo, int hash_algo,
+                            const gchar *password, gssize n_password,
+                            const guchar *salt, gsize n_salt, int iterations,
                             guchar **key, guchar **iv)
 {
 	gcry_md_hd_t mdh;
@@ -119,38 +119,38 @@ egg_symkey_generate_simple (int cipher_algo, int hash_algo,
 	g_assert (hash_algo);
 
 	g_return_val_if_fail (iterations >= 1, FALSE);
-	
+
 	if (!password)
 		n_password = 0;
 	if (n_password == -1)
 		n_password = strlen (password);
-	
-	/* 
+
+	/*
 	 * If cipher algo needs more bytes than hash algo has available
 	 * then the entire hashing process is done again (with the previous
 	 * hash bytes as extra input), and so on until satisfied.
-	 */ 
-	
+	 */
+
 	needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
 	needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
-	
+
 	gcry = gcry_md_open (&mdh, hash_algo, 0);
 	if (gcry) {
-		g_warning ("couldn't create '%s' hash context: %s", 
+		g_warning ("couldn't create '%s' hash context: %s",
 			   gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
 		return FALSE;
 	}
 
 	n_digest = gcry_md_get_algo_dlen (hash_algo);
 	g_return_val_if_fail (n_digest > 0, FALSE);
-	
+
 	digest = egg_secure_alloc (n_digest);
 	g_return_val_if_fail (digest, FALSE);
 	if (key) {
 		*key = egg_secure_alloc (needed_key);
 		g_return_val_if_fail (*key, FALSE);
 	}
-	if (iv) 
+	if (iv)
 		*iv = g_new0 (guchar, needed_iv);
 
 	at_key = key ? *key : NULL;
@@ -158,7 +158,7 @@ egg_symkey_generate_simple (int cipher_algo, int hash_algo,
 
 	for (pass = 0; TRUE; ++pass) {
 		gcry_md_reset (mdh);
-		
+
 		/* Hash in the previous buffer on later passes */
 		if (pass > 0)
 			gcry_md_write (mdh, digest, n_digest);
@@ -171,7 +171,7 @@ egg_symkey_generate_simple (int cipher_algo, int hash_algo,
 		digested = gcry_md_read (mdh, 0);
 		g_return_val_if_fail (digested, FALSE);
 		memcpy (digest, digested, n_digest);
-		
+
 		for (i = 1; i < iterations; ++i) {
 			gcry_md_reset (mdh);
 			gcry_md_write (mdh, digest, n_digest);
@@ -180,9 +180,9 @@ egg_symkey_generate_simple (int cipher_algo, int hash_algo,
 			g_return_val_if_fail (digested, FALSE);
 			memcpy (digest, digested, n_digest);
 		}
-		
+
 		/* Copy as much as possible into the destinations */
-		i = 0; 
+		i = 0;
 		while (needed_key && i < n_digest) {
 			if (at_key)
 				*(at_key++) = digest[i];
@@ -190,25 +190,25 @@ egg_symkey_generate_simple (int cipher_algo, int hash_algo,
 			i++;
 		}
 		while (needed_iv && i < n_digest) {
-			if (at_iv) 
+			if (at_iv)
 				*(at_iv++) = digest[i];
 			needed_iv--;
 			i++;
 		}
-		
+
 		if (needed_key == 0 && needed_iv == 0)
 			break;
 	}
 
 	egg_secure_free (digest);
 	gcry_md_close (mdh);
-	
+
 	return TRUE;
 }
 
 gboolean
-egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password, 
-                         gssize n_password, const guchar *salt, gsize n_salt, int iterations, 
+egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password,
+                         gssize n_password, const guchar *salt, gsize n_salt, int iterations,
                          guchar **key, guchar **iv)
 {
 	gcry_md_hd_t mdh;
@@ -222,38 +222,38 @@ egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password,
 	g_assert (hash_algo);
 
 	g_return_val_if_fail (iterations >= 1, FALSE);
-	
+
 	if (!password)
 		n_password = 0;
 	if (n_password == -1)
 		n_password = strlen (password);
-	
-	/* 
+
+	/*
 	 * We only do one pass here.
-	 * 
+	 *
 	 * The key ends up as the first needed_key bytes of the hash buffer.
-	 * The iv ends up as the last needed_iv bytes of the hash buffer. 
-	 * 
-	 * The IV may overlap the key (which is stupid) if the wrong pair of 
+	 * The iv ends up as the last needed_iv bytes of the hash buffer.
+	 *
+	 * The IV may overlap the key (which is stupid) if the wrong pair of
 	 * hash/cipher algorithms are chosen.
-	 */ 
+	 */
 
 	n_digest = gcry_md_get_algo_dlen (hash_algo);
 	g_return_val_if_fail (n_digest > 0, FALSE);
-	
+
 	needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
 	needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
 	if (needed_iv + needed_key > 16 || needed_iv + needed_key > n_digest) {
-		g_warning ("using PBE symkey generation with %s using an algorithm that needs " 
+		g_warning ("using PBE symkey generation with %s using an algorithm that needs "
 		           "too many bytes of key and/or IV: %s",
-		           gcry_cipher_algo_name (hash_algo), 
+		           gcry_cipher_algo_name (hash_algo),
 		           gcry_cipher_algo_name (cipher_algo));
 		return FALSE;
 	}
-	
+
 	gcry = gcry_md_open (&mdh, hash_algo, 0);
 	if (gcry) {
-		g_warning ("couldn't create '%s' hash context: %s", 
+		g_warning ("couldn't create '%s' hash context: %s",
 			   gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
 		return FALSE;
 	}
@@ -264,7 +264,7 @@ egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password,
 		*key = egg_secure_alloc (needed_key);
 		g_return_val_if_fail (*key, FALSE);
 	}
-	if (iv) 
+	if (iv)
 		*iv = g_new0 (guchar, needed_iv);
 
 	if (password)
@@ -275,31 +275,31 @@ egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password,
 	digested = gcry_md_read (mdh, 0);
 	g_return_val_if_fail (digested, FALSE);
 	memcpy (digest, digested, n_digest);
-		
+
 	for (i = 1; i < iterations; ++i)
 		gcry_md_hash_buffer (hash_algo, digest, digest, n_digest);
-	
+
 	/* The first x bytes are the key */
 	if (key) {
 		g_assert (needed_key <= n_digest);
 		memcpy (*key, digest, needed_key);
 	}
-	
+
 	/* The last 16 - x bytes are the iv */
 	if (iv) {
 		g_assert (needed_iv <= n_digest && n_digest >= 16);
 		memcpy (*iv, digest + (16 - needed_iv), needed_iv);
 	}
-		
+
 	egg_secure_free (digest);
 	gcry_md_close (mdh);
-	
-	return TRUE;	
+
+	return TRUE;
 }
 
 static gboolean
-generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password, 
-                 gssize n_password, const guchar *salt, gsize n_salt, 
+generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
+                 gssize n_password, const guchar *salt, gsize n_salt,
                  int iterations, guchar *output, gsize n_output)
 {
 	gcry_mpi_t num_b1, num_ij;
@@ -314,20 +314,20 @@ generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
 	gsize length;
 
 	num_b1 = num_ij = NULL;
-	
+
 	n_hash = gcry_md_get_algo_dlen (hash_algo);
 	g_return_val_if_fail (n_hash > 0, FALSE);
-	
+
 	if (!utf8_password)
 		n_password = 0;
-	if (n_password == -1) 
+	if (n_password == -1)
 		end_password = utf8_password + strlen (utf8_password);
 	else
 		end_password = utf8_password + n_password;
-	
+
 	gcry = gcry_md_open (&mdh, hash_algo, 0);
 	if (gcry) {
-		g_warning ("couldn't create '%s' hash context: %s", 
+		g_warning ("couldn't create '%s' hash context: %s",
 		           gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
 		return FALSE;
 	}
@@ -337,7 +337,7 @@ generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
 	buf_i = egg_secure_alloc (128);
 	buf_b = egg_secure_alloc (64);
 	g_return_val_if_fail (hash && buf_i && buf_b, FALSE);
-		
+
 	/* Bring in the salt */
 	p = buf_i;
 	if (salt) {
@@ -347,12 +347,12 @@ generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
 		memset (p, 0, 64);
 		p += 64;
 	}
-	
+
 	/* Bring in the password, as 16bits per character BMP string, ie: UCS2 */
 	if (utf8_password) {
 		p2 = utf8_password;
 		for (i = 0; i < 64; i += 2) {
-			
+
 			/* Get a character from the string */
 			if (p2 < end_password) {
 				unich = g_utf8_get_char (p2);
@@ -370,9 +370,8 @@ generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
 		}
 	} else {
 		memset (p, 0, 64);
-		p += 64;
 	}
-	
+
 	/* Hash and bash */
 	for (;;) {
 		gcry_md_reset (mdh);
@@ -380,27 +379,27 @@ generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
 		/* Put in the PKCS#12 type of key */
 		for (i = 0; i < 64; ++i)
 			gcry_md_putc (mdh, type);
-			
+
 		/* Bring in the password */
 		gcry_md_write (mdh, buf_i, utf8_password ? 128 : 64);
-		
+
 		/* First iteration done */
 		memcpy (hash, gcry_md_read (mdh, hash_algo), n_hash);
-		
+
 		/* All the other iterations */
 		for (i = 1; i < iterations; i++)
 			gcry_md_hash_buffer (hash_algo, hash, hash, n_hash);
-		
+
 		/* Take out as much as we need */
 		for (i = 0; i < n_hash && n_output; ++i) {
 			*(output++) = hash[i];
 			--n_output;
 		}
-		
+
 		/* Is that enough generated keying material? */
 		if (!n_output)
 			break;
-			
+
 		/* Need more bytes, do some voodoo */
 		for (i = 0; i < 64; ++i)
 			buf_b[i] = hash[i % n_hash];
@@ -420,67 +419,67 @@ generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
 			g_return_val_if_fail (gcry == 0, FALSE);
 			gcry_mpi_release (num_ij);
 		}
-	}  
-	
+	}
+
 	egg_secure_free (buf_i);
 	egg_secure_free (buf_b);
 	egg_secure_free (hash);
 	gcry_mpi_release (num_b1);
 	gcry_md_close (mdh);
-	
+
 	return TRUE;
 }
 
 gboolean
-egg_symkey_generate_pkcs12 (int cipher_algo, int hash_algo, const gchar *password, 
+egg_symkey_generate_pkcs12 (int cipher_algo, int hash_algo, const gchar *password,
                             gssize n_password, const guchar *salt, gsize n_salt,
                             int iterations, guchar **key, guchar **iv)
 {
 	gsize n_block, n_key;
 	gboolean ret = TRUE;
-	
+
 	g_return_val_if_fail (cipher_algo, FALSE);
 	g_return_val_if_fail (hash_algo, FALSE);
 	g_return_val_if_fail (iterations > 0, FALSE);
-	
+
 	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
 	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
-	
+
 	if (password && !g_utf8_validate (password, n_password, NULL)) {
 		g_warning ("invalid non-UTF8 password");
 		g_return_val_if_reached (FALSE);
 	}
-	
+
 	if (key)
 		*key = NULL;
 	if (iv)
 		*iv = NULL;
-	
+
 	/* Generate us an key */
 	if (key) {
 		*key = egg_secure_alloc (n_key);
 		g_return_val_if_fail (*key != NULL, FALSE);
-		ret = generate_pkcs12 (hash_algo, 1, password, n_password, salt, n_salt, 
+		ret = generate_pkcs12 (hash_algo, 1, password, n_password, salt, n_salt,
 		                       iterations, *key, n_key);
-	} 
-	
+	}
+
 	/* Generate us an iv */
 	if (ret && iv) {
 		if (n_block > 1) {
 			*iv = g_malloc (n_block);
-			ret = generate_pkcs12 (hash_algo, 2, password, n_password, salt, n_salt, 
+			ret = generate_pkcs12 (hash_algo, 2, password, n_password, salt, n_salt,
 			                       iterations, *iv, n_block);
 		} else {
 			*iv = NULL;
 		}
 	}
-	
+
 	/* Cleanup in case of failure */
 	if (!ret) {
 		g_free (iv ? *iv : NULL);
 		egg_secure_free (key ? *key : NULL);
 	}
-	
+
 	return ret;
 }
 
@@ -531,7 +530,7 @@ generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
 	gcry_error_t gcry;
 	guchar *U, *T, *buf;
 	gsize n_buf, n_hash;
-	
+
 	g_return_val_if_fail (hash_algo > 0, FALSE);
 	g_return_val_if_fail (iterations > 0, FALSE);
 	g_return_val_if_fail (n_output > 0, FALSE);
@@ -539,10 +538,10 @@ generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
 
 	n_hash = gcry_md_get_algo_dlen (hash_algo);
 	g_return_val_if_fail (n_hash > 0, FALSE);
-	
+
 	gcry = gcry_md_open (&mdh, hash_algo, GCRY_MD_FLAG_HMAC);
 	if (gcry != 0) {
-		g_warning ("couldn't create '%s' hash context: %s", 
+		g_warning ("couldn't create '%s' hash context: %s",
 		           gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
 		return FALSE;
 	}
@@ -556,10 +555,10 @@ generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
 
 	/* n_hash blocks in output, rounding up */
 	l = ((n_output - 1) / n_hash) + 1;
-	
+
 	/* number of bytes in last, rounded up, n_hash block */
 	r = n_output - (l - 1) * n_hash;
-	
+
 	memcpy (buf, salt, n_salt);
 	for (i = 1; i <= l; i++) {
 		memset (T, 0, n_hash);
@@ -568,21 +567,21 @@ generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
 
 			gcry = gcry_md_setkey (mdh, password, n_password);
 			g_return_val_if_fail (gcry == 0, FALSE);
-			
+
 			/* For first iteration on each block add 4 extra bytes */
 			if (u == 1) {
 				buf[n_salt + 0] = (i & 0xff000000) >> 24;
 				buf[n_salt + 1] = (i & 0x00ff0000) >> 16;
 				buf[n_salt + 2] = (i & 0x0000ff00) >> 8;
 				buf[n_salt + 3] = (i & 0x000000ff) >> 0;
-				
+
 				gcry_md_write (mdh, buf, n_buf);
-		
+
 			/* Other iterations, any block */
 			} else {
 				gcry_md_write (mdh, U, n_hash);
 			}
-			
+
 			memcpy (U, gcry_md_read (mdh, hash_algo), n_hash);
 
 			for (k = 0; k < n_hash; k++)
@@ -591,7 +590,7 @@ generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
 
 		memcpy (output + (i - 1) * n_hash, T, i == l ? r : n_hash);
 	}
-	
+
 	egg_secure_free (T);
 	egg_secure_free (U);
 	egg_secure_free (buf);
@@ -600,39 +599,39 @@ generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
 }
 
 gboolean
-egg_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo, 
-                            const gchar *password, gssize n_password, 
-                            const guchar *salt, gsize n_salt, int iterations, 
+egg_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo,
+                            const gchar *password, gssize n_password,
+                            const guchar *salt, gsize n_salt, int iterations,
                             guchar **key, guchar **iv)
 {
 	gsize n_key, n_block;
 	gboolean ret = TRUE;
-	
+
 	g_return_val_if_fail (hash_algo, FALSE);
 	g_return_val_if_fail (cipher_algo, FALSE);
 	g_return_val_if_fail (iterations > 0, FALSE);
-	
+
 	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
 	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
-	
+
 	if (key)
 		*key = NULL;
 	if (iv)
 		*iv = NULL;
-	
+
 	if (!password)
 		n_password = 0;
 	if (n_password == -1)
 		n_password = strlen (password);
-	
+
 	/* Generate us an key */
 	if (key) {
 		*key = egg_secure_alloc (n_key);
 		g_return_val_if_fail (*key != NULL, FALSE);
-		ret = generate_pbkdf2 (hash_algo, password, n_password, salt, n_salt, 
+		ret = generate_pbkdf2 (hash_algo, password, n_password, salt, n_salt,
 		                       iterations, *key, n_key);
-	} 
-	
+	}
+
 	/* Generate us an iv */
 	if (ret && iv) {
 		if (n_block > 1) {
@@ -642,13 +641,13 @@ egg_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo,
 			*iv = NULL;
 		}
 	}
-	
+
 	/* Cleanup in case of failure */
 	if (!ret) {
 		g_free (iv ? *iv : NULL);
 		egg_secure_free (key ? *key : NULL);
 	}
-	
+
 	return ret;
 }
 
@@ -658,14 +657,17 @@ egg_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo,
 
 
 static gboolean
-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)
+read_cipher_pkcs5_pbe (int cipher_algo,
+                       int cipher_mode,
+                       int hash_algo,
+                       const gchar *password,
+                       gsize n_password,
+                       EggBytes *data,
+                       gcry_cipher_hd_t *cih)
 {
 	GNode *asn = NULL;
 	gcry_error_t gcry;
-	gconstpointer salt;
-	gsize n_salt;
+	EggBytes *salt = NULL;
 	gsize n_block, n_key;
 	gulong iterations;
 	guchar *key = NULL;
@@ -674,11 +676,11 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
 
 	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);
+	g_return_val_if_fail (data != NULL, FALSE);
 
 	*cih = NULL;
 	ret = FALSE;
-	
+
 	/* Check if we can use this algorithm */
 	if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0 ||
 	    gcry_md_test_algo (hash_algo) != 0)
@@ -687,10 +689,10 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
 	asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBE-params");
 	g_return_val_if_fail (asn, FALSE);
 
-	if (!egg_asn1x_decode (asn, data, n_data))
+	if (!egg_asn1x_decode (asn, data))
 		goto done;
 
-	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL), &n_salt);
+	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL));
 	if (!salt)
 		goto done;
 	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
@@ -699,25 +701,28 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
 	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);
-		
-	if (!egg_symkey_generate_pbe (cipher_algo, hash_algo, password, n_password, salt,
-	                              n_salt, iterations, &key, n_block > 1 ? &iv : NULL))
+
+	if (!egg_symkey_generate_pbe (cipher_algo, hash_algo, password, n_password,
+	                              egg_bytes_get_data (salt), egg_bytes_get_size (salt),
+	                              iterations, &key, n_block > 1 ? &iv : NULL))
 		goto done;
-		
+
 	gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0);
 	if (gcry != 0) {
 		g_warning ("couldn't create cipher: %s", gcry_strerror (gcry));
 		goto done;
 	}
-	
-	if (iv) 
+
+	if (iv)
 		gcry_cipher_setiv (*cih, iv, n_block);
 	gcry_cipher_setkey (*cih, key, n_key);
-	
+
 	ret = TRUE;
 
 done:
 	g_free (iv);
+	if (salt != NULL)
+		egg_bytes_unref (salt);
 	egg_secure_free (key);
 	egg_asn1x_destroy (asn);
 
@@ -725,12 +730,12 @@ done:
 }
 
 static gboolean
-setup_pkcs5_rc2_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
+setup_pkcs5_rc2_params (EggBytes *data,
+                        gcry_cipher_hd_t cih)
 {
 	GNode *asn = NULL;
 	gcry_error_t gcry;
-	const guchar *iv;
-	gsize n_iv;
+	EggBytes *iv = NULL;
 	gulong version;
 	gboolean ret = FALSE;
 
@@ -739,135 +744,147 @@ setup_pkcs5_rc2_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
 	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))
+	if (!egg_asn1x_decode (asn, 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);
+	iv = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "iv", NULL));
 	if (!iv)
 		goto done;
 
-	gcry = gcry_cipher_setiv (cih, iv, n_iv);
+	gcry = gcry_cipher_setiv (cih, egg_bytes_get_data (iv), egg_bytes_get_size (iv));
 	if (gcry != 0) {
-		g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv);
+		g_message ("couldn't set %lu byte iv on cipher", (gulong)egg_bytes_get_size (iv));
 		goto done;
 	}
 
 	ret = TRUE;
 
 done:
+	if (iv != NULL)
+		egg_bytes_unref (iv);
 	egg_asn1x_destroy (asn);
 	return ret;
 }
 
 static gboolean
-setup_pkcs5_des_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
+setup_pkcs5_des_params (EggBytes *data,
+                        gcry_cipher_hd_t cih)
 {
 	GNode *asn = NULL;
 	gcry_error_t gcry;
-	gconstpointer iv;
-	gsize n_iv;
+	EggBytes *iv;
+	gboolean ret;
 
 	g_assert (data);
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "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);
+	if (!asn)
+		asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-CBC-params", data);
 	if (!asn)
-		asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-CBC-params", data, n_data);
-	if (!asn) 
 		return FALSE;
 
-	iv = egg_asn1x_get_raw_value (asn, &n_iv);
+	iv = egg_asn1x_get_raw_value (asn);
 	egg_asn1x_destroy (asn);
 
 	if (!iv)
 		return FALSE;
-		
-	gcry = gcry_cipher_setiv (cih, iv, n_iv);
-			
+
+	gcry = gcry_cipher_setiv (cih, egg_bytes_get_data (iv), egg_bytes_get_size (iv));
 	if (gcry != 0) {
-		g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv);
-		return FALSE;
+		g_message ("couldn't set %lu byte iv on cipher", (gulong)egg_bytes_get_size (iv));
+		ret = FALSE;
+	} else {
+		ret = TRUE;
 	}
-	
-	return TRUE;
+
+	egg_bytes_unref (iv);
+	return ret;
 }
 
 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)
+setup_pkcs5_pbkdf2_params (const gchar *password,
+                           gsize n_password,
+                           EggBytes *data,
+                           int cipher_algo,
+                           gcry_cipher_hd_t cih)
 {
 	GNode *asn = NULL;
 	gboolean ret;
 	gcry_error_t gcry;
-	guchar *key = NULL; 
-	const guchar *salt;
-	gsize n_salt, n_key;
+	guchar *key = NULL;
+	EggBytes *salt = NULL;
+	gsize n_key;
 	gulong iterations;
 
 	g_assert (cipher_algo);
-	g_assert (data);
-	
+	g_assert (data != NULL);
+
 	ret = FALSE;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBKDF2-params", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBKDF2-params", data);
 	if (!asn)
 		goto done;
 
 	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
 		iterations = 1;
-	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", "specified", NULL), &n_salt);
+	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", "specified", NULL));
 	if (!salt)
 		goto done;
 
-	if (!egg_symkey_generate_pbkdf2 (cipher_algo, GCRY_MD_SHA1, password, n_password, 
-	                                 salt, n_salt, iterations, &key, NULL))
+	if (!egg_symkey_generate_pbkdf2 (cipher_algo, GCRY_MD_SHA1, password, n_password,
+	                                 egg_bytes_get_data (salt), egg_bytes_get_size (salt),
+	                                 iterations, &key, NULL))
 		goto done;
 
 	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
 	g_return_val_if_fail (n_key > 0, FALSE);
-	
+
 	gcry = gcry_cipher_setkey (cih, key, n_key);
 	if (gcry != 0) {
 		g_message ("couldn't set %lu byte key on cipher", (gulong)n_key);
 		goto done;
 	}
-	
+
 	ret = TRUE;
-	                                         
+
 done:
+	if (salt != NULL)
+		egg_bytes_unref (salt);
 	egg_secure_free (key);
 	egg_asn1x_destroy (asn);
 	return ret;
 }
 
 static gboolean
-read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *data, 
-                         gsize n_data, gcry_cipher_hd_t *cih)
+read_cipher_pkcs5_pbes2 (const gchar *password,
+                         gsize n_password,
+                         EggBytes *data,
+                         gcry_cipher_hd_t *cih)
 {
 	GNode *asn = NULL;
 	gboolean r, ret;
 	GQuark key_deriv_algo, enc_oid;
+	EggBytes *params = NULL;
 	gcry_error_t gcry;
 	int algo, mode;
-	gconstpointer params;
-	gsize n_params;
 
 	g_return_val_if_fail (cih != NULL, FALSE);
-	g_return_val_if_fail (data != NULL && n_data != 0, FALSE);
-	
+	g_return_val_if_fail (data != NULL, FALSE);
+
 	init_quarks ();
-	
+
 	*cih = NULL;
 	ret = FALSE;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBES2-params", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBES2-params", data);
 	if (!asn)
 		goto done;
 
 	algo = mode = 0;
-	
+
 	/* Read in all the encryption type */
 	enc_oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionScheme", "algorithm", NULL));
 	if (!enc_oid)
@@ -880,7 +897,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 		algo = GCRY_CIPHER_RFC2268_128;
 	else if (enc_oid == OID_DES_RC5_CBC)
 		/* RC5 doesn't exist in libgcrypt */;
-	
+
 	/* Unsupported? */
 	if (algo == 0 || gcry_cipher_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
 		goto done;
@@ -891,19 +908,19 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 		g_warning ("couldn't create cipher: %s", gcry_cipher_algo_name (algo));
 		goto done;
 	}
-		
+
 	/* Read out the parameters */
-	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL), &n_params);
+	params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL));
 	if (!params)
 		goto done;
 
 	switch (algo) {
 	case GCRY_CIPHER_3DES:
 	case GCRY_CIPHER_DES:
-		r = setup_pkcs5_des_params (params, n_params, *cih);
+		r = setup_pkcs5_des_params (params, *cih);
 		break;
 	case GCRY_CIPHER_RFC2268_128:
-		r = setup_pkcs5_rc2_params (params, n_params, *cih);
+		r = setup_pkcs5_rc2_params (params, *cih);
 		break;
 	default:
 		/* Should have been caught on the oid check above */
@@ -912,7 +929,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 		break;
 	};
 
-	if (r != TRUE) 
+	if (r != TRUE)
 		goto done;
 
 	/* Read out the key creation paramaters */
@@ -924,11 +941,12 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 		goto done;
 	}
 
-	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL), &n_params);
+	egg_bytes_unref (params);
+	params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL));
 	if (!params)
 		goto done;
 
-	ret = setup_pkcs5_pbkdf2_params (password, n_password, params, n_params, algo, *cih);
+	ret = setup_pkcs5_pbkdf2_params (password, n_password, params, algo, *cih);
 
 done:
 	if (ret != TRUE && *cih) {
@@ -936,20 +954,24 @@ done:
 		*cih = NULL;
 	}
 
+	if (params != NULL)
+		egg_bytes_unref (params);
 	egg_asn1x_destroy (asn);
 	return ret;
 }
 
 static gboolean
-read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password, 
-                        gsize n_password, const guchar *data, gsize n_data, 
+read_cipher_pkcs12_pbe (int cipher_algo,
+                        int cipher_mode,
+                        const gchar *password,
+                        gsize n_password,
+                        EggBytes *data,
                         gcry_cipher_hd_t *cih)
 {
 	GNode *asn = NULL;
 	gcry_error_t gcry;
 	gboolean ret;
-	const guchar *salt;
-	gsize n_salt;
+	EggBytes *salt = NULL;
 	gsize n_block, n_key;
 	gulong iterations;
 	guchar *key = NULL;
@@ -957,52 +979,54 @@ read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password,
 
 	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);
-	
+	g_return_val_if_fail (data != NULL, FALSE);
+
 	*cih = NULL;
 	ret = FALSE;
-	
+
 	/* Check if we can use this algorithm */
 	if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
 		goto done;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PbeParams", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PbeParams", data);
 	if (!asn)
 		goto done;
 
-	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL), &n_salt);
+	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL));
 	if (!salt)
 		goto done;
 	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);
 	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
-	
+
 	/* Generate IV and key using salt read above */
-	if (!egg_symkey_generate_pkcs12 (cipher_algo, GCRY_MD_SHA1, password, 
-	                                        n_password, salt, n_salt, iterations, &key, 
-	                                        n_block > 1 ? &iv : NULL))
+	if (!egg_symkey_generate_pkcs12 (cipher_algo, GCRY_MD_SHA1, password, n_password,
+	                                 egg_bytes_get_data (salt), egg_bytes_get_size (salt),
+	                                 iterations, &key, n_block > 1 ? &iv : NULL))
 		goto done;
-		
+
 	gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0);
 	if (gcry != 0) {
 		g_warning ("couldn't create encryption cipher: %s", gcry_strerror (gcry));
 		goto done;
 	}
-	
-	if (iv) 
+
+	if (iv)
 		gcry_cipher_setiv (*cih, iv, n_block);
 	gcry_cipher_setkey (*cih, key, n_key);
-	
+
 	ret = TRUE;
-	
+
 done:
 	if (ret != TRUE && *cih) {
 		gcry_cipher_close (*cih);
 		*cih = NULL;
 	}
-	
+
+	if (salt != NULL)
+		egg_bytes_unref (salt);
 	g_free (iv);
 	egg_secure_free (key);
 	egg_asn1x_destroy (asn);
@@ -1013,8 +1037,7 @@ static gboolean
 read_mac_pkcs12_pbe (int hash_algo,
                      const gchar *password,
                      gsize n_password,
-                     const guchar *data,
-                     gsize n_data,
+                     EggBytes *data,
                      gcry_md_hd_t *mdh,
                      gsize *digest_len)
 {
@@ -1022,14 +1045,13 @@ read_mac_pkcs12_pbe (int hash_algo,
 	gcry_error_t gcry;
 	gboolean ret;
 	gsize n_key;
-	const guchar *salt;
-	gsize n_salt;
+	EggBytes *salt = NULL;
 	gulong iterations;
 	guchar *key = NULL;
 
 	g_return_val_if_fail (hash_algo != 0, FALSE);
 	g_return_val_if_fail (mdh != NULL, FALSE);
-	g_return_val_if_fail (data != NULL && n_data != 0, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
 
 	*mdh = NULL;
 	ret = FALSE;
@@ -1038,11 +1060,11 @@ read_mac_pkcs12_pbe (int hash_algo,
 	if (gcry_md_algo_info (hash_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
 		goto done;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-MacData", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-MacData", data);
 	if (!asn)
 		goto done;
 
-	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "macSalt", NULL), &n_salt);
+	salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "macSalt", NULL));
 	if (!salt)
 		goto done;
 	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
@@ -1052,7 +1074,8 @@ read_mac_pkcs12_pbe (int hash_algo,
 
 	/* Generate IV and key using salt read above */
 	if (!egg_symkey_generate_pkcs12_mac (hash_algo, password, n_password,
-	                                     salt, n_salt, iterations, &key))
+	                                     egg_bytes_get_data (salt), egg_bytes_get_size (salt),
+	                                     iterations, &key))
 		goto done;
 
 	gcry = gcry_md_open (mdh, hash_algo, GCRY_MD_FLAG_HMAC);
@@ -1073,82 +1096,86 @@ done:
 		*mdh = NULL;
 	}
 
+	if (salt != NULL)
+		egg_bytes_unref (salt);
 	egg_secure_free (key);
 	egg_asn1x_destroy (asn);
 	return ret;
 }
 
 gboolean
-egg_symkey_read_cipher (GQuark oid_scheme, const gchar *password, gsize n_password,
-                        const guchar *data, gsize n_data, gcry_cipher_hd_t *cih)
+egg_symkey_read_cipher (GQuark oid_scheme,
+                        const gchar *password,
+                        gsize n_password,
+                        EggBytes *data,
+                        gcry_cipher_hd_t *cih)
 {
 	gboolean ret = FALSE;
-	
+
 	g_return_val_if_fail (oid_scheme != 0, FALSE);
 	g_return_val_if_fail (cih != NULL, FALSE);
-	g_return_val_if_fail (data != NULL && n_data != 0, FALSE);
-	
+	g_return_val_if_fail (data != NULL, FALSE);
+
 	init_quarks ();
-	
+
 	/* PKCS#5 PBE */
 	if (oid_scheme == OID_PBE_MD2_DES_CBC)
 		ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
-		                             GCRY_MD_MD2, password, n_password, data, n_data, cih);
+		                             GCRY_MD_MD2, password, n_password, data, cih);
 
 	else if (oid_scheme == OID_PBE_MD2_RC2_CBC)
 		/* RC2-64 has no implementation in libgcrypt */;
 
 	else if (oid_scheme == OID_PBE_MD5_DES_CBC)
 		ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
-		                             GCRY_MD_MD5, password, n_password, data, n_data, cih);
+		                             GCRY_MD_MD5, password, n_password, data, cih);
 	else if (oid_scheme == OID_PBE_MD5_RC2_CBC)
 		/* RC2-64 has no implementation in libgcrypt */;
 
 	else if (oid_scheme == OID_PBE_SHA1_DES_CBC)
 		ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
-		                             GCRY_MD_SHA1, password, n_password, data, n_data, cih);
+		                             GCRY_MD_SHA1, password, n_password, data, cih);
 	else if (oid_scheme == OID_PBE_SHA1_RC2_CBC)
 		/* RC2-64 has no implementation in libgcrypt */;
 
-	
+
 	/* PKCS#5 PBES2 */
 	else if (oid_scheme == OID_PBES2)
-		ret = read_cipher_pkcs5_pbes2 (password, n_password, data, n_data, cih);
+		ret = read_cipher_pkcs5_pbes2 (password, n_password, data, cih);
+
 
-		
 	/* PKCS#12 PBE */
 	else if (oid_scheme == OID_PKCS12_PBE_ARCFOUR_SHA1)
-		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 
-		                              password, n_password, data, n_data, cih);
+		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM,
+		                              password, n_password, data, cih);
 	else if (oid_scheme == OID_PKCS12_PBE_RC4_40_SHA1)
 		/* RC4-40 has no implementation in libgcrypt */;
 
 	else if (oid_scheme == OID_PKCS12_PBE_3DES_SHA1)
-		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 
-		                              password, n_password, data, n_data, cih);
-	else if (oid_scheme == OID_PKCS12_PBE_2DES_SHA1) 
+		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC,
+		                              password, n_password, data, cih);
+	else if (oid_scheme == OID_PKCS12_PBE_2DES_SHA1)
 		/* 2DES has no implementation in libgcrypt */;
-		
+
 	else if (oid_scheme == OID_PKCS12_PBE_RC2_128_SHA1)
-		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_128, GCRY_CIPHER_MODE_CBC, 
-		                              password, n_password, data, n_data, cih);
+		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_128, GCRY_CIPHER_MODE_CBC,
+		                              password, n_password, data, cih);
 
 	else if (oid_scheme == OID_PKCS12_PBE_RC2_40_SHA1)
-		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_40, GCRY_CIPHER_MODE_CBC, 
-		                              password, n_password, data, n_data, cih);
+		ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_40, GCRY_CIPHER_MODE_CBC,
+		                              password, n_password, data, cih);
 
 	if (ret == FALSE)
-    		g_message ("unsupported or invalid cipher: %s", g_quark_to_string (oid_scheme));
-	
-    	return ret;
+		g_message ("unsupported or invalid cipher: %s", g_quark_to_string (oid_scheme));
+
+	return ret;
 }
 
 gboolean
 egg_symkey_read_mac (GQuark oid_scheme,
                      const gchar *password,
                      gsize n_password,
-                     const guchar *data,
-                     gsize n_data,
+                     EggBytes *data,
                      gcry_md_hd_t *mdh,
                      gsize *digest_len)
 {
@@ -1156,14 +1183,14 @@ egg_symkey_read_mac (GQuark oid_scheme,
 
 	g_return_val_if_fail (oid_scheme != 0, FALSE);
 	g_return_val_if_fail (mdh != NULL, FALSE);
-	g_return_val_if_fail (data != NULL && n_data != 0, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
 
 	init_quarks ();
 
 	/* PKCS#12 MAC with SHA-1 */
 	if (oid_scheme == OID_SHA1)
 		ret = read_mac_pkcs12_pbe (GCRY_MD_SHA1, password, n_password,
-		                           data, n_data, mdh, digest_len);
+		                           data, mdh, digest_len);
 
 	if (ret == FALSE)
 		g_message ("unsupported or invalid mac: %s", g_quark_to_string (oid_scheme));
diff --git a/egg/egg-symkey.h b/egg/egg-symkey.h
index 21feab6..de9eb8b 100644
--- a/egg/egg-symkey.h
+++ b/egg/egg-symkey.h
@@ -1,13 +1,13 @@
-/* 
+/*
  * gnome-keyring
- * 
+ *
  * Copyright (C) 2008 Stefan Walter
  * 
  * This program is free software; you can redistribute it and/or modify 
  * it under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
- *  
+ *
  * This program 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
@@ -16,7 +16,7 @@
  * You should have received a copy of the GNU Lesser General 
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.  
+ * 02111-1307, USA.
  */
 
 #ifndef EGG_SYMKEY_H_
@@ -26,34 +26,36 @@
 
 #include <gcrypt.h>
 
-gboolean                 egg_symkey_generate_simple             (int cipher_algo, 
-                                                                 int hash_algo, 
-                                                                 const gchar *password, 
+#include <egg/egg-bytes.h>
+
+gboolean                 egg_symkey_generate_simple             (int cipher_algo,
+                                                                 int hash_algo,
+                                                                 const gchar *password,
                                                                  gssize n_password,
-                                                                 const guchar *salt, 
-                                                                 gsize n_salt, 
-                                                                 int iterations, 
-                                                                 guchar **key, 
+                                                                 const guchar *salt,
+                                                                 gsize n_salt,
+                                                                 int iterations,
+                                                                 guchar **key,
                                                                  guchar **iv);
 
-gboolean                 egg_symkey_generate_pbe                (int cipher_algo, 
-                                                                 int hash_algo, 
+gboolean                 egg_symkey_generate_pbe                (int cipher_algo,
+                                                                 int hash_algo,
                                                                  const gchar *password,
                                                                  gssize n_password,
-                                                                 const guchar *salt, 
-                                                                 gsize n_salt, 
-                                                                 int iterations, 
-                                                                 guchar **key, 
+                                                                 const guchar *salt,
+                                                                 gsize n_salt,
+                                                                 int iterations,
+                                                                 guchar **key,
                                                                  guchar **iv);
 
-gboolean                 egg_symkey_generate_pkcs12             (int cipher_algo, 
+gboolean                 egg_symkey_generate_pkcs12             (int cipher_algo,
                                                                  int hash_algo,
                                                                  const gchar *password,
                                                                  gssize n_password,
                                                                  const guchar *salt,
                                                                  gsize n_salt,
                                                                  int iterations,
-                                                                 guchar **key, 
+                                                                 guchar **key,
                                                                  guchar **iv);
 
 gboolean                 egg_symkey_generate_pkcs12_mac         (int hash_algo,
@@ -64,28 +66,26 @@ gboolean                 egg_symkey_generate_pkcs12_mac         (int hash_algo,
                                                                  int iterations,
                                                                  guchar **key);
 
-gboolean                 egg_symkey_generate_pbkdf2             (int cipher_algo, 
-                                                                 int hash_algo, 
+gboolean                 egg_symkey_generate_pbkdf2             (int cipher_algo,
+                                                                 int hash_algo,
                                                                  const gchar *password,
                                                                  gssize n_password,
-                                                                 const guchar *salt, 
-                                                                 gsize n_salt, 
-                                                                 int iterations, 
-                                                                 guchar **key, 
+                                                                 const guchar *salt,
+                                                                 gsize n_salt,
+                                                                 int iterations,
+                                                                 guchar **key,
                                                                  guchar **iv);
 
-gboolean                 egg_symkey_read_cipher                 (GQuark oid_scheme, 
+gboolean                 egg_symkey_read_cipher                 (GQuark oid_scheme,
                                                                  const gchar *password,
-                                                                 gsize n_password, 
-                                                                 const guchar *data, 
-                                                                 gsize n_data, 
+                                                                 gsize n_password,
+                                                                 EggBytes *data,
                                                                  gcry_cipher_hd_t *cih);
 
 gboolean                 egg_symkey_read_mac                    (GQuark oid_scheme,
                                                                  const gchar *password,
                                                                  gsize n_password,
-                                                                 const guchar *data,
-                                                                 gsize n_data,
+                                                                 EggBytes *data,
                                                                  gcry_md_hd_t *mdh,
                                                                  gsize *digest_len);
 
diff --git a/egg/egg-testing.h b/egg/egg-testing.h
index 8dca086..5b4c911 100644
--- a/egg/egg-testing.h
+++ b/egg/egg-testing.h
@@ -37,6 +37,13 @@
 	            G_STRFUNC, #a "[" #na"] " #cmp " " #b "[" #nb "]", \
                     __p1, __n1, #cmp, __p2, __n2); } while (0)
 
+#define egg_assert_cmpbytes(a, cmp, b, nb) \
+	do { gpointer __p1 = (gpointer)(a); gconstpointer __p2 = (b); gsize __n2 = (nb); \
+	     if (egg_bytes_get_size (__p1) cmp __n2 && memcmp (egg_bytes_get_data (__p1), __p2, __n2) cmp 0) ; else \
+	        egg_assertion_message_cmpmem (G_LOG_DOMAIN, __FILE__, __LINE__, \
+	            G_STRFUNC, #a " " #cmp " " #b, \
+                    egg_bytes_get_data (__p1), egg_bytes_get_size(__p1), #cmp, __p2, __n2); } while (0)
+
 void       egg_assertion_message_cmpmem        (const char *domain, const char *file,
                                                 int line, const char *func,
                                                 const char *expr, gconstpointer arg1,
diff --git a/egg/tests/Makefile.am b/egg/tests/Makefile.am
index aa5fac7..a6d51e1 100644
--- a/egg/tests/Makefile.am
+++ b/egg/tests/Makefile.am
@@ -1,6 +1,12 @@
+include $(top_srcdir)/Makefile.decl
 
-asn1-def-test.c: test.asn
-	$(ASN1PARSER) -o asn1-def-test.c $(srcdir)/test.asn
+ASN_FILES = \
+	test.asn
+
+ASN_SRCS = $(ASN_FILES:.asn=.asn.h)
+
+BUILT_SOURCES = \
+	$(ASN_SRCS)
 
 INCLUDES = \
 	-I$(top_builddir) \
@@ -30,7 +36,7 @@ TEST_PROGS = \
 
 test_asn1_SOURCES = \
 	test-asn1.c \
-	asn1-def-test.c
+	$(ASN_SRCS)
 
 check_PROGRAMS = $(TEST_PROGS)
 
@@ -42,11 +48,11 @@ check-local: test
 all-local: $(check_PROGRAMS)
 
 EXTRA_DIST = \
-	test.asn \
+	$(ASN_FILES) \
 	files
 
 DISTCLEANFILES = \
-	asn1-def-test.c
+	$(ASN_SRCS)
 
 # ------------------------------------------------------------------------------
 
diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c
index 9403ebb..7844c92 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -28,13 +28,13 @@
 #include "egg/egg-testing.h"
 
 #include <glib.h>
-#include <libtasn1.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
-extern const ASN1_ARRAY_TYPE test_asn1_tab[];
+typedef struct _EggAsn1xDef ASN1_ARRAY_TYPE;
+#include "test.asn.h"
 
 const gchar I33[] =           "\x02\x01\x2A";
 const gchar I253[] =           "\x02\x02\x00\xFD";
@@ -42,7 +42,8 @@ const gchar BFALSE[] =        "\x01\x01\x00";
 const gchar BTRUE[] =         "\x01\x01\xFF";
 const gchar SFARNSWORTH[] =   "\x04\x0A""farnsworth";
 const gchar SIMPLICIT[] =     "\x85\x08""implicit";
-const gchar SEXPLICIT[] =     "\xE5\x0A\x04\x08""explicit";
+const gchar SEXPLICIT[] =     "\xA5\x0A\x04\x08""explicit";
+const gchar SUNIVERSAL[] =    "\x05\x09""universal";
 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";
@@ -60,31 +61,38 @@ const gchar ENUM_THREE[] =           "\x0A\x01\x03";
 static void
 test_boolean (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	gboolean value;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestBoolean");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_BOOLEAN, ==, egg_asn1x_type (asn));
+
 	/* Shouldn't succeed */
 	if (egg_asn1x_get_boolean (asn, &value))
 		g_assert_not_reached ();
 
 	/* Decode a false */
-	if (!egg_asn1x_decode (asn, BFALSE, XL (BFALSE)))
+	bytes = egg_bytes_new_static (BFALSE, XL (BFALSE));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
 	value = TRUE;
 	if (!egg_asn1x_get_boolean (asn, &value))
 		g_assert_not_reached ();
 	g_assert (value == FALSE);
+	egg_bytes_unref (bytes);
 
 	/* Decode a true */
-	if (!egg_asn1x_decode (asn, BTRUE, XL (BTRUE)))
+	bytes = egg_bytes_new_static (BTRUE, XL (BTRUE));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
 	value = FALSE;
 	if (!egg_asn1x_get_boolean (asn, &value))
 		g_assert_not_reached ();
 	g_assert (value == TRUE);
+	egg_bytes_unref (bytes);
 
 	egg_asn1x_clear (asn);
 
@@ -99,23 +107,24 @@ static void
 test_null (void)
 {
 	GNode *asn;
-	gpointer data;
-	gsize n_data;
+	EggBytes *data;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestNull");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_NULL, ==, egg_asn1x_type (asn));
+
 	if (!egg_asn1x_set_null (asn))
 		g_assert_not_reached ();
 
-	data = egg_asn1x_encode (asn, g_realloc, &n_data);
-	egg_assert_cmpmem (NULL_TEST, XL (NULL_TEST), ==, data, n_data);
+	data = egg_asn1x_encode (asn, g_realloc);
+	egg_assert_cmpmem (NULL_TEST, XL (NULL_TEST), ==, egg_bytes_get_data (data), egg_bytes_get_size (data));
 
-	if (!egg_asn1x_decode (asn, data, n_data))
+	if (!egg_asn1x_decode (asn, data))
 		g_assert_not_reached ();
 
 	egg_asn1x_destroy (asn);
-	g_free (data);
+	egg_bytes_unref (data);
 }
 
 static void
@@ -123,20 +132,25 @@ test_integer (void)
 {
 	GNode *asn;
 	gulong value;
+	EggBytes *bytes;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestInteger");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_INTEGER, ==, egg_asn1x_type (asn));
+
 	/* Shouldn't succeed */
 	if (egg_asn1x_get_integer_as_ulong (asn, &value))
 		g_assert_not_reached ();
 
 	/* Should suceed now */
-	if (!egg_asn1x_decode (asn, I33, XL (I33)))
+	bytes = egg_bytes_new_static (I33, XL (I33));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
 	if (!egg_asn1x_get_integer_as_ulong (asn, &value))
 		g_assert_not_reached ();
 	g_assert (value == 42);
+	egg_bytes_unref (bytes);
 
 	egg_asn1x_clear (asn);
 
@@ -152,50 +166,55 @@ test_unsigned (void)
 {
 	GNode *asn;
 	gulong value;
-	guchar *check;
-	gsize n_check;
+	EggBytes *check;
 	guchar val;
-	gconstpointer usg;
-	gsize n_usg;
+	EggBytes *bytes;
+	EggBytes *usg;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestInteger");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_INTEGER, ==, egg_asn1x_type (asn));
+
 	/* Check with ulong */
-	if (!egg_asn1x_decode (asn, I253, XL (I253)))
+	bytes = egg_bytes_new_static (I253, XL (I253));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
 	if (!egg_asn1x_get_integer_as_ulong (asn, &value))
 		g_assert_not_reached ();
 	g_assert (value == 253);
+	egg_bytes_unref (bytes);
 
 	egg_asn1x_clear (asn);
 
 	if (!egg_asn1x_set_integer_as_ulong (asn, 253))
 		g_assert_not_reached ();
 
-	check = egg_asn1x_encode (asn, NULL, &n_check);
-	egg_assert_cmpmem (check, n_check, ==, I253, XL (I253));
+	check = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpmem (I253, XL (I253), ==, egg_bytes_get_data (check), egg_bytes_get_size (check));
+	egg_bytes_unref (check);
 
 	/* Now check with usg */
-	if (!egg_asn1x_decode (asn, I253, XL (I253)))
+	bytes = egg_bytes_new_static (I253, XL (I253));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
-	g_free (check);
+	egg_bytes_unref (bytes);
 
 	val = 0xFD; /* == 253 */
-	usg = egg_asn1x_get_integer_as_usg (asn, &n_usg);
-	egg_assert_cmpmem (&val, 1, ==, usg, n_usg);
+	usg = egg_asn1x_get_integer_as_usg (asn);
+	egg_assert_cmpmem (&val, 1, ==, egg_bytes_get_data (usg), egg_bytes_get_size (usg));
+	egg_bytes_unref (usg);
 
 	egg_asn1x_clear (asn);
 
-	if (!egg_asn1x_set_integer_as_usg (asn, &val, 1, NULL))
-		g_assert_not_reached ();
+	egg_asn1x_take_integer_as_usg (asn, egg_bytes_new_static (&val, 1));
 
-	check = egg_asn1x_encode (asn, NULL, &n_check);
-	egg_assert_cmpsize (n_check, ==, XL (I253));
-	egg_assert_cmpmem (check, n_check, ==, I253, XL (I253));
+	check = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpsize (egg_bytes_get_size (check), ==, XL (I253));
+	egg_assert_cmpmem (I253, XL (I253), ==, egg_bytes_get_data (check), egg_bytes_get_size (check));
+	egg_bytes_unref (check);
 
 	egg_asn1x_destroy (asn);
-	g_free (check);
 }
 
 static void
@@ -203,17 +222,23 @@ test_octet_string (void)
 {
 	GNode *asn;
 	gchar *value;
+	EggBytes *bytes;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestOctetString");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_OCTET_STRING, ==, egg_asn1x_type (asn));
+
 	/* Shouldn't succeed */
 	if (egg_asn1x_get_string_as_utf8 (asn, NULL))
 		g_assert_not_reached ();
 
 	/* Should work */
-	if (!egg_asn1x_decode (asn, SFARNSWORTH, XL (SFARNSWORTH)))
+	bytes = egg_bytes_new_static (SFARNSWORTH, XL (SFARNSWORTH));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
+
 	value = egg_asn1x_get_string_as_utf8 (asn, NULL);
 	g_assert_cmpstr (value, ==, "farnsworth");
 	g_free (value);
@@ -230,19 +255,24 @@ test_octet_string (void)
 static void
 test_generalized_time (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	glong value;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestGeneralized");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_TIME, ==, egg_asn1x_type (asn));
+
 	/* Shouldn't succeed */
 	value = egg_asn1x_get_time_as_long (asn);
 	g_assert (value == -1);
 
 	/* Should work */
-	if (!egg_asn1x_decode (asn, TGENERALIZED, XL (TGENERALIZED)))
+	bytes = egg_bytes_new_static (TGENERALIZED, XL (TGENERALIZED));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 	value = egg_asn1x_get_time_as_long (asn);
 	g_assert (value == 1185368728);
 
@@ -256,8 +286,9 @@ test_generalized_time (void)
 }
 
 static void
-test_implicit (void)
+test_implicit_encode (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	gchar *value;
 
@@ -265,8 +296,10 @@ test_implicit (void)
 	g_assert (asn);
 
 	/* Should work */
-	if (!egg_asn1x_decode (asn, SIMPLICIT, XL (SIMPLICIT)))
+	bytes = egg_bytes_new_static (SIMPLICIT, XL (SIMPLICIT));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 	value = egg_asn1x_get_string_as_utf8 (asn, NULL);
 	g_assert_cmpstr (value, ==, "implicit");
 	g_free (value);
@@ -275,8 +308,28 @@ test_implicit (void)
 }
 
 static void
-test_explicit (void)
+test_implicit_decode (void)
 {
+	EggBytes *bytes;
+	GNode *asn;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestImplicit");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_string_as_utf8 (asn, g_strdup ("implicit"), g_free))
+		g_assert_not_reached ();
+
+	bytes = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpbytes (bytes, ==, SIMPLICIT, XL (SIMPLICIT));
+
+	egg_asn1x_destroy (asn);
+	egg_bytes_unref (bytes);
+}
+
+static void
+test_explicit_decode (void)
+{
+	EggBytes *bytes;
 	GNode *asn;
 	gchar *value;
 
@@ -284,8 +337,11 @@ test_explicit (void)
 	g_assert (asn);
 
 	/* Should work */
-	if (!egg_asn1x_decode (asn, SEXPLICIT, XL (SEXPLICIT)))
+	bytes = egg_bytes_new_static (SEXPLICIT, XL (SEXPLICIT));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
+
 	value = egg_asn1x_get_string_as_utf8 (asn, NULL);
 	g_assert_cmpstr (value, ==, "explicit");
 	g_free (value);
@@ -294,41 +350,112 @@ test_explicit (void)
 }
 
 static void
+test_explicit_encode (void)
+{
+	EggBytes *bytes;
+	GNode *asn;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestExplicit");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_string_as_utf8 (asn, g_strdup ("explicit"), g_free))
+		g_assert_not_reached ();
+
+	bytes = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpbytes (bytes, ==, SEXPLICIT, XL (SEXPLICIT));
+
+	egg_asn1x_destroy (asn);
+	egg_bytes_unref (bytes);
+}
+
+static void
+test_universal_decode (void)
+{
+	EggBytes *bytes;
+	GNode *asn;
+	gchar *value;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestUniversal");
+	g_assert (asn);
+
+	/* Should work */
+	bytes = egg_bytes_new_static (SUNIVERSAL, XL (SUNIVERSAL));
+	if (!egg_asn1x_decode (asn, bytes))
+		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
+
+	value = egg_asn1x_get_string_as_utf8 (asn, NULL);
+	g_assert_cmpstr (value, ==, "universal");
+	g_free (value);
+
+	egg_asn1x_destroy (asn);
+}
+
+static void
+test_universal_encode (void)
+{
+	EggBytes *bytes;
+	GNode *asn;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestUniversal");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_string_as_utf8 (asn, g_strdup ("universal"), g_free))
+		g_assert_not_reached ();
+
+	bytes = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpbytes (bytes, ==, SUNIVERSAL, XL (SUNIVERSAL));
+
+	egg_asn1x_destroy (asn);
+	egg_bytes_unref (bytes);
+}
+
+static void
 test_bit_string_decode (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
-	guchar *bits;
+	EggBytes *bits;
 	guint n_bits;
+	const guchar *data;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_BIT_STRING, ==, egg_asn1x_type (asn));
+
 	/* Should work */
-	if (!egg_asn1x_decode (asn, BITS_TEST, XL (BITS_TEST)))
+	bytes = egg_bytes_new_static (BITS_TEST, XL (BITS_TEST));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 
-	bits = egg_asn1x_get_bits_as_raw (asn, NULL, &n_bits);
-	g_assert (bits);
+	bits = egg_asn1x_get_bits_as_raw (asn, &n_bits);
+	g_assert (bits != NULL);
 	g_assert_cmpuint (n_bits, ==, 18);
-	g_assert_cmpint (bits[0], ==, 0x6e);
-	g_assert_cmpint (bits[1], ==, 0x5d);
-	g_assert_cmpint (bits[2], ==, 0xc0);
+	data = egg_bytes_get_data (bits);
+	g_assert_cmpint (data[0], ==, 0x6e);
+	g_assert_cmpint (data[1], ==, 0x5d);
+	g_assert_cmpint (data[2], ==, 0xc0);
 
-	g_free (bits);
+	egg_bytes_unref (bits);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_bit_string_decode_bad (void)
 {
+	EggBytes *bytes;
 	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)))
+	bytes = egg_bytes_new_static (BITS_BAD, XL (BITS_BAD));
+	if (egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 
 	egg_asn1x_destroy (asn);
 }
@@ -336,6 +463,7 @@ test_bit_string_decode_bad (void)
 static void
 test_bit_string_decode_ulong (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	gulong bits;
 	guint n_bits;
@@ -344,8 +472,10 @@ test_bit_string_decode_ulong (void)
 	g_assert (asn);
 
 	/* Should work */
-	if (!egg_asn1x_decode (asn, BITS_TEST, XL (BITS_TEST)))
+	bytes = egg_bytes_new_static (BITS_TEST, XL (BITS_TEST));
+	if (!egg_asn1x_decode (asn, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 
 	if (!egg_asn1x_get_bits_as_ulong (asn, &bits, &n_bits))
 		g_assert_not_reached ();
@@ -359,46 +489,46 @@ test_bit_string_decode_ulong (void)
 static void
 test_bit_string_encode_decode (void)
 {
+	EggBytes *data;
 	GNode *asn;
 	guchar bits[] = { 0x5d, 0x6e, 0x83 };
-	guchar *check;
-	guint n_check, n_bits = 17;
-	gpointer data;
-	gsize n_data;
+	EggBytes *check;
+	const guchar *ch;
+	guint n_bits = 17;
+	guint n_check;
 
 	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 ();
+	egg_asn1x_take_bits_as_raw (asn, egg_bytes_new (bits, 3), n_bits);
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
+	data = egg_asn1x_encode (asn, NULL);
 	g_assert (data);
 
-	if (!egg_asn1x_decode (asn, data, n_data))
+	if (!egg_asn1x_decode (asn, 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);
+	egg_bytes_unref (data);
 
-	g_free (check);
+	check = egg_asn1x_get_bits_as_raw (asn, &n_check);
+	g_assert (check != NULL);
+	g_assert_cmpuint (n_check, ==, 17);
+	ch = egg_bytes_get_data (check);
+	g_assert_cmpint (ch[0], ==, 0x5d);
+	g_assert_cmpint (ch[1], ==, 0x6e);
+	g_assert_cmpint (ch[2], ==, 0x80);
 
-	g_free (data);
+	egg_bytes_unref (check);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_bit_string_encode_decode_ulong (void)
 {
+	EggBytes *data;
 	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);
@@ -406,51 +536,48 @@ test_bit_string_encode_decode_ulong (void)
 	if (!egg_asn1x_set_bits_as_ulong (asn, bits, n_bits))
 		g_assert_not_reached ();
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
+	data = egg_asn1x_encode (asn, NULL);
 	g_assert (data);
 
-	if (!egg_asn1x_decode (asn, data, n_data))
+	if (!egg_asn1x_decode (asn, data))
 		g_assert_not_reached ();
 
+	egg_bytes_unref (data);
+
 	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);
 }
 
 static void
 test_bit_string_encode_decode_zero (void)
 {
+	EggBytes *data;
 	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 ();
+	egg_asn1x_take_bits_as_raw (asn, egg_bytes_new_static ("", 0), 0);
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
+	data = egg_asn1x_encode (asn, NULL);
 	g_assert (data);
 
-	egg_assert_cmpsize (n_data, ==, XL (BITS_ZERO));
-	g_assert (memcmp (data, BITS_ZERO, n_data) == 0);
+	egg_assert_cmpmem (egg_bytes_get_data (data), egg_bytes_get_size (data), ==, BITS_ZERO, XL (BITS_ZERO));
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_have (void)
 {
+	EggBytes *data;
 	GNode *asn;
-	guchar *data;
-	gsize n_data;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestBoolean");
 	g_assert (asn);
@@ -462,12 +589,12 @@ test_have (void)
 
 	g_assert (!egg_asn1x_have (asn));
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
+	data = egg_asn1x_encode (asn, NULL);
 	g_assert (data);
 
 	g_assert (egg_asn1x_have (asn));
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
@@ -483,10 +610,10 @@ test_is_freed (gpointer unused)
 static void
 test_any_set_raw (void)
 {
+	EggBytes *bytes;
 	GNode *asn, *node;
-	guchar *data;
-	const guchar *check;
-	gsize n_data, n_check;
+	EggBytes *data;
+	EggBytes *check;
 
 	/* ENCODED SEQUENCE ANY with OCTET STRING */
 	const gchar SEQ_ENCODING[] =  "\x30\x0C\x04\x0A""farnsworth";
@@ -498,22 +625,24 @@ test_any_set_raw (void)
 	node = egg_asn1x_node (asn, "contents", NULL);
 	g_assert (node);
 
-	if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
+	bytes = egg_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH),
+	                                      test_is_freed, NULL);
+	if (!egg_asn1x_set_element_raw (node, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	g_assert (data);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data != NULL);
 
-	egg_assert_cmpsize (n_data, ==, XL (SEQ_ENCODING));
-	g_assert (memcmp (data, SEQ_ENCODING, n_data) == 0);
+	egg_assert_cmpbytes (data, ==, SEQ_ENCODING, XL (SEQ_ENCODING));
 
-	check = egg_asn1x_get_raw_element (node, &n_check);
+	check = egg_asn1x_get_element_raw (node);
 	g_assert (check);
 
-	egg_assert_cmpsize (n_check, ==, XL (SFARNSWORTH));
-	g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+	egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH));
 
-	g_free (data);
+	egg_bytes_unref (data);
+	egg_bytes_unref (check);
 	egg_asn1x_destroy (asn);
 	g_assert (is_freed);
 }
@@ -521,10 +650,10 @@ test_any_set_raw (void)
 static void
 test_any_set_raw_explicit (void)
 {
+	EggBytes *bytes;
 	GNode *asn, *node;
-	guchar *data;
-	const guchar *check;
-	gsize n_data, n_check;
+	EggBytes *data;
+	EggBytes *check;
 
 	/* ENCODED SEQUENCE [89] ANY with OCTET STRING */
 	const gchar SEQ_ENCODING[] =  "\x30\x0F\xBF\x59\x0C\x04\x0A""farnsworth";
@@ -536,22 +665,23 @@ test_any_set_raw_explicit (void)
 	node = egg_asn1x_node (asn, "contents", NULL);
 	g_assert (node);
 
-	if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
+	bytes = egg_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), test_is_freed, NULL);
+	if (!egg_asn1x_set_element_raw (node, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	g_assert (data);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data != NULL);
 
-	egg_assert_cmpsize (n_data, ==, XL (SEQ_ENCODING));
-	g_assert (memcmp (data, SEQ_ENCODING, n_data) == 0);
+	egg_assert_cmpbytes (data, ==, SEQ_ENCODING, XL (SEQ_ENCODING));
 
-	check = egg_asn1x_get_raw_element (node, &n_check);
+	check = egg_asn1x_get_element_raw (node);
 	g_assert (check);
 
-	g_assert (n_check == XL (SFARNSWORTH));
-	g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+	egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH));
 
-	g_free (data);
+	egg_bytes_unref (data);
+	egg_bytes_unref (check);
 	egg_asn1x_destroy (asn);
 	g_assert (is_freed);
 }
@@ -559,22 +689,26 @@ test_any_set_raw_explicit (void)
 static void
 test_choice_not_chosen (void)
 {
+	EggBytes *bytes;
 	GNode *asn, *node;
-	guchar *data;
-	gsize n_data;
+	EggBytes *data;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestAnyChoice");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_CHOICE, ==, egg_asn1x_type (asn));
+
 	node = egg_asn1x_node (asn, "choiceShortTag", NULL);
 	g_assert (node);
 
-	if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), NULL))
+	bytes = egg_bytes_new_static (SFARNSWORTH, XL (SFARNSWORTH));
+	if (!egg_asn1x_set_element_raw (node, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 
 	/* egg_asn1x_set_choice() was not called */
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	g_assert (!data);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data == NULL);
 	g_assert (egg_asn1x_message (asn));
 	g_assert (strstr (egg_asn1x_message (asn), "TestAnyChoice") != NULL);
 
@@ -584,14 +718,16 @@ test_choice_not_chosen (void)
 static void
 perform_asn1_any_choice_set_raw (const gchar *choice, const gchar *encoding, gsize n_encoding)
 {
+	EggBytes *bytes;
 	GNode *asn, *node;
-	guchar *data;
-	const guchar *check;
-	gsize n_data, n_check;
+	EggBytes *data;
+	EggBytes *check;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestAnyChoice");
 	g_assert (asn);
 
+	g_assert_cmpint (EGG_ASN1X_CHOICE, ==, egg_asn1x_type (asn));
+
 	is_freed = FALSE;
 	node = egg_asn1x_node (asn, choice, NULL);
 	g_assert (node);
@@ -599,26 +735,27 @@ perform_asn1_any_choice_set_raw (const gchar *choice, const gchar *encoding, gsi
 	if (!egg_asn1x_set_choice (asn, node))
 		g_assert_not_reached ();
 
-	if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
+	bytes = egg_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), test_is_freed, NULL);
+	if (!egg_asn1x_set_element_raw (node, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	if (!data) {
+	data = egg_asn1x_encode (asn, NULL);
+	if (data == NULL) {
 		g_printerr ("%s\n", egg_asn1x_message (asn));
 		g_assert_not_reached ();
 	}
-	g_assert (data);
+	g_assert (data != NULL);
 
-	egg_assert_cmpsize (n_data, ==, n_encoding);
-	g_assert (memcmp (data, encoding, n_data) == 0);
+	egg_assert_cmpbytes (data, ==, encoding, n_encoding);
 
-	check = egg_asn1x_get_raw_element (node, &n_check);
-	g_assert (check);
+	check = egg_asn1x_get_element_raw (node);
+	g_assert (check != NULL);
 
-	g_assert (n_check == XL (SFARNSWORTH));
-	g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+	egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH));
 
-	g_free (data);
+	egg_bytes_unref (data);
+	egg_bytes_unref (check);
 	egg_asn1x_destroy (asn);
 	g_assert (is_freed);
 }
@@ -640,10 +777,10 @@ test_any_choice_set_raw_long_tag (void)
 static void
 test_append (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	GNode *child;
-	gpointer data;
-	gsize n_data;
+	EggBytes *data;
 
 	/* SEQUENCE OF with one INTEGER = 1 */
 	const gchar SEQOF_ONE[] =  "\x30\x03\x02\x01\x01";
@@ -651,8 +788,12 @@ test_append (void)
 	/* SEQUENCE OF with two INTEGER = 1, 2 */
 	const gchar SEQOF_TWO[] =  "\x30\x06\x02\x01\x01\x02\x01\x02";
 
-	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestSeqOf", SEQOF_ONE, XL (SEQOF_ONE));
+	bytes = egg_bytes_new_static (SEQOF_ONE, XL (SEQOF_ONE));
+	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestSeqOf", bytes);
 	g_assert (asn);
+	egg_bytes_unref (bytes);
+
+	g_assert_cmpint (EGG_ASN1X_SEQUENCE_OF, ==, egg_asn1x_type (asn));
 
 	child = egg_asn1x_append (asn);
 	g_assert (child);
@@ -661,22 +802,20 @@ test_append (void)
 	if (!egg_asn1x_set_integer_as_ulong (child, 2))
 		g_assert_not_reached ();
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	g_assert (data);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data != NULL);
 
-	g_assert (n_data == XL (SEQOF_TWO));
-	g_assert (memcmp (data, SEQOF_TWO, n_data) == 0);
+	egg_assert_cmpbytes (data, ==, SEQOF_TWO, XL (SEQOF_TWO));
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_append_and_clear (void)
 {
+	EggBytes *data;
 	GNode *asn;
-	gpointer data;
-	gsize n_data;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestSeqOf");
 	g_assert (asn);
@@ -690,8 +829,8 @@ test_append_and_clear (void)
 
 	g_assert_cmpuint (egg_asn1x_count (asn), ==, 0);
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	g_assert (data);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data != NULL);
 
 	g_assert_cmpuint (egg_asn1x_count (asn), ==, 2);
 
@@ -699,15 +838,15 @@ test_append_and_clear (void)
 	g_assert_cmpuint (egg_asn1x_count (asn), ==, 0);
 
 	egg_asn1x_destroy (asn);
-	g_free (data);
+	egg_bytes_unref (data);
 }
 
 static void
 test_setof (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
-	gpointer data;
-	gsize n_data;
+	EggBytes *data;
 
 	/* SEQUENCE OF with one INTEGER = 3 */
 	const gchar SETOF_ONE[] =  "\x31\x03\x02\x01\x03";
@@ -715,8 +854,12 @@ test_setof (void)
 	/* SET OF with two INTEGER = 1, 3, 8 */
 	const gchar SETOF_THREE[] =  "\x31\x09\x02\x01\x01\x02\x01\x03\x02\x01\x08";
 
-	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestSetOf", SETOF_ONE, XL (SETOF_ONE));
-	g_assert (asn);
+	bytes = egg_bytes_new_static (SETOF_ONE, XL (SETOF_ONE));
+	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestSetOf", bytes);
+	g_assert (asn != NULL);
+	egg_bytes_unref (bytes);
+
+	g_assert_cmpint (EGG_ASN1X_SET_OF, ==, egg_asn1x_type (asn));
 
 	/* Add integer 1, in SET OF DER should sort to front */
 	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 1))
@@ -726,25 +869,23 @@ test_setof (void)
 	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 8))
 		g_assert_not_reached ();
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	if (!data) {
+	data = egg_asn1x_encode (asn, NULL);
+	if (data == NULL) {
 		g_printerr ("%s\n", egg_asn1x_message (asn));
 		g_assert_not_reached ();
 	}
 
-	g_assert (n_data == XL (SETOF_THREE));
-	g_assert (memcmp (data, SETOF_THREE, n_data) == 0);
+	egg_assert_cmpbytes (data, ==, SETOF_THREE, XL (SETOF_THREE));
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_setof_empty (void)
 {
+	EggBytes *data;
 	GNode *asn;
-	gpointer data;
-	gsize n_data;
 
 	/* SEQUENCE OF with nothing */
 	const gchar SETOF_NONE[] =  "\x31\x00";
@@ -752,29 +893,32 @@ test_setof_empty (void)
 	asn = egg_asn1x_create (test_asn1_tab, "TestSetOf");
 	g_assert (asn);
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	if (!data) {
+	data = egg_asn1x_encode (asn, NULL);
+	if (data == NULL) {
 		g_printerr ("%s\n", egg_asn1x_message (asn));
 		g_assert_not_reached ();
 	}
 
-	g_assert (n_data == XL (SETOF_NONE));
-	g_assert (memcmp (data, SETOF_NONE, n_data) == 0);
+	egg_assert_cmpbytes (data, ==, SETOF_NONE, XL (SETOF_NONE));
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_enumerated (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
-	gpointer data;
-	gsize n_data;
+	EggBytes *data;
 	GQuark value;
 
-	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestEnumerated", ENUM_TWO, XL (ENUM_TWO));
-	g_assert (asn);
+	bytes = egg_bytes_new_static (ENUM_TWO, XL (ENUM_TWO));
+	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestEnumerated", bytes);
+	g_assert (asn != NULL);
+	egg_bytes_unref (bytes);
+
+	g_assert_cmpint (EGG_ASN1X_ENUMERATED, ==, egg_asn1x_type (asn));
 
 	value = egg_asn1x_get_enumerated (asn);
 	g_assert (value);
@@ -783,13 +927,12 @@ test_enumerated (void)
 	if (!egg_asn1x_set_enumerated (asn, g_quark_from_static_string ("valueThree")))
 		g_assert_not_reached ();
 
-	data = egg_asn1x_encode (asn, NULL, &n_data);
-	g_assert (data);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data != NULL);
 
-	g_assert (n_data == XL (ENUM_THREE));
-	g_assert (memcmp (data, ENUM_THREE, n_data) == 0);
+	egg_assert_cmpbytes (data, ==, ENUM_THREE, XL (ENUM_THREE));
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
@@ -802,6 +945,8 @@ typedef struct {
 static void
 setup (Test *test, gconstpointer unused)
 {
+	EggBytes *bytes;
+
 	if (!g_file_get_contents (SRCDIR "/files/test-certificate-1.der",
 	                          (gchar**)&test->data, &test->n_data, NULL))
 		g_assert_not_reached ();
@@ -809,8 +954,10 @@ setup (Test *test, gconstpointer unused)
 	test->asn1 = egg_asn1x_create (pkix_asn1_tab, "Certificate");
 	g_assert (test->asn1 != NULL);
 
-	if (!egg_asn1x_decode (test->asn1, test->data, test->n_data))
+	bytes = egg_bytes_new_static (test->data, test->n_data);
+	if (!egg_asn1x_decode (test->asn1, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -829,9 +976,8 @@ test_node_name (Test* test, gconstpointer unused)
 static void
 test_asn1_integers (Test* test, gconstpointer unused)
 {
+	EggBytes *data;
 	GNode *asn;
-	guchar *data;
-	gsize n_data;
 	gboolean ret;
 	gulong val;
 
@@ -848,13 +994,13 @@ test_asn1_integers (Test* test, gconstpointer unused)
 	g_assert ("couldn't write integer" && ret);
 
 	/* Now encode the whole caboodle */
-	data = egg_asn1x_encode (asn, NULL, &n_data);
+	data = egg_asn1x_encode (asn, NULL);
 	g_assert ("encoding asn1 didn't work" && data != NULL);
 
 	egg_asn1x_destroy (asn);
 
 	/* Now decode it all nicely */
-	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestIntegers", data, n_data);
+	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestIntegers", data);
 	g_return_if_fail (asn != NULL);
 
 	/* And get out the values */
@@ -870,16 +1016,16 @@ test_asn1_integers (Test* test, gconstpointer unused)
 	g_assert ("couldn't read integer from asn1" && ret);
 	g_assert_cmpuint (val, ==, 209384022);
 
-	g_free (data);
+	egg_asn1x_destroy (asn);
+	egg_bytes_unref (data);
 }
 
 static void
 test_boolean_seq (Test* test, gconstpointer unused)
 {
+	EggBytes *data;
 	GNode *asn = NULL;
 	gboolean value, ret;
-	gpointer data;
-	gsize n_data;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq");
 	g_assert ("asn test structure is null" && asn != NULL);
@@ -893,8 +1039,8 @@ test_boolean_seq (Test* test, gconstpointer unused)
 	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);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data != NULL);
 
 	ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
 	g_assert (ret);
@@ -903,26 +1049,25 @@ test_boolean_seq (Test* test, gconstpointer unused)
 	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);
+	egg_bytes_unref (data);
+	data = egg_asn1x_encode (asn, NULL);
+	g_assert (data != NULL);
 
 	ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
 	g_assert (ret);
 	g_assert (value == FALSE);
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_write_value (Test* test, gconstpointer unused)
 {
+	EggBytes *encoded;
 	GNode *asn = NULL;
 	guchar *data;
 	gsize n_data;
-	guchar *encoded;
-	gsize n_encoded;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestData");
 	g_assert ("asn test structure is null" && asn != NULL);
@@ -930,7 +1075,7 @@ test_write_value (Test* test, gconstpointer unused)
 	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
 		g_assert_not_reached ();
 
-	encoded = egg_asn1x_encode (asn, NULL, &n_encoded);
+	encoded = egg_asn1x_encode (asn, NULL);
 	g_assert (encoded);
 
 	data = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "data", NULL), NULL, &n_data);
@@ -939,18 +1084,17 @@ test_write_value (Test* test, gconstpointer unused)
 	g_assert (memcmp (data, "SOME DATA", 9) == 0);
 	g_free (data);
 
-	g_free (encoded);
+	egg_bytes_unref (encoded);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_element_length_content (Test* test, gconstpointer unused)
 {
+	EggBytes *buffer;
 	GNode *asn = NULL;
-	gchar *buffer;
 	const guchar *content;
 	gsize n_content;
-	gsize n_buffer;
 	gssize length;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestData");
@@ -959,15 +1103,17 @@ test_element_length_content (Test* test, gconstpointer unused)
 	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);
+	buffer = egg_asn1x_encode (asn, NULL);
 	g_assert (buffer != NULL);
 
 	/* Now the real test */
-	length = egg_asn1x_element_length (buffer, n_buffer + 1024);
+	length = egg_asn1x_element_length (egg_bytes_get_data (buffer),
+	                                   egg_bytes_get_size (buffer) + 1024);
 	g_assert_cmpint (length, ==, 13);
 
-	content = egg_asn1x_element_content (buffer, length, &n_content);
-	g_assert (content);
+	content = egg_asn1x_element_content (egg_bytes_get_data (buffer),
+	                                     length, &n_content);
+	g_assert (content != NULL);
 	g_assert_cmpuint (n_content, ==, 11);
 
 	content = egg_asn1x_element_content (content, n_content, &n_content);
@@ -975,26 +1121,24 @@ test_element_length_content (Test* test, gconstpointer unused)
 	g_assert_cmpuint (n_content, ==, 9);
 	g_assert (memcmp (content, "SOME DATA", 9) == 0);
 
-	const char *BAD_ASN_TAG = "\x00";
+	const guchar *BAD_ASN_TAG = (guchar *)"\x00";
 	content = egg_asn1x_element_content (BAD_ASN_TAG, 1, &n_content);
 	g_assert (content == NULL);
 
-	const char *BAD_ASN_LENGTH = "\x30\x80";
+	const guchar *BAD_ASN_LENGTH = (guchar *)"\x30\x80";
 	content = egg_asn1x_element_content (BAD_ASN_LENGTH, 2, &n_content);
 	g_assert (content == NULL);
 
 	egg_asn1x_destroy (asn);
-	g_free (buffer);
+	egg_bytes_unref (buffer);
 }
 
 static void
 test_read_element (Test* test, gconstpointer unused)
 {
+	EggBytes *buffer;
 	GNode *asn = NULL;
-	guchar *buffer;
-	gconstpointer data;
-	gsize n_data;
-	gsize n_buffer;
+	EggBytes *data;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestData");
 	g_assert ("asn test structure is null" && asn != NULL);
@@ -1002,38 +1146,42 @@ test_read_element (Test* test, gconstpointer unused)
 	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);
+	buffer = egg_asn1x_encode (asn, NULL);
 	g_assert (buffer != NULL);
 
 	/* Now the real test */
-	data = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "data", NULL), &n_data);
+	data = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "data", NULL));
 	g_assert (data != NULL);
-	g_assert_cmpint (n_data, ==, 11);
+	g_assert_cmpint (egg_bytes_get_size (data), ==, 11);
+	egg_bytes_unref (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 (memcmp (data, "SOME DATA", 9) == 0);
+	data = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "data", NULL));
+	g_assert (data != NULL);
+	egg_assert_cmpbytes (data, ==, "SOME DATA", 9);
+	egg_bytes_unref (data);
 
 	egg_asn1x_destroy (asn);
-	g_free (buffer);
+	egg_bytes_unref (buffer);
 }
 
 static void
 test_oid (Test* test, gconstpointer unused)
 {
+	EggBytes *buffer;
 	GNode *asn = NULL;
+	GNode *node;
 	GQuark oid, check;
-	guchar *buffer;
-	gsize n_buffer;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestOid");
 	g_assert ("asn test structure is null" && asn != NULL);
 
-	if (!egg_asn1x_set_oid_as_string (egg_asn1x_node (asn, "oid", NULL), "1.2.34567.89"))
+	node = egg_asn1x_node (asn, "oid", NULL);
+	g_assert_cmpint (EGG_ASN1X_OBJECT_ID, ==, egg_asn1x_type (node));
+
+	if (!egg_asn1x_set_oid_as_string (node, "1.2.34567.89"))
 		g_assert_not_reached ();
 
-	buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+	buffer = egg_asn1x_encode (asn, NULL);
 	g_assert (buffer != NULL);
 
 	/* Now a quark has been defined */
@@ -1047,15 +1195,15 @@ test_oid (Test* test, gconstpointer unused)
 	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 ();
 
-	g_free (buffer);
-	buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+	egg_bytes_unref (buffer);
+	buffer = egg_asn1x_encode (asn, NULL);
 	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), ==, "5.4.3.2.1678");
 
-	g_free (buffer);
+	egg_bytes_unref (buffer);
 	egg_asn1x_destroy (asn);
 }
 
@@ -1211,8 +1359,12 @@ main (int argc, char **argv)
 	g_test_add_func ("/asn1/unsigned", test_unsigned);
 	g_test_add_func ("/asn1/octet_string", test_octet_string);
 	g_test_add_func ("/asn1/generalized_time", test_generalized_time);
-	g_test_add_func ("/asn1/implicit", test_implicit);
-	g_test_add_func ("/asn1/explicit", test_explicit);
+	g_test_add_func ("/asn1/implicit/decode", test_implicit_decode);
+	g_test_add_func ("/asn1/implicit/encode", test_implicit_encode);
+	g_test_add_func ("/asn1/explicit/decode", test_explicit_decode);
+	g_test_add_func ("/asn1/explicit/encode", test_explicit_encode);
+	g_test_add_func ("/asn1/universal/decode", test_universal_decode);
+	g_test_add_func ("/asn1/universal/encode", test_universal_encode);
 	g_test_add_func ("/asn1/bit_string_decode", test_bit_string_decode);
 	g_test_add_func ("/asn1/bit_string_decode_bad", test_bit_string_decode_bad);
 	g_test_add_func ("/asn1/bit_string_decode_ulong", test_bit_string_decode_ulong);
diff --git a/egg/tests/test-asn1x.c b/egg/tests/test-asn1x.c
index baeba55..720d62a 100644
--- a/egg/tests/test-asn1x.c
+++ b/egg/tests/test-asn1x.c
@@ -64,32 +64,37 @@ build_personal_name (void)
 #endif
 
 static void
-test_some_asn1_stuff (const ASN1_ARRAY_TYPE *defs, const gchar *file, const gchar *identifier)
+test_some_asn1_stuff (const EggAsn1xDef *defs,
+                      const gchar *file,
+                      const gchar *identifier)
 {
 	GNode *asn;
-	gpointer data, encoded;
-	gsize n_data, n_encoded;
+	EggBytes *encoded;
+	gpointer data;
+	gsize n_data;
+	EggBytes *bytes;
 
 	if (!g_file_get_contents (file, (gchar**)&data, &n_data, NULL))
 		g_assert_not_reached ();
+	bytes = egg_bytes_new_take (data, n_data);
 	asn = egg_asn1x_create (defs, identifier);
 	egg_asn1x_dump (asn);
 
-	if (!egg_asn1x_decode (asn, data, n_data))
+	if (!egg_asn1x_decode (asn, bytes))
 		g_warning ("decode of %s failed: %s", identifier, egg_asn1x_message (asn));
 
-	encoded = egg_asn1x_encode (asn, NULL, &n_encoded);
+	encoded = egg_asn1x_encode (asn, NULL);
 	if (encoded == NULL)
 		g_warning ("encode of %s failed: %s", identifier, egg_asn1x_message (asn));
 
 	/* Decode the encoding */
-	if (!egg_asn1x_decode (asn, encoded, n_encoded))
+	if (!egg_asn1x_decode (asn, encoded))
 		g_warning ("decode of encoded %s failed: %s", identifier, egg_asn1x_message (asn));
 
 	egg_asn1x_clear (asn);
 	egg_asn1x_destroy (asn);
-	g_free (encoded);
-	g_free (data);
+	egg_bytes_unref (bytes);
+	egg_bytes_unref (encoded);
 }
 
 int
diff --git a/egg/tests/test-dh.c b/egg/tests/test-dh.c
index ba9fcfc..a676f93 100644
--- a/egg/tests/test-dh.c
+++ b/egg/tests/test-dh.c
@@ -34,7 +34,7 @@
 #include <glib.h>
 #include <gcrypt.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 test_perform (void)
diff --git a/egg/tests/test-dn.c b/egg/tests/test-dn.c
index 98f5a43..929cec2 100644
--- a/egg/tests/test-dn.c
+++ b/egg/tests/test-dn.c
@@ -27,10 +27,10 @@
 #include "egg/egg-asn1x.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-oid.h"
+#include "egg/egg-testing.h"
 
 #include <glib.h>
 #include <gcrypt.h>
-#include <libtasn1.h>
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -45,6 +45,8 @@ typedef struct {
 static void
 setup (Test *test, gconstpointer unused)
 {
+	EggBytes *bytes;
+
 	if (!g_file_get_contents (SRCDIR "/files/test-certificate-1.der",
 	                          (gchar**)&test->data, &test->n_data, NULL))
 		g_assert_not_reached ();
@@ -52,8 +54,10 @@ setup (Test *test, gconstpointer unused)
 	test->asn1 = egg_asn1x_create (pkix_asn1_tab, "Certificate");
 	g_assert (test->asn1 != NULL);
 
-	if (!egg_asn1x_decode (test->asn1, test->data, test->n_data))
+	bytes = egg_bytes_new_static (test->data, test->n_data);
+	if (!egg_asn1x_decode (test->asn1, bytes))
 		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -80,18 +84,23 @@ test_dn_value (Test* test, gconstpointer unused)
 {
 	const guchar value[] = { 0x13, 0x1a, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x43, 0x41 };
 	gsize n_value = 28;
+	EggBytes *bytes;
 	GQuark oid;
 	gchar *text;
 
 	/* Some printable strings */
 	oid = g_quark_from_static_string ("2.5.4.3");
-	text = egg_dn_print_value (oid, value, n_value);
+	bytes = egg_bytes_new_static (value, n_value);
+	text = egg_dn_print_value (oid, bytes);
+	egg_bytes_unref (bytes);
 	g_assert_cmpstr (text, ==, "Thawte Personal Premium CA");
 	g_free (text);
 
 	/* Unknown oid */
 	oid = g_quark_from_static_string ("1.1.1.1.1.1");
-	text = egg_dn_print_value (oid, value, n_value);
+	bytes = egg_bytes_new_static (value, n_value);
+	text = egg_dn_print_value (oid, bytes);
+	egg_bytes_unref (bytes);
 	g_assert_cmpstr (text, ==, "#131A54686177746520506572736F6E616C205072656D69756D204341");
 	g_free (text);
 }
@@ -99,14 +108,17 @@ test_dn_value (Test* test, gconstpointer unused)
 static int last_index = 0;
 
 static void
-concatenate_dn (guint index, GQuark oid, const guchar *value, gsize n_value, gpointer user_data)
+concatenate_dn (guint index,
+                GQuark oid,
+                EggBytes *value,
+                gpointer user_data)
 {
 	GString *dn = user_data;
 	gchar *text;
 
 	g_assert (oid);
-	g_assert (value);
-	g_assert (n_value);
+	g_assert (value != NULL);
+	g_assert (egg_bytes_get_size (value) != 0);
 
 	g_assert (index == last_index);
 	++last_index;
@@ -118,7 +130,7 @@ concatenate_dn (guint index, GQuark oid, const guchar *value, gsize n_value, gpo
 	g_string_append (dn, egg_oid_get_name (oid));
 	g_string_append_c (dn, '=');
 
-	text = egg_dn_print_value (oid, value, n_value);
+	text = egg_dn_print_value (oid, value);
 	g_string_append (dn, text);
 	g_free (text);
 }
@@ -164,6 +176,43 @@ test_read_dn_part (Test* test, gconstpointer unused)
 	g_assert (value == NULL);
 }
 
+static void
+test_add_dn_part (Test *test,
+                  gconstpointer unused)
+{
+	EggBytes *check;
+	EggBytes *dn;
+	GNode *check_dn;
+	GNode *asn;
+	GNode *node;
+
+	asn = egg_asn1x_create (pkix_asn1_tab, "Name");
+	node = egg_asn1x_node (asn, "rdnSequence", NULL);
+	egg_asn1x_set_choice (asn, node);
+	egg_dn_add_string_part (node, g_quark_from_static_string ("2.5.4.6"), "ZA");
+	egg_dn_add_string_part (node, g_quark_from_static_string ("2.5.4.8"), "Western Cape");
+	egg_dn_add_string_part (node, g_quark_from_static_string ("2.5.4.7"), "Cape Town");
+	egg_dn_add_string_part (node, g_quark_from_static_string ("2.5.4.10"), "Thawte Consulting");
+	egg_dn_add_string_part (node, g_quark_from_static_string ("2.5.4.11"), "Certification Services Division");
+	egg_dn_add_string_part (node, g_quark_from_static_string ("2.5.4.3"), "Thawte Personal Premium CA");
+	egg_dn_add_string_part (node, g_quark_from_static_string ("1.2.840.113549.1.9.1"), "personal-premium thawte com");
+
+	dn = egg_asn1x_encode (asn, NULL);
+	if (dn == NULL) {
+		g_warning ("couldn't encode dn: %s", egg_asn1x_message (asn));
+		g_assert_not_reached ();
+	}
+
+	check_dn = egg_asn1x_node (test->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL);
+	check = egg_asn1x_encode (check_dn, NULL);
+	egg_asn1x_destroy (asn);
+
+	egg_assert_cmpbytes (dn, ==, egg_bytes_get_data (check), egg_bytes_get_size (check));
+
+	egg_bytes_unref (dn);
+	egg_bytes_unref (check);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -173,6 +222,7 @@ main (int argc, char **argv)
 	g_test_add ("/dn/dn_value", Test, NULL, setup, test_dn_value, teardown);
 	g_test_add ("/dn/parse_dn", Test, NULL, setup, test_parse_dn, teardown);
 	g_test_add ("/dn/read_dn_part", Test, NULL, setup, test_read_dn_part, teardown);
+	g_test_add ("/dn/add_dn_part", Test, NULL, setup, test_add_dn_part, teardown);
 
 	return g_test_run ();
 }
diff --git a/egg/tests/test-hkdf.c b/egg/tests/test-hkdf.c
index 93f16df..de1d196 100644
--- a/egg/tests/test-hkdf.c
+++ b/egg/tests/test-hkdf.c
@@ -33,7 +33,7 @@
 
 #include <gcrypt.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 test_hkdf_test_case_1 (void)
diff --git a/egg/tests/test-openssl.c b/egg/tests/test-openssl.c
index da5e457..87596fd 100644
--- a/egg/tests/test-openssl.c
+++ b/egg/tests/test-openssl.c
@@ -36,11 +36,12 @@
 #include <string.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+#include <egg/egg-bytes.h>
+
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 typedef struct {
-	guchar *input;
-	gsize n_input;
+	EggBytes *input;
 	GQuark reftype;
 	guchar *refenc;
 	guchar *refdata;
@@ -52,14 +53,19 @@ typedef struct {
 static void
 setup (Test *test, gconstpointer unused)
 {
-	if (!g_file_get_contents (SRCDIR "/files/pem-rsa-enc.key", (gchar**)&test->input, &test->n_input, NULL))
+	gchar *contents;
+	gsize length;
+
+	if (!g_file_get_contents (SRCDIR "/files/pem-rsa-enc.key", &contents, &length, NULL))
 		g_assert_not_reached ();
+
+	test->input = egg_bytes_new_take (contents, length);
 }
 
 static void
 teardown (Test *test, gconstpointer unused)
 {
-	g_free (test->input);
+	egg_bytes_unref (test->input);
 	g_free (test->refenc);
 	egg_secure_free (test->refdata);
 	g_hash_table_destroy (test->refheaders);
@@ -73,24 +79,21 @@ copy_each_key_value (gpointer key, gpointer value, gpointer user_data)
 
 static void
 parse_reference (GQuark type,
-                 const guchar *data,
-                 gsize n_data,
-                 const gchar *outer,
-                 gsize n_outer,
+                 EggBytes *data,
+                 EggBytes *outer,
                  GHashTable *headers,
                  gpointer user_data)
 {
 	Test *test = user_data;
-	gboolean res;
 	const gchar *dekinfo;
 
 	g_assert (type);
 	test->reftype = type;
 
 	g_assert ("no data in PEM callback" && data != NULL);
-	g_assert ("no data in PEM callback" && n_data > 0);
-	test->refenc = g_memdup (data, n_data);
-	test->n_refenc = n_data;
+	g_assert ("no data in PEM callback" && egg_bytes_get_size (data) > 0);
+	test->refenc = g_memdup (egg_bytes_get_data (data), egg_bytes_get_size (data));
+	test->n_refenc = egg_bytes_get_size (data);
 
 	g_assert ("no headers present in file" && headers != NULL);
 	g_assert (!test->refheaders);
@@ -99,10 +102,9 @@ parse_reference (GQuark type,
 	dekinfo = egg_openssl_get_dekinfo (headers);
 	g_assert ("no dekinfo in headers" && dekinfo != NULL);
 
-	res = egg_openssl_decrypt_block (dekinfo, "booo", 4, data, n_data, &test->refdata, &test->n_refdata);
-	g_assert ("couldn't openssl decrypt block" && res == TRUE);
+	test->refdata = egg_openssl_decrypt_block (dekinfo, "booo", 4, data, &test->n_refdata);
 	g_assert ("no data returned from openssl decrypt" && test->refdata != NULL);
-	g_assert ("invalid amount of data returned from openssl decrypt" && test->n_refdata == n_data);
+	g_assert ("invalid amount of data returned from openssl decrypt" && test->n_refdata == egg_bytes_get_size (data));
 }
 
 static void
@@ -110,7 +112,7 @@ test_parse_reference (Test *test, gconstpointer unused)
 {
 	guint num;
 
-	num = egg_armor_parse (test->input, test->n_input, parse_reference, test);
+	num = egg_armor_parse (test->input, parse_reference, test);
 	g_assert ("couldn't PEM block in reference data" && num == 1);
 
 	g_assert ("parse_reference() wasn't called" && test->refdata != NULL);
@@ -122,22 +124,26 @@ test_write_reference (Test *test, gconstpointer unused)
 	const gchar *dekinfo;
 	guchar *encrypted;
 	gsize n_encrypted;
-	gboolean ret;
+	EggBytes *data;
 	guint num;
 
-	num = egg_armor_parse (test->input, test->n_input, parse_reference, test);
+	num = egg_armor_parse (test->input, parse_reference, test);
 	g_assert ("couldn't PEM block in reference data" && num == 1);
 
 	dekinfo = egg_openssl_get_dekinfo (test->refheaders);
 	g_assert ("no dekinfo in headers" && dekinfo != NULL);
 
-	ret = egg_openssl_encrypt_block (dekinfo, "booo", 4, test->refdata, test->n_refdata, &encrypted, &n_encrypted);
-	g_assert ("couldn't openssl encrypt block" && ret == TRUE);
+	data = egg_bytes_new_static (test->refdata, test->n_refdata);
+	encrypted = egg_openssl_encrypt_block (dekinfo, "booo", 4, data, &n_encrypted);
+	egg_bytes_unref (data);
+
 	g_assert ("no data returned from openssl encrypt" && encrypted != NULL);
 	g_assert ("invalid amount of data returned from openssl encrypt" && test->n_refdata <= n_encrypted);
 
 	g_assert ("data length doesn't match input length" && n_encrypted == test->n_refenc);
 	g_assert ("data doesn't match input" && memcmp (encrypted, test->refenc, n_encrypted) == 0);
+
+	g_free (encrypted);
 }
 
 static void
@@ -147,7 +153,7 @@ test_write_exactly_same (Test *test, gconstpointer unused)
 	gsize n_result;
 	guint num;
 
-	num = egg_armor_parse (test->input, test->n_input, parse_reference, test);
+	num = egg_armor_parse (test->input, parse_reference, test);
 	g_assert ("couldn't PEM block in reference data" && num == 1);
 
 	result = egg_armor_write (test->refenc, test->n_refenc, test->reftype,
@@ -159,7 +165,7 @@ test_write_exactly_same (Test *test, gconstpointer unused)
 	 * and line endings.
 	 */
 
-	egg_assert_cmpmem (test->input, test->n_input, ==, result, n_result);
+	egg_assert_cmpbytes (test->input, ==, result, n_result);
 	g_free (result);
 }
 
@@ -171,25 +177,28 @@ static void
 test_openssl_roundtrip (Test *test, gconstpointer unused)
 {
 	const gchar *dekinfo;
-	gboolean res;
-	gboolean ret;
 	guchar *encrypted, *decrypted;
 	gsize n_encrypted, n_decrypted;
+	EggBytes *data;
 	int i;
 	guint num;
 
-	num = egg_armor_parse (test->input, test->n_input, parse_reference, test);
+	num = egg_armor_parse (test->input, parse_reference, test);
 	g_assert ("couldn't PEM block in reference data" && num == 1);
 
 	dekinfo = egg_openssl_prep_dekinfo (test->refheaders);
 
-	ret = egg_openssl_encrypt_block (dekinfo, "password", -1, TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted);
-	g_assert ("couldn't openssl encrypt block" && ret == TRUE);
+	data = egg_bytes_new_static (TEST_DATA, TEST_DATA_L);
+	encrypted = egg_openssl_encrypt_block (dekinfo, "password", -1, data, &n_encrypted);
+	egg_bytes_unref (data);
+
 	g_assert ("no data returned from openssl encrypt" && encrypted != NULL);
 	g_assert ("invalid amount of data returned from openssl encrypt" && TEST_DATA_L <= n_encrypted);
 
-	res = egg_openssl_decrypt_block (dekinfo, "password", 8, encrypted, n_encrypted, &decrypted, &n_decrypted);
-	g_assert ("couldn't openssl decrypt block" && res == TRUE);
+	data = egg_bytes_new_with_free_func (encrypted, n_encrypted, egg_secure_free, encrypted);
+	decrypted = egg_openssl_decrypt_block (dekinfo, "password", 8, data, &n_decrypted);
+	egg_bytes_unref (data);
+
 	g_assert ("no data returned from openssl decrypt" && decrypted != NULL);
 
 	/* Check that the data was decrypted properly */
@@ -199,6 +208,8 @@ test_openssl_roundtrip (Test *test, gconstpointer unused)
 	/* Check that the remainder is all zeros */
 	for (i = TEST_DATA_L; i < n_decrypted; ++i)
 		g_assert ("non null byte in padding" && decrypted[i] == 0);
+
+	egg_secure_free (decrypted);
 }
 
 int
diff --git a/egg/tests/test-secmem.c b/egg/tests/test-secmem.c
index 20beec9..6ac5e96 100644
--- a/egg/tests/test-secmem.c
+++ b/egg/tests/test-secmem.c
@@ -32,7 +32,7 @@
 #include <string.h>
 
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 /* Declared in egg-secure-memory.c */
 extern int egg_secure_warnings;
diff --git a/egg/tests/test-symkey.c b/egg/tests/test-symkey.c
index b65ee30..b4c1e2d 100644
--- a/egg/tests/test-symkey.c
+++ b/egg/tests/test-symkey.c
@@ -33,7 +33,7 @@
 #include <stdio.h>
 #include <string.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static const struct {
 	const gchar *password;
@@ -138,6 +138,8 @@ test_generate_key_simple (void)
 		               gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0);
 
 		g_assert (ret && "invalid simple key generated");
+
+		egg_secure_free (key);
 	}
 }
 
@@ -165,6 +167,8 @@ test_generate_key_pkcs12 (void)
 			        gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0);
 
 		g_assert ("invalid pkcs12 key generated" && ret);
+
+		egg_secure_free (key);
 	}
 }
 
@@ -192,6 +196,8 @@ test_generate_key_pbkdf2 (void)
 			        gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0);
 
 		g_assert ("invalid pbkdf2 key generated" && ret);
+
+		egg_secure_free (key);
 	}
 }
 
@@ -220,6 +226,7 @@ test_generate_key_pbe (void)
 
 		g_assert ("invalid pbe key generated" && ret);
 
+		egg_secure_free (key);
 	}
 }
 
diff --git a/egg/tests/test.asn b/egg/tests/test.asn
index 28cb176..5412a63 100644
--- a/egg/tests/test.asn
+++ b/egg/tests/test.asn
@@ -18,6 +18,8 @@ TestImplicit ::= [5] IMPLICIT OCTET STRING
 
 TestExplicit ::= [5] EXPLICIT OCTET STRING
 
+TestUniversal ::= [UNIVERSAL 5] IMPLICIT OCTET STRING
+
 TestBitString ::= BIT STRING
 
 TestIntegers ::= SEQUENCE {
diff --git a/pam/gkr-pam-stubs.c b/pam/gkr-pam-stubs.c
index 13c4436..cccec13 100644
--- a/pam/gkr-pam-stubs.c
+++ b/pam/gkr-pam-stubs.c
@@ -30,21 +30,23 @@
  * locking for memory between threads
  */ 
 
-void
+static void
 egg_memory_lock (void)
 {
 	/* No threads in PAM, no locking */
 }
 
-void 
+static void
 egg_memory_unlock (void)
 {
 	/* No threads in PAM, no locking */
 }
 
-void*
+static void *
 egg_memory_fallback (void *p, size_t sz)
 {
 	/* Handles allocation, reallocation and freeing */
 	return realloc (p, sz);
 }
+
+EGG_SECURE_DEFINE_GLOBALS (egg_memory_lock, egg_memory_unlock, egg_memory_fallback);
diff --git a/pkcs11/gkm/Makefile.am b/pkcs11/gkm/Makefile.am
index 54f867c..f0e902c 100644
--- a/pkcs11/gkm/Makefile.am
+++ b/pkcs11/gkm/Makefile.am
@@ -1,4 +1,3 @@
-
 INCLUDES = \
 	-I$(top_builddir) \
 	-I$(top_srcdir) \
@@ -13,8 +12,7 @@ noinst_LTLIBRARIES = \
 	libgkm.la
 
 BUILT_SOURCES = \
-	gkm-marshal.c gkm-marshal.h \
-	asn1-def-pk.h asn1-def-pkix.h
+	gkm-marshal.c gkm-marshal.h
 
 libgkm_la_SOURCES = \
 	gkm-aes-key.c gkm-aes-key.h \
@@ -83,16 +81,8 @@ gkm-marshal.c: gkm-marshal.list $(GLIB_GENMARSHAL)
 	echo "#include \"gkm-marshal.h\"" > $@ && \
 	$(GLIB_GENMARSHAL) $< --body --prefix=gkm_marshal >> $@
 
-asn1-def-pk.h: pk.asn
-	$(ASN1PARSER) -o asn1-def-pk.h $<
-
-asn1-def-pkix.h: pkix.asn
-	$(ASN1PARSER) -o asn1-def-pkix.h $<
-
 EXTRA_DIST = \
-	gkm-marshal.list \
-	pkix.asn \
-	pk.asn
+	gkm-marshal.list
 
 # -------------------------------------------------------------------------------
 
diff --git a/pkcs11/gkm/gkm-attributes.c b/pkcs11/gkm/gkm-attributes.c
index 52f5894..71f6af9 100644
--- a/pkcs11/gkm/gkm-attributes.c
+++ b/pkcs11/gkm/gkm-attributes.c
@@ -247,6 +247,13 @@ gkm_attribute_set_data (CK_ATTRIBUTE_PTR attr, gconstpointer value, gsize n_valu
 }
 
 CK_RV
+gkm_attribute_set_bytes (CK_ATTRIBUTE_PTR attr,
+                         EggBytes *value)
+{
+	return gkm_attribute_set_data (attr, egg_bytes_get_data (value), egg_bytes_get_size (value));
+}
+
+CK_RV
 gkm_attribute_set_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t mpi)
 {
 	gsize len;
diff --git a/pkcs11/gkm/gkm-attributes.h b/pkcs11/gkm/gkm-attributes.h
index 7f09fac..3c300af 100644
--- a/pkcs11/gkm/gkm-attributes.h
+++ b/pkcs11/gkm/gkm-attributes.h
@@ -28,6 +28,8 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "egg/egg-bytes.h"
+
 CK_RV                 gkm_attribute_get_bool                           (CK_ATTRIBUTE_PTR attr,
                                                                         gboolean *value);
 
@@ -67,6 +69,9 @@ CK_RV                 gkm_attribute_set_data                           (CK_ATTRI
                                                                         gconstpointer value,
                                                                         gsize n_value);
 
+CK_RV                 gkm_attribute_set_bytes                          (CK_ATTRIBUTE_PTR attr,
+                                                                        EggBytes *value);
+
 CK_RV                 gkm_attribute_set_mpi                            (CK_ATTRIBUTE_PTR attr,
                                                                         gcry_mpi_t mpi);
 
diff --git a/pkcs11/gkm/gkm-certificate.c b/pkcs11/gkm/gkm-certificate.c
index 1e3e2f2..ca5a2e0 100644
--- a/pkcs11/gkm/gkm-certificate.c
+++ b/pkcs11/gkm/gkm-certificate.c
@@ -53,8 +53,7 @@ enum {
 struct _GkmCertificatePrivate {
 	GkmCertificateKey *key;
 	GNode *asn1;
-	guchar *data;
-	gsize n_data;
+	EggBytes *der;
 	gchar *label;
 };
 
@@ -122,6 +121,8 @@ factory_create_certificate (GkmSession *session, GkmTransaction *transaction,
 {
 	CK_ATTRIBUTE_PTR attr;
 	GkmCertificate *cert;
+	EggBytes *bytes;
+	gboolean ret;
 
 	g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
 	g_return_val_if_fail (attrs || !n_attrs, NULL);
@@ -139,7 +140,11 @@ factory_create_certificate (GkmSession *session, GkmTransaction *transaction,
 	                     NULL);
 
 	/* Load the certificate from the data specified */
-	if (!gkm_serializable_load (GKM_SERIALIZABLE (cert), NULL, attr->pValue, attr->ulValueLen)) {
+	bytes = egg_bytes_new (attr->pValue, attr->ulValueLen);
+	ret = gkm_serializable_load (GKM_SERIALIZABLE (cert), NULL, bytes);
+	egg_bytes_unref (bytes);
+
+	if(!ret) {
 		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
 		g_object_unref (cert);
 		return NULL;
@@ -162,7 +167,7 @@ gkm_certificate_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATT
 {
 	GkmCertificate *self = GKM_CERTIFICATE (base);
 	CK_ULONG category;
-	const guchar *cdata;
+	EggBytes *cdata;
 	guchar *data;
 	gsize n_data;
 	time_t when;
@@ -191,11 +196,13 @@ gkm_certificate_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATT
 		return gkm_attribute_set_ulong (attr, category);
 
 	case CKA_CHECK_VALUE:
-		g_return_val_if_fail (self->pv->data, CKR_GENERAL_ERROR);
+		g_return_val_if_fail (self->pv->der != NULL, CKR_GENERAL_ERROR);
 		n_data = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
 		g_return_val_if_fail (n_data && n_data > 3, CKR_GENERAL_ERROR);
 		data = g_new0 (guchar, n_data);
-		gcry_md_hash_buffer (GCRY_MD_SHA1, data, self->pv->data, self->pv->n_data);
+		gcry_md_hash_buffer (GCRY_MD_SHA1, data,
+		                     egg_bytes_get_data (self->pv->der),
+		                     egg_bytes_get_size (self->pv->der));
 		rv = gkm_attribute_set_data (attr, data, 3);
 		g_free (data);
 		return rv;
@@ -213,9 +220,11 @@ gkm_certificate_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATT
 
 	case CKA_SUBJECT:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
-		cdata = egg_asn1x_get_raw_element (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "subject", NULL), &n_data);
+		cdata = egg_asn1x_get_element_raw (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "subject", NULL));
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
-		return gkm_attribute_set_data (attr, cdata, n_data);
+		rv = gkm_attribute_set_bytes (attr, cdata);
+		egg_bytes_unref (cdata);
+		return rv;
 
 	case CKA_ID:
 		if (!self->pv->key)
@@ -224,19 +233,23 @@ 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_asn1x_get_raw_element (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "issuer", NULL), &n_data);
+		cdata = egg_asn1x_get_element_raw (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "issuer", NULL));
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
-		return gkm_attribute_set_data (attr, cdata, n_data);
+		rv = gkm_attribute_set_bytes (attr, cdata);
+		egg_bytes_unref (cdata);
+		return rv;
 
 	case CKA_SERIAL_NUMBER:
 		g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
-		cdata = egg_asn1x_get_raw_element (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "serialNumber", NULL), &n_data);
+		cdata = egg_asn1x_get_element_raw (egg_asn1x_node (self->pv->asn1, "tbsCertificate", "serialNumber", NULL));
 		g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
-		return gkm_attribute_set_data (attr, cdata, n_data);
+		rv = gkm_attribute_set_bytes (attr, cdata);
+		egg_bytes_unref (cdata);
+		return rv;
 
 	case CKA_VALUE:
-		g_return_val_if_fail (self->pv->data, CKR_GENERAL_ERROR);
-		return gkm_attribute_set_data (attr, self->pv->data, self->pv->n_data);
+		g_return_val_if_fail (self->pv->der != NULL, CKR_GENERAL_ERROR);
+		return gkm_attribute_set_bytes (attr, self->pv->der);
 
 	/* These are only used for strange online certificates which we don't support */
 	case CKA_URL:
@@ -287,7 +300,8 @@ gkm_certificate_finalize (GObject *obj)
 	GkmCertificate *self = GKM_CERTIFICATE (obj);
 
 	g_assert (!self->pv->key);
-	g_free (self->pv->data);
+	if (self->pv->der)
+		egg_bytes_unref (self->pv->der);
 	g_free (self->pv->label);
 	egg_asn1x_destroy (self->pv->asn1);
 
@@ -358,40 +372,36 @@ gkm_certificate_class_init (GkmCertificateClass *klass)
 }
 
 static gboolean
-gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, gconstpointer data, gsize n_data)
+gkm_certificate_real_load (GkmSerializable *base,
+                           GkmSecret *login,
+                           EggBytes *data)
 {
 	GkmCertificate *self = GKM_CERTIFICATE (base);
 	GNode *asn1 = NULL;
 	GkmDataResult res;
-	guchar *copy, *keydata;
-	gsize n_keydata;
+	EggBytes *keydata;
 	gcry_sexp_t sexp;
 	GkmSexp *wrapper;
 
-	g_return_val_if_fail (GKM_IS_CERTIFICATE (self), FALSE);
-
-	if (!data || !n_data) {
+	if (egg_bytes_get_size (data) == 0) {
 		g_message ("cannot load empty certificate file");
 		return FALSE;
 	}
 
-	copy = g_memdup (data, n_data);
-
 	/* Parse the ASN1 data */
-	res = gkm_data_der_read_certificate (copy, n_data, &asn1);
+	res = gkm_data_der_read_certificate (data, &asn1);
 	if (res != GKM_DATA_SUCCESS) {
 		g_message ("couldn't parse certificate data");
-		g_free (copy);
 		return FALSE;
 	}
 
 	/* Generate a raw public key from our certificate */
-	keydata = egg_asn1x_encode (egg_asn1x_node (asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), NULL, &n_keydata);
+	keydata = egg_asn1x_encode (egg_asn1x_node (asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), NULL);
 	g_return_val_if_fail (keydata, FALSE);
 
 	/* Now create us a nice public key with that identifier */
-	res = gkm_data_der_read_public_key_info (keydata, n_keydata, &sexp);
-	g_free (keydata);
+	res = gkm_data_der_read_public_key_info (keydata, &sexp);
+	egg_bytes_unref (keydata);
 
 	switch (res) {
 
@@ -417,7 +427,6 @@ gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, gconstpointe
 	case GKM_DATA_FAILURE:
 	case GKM_DATA_LOCKED:
 		g_warning ("couldn't parse certificate key data");
-		g_free (copy);
 		egg_asn1x_destroy (asn1);
 		return FALSE;
 
@@ -426,9 +435,10 @@ gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, gconstpointe
 		break;
 	}
 
-	g_free (self->pv->data);
-	self->pv->data = copy;
-	self->pv->n_data = n_data;
+	egg_bytes_ref (data);
+	if (self->pv->der)
+		egg_bytes_unref (self->pv->der);
+	self->pv->der = data;
 
 	egg_asn1x_destroy (self->pv->asn1);
 	self->pv->asn1 = asn1;
@@ -436,18 +446,15 @@ gkm_certificate_real_load (GkmSerializable *base, GkmSecret *login, gconstpointe
 	return TRUE;
 }
 
-static gboolean
-gkm_certificate_real_save (GkmSerializable *base, GkmSecret *login, gpointer *data, gsize *n_data)
+static EggBytes *
+gkm_certificate_real_save (GkmSerializable *base,
+                           GkmSecret *login)
 {
 	GkmCertificate *self = GKM_CERTIFICATE (base);
 
 	g_return_val_if_fail (GKM_IS_CERTIFICATE (self), FALSE);
-	g_return_val_if_fail (data, FALSE);
-	g_return_val_if_fail (n_data, FALSE);
 
-	*n_data = self->pv->n_data;
-	*data = g_memdup (self->pv->data, self->pv->n_data);
-	return TRUE;
+	return egg_bytes_ref (self->pv->der);
 }
 
 static void
@@ -465,9 +472,8 @@ gkm_certificate_serializable (GkmSerializableIface *iface)
 gboolean
 gkm_certificate_calc_category (GkmCertificate *self, GkmSession *session, CK_ULONG* category)
 {
-	const guchar *extension;
+	EggBytes *extension;
 	GkmManager *manager;
-	gsize n_extension;
 	GkmDataResult res;
 	gboolean is_ca;
 	GkmObject *object;
@@ -486,9 +492,9 @@ gkm_certificate_calc_category (GkmCertificate *self, GkmSession *session, CK_ULO
 	}
 
 	/* Read in the Basic Constraints section */
-	extension = gkm_certificate_get_extension (self, OID_BASIC_CONSTRAINTS, &n_extension, NULL);
+	extension = gkm_certificate_get_extension (self, OID_BASIC_CONSTRAINTS, NULL);
 	if (extension != NULL) {
-		res = gkm_data_der_read_basic_constraints (extension, n_extension, &is_ca, NULL);
+		res = gkm_data_der_read_basic_constraints (extension, &is_ca, NULL);
 
 		if (res != GKM_DATA_SUCCESS)
 			return FALSE;
@@ -512,9 +518,9 @@ gkm_certificate_get_public_key (GkmCertificate *self)
 	return self->pv->key;
 }
 
-const guchar*
+EggBytes *
 gkm_certificate_get_extension (GkmCertificate *self, GQuark oid,
-                               gsize *n_extension, gboolean *critical)
+                               gboolean *critical)
 {
 	guchar *val;
 	gsize n_val;
@@ -523,7 +529,6 @@ gkm_certificate_get_extension (GkmCertificate *self, GQuark oid,
 	g_return_val_if_fail (GKM_IS_CERTIFICATE (self), NULL);
 	g_return_val_if_fail (self->pv->asn1, NULL);
 	g_return_val_if_fail (oid, NULL);
-	g_return_val_if_fail (n_extension, NULL);
 
 	index = find_certificate_extension (self, oid);
 	if (index <= 0)
@@ -548,7 +553,7 @@ gkm_certificate_get_extension (GkmCertificate *self, GQuark oid,
 
 	/* And the extension value */
 	return egg_asn1x_get_raw_value (egg_asn1x_node (self->pv->asn1, "tbsCertificate",
-	                                "extensions", index, "extnValue", NULL), n_extension);
+	                                "extensions", index, "extnValue", NULL));
 }
 
 const gchar*
@@ -593,14 +598,15 @@ gkm_certificate_hash (GkmCertificate *self, int hash_algo, gsize *n_hash)
 	guchar *hash;
 
 	g_return_val_if_fail (GKM_IS_CERTIFICATE (self), NULL);
-	g_return_val_if_fail (self->pv->data, NULL);
+	g_return_val_if_fail (self->pv->der != NULL, NULL);
 	g_return_val_if_fail (n_hash, NULL);
 
 	*n_hash = gcry_md_get_algo_dlen (hash_algo);
 	g_return_val_if_fail (*n_hash > 0, NULL);
 
 	hash = g_malloc0 (*n_hash);
-	gcry_md_hash_buffer (hash_algo, hash, self->pv->data, self->pv->n_data);
+	gcry_md_hash_buffer (hash_algo, hash, egg_bytes_get_data (self->pv->der),
+	                     egg_bytes_get_size (self->pv->der));
 
 	return hash;
 }
@@ -609,11 +615,11 @@ gconstpointer
 gkm_certificate_der_data (GkmCertificate *self, gsize *n_data)
 {
 	g_return_val_if_fail (GKM_IS_CERTIFICATE (self), NULL);
-	g_return_val_if_fail (self->pv->data, NULL);
+	g_return_val_if_fail (self->pv->der != NULL, NULL);
 	g_return_val_if_fail (n_data, NULL);
 
-	*n_data = self->pv->n_data;
-	return self->pv->data;
+	*n_data = egg_bytes_get_size (self->pv->der);
+	return egg_bytes_get_data (self->pv->der);
 }
 
 GkmFactory*
diff --git a/pkcs11/gkm/gkm-certificate.h b/pkcs11/gkm/gkm-certificate.h
index ac630b3..506a17f 100644
--- a/pkcs11/gkm/gkm-certificate.h
+++ b/pkcs11/gkm/gkm-certificate.h
@@ -27,6 +27,8 @@
 #include "gkm-object.h"
 #include "gkm-types.h"
 
+#include "egg/egg-bytes.h"
+
 #define GKM_FACTORY_CERTIFICATE            (gkm_certificate_get_factory ())
 
 #define GKM_TYPE_CERTIFICATE               (gkm_certificate_get_type ())
@@ -58,9 +60,8 @@ gboolean                   gkm_certificate_calc_category          (GkmCertificat
 
 GkmCertificateKey*         gkm_certificate_get_public_key         (GkmCertificate *self);
 
-const guchar*              gkm_certificate_get_extension          (GkmCertificate *self,
+EggBytes *                 gkm_certificate_get_extension          (GkmCertificate *self,
                                                                    GQuark oid,
-                                                                   gsize *n_extension,
                                                                    gboolean *critical);
 
 const gchar*               gkm_certificate_get_label              (GkmCertificate *self);
diff --git a/pkcs11/gkm/gkm-data-asn1.c b/pkcs11/gkm/gkm-data-asn1.c
index 6641395..5765862 100644
--- a/pkcs11/gkm/gkm-data-asn1.c
+++ b/pkcs11/gkm/gkm-data-asn1.c
@@ -31,18 +31,19 @@ gboolean
 gkm_data_asn1_read_mpi (GNode *asn, gcry_mpi_t *mpi)
 {
 	gcry_error_t gcry;
+	EggBytes *buf;
 	gsize sz;
-	const guchar *buf;
 
 	g_return_val_if_fail (asn, FALSE);
 	g_return_val_if_fail (mpi, FALSE);
 
-	buf = egg_asn1x_get_raw_value (asn, &sz);
+	buf = egg_asn1x_get_raw_value (asn);
 	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);
+	sz = egg_bytes_get_size (buf);
+	gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_STD, egg_bytes_get_data (buf), sz, &sz);
 	if (gcry != 0)
 		return FALSE;
 
@@ -53,6 +54,7 @@ gboolean
 gkm_data_asn1_write_mpi (GNode *asn, gcry_mpi_t mpi)
 {
 	gcry_error_t gcry;
+	EggBytes *bytes;
 	gsize len;
 	guchar *buf;
 
@@ -69,5 +71,9 @@ gkm_data_asn1_write_mpi (GNode *asn, gcry_mpi_t mpi)
 	gcry = gcry_mpi_print (GCRYMPI_FMT_STD, buf, len, &len, mpi);
 	g_return_val_if_fail (gcry == 0, FALSE);
 
-	return egg_asn1x_set_integer_as_raw (asn, buf, len, gcry_free);
+	bytes = egg_bytes_new_with_free_func (buf, len, gcry_free, buf);
+	egg_asn1x_set_integer_as_raw (asn, bytes);
+	egg_bytes_unref (bytes);
+
+	return TRUE;
 }
diff --git a/pkcs11/gkm/gkm-data-der.c b/pkcs11/gkm/gkm-data-der.c
index d9a5001..0dfc76d 100644
--- a/pkcs11/gkm/gkm-data-der.c
+++ b/pkcs11/gkm/gkm-data-der.c
@@ -77,7 +77,8 @@ init_quarks (void)
 	"    (e %m)))"
 
 GkmDataResult
-gkm_data_der_read_public_key_rsa (gconstpointer data, gsize n_data, gcry_sexp_t *s_key)
+gkm_data_der_read_public_key_rsa (EggBytes *data,
+                                  gcry_sexp_t *s_key)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	GNode *asn = NULL;
@@ -86,7 +87,7 @@ gkm_data_der_read_public_key_rsa (gconstpointer data, gsize n_data, gcry_sexp_t
 
 	n = e = NULL;
 
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
 	if (!asn)
 		goto done;
 
@@ -125,7 +126,8 @@ done:
 	"    (u %m)))"
 
 GkmDataResult
-gkm_data_der_read_private_key_rsa (gconstpointer data, gsize n_data, gcry_sexp_t *s_key)
+gkm_data_der_read_private_key_rsa (EggBytes *data,
+                                   gcry_sexp_t *s_key)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	gcry_mpi_t n, e, d, p, q, u;
@@ -136,7 +138,7 @@ gkm_data_der_read_private_key_rsa (gconstpointer data, gsize n_data, gcry_sexp_t
 
 	n = e = d = p = q = u = NULL;
 
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data);
 	if (!asn)
 		goto done;
 
@@ -202,7 +204,8 @@ done:
 	"    (y %m)))"
 
 GkmDataResult
-gkm_data_der_read_public_key_dsa (gconstpointer data, gsize n_data, gcry_sexp_t *s_key)
+gkm_data_der_read_public_key_dsa (EggBytes *data,
+                                  gcry_sexp_t *s_key)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	GNode *asn = NULL;
@@ -211,7 +214,7 @@ gkm_data_der_read_public_key_dsa (gconstpointer data, gsize n_data, gcry_sexp_t
 
 	p = q = g = y = NULL;
 
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicKey", data);
 	if (!asn)
 		goto done;
 
@@ -244,8 +247,8 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_public_key_dsa_parts (gconstpointer keydata, gsize n_keydata,
-                                        gconstpointer params, gsize n_params,
+gkm_data_der_read_public_key_dsa_parts (EggBytes *keydata,
+                                        EggBytes *params,
                                         gcry_sexp_t *s_key)
 {
 	gcry_mpi_t p, q, g, y;
@@ -256,8 +259,8 @@ gkm_data_der_read_public_key_dsa_parts (gconstpointer keydata, gsize n_keydata,
 
 	p = q = g = y = NULL;
 
-	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);
+	asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
+	asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicPart", keydata);
 	if (!asn_params || !asn_key)
 		goto done;
 
@@ -302,7 +305,8 @@ done:
 	"    (x %m)))"
 
 GkmDataResult
-gkm_data_der_read_private_key_dsa (gconstpointer data, gsize n_data, gcry_sexp_t *s_key)
+gkm_data_der_read_private_key_dsa (EggBytes *data,
+                                   gcry_sexp_t *s_key)
 {
 	gcry_mpi_t p, q, g, y, x;
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
@@ -311,7 +315,7 @@ gkm_data_der_read_private_key_dsa (gconstpointer data, gsize n_data, gcry_sexp_t
 
 	p = q = g = y = x = NULL;
 
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data, n_data);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data);
 	if (!asn)
 		goto done;
 
@@ -346,8 +350,8 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_private_key_dsa_parts (gconstpointer keydata, gsize n_keydata,
-                                         gconstpointer params, gsize n_params,
+gkm_data_der_read_private_key_dsa_parts (EggBytes *keydata,
+                                         EggBytes *params,
                                          gcry_sexp_t *s_key)
 {
 	gcry_mpi_t p, q, g, y, x;
@@ -358,8 +362,8 @@ gkm_data_der_read_private_key_dsa_parts (gconstpointer keydata, gsize n_keydata,
 
 	p = q = g = y = x = NULL;
 
-	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);
+	asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
+	asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata);
 	if (!asn_params || !asn_key)
 		goto done;
 
@@ -400,31 +404,31 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_public_key (gconstpointer data, gsize n_data, gcry_sexp_t *s_key)
+gkm_data_der_read_public_key (EggBytes *data, gcry_sexp_t *s_key)
 {
 	GkmDataResult res;
 
-	res = gkm_data_der_read_public_key_rsa (data, n_data, s_key);
+	res = gkm_data_der_read_public_key_rsa (data, s_key);
 	if (res == GKM_DATA_UNRECOGNIZED)
-		res = gkm_data_der_read_public_key_dsa (data, n_data, s_key);
+		res = gkm_data_der_read_public_key_dsa (data, s_key);
 
 	return res;
 }
 
 GkmDataResult
-gkm_data_der_read_public_key_info (gconstpointer data, gsize n_data, gcry_sexp_t* s_key)
+gkm_data_der_read_public_key_info (EggBytes *data,
+                                   gcry_sexp_t* s_key)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	GQuark oid;
 	GNode *asn = NULL;
-	gsize n_params;
+	EggBytes *params;
+	EggBytes *key = NULL;
 	guint n_bits;
-	const guchar *params;
-	guchar *key = NULL;
 
 	init_quarks ();
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data);
 	if (!asn)
 		goto done;
 
@@ -436,20 +440,25 @@ gkm_data_der_read_public_key_info (gconstpointer data, gsize n_data, gcry_sexp_t
 		goto done;
 
 	/* A bit string so we cannot process in place */
-	key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), NULL, &n_bits);
+	key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), &n_bits);
 	if (!key)
 		goto done;
+	if (n_bits % 8 != 0) {
+		g_message ("invalid bit length for public key: %u", n_bits);
+		goto done;
+	}
 
 	/* An RSA key is simple */
 	if (oid == OID_PKIX1_RSA) {
-		ret = gkm_data_der_read_public_key_rsa (key, n_bits / 8, s_key);
+		ret = gkm_data_der_read_public_key_rsa (key, s_key);
 
 	/* A DSA key paramaters are stored separately */
 	} else if (oid == OID_PKIX1_DSA) {
-		params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "algorithm", "parameters", NULL), &n_params);
+		params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "algorithm", "parameters", NULL));
 		if (!params)
 			goto done;
-		ret = gkm_data_der_read_public_key_dsa_parts (key, n_bits / 8, params, n_params, s_key);
+		ret = gkm_data_der_read_public_key_dsa_parts (key, params, s_key);
+		egg_bytes_unref (params);
 
 	} else {
 		g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid));
@@ -459,7 +468,8 @@ gkm_data_der_read_public_key_info (gconstpointer data, gsize n_data, gcry_sexp_t
 
 done:
 	egg_asn1x_destroy (asn);
-	g_free (key);
+	if (key)
+		egg_bytes_unref (key);
 
 	if (ret == GKM_DATA_FAILURE)
 		g_message ("invalid subject public-key info");
@@ -468,34 +478,34 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_private_key (gconstpointer data, gsize n_data, gcry_sexp_t *s_key)
+gkm_data_der_read_private_key (EggBytes *data,
+                               gcry_sexp_t *s_key)
 {
 	GkmDataResult res;
 
-	res = gkm_data_der_read_private_key_rsa (data, n_data, s_key);
+	res = gkm_data_der_read_private_key_rsa (data, s_key);
 	if (res == GKM_DATA_UNRECOGNIZED)
-		res = gkm_data_der_read_private_key_dsa (data, n_data, s_key);
+		res = gkm_data_der_read_private_key_dsa (data, s_key);
 
 	return res;
 }
 
 GkmDataResult
-gkm_data_der_read_private_pkcs8_plain (gconstpointer data, gsize n_data, gcry_sexp_t *s_key)
+gkm_data_der_read_private_pkcs8_plain (EggBytes *data,
+                                       gcry_sexp_t *s_key)
 {
 	GNode *asn = NULL;
 	GkmDataResult ret;
 	int algorithm;
 	GQuark key_algo;
-	const guchar *keydata;
-	gsize n_keydata;
-	const guchar *params;
-	gsize n_params;
+	EggBytes *keydata = NULL;
+	EggBytes *params = NULL;
 
 	ret = GKM_DATA_UNRECOGNIZED;
 
 	init_quarks ();
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data);
 	if (!asn)
 		goto done;
 
@@ -515,12 +525,11 @@ gkm_data_der_read_private_pkcs8_plain (gconstpointer data, gsize n_data, gcry_se
 		goto done;
 	}
 
-	keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL), &n_keydata);
+	keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL));
 	if (!keydata)
 		goto done;
 
-	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL),
-	                                    &n_params);
+	params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL));
 
 	ret = GKM_DATA_SUCCESS;
 
@@ -528,16 +537,15 @@ done:
 	if (ret == GKM_DATA_SUCCESS) {
 		switch (algorithm) {
 		case GCRY_PK_RSA:
-			ret = gkm_data_der_read_private_key_rsa (keydata, n_keydata, s_key);
+			ret = gkm_data_der_read_private_key_rsa (keydata, s_key);
 			break;
 		case GCRY_PK_DSA:
 			/* Try the normal one block format */
-			ret = gkm_data_der_read_private_key_dsa (keydata, n_keydata, s_key);
+			ret = gkm_data_der_read_private_key_dsa (keydata, s_key);
 
 			/* Otherwise try the two part format that everyone seems to like */
-			if (ret == GKM_DATA_UNRECOGNIZED && params && n_params)
-				ret = gkm_data_der_read_private_key_dsa_parts (keydata, n_keydata,
-				                                               params, n_params, s_key);
+			if (ret == GKM_DATA_UNRECOGNIZED && params)
+				ret = gkm_data_der_read_private_key_dsa_parts (keydata, params, s_key);
 			break;
 		default:
 			g_message ("invalid or unsupported key type in PKCS#8 key");
@@ -549,13 +557,19 @@ done:
 		g_message ("invalid PKCS#8 key");
 	}
 
+	if (params)
+		egg_bytes_unref (params);
+	if (keydata)
+		egg_bytes_unref (keydata);
 	egg_asn1x_destroy (asn);
 	return ret;
 }
 
 GkmDataResult
-gkm_data_der_read_private_pkcs8_crypted (gconstpointer data, gsize n_data, const gchar *password,
-                                         gsize n_password, gcry_sexp_t *s_key)
+gkm_data_der_read_private_pkcs8_crypted (EggBytes *data,
+                                         const gchar *password,
+                                         gsize n_password,
+                                         gcry_sexp_t *s_key)
 {
 	GNode *asn = NULL;
 	gcry_cipher_hd_t cih = NULL;
@@ -563,15 +577,16 @@ gkm_data_der_read_private_pkcs8_crypted (gconstpointer data, gsize n_data, const
 	GkmDataResult ret, r;
 	GQuark scheme;
 	guchar *crypted = NULL;
-	const guchar *params;
-	gsize n_crypted, n_params;
+	EggBytes *params;
+	EggBytes *bytes;
+	gsize n_crypted;
 	gint l;
 
 	init_quarks ();
 
 	ret = GKM_DATA_UNRECOGNIZED;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data);
 	if (!asn)
 		goto done;
 
@@ -582,14 +597,16 @@ gkm_data_der_read_private_pkcs8_crypted (gconstpointer data, gsize n_data, const
 	if (!scheme)
 		goto done;
 
-	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params);
+	params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL));
 	if (!params)
 		goto done;
 
 	/*
 	 * Parse the encryption stuff into a cipher.
 	 */
-	r = egg_symkey_read_cipher (scheme, password, n_password, params, n_params, &cih);
+	r = egg_symkey_read_cipher (scheme, password, n_password, params, &cih);
+	egg_bytes_unref (params);
+
 	if (r == GKM_DATA_UNRECOGNIZED) {
 		ret = GKM_DATA_FAILURE;
 		goto done;
@@ -620,11 +637,13 @@ gkm_data_der_read_private_pkcs8_crypted (gconstpointer data, gsize n_data, const
 	}
 	n_crypted = l;
 
-	/* Try to parse the resulting key */
-	ret = gkm_data_der_read_private_pkcs8_plain (crypted, n_crypted, s_key);
-	egg_secure_free (crypted);
+	bytes = egg_bytes_new_with_free_func (crypted, n_crypted, egg_secure_free, crypted);
 	crypted = NULL;
 
+	/* Try to parse the resulting key */
+	ret = gkm_data_der_read_private_pkcs8_plain (bytes, s_key);
+	egg_bytes_unref (bytes);
+
 	/* If unrecognized we assume bad password */
 	if (ret == GKM_DATA_UNRECOGNIZED)
 		ret = GKM_DATA_LOCKED;
@@ -639,24 +658,26 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_private_pkcs8 (gconstpointer data, gsize n_data, const gchar *password,
-                                 gsize n_password, gcry_sexp_t *s_key)
+gkm_data_der_read_private_pkcs8 (EggBytes *data,
+                                 const gchar *password,
+                                 gsize n_password,
+                                 gcry_sexp_t *s_key)
 {
 	GkmDataResult res;
 
-	res = gkm_data_der_read_private_pkcs8_crypted (data, n_data, password, n_password, s_key);
+	res = gkm_data_der_read_private_pkcs8_crypted (data, password, n_password, s_key);
 	if (res == GKM_DATA_UNRECOGNIZED)
-		res = gkm_data_der_read_private_pkcs8_plain (data, n_data, s_key);
+		res = gkm_data_der_read_private_pkcs8_plain (data, s_key);
 
 	return res;
 }
 
-gpointer
-gkm_data_der_write_public_key_rsa (gcry_sexp_t s_key, gsize *len)
+EggBytes *
+gkm_data_der_write_public_key_rsa (gcry_sexp_t s_key)
 {
 	GNode *asn = NULL;
 	gcry_mpi_t n, e;
-	guchar *result = NULL;
+	EggBytes *result = NULL;
 
 	n = e = NULL;
 
@@ -671,7 +692,7 @@ gkm_data_der_write_public_key_rsa (gcry_sexp_t s_key, gsize *len)
 	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "publicExponent", NULL), e))
 		goto done;
 
-	result = egg_asn1x_encode (asn, NULL, len);
+	result = egg_asn1x_encode (asn, NULL);
 	if (result == NULL)
 		g_warning ("couldn't encode public rsa key: %s", egg_asn1x_message (asn));
 
@@ -683,12 +704,12 @@ done:
 	return result;
 }
 
-gpointer
-gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key, gsize *n_key)
+EggBytes *
+gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key)
 {
 	GNode *asn = NULL;
 	gcry_mpi_t n, e, d, p, q, u, e1, e2, tmp;
-	guchar *result = NULL;
+	EggBytes *result = NULL;
 
 	n = e = d = p = q = u = e1 = e2 = tmp = NULL;
 
@@ -729,7 +750,7 @@ gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key, gsize *n_key)
 	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0))
 		goto done;
 
-	result = egg_asn1x_encode (asn, egg_secure_realloc, n_key);
+	result = egg_asn1x_encode (asn, egg_secure_realloc);
 	if (result == NULL)
 		g_warning ("couldn't encode private rsa key: %s", egg_asn1x_message (asn));
 
@@ -749,12 +770,12 @@ done:
 	return result;
 }
 
-gpointer
-gkm_data_der_write_public_key_dsa (gcry_sexp_t s_key, gsize *len)
+EggBytes *
+gkm_data_der_write_public_key_dsa (gcry_sexp_t s_key)
 {
 	GNode *asn = NULL;
 	gcry_mpi_t p, q, g, y;
-	guchar *result = NULL;
+	EggBytes *result = NULL;
 
 	p = q = g = y = NULL;
 
@@ -776,7 +797,7 @@ gkm_data_der_write_public_key_dsa (gcry_sexp_t s_key, gsize *len)
 	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0))
 		goto done;
 
-	result = egg_asn1x_encode (asn, NULL, len);
+	result = egg_asn1x_encode (asn, NULL);
 	if (result == NULL)
 		g_warning ("couldn't encode public dsa key: %s", egg_asn1x_message (asn));
 
@@ -790,12 +811,12 @@ done:
 	return result;
 }
 
-gpointer
-gkm_data_der_write_private_key_dsa_part (gcry_sexp_t skey, gsize *n_key)
+EggBytes *
+gkm_data_der_write_private_key_dsa_part (gcry_sexp_t skey)
 {
 	GNode *asn = NULL;
 	gcry_mpi_t x;
-	guchar *result = NULL;
+	EggBytes *result = NULL;
 
 	x = NULL;
 
@@ -808,7 +829,7 @@ gkm_data_der_write_private_key_dsa_part (gcry_sexp_t skey, gsize *n_key)
 	if (!gkm_data_asn1_write_mpi (asn, x))
 		goto done;
 
-	result = egg_asn1x_encode (asn, egg_secure_realloc, n_key);
+	result = egg_asn1x_encode (asn, egg_secure_realloc);
 	if (result == NULL)
 		g_warning ("couldn't encode private dsa key: %s", egg_asn1x_message (asn));
 
@@ -819,12 +840,12 @@ done:
 	return result;
 }
 
-gpointer
-gkm_data_der_write_private_key_dsa_params (gcry_sexp_t skey, gsize *n_params)
+EggBytes *
+gkm_data_der_write_private_key_dsa_params (gcry_sexp_t skey)
 {
 	GNode *asn = NULL;
 	gcry_mpi_t p, q, g;
-	guchar *result = NULL;
+	EggBytes *result = NULL;
 
 	p = q = g = NULL;
 
@@ -841,7 +862,7 @@ gkm_data_der_write_private_key_dsa_params (gcry_sexp_t skey, gsize *n_params)
 	    !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "g", NULL), g))
 		goto done;
 
-	result = egg_asn1x_encode (asn, egg_secure_realloc, n_params);
+	result = egg_asn1x_encode (asn, egg_secure_realloc);
 	if (result == NULL)
 		g_warning ("couldn't encode private dsa params: %s", egg_asn1x_message (asn));
 
@@ -854,12 +875,12 @@ done:
 	return result;
 }
 
-gpointer
-gkm_data_der_write_private_key_dsa (gcry_sexp_t s_key, gsize *len)
+EggBytes *
+gkm_data_der_write_private_key_dsa (gcry_sexp_t s_key)
 {
 	GNode *asn = NULL;
 	gcry_mpi_t p, q, g, y, x;
-	guchar *result = NULL;
+	EggBytes *result = NULL;
 
 	p = q = g = y = x = NULL;
 
@@ -883,7 +904,7 @@ gkm_data_der_write_private_key_dsa (gcry_sexp_t s_key, gsize *len)
 	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0))
 		goto done;
 
-	result = egg_asn1x_encode (asn, egg_secure_realloc, len);
+	result = egg_asn1x_encode (asn, egg_secure_realloc);
 	if (result == NULL)
 		g_warning ("couldn't encode private dsa key: %s", egg_asn1x_message (asn));
 
@@ -898,8 +919,8 @@ done:
 	return result;
 }
 
-gpointer
-gkm_data_der_write_public_key (gcry_sexp_t s_key, gsize *len)
+EggBytes *
+gkm_data_der_write_public_key (gcry_sexp_t s_key)
 {
 	gboolean is_priv;
 	int algorithm;
@@ -913,16 +934,16 @@ gkm_data_der_write_public_key (gcry_sexp_t s_key, gsize *len)
 
 	switch (algorithm) {
 	case GCRY_PK_RSA:
-		return gkm_data_der_write_public_key_rsa (s_key, len);
+		return gkm_data_der_write_public_key_rsa (s_key);
 	case GCRY_PK_DSA:
-		return gkm_data_der_write_public_key_dsa (s_key, len);
+		return gkm_data_der_write_public_key_dsa (s_key);
 	default:
 		g_return_val_if_reached (NULL);
 	}
 }
 
-gpointer
-gkm_data_der_write_private_key (gcry_sexp_t s_key, gsize *len)
+EggBytes *
+gkm_data_der_write_private_key (gcry_sexp_t s_key)
 {
 	gboolean is_priv;
 	int algorithm;
@@ -936,9 +957,9 @@ gkm_data_der_write_private_key (gcry_sexp_t s_key, gsize *len)
 
 	switch (algorithm) {
 	case GCRY_PK_RSA:
-		return gkm_data_der_write_private_key_rsa (s_key, len);
+		return gkm_data_der_write_private_key_rsa (s_key);
 	case GCRY_PK_DSA:
-		return gkm_data_der_write_private_key_dsa (s_key, len);
+		return gkm_data_der_write_private_key_dsa (s_key);
 	default:
 		g_return_val_if_reached (NULL);
 	}
@@ -952,8 +973,9 @@ prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password,
 	gcry_cipher_hd_t cih;
 	guchar salt[8];
 	gcry_error_t gcry;
-	guchar *key, *iv, *portion;
-	gsize n_key, n_portion;
+	guchar *key, *iv;
+	EggBytes *portion;
+	gsize n_key;
 	int iterations;
 
 	init_quarks ();
@@ -988,15 +1010,16 @@ prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password,
 		g_return_val_if_reached (NULL);
 	if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn1_params, "iterations", NULL), iterations))
 		g_return_val_if_reached (NULL);
-	portion = egg_asn1x_encode (asn1_params, NULL, &n_portion);
+	portion = egg_asn1x_encode (asn1_params, NULL);
 	if (portion == NULL) {
 		g_warning ("couldn't encode pkcs8 params key: %s", egg_asn1x_message (asn1_params));
 		g_return_val_if_reached (NULL);
 	}
 
-	if (!egg_asn1x_set_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL),
-	                                portion, n_portion, g_free))
+	if (!egg_asn1x_set_element_raw (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL),
+	                                portion))
 		g_return_val_if_reached (NULL);
+	egg_bytes_unref (portion);
 
 	/* Now make a cipher that matches what we wrote out */
 	gcry = gcry_cipher_open (&cih, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
@@ -1013,15 +1036,16 @@ prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password,
 	return cih;
 }
 
-gpointer
-gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey, gsize *n_data)
+EggBytes *
+gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey)
 {
 	GNode *asn = NULL;
 	int algorithm;
 	gboolean is_priv;
 	GQuark oid;
-	guchar *params, *key, *data;
-	gsize n_params, n_key;
+	EggBytes *params;
+	EggBytes *key;
+	EggBytes *data;
 
 	init_quarks ();
 
@@ -1044,15 +1068,14 @@ gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey, gsize *n_data)
 	case GCRY_PK_RSA:
 		oid = OID_PKIX1_RSA;
 		params = NULL;
-		n_params = 0;
-		key = gkm_data_der_write_private_key_rsa (skey, &n_key);
+		key = gkm_data_der_write_private_key_rsa (skey);
 		break;
 
 	/* DSA gets incoded with the params seperate */
 	case GCRY_PK_DSA:
 		oid = OID_PKIX1_DSA;
-		key = gkm_data_der_write_private_key_dsa_part (skey, &n_key);
-		params = gkm_data_der_write_private_key_dsa_params (skey, &n_params);
+		key = gkm_data_der_write_private_key_dsa_part (skey);
+		params = gkm_data_der_write_private_key_dsa_params (skey);
 		break;
 
 	default:
@@ -1066,17 +1089,19 @@ gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey, gsize *n_data)
 
 	/* Write out the parameters */
 	if (params) {
-		if (!egg_asn1x_set_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL),
-		                                params, n_params, egg_secure_free))
+		if (!egg_asn1x_set_element_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL),
+		                                params))
 			g_return_val_if_reached (NULL);
+		egg_bytes_unref (params);
 	}
 
 	/* Write out the key portion */
-	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "privateKey", NULL),
-	                                  key, n_key, egg_secure_free))
+	if (!egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL), key))
 		g_return_val_if_reached (NULL);
 
-	data = egg_asn1x_encode (asn, egg_secure_realloc, n_data);
+	egg_bytes_unref (key);
+
+	data = egg_asn1x_encode (asn, egg_secure_realloc);
 	if (data == NULL)
 		g_warning ("couldn't encode private pkcs8 key: %s", egg_asn1x_message (asn));
 
@@ -1084,18 +1109,21 @@ gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey, gsize *n_data)
 	return data;
 }
 
-gpointer
-gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *password,
-                                          gsize n_password, gsize *n_data)
+EggBytes *
+gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey,
+                                          const gchar *password,
+                                          gsize n_password)
 {
 	gcry_error_t gcry;
 	gcry_cipher_hd_t cih;
 	GNode *asn = NULL;
-	guchar *key, *data;
-	gsize n_key, block = 0;
+	EggBytes *key, *data;
+	guchar *raw;
+	gsize n_raw, n_key;
+	gsize block = 0;
 
 	/* Encode the key in normal pkcs8 fashion */
-	key = gkm_data_der_write_private_pkcs8_plain (skey, &n_key);
+	key = gkm_data_der_write_private_pkcs8_plain (skey);
 	if (key == NULL)
 		return NULL;
 
@@ -1106,30 +1134,39 @@ gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *passwor
 	cih = prepare_and_encode_pkcs8_cipher (asn, password, n_password, &block);
 	g_return_val_if_fail (cih, NULL);
 
+	n_key = egg_bytes_get_size (key);
+
 	/* Pad the block of data */
 	if(block > 1) {
-		gsize pad;
-		guchar *padded;
-
-		pad = block - (n_key % block);
-		if (pad == 0)
-			pad = block;
-		padded = egg_secure_realloc (key, n_key + pad);
-		memset (padded + n_key, pad, pad);
-		key = padded;
-		n_key += pad;
+		gsize n_pad = block - (n_key % block);
+		if (n_pad == 0)
+			n_pad = block;
+		raw = egg_secure_alloc (n_key + n_pad);
+		memcpy (raw, egg_bytes_get_data (key), n_key);
+		memset (raw + n_key, (int)n_pad, n_pad);
+		n_raw = n_key + n_pad;
+
+	/* No padding, probably stream cipher */
+	} else {
+		raw = egg_secure_alloc (n_key);
+		memcpy (raw, egg_bytes_get_data (key), n_key);
+		n_raw = n_key;
 	}
 
-	gcry = gcry_cipher_encrypt (cih, key, n_key, NULL, 0);
+	egg_bytes_unref (key);
+
+	gcry = gcry_cipher_encrypt (cih, raw, n_raw, NULL, 0);
 	g_return_val_if_fail (gcry == 0, NULL);
 
 	gcry_cipher_close (cih);
+	key = egg_bytes_new_with_free_func (raw, n_raw, egg_secure_free, raw);
 
-	if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL),
-	                                  key, n_key, egg_secure_free))
+	if (!egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "encryptedData", NULL), key))
 		g_return_val_if_reached (NULL);
 
-	data = egg_asn1x_encode (asn, NULL, n_data);
+	egg_bytes_unref (key);
+
+	data = egg_asn1x_encode (asn, NULL);
 	if (data == NULL)
 		g_warning ("couldn't encode encrypted pkcs8 key: %s", egg_asn1x_message (asn));
 
@@ -1142,9 +1179,10 @@ gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *passwor
  */
 
 GkmDataResult
-gkm_data_der_read_certificate (gconstpointer data, gsize n_data, GNode **asn1)
+gkm_data_der_read_certificate (EggBytes *data,
+                               GNode **asn1)
 {
-	*asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
+	*asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data);
 	if (!*asn1)
 		return GKM_DATA_UNRECOGNIZED;
 
@@ -1152,15 +1190,16 @@ gkm_data_der_read_certificate (gconstpointer data, gsize n_data, GNode **asn1)
 }
 
 GkmDataResult
-gkm_data_der_read_basic_constraints (gconstpointer data, gsize n_data,
-                                     gboolean *is_ca, gint *path_len)
+gkm_data_der_read_basic_constraints (EggBytes *data,
+                                     gboolean *is_ca,
+                                     gint *path_len)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	GNode *asn = NULL;
 	GNode *node;
 	gulong value;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data);
 	if (!asn)
 		goto done;
 
@@ -1195,13 +1234,14 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_key_usage (gconstpointer data, gsize n_data, gulong *key_usage)
+gkm_data_der_read_key_usage (EggBytes *data,
+                             gulong *key_usage)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	GNode *asn = NULL;
 	guint n_bits;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data);
 	if (!asn)
 		goto done;
 
@@ -1218,7 +1258,8 @@ done:
 }
 
 GkmDataResult
-gkm_data_der_read_enhanced_usage (gconstpointer data, gsize n_data, GQuark **usage_oids)
+gkm_data_der_read_enhanced_usage (EggBytes *data,
+                                  GQuark **usage_oids)
 {
 	GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
 	GNode *asn = NULL;
@@ -1227,7 +1268,7 @@ gkm_data_der_read_enhanced_usage (gconstpointer data, gsize n_data, GQuark **usa
 	GQuark oid;
 	int i;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data);
 	if (!asn)
 		goto done;
 
@@ -1252,15 +1293,14 @@ done:
 }
 
 
-gpointer
-gkm_data_der_write_certificate (GNode *asn1, gsize *n_data)
+EggBytes *
+gkm_data_der_write_certificate (GNode *asn1)
 {
-	gpointer result;
+	EggBytes *result;
 
 	g_return_val_if_fail (asn1, NULL);
-	g_return_val_if_fail (n_data, NULL);
 
-	result = egg_asn1x_encode (asn1, NULL, n_data);
+	result = egg_asn1x_encode (asn1, NULL);
 	if (result == NULL)
 		g_warning ("couldn't encode certificate: %s", egg_asn1x_message (asn1));
 
diff --git a/pkcs11/gkm/gkm-data-der.h b/pkcs11/gkm/gkm-data-der.h
index 664259a..f98ec6b 100644
--- a/pkcs11/gkm/gkm-data-der.h
+++ b/pkcs11/gkm/gkm-data-der.h
@@ -30,94 +30,97 @@
 #include "gkm-data-types.h"
 
 #include "egg/egg-asn1x.h"
+#include "egg/egg-bytes.h"
 
 /* -----------------------------------------------------------------------------
  * PRIVATE KEYS
  */
 
-GkmDataResult      gkm_data_der_read_private_key_rsa         (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_private_key_rsa         (EggBytes *data,
                                                               gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_private_key_dsa         (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_private_key_dsa         (EggBytes *data,
                                                               gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_private_key_dsa_parts   (gconstpointer keydata, gsize n_keydata,
-                                                              gconstpointer params, gsize n_params,
+GkmDataResult      gkm_data_der_read_private_key_dsa_parts   (EggBytes *keydata,
+                                                              EggBytes *params,
                                                               gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_private_key             (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_private_key             (EggBytes *data,
                                                               gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_private_pkcs8           (gconstpointer data, gsize n_data,
-                                                              const gchar *password, gsize n_password,
+GkmDataResult      gkm_data_der_read_private_pkcs8           (EggBytes *data,
+                                                              const gchar *password,
+                                                              gsize n_password,
                                                               gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_private_pkcs8_plain     (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_private_pkcs8_plain     (EggBytes *data,
                                                               gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_private_pkcs8_crypted   (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_private_pkcs8_crypted   (EggBytes *data,
                                                               const gchar *password, gsize n_password,
                                                               gcry_sexp_t *s_key);
 
-gpointer           gkm_data_der_write_private_key_rsa        (gcry_sexp_t s_key, gsize *n_data);
+EggBytes *         gkm_data_der_write_private_key_rsa        (gcry_sexp_t s_key);
 
-gpointer           gkm_data_der_write_private_key_dsa        (gcry_sexp_t s_key, gsize *len);
+EggBytes *         gkm_data_der_write_private_key_dsa        (gcry_sexp_t s_key);
 
-gpointer           gkm_data_der_write_private_key_dsa_part   (gcry_sexp_t skey, gsize *n_key);
+EggBytes *         gkm_data_der_write_private_key_dsa_part   (gcry_sexp_t skey);
 
-gpointer           gkm_data_der_write_private_key_dsa_params (gcry_sexp_t skey, gsize *n_params);
+EggBytes *         gkm_data_der_write_private_key_dsa_params (gcry_sexp_t skey);
 
-gpointer           gkm_data_der_write_private_key            (gcry_sexp_t s_key, gsize *n_data);
+EggBytes *         gkm_data_der_write_private_key            (gcry_sexp_t s_key);
 
-gpointer           gkm_data_der_write_private_pkcs8_plain    (gcry_sexp_t skey, gsize *n_data);
+EggBytes *         gkm_data_der_write_private_pkcs8_plain    (gcry_sexp_t skey);
 
-gpointer           gkm_data_der_write_private_pkcs8_crypted  (gcry_sexp_t skey, const gchar *password,
-                                                              gsize n_password, gsize *n_data);
+EggBytes *         gkm_data_der_write_private_pkcs8_crypted  (gcry_sexp_t skey,
+                                                              const gchar *password,
+                                                              gsize n_password);
 
 /* -----------------------------------------------------------------------------
  * PUBLIC KEYS
  */
 
-GkmDataResult      gkm_data_der_read_public_key_rsa        (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_public_key_rsa        (EggBytes *data,
                                                             gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_public_key_dsa        (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_public_key_dsa        (EggBytes *data,
                                                             gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_public_key_dsa_parts  (gconstpointer keydata, gsize n_keydata,
-                                                            gconstpointer params, gsize n_params,
+GkmDataResult      gkm_data_der_read_public_key_dsa_parts  (EggBytes *keydata,
+                                                            EggBytes *params,
                                                             gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_public_key            (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_public_key            (EggBytes *data,
                                                             gcry_sexp_t *s_key);
 
-GkmDataResult      gkm_data_der_read_public_key_info       (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_public_key_info       (EggBytes *data,
                                                             gcry_sexp_t *s_key);
 
-gpointer           gkm_data_der_write_public_key_rsa       (gcry_sexp_t s_key, gsize *len);
+EggBytes *         gkm_data_der_write_public_key_rsa       (gcry_sexp_t s_key);
 
-gpointer           gkm_data_der_write_public_key_dsa       (gcry_sexp_t s_key, gsize *len);
+EggBytes *         gkm_data_der_write_public_key_dsa       (gcry_sexp_t s_key);
 
-gpointer           gkm_data_der_write_public_key           (gcry_sexp_t s_key, gsize *len);
+EggBytes *         gkm_data_der_write_public_key           (gcry_sexp_t s_key);
 
 
 /* -----------------------------------------------------------------------------
  * CERTIFICATES
  */
 
-GkmDataResult      gkm_data_der_read_certificate           (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_certificate           (EggBytes *data,
                                                             GNode **asn1);
 
-GkmDataResult      gkm_data_der_read_basic_constraints     (gconstpointer data, gsize n_data,
-                                                            gboolean *is_ca, gint *path_len);
+GkmDataResult      gkm_data_der_read_basic_constraints     (EggBytes *data,
+                                                            gboolean *is_ca,
+                                                            gint *path_len);
 
-GkmDataResult      gkm_data_der_read_key_usage             (gconstpointer data,
-                                                            gsize n_data,
+GkmDataResult      gkm_data_der_read_key_usage             (EggBytes *data,
                                                             gulong *key_usage);
 
-GkmDataResult      gkm_data_der_read_enhanced_usage        (gconstpointer data, gsize n_data,
+GkmDataResult      gkm_data_der_read_enhanced_usage        (EggBytes *data,
                                                             GQuark **oids);
 
-gpointer           gkm_data_der_write_certificate          (GNode *asn1, gsize *n_data);
+EggBytes *         gkm_data_der_write_certificate          (GNode *asn1);
 
 #endif /*GKRPKIXDER_H_*/
diff --git a/pkcs11/gkm/gkm-serializable.c b/pkcs11/gkm/gkm-serializable.c
index c0ff12d..4fab9e5 100644
--- a/pkcs11/gkm/gkm-serializable.c
+++ b/pkcs11/gkm/gkm-serializable.c
@@ -63,17 +63,18 @@ gkm_serializable_get_type (void)
 }
 
 gboolean
-gkm_serializable_load (GkmSerializable *self, GkmSecret *login, gconstpointer data, gsize n_data)
+gkm_serializable_load (GkmSerializable *self, GkmSecret *login, EggBytes *data)
 {
 	g_return_val_if_fail (GKM_IS_SERIALIZABLE (self), FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
 	g_return_val_if_fail (GKM_SERIALIZABLE_GET_INTERFACE (self)->load, FALSE);
-	return GKM_SERIALIZABLE_GET_INTERFACE (self)->load (self, login, data, n_data);
+	return GKM_SERIALIZABLE_GET_INTERFACE (self)->load (self, login, data);
 }
 
-gboolean
-gkm_serializable_save (GkmSerializable *self, GkmSecret *login, gpointer *data, gsize *n_data)
+EggBytes *
+gkm_serializable_save (GkmSerializable *self, GkmSecret *login)
 {
 	g_return_val_if_fail (GKM_IS_SERIALIZABLE (self), FALSE);
 	g_return_val_if_fail (GKM_SERIALIZABLE_GET_INTERFACE (self)->save, FALSE);
-	return GKM_SERIALIZABLE_GET_INTERFACE (self)->save (self, login, data, n_data);
+	return GKM_SERIALIZABLE_GET_INTERFACE (self)->save (self, login);
 }
diff --git a/pkcs11/gkm/gkm-serializable.h b/pkcs11/gkm/gkm-serializable.h
index 385793c..8e773ec 100644
--- a/pkcs11/gkm/gkm-serializable.h
+++ b/pkcs11/gkm/gkm-serializable.h
@@ -26,6 +26,8 @@
 
 #include "gkm-types.h"
 
+#include "egg/egg-bytes.h"
+
 G_BEGIN_DECLS
 
 #define GKM_TYPE_SERIALIZABLE                 (gkm_serializable_get_type())
@@ -41,22 +43,22 @@ struct _GkmSerializableIface {
 
 	const gchar *extension;
 
-	gboolean (*load) (GkmSerializable *self, GkmSecret *login, gconstpointer data, gsize n_data);
+	gboolean   (*load) (GkmSerializable *self,
+	                    GkmSecret *login,
+	                    EggBytes *data);
 
-	gboolean (*save) (GkmSerializable *self, GkmSecret *login, gpointer *data, gsize *n_data);
+	EggBytes * (*save) (GkmSerializable *self,
+	                    GkmSecret *login);
 };
 
 GType                  gkm_serializable_get_type                          (void) G_GNUC_CONST;
 
 gboolean               gkm_serializable_load                              (GkmSerializable *self,
                                                                            GkmSecret *login,
-                                                                           gconstpointer data,
-                                                                           gsize n_data);
+                                                                           EggBytes *data);
 
-gboolean                gkm_serializable_save                             (GkmSerializable *self,
-                                                                           GkmSecret *login,
-                                                                           gpointer *data,
-                                                                           gsize *n_data);
+EggBytes *             gkm_serializable_save                              (GkmSerializable *self,
+                                                                           GkmSecret *login);
 
 G_END_DECLS
 
diff --git a/pkcs11/gkm/tests/Makefile.am b/pkcs11/gkm/tests/Makefile.am
index 034e147..9dcd70b 100644
--- a/pkcs11/gkm/tests/Makefile.am
+++ b/pkcs11/gkm/tests/Makefile.am
@@ -1,3 +1,12 @@
+include $(top_srcdir)/Makefile.decl
+
+ASN_FILES = \
+	test.asn
+
+ASN_SRCS = $(ASN_FILES:.asn=.asn.h)
+
+BUILT_SOURCES = \
+	$(ASN_SRCS)
 
 INCLUDES = \
 	-I$(top_builddir) \
@@ -16,9 +25,6 @@ LDADD = \
 
 noinst_LIBRARIES = libgkm-mock.a
 
-BUILT_SOURCES = \
-	asn1-def-test.h
-
 libgkm_mock_a_SOURCES = \
 	mock-module.c mock-module.h \
 	mock-locked-object.c mock-locked-object.h \
@@ -72,11 +78,8 @@ check-local: test
 
 all-local: $(check_PROGRAMS)
 
-asn1-def-test.h: test.asn
-	$(ASN1PARSER) -o asn1-def-test.h $(srcdir)/test.asn
-
 EXTRA_DIST = \
-	test.asn \
+	$(ASN_FILES) \
 	files
 
 DISTCLEANFILES = \
diff --git a/pkcs11/gkm/tests/mock-module.c b/pkcs11/gkm/tests/mock-module.c
index 3abe116..58d8664 100644
--- a/pkcs11/gkm/tests/mock-module.c
+++ b/pkcs11/gkm/tests/mock-module.c
@@ -33,7 +33,7 @@ GKM_DEFINE_MODULE (test_module, GKM_TYPE_MODULE);
 
 #include "gkm/gkm-certificate.h"
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 GkmModule*
 mock_module_initialize_and_enter (void)
diff --git a/pkcs11/gkm/tests/test-certificate.c b/pkcs11/gkm/tests/test-certificate.c
index 7ad9a6d..1927926 100644
--- a/pkcs11/gkm/tests/test-certificate.c
+++ b/pkcs11/gkm/tests/test-certificate.c
@@ -40,8 +40,7 @@
 typedef struct {
 	GkmModule *module;
 	GkmSession *session;
-	gpointer certificate_data;
-	gsize n_certificate_data;
+	EggBytes *certificate_data;
 	GkmCertificate *certificate;
 } Test;
 
@@ -58,21 +57,20 @@ setup_basic (Test* test,
 	if (!g_file_get_contents (SRCDIR "/files/test-certificate-1.der", &data, &length, NULL))
 		g_assert_not_reached ();
 
-	test->certificate_data = data;
-	test->n_certificate_data = length;
+	test->certificate_data = egg_bytes_new_take (data, length);
 }
 
 static void
 teardown_basic (Test* test,
                 gconstpointer unused)
 {
-	g_free (test->certificate_data);
+	egg_bytes_unref (test->certificate_data);
 	mock_module_leave_and_finalize ();
 }
 
 static GkmCertificate *
 create_certificate_object (GkmSession *session,
-                           gpointer data, gsize length)
+                           EggBytes *data)
 {
 	GkmCertificate *certificate;
 
@@ -82,7 +80,7 @@ create_certificate_object (GkmSession *session,
 	                            "manager", gkm_session_get_manager (session),
 	                            NULL);
 
-	if (!gkm_serializable_load (GKM_SERIALIZABLE (certificate), NULL, data, length))
+	if (!gkm_serializable_load (GKM_SERIALIZABLE (certificate), NULL, data))
 		g_assert_not_reached ();
 
 	return certificate;
@@ -93,7 +91,7 @@ setup (Test *test,
        gconstpointer unused)
 {
 	setup_basic (test, unused);
-	test->certificate = create_certificate_object (test->session, test->certificate_data, test->n_certificate_data);
+	test->certificate = create_certificate_object (test->session, test->certificate_data);
 }
 
 static void
@@ -171,9 +169,8 @@ test_attribute_value (Test* test,
 	data = gkm_object_get_attribute_data (GKM_OBJECT (test->certificate),
 	                                      test->session, CKA_VALUE, &n_data);
 
-	raw = test->certificate_data;
-	n_raw = test->n_certificate_data
-			;
+	raw = egg_bytes_get_data (test->certificate_data);
+	n_raw = egg_bytes_get_size (test->certificate_data);
 	egg_assert_cmpmem (data, n_data, ==, raw, n_raw);
 	g_free (data);
 }
diff --git a/pkcs11/gkm/tests/test-data-asn1.c b/pkcs11/gkm/tests/test-data-asn1.c
index b29ea0b..e9d98d6 100644
--- a/pkcs11/gkm/tests/test-data-asn1.c
+++ b/pkcs11/gkm/tests/test-data-asn1.c
@@ -36,29 +36,33 @@
 #include "egg/egg-asn1x.h"
 #include "egg/egg-asn1-defs.h"
 
-#include "asn1-def-test.h"
+typedef struct _EggAsn1xDef ASN1_ARRAY_TYPE;
+#include "test.asn.h"
 
 typedef struct {
 	GNode *asn1_cert;
-	gchar *data_cert;
-	gsize n_data_cert;
 } Test;
 
 static void
 setup (Test *test, gconstpointer unused)
 {
-	if (!g_file_get_contents (SRCDIR "/files/test-certificate-1.der", &test->data_cert, &test->n_data_cert, NULL))
+	EggBytes *data;
+	gchar *contents;
+	gsize length;
+
+	if (!g_file_get_contents (SRCDIR "/files/test-certificate-1.der", &contents, &length, NULL))
 		g_assert_not_reached ();
 
-	test->asn1_cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", test->data_cert, test->n_data_cert);
+	data = egg_bytes_new_take (contents, length);
+	test->asn1_cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data);
 	g_assert (test->asn1_cert);
+	egg_bytes_unref (data);
 }
 
 static void
 teardown (Test *test, gconstpointer unused)
 {
 	egg_asn1x_destroy (test->asn1_cert);
-	g_free (test->data_cert);
 }
 
 static void
@@ -66,8 +70,7 @@ test_asn1_integers (Test *test, gconstpointer unused)
 {
 	GNode *asn;
 	gcry_mpi_t mpi, mpt;
-	guchar *data;
-	gsize n_data;
+	EggBytes *data;
 	gboolean ret;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestIntegers");
@@ -82,21 +85,21 @@ test_asn1_integers (Test *test, gconstpointer unused)
 	ret = gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "mpi", NULL), mpi);
 
 	/* Now encode the whole caboodle */
-	data = egg_asn1x_encode (asn, NULL, &n_data);
+	data = egg_asn1x_encode (asn, NULL);
 	g_assert ("encoding asn1 didn't work" && data != NULL);
 
 	egg_asn1x_destroy (asn);
 
 	/* Now decode it all nicely */
-	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestIntegers", data, n_data);
-	g_assert (asn);
+	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestIntegers", data);
+	g_assert (asn != NULL);
 
 	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);
 
-	g_free (data);
+	egg_bytes_unref (data);
 }
 
 int
diff --git a/pkcs11/gkm/tests/test-data-der.c b/pkcs11/gkm/tests/test-data-der.c
index 2bc90df..dc751d3 100644
--- a/pkcs11/gkm/tests/test-data-der.c
+++ b/pkcs11/gkm/tests/test-data-der.c
@@ -41,7 +41,7 @@
 #include <stdio.h>
 #include <string.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 typedef struct {
 	GNode *certificate;
@@ -95,36 +95,45 @@ compare_keys (gcry_sexp_t key, gcry_sexp_t sexp)
 static void
 test_der_public (gcry_sexp_t key)
 {
-	guchar *data;
-	gsize n_data;
+	EggBytes *data;
 	GkmDataResult ret;
 	gcry_sexp_t sexp;
 
 	/* Encode it */
-	data = gkm_data_der_write_public_key (key, &n_data);
+	data = gkm_data_der_write_public_key (key);
 	g_assert ("couldn't encode public key" && data != NULL);
-	g_assert ("encoding is empty" && n_data > 0);
+	g_assert ("encoding is empty" && egg_bytes_get_size (data) > 0);
 
 	/* Now parse it */
-	ret = gkm_data_der_read_public_key (data, n_data, &sexp);
+	ret = gkm_data_der_read_public_key (data, &sexp);
 	g_assert ("couldn't decode public key" && ret == GKM_DATA_SUCCESS);
 	g_assert ("parsed key is empty" && sexp != NULL);
 
 	/* Now compare them */
 	g_assert ("key parsed differently" && compare_keys (key, sexp));
+
+	egg_bytes_unref (data);
 }
 
 static void
 setup (Test *test, gconstpointer unused)
 {
+	EggBytes *data;
+
 	if (!g_file_get_contents (SRCDIR "/files/test-certificate-1.der", &test->certificate_data, &test->n_certificate_data, NULL))
 		g_assert_not_reached ();
-	test->certificate = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", test->certificate_data, test->n_certificate_data);
-	g_assert (test->certificate);
+
+	data = egg_bytes_new (test->certificate_data, test->n_certificate_data);
+	test->certificate = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data);
+	g_assert (test->certificate != NULL);
+	egg_bytes_unref (data);
+
 	if (!g_file_get_contents (SRCDIR "/files/test-certificate-2.der", &test->certificate2_data, &test->n_certificate2_data, NULL))
 		g_assert_not_reached ();
-	test->certificate2 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", test->certificate2_data, test->n_certificate2_data);
-	g_assert (test->certificate2);
+	data = egg_bytes_new (test->certificate2_data, test->n_certificate2_data);
+	test->certificate2 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data);
+	g_assert (test->certificate2 != NULL);
+	egg_bytes_unref (data);
 }
 
 static void
@@ -163,25 +172,24 @@ test_der_dsa_public (Test *test, gconstpointer unused)
 static void
 test_der_private (gcry_sexp_t key)
 {
-	guchar *data;
-	gsize n_data;
+	EggBytes *data;
 	GkmDataResult ret;
 	gcry_sexp_t sexp;
 
 	/* Encode it */
-	data = gkm_data_der_write_private_key (key, &n_data);
+	data = gkm_data_der_write_private_key (key);
 	g_assert ("couldn't encode private key" && data != NULL);
-	g_assert ("encoding is empty" && n_data > 0);
+	g_assert ("encoding is empty" && egg_bytes_get_size (data) > 0);
 
 	/* Now parse it */
-	ret = gkm_data_der_read_private_key (data, n_data, &sexp);
+	ret = gkm_data_der_read_private_key (data, &sexp);
 	g_assert ("couldn't decode private key" && ret == GKM_DATA_SUCCESS);
 	g_assert ("parsed key is empty" && sexp != NULL);
 
 	/* Now compare them */
 	g_assert ("key parsed differently" && compare_keys (key, sexp));
 
-	egg_secure_free (data);
+	egg_bytes_unref (data);
 }
 
 static void
@@ -211,8 +219,7 @@ test_der_dsa_private (Test *test, gconstpointer unused)
 static void
 test_der_dsa_private_parts (Test *test, gconstpointer unused)
 {
-	guchar *params, *key;
-	gsize n_params, n_key;
+	EggBytes *params, *key;
 	gcry_sexp_t skey, pkey;
 	gcry_error_t gcry;
 	GkmDataResult result;
@@ -221,21 +228,21 @@ test_der_dsa_private_parts (Test *test, gconstpointer unused)
 	g_return_if_fail (gcry == 0);
 
 	/* Encode the the dsa key by parts */
-	params = gkm_data_der_write_private_key_dsa_params (skey, &n_params);
+	params = gkm_data_der_write_private_key_dsa_params (skey);
 	g_assert ("didn't encode dsa params" && params != NULL);
-	key = gkm_data_der_write_private_key_dsa_part (skey, &n_key);
+	key = gkm_data_der_write_private_key_dsa_part (skey);
 	g_assert ("didn't encode dsa key" && key != NULL);
 
 	/* Parse the dsa key by parts */
-	result = gkm_data_der_read_private_key_dsa_parts (key, n_key, params, n_params, &pkey);
+	result = gkm_data_der_read_private_key_dsa_parts (key, params, &pkey);
 	g_assert ("couldn't parse dsa parts" && result == GKM_DATA_SUCCESS);
 	g_assert ("parsing dsa parts resulted in null key" && pkey != NULL);
 
 	/* Now compare them */
 	g_assert ("key parsed differently" && compare_keys (skey, pkey));
 
-	egg_secure_free (params);
-	egg_secure_free (key);
+	egg_bytes_unref (params);
+	egg_bytes_unref (key);
 }
 
 const gchar *certpub = "(public-key (rsa " \
@@ -245,17 +252,16 @@ const gchar *certpub = "(public-key (rsa " \
 static void
 test_read_public_key_info (Test *test, gconstpointer unused)
 {
-	const guchar *data;
+	EggBytes *data;
 	guchar hash[20];
-	gsize n_data;
 	GkmDataResult res;
 	gcry_sexp_t sexp, match;
 	gcry_error_t gcry;
 
-	data = egg_asn1x_get_raw_element (egg_asn1x_node (test->certificate, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_data);
-	g_assert (data);
+	data = egg_asn1x_get_element_raw (egg_asn1x_node (test->certificate, "tbsCertificate", "subjectPublicKeyInfo", NULL));
+	g_assert (data != NULL);
 
-	res = gkm_data_der_read_public_key_info (data, n_data, &sexp);
+	res = gkm_data_der_read_public_key_info (data, &sexp);
 	g_assert (res == GKM_DATA_SUCCESS);
 	g_assert (sexp != NULL);
 
@@ -269,6 +275,7 @@ test_read_public_key_info (Test *test, gconstpointer unused)
 
 	gcry_sexp_release (sexp);
 	gcry_sexp_release (match);
+	egg_bytes_unref (data);
 }
 
 static void
@@ -276,77 +283,79 @@ test_read_certificate (Test *test, gconstpointer unused)
 {
 	GNode *asn = NULL;
 	GkmDataResult res;
+	EggBytes *data;
 
-	res = gkm_data_der_read_certificate (test->certificate_data, test->n_certificate_data, &asn);
+	data = egg_bytes_new (test->certificate_data, test->n_certificate_data);
+	res = gkm_data_der_read_certificate (data, &asn);
 	g_assert (res == GKM_DATA_SUCCESS);
 	g_assert (asn != NULL);
 
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
 static void
 test_write_certificate (Test *test, gconstpointer unused)
 {
-	guchar *data;
-	gsize n_data;
+	EggBytes *data;
 
-	data = gkm_data_der_write_certificate (test->certificate, &n_data);
-	g_assert (data);
-	g_assert (n_data == test->n_certificate_data);
-	g_assert (memcmp (data, test->certificate_data, n_data) == 0);
-	g_free (data);
+	data = gkm_data_der_write_certificate (test->certificate);
+	g_assert (egg_bytes_get_size (data) == test->n_certificate_data);
+	g_assert (memcmp (egg_bytes_get_data (data), test->certificate_data, egg_bytes_get_size (data)) == 0);
+	egg_bytes_unref (data);
 }
 
 static void
 on_ca_certificate_public_key_info (GQuark type,
-                                   const guchar *data,
-                                   gsize n_data,
-                                   const gchar *outer,
-                                   gsize n_outer,
+                                   EggBytes *data,
+                                   EggBytes *outer,
                                    GHashTable *headers,
                                    gpointer user_data)
 {
 	GNode *asn1 = NULL;
 	GkmDataResult res;
-	gpointer keydata;
-	gsize n_keydata;
+	EggBytes *keydata;
 	gcry_sexp_t sexp;
 
 	g_assert (g_quark_try_string ("CERTIFICATE") == type);
 
 	/* Parse the ASN1 data */
-	res = gkm_data_der_read_certificate (data, n_data, &asn1);
+	res = gkm_data_der_read_certificate (data, &asn1);
 	g_assert (res == GKM_DATA_SUCCESS);
 
 	/* Generate a raw public key from our test->certificate */
-	keydata = egg_asn1x_encode (egg_asn1x_node (asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), NULL, &n_keydata);
-	g_assert (keydata);
+	keydata = egg_asn1x_encode (egg_asn1x_node (asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), NULL);
+	g_assert (keydata != NULL);
 
 	/* Now create us a nice public key with that identifier */
-	res = gkm_data_der_read_public_key_info (keydata, n_keydata, &sexp);
+	res = gkm_data_der_read_public_key_info (keydata, &sexp);
 	g_assert (res == GKM_DATA_SUCCESS || res == GKM_DATA_UNRECOGNIZED);
 
 	if (res == GKM_DATA_SUCCESS)
 		gcry_sexp_release (sexp);
-	g_free (keydata);
+	egg_bytes_unref (keydata);
 }
 
 static void
 test_read_ca_certificates_public_key_info (Test *test, gconstpointer unused)
 {
+	EggBytes *bytes;
 	gchar *data;
 	gsize n_data;
 
 	if (!g_file_get_contents (SRCDIR "/files/ca-certificates.crt", &data, &n_data, NULL))
 		g_assert_not_reached ();
-	egg_armor_parse (data, n_data, on_ca_certificate_public_key_info, NULL);
-	g_free (data);
+
+	bytes = egg_bytes_new_take (data, n_data);
+	egg_armor_parse (bytes, on_ca_certificate_public_key_info, NULL);
+	egg_bytes_unref (bytes);
 }
 
-static const guchar*
-find_extension (GNode *asn, gconstpointer data, gsize n_data, const gchar *oid, gsize *n_extension)
+static EggBytes *
+find_extension (GNode *asn,
+                const gchar *oid)
 {
-	const guchar *value;
+	EggBytes *value;
 	GNode *node = NULL;
 	gchar *exoid;
 	guint index;
@@ -364,7 +373,7 @@ find_extension (GNode *asn, gconstpointer data, gsize n_data, const gchar *oid,
 		if (strcmp (exoid, oid) == 0) {
 			g_free (exoid);
 			node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, "extnValue", NULL);
-			value = egg_asn1x_get_raw_value (node, n_extension);
+			value = egg_asn1x_get_raw_value (node);
 			g_assert (value);
 			return value;
 		}
@@ -378,58 +387,60 @@ find_extension (GNode *asn, gconstpointer data, gsize n_data, const gchar *oid,
 static void
 test_read_basic_constraints (Test *test, gconstpointer unused)
 {
-	const guchar *extension;
-	gsize n_extension;
+	EggBytes *extension;
 	gboolean is_ca;
 	gint path_len;
 	GkmDataResult res;
 
-	extension = egg_asn1x_get_raw_value (egg_asn1x_node (test->certificate, "tbsCertificate", "extensions", 1, "extnValue", NULL),
-	                                     &n_extension);
-	g_assert (extension);
+	extension = egg_asn1x_get_raw_value (egg_asn1x_node (test->certificate, "tbsCertificate", "extensions", 1, "extnValue", NULL));
+	g_assert (extension != NULL);
 
-	res = gkm_data_der_read_basic_constraints (extension, n_extension, &is_ca, &path_len);
+	res = gkm_data_der_read_basic_constraints (extension, &is_ca, &path_len);
 	g_assert (res == GKM_DATA_SUCCESS);
 	g_assert (is_ca == TRUE);
 	g_assert (path_len == -1);
+
+	egg_bytes_unref (extension);
 }
 
 static void
 test_read_key_usage (Test *test, gconstpointer unused)
 {
-	const guchar *extension;
-	gsize n_extension;
+	EggBytes *extension;
 	gulong key_usage;
 	GkmDataResult res;
 
-	extension = find_extension (test->certificate2, test->certificate2_data, test->n_certificate2_data, "2.5.29.15", &n_extension);
+	extension = find_extension (test->certificate2, "2.5.29.15");
 	g_assert (extension);
 
-	res = gkm_data_der_read_key_usage (extension, n_extension, &key_usage);
+	res = gkm_data_der_read_key_usage (extension, &key_usage);
 	g_assert (res == GKM_DATA_SUCCESS);
 	g_assert_cmpuint (key_usage, ==, 0x01);
+
+	egg_bytes_unref (extension);
 }
 
 static void
 test_read_enhanced_usage (Test *test, gconstpointer unused)
 {
-	const guchar *extension;
-	gsize n_extension;
+	EggBytes *extension;
 	GQuark *usages;
 	GkmDataResult res;
 
-	extension = find_extension (test->certificate2, test->certificate2_data, test->n_certificate2_data, "2.5.29.37", &n_extension);
+	extension = find_extension (test->certificate2, "2.5.29.37");
 	g_assert (extension);
 
-	res = gkm_data_der_read_enhanced_usage (extension, n_extension, &usages);
+	res = gkm_data_der_read_enhanced_usage (extension, &usages);
 	g_assert (res == GKM_DATA_SUCCESS);
 
+	egg_bytes_unref (extension);
 	g_free (usages);
 }
 
 static void
 test_read_all_pkcs8 (Test *test, gconstpointer unused)
 {
+	EggBytes *bytes;
 	gcry_sexp_t sexp;
 	GkmDataResult res;
 	GDir *dir;
@@ -454,12 +465,13 @@ test_read_all_pkcs8 (Test *test, gconstpointer unused)
 			g_assert_not_reached ();
 		g_free (path);
 
-		res = gkm_data_der_read_private_pkcs8 (data, n_data, "booo", 4, &sexp);
+		bytes = egg_bytes_new_take (data, n_data);
+		res = gkm_data_der_read_private_pkcs8 (bytes, "booo", 4, &sexp);
 		g_assert (res == GKM_DATA_SUCCESS);
+		egg_bytes_unref (bytes);
 
 		g_assert (gkm_sexp_parse_key (sexp, NULL, NULL, NULL));
 		gcry_sexp_release (sexp);
-		g_free (data);
 	}
 
 	g_dir_close (dir);
@@ -470,16 +482,18 @@ test_read_pkcs8_bad_password (Test *test, gconstpointer unused)
 {
 	gcry_sexp_t sexp;
 	GkmDataResult res;
+	EggBytes *bytes;
 	gchar *data;
 	gsize n_data;
 
 	if (!g_file_get_contents (SRCDIR "/files/der-key-encrypted-pkcs5.p8", &data, &n_data, NULL))
 		g_assert_not_reached ();
 
-	res = gkm_data_der_read_private_pkcs8 (data, n_data, "wrong password", 4, &sexp);
+	bytes = egg_bytes_new_take (data, n_data);
+	res = gkm_data_der_read_private_pkcs8 (bytes, "wrong password", 4, &sexp);
 	g_assert (res == GKM_DATA_LOCKED);
 
-	g_free (data);
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -488,22 +502,20 @@ test_write_pkcs8_plain (Test *test, gconstpointer unused)
 	gcry_sexp_t sexp, check;
 	gcry_error_t gcry;
 	GkmDataResult res;
-	guchar *data;
-	gsize n_data;
+	EggBytes *data;
 
 	/* RSA */
 
 	gcry = gcry_sexp_sscan (&sexp, NULL, rsaprv, strlen (rsaprv));
 	g_return_if_fail (gcry == 0);
 
-	data = gkm_data_der_write_private_pkcs8_plain (sexp, &n_data);
-	g_assert (data);
-	g_assert (n_data);
+	data = gkm_data_der_write_private_pkcs8_plain (sexp);
+	g_assert (data != NULL);
 
-	res = gkm_data_der_read_private_pkcs8_plain (data, n_data, &check);
-	egg_secure_free (data);
+	res = gkm_data_der_read_private_pkcs8_plain (data, &check);
+	egg_bytes_unref (data);
 	g_assert (res == GKM_DATA_SUCCESS);
-	g_assert (check);
+	g_assert (check != NULL);
 
 	g_assert (compare_keys (sexp, check));
 	gcry_sexp_release (sexp);
@@ -515,14 +527,13 @@ test_write_pkcs8_plain (Test *test, gconstpointer unused)
 	gcry = gcry_sexp_sscan (&sexp, NULL, dsaprv, strlen (dsaprv));
 	g_return_if_fail (gcry == 0);
 
-	data = gkm_data_der_write_private_pkcs8_plain (sexp, &n_data);
-	g_assert (data);
-	g_assert (n_data);
+	data = gkm_data_der_write_private_pkcs8_plain (sexp);
+	g_assert (data != NULL);
 
-	res = gkm_data_der_read_private_pkcs8_plain (data, n_data, &check);
-	egg_secure_free (data);
+	res = gkm_data_der_read_private_pkcs8_plain (data, &check);
+	egg_bytes_unref (data);
 	g_assert (res == GKM_DATA_SUCCESS);
-	g_assert (check);
+	g_assert (check != NULL);
 
 	g_assert (compare_keys (sexp, check));
 	gcry_sexp_release (sexp);
@@ -536,22 +547,20 @@ test_write_pkcs8_encrypted (Test *test, gconstpointer unused)
 	gcry_sexp_t sexp, check;
 	gcry_error_t gcry;
 	GkmDataResult res;
-	guchar *data;
-	gsize n_data;
+	EggBytes *data;
 
 	/* RSA */
 
 	gcry = gcry_sexp_sscan (&sexp, NULL, rsaprv, strlen (rsaprv));
 	g_return_if_fail (gcry == 0);
 
-	data = gkm_data_der_write_private_pkcs8_crypted (sexp, "testo", 5, &n_data);
-	g_assert (data);
-	g_assert (n_data);
+	data = gkm_data_der_write_private_pkcs8_crypted (sexp, "testo", 5);
+	g_assert (data != NULL);
 
-	res = gkm_data_der_read_private_pkcs8_crypted (data, n_data, "testo", 5, &check);
-	g_free (data);
+	res = gkm_data_der_read_private_pkcs8_crypted (data, "testo", 5, &check);
+	egg_bytes_unref (data);
 	g_assert (res == GKM_DATA_SUCCESS);
-	g_assert (check);
+	g_assert (check != NULL);
 
 	g_assert (compare_keys (sexp, check));
 	gcry_sexp_release (sexp);
@@ -563,14 +572,13 @@ test_write_pkcs8_encrypted (Test *test, gconstpointer unused)
 	gcry = gcry_sexp_sscan (&sexp, NULL, dsaprv, strlen (dsaprv));
 	g_return_if_fail (gcry == 0);
 
-	data = gkm_data_der_write_private_pkcs8_crypted (sexp, "testo", 5, &n_data);
-	g_assert (data);
-	g_assert (n_data);
+	data = gkm_data_der_write_private_pkcs8_crypted (sexp, "testo", 5);
+	g_assert (data != NULL);
 
-	res = gkm_data_der_read_private_pkcs8_crypted (data, n_data, "testo", 5, &check);
-	g_free (data);
+	res = gkm_data_der_read_private_pkcs8_crypted (data, "testo", 5, &check);
+	egg_bytes_unref (data);
 	g_assert (res == GKM_DATA_SUCCESS);
-	g_assert (check);
+	g_assert (check != NULL);
 
 	g_assert (compare_keys (sexp, check));
 	gcry_sexp_release (sexp);
diff --git a/pkcs11/gkm/tests/test-secret.c b/pkcs11/gkm/tests/test-secret.c
index 67e7a62..e8fc58d 100644
--- a/pkcs11/gkm/tests/test-secret.c
+++ b/pkcs11/gkm/tests/test-secret.c
@@ -31,7 +31,7 @@
 
 #include "egg/egg-secure-memory.h"
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 test_secret (void)
diff --git a/pkcs11/gkm/tests/test-sexp.c b/pkcs11/gkm/tests/test-sexp.c
index 5f3e062..3d9e039 100644
--- a/pkcs11/gkm/tests/test-sexp.c
+++ b/pkcs11/gkm/tests/test-sexp.c
@@ -34,7 +34,7 @@
 
 #include <gcrypt.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 #define TEST_RSA \
 "(private-key (rsa " \
diff --git a/pkcs11/gnome2-store/gkm-gnome2-private-key.c b/pkcs11/gnome2-store/gkm-gnome2-private-key.c
index a2bc738..a9c5c4e 100644
--- a/pkcs11/gnome2-store/gkm-gnome2-private-key.c
+++ b/pkcs11/gnome2-store/gkm-gnome2-private-key.c
@@ -46,9 +46,7 @@ enum {
 struct _GkmGnome2PrivateKey {
 	GkmPrivateXsaKey parent;
 
-	guchar *private_data;
-	gsize n_private_data;
-
+	EggBytes *private_bytes;
 	GkmSexp *private_sexp;
 	gboolean is_encrypted;
 	GkmSecret *login;
@@ -122,8 +120,7 @@ gkm_gnome2_private_key_real_acquire_crypto_sexp (GkmSexpKey *base, GkmSession *u
 	g_return_val_if_fail (self->is_encrypted, NULL);
 
 	password = gkm_secret_get_password (self->login, &n_password);
-	res = gkm_data_der_read_private_pkcs8 (self->private_data, self->n_private_data,
-	                                       password, n_password, &sexp);
+	res = gkm_data_der_read_private_pkcs8 (self->private_bytes, password, n_password, &sexp);
 	g_return_val_if_fail (res == GKM_DATA_SUCCESS, NULL);
 
 	return gkm_sexp_new (sexp);
@@ -154,8 +151,8 @@ gkm_gnome2_private_key_finalize (GObject *obj)
 
 	g_assert (self->login == NULL);
 
-	g_free (self->private_data);
-	self->private_data = NULL;
+	if (self->private_bytes)
+		egg_bytes_unref (self->private_bytes);
 
 	if (self->private_sexp)
 		gkm_sexp_unref (self->private_sexp);
@@ -204,7 +201,9 @@ gkm_gnome2_private_key_class_init (GkmGnome2PrivateKeyClass *klass)
 }
 
 static gboolean
-gkm_gnome2_private_key_real_load (GkmSerializable *base, GkmSecret *login, gconstpointer data, gsize n_data)
+gkm_gnome2_private_key_real_load (GkmSerializable *base,
+                                  GkmSecret *login,
+                                  EggBytes *data)
 {
 	GkmGnome2PrivateKey *self = GKM_GNOME2_PRIVATE_KEY (base);
 	GkmDataResult res;
@@ -213,10 +212,10 @@ gkm_gnome2_private_key_real_load (GkmSerializable *base, GkmSecret *login, gcons
 	const gchar *password;
 	gsize n_password;
 
-	g_return_val_if_fail (GKM_IS_GNOME2_PRIVATE_KEY (self), FALSE);
-	g_return_val_if_fail (data, FALSE);
+	if (egg_bytes_get_size (data) == 0)
+		return FALSE;
 
-	res = gkm_data_der_read_private_pkcs8 (data, n_data, NULL, 0, &sexp);
+	res = gkm_data_der_read_private_pkcs8 (data, NULL, 0, &sexp);
 
 	/* An unencrypted pkcs8 file */
 	if (res == GKM_DATA_SUCCESS) {
@@ -232,7 +231,7 @@ gkm_gnome2_private_key_real_load (GkmSerializable *base, GkmSecret *login, gcons
 		}
 
 		password = gkm_secret_get_password (login, &n_password);
-		res = gkm_data_der_read_private_pkcs8 (data, n_data, password, n_password, &sexp);
+		res = gkm_data_der_read_private_pkcs8 (data, password, n_password, &sexp);
 	}
 
 	switch (res) {
@@ -262,9 +261,9 @@ gkm_gnome2_private_key_real_load (GkmSerializable *base, GkmSecret *login, gcons
 
 	/* Encrypted private key, keep login and data */
 	if (self->is_encrypted) {
-		g_free (self->private_data);
-		self->n_private_data = n_data;
-		self->private_data = g_memdup (data, n_data);
+		if (self->private_bytes)
+			egg_bytes_unref (self->private_bytes);
+		self->private_bytes = egg_bytes_ref (data);
 
 		g_object_ref (login);
 		if (self->login)
@@ -289,18 +288,16 @@ gkm_gnome2_private_key_real_load (GkmSerializable *base, GkmSecret *login, gcons
 	return TRUE;
 }
 
-static gboolean
-gkm_gnome2_private_key_real_save (GkmSerializable *base, GkmSecret *login, gpointer *data, gsize *n_data)
+static EggBytes *
+gkm_gnome2_private_key_real_save (GkmSerializable *base, GkmSecret *login)
 {
 	GkmGnome2PrivateKey *self = GKM_GNOME2_PRIVATE_KEY (base);
 	const gchar *password = NULL;
 	gsize n_password;
 	GkmSexp *sexp;
-	guchar *key;
+	EggBytes *result;
 
 	g_return_val_if_fail (GKM_IS_GNOME2_PRIVATE_KEY (self), FALSE);
-	g_return_val_if_fail (data, FALSE);
-	g_return_val_if_fail (n_data, FALSE);
 
 	sexp = gkm_gnome2_private_key_real_acquire_crypto_sexp (GKM_SEXP_KEY (self), NULL);
 	g_return_val_if_fail (sexp, FALSE);
@@ -308,21 +305,14 @@ gkm_gnome2_private_key_real_save (GkmSerializable *base, GkmSecret *login, gpoin
 	if (login != NULL)
 		password = gkm_secret_get_password (login, &n_password);
 	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);
+		result = gkm_data_der_write_private_pkcs8_plain (gkm_sexp_get (sexp));
 	} else {
-		*data = gkm_data_der_write_private_pkcs8_crypted (gkm_sexp_get (sexp), password,
-		                                                  n_password, n_data);
+		result = gkm_data_der_write_private_pkcs8_crypted (gkm_sexp_get (sexp), password,
+		                                                   n_password);
 	}
 
 	gkm_sexp_unref (sexp);
-	return *data != NULL;
+	return result;
 }
 
 static void
diff --git a/pkcs11/gnome2-store/gkm-gnome2-public-key.c b/pkcs11/gnome2-store/gkm-gnome2-public-key.c
index e5c16be..e40d18b 100644
--- a/pkcs11/gnome2-store/gkm-gnome2-public-key.c
+++ b/pkcs11/gnome2-store/gkm-gnome2-public-key.c
@@ -120,17 +120,19 @@ gkm_gnome2_public_key_class_init (GkmGnome2PublicKeyClass *klass)
 
 
 static gboolean
-gkm_gnome2_public_key_real_load (GkmSerializable *base, GkmSecret *login, gconstpointer data, gsize n_data)
+gkm_gnome2_public_key_real_load (GkmSerializable *base,
+                                 GkmSecret *login,
+                                 EggBytes *data)
 {
 	GkmGnome2PublicKey *self = GKM_GNOME2_PUBLIC_KEY (base);
 	GkmDataResult res;
 	GkmSexp *wrapper;
 	gcry_sexp_t sexp;
 
-	g_return_val_if_fail (GKM_IS_GNOME2_PUBLIC_KEY (self), FALSE);
-	g_return_val_if_fail (data, FALSE);
+	if (egg_bytes_get_size (data) == 0)
+		return FALSE;
 
-	res = gkm_data_der_read_public_key (data, n_data, &sexp);
+	res = gkm_data_der_read_public_key (data, &sexp);
 
 	switch (res) {
 	case GKM_DATA_LOCKED:
@@ -155,21 +157,18 @@ gkm_gnome2_public_key_real_load (GkmSerializable *base, GkmSecret *login, gconst
 	return TRUE;
 }
 
-static gboolean
-gkm_gnome2_public_key_real_save (GkmSerializable *base, GkmSecret *login, gpointer *data, gsize *n_data)
+static EggBytes *
+gkm_gnome2_public_key_real_save (GkmSerializable *base, GkmSecret *login)
 {
 	GkmGnome2PublicKey *self = GKM_GNOME2_PUBLIC_KEY (base);
 	GkmSexp *wrapper;
 
 	g_return_val_if_fail (GKM_IS_GNOME2_PUBLIC_KEY (self), FALSE);
-	g_return_val_if_fail (data, FALSE);
-	g_return_val_if_fail (n_data, FALSE);
 
 	wrapper = gkm_sexp_key_get_base (GKM_SEXP_KEY (self));
 	g_return_val_if_fail (wrapper, FALSE);
 
-	*data = gkm_data_der_write_public_key (gkm_sexp_get (wrapper), n_data);
-	return *data != NULL;
+	return gkm_data_der_write_public_key (gkm_sexp_get (wrapper));
 }
 
 static void
diff --git a/pkcs11/gnome2-store/gkm-gnome2-standalone.c b/pkcs11/gnome2-store/gkm-gnome2-standalone.c
index 631499c..102a46a 100644
--- a/pkcs11/gnome2-store/gkm-gnome2-standalone.c
+++ b/pkcs11/gnome2-store/gkm-gnome2-standalone.c
@@ -34,7 +34,7 @@
 #include <glib-object.h>
 
 /* Module callbacks for secure memory */
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 CK_RV
 C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
diff --git a/pkcs11/gnome2-store/gkm-gnome2-storage.c b/pkcs11/gnome2-store/gkm-gnome2-storage.c
index ac52ccf..e654c5b 100644
--- a/pkcs11/gnome2-store/gkm-gnome2-storage.c
+++ b/pkcs11/gnome2-store/gkm-gnome2-storage.c
@@ -92,16 +92,20 @@ G_DEFINE_TYPE (GkmGnome2Storage, gkm_gnome2_storage, GKM_TYPE_STORE);
 #define UNWANTED_IDENTIFIER_CHARS  ":/\\<>|\t\n\r\v "
 
 static gchar*
-name_for_subject (const guchar *subject, gsize n_subject)
+name_for_subject (const guchar *subject,
+                  gsize n_subject)
 {
 	GNode *asn;
 	gchar *name;
+	EggBytes *bytes;
 
 	g_assert (subject);
 	g_assert (n_subject);
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Name", subject, n_subject);
-	g_return_val_if_fail (asn, NULL);
+	bytes = egg_bytes_new (subject, n_subject);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Name", bytes);
+	g_return_val_if_fail (asn != NULL, NULL);
+	egg_bytes_unref (bytes);
 
 	name = egg_dn_read_part (egg_asn1x_node (asn, "rdnSequence", NULL), "CN");
 	egg_asn1x_destroy (asn);
@@ -495,6 +499,7 @@ data_file_entry_added (GkmGnome2File *store, const gchar *identifier, GkmGnome2S
 {
 	GError *error = NULL;
 	GkmObject *object;
+	EggBytes *bytes;
 	gboolean ret;
 	guchar *data;
 	gsize n_data;
@@ -531,6 +536,7 @@ data_file_entry_added (GkmGnome2File *store, const gchar *identifier, GkmGnome2S
 	/* Make sure that the object wasn't tampered with */
 	if (!check_object_hash (self, identifier, data, n_data)) {
 		g_message ("file in user store doesn't match hash: %s", identifier);
+		g_free (data);
 		return;
 	}
 
@@ -540,13 +546,15 @@ data_file_entry_added (GkmGnome2File *store, const gchar *identifier, GkmGnome2S
 	g_return_if_fail (GKM_IS_SERIALIZABLE (object));
 	g_return_if_fail (GKM_SERIALIZABLE_GET_INTERFACE (object)->extension);
 
+	bytes = egg_bytes_new_take (data, n_data);
+
 	/* And load the data into it */
-	if (gkm_serializable_load (GKM_SERIALIZABLE (object), self->login, data, n_data))
+	if (gkm_serializable_load (GKM_SERIALIZABLE (object), self->login, bytes))
 		take_object_ownership (self, identifier, object);
 	else
 		g_message ("failed to load file in user store: %s", identifier);
 
-	g_free (data);
+	egg_bytes_unref (bytes);
 	g_object_unref (object);
 }
 
@@ -587,6 +595,7 @@ relock_object (GkmGnome2Storage *self, GkmTransaction *transaction, const gchar
 {
 	GError *error = NULL;
 	GkmObject *object;
+	EggBytes *bytes;
 	gpointer data;
 	gsize n_data;
 	GType type;
@@ -628,23 +637,26 @@ relock_object (GkmGnome2Storage *self, GkmTransaction *transaction, const gchar
 	if (!check_object_hash (self, identifier, data, n_data)) {
 		g_message ("file in data store doesn't match hash: %s", identifier);
 		gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
+		g_free (data);
 		return;
 	}
 
+	bytes = egg_bytes_new_take (data, n_data);
+
 	/* Load it into our temporary object */
-	if (!gkm_serializable_load (GKM_SERIALIZABLE (object), old_login, data, n_data)) {
+	if (!gkm_serializable_load (GKM_SERIALIZABLE (object), old_login, bytes)) {
 		g_message ("unrecognized or invalid user store file: %s", identifier);
 		gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
-		g_free (data);
+		egg_bytes_unref (bytes);
 		g_object_unref (object);
 		return;
 	}
 
-	g_free (data);
-	data = NULL;
+	egg_bytes_unref (bytes);
 
 	/* Read it out of our temporary object */
-	if (!gkm_serializable_save (GKM_SERIALIZABLE (object), new_login, &data, &n_data)) {
+	bytes = gkm_serializable_save (GKM_SERIALIZABLE (object), new_login);
+	if (bytes == NULL) {
 		g_warning ("unable to serialize data with new login: %s", identifier);
 		gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
 		g_object_unref (object);
@@ -661,8 +673,7 @@ relock_object (GkmGnome2Storage *self, GkmTransaction *transaction, const gchar
 	if (!gkm_transaction_get_failed (transaction))
 		store_object_hash (self, transaction, identifier, data, n_data);
 
-	g_free (data);
-
+	egg_bytes_unref (bytes);
 }
 
 typedef struct _RelockArgs {
@@ -1045,8 +1056,7 @@ gkm_gnome2_storage_create (GkmGnome2Storage *self, GkmTransaction *transaction,
 	gboolean is_private;
 	GkmDataResult res;
 	gchar *identifier;
-	gpointer data;
-	gsize n_data;
+	EggBytes *data;
 	gchar *path;
 
 	g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
@@ -1113,17 +1123,23 @@ gkm_gnome2_storage_create (GkmGnome2Storage *self, GkmTransaction *transaction,
 	}
 
 	/* Serialize the object in question */
-	if (!gkm_serializable_save (GKM_SERIALIZABLE (object), is_private ? self->login : NULL, &data, &n_data)) {
+	data = gkm_serializable_save (GKM_SERIALIZABLE (object), is_private ? self->login : NULL);
+
+	if (data == NULL) {
 		gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
 		g_return_if_reached ();
 	}
 
 	path = g_build_filename (self->directory, identifier, NULL);
-	gkm_transaction_write_file (transaction, path, data, n_data);
+	gkm_transaction_write_file (transaction, path,
+	                            egg_bytes_get_data (data),
+	                            egg_bytes_get_size (data));
 
 	/* Make sure we write in the object hash */
 	if (!gkm_transaction_get_failed (transaction))
-		store_object_hash (self, transaction, identifier, data, n_data);
+		store_object_hash (self, transaction, identifier,
+		                   egg_bytes_get_data (data),
+		                   egg_bytes_get_size (data));
 
 	/* Now we decide to own the object */
 	if (!gkm_transaction_get_failed (transaction))
@@ -1131,7 +1147,7 @@ gkm_gnome2_storage_create (GkmGnome2Storage *self, GkmTransaction *transaction,
 
 	g_free (identifier);
 	g_free (path);
-	g_free (data);
+	egg_bytes_unref (data);
 }
 
 void
diff --git a/pkcs11/gnome2-store/tests/check-gnome2-module.c b/pkcs11/gnome2-store/tests/check-gnome2-module.c
index 5385778..d5f4600 100644
--- a/pkcs11/gnome2-store/tests/check-gnome2-module.c
+++ b/pkcs11/gnome2-store/tests/check-gnome2-module.c
@@ -34,7 +34,7 @@
 
 static int failures = 0;
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 on_p11_tests_log (int level, const char *section, const char *message)
diff --git a/pkcs11/gnome2-store/tests/frob-gnome2-file.c b/pkcs11/gnome2-store/tests/frob-gnome2-file.c
index e3515ef..4667a90 100644
--- a/pkcs11/gnome2-store/tests/frob-gnome2-file.c
+++ b/pkcs11/gnome2-store/tests/frob-gnome2-file.c
@@ -39,7 +39,7 @@
 #include <string.h>
 #include <unistd.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void G_GNUC_NORETURN
 failure (const gchar* message, ...)
diff --git a/pkcs11/gnome2-store/tests/mock-gnome2-module.c b/pkcs11/gnome2-store/tests/mock-gnome2-module.c
index f652fd0..2441af2 100644
--- a/pkcs11/gnome2-store/tests/mock-gnome2-module.c
+++ b/pkcs11/gnome2-store/tests/mock-gnome2-module.c
@@ -31,7 +31,7 @@
 
 #include "gnome2-store/gkm-gnome2-store.h"
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static GMutex *mutex = NULL;
 
diff --git a/pkcs11/gnome2-store/tests/test-gnome2-file.c b/pkcs11/gnome2-store/tests/test-gnome2-file.c
index 7b9d9f8..3ab97a2 100644
--- a/pkcs11/gnome2-store/tests/test-gnome2-file.c
+++ b/pkcs11/gnome2-store/tests/test-gnome2-file.c
@@ -48,7 +48,7 @@ typedef struct {
 	GkmSecret *login;
 } Test;
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 setup (Test *test, gconstpointer unused)
diff --git a/pkcs11/gnome2-store/tests/test-gnome2-private-key.c b/pkcs11/gnome2-store/tests/test-gnome2-private-key.c
index f7ca8c7..10580cf 100644
--- a/pkcs11/gnome2-store/tests/test-gnome2-private-key.c
+++ b/pkcs11/gnome2-store/tests/test-gnome2-private-key.c
@@ -38,6 +38,7 @@
 #include "gkm/gkm-session.h"
 #include "gkm/gkm-test.h"
 
+#include "egg/egg-bytes.h"
 #include "egg/egg-testing.h"
 
 #include "pkcs11i.h"
@@ -45,8 +46,7 @@
 typedef struct {
 	GkmModule *module;
 	GkmSession *session;
-	gpointer key_data;
-	gsize n_key_data;
+	EggBytes *key_data;
 	GkmGnome2PrivateKey *key;
 } Test;
 
@@ -63,15 +63,14 @@ setup_basic (Test* test,
 	if (!g_file_get_contents (SRCDIR "/files/der-key-v2-des3.p8", &data, &length, NULL))
 		g_assert_not_reached ();
 
-	test->key_data = data;
-	test->n_key_data = length;
+	test->key_data = egg_bytes_new_take (data, length);
 }
 
 static void
 teardown_basic (Test* test,
                 gconstpointer unused)
 {
-	g_free (test->key_data);
+	egg_bytes_unref (test->key_data);
 	mock_gnome2_module_leave_and_finalize ();
 }
 
@@ -90,7 +89,7 @@ setup (Test *test,
 	                          NULL);
 
 	login = gkm_secret_new_from_password ("booo");
-	if (!gkm_serializable_load (GKM_SERIALIZABLE (test->key), login, test->key_data, test->n_key_data))
+	if (!gkm_serializable_load (GKM_SERIALIZABLE (test->key), login, test->key_data))
 		g_assert_not_reached ();
 	g_object_unref (login);
 }
@@ -117,11 +116,11 @@ test_load_private_key (Test *test,
 	                    NULL);
 
 	/* It's encrypted, this should fail */
-	if (gkm_serializable_load (GKM_SERIALIZABLE (key), NULL, test->key_data, test->n_key_data))
+	if (gkm_serializable_load (GKM_SERIALIZABLE (key), NULL, test->key_data))
 		g_assert_not_reached ();
 
 	login = gkm_secret_new_from_password ("booo");
-	if (!gkm_serializable_load (GKM_SERIALIZABLE (key), login, test->key_data, test->n_key_data))
+	if (!gkm_serializable_load (GKM_SERIALIZABLE (key), login, test->key_data))
 		g_assert_not_reached ();
 	g_object_unref (login);
 
@@ -133,25 +132,22 @@ test_save_private_key (Test *test,
                        gconstpointer unused)
 {
 	GkmSecret *login;
-	gpointer data;
-	gsize n_data;
+	EggBytes *data;
 	gcry_sexp_t sexp;
 
 	/* Save unencrypted */
-	if (!gkm_serializable_save (GKM_SERIALIZABLE (test->key), NULL, &data, &n_data))
-		g_assert_not_reached ();
+	data = gkm_serializable_save (GKM_SERIALIZABLE (test->key), NULL);
 	g_assert (data != NULL);
-	g_assert (gkm_data_der_read_private_pkcs8_plain (data, n_data, &sexp) == GKM_DATA_SUCCESS);
-	g_free (data);
+	g_assert (gkm_data_der_read_private_pkcs8_plain (data, &sexp) == GKM_DATA_SUCCESS);
+	egg_bytes_unref (data);
 	gcry_sexp_release (sexp);
 
 	/* Save encrypted */
 	login = gkm_secret_new_from_password ("booo");
-	if (!gkm_serializable_save (GKM_SERIALIZABLE (test->key), login, &data, &n_data))
-		g_assert_not_reached ();
+	data = gkm_serializable_save (GKM_SERIALIZABLE (test->key), login);
 	g_assert (data != NULL);
-	g_assert (gkm_data_der_read_private_pkcs8_crypted (data, n_data, "booo", 4, &sexp) == GKM_DATA_SUCCESS);
-	g_free (data);
+	g_assert (gkm_data_der_read_private_pkcs8_crypted (data, "booo", 4, &sexp) == GKM_DATA_SUCCESS);
+	egg_bytes_unref (data);
 	gcry_sexp_release (sexp);
 	g_object_unref (login);
 }
diff --git a/pkcs11/gnome2-store/tests/test-gnome2-storage.c b/pkcs11/gnome2-store/tests/test-gnome2-storage.c
index ac489c8..862547a 100644
--- a/pkcs11/gnome2-store/tests/test-gnome2-storage.c
+++ b/pkcs11/gnome2-store/tests/test-gnome2-storage.c
@@ -98,6 +98,7 @@ setup_module (Test *test,
 	CK_ATTRIBUTE url = { CKA_URL, NULL, 0 };
 	gchar *contents;
 	gsize length;
+	EggBytes *bytes;
 	GkmManager *manager;
 	GError *error = NULL;
 	GkmSession *session;
@@ -129,9 +130,12 @@ setup_module (Test *test,
 	                                 NULL);
 	g_file_get_contents (SRCDIR "/files/test-certificate.cer", &contents, &length, &error);
 	g_assert_no_error (error);
-	if (!gkm_serializable_load (GKM_SERIALIZABLE (test->new_object), NULL, contents, length))
+
+	bytes = egg_bytes_new_take (contents, length);
+	if (!gkm_serializable_load (GKM_SERIALIZABLE (test->new_object), NULL, bytes))
 		g_assert_not_reached ();
-	g_free (contents);
+	egg_bytes_unref (bytes);
+
 	/* We happen to know this certificate will get named */
 	test->new_filename = g_build_filename (test->directory, "CA_Cert_Signing_Authority.cer", NULL);
 
diff --git a/pkcs11/roots-store/gkm-roots-module.c b/pkcs11/roots-store/gkm-roots-module.c
index a36c15b..253b801 100644
--- a/pkcs11/roots-store/gkm-roots-module.c
+++ b/pkcs11/roots-store/gkm-roots-module.c
@@ -93,8 +93,9 @@ GKM_DEFINE_MODULE (gkm_roots_module, GKM_TYPE_ROOTS_MODULE);
  */
 
 static GkmCertificate*
-add_certificate_for_data (GkmRootsModule *self, const guchar *data,
-                          gsize n_data, const gchar *path)
+add_certificate_for_data (GkmRootsModule *self,
+                          EggBytes *data,
+                          const gchar *path)
 {
 	GkmCertificate *cert;
 	GkmManager *manager;
@@ -108,7 +109,9 @@ add_certificate_for_data (GkmRootsModule *self, const guchar *data,
 	g_return_val_if_fail (manager, NULL);
 
 	/* Hash the certificate */
-	hash = g_compute_checksum_for_data (G_CHECKSUM_MD5, data, n_data);
+	hash = g_compute_checksum_for_data (G_CHECKSUM_MD5,
+	                                    egg_bytes_get_data (data),
+	                                    egg_bytes_get_size (data));
 	unique = g_strdup_printf ("%s:%s", path, hash);
 	g_free (hash);
 
@@ -123,7 +126,7 @@ add_certificate_for_data (GkmRootsModule *self, const guchar *data,
 	cert = GKM_CERTIFICATE (gkm_roots_certificate_new (GKM_MODULE (self), unique, path));
 	g_free (unique);
 
-	if (!gkm_serializable_load (GKM_SERIALIZABLE (cert), NULL, data, n_data)) {
+	if (!gkm_serializable_load (GKM_SERIALIZABLE (cert), NULL, data)) {
 		g_message ("couldn't parse certificate(s): %s", path);
 		g_object_unref (cert);
 		return NULL;
@@ -139,10 +142,8 @@ add_certificate_for_data (GkmRootsModule *self, const guchar *data,
 
 static void
 parsed_pem_block (GQuark type,
-                  const guchar *data,
-                  gsize n_data,
-                  const gchar *outer,
-                  gsize n_outer,
+                  EggBytes *data,
+                  EggBytes *outer,
                   GHashTable *headers,
                   gpointer user_data)
 {
@@ -161,7 +162,7 @@ parsed_pem_block (GQuark type,
 	}
 
 	if (type == PEM_CERTIFICATE) {
-		cert = add_certificate_for_data (ctx->module, data, n_data, ctx->path);
+		cert = add_certificate_for_data (ctx->module, data, ctx->path);
 		if (cert != NULL) {
 			g_hash_table_remove (ctx->checks, cert);
 			++ctx->count;
@@ -184,6 +185,7 @@ file_load (GkmFileTracker *tracker, const gchar *path, GkmRootsModule *self)
 	ParsePrivate ctx;
 	GkmManager *manager;
 	GkmCertificate *cert;
+	EggBytes *bytes;
 	guchar *data;
 	GList *objects, *l;
 	GError *error = NULL;
@@ -211,12 +213,14 @@ file_load (GkmFileTracker *tracker, const gchar *path, GkmRootsModule *self)
 		g_hash_table_insert (ctx.checks, l->data, l->data);
 	g_list_free (objects);
 
+	bytes = egg_bytes_new_take (data, n_data);
+
 	/* Try and parse the PEM */
-	egg_armor_parse (data, n_data, parsed_pem_block, &ctx);
+	egg_armor_parse (bytes, parsed_pem_block, &ctx);
 
 	/* If no PEM data, try to parse directly as DER  */
 	if (ctx.count == 0) {
-		cert = add_certificate_for_data (self, data, n_data, path);
+		cert = add_certificate_for_data (self, bytes, path);
 		if (cert != NULL)
 			g_hash_table_remove (ctx.checks, cert);
 	}
@@ -224,7 +228,7 @@ file_load (GkmFileTracker *tracker, const gchar *path, GkmRootsModule *self)
 	g_hash_table_foreach (ctx.checks, remove_each_certificate, self);
 	g_hash_table_destroy (ctx.checks);
 
-	g_free (data);
+	egg_bytes_unref (data);
 }
 
 static void
diff --git a/pkcs11/roots-store/gkm-roots-standalone.c b/pkcs11/roots-store/gkm-roots-standalone.c
index fb0f642..bceb232 100644
--- a/pkcs11/roots-store/gkm-roots-standalone.c
+++ b/pkcs11/roots-store/gkm-roots-standalone.c
@@ -35,7 +35,7 @@
 #include "pkcs11/pkcs11.h"
 
 /* Module callbacks for secure memory */
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 const gchar* g_module_check_init (GModule *module);
 
diff --git a/pkcs11/roots-store/gkm-roots-trust.c b/pkcs11/roots-store/gkm-roots-trust.c
index 93da42b..3810cdb 100644
--- a/pkcs11/roots-store/gkm-roots-trust.c
+++ b/pkcs11/roots-store/gkm-roots-trust.c
@@ -126,20 +126,18 @@ full_certificate (GkmRootsTrust *self, CK_ATTRIBUTE_PTR result)
 static GQuark*
 lookup_extended_usages (GkmRootsTrust *self)
 {
-	gconstpointer extension;
-	gsize n_extension;
+	EggBytes *extension;
 	GQuark *usages = NULL;
 	GkmDataResult res;
 
 	extension = gkm_certificate_get_extension (self->pv->certificate,
-	                                           OID_ENHANCED_USAGE,
-	                                           &n_extension, NULL);
+	                                           OID_ENHANCED_USAGE, NULL);
 
 	if (!extension)
 		return NULL;
 
 	/* Returns null terminated set of OID quarks */
-	res = gkm_data_der_read_enhanced_usage (extension, n_extension, &usages);
+	res = gkm_data_der_read_enhanced_usage (extension, &usages);
 
 	/* Failure: An empty set means nothing is trusted */
 	if (res != GKM_DATA_SUCCESS) {
@@ -147,6 +145,7 @@ lookup_extended_usages (GkmRootsTrust *self)
 		usages = g_new0 (GQuark, 1);
 	}
 
+	egg_bytes_unref (extension);
 	return usages;
 }
 
diff --git a/pkcs11/roots-store/tests/check-roots-module.c b/pkcs11/roots-store/tests/check-roots-module.c
index 1bc9e16..c73a188 100644
--- a/pkcs11/roots-store/tests/check-roots-module.c
+++ b/pkcs11/roots-store/tests/check-roots-module.c
@@ -34,7 +34,7 @@
 
 static int failures = 0;
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS();
 
 static void
 on_p11_tests_log (int level, const char *section, const char *message)
diff --git a/pkcs11/secret-store/gkm-secret-standalone.c b/pkcs11/secret-store/gkm-secret-standalone.c
index 70924b9..cfc3956 100644
--- a/pkcs11/secret-store/gkm-secret-standalone.c
+++ b/pkcs11/secret-store/gkm-secret-standalone.c
@@ -35,7 +35,7 @@
 #include "pkcs11/pkcs11.h"
 
 /* Module callbacks for secure memory */
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 const gchar* g_module_check_init (GModule *module);
 
diff --git a/pkcs11/secret-store/tests/dump-keyring0-format.c b/pkcs11/secret-store/tests/dump-keyring0-format.c
index 9b42d9f..0da05ed 100644
--- a/pkcs11/secret-store/tests/dump-keyring0-format.c
+++ b/pkcs11/secret-store/tests/dump-keyring0-format.c
@@ -55,7 +55,7 @@ enum {
 	ACCESS_REMOVE = 1 << 2
 };
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 #define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n"
 #define KEYRING_FILE_HEADER_LEN 16
diff --git a/pkcs11/secret-store/tests/mock-secret-module.c b/pkcs11/secret-store/tests/mock-secret-module.c
index 6cb698c..7022e69 100644
--- a/pkcs11/secret-store/tests/mock-secret-module.c
+++ b/pkcs11/secret-store/tests/mock-secret-module.c
@@ -42,7 +42,7 @@
 
 #include <string.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static GMutex *mutex = NULL;
 static gchar *directory = NULL;
diff --git a/pkcs11/secret-store/tests/test-secret-data.c b/pkcs11/secret-store/tests/test-secret-data.c
index a71e301..c1bf54b 100644
--- a/pkcs11/secret-store/tests/test-secret-data.c
+++ b/pkcs11/secret-store/tests/test-secret-data.c
@@ -36,7 +36,7 @@
 #include <stdio.h>
 #include <string.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 test_new (void)
diff --git a/pkcs11/ssh-store/gkm-ssh-openssh.c b/pkcs11/ssh-store/gkm-ssh-openssh.c
index 5003471..831e555 100644
--- a/pkcs11/ssh-store/gkm-ssh-openssh.c
+++ b/pkcs11/ssh-store/gkm-ssh-openssh.c
@@ -155,31 +155,34 @@ read_public (EggBuffer *req, gsize *offset, gcry_sexp_t *key, int *algo)
 }
 
 static GkmDataResult
-load_encrypted_key (const guchar *data, gsize n_data, const gchar *dekinfo,
-                    const gchar *password, gssize n_password, gcry_sexp_t *skey)
+load_encrypted_key (EggBytes *data,
+                    const gchar *dekinfo,
+                    const gchar *password,
+                    gssize n_password,
+                    gcry_sexp_t *skey)
 {
 	guchar *decrypted = NULL;
 	gsize n_decrypted = 0;
+	EggBytes *bytes;
 	GkmDataResult ret;
-	gboolean res;
 	gint length;
 
 	/* Decrypt, this will result in garble if invalid password */
-	res = egg_openssl_decrypt_block (dekinfo, password, n_password,
-	                                      data, n_data, &decrypted, &n_decrypted);
-	if (!res)
+	decrypted = egg_openssl_decrypt_block (dekinfo, password, n_password,
+	                                       data, &n_decrypted);
+	if (!decrypted)
 		return FALSE;
 
-	g_assert (decrypted);
-
 	/* Unpad the DER data */
 	length = egg_asn1x_element_length (decrypted, n_decrypted);
 	if (length > 0)
 		n_decrypted = length;
 
+	bytes = egg_bytes_new_with_free_func (decrypted, n_decrypted, egg_secure_free, decrypted);
+
 	/* Try to parse */
-	ret = gkm_data_der_read_private_key (decrypted, n_decrypted, skey);
-	egg_secure_free (decrypted);
+	ret = gkm_data_der_read_private_key (bytes, skey);
+	egg_bytes_unref (bytes);
 
 	if (ret != GKM_DATA_UNRECOGNIZED)
 		return ret;
@@ -207,10 +210,8 @@ is_private_key_type (GQuark type)
 
 static void
 parsed_pem_block (GQuark type,
-                  const guchar *data,
-                  gsize n_data,
-                  const gchar *outer,
-                  gsize n_outer,
+                  EggBytes *data,
+                  EggBytes *outer,
                   GHashTable *headers,
                   gpointer user_data)
 {
@@ -229,21 +230,19 @@ parsed_pem_block (GQuark type,
 	/* If it's encrypted ... */
 	dekinfo = egg_openssl_get_dekinfo (headers);
 	if (dekinfo) {
-		ctx->result = load_encrypted_key (data, n_data, dekinfo, ctx->password,
+		ctx->result = load_encrypted_key (data, dekinfo, ctx->password,
 		                                  ctx->n_password, &ctx->sexp);
 
 	/* not encryted, just load the data */
 	} else {
-		ctx->result = gkm_data_der_read_private_key (data, n_data, &ctx->sexp);
+		ctx->result = gkm_data_der_read_private_key (data, &ctx->sexp);
 	}
 }
 
 static void
 digest_pem_block (GQuark type,
-                  const guchar *data,
-                  gsize n_data,
-                  const gchar *outer,
-                  gsize n_outer,
+                  EggBytes *data,
+                  EggBytes *outer,
                   GHashTable *headers,
                   gpointer user_data)
 {
@@ -258,7 +257,9 @@ digest_pem_block (GQuark type,
 	if (*result != NULL)
 		return;
 
-	*result = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, n_data);
+	*result = g_compute_checksum_for_data (G_CHECKSUM_SHA1,
+	                                       egg_bytes_get_data (data),
+	                                       egg_bytes_get_size (data));
 }
 
 /* ------------------------------------------------------------------------------
@@ -372,8 +373,9 @@ gkm_ssh_openssh_parse_public_key (gconstpointer input, gsize n_data,
 }
 
 GkmDataResult
-gkm_ssh_openssh_parse_private_key (gconstpointer data, gsize n_data,
-                                   const gchar *password, gssize n_password,
+gkm_ssh_openssh_parse_private_key (EggBytes *data,
+                                   const gchar *password,
+                                   gssize n_password,
                                    gcry_sexp_t *sexp)
 {
 	ParsePrivate ctx;
@@ -386,7 +388,7 @@ gkm_ssh_openssh_parse_private_key (gconstpointer data, gsize n_data,
 	ctx.password = password;
 	ctx.n_password = n_password;
 
-	num = egg_armor_parse (data, n_data, parsed_pem_block, &ctx);
+	num = egg_armor_parse (data, parsed_pem_block, &ctx);
 
 	/* Didn't find any private key there */
 	if (num == 0 || !ctx.seen) {
@@ -398,10 +400,10 @@ gkm_ssh_openssh_parse_private_key (gconstpointer data, gsize n_data,
 	return ctx.result;
 }
 
-gchar*
-gkm_ssh_openssh_digest_private_key (const guchar *data, gsize n_data)
+gchar *
+gkm_ssh_openssh_digest_private_key (EggBytes *data)
 {
 	gchar *result = NULL;
-	egg_armor_parse (data, n_data, digest_pem_block, &result);
+	egg_armor_parse (data, digest_pem_block, &result);
 	return result;
 }
diff --git a/pkcs11/ssh-store/gkm-ssh-openssh.h b/pkcs11/ssh-store/gkm-ssh-openssh.h
index fe8db8e..62cdd2e 100644
--- a/pkcs11/ssh-store/gkm-ssh-openssh.h
+++ b/pkcs11/ssh-store/gkm-ssh-openssh.h
@@ -7,18 +7,18 @@
 
 #include "gkm/gkm-data-types.h"
 
+#include <egg/egg-bytes.h>
+
 GkmDataResult         gkm_ssh_openssh_parse_public_key                   (gconstpointer data,
                                                                           gsize n_data,
                                                                           gcry_sexp_t *sexp,
                                                                           gchar **comment);
 
-GkmDataResult         gkm_ssh_openssh_parse_private_key                  (gconstpointer data,
-                                                                          gsize n_data,
+GkmDataResult         gkm_ssh_openssh_parse_private_key                  (EggBytes *data,
                                                                           const gchar *password,
                                                                           gssize n_password,
                                                                           gcry_sexp_t *sexp);
 
-gchar*                gkm_ssh_openssh_digest_private_key                 (const guchar *data,
-                                                                          gsize n_data);
+gchar*                gkm_ssh_openssh_digest_private_key                 (EggBytes *data);
 
 #endif /* GKM_SSHOPENSSH_H_ */
diff --git a/pkcs11/ssh-store/gkm-ssh-private-key.c b/pkcs11/ssh-store/gkm-ssh-private-key.c
index b633a56..4141078 100644
--- a/pkcs11/ssh-store/gkm-ssh-private-key.c
+++ b/pkcs11/ssh-store/gkm-ssh-private-key.c
@@ -46,9 +46,8 @@ struct _GkmSshPrivateKey {
 	GkmPrivateXsaKey parent;
 
 	GkmSshPublicKey *pubkey;
+	EggBytes *private_bytes;
 	gchar *label;
-	guchar *private_data;
-	gsize n_private_data;
 
 	gboolean is_encrypted;
 };
@@ -69,8 +68,7 @@ unlock_private_key (GkmSshPrivateKey *self, const gchar *password,
 
 	g_assert (GKM_IS_SSH_PRIVATE_KEY (self));
 
-	res = gkm_ssh_openssh_parse_private_key (self->private_data,
-	                                         self->n_private_data,
+	res = gkm_ssh_openssh_parse_private_key (self->private_bytes,
 	                                         password, n_password, &sexp);
 
 	switch (res) {
@@ -99,8 +97,10 @@ unlock_private_key (GkmSshPrivateKey *self, const gchar *password,
 }
 
 static void
-realize_and_take_data (GkmSshPrivateKey *self, gcry_sexp_t sexp, gchar *comment,
-                       guchar *private_data, gsize n_private_data)
+realize_and_take_data (GkmSshPrivateKey *self,
+                       gcry_sexp_t sexp,
+                       gchar *comment,
+                       EggBytes *private_data)
 {
 	GkmSexp *wrapper;
 
@@ -118,9 +118,9 @@ realize_and_take_data (GkmSshPrivateKey *self, gcry_sexp_t sexp, gchar *comment,
 	g_free (comment);
 
 	/* Own the data */
-	g_free (self->private_data);
-	self->private_data = private_data;
-	self->n_private_data = n_private_data;
+	if (self->private_bytes)
+		egg_bytes_unref (self->private_bytes);
+	self->private_bytes = private_data;
 
 	/* Try to parse the private data, and note if it's not actually encrypted */
 	self->is_encrypted = TRUE;
@@ -148,9 +148,9 @@ gkm_ssh_private_key_get_attribute (GkmObject *base, GkmSession *session, CK_ATTR
 
 	/* COMPAT: Previous versions of gnome-keyring used this to save unlock passwords */
 	case CKA_GNOME_INTERNAL_SHA1:
-		if (!self->private_data)
+		if (!self->private_bytes)
 			return CKR_ATTRIBUTE_TYPE_INVALID;
-		digest = gkm_ssh_openssh_digest_private_key (self->private_data, self->n_private_data);
+		digest = gkm_ssh_openssh_digest_private_key (self->private_bytes);
 		rv = gkm_attribute_set_string (attr, digest);
 		g_free (digest);
 		return rv;
@@ -231,11 +231,9 @@ gkm_ssh_private_key_finalize (GObject *obj)
 
 	g_assert (self->pubkey == NULL);
 
-	g_free (self->private_data);
-	self->private_data = NULL;
-
+	if (self->private_bytes)
+		egg_bytes_unref (self->private_bytes);
 	g_free (self->label);
-	self->label = NULL;
 
 	G_OBJECT_CLASS (gkm_ssh_private_key_parent_class)->finalize (obj);
 }
@@ -350,7 +348,7 @@ gkm_ssh_private_key_parse (GkmSshPrivateKey *self, const gchar *public_path,
 	if (comment == NULL)
 		comment = g_path_get_basename (private_path);
 
-	realize_and_take_data (self, sexp, comment, private_data, n_private_data);
+	realize_and_take_data (self, sexp, comment, egg_bytes_new_take (private_data, n_private_data));
 	return TRUE;
 }
 
diff --git a/pkcs11/ssh-store/gkm-ssh-standalone.c b/pkcs11/ssh-store/gkm-ssh-standalone.c
index 0d7c10d..3b53f48 100644
--- a/pkcs11/ssh-store/gkm-ssh-standalone.c
+++ b/pkcs11/ssh-store/gkm-ssh-standalone.c
@@ -35,7 +35,7 @@
 #include <gmodule.h>
 
 /* Module callbacks for secure memory */
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 const gchar* g_module_check_init (GModule *module);
 
diff --git a/pkcs11/ssh-store/tests/check-ssh-module.c b/pkcs11/ssh-store/tests/check-ssh-module.c
index eeeb2de..a52dd2e 100644
--- a/pkcs11/ssh-store/tests/check-ssh-module.c
+++ b/pkcs11/ssh-store/tests/check-ssh-module.c
@@ -34,7 +34,7 @@
 
 static int failures = 0;
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 on_p11_tests_log (int level, const char *section, const char *message)
diff --git a/pkcs11/ssh-store/tests/mock-ssh-module.c b/pkcs11/ssh-store/tests/mock-ssh-module.c
index 2cec728..aad0bc3 100644
--- a/pkcs11/ssh-store/tests/mock-ssh-module.c
+++ b/pkcs11/ssh-store/tests/mock-ssh-module.c
@@ -31,7 +31,7 @@
 
 #include "ssh-store/gkm-ssh-store.h"
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static GMutex *mutex = NULL;
 
diff --git a/pkcs11/ssh-store/tests/test-ssh-openssh.c b/pkcs11/ssh-store/tests/test-ssh-openssh.c
index 12fc0cc..2cc8136 100644
--- a/pkcs11/ssh-store/tests/test-ssh-openssh.c
+++ b/pkcs11/ssh-store/tests/test-ssh-openssh.c
@@ -34,7 +34,7 @@
 #include <stdio.h>
 #include <string.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static const gchar *PRIVATE_FILES[] = {
 	SRCDIR "/files/id_rsa_encrypted",
@@ -95,6 +95,7 @@ test_parse_private (void)
 	gsize n_data;
 	int algorithm;
 	gboolean is_private;
+	EggBytes *bytes;
 	guint i;
 	GkmDataResult res;
 
@@ -104,7 +105,10 @@ test_parse_private (void)
 		if (!g_file_get_contents (PRIVATE_FILES[i], &data, &n_data, NULL))
 			g_assert_not_reached ();
 
-		res = gkm_ssh_openssh_parse_private_key (data, n_data, "password", 8, &sexp);
+		bytes = egg_bytes_new_take (data, n_data);
+		res = gkm_ssh_openssh_parse_private_key (bytes, "password", 8, &sexp);
+		egg_bytes_unref (bytes);
+
 		if (res != GKM_DATA_SUCCESS) {
 			g_warning ("couldn't parse private key: %s", PRIVATE_FILES[i]);
 			g_assert_cmpint (res, ==, GKM_DATA_SUCCESS);
@@ -116,7 +120,6 @@ test_parse_private (void)
 		g_assert_cmpint (algorithm, !=, 0);
 		g_assert (is_private);
 
-		g_free (data);
 		gcry_sexp_release (sexp);
 	}
 }
diff --git a/pkcs11/wrap-layer/tests/mock-secret-store.c b/pkcs11/wrap-layer/tests/mock-secret-store.c
index 7e8e08e..5f6a9b5 100644
--- a/pkcs11/wrap-layer/tests/mock-secret-store.c
+++ b/pkcs11/wrap-layer/tests/mock-secret-store.c
@@ -31,7 +31,7 @@
 
 static guint secret_identifier = 8800;
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static CK_RV
 mock_secret_C_Initialize (CK_VOID_PTR pInitArgs)
diff --git a/pkcs11/xdg-store/Makefile.am b/pkcs11/xdg-store/Makefile.am
index 569ae65..bbe0e56 100644
--- a/pkcs11/xdg-store/Makefile.am
+++ b/pkcs11/xdg-store/Makefile.am
@@ -1,3 +1,12 @@
+include $(top_srcdir)/Makefile.decl
+
+ASN_FILES = \
+	xdg.asn
+
+ASN_SRCS = $(ASN_FILES:.asn=.asn.h)
+
+BUILT_SOURCES = \
+	$(ASN_SRCS)
 
 INCLUDES = \
 	-I$(top_builddir) \
@@ -14,21 +23,16 @@ INCLUDES = \
 noinst_LTLIBRARIES = \
 	libgkm-xdg-store.la
 
-BUILT_SOURCES = \
-	asn1-def-xdg.c
-
 libgkm_xdg_store_la_SOURCES = \
 	gkm-xdg-store.h \
+	gkm-xdg-asn1-defs.c gkm-xdg-asn1-defs.h \
 	gkm-xdg-assertion.c gkm-xdg-assertion.h \
 	gkm-xdg-module.c gkm-xdg-module.h \
 	gkm-xdg-trust.c gkm-xdg-trust.h \
 	$(BUILT_SOURCES)
 
-asn1-def-xdg.c: xdg.asn
-	$(ASN1PARSER) -o asn1-def-xdg.c $(srcdir)/xdg.asn
-
 EXTRA_DIST = \
-	xdg.asn
+	$(ASN_FILES)
 
 # ------------------------------------------------------------------------------
 # The standalone module
diff --git a/pkcs11/xdg-store/gkm-xdg-asn1-defs.c b/pkcs11/xdg-store/gkm-xdg-asn1-defs.c
new file mode 100644
index 0000000..403f620
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-asn1-defs.c
@@ -0,0 +1,32 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-asn1-defs.c - ASN.1 definitions
+
+   Copyright (C) 2011 Collabora Ltd.
+
+   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 <stefw collabora co uk>
+*/
+
+#include "config.h"
+
+#include "gkm-xdg-asn1-defs.h"
+
+#include <stdlib.h>
+
+typedef struct _EggAsn1xDef ASN1_ARRAY_TYPE;
+
+#include "xdg.asn.h"
diff --git a/pkcs11/xdg-store/gkm-xdg-asn1-defs.h b/pkcs11/xdg-store/gkm-xdg-asn1-defs.h
new file mode 100644
index 0000000..9eebd08
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-asn1-defs.h
@@ -0,0 +1,31 @@
+/* -*- 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 GKM_XDG_ASN1_DEFS_H_
+#define GKM_XDG_ASN1_DEFS_H_
+
+#include "egg/egg-asn1-defs.h"
+
+extern const struct _EggAsn1xDef xdg_asn1_tab[];
+
+#endif /* GKM_XDG_ASN1_DEFS_H_ */
diff --git a/pkcs11/xdg-store/gkm-xdg-module.c b/pkcs11/xdg-store/gkm-xdg-module.c
index 708d4ee..fd3da09 100644
--- a/pkcs11/xdg-store/gkm-xdg-module.c
+++ b/pkcs11/xdg-store/gkm-xdg-module.c
@@ -203,6 +203,7 @@ file_load (GkmFileTracker *tracker, const gchar *path, GkmXdgModule *self)
 	GkmManager *manager;
 	gboolean added = FALSE;
 	GError *error = NULL;
+	EggBytes *bytes;
 	GType type;
 	guchar *data;
 	gsize n_data;
@@ -243,9 +244,12 @@ file_load (GkmFileTracker *tracker, const gchar *path, GkmXdgModule *self)
 		g_object_unref (object);
 		g_clear_error (&error);
 		return;
+	}
+
+	bytes = egg_bytes_new_take (data, n_data);
 
 	/* And load the data into it */
-	} else if (gkm_serializable_load (GKM_SERIALIZABLE (object), NULL, data, n_data)) {
+	if (gkm_serializable_load (GKM_SERIALIZABLE (object), NULL, bytes)) {
 		if (added)
 			add_object_to_module (self, object, path, NULL);
 		gkm_object_expose (object, TRUE);
@@ -258,6 +262,7 @@ file_load (GkmFileTracker *tracker, const gchar *path, GkmXdgModule *self)
 		}
 	}
 
+	egg_bytes_unref (bytes);
 	g_object_unref (object);
 }
 
@@ -275,16 +280,19 @@ file_remove (GkmFileTracker *tracker, const gchar *path, GkmXdgModule *self)
 }
 
 static gchar*
-name_for_subject (gconstpointer subject, gsize n_subject)
+name_for_subject (gconstpointer data,
+                  gsize n_data)
 {
+	EggBytes *subject;
 	GNode *asn;
 	gchar *name;
 
-	g_assert (subject);
-	g_assert (n_subject);
+	g_assert (data != NULL);
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Name", subject, n_subject);
-	g_return_val_if_fail (asn, NULL);
+	subject = egg_bytes_new (data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Name", subject);
+	g_return_val_if_fail (asn != NULL, NULL);
+	egg_bytes_unref (subject);
 
 	name = egg_dn_read_part (egg_asn1x_node (asn, "rdnSequence", NULL), "CN");
 	egg_asn1x_destroy (asn);
@@ -430,10 +438,9 @@ gkm_xdg_module_real_store_token_object (GkmModule *module, GkmTransaction *trans
                                         GkmObject *object)
 {
 	GkmXdgModule *self = GKM_XDG_MODULE (module);
-	GkmTrust *trust;
 	const gchar *filename;
-	gpointer data;
-	gsize n_data;
+	EggBytes *bytes;
+	GkmTrust *trust;
 
 	/* Always serialize the trust object for each assertion */
 	if (GKM_XDG_IS_ASSERTION (object)) {
@@ -449,7 +456,9 @@ gkm_xdg_module_real_store_token_object (GkmModule *module, GkmTransaction *trans
 	}
 
 	/* Serialize the object in question */
-	if (!gkm_serializable_save (GKM_SERIALIZABLE (object), NULL, &data, &n_data)) {
+	bytes = gkm_serializable_save (GKM_SERIALIZABLE (object), NULL);
+
+	if (bytes == NULL) {
 		gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
 		g_return_if_reached ();
 	}
@@ -458,8 +467,10 @@ gkm_xdg_module_real_store_token_object (GkmModule *module, GkmTransaction *trans
 	g_return_if_fail (filename != NULL);
 	g_return_if_fail (g_hash_table_lookup (self->objects_by_path, filename) == object);
 
-	gkm_transaction_write_file (transaction, filename, data, n_data);
-	g_free (data);
+	gkm_transaction_write_file (transaction, filename,
+	                            egg_bytes_get_data (bytes),
+	                            egg_bytes_get_size (bytes));
+	egg_bytes_unref (bytes);
 }
 
 static void
diff --git a/pkcs11/xdg-store/gkm-xdg-standalone.c b/pkcs11/xdg-store/gkm-xdg-standalone.c
index dd1d328..8dbfa13 100644
--- a/pkcs11/xdg-store/gkm-xdg-standalone.c
+++ b/pkcs11/xdg-store/gkm-xdg-standalone.c
@@ -35,7 +35,7 @@
 #include <gmodule.h>
 
 /* Module callbacks for secure memory */
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 const gchar* g_module_check_init (GModule *module);
 
diff --git a/pkcs11/xdg-store/gkm-xdg-trust.c b/pkcs11/xdg-store/gkm-xdg-trust.c
index f9a4f59..75f66d4 100644
--- a/pkcs11/xdg-store/gkm-xdg-trust.c
+++ b/pkcs11/xdg-store/gkm-xdg-trust.c
@@ -26,7 +26,6 @@
 
 #include "egg/egg-asn1x.h"
 #include "egg/egg-asn1-defs.h"
-#include "egg/egg-byte-array.h"
 
 #include "gkm/gkm-assertion.h"
 #include "gkm/gkm-attributes.h"
@@ -45,16 +44,14 @@
 
 #include <glib/gi18n.h>
 
+extern const struct _EggAsn1xDef xdg_asn1_tab[];
+
 struct _GkmXdgTrustPrivate {
 	GHashTable *assertions;
 	GNode *asn;
-	gpointer data;
-	gsize n_data;
+	EggBytes *bytes;
 };
 
-/* From asn1-def-xdg.c */
-extern const ASN1_ARRAY_TYPE xdg_asn1_tab[];
-
 static void gkm_xdg_trust_serializable (GkmSerializableIface *iface);
 
 G_DEFINE_TYPE_EXTENDED (GkmXdgTrust, gkm_xdg_trust, GKM_TYPE_TRUST, 0,
@@ -107,8 +104,8 @@ static CK_RV
 trust_get_der (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 {
 	GNode *node;
-	gconstpointer element;
-	gsize n_element;
+	EggBytes *element;
+	CK_RV rv;
 
 	g_assert (GKM_XDG_IS_TRUST (self));
 
@@ -119,16 +116,18 @@ trust_get_der (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 	if (!egg_asn1x_have (node))
 		return CKR_ATTRIBUTE_TYPE_INVALID;
 
-	element = egg_asn1x_get_raw_element (node, &n_element);
-	return gkm_attribute_set_data (attr, element, n_element);
+	element = egg_asn1x_get_element_raw (node);
+	rv = gkm_attribute_set_bytes (attr, element);
+	egg_bytes_unref (element);
+
+	return rv;
 }
 
 static CK_RV
 trust_get_integer (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 {
 	GNode *node;
-	gconstpointer integer;
-	gsize n_integer;
+	EggBytes *integer;
 	CK_RV rv;
 
 	g_assert (GKM_XDG_IS_TRUST (self));
@@ -140,10 +139,11 @@ trust_get_integer (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 	if (!egg_asn1x_have (node))
 		return CKR_ATTRIBUTE_TYPE_INVALID;
 
-	integer = egg_asn1x_get_integer_as_raw (node, &n_integer);
+	integer = egg_asn1x_get_integer_as_raw (node);
 	g_return_val_if_fail (integer, CKR_GENERAL_ERROR);
 
-	rv = gkm_attribute_set_data (attr, integer, n_integer);
+	rv = gkm_attribute_set_bytes (attr, integer);
+	egg_bytes_unref (integer);
 
 	return rv;
 }
@@ -152,8 +152,8 @@ static CK_RV
 trust_get_hash (GkmXdgTrust *self, GChecksumType ctype, CK_ATTRIBUTE_PTR attr)
 {
 	GNode *cert;
-	gconstpointer element;
-	gsize n_element;
+	EggBytes *element;
+	CK_RV rv;
 
 	cert = egg_asn1x_node (self->pv->asn, "reference", "certComplete", NULL);
 	g_return_val_if_fail (cert, CKR_GENERAL_ERROR);
@@ -162,18 +162,23 @@ trust_get_hash (GkmXdgTrust *self, GChecksumType ctype, CK_ATTRIBUTE_PTR attr)
 	if (!egg_asn1x_have (cert))
 		return CKR_ATTRIBUTE_TYPE_INVALID;
 
-	element = egg_asn1x_get_raw_element (cert, &n_element);
-	g_return_val_if_fail (element, CKR_GENERAL_ERROR);
+	element = egg_asn1x_get_element_raw (cert);
+	g_return_val_if_fail (element != NULL, CKR_GENERAL_ERROR);
+
+	rv = gkm_attribute_set_checksum (attr, ctype,
+	                                 egg_bytes_get_data (element),
+	                                 egg_bytes_get_size (element));
 
-	return gkm_attribute_set_checksum (attr, ctype, element, n_element);
+	egg_bytes_unref (element);
+	return rv;
 }
 
 static CK_RV
 trust_get_complete (GkmXdgTrust *self, CK_ATTRIBUTE_PTR attr)
 {
 	GNode *cert;
-	gconstpointer element;
-	gsize n_element;
+	EggBytes *element;
+	CK_RV rv;
 
 	cert = egg_asn1x_node (self->pv->asn, "reference", "certComplete", NULL);
 	g_return_val_if_fail (cert, CKR_GENERAL_ERROR);
@@ -182,10 +187,13 @@ trust_get_complete (GkmXdgTrust *self, CK_ATTRIBUTE_PTR attr)
 	if (!egg_asn1x_have (cert))
 		return CKR_ATTRIBUTE_TYPE_INVALID;
 
-	element = egg_asn1x_get_raw_element (cert, &n_element);
-	g_return_val_if_fail (element, CKR_GENERAL_ERROR);
+	element = egg_asn1x_get_element_raw (cert);
+	g_return_val_if_fail (element != NULL, CKR_GENERAL_ERROR);
+
+	rv = gkm_attribute_set_bytes (attr, element);
+	egg_bytes_unref (element);
 
-	return gkm_attribute_set_data (attr, element, n_element);
+	return rv;
 }
 
 
@@ -194,6 +202,7 @@ validate_der (CK_ATTRIBUTE_PTR attr, const gchar *asn_type)
 {
 	GNode *asn;
 	gboolean valid = TRUE;
+	EggBytes *data;
 
 	if (!attr->pValue || attr->ulValueLen == (CK_ULONG)-1)
 		return FALSE;
@@ -201,7 +210,10 @@ validate_der (CK_ATTRIBUTE_PTR attr, const gchar *asn_type)
 	asn = egg_asn1x_create (pkix_asn1_tab, asn_type);
 	g_return_val_if_fail (asn, FALSE);
 
-	valid = egg_asn1x_decode (asn, attr->pValue, attr->ulValueLen);
+	data = egg_bytes_new_static (attr->pValue, attr->ulValueLen);
+	valid = egg_asn1x_decode (asn, data);
+	egg_bytes_unref (data);
+
 	if (!valid)
 		g_message ("failed to parse certificate passed to trust assertion: %s",
 		           egg_asn1x_message (asn));
@@ -262,8 +274,8 @@ check_and_unref_assertion (gpointer data)
 static GHashTable*
 create_assertions (void)
 {
-	return g_hash_table_new_full (egg_byte_array_hash, egg_byte_array_equal,
-	                              (GDestroyNotify)g_byte_array_unref,
+	return g_hash_table_new_full (egg_bytes_hash, egg_bytes_equal,
+	                              (GDestroyNotify)egg_bytes_unref,
 	                              check_and_unref_assertion);
 }
 
@@ -311,41 +323,44 @@ create_assertion (GkmXdgTrust *self, GNode *asn)
 	return assertion;
 }
 
-static GByteArray*
-create_assertion_key (const gchar *purpose, const gchar *peer)
+static EggBytes *
+create_assertion_key (const gchar *purpose,
+                      const gchar *peer)
 {
-	GByteArray *key;
+	GString *string;
+	gsize len;
 
 	g_return_val_if_fail (purpose, NULL);
 
-	key = g_byte_array_new ();
-	g_byte_array_append (key, (void*)purpose, strlen (purpose));
+	string = g_string_sized_new (32);
+	g_string_append (string, purpose);
 
 	if (peer != NULL) {
-		g_byte_array_append (key, (void*)"\0", 1);
-		g_byte_array_append (key, (void*)peer, strlen (peer));
+		g_string_append_len (string, "\0", 1);
+		g_string_append (string, peer);
 	}
 
-	return key;
+	len = string->len;
+	return egg_bytes_new_take (g_string_free (string, FALSE), len);
 }
 
-static GByteArray*
+static EggBytes *
 lookup_assertion_key (GkmAssertion *assertion)
 {
 	return g_object_get_qdata (G_OBJECT (assertion), QDATA_ASSERTION_KEY);
 }
 
-static GByteArray*
+static EggBytes *
 lookup_or_create_assertion_key (GkmAssertion *assertion)
 {
-	GByteArray *key;
+	EggBytes *key;
 
 	key = lookup_assertion_key (assertion);
 	if (key == NULL) {
 		key = create_assertion_key (gkm_assertion_get_purpose (assertion),
 		                            gkm_assertion_get_peer (assertion));
 		g_object_set_qdata_full (G_OBJECT (assertion), QDATA_ASSERTION_KEY,
-		                         g_byte_array_ref (key), (GDestroyNotify)g_byte_array_unref);
+		                         egg_bytes_ref (key), (GDestroyNotify)egg_bytes_unref);
 	}
 
 	return key;
@@ -368,12 +383,12 @@ static void
 add_assertion_to_trust (GkmXdgTrust *self, GkmAssertion *assertion,
                         GkmTransaction *transaction)
 {
-	GByteArray *key;
+	EggBytes *key;
 
 	key = lookup_or_create_assertion_key (assertion);
-	g_assert (key);
+	g_assert (key != NULL);
 
-	g_hash_table_insert (self->pv->assertions, g_byte_array_ref (key), g_object_ref (assertion));
+	g_hash_table_insert (self->pv->assertions, egg_bytes_ref (key), g_object_ref (assertion));
 	gkm_object_expose (GKM_OBJECT (assertion), gkm_object_is_exposed (GKM_OBJECT (self)));
 
 	if (transaction != NULL)
@@ -399,10 +414,10 @@ static void
 remove_assertion_from_trust (GkmXdgTrust *self, GkmAssertion *assertion,
                              GkmTransaction *transaction)
 {
-	GByteArray *key;
+	EggBytes *key;
 
 	key = lookup_assertion_key (assertion);
-	g_assert (key);
+	g_assert (key != NULL);
 
 	gkm_object_expose (GKM_OBJECT (assertion), FALSE);
 
@@ -419,11 +434,9 @@ remove_assertion_from_trust (GkmXdgTrust *self, GkmAssertion *assertion,
 static gboolean
 load_assertions (GkmXdgTrust *self, GNode *asn)
 {
-	gconstpointer element;
 	GHashTable *assertions;
 	GkmAssertion *assertion;
-	gsize n_element;
-	GByteArray *key;
+	EggBytes *key;
 	GNode *node;
 	guint count, i;
 
@@ -437,15 +450,11 @@ load_assertions (GkmXdgTrust *self, GNode *asn)
 
 	for (i = 0; i < count; ++i) {
 		node = egg_asn1x_node (asn, "assertions", i + 1, NULL);
-		g_return_val_if_fail (node, FALSE);
+		g_return_val_if_fail (node != NULL, FALSE);
 
 		/* We use the raw DER encoding as an assertion */
-		element = egg_asn1x_get_raw_element (node, &n_element);
-		g_return_val_if_fail (node, FALSE);
-
-		/* Double check that this is valid, because it's how we hash */
-		key = g_byte_array_new ();
-		g_byte_array_append (key, element, n_element);
+		key = egg_asn1x_get_element_raw (node);
+		g_return_val_if_fail (key != NULL, FALSE);
 
 		/* Already have this assertion? */
 		assertion = g_hash_table_lookup (assertions, key);
@@ -459,7 +468,7 @@ load_assertions (GkmXdgTrust *self, GNode *asn)
 		}
 
 		add_assertion_to_trust (self, assertion, NULL);
-		g_byte_array_unref (key);
+		egg_bytes_unref (key);
 		g_object_unref (assertion);
 	}
 
@@ -522,6 +531,7 @@ create_trust_for_reference (GkmModule *module, GkmManager *manager,
 {
 	GkmXdgTrust *trust;
 	GNode *asn, *ref, *node;
+	EggBytes *bytes;
 
 	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
 	g_return_val_if_fail (asn, NULL);
@@ -530,20 +540,20 @@ create_trust_for_reference (GkmModule *module, GkmManager *manager,
 	node = egg_asn1x_node (ref, "certReference", NULL);
 
 	egg_asn1x_set_choice (ref, node);
-	egg_asn1x_set_integer_as_raw (egg_asn1x_node (node, "serialNumber", NULL),
-	                              g_memdup (serial->pValue, serial->ulValueLen),
-	                              serial->ulValueLen, g_free);
+	bytes = egg_bytes_new (serial->pValue, serial->ulValueLen);
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (node, "serialNumber", NULL), bytes);
+	egg_bytes_unref (bytes);
 
-	egg_asn1x_set_raw_element (egg_asn1x_node (node, "issuer", NULL),
-	                           g_memdup (issuer->pValue, issuer->ulValueLen),
-	                           issuer->ulValueLen, g_free);
+	bytes = egg_bytes_new (issuer->pValue, issuer->ulValueLen);
+	egg_asn1x_set_element_raw (egg_asn1x_node (node, "issuer", NULL), bytes);
+	egg_bytes_unref (bytes);
 
 	trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL);
 	trust->pv->asn = asn;
 
 	/* Encode it, so we have read access to all the data */
-	trust->pv->data = egg_asn1x_encode (asn, NULL, &trust->pv->n_data);
-	if (!trust->pv->data) {
+	trust->pv->bytes = egg_asn1x_encode (asn, NULL);
+	if (!trust->pv->bytes) {
 		g_warning ("created invalid trust object: %s", egg_asn1x_message (asn));
 		return NULL;
 	}
@@ -557,6 +567,7 @@ create_trust_for_complete (GkmModule *module, GkmManager *manager,
 {
 	GkmXdgTrust *trust;
 	GNode *asn, *ref, *node;
+	EggBytes *bytes;
 
 	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
 	g_return_val_if_fail (asn, NULL);
@@ -565,15 +576,16 @@ create_trust_for_complete (GkmModule *module, GkmManager *manager,
 	node = egg_asn1x_node (ref, "certComplete", NULL);
 
 	egg_asn1x_set_choice (ref, node);
-	egg_asn1x_set_raw_element (node, g_memdup (cert->pValue, cert->ulValueLen),
-	                           cert->ulValueLen, g_free);
+	bytes = egg_bytes_new (cert->pValue, cert->ulValueLen);
+	egg_asn1x_set_element_raw (node, bytes);
+	egg_bytes_unref (bytes);
 
 	trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL);
 	trust->pv->asn = asn;
 
 	/* Encode it, which validates, and so we have read access to all the data */
-	trust->pv->data = egg_asn1x_encode (asn, NULL, &trust->pv->n_data);
-	if (!trust->pv->data) {
+	trust->pv->bytes = egg_asn1x_encode (asn, NULL);
+	if (!trust->pv->bytes) {
 		g_warning ("created invalid trust object: %s", egg_asn1x_message (asn));
 		return NULL;
 	}
@@ -642,12 +654,12 @@ gkm_xdg_trust_get_level (GkmTrust *base, const gchar *purpose)
 {
 	GkmXdgTrust *self = GKM_XDG_TRUST (base);
 	GkmAssertion *assertion;
-	GByteArray *key;
+	EggBytes *key;
 	gulong type;
 
 	key = create_assertion_key (purpose, NULL);
 	assertion = g_hash_table_lookup (self->pv->assertions, key);
-	g_byte_array_unref (key);
+	egg_bytes_unref (key);
 
 	if (!assertion)
 		return GKM_TRUST_UNKNOWN;
@@ -705,74 +717,64 @@ gkm_xdg_trust_class_init (GkmXdgTrustClass *klass)
 }
 
 static gboolean
-gkm_xdg_trust_real_load (GkmSerializable *base, GkmSecret *login, gconstpointer data, gsize n_data)
+gkm_xdg_trust_real_load (GkmSerializable *base,
+                         GkmSecret *login,
+                         EggBytes *data)
 {
 	GkmXdgTrust *self = GKM_XDG_TRUST (base);
 	GNode *asn = NULL;
-	gpointer copy;
 
-	g_return_val_if_fail (GKM_XDG_IS_TRUST (self), FALSE);
-	g_return_val_if_fail (data, FALSE);
-
-	if (n_data == 0)
+	if (egg_bytes_get_size (data) == 0)
 		return FALSE;
 
-	copy = g_memdup (data, n_data);
-
 	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
 	g_return_val_if_fail (asn, FALSE);
 
-	if (!egg_asn1x_decode (asn, copy, n_data)) {
+	if (!egg_asn1x_decode (asn, data)) {
 		g_warning ("couldn't parse trust data: %s", egg_asn1x_message (asn));
 		egg_asn1x_destroy (asn);
-		g_free (copy);
 		return FALSE;
 	}
 
 	/* Next parse out all the pairs */
 	if (!load_assertions (self, asn)) {
 		egg_asn1x_destroy (asn);
-		g_free (copy);
 		return FALSE;
 	}
 
 	/* Take ownership of this new data */
-	g_free (self->pv->data);
-	self->pv->data = copy;
-	self->pv->n_data = n_data;
+	if (self->pv->bytes)
+		egg_bytes_unref (self->pv->bytes);
+	self->pv->bytes = egg_bytes_ref (data);
 	egg_asn1x_destroy (self->pv->asn);
 	self->pv->asn = asn;
 
 	return TRUE;
 }
 
-static gboolean
-gkm_xdg_trust_real_save (GkmSerializable *base, GkmSecret *login, gpointer *data, gsize *n_data)
+static EggBytes *
+gkm_xdg_trust_real_save (GkmSerializable *base, GkmSecret *login)
 {
 	GkmXdgTrust *self = GKM_XDG_TRUST (base);
+	EggBytes *bytes;
 
 	g_return_val_if_fail (GKM_XDG_IS_TRUST (self), FALSE);
-	g_return_val_if_fail (data, FALSE);
-	g_return_val_if_fail (n_data, FALSE);
 	g_return_val_if_fail (self->pv->asn, FALSE);
 
 	if (!save_assertions (self, self->pv->asn))
 		return FALSE;
 
-	*data = egg_asn1x_encode (self->pv->asn, NULL, n_data);
-	if (*data == NULL) {
+	bytes = egg_asn1x_encode (self->pv->asn, NULL);
+	if (bytes == NULL) {
 		g_warning ("encoding trust failed: %s", egg_asn1x_message (self->pv->asn));
 		return FALSE;
 	}
 
-	/* ASN.1 now refers to this data, take ownership */
-	g_free (self->pv->data);
-	self->pv->data = *data;
-	self->pv->n_data = *n_data;
+	if (self->pv->bytes)
+		egg_bytes_unref (self->pv->bytes);
+	self->pv->bytes = bytes;
 
-	/* Return a duplicate, since we own encoded */
-	*data = g_memdup (*data, *n_data);
-	return TRUE;
+	return egg_bytes_ref (bytes);
 }
 
 static void
@@ -847,7 +849,7 @@ gkm_xdg_trust_replace_assertion (GkmXdgTrust *self, GkmAssertion *assertion,
                              GkmTransaction *transaction)
 {
 	GkmAssertion *previous;
-	GByteArray *key;
+	EggBytes *key;
 
 	g_return_if_fail (GKM_XDG_IS_TRUST (self));
 	g_return_if_fail (GKM_IS_ASSERTION (assertion));
@@ -862,14 +864,14 @@ gkm_xdg_trust_replace_assertion (GkmXdgTrust *self, GkmAssertion *assertion,
 		remove_assertion_from_trust (self, previous, transaction);
 	add_assertion_to_trust (self, assertion, transaction);
 
-	g_byte_array_unref (key);
+	egg_bytes_unref (key);
 }
 
 void
 gkm_xdg_trust_remove_assertion (GkmXdgTrust *self, GkmAssertion *assertion,
                                 GkmTransaction *transaction)
 {
-	GByteArray *key;
+	EggBytes *key;
 
 	g_return_if_fail (GKM_XDG_IS_TRUST (self));
 	g_return_if_fail (GKM_IS_ASSERTION (assertion));
diff --git a/pkcs11/xdg-store/tests/check-xdg-module.c b/pkcs11/xdg-store/tests/check-xdg-module.c
index 64ea387..4ed03a0 100644
--- a/pkcs11/xdg-store/tests/check-xdg-module.c
+++ b/pkcs11/xdg-store/tests/check-xdg-module.c
@@ -34,7 +34,7 @@
 
 static int failures = 0;
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static void
 on_p11_tests_log (int level, const char *section, const char *message)
diff --git a/pkcs11/xdg-store/tests/dump-trust-file.c b/pkcs11/xdg-store/tests/dump-trust-file.c
index a0a1ca3..14c31a3 100644
--- a/pkcs11/xdg-store/tests/dump-trust-file.c
+++ b/pkcs11/xdg-store/tests/dump-trust-file.c
@@ -33,8 +33,7 @@
 #include <stdlib.h>
 
 /* Bring in the relevant definitions */
-#include "../asn1-def-xdg.c"
-
+#include "xdg-store/gkm-xdg-asn1-defs.h"
 
 static void
 barf_and_die (const char *msg, const char *detail)
@@ -50,26 +49,25 @@ static void
 dump_certificate_reference (GNode *asn)
 {
 	gchar *issuer, *serial;
-	gconstpointer data;
-	gsize n_data;
+	EggBytes *data;
 	GNode *name;
-	gconstpointer element;
-	gsize n_element;
+	EggBytes *element;
 
 	/* Parse the name out */
 	name = egg_asn1x_create (pkix_asn1_tab, "Name");
 	g_return_if_fail (name);
-	element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "issuer", NULL), &n_element);
+	element = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "issuer", NULL));
 	g_return_if_fail (element);
-	if (!egg_asn1x_decode (name, element, n_element))
+	if (!egg_asn1x_decode (name, element))
 		barf_and_die ("couldn't parse certificate", egg_asn1x_message (name));
+	egg_bytes_unref (element);
 
 	issuer = egg_dn_read (name);
 	g_return_if_fail (issuer);
 
-	data = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "serial", NULL), &n_data);
-	g_return_if_fail (data && n_data);
-	serial = egg_hex_encode (data, n_data);
+	data = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "serial", NULL));
+	g_return_if_fail (data != NULL);
+	serial = egg_hex_encode (egg_bytes_get_data (data), egg_bytes_get_size (data));
 
 	g_print ("Reference\n");
 	g_print ("    issuer: %s\n", issuer);
@@ -86,17 +84,18 @@ dump_certificate_complete (GNode *asn)
 {
 	GNode *cert;
 	gchar *issuer, *serial, *subject;
-	gconstpointer element;
-	gconstpointer data;
-	gsize n_data, n_element;
+	EggBytes *element;
+	EggBytes *data;
 
 	/* Parse the certificate out */
 	cert = egg_asn1x_create (pkix_asn1_tab, "Certificate");
 	g_return_if_fail (cert);
-	element = egg_asn1x_get_raw_element (asn, &n_element);
+
+	element = egg_asn1x_get_element_raw (asn);
 	g_return_if_fail (element);
-	if (!egg_asn1x_decode (cert, element, n_element))
+	if (!egg_asn1x_decode (cert, element))
 		barf_and_die ("couldn't parse certificate", egg_asn1x_message (cert));
+	egg_bytes_unref (element);
 
 	issuer = egg_dn_read (egg_asn1x_node (asn, "issuer", NULL));
 	g_return_if_fail (issuer);
@@ -104,9 +103,10 @@ dump_certificate_complete (GNode *asn)
 	subject = egg_dn_read (egg_asn1x_node (asn, "subject", NULL));
 	g_return_if_fail (subject);
 
-	data = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "serial", NULL), &n_data);
-	g_return_if_fail (data && n_data);
-	serial = egg_hex_encode (data, n_data);
+	data = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "serial", NULL));
+	g_return_if_fail (data != NULL);
+	serial = egg_hex_encode (egg_bytes_get_data (data), egg_bytes_get_size (data));
+	egg_bytes_unref (data);
 
 	g_print ("Complete\n");
 	g_print ("    issuer: %s\n", issuer);
@@ -155,6 +155,7 @@ main(int argc, char* argv[])
 	gchar *contents;
 	gsize n_contents;
 	GNode *asn, *node;
+	EggBytes *bytes;
 	gint i, count;
 
 	if (argc != 2) {
@@ -168,8 +169,10 @@ main(int argc, char* argv[])
 	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
 	g_return_val_if_fail (asn, 1);
 
-	if (!egg_asn1x_decode (asn, contents, n_contents))
+	bytes = egg_bytes_new_take (contents, n_contents);
+	if (!egg_asn1x_decode (asn, bytes))
 		barf_and_die ("couldn't parse file", egg_asn1x_message (asn));
+	egg_bytes_unref (bytes);
 
 	/* Print out the certificate we refer to first */
 	node = egg_asn1x_node (asn, "reference", "certReference", NULL);
diff --git a/pkcs11/xdg-store/tests/frob-trust-file.c b/pkcs11/xdg-store/tests/frob-trust-file.c
index 129e609..a576377 100644
--- a/pkcs11/xdg-store/tests/frob-trust-file.c
+++ b/pkcs11/xdg-store/tests/frob-trust-file.c
@@ -31,8 +31,7 @@
 #include <libtasn1.h>
 #include <stdlib.h>
 
-/* Bring in the relevant definitions */
-#include "../asn1-def-xdg.c"
+#include "xdg-store/gkm-xdg-asn1-defs.h"
 
 static void
 barf_and_die (const gchar *msg, const gchar *detail)
@@ -49,8 +48,9 @@ create_trust_file_for_certificate (const gchar *filename, const gchar *certifica
 {
 	GError *err = NULL;
 	GNode *asn, *cert, *choice, *ref;
-	gchar *data, *result;
-	gsize n_data, n_result;
+	EggBytes *bytes, *result;
+	gchar *data;
+	gsize n_data;
 
 	if (!g_file_get_contents (certificate, &data, &n_data, &err))
 		barf_and_die ("couldn't read certificate file", egg_error_message (err));
@@ -58,7 +58,9 @@ create_trust_file_for_certificate (const gchar *filename, const gchar *certifica
 	/* Make sure the certificate is */
 	cert = egg_asn1x_create (pkix_asn1_tab, "Certificate");
 	g_return_if_fail (cert);
-	if (!egg_asn1x_decode (cert, data, n_data))
+
+	bytes = egg_bytes_new_take (data, n_data);
+	if (!egg_asn1x_decode (cert, bytes))
 		barf_and_die ("couldn't parse der certificate file", egg_asn1x_message (cert));
 
 	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
@@ -67,19 +69,23 @@ create_trust_file_for_certificate (const gchar *filename, const gchar *certifica
 	ref = egg_asn1x_node (asn, "reference", NULL);
 	choice = egg_asn1x_node (ref, "certComplete", NULL);
 
-	if (!egg_asn1x_set_choice (ref, choice) ||
-	    !egg_asn1x_set_raw_element (choice, data, n_data, g_free))
+	if (!egg_asn1x_set_choice (ref, choice) || !egg_asn1x_set_element_raw (choice, bytes))
 		g_return_if_reached ();
 
-	result = egg_asn1x_encode (asn, NULL, &n_result);
+	egg_bytes_unref (bytes);
+
+	result = egg_asn1x_encode (asn, NULL);
 	if (result == NULL)
 		barf_and_die ("couldn't encode the trust file", egg_asn1x_message (asn));
 
 	egg_asn1x_destroy (asn);
 	egg_asn1x_destroy (cert);
 
-	if (!g_file_set_contents (filename, result, n_result, &err))
+	if (!g_file_set_contents (filename, egg_bytes_get_data (result),
+	                          egg_bytes_get_size (result), &err))
 		barf_and_die ("couldn't write trust file", egg_error_message (err));
+
+	egg_bytes_unref (result);
 }
 
 static void
@@ -88,10 +94,12 @@ create_trust_file_for_issuer_and_serial (const gchar *filename, const gchar *cer
 	GError *err = NULL;
 	GNode *asn, *cert, *choice, *ref;
 	GNode *issuer, *serial;
-	gchar *data, *result;
-	gconstpointer value;
-	gconstpointer element;
-	gsize n_data, n_result, n_element, n_value;
+	gchar *data;
+	EggBytes *result;
+	EggBytes *value;
+	EggBytes *element;
+	gsize n_data;
+	EggBytes *bytes;
 
 	if (!g_file_get_contents (certificate, &data, &n_data, &err))
 		barf_and_die ("couldn't read certificate file", egg_error_message (err));
@@ -99,8 +107,11 @@ create_trust_file_for_issuer_and_serial (const gchar *filename, const gchar *cer
 	/* Make sure the certificate is */
 	cert = egg_asn1x_create (pkix_asn1_tab, "Certificate");
 	g_return_if_fail (cert);
-	if (!egg_asn1x_decode (cert, data, n_data))
+
+	bytes = egg_bytes_new_take (data, n_data);
+	if (!egg_asn1x_decode (cert, bytes))
 		barf_and_die ("couldn't parse der certificate file", egg_asn1x_message (cert));
+	egg_bytes_unref (bytes);
 
 	/* Dig out the issuer and serial */
 	issuer = egg_asn1x_node (cert, "tbsCertificate", "issuer", NULL);
@@ -118,15 +129,16 @@ create_trust_file_for_issuer_and_serial (const gchar *filename, const gchar *cer
 		g_return_if_reached ();
 
 	/* Copy over the serial and issuer */
-	element = egg_asn1x_get_raw_element (issuer, &n_element);
-	if (!egg_asn1x_set_raw_element (egg_asn1x_node (choice, "issuer", NULL),
-	                                g_memdup (element, n_element), n_element, g_free))
-		g_return_if_reached ();
-	value = egg_asn1x_get_integer_as_raw (serial, &n_value);
-	if (!egg_asn1x_set_integer_as_raw (egg_asn1x_node (choice, "serialNumber", NULL), value, n_value, NULL))
+	element = egg_asn1x_get_element_raw (issuer);
+	if (!egg_asn1x_set_element_raw (egg_asn1x_node (choice, "issuer", NULL), element))
 		g_return_if_reached ();
+	egg_bytes_unref (element);
+
+	value = egg_asn1x_get_integer_as_raw (serial);
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (choice, "serialNumber", NULL), value);
+	egg_bytes_unref (value);
 
-	result = egg_asn1x_encode (asn, NULL, &n_result);
+	result = egg_asn1x_encode (asn, NULL);
 	if (result == NULL)
 		barf_and_die ("couldn't encode the trust file", egg_asn1x_message (asn));
 
@@ -134,19 +146,22 @@ create_trust_file_for_issuer_and_serial (const gchar *filename, const gchar *cer
 	egg_asn1x_destroy (cert);
 	egg_asn1x_destroy (asn);
 
-	if (!g_file_set_contents (filename, result, n_result, &err))
+	if (!g_file_set_contents (filename, egg_bytes_get_data (result),
+	                          egg_bytes_get_size (result), &err))
 		barf_and_die ("couldn't write trust file", egg_error_message (err));
 
-	g_free (result);
+	egg_bytes_unref (result);
 }
 
 static void
 add_trust_purpose_to_file (const gchar *filename, const gchar *purpose)
 {
 	GError *err = NULL;
-	gchar *data, *result;
-	gsize n_data, n_result;
+	gchar *data;
+	EggBytes *result;
+	gsize n_data;
 	GNode *asn, *assertion;
+	EggBytes *bytes;
 
 	if (!g_file_get_contents (filename, &data, &n_data, &err))
 		barf_and_die ("couldn't read trust file", egg_error_message (err));
@@ -156,8 +171,10 @@ add_trust_purpose_to_file (const gchar *filename, const gchar *purpose)
 	g_return_if_fail (asn);
 
 	/* And parse it */
-	if (!egg_asn1x_decode (asn, data, n_data))
+	bytes = egg_bytes_new_take (data, n_data);
+	if (!egg_asn1x_decode (asn, bytes))
 		barf_and_die ("couldn't parse trust file", egg_asn1x_message (asn));
+	egg_bytes_unref (bytes);
 
 	assertion = egg_asn1x_append (egg_asn1x_node (asn, "assertions", NULL));
 	g_return_if_fail (assertion);
@@ -166,14 +183,15 @@ add_trust_purpose_to_file (const gchar *filename, const gchar *purpose)
 	    !egg_asn1x_set_enumerated (egg_asn1x_node (assertion, "level", NULL), g_quark_from_string ("trusted")))
 		g_return_if_reached ();
 
-	result = egg_asn1x_encode (asn, NULL, &n_result);
+	result = egg_asn1x_encode (asn, NULL);
 	if (result == NULL)
 		barf_and_die ("couldn't encode trust file", egg_asn1x_message (asn));
 
 	g_free (data);
 	egg_asn1x_destroy (asn);
 
-	if (!g_file_set_contents (filename, result, n_result, &err))
+	if (!g_file_set_contents (filename, egg_bytes_get_data (result),
+	                          egg_bytes_get_size (result), &err))
 		barf_and_die ("couldn't write trust file", egg_error_message (err));
 
 	g_free (result);
diff --git a/pkcs11/xdg-store/tests/mock-xdg-module.c b/pkcs11/xdg-store/tests/mock-xdg-module.c
index f8271c2..a3b8cb9 100644
--- a/pkcs11/xdg-store/tests/mock-xdg-module.c
+++ b/pkcs11/xdg-store/tests/mock-xdg-module.c
@@ -41,7 +41,7 @@
 
 #include <string.h>
 
-EGG_SECURE_GLIB_DEFINITIONS ();
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
 
 static GMutex *mutex = NULL;
 static gchar *directory = NULL;



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