[gcr] gcr: Use GBytes immutable ref counted byte buffers



commit 97cd79171dfbba24394f070f3946b20c2d518d2d
Author: Stef Walter <stefw collabora co uk>
Date:   Wed Nov 16 08:38:44 2011 +0100

    gcr: Use GBytes immutable ref counted byte buffers
    
     * Copy from glib patch to EggBytes
     * This allows us to reliably build up ASN.1 structures from different
       sources, and is needed for the certificate request work.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=663291

 egg/Makefile.am                     |    2 +-
 egg/egg-armor.c                     |   40 ++-
 egg/egg-armor.h                     |   11 +-
 egg/egg-asn1x.c                     |  595 +++++++++++++++++++++++------------
 egg/egg-asn1x.h                     |   80 ++---
 egg/egg-byte-array.c                |   65 ----
 egg/egg-byte-array.h                |   33 --
 egg/egg-bytes.c                     |  453 ++++++++++++++++++++++++++
 egg/egg-bytes.h                     |  106 +++++++
 egg/egg-dn.c                        |   79 +++--
 egg/egg-dn.h                        |    8 +-
 egg/egg-openssl.c                   |   82 +++--
 egg/egg-openssl.h                   |   20 +-
 egg/egg-symkey.c                    |  193 +++++++-----
 egg/egg-symkey.h                    |    8 +-
 egg/tests/test-asn1.c               |  435 ++++++++++++++------------
 egg/tests/test-asn1x.c              |   17 +-
 egg/tests/test-dn.c                 |   26 ++-
 egg/tests/test-openssl.c            |   65 +++--
 gcr/gcr-certificate-extensions.c    |   54 ++--
 gcr/gcr-certificate-extensions.h    |   20 +-
 gcr/gcr-certificate-renderer.c      |  141 +++++----
 gcr/gcr-certificate.c               |  148 ++++++---
 gcr/gcr-fingerprint.c               |  115 +++++---
 gcr/gcr-openpgp.c                   |   16 +-
 gcr/gcr-openpgp.h                   |    8 +-
 gcr/gcr-openssh.c                   |   35 ++-
 gcr/gcr-openssh.h                   |    8 +-
 gcr/gcr-parser.c                    |  470 +++++++++++++++-------------
 gcr/tests/frob-openpgp.c            |   29 +-
 gcr/tests/test-fingerprint.c        |   95 +++---
 gcr/tests/test-openpgp.c            |   26 +-
 gcr/tests/test-openssh.c            |   39 ++-
 gcr/tests/test-pkcs11-certificate.c |   16 +-
 34 files changed, 2233 insertions(+), 1305 deletions(-)
---
diff --git a/egg/Makefile.am b/egg/Makefile.am
index 5eaff47..259d522 100644
--- a/egg/Makefile.am
+++ b/egg/Makefile.am
@@ -20,7 +20,7 @@ libegg_la_SOURCES = \
 	egg-armor.c egg-armor.h \
 	egg-asn1x.c egg-asn1x.h \
 	egg-buffer.c egg-buffer.h \
-	egg-byte-array.c egg-byte-array.h \
+	egg-bytes.c egg-bytes.h \
 	egg-dh.c egg-dh.h \
 	egg-dn.c egg-dn.h \
 	egg-error.h \
diff --git a/egg/egg-armor.c b/egg/egg-armor.c
index 5a4b047..b82730b 100644
--- a/egg/egg-armor.c
+++ b/egg/egg-armor.c
@@ -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-asn1x.c b/egg/egg-asn1x.c
index f2d4b42..ab862e0 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -107,6 +107,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 +119,9 @@ typedef struct _Abuf Abuf;
 typedef struct _Abits Abits;
 
 struct _Aenc {
-	EggAsn1xEncoder encoder;
+	Aencoder encoder;
 	gpointer data;
+	GDestroyNotify destroy;
 };
 
 struct _Atlv {
@@ -136,9 +142,7 @@ struct _Anode {
 	Atlv *tlv;
 	Aenc *enc;
 
-	gpointer user_data;
-	GDestroyNotify destroy;
-
+	EggBytes *backing;
 	gchar* failure;
 
 	gint chosen : 1;
@@ -152,13 +156,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);
 
@@ -367,17 +370,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 +432,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 +491,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 +512,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);
 }
 
@@ -826,7 +855,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 +865,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 +913,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 +935,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 +946,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 +981,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 +992,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;
 
@@ -978,18 +1016,18 @@ anode_decode_primitive (GNode *node, Atlv *tlv, gint flags)
 	case TYPE_NULL:
 	case TYPE_GENERALSTRING:
 	case TYPE_TIME:
-		anode_set_tlv_data (node, tlv);
+		anode_set_tlv_data (node, backing, tlv);
 		return TRUE;
 
 	/* Transparent types */
 	case TYPE_ANY:
-		anode_set_tlv_data (node, tlv);
+		anode_set_tlv_data (node, backing, tlv);
 		return TRUE;
 
 	case TYPE_CHOICE:
-		if (!anode_decode_choice (node, tlv))
+		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 +1038,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;
@@ -1020,7 +1061,7 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 		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 */
@@ -1039,7 +1080,7 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 				return FALSE;
 			break;
 		case TYPE_CHOICE:
-			if (!anode_decode_choice (node, tlv))
+			if (!anode_decode_choice (node, backing, tlv))
 				return FALSE;
 			break;
 		case TYPE_GENERALSTRING:
@@ -1049,12 +1090,12 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 			break;
 		case TYPE_SEQUENCE:
 		case TYPE_SET:
-			if (!anode_decode_sequence_or_set (node, tlv))
+			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))
+			if (!anode_decode_sequence_or_set_of (node, backing, tlv))
 				return FALSE;
 			break;
 		default:
@@ -1080,7 +1121,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 +1140,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 +1163,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 +1187,26 @@ 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);
+	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 +1214,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,8 +1305,11 @@ 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;
 	gulong tag;
@@ -1328,13 +1381,15 @@ 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)
 {
 	gint type;
 	guchar cls;
@@ -1375,9 +1430,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,7 +1493,8 @@ 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)
@@ -1457,7 +1514,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 +1542,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 +1565,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 +1579,7 @@ 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);
 	sign = !!(p[0] & 0x80);
 	if (sign) {
 		g_assert (n_data > 1);
@@ -1519,9 +1593,11 @@ 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 *node,
+                          guchar *data,
+                          gsize n_data)
 {
-	GNode *node = user_data;
 	GNode *child;
 	gsize length;
 	Atlv *tlv;
@@ -1531,7 +1607,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 +1619,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 +1640,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, node, data, n_data))
 		return FALSE;
 
 	/* Child's buffer matches ours */
@@ -1571,7 +1651,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 +1671,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) {
@@ -1611,8 +1694,10 @@ 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) {
+		anode_set_enc_data (node, anode_encoder_data,
+		                    (guchar *)tlv->buf + tlv->off, NULL);
+	}
 
 	tlv->buf = tlv->end = NULL;
 	return TRUE;
@@ -1636,8 +1721,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;
 
@@ -1716,20 +1801,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 +1864,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;
 }
@@ -2472,7 +2591,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;
 }
 
@@ -2483,7 +2602,7 @@ egg_asn1x_set_null (GNode *node)
 	g_return_val_if_fail (anode_def_type (node) == TYPE_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;
 }
 
@@ -2553,7 +2672,7 @@ 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;
 }
 
@@ -2611,100 +2730,132 @@ 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);
 
 	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 (node != NULL, FALSE);
 	g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
 
-	p = egg_asn1x_get_integer_as_raw (node, &len);
+	tlv = anode_get_tlv_data (node);
+	if (tlv == NULL || tlv->buf == NULL)
+		return NULL;
+
+	backing = anode_get_backing (node);
+	if (backing == NULL)
+		return NULL;
+
+	p = tlv->buf + tlv->off;
+	len = tlv->len;
+
 	sign = !!(p[0] & 0x80);
 	if (sign) {
 		g_warning ("invalid two's complement integer is negative, but expected unsigned");
 		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) == TYPE_INTEGER);
 
 	/* Make sure the integer is properly encoded in twos complement*/
-	p = (guchar*)data;
+	p = egg_bytes_get_data (value);
 	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) == TYPE_INTEGER);
 
 	/* Make sure the integer is properly encoded in twos complement*/
-	p = (guchar*)data;
+	p = egg_bytes_get_data (value);
 	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 +2863,63 @@ 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_raw_element (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;
 
+	backing = anode_get_backing (node);
+	if (backing == NULL)
+		return NULL;
+
 	if (anode_calc_explicit (node)) {
-		*n_element = (tlv->len + tlv->off) - tlv->oft;
-		return tlv->buf + tlv->oft;
+		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_raw_element (GNode *node,
+                           EggBytes *element)
 {
 	Atlv dtlv, *tlv;
 	gint oft, flags;
+	const guchar *data;
+	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);
+	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 +2931,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 */
@@ -2782,44 +2946,39 @@ egg_asn1x_set_raw_element (GNode *node, gpointer data,
 	/* 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);
+		                                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*
@@ -2872,10 +3031,25 @@ egg_asn1x_set_string_as_raw (GNode *node, guchar *data, gsize n_data, GDestroyNo
 	type = anode_def_type (node);
 	g_return_val_if_fail (type == TYPE_OCTET_STRING || type == TYPE_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);
+}
+
 gchar *
 egg_asn1x_get_bmpstring_as_utf8 (GNode *node)
 {
@@ -2933,61 +3107,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;
-
 	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 == TYPE_BIT_STRING);
 
 	length = (n_bits / 8);
 	if (n_bits % 8)
 		length += 1;
 
 	ab = g_slice_new0 (Abits);
-	ab->bits = bits;
+	ab->bits = egg_bytes_ref (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
@@ -3056,9 +3236,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;
@@ -3166,7 +3345,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;
 }
 
@@ -3919,8 +4098,9 @@ egg_asn1x_create_quark (const ASN1_ARRAY_TYPE *defs, GQuark 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 ASN1_ARRAY_TYPE *defs,
+                             const gchar *identifier,
+                             EggBytes *data)
 {
 	GNode *asn;
 
@@ -3930,7 +4110,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;
 	}
@@ -4156,16 +4336,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 +4359,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..e211b6d 100644
--- a/egg/egg-asn1x.h
+++ b/egg/egg-asn1x.h
@@ -26,13 +26,13 @@
 
 #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,
@@ -43,27 +43,23 @@ GNode*              egg_asn1x_create_quark           (const struct static_struct
 
 GNode*              egg_asn1x_create_and_decode      (const struct static_struct_asn *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);
 
@@ -102,38 +98,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);
+
+EggBytes *          egg_asn1x_get_raw_value          (GNode *node);
 
-gconstpointer       egg_asn1x_get_raw_element        (GNode *node,
-                                                      gsize *n_data);
+EggBytes *          egg_asn1x_get_raw_element        (GNode *node);
 
 gboolean            egg_asn1x_set_raw_element        (GNode *node,
-                                                      gpointer user_data,
-                                                      gsize n_data,
-                                                      GDestroyNotify destroy);
+                                                      EggBytes *value);
 
 guchar*             egg_asn1x_get_string_as_raw      (GNode *node,
                                                       EggAllocator allocator,
@@ -144,14 +130,18 @@ 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);
+
+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 +151,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 +176,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 +189,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..22bac5e
--- /dev/null
+++ b/egg/egg-bytes.c
@@ -0,0 +1,453 @@
+/*
+ * 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);
+    }
+}
+
+/**
+ * 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..57cba03
--- /dev/null
+++ b/egg/egg-bytes.h
@@ -0,0 +1,106 @@
+/*
+ * 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/gtypes.h>
+#include <glib/garray.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);
+
+#define egg_assert_equal_bytes(b, p, s) \
+	egg_assert_cmpmem (egg_bytes_get_data (b), egg_bytes_get_size (b), ==, (p), (s))
+
+#endif /* __EGG_BYTES_H__ */
diff --git a/egg/egg-dn.c b/egg/egg-dn.c
index b41844e..1edcd59 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_raw_element (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,8 +201,7 @@ 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;
@@ -226,10 +233,10 @@ 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_raw_element (node);
 			g_return_val_if_fail (value, NULL);
 
-			return dn_print_oid_value (oid, egg_oid_get_flags (oid), value, n_value);
+			return dn_print_oid_value (oid, egg_oid_get_flags (oid), value);
 		}
 	}
 
@@ -241,8 +248,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 +277,24 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
 				break;
 			}
 
-			value = egg_asn1x_get_raw_element (node, &n_value);
+			value = egg_asn1x_get_raw_element (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, n_value);
+	return dn_print_oid_value (oid, egg_oid_get_flags (oid), value);
 }
diff --git a/egg/egg-dn.h b/egg/egg-dn.h
index 96fe5ff..5d36d7e 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,6 @@ gboolean           egg_dn_parse                           (GNode *node,
                                                            gpointer user_data);
 
 gchar*             egg_dn_print_value                     (GQuark oid,
-                                                           const guchar *value,
-                                                           gsize n_value);
+                                                           EggBytes *value);
 
 #endif /* EGG_DN_H_ */
diff --git a/egg/egg-openssl.c b/egg/egg-openssl.c
index 77318f5..dc38e2b 100644
--- a/egg/egg-openssl.c
+++ b/egg/egg-openssl.c
@@ -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,6 +215,7 @@ 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;
@@ -224,43 +227,46 @@ egg_openssl_decrypt_block (const gchar *dekinfo, const gchar *password,
 
 	/* 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)) {
+	                                 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,
 	                                        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*
diff --git a/egg/egg-openssl.h b/egg/egg-openssl.h
index a998c9e..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-symkey.c b/egg/egg-symkey.c
index 5f5070b..835d4a3 100644
--- a/egg/egg-symkey.c
+++ b/egg/egg-symkey.c
@@ -658,14 +658,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,7 +677,7 @@ 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;
@@ -687,10 +690,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))
@@ -700,8 +703,9 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_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);
@@ -718,6 +722,8 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
 
 done:
 	g_free (iv);
+	if (salt != NULL)
+		egg_bytes_unref (salt);
 	egg_secure_free (key);
 	egg_asn1x_destroy (asn);
 
@@ -725,12 +731,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,90 +745,99 @@ 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, n_data);
+		asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-CBC-params", 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;
+	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))
+	                                 egg_bytes_get_data (salt), egg_bytes_get_size (salt),
+	                                 iterations, &key, NULL))
 		goto done;
 
 	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
@@ -837,32 +852,35 @@ setup_pkcs5_pbkdf2_params (const gchar *password, gsize n_password, const guchar
 	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;
 
@@ -893,17 +911,17 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
 	}
 
 	/* Read out the parameters */
-	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL), &n_params);
+	params = egg_asn1x_get_raw_element (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 */
@@ -924,11 +942,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_raw_element (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 +955,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,7 +980,7 @@ 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;
@@ -966,11 +989,11 @@ read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password,
 	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))
@@ -980,9 +1003,9 @@ read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password,
 	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);
@@ -1003,6 +1026,8 @@ done:
 		*cih = NULL;
 	}
 
+	if (salt != NULL)
+		egg_bytes_unref (salt);
 	g_free (iv);
 	egg_secure_free (key);
 	egg_asn1x_destroy (asn);
@@ -1013,8 +1038,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 +1046,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 +1061,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 +1075,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 +1097,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);
+		                              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);
+		                              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);
+		                              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);
+		                              password, n_password, data, cih);
 
 	if (ret == FALSE)
-    		g_message ("unsupported or invalid cipher: %s", g_quark_to_string (oid_scheme));
+		g_message ("unsupported or invalid cipher: %s", g_quark_to_string (oid_scheme));
 
-    	return ret;
+	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,17 +1184,18 @@ 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));
 
+	egg_bytes_unref (data);
 	return ret;
 }
diff --git a/egg/egg-symkey.h b/egg/egg-symkey.h
index feb1a25..b11d1dd 100644
--- a/egg/egg-symkey.h
+++ b/egg/egg-symkey.h
@@ -26,6 +26,8 @@
 
 #include <gcrypt.h>
 
+#include <egg/egg-bytes.h>
+
 gboolean                 egg_symkey_generate_simple             (int cipher_algo,
                                                                  int hash_algo,
                                                                  const gchar *password,
@@ -77,15 +79,13 @@ gboolean                 egg_symkey_generate_pbkdf2             (int cipher_algo
 gboolean                 egg_symkey_read_cipher                 (GQuark oid_scheme,
                                                                  const gchar *password,
                                                                  gsize n_password,
-                                                                 const guchar *data,
-                                                                 gsize n_data,
+                                                                 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/tests/test-asn1.c b/egg/tests/test-asn1.c
index 9403ebb..2ab9f52 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -60,6 +60,7 @@ const gchar ENUM_THREE[] =           "\x0A\x01\x03";
 static void
 test_boolean (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	gboolean value;
 
@@ -71,20 +72,24 @@ test_boolean (void)
 		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,8 +104,7 @@ 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);
@@ -108,14 +112,14 @@ test_null (void)
 	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,6 +127,7 @@ test_integer (void)
 {
 	GNode *asn;
 	gulong value;
+	EggBytes *bytes;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestInteger");
 	g_assert (asn);
@@ -132,11 +137,13 @@ test_integer (void)
 		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 +159,53 @@ 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);
 
 	/* 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,6 +213,7 @@ test_octet_string (void)
 {
 	GNode *asn;
 	gchar *value;
+	EggBytes *bytes;
 
 	asn = egg_asn1x_create (test_asn1_tab, "TestOctetString");
 	g_assert (asn);
@@ -212,8 +223,11 @@ test_octet_string (void)
 		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,6 +244,7 @@ test_octet_string (void)
 static void
 test_generalized_time (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	glong value;
 
@@ -241,8 +256,10 @@ test_generalized_time (void)
 	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);
 
@@ -258,6 +275,7 @@ test_generalized_time (void)
 static void
 test_implicit (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	gchar *value;
 
@@ -265,8 +283,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);
@@ -277,6 +297,7 @@ test_implicit (void)
 static void
 test_explicit (void)
 {
+	EggBytes *bytes;
 	GNode *asn;
 	gchar *value;
 
@@ -284,8 +305,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);
@@ -296,39 +320,47 @@ test_explicit (void)
 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);
 
 	/* 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 +368,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 +377,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 +394,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_set_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 +441,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_set_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 +494,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 +515,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 +530,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_raw_element (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_equal_bytes (data, SEQ_ENCODING, XL (SEQ_ENCODING));
 
-	check = egg_asn1x_get_raw_element (node, &n_check);
+	check = egg_asn1x_get_raw_element (node);
 	g_assert (check);
 
-	egg_assert_cmpsize (n_check, ==, XL (SFARNSWORTH));
-	g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+	egg_assert_equal_bytes (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 +555,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 +570,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_raw_element (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_equal_bytes (data, SEQ_ENCODING, XL (SEQ_ENCODING));
 
-	check = egg_asn1x_get_raw_element (node, &n_check);
+	check = egg_asn1x_get_raw_element (node);
 	g_assert (check);
 
-	g_assert (n_check == XL (SFARNSWORTH));
-	g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+	egg_assert_equal_bytes (check, SFARNSWORTH, XL (SFARNSWORTH));
 
-	g_free (data);
+	egg_bytes_unref (data);
+	egg_bytes_unref (check);
 	egg_asn1x_destroy (asn);
 	g_assert (is_freed);
 }
@@ -559,9 +594,9 @@ 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);
@@ -569,12 +604,14 @@ test_choice_not_chosen (void)
 	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_raw_element (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,10 +621,10 @@ 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);
@@ -599,26 +636,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_raw_element (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_equal_bytes (data, encoding, n_encoding);
 
-	check = egg_asn1x_get_raw_element (node, &n_check);
-	g_assert (check);
+	check = egg_asn1x_get_raw_element (node);
+	g_assert (check != NULL);
 
-	g_assert (n_check == XL (SFARNSWORTH));
-	g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+	egg_assert_equal_bytes (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 +678,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 +689,10 @@ 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);
 
 	child = egg_asn1x_append (asn);
 	g_assert (child);
@@ -661,22 +701,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_equal_bytes (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 +728,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 +737,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 +753,10 @@ 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);
 
 	/* 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 +766,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_equal_bytes (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 +790,30 @@ 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_equal_bytes (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);
 
 	value = egg_asn1x_get_enumerated (asn);
 	g_assert (value);
@@ -783,13 +822,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_equal_bytes (data, ENUM_THREE, XL (ENUM_THREE));
 
-	g_free (data);
+	egg_bytes_unref (data);
 	egg_asn1x_destroy (asn);
 }
 
@@ -802,6 +840,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 +849,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 +871,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 +889,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 +911,15 @@ 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_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 +933,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 +943,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 +969,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 +978,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 +997,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 +1015,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,30 +1040,29 @@ 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_raw_element (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);
 
-	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_equal_bytes (data, "SOME DATA", 9);
 
 	egg_asn1x_destroy (asn);
-	g_free (buffer);
+	egg_bytes_unref (buffer);
 }
 
 static void
 test_oid (Test* test, gconstpointer unused)
 {
+	EggBytes *buffer;
 	GNode *asn = NULL;
 	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);
@@ -1033,7 +1070,7 @@ test_oid (Test* test, gconstpointer unused)
 	if (!egg_asn1x_set_oid_as_string (egg_asn1x_node (asn, "oid", NULL), "1.2.34567.89"))
 		g_assert_not_reached ();
 
-	buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+	buffer = egg_asn1x_encode (asn, NULL);
 	g_assert (buffer != NULL);
 
 	/* Now a quark has been defined */
@@ -1047,15 +1084,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);
 }
 
diff --git a/egg/tests/test-asn1x.c b/egg/tests/test-asn1x.c
index baeba55..cc60c7f 100644
--- a/egg/tests/test-asn1x.c
+++ b/egg/tests/test-asn1x.c
@@ -67,29 +67,32 @@ static void
 test_some_asn1_stuff (const ASN1_ARRAY_TYPE *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-dn.c b/egg/tests/test-dn.c
index 98f5a43..7f95439 100644
--- a/egg/tests/test-dn.c
+++ b/egg/tests/test-dn.c
@@ -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);
 }
diff --git a/egg/tests/test-openssl.c b/egg/tests/test-openssl.c
index da5e457..d3d672e 100644
--- a/egg/tests/test-openssl.c
+++ b/egg/tests/test-openssl.c
@@ -36,11 +36,12 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <egg/egg-bytes.h>
+
 EGG_SECURE_GLIB_DEFINITIONS ();
 
 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,17 +124,19 @@ 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);
 
@@ -147,7 +151,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 +163,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_equal_bytes (test->input, result, n_result);
 	g_free (result);
 }
 
@@ -171,25 +175,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 */
diff --git a/gcr/gcr-certificate-extensions.c b/gcr/gcr-certificate-extensions.c
index 8256da2..f130225 100644
--- a/gcr/gcr-certificate-extensions.c
+++ b/gcr/gcr-certificate-extensions.c
@@ -32,18 +32,18 @@
 #include <glib/gi18n-lib.h>
 
 gboolean
-_gcr_certificate_extension_basic_constraints (gconstpointer data, gsize n_data,
-                                              gboolean *is_ca, gint *path_len)
+_gcr_certificate_extension_basic_constraints (EggBytes *data,
+                                              gboolean *is_ca,
+                                              gint *path_len)
 {
 	gboolean ret = TRUE;
 	GNode *asn = NULL;
 	GNode *node;
 	gulong value;
 
-	g_return_val_if_fail (data, FALSE);
-	g_return_val_if_fail (n_data, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	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 == NULL)
 		return FALSE;
 
@@ -69,8 +69,8 @@ _gcr_certificate_extension_basic_constraints (gconstpointer data, gsize n_data,
 	return ret;
 }
 
-GQuark*
-_gcr_certificate_extension_extended_key_usage (gconstpointer data, gsize n_data)
+GQuark *
+_gcr_certificate_extension_extended_key_usage (EggBytes *data)
 {
 	GNode *asn = NULL;
 	GNode *node;
@@ -78,7 +78,9 @@ _gcr_certificate_extension_extended_key_usage (gconstpointer data, gsize n_data)
 	GQuark oid;
 	int i;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data, n_data);
+	g_return_val_if_fail (data != NULL, NULL);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data);
 	if (asn == NULL)
 		return NULL;
 
@@ -96,13 +98,15 @@ _gcr_certificate_extension_extended_key_usage (gconstpointer data, gsize n_data)
 }
 
 gpointer
-_gcr_certificate_extension_subject_key_identifier (gconstpointer data, gsize n_data,
+_gcr_certificate_extension_subject_key_identifier (EggBytes *data,
                                                    gsize *n_keyid)
 {
 	GNode *asn = NULL;
 	gpointer result;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectKeyIdentifier", data, n_data);
+	g_return_val_if_fail (data != NULL, NULL);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectKeyIdentifier", data);
 	if (asn == NULL)
 		return NULL;
 
@@ -113,14 +117,16 @@ _gcr_certificate_extension_subject_key_identifier (gconstpointer data, gsize n_d
 }
 
 gboolean
-_gcr_certificate_extension_key_usage (gconstpointer data, gsize n_data,
+_gcr_certificate_extension_key_usage (EggBytes *data,
                                       gulong *key_usage)
 {
 	GNode *asn = NULL;
 	gboolean ret = TRUE;
 	guint n_bits;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data, n_data);
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data);
 	if (asn == NULL)
 		return FALSE;
 
@@ -134,28 +140,28 @@ general_name_parse_other (GNode *node, GcrGeneralName *general)
 {
 	GNode *decode = NULL;
 	GQuark oid;
-	gconstpointer value;
-	gsize n_value;
+	EggBytes *value;
 
 	general->type = GCR_GENERAL_NAME_OTHER;
 	general->description = _("Other Name");
 
 	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "type-id", NULL));
-	value = egg_asn1x_get_raw_element (egg_asn1x_node (node, "value", NULL), &n_value);
+	value = egg_asn1x_get_raw_element (egg_asn1x_node (node, "value", NULL));
 
 	if (value == NULL)
 		return;
 
 	if (oid == GCR_OID_ALT_NAME_XMPP_ADDR) {
 		general->description = _("XMPP Addr");
-		decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "UTF8String", value, n_value);
+		decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "UTF8String", value);
 		general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
 	} else if (oid == GCR_OID_ALT_NAME_DNS_SRV) {
 		general->description = _("DNS SRV");
-		decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "IA5String", value, n_value);
+		decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "IA5String", value);
 		general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
 	}
 
+	egg_bytes_unref (value);
 	egg_asn1x_destroy (decode);
 }
 
@@ -222,7 +228,7 @@ general_name_parse_registered (GNode *node, GcrGeneralName *general)
 }
 
 GArray*
-_gcr_certificate_extension_subject_alt_name (gconstpointer data, gsize n_data)
+_gcr_certificate_extension_subject_alt_name (EggBytes *data)
 {
 	GNode *asn = NULL;
 	guint count, i;
@@ -233,7 +239,7 @@ _gcr_certificate_extension_subject_alt_name (gconstpointer data, gsize n_data)
 
 	_gcr_oids_init ();
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectAltName", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectAltName", data);
 	if (asn == NULL)
 		return NULL;
 
@@ -276,7 +282,7 @@ _gcr_certificate_extension_subject_alt_name (gconstpointer data, gsize n_data)
 		else if (g_str_equal (node_name, "registeredID"))
 			general_name_parse_registered (choice, &general);
 
-		general.raw = egg_asn1x_get_raw_element (choice, &general.n_raw);
+		general.raw = egg_asn1x_get_raw_element (choice);
 		g_array_append_val (names, general);
 	}
 
@@ -287,9 +293,13 @@ _gcr_certificate_extension_subject_alt_name (gconstpointer data, gsize n_data)
 void
 _gcr_general_names_free (GArray *names)
 {
+	GcrGeneralName *name;
 	guint i;
 
-	for (i = 0; names && i < names->len; i++)
-		g_free (g_array_index (names, GcrGeneralName, i).display);
+	for (i = 0; names && i < names->len; i++) {
+		name = &g_array_index (names, GcrGeneralName, i);
+		g_free (name->display);
+		egg_bytes_unref (name->raw);
+	}
 	g_array_free (names, TRUE);
 }
diff --git a/gcr/gcr-certificate-extensions.h b/gcr/gcr-certificate-extensions.h
index 9101008..ea5792f 100644
--- a/gcr/gcr-certificate-extensions.h
+++ b/gcr/gcr-certificate-extensions.h
@@ -30,18 +30,17 @@
 
 #include <glib.h>
 
+#include <egg/egg-bytes.h>
+
 G_BEGIN_DECLS
 
-gboolean   _gcr_certificate_extension_basic_constraints       (gconstpointer data,
-                                                               gsize n_data,
+gboolean   _gcr_certificate_extension_basic_constraints       (EggBytes *data,
                                                                gboolean *is_ca,
                                                                gint *path_len);
 
-GQuark*    _gcr_certificate_extension_extended_key_usage      (gconstpointer data,
-                                                               gsize n_data);
+GQuark *   _gcr_certificate_extension_extended_key_usage      (EggBytes *data);
 
-gpointer   _gcr_certificate_extension_subject_key_identifier  (gconstpointer data,
-                                                               gsize n_data,
+gpointer   _gcr_certificate_extension_subject_key_identifier  (EggBytes *data,
                                                                gsize *n_keyid);
 
 typedef enum {
@@ -54,8 +53,7 @@ typedef enum {
 	GCR_KEY_USAGE_CRL_SIGN = 1 << 6,
 } GcrCertificateExtensionKeyUsage;
 
-gboolean   _gcr_certificate_extension_key_usage               (gconstpointer data,
-                                                               gsize n_data,
+gboolean   _gcr_certificate_extension_key_usage               (EggBytes *data,
                                                                gulong *key_usage);
 
 typedef enum {
@@ -74,12 +72,10 @@ typedef struct {
 	GcrGeneralNameType type;
 	const gchar *description;
 	gchar *display;
-	gconstpointer raw;
-	gsize n_raw;
+	EggBytes *raw;
 } GcrGeneralName;
 
-GArray *   _gcr_certificate_extension_subject_alt_name        (gconstpointer data,
-                                                               gsize n_data);
+GArray *   _gcr_certificate_extension_subject_alt_name        (EggBytes *data);
 
 void       _gcr_general_names_free                            (GArray *names);
 
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
index 7995917..a350d3e 100644
--- a/gcr/gcr-certificate-renderer.c
+++ b/gcr/gcr-certificate-renderer.c
@@ -102,15 +102,16 @@ calculate_label (GcrCertificateRenderer *self)
 }
 
 static gboolean
-append_extension_basic_constraints (GcrCertificateRenderer *self, GcrDisplayView *view,
-                                    gconstpointer data, gsize n_data)
+append_extension_basic_constraints (GcrCertificateRenderer *self,
+                                    GcrDisplayView *view,
+                                    EggBytes *data)
 {
 	GcrRenderer *renderer = GCR_RENDERER (self);
 	gboolean is_ca = FALSE;
 	gint path_len = -1;
 	gchar *number;
 
-	if (!_gcr_certificate_extension_basic_constraints (data, n_data, &is_ca, &path_len))
+	if (!_gcr_certificate_extension_basic_constraints (data, &is_ca, &path_len))
 		return FALSE;
 
 	_gcr_display_view_append_heading (view, renderer, _("Basic Constraints"));
@@ -127,15 +128,16 @@ append_extension_basic_constraints (GcrCertificateRenderer *self, GcrDisplayView
 }
 
 static gboolean
-append_extension_extended_key_usage (GcrCertificateRenderer *self, GcrDisplayView *view,
-                                     gconstpointer data, gsize n_data)
+append_extension_extended_key_usage (GcrCertificateRenderer *self,
+                                     GcrDisplayView *view,
+                                     EggBytes *data)
 {
 	GcrRenderer *renderer = GCR_RENDERER (self);
 	GQuark *oids;
 	GString *text;
 	guint i;
 
-	oids = _gcr_certificate_extension_extended_key_usage (data, n_data);
+	oids = _gcr_certificate_extension_extended_key_usage (data);
 	if (oids == NULL)
 		return FALSE;
 
@@ -159,14 +161,15 @@ append_extension_extended_key_usage (GcrCertificateRenderer *self, GcrDisplayVie
 }
 
 static gboolean
-append_extension_subject_key_identifier (GcrCertificateRenderer *self, GcrDisplayView *view,
-                                         gconstpointer data, gsize n_data)
+append_extension_subject_key_identifier (GcrCertificateRenderer *self,
+                                         GcrDisplayView *view,
+                                         EggBytes *data)
 {
 	GcrRenderer *renderer = GCR_RENDERER (self);
 	gpointer keyid;
 	gsize n_keyid;
 
-	keyid = _gcr_certificate_extension_subject_key_identifier (data, n_data, &n_keyid);
+	keyid = _gcr_certificate_extension_subject_key_identifier (data, &n_keyid);
 	if (keyid == NULL)
 		return FALSE;
 
@@ -191,15 +194,16 @@ static const struct {
 };
 
 static gboolean
-append_extension_key_usage (GcrCertificateRenderer *self, GcrDisplayView *view,
-                            gconstpointer data, gsize n_data)
+append_extension_key_usage (GcrCertificateRenderer *self,
+                            GcrDisplayView *view,
+                            EggBytes *data)
 {
 	GcrRenderer *renderer = GCR_RENDERER (self);
 	gulong key_usage;
 	GString *text;
 	guint i;
 
-	if (!_gcr_certificate_extension_key_usage (data, n_data, &key_usage))
+	if (!_gcr_certificate_extension_key_usage (data, &key_usage))
 		return FALSE;
 
 	text = g_string_new ("");
@@ -221,15 +225,16 @@ append_extension_key_usage (GcrCertificateRenderer *self, GcrDisplayView *view,
 }
 
 static gboolean
-append_extension_subject_alt_name (GcrCertificateRenderer *self, GcrDisplayView *view,
-                                   gconstpointer data, gsize n_data)
+append_extension_subject_alt_name (GcrCertificateRenderer *self,
+                                   GcrDisplayView *view,
+                                   EggBytes *data)
 {
 	GcrRenderer *renderer = GCR_RENDERER (self);
 	GArray *general_names;
 	GcrGeneralName *general;
 	guint i;
 
-	general_names = _gcr_certificate_extension_subject_alt_name (data, n_data);
+	general_names = _gcr_certificate_extension_subject_alt_name (data);
 	if (general_names == NULL)
 		return FALSE;
 
@@ -239,7 +244,8 @@ append_extension_subject_alt_name (GcrCertificateRenderer *self, GcrDisplayView
 		general = &g_array_index (general_names, GcrGeneralName, i);
 		if (general->display == NULL)
 			_gcr_display_view_append_hex (view, renderer, general->description,
-			                              general->raw, general->n_raw);
+			                              egg_bytes_get_data (general->raw),
+			                              egg_bytes_get_size (general->raw));
 		else
 			_gcr_display_view_append_value (view, renderer, general->description,
 			                                general->display, FALSE);
@@ -269,14 +275,15 @@ append_extension_hex (GcrCertificateRenderer *self, GcrDisplayView *view,
 }
 
 static gboolean
-append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
-                  GNode *asn, const guchar *data, gsize n_data, gint index)
+append_extension (GcrCertificateRenderer *self,
+                  GcrDisplayView *view,
+                  GNode *asn,
+                  gint index)
 {
 	GcrRenderer *renderer = GCR_RENDERER (self);
 	GNode *node;
 	GQuark oid;
-	gsize n_value;
-	const guchar *value;
+	EggBytes *value;
 	gboolean critical;
 	gboolean ret = FALSE;
 
@@ -290,23 +297,25 @@ append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
 	g_return_val_if_fail (oid, FALSE);
 
 	/* Extension value */
-	value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL), &n_value);
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL));
 
 	/* The custom parsers */
 	if (oid == GCR_OID_BASIC_CONSTRAINTS)
-		ret = append_extension_basic_constraints (self, view, value, n_value);
+		ret = append_extension_basic_constraints (self, view, value);
 	else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
-		ret = append_extension_extended_key_usage (self, view, value, n_value);
+		ret = append_extension_extended_key_usage (self, view, value);
 	else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER)
-		ret = append_extension_subject_key_identifier (self, view, value, n_value);
+		ret = append_extension_subject_key_identifier (self, view, value);
 	else if (oid == GCR_OID_KEY_USAGE)
-		ret = append_extension_key_usage (self, view, value, n_value);
+		ret = append_extension_key_usage (self, view, value);
 	else if (oid == GCR_OID_SUBJECT_ALT_NAME)
-		ret = append_extension_subject_alt_name (self, view, value, n_value);
+		ret = append_extension_subject_alt_name (self, view, value);
 
 	/* Otherwise the default raw display */
 	if (ret == FALSE)
-		ret = append_extension_hex (self, view, oid, value, n_value);
+		ret = append_extension_hex (self, view, oid,
+		                            egg_bytes_get_data (value),
+		                            egg_bytes_get_size (value));
 
 	/* Critical */
 	if (ret == TRUE && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) {
@@ -314,6 +323,7 @@ append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
 		                                critical ? _("Yes") : _("No"), FALSE);
 	}
 
+	egg_bytes_unref (value);
 	return ret;
 }
 
@@ -323,8 +333,10 @@ typedef struct _on_parsed_dn_args {
 } on_parsed_dn_args;
 
 static void
-on_parsed_dn_part (guint index, GQuark oid, const guchar *value,
-                   gsize n_value, gpointer user_data)
+on_parsed_dn_part (guint index,
+                   GQuark oid,
+                   EggBytes *value,
+                   gpointer user_data)
 {
 	GcrCertificateRenderer *self = ((on_parsed_dn_args*)user_data)->renderer;
 	GcrDisplayView *view = ((on_parsed_dn_args*)user_data)->view;
@@ -354,7 +366,7 @@ on_parsed_dn_part (guint index, GQuark oid, const guchar *value,
 		g_assert_not_reached ();
 	}
 
-	display = egg_dn_print_value (oid, value, n_value);
+	display = egg_dn_print_value (oid, value);
 	if (display == NULL)
 		display = g_strdup ("");
 
@@ -562,17 +574,19 @@ static void
 gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 {
 	GcrCertificateRenderer *self;
-	gconstpointer data, value;
-	gsize n_data, n_value, n_raw;
+	gconstpointer data;
+	gsize n_data, n_raw;
 	GcrDisplayView *view;
 	on_parsed_dn_args args;
 	const gchar *text;
 	GcrCertificate *cert;
 	gpointer raw;
-	gconstpointer number;
+	EggBytes *number;
 	gulong version;
 	guint bits, index;
 	gchar *display;
+	EggBytes *bytes;
+	EggBytes *value;
 	GNode *asn;
 	GQuark oid;
 	GDate date;
@@ -602,8 +616,10 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	_gcr_display_view_set_icon (view, GCR_RENDERER (self), icon);
 	g_object_unref (icon);
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
-	g_return_if_fail (asn);
+	bytes = egg_bytes_new_static (data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
+	g_return_if_fail (asn != NULL);
+	egg_bytes_unref (bytes);
 
 	display = calculate_label (self);
 	_gcr_display_view_append_title (view, renderer, display);
@@ -647,9 +663,12 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	_gcr_display_view_append_value (view, renderer, _("Version"), display, FALSE);
 	g_free (display);
 
-	number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), &n_raw);
+	number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL));
 	g_return_if_fail (number != NULL);
-	_gcr_display_view_append_hex (view, renderer, _("Serial Number"), number, n_raw);
+	_gcr_display_view_append_hex (view, renderer, _("Serial Number"),
+	                              egg_bytes_get_data (number),
+	                              egg_bytes_get_size (number));
+	egg_bytes_unref (number);
 
 	display = g_malloc0 (128);
 	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) {
@@ -677,14 +696,19 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	text = egg_oid_get_description (oid);
 	_gcr_display_view_append_value (view, renderer, _("Signature Algorithm"), text, FALSE);
 
-	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value);
-	if (value && n_value)
-		_gcr_display_view_append_hex (view, renderer, _("Signature Parameters"), value, n_value);
+	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL));
+	if (value) {
+		_gcr_display_view_append_hex (view, renderer, _("Signature Parameters"),
+		                              egg_bytes_get_data (value),
+		                              egg_bytes_get_size (value));
+		egg_bytes_unref (value);
+	}
 
-	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), NULL, &bits);
-	g_return_if_fail (raw);
-	_gcr_display_view_append_hex (view, renderer, _("Signature"), raw, bits / 8);
-	g_free (raw);
+	value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), &bits);
+	g_return_if_fail (value != NULL);
+	_gcr_display_view_append_hex (view, renderer, _("Signature"),
+	                              egg_bytes_get_data (value), bits / 8);
+	egg_bytes_unref (value);
 
 	/* Public Key Info */
 	_gcr_display_view_append_heading (view, renderer, _("Public Key Info"));
@@ -695,9 +719,13 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	_gcr_display_view_append_value (view, renderer, _("Key Algorithm"), text, FALSE);
 
 	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
-	                                                   "algorithm", "parameters", NULL), &n_value);
-	if (value && n_value)
-		_gcr_display_view_append_hex (view, renderer, _("Key Parameters"), value, n_value);
+	                                                   "algorithm", "parameters", NULL));
+	if (value) {
+		_gcr_display_view_append_hex (view, renderer, _("Key Parameters"),
+		                              egg_bytes_get_data (value),
+		                              egg_bytes_get_size (value));
+		egg_bytes_unref (value);
+	}
 
 	bits = gcr_certificate_get_key_size (cert);
 	if (bits > 0) {
@@ -707,20 +735,23 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	}
 
 	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate",
-	                                                   "subjectPublicKeyInfo", NULL), &n_value);
-	raw = gcr_fingerprint_from_subject_public_key_info (value, n_value, G_CHECKSUM_SHA1, &n_raw);
+	                                                   "subjectPublicKeyInfo", NULL));
+	raw = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (bytes),
+	                                                    egg_bytes_get_size (bytes),
+	                                                    G_CHECKSUM_SHA1, &n_raw);
 	_gcr_display_view_append_hex (view, renderer, _("Key SHA1 Fingerprint"), raw, n_raw);
 	g_free (raw);
 
-	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
-	                                                 "subjectPublicKey", NULL), NULL, &bits);
-	g_return_if_fail (raw);
-	_gcr_display_view_append_hex (view, renderer, _("Public Key"), raw, bits / 8);
-	g_free (raw);
+	value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
+	                                                   "subjectPublicKey", NULL), &bits);
+	g_return_if_fail (value != NULL);
+	_gcr_display_view_append_hex (view, renderer, _("Public Key"),
+	                              egg_bytes_get_data (value), bits / 8);
+	egg_bytes_unref (value);
 
 	/* Extensions */
 	for (index = 1; TRUE; ++index) {
-		if (!append_extension (self, view, asn, data, n_data, index))
+		if (!append_extension (self, view, asn, index))
 			break;
 	}
 
diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c
index 5dd16ab..889c67a 100644
--- a/gcr/gcr-certificate.c
+++ b/gcr/gcr-certificate.c
@@ -104,8 +104,8 @@ typedef struct _GcrCertificateInfo {
 
 /* Forward declarations */
 
-static gconstpointer _gcr_certificate_get_subject_const (GcrCertificate *self, gsize *n_data);
-static gconstpointer _gcr_certificate_get_issuer_const (GcrCertificate *self, gsize *n_data);
+static EggBytes * _gcr_certificate_get_subject_const (GcrCertificate *self);
+static EggBytes * _gcr_certificate_get_issuer_const (GcrCertificate *self);
 
 enum {
 	PROP_FIRST = 0x0007000,
@@ -139,6 +139,7 @@ static GcrCertificateInfo*
 certificate_info_load (GcrCertificate *cert)
 {
 	GcrCertificateInfo *info;
+	EggBytes *bytes;
 	GNode *asn1;
 	gconstpointer der;
 	gsize n_der;
@@ -154,8 +155,14 @@ certificate_info_load (GcrCertificate *cert)
 			return info;
 	}
 
+	/* TODO: Once GBytes is public, add to GcrCertificate interface */
+	bytes = egg_bytes_new_static (der, n_der);
+
 	/* Cache is invalid or non existent */
-	asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", der, n_der);
+	asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
+
+	egg_bytes_unref (bytes);
+
 	if (asn1 == NULL) {
 		g_warning ("a derived class provided an invalid or unparseable X.509 DER certificate data.");
 		return NULL;
@@ -171,56 +178,67 @@ certificate_info_load (GcrCertificate *cert)
 }
 
 static guint
-calculate_rsa_key_size (gconstpointer data, gsize n_data)
+calculate_rsa_key_size (EggBytes *data)
 {
+	EggBytes *content;
+	guint key_size;
 	GNode *asn;
-	gsize n_content;
 
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data, n_data);
-	g_return_val_if_fail (asn, 0);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
+	g_return_val_if_fail (asn != NULL, 0);
 
-	if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL), &n_content))
+	content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL));
+	if (!content)
 		g_return_val_if_reached (0);
 
 	egg_asn1x_destroy (asn);
 
 	/* Removes the complement */
-	return (n_content / 2) * 2 * 8;
+	key_size = (egg_bytes_get_size (content) / 2) * 2 * 8;
+
+	egg_bytes_unref (content);
+	return key_size;
 }
 
 static guint
-calculate_dsa_params_size (gconstpointer data, gsize n_data)
+calculate_dsa_params_size (EggBytes *data)
 {
+	EggBytes *content;
+	gsize params_size;
 	GNode *asn;
-	gsize n_content;
 
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data, n_data);
-	g_return_val_if_fail (asn, 0);
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data);
+	g_return_val_if_fail (asn != NULL, 0);
 
-	if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL), &n_content))
+	content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL));
+	if (!content)
 		g_return_val_if_reached (0);
 
 	egg_asn1x_destroy (asn);
 
 	/* Removes the complement */
-	return (n_content / 2) * 2 * 8;
+	params_size = (egg_bytes_get_size (content) / 2) * 2 * 8;
+
+	egg_bytes_unref (content);
+	return params_size;
 }
 
 static guint
 calculate_key_size (GcrCertificateInfo *info)
 {
 	GNode *asn;
-	gconstpointer data, params;
-	gsize n_data, n_params;
+	EggBytes *data;
 	guint key_size = 0, n_bits;
-	guchar *key = NULL;
+	EggBytes *key;
 	GQuark oid;
 
-	data = egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_data);
+	data = egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL));
 	g_return_val_if_fail (data != NULL, 0);
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data, n_data);
-	g_return_val_if_fail (asn, 0);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data);
+	g_return_val_if_fail (asn != NULL, 0);
+
+	egg_bytes_unref (data);
 
 	/* Figure out the algorithm */
 	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "algorithm", "algorithm", NULL));
@@ -230,15 +248,16 @@ calculate_key_size (GcrCertificateInfo *info)
 	if (oid == GCR_OID_PKIX1_RSA) {
 
 		/* 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);
-		g_return_val_if_fail (key, 0);
-		key_size = calculate_rsa_key_size (key, n_bits / 8);
-		g_free (key);
+		key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), &n_bits);
+		g_return_val_if_fail (key != NULL, 0);
+		key_size = calculate_rsa_key_size (key);
+		egg_bytes_unref (key);
 
 	/* The DSA key size is discovered by the prime in params */
 	} else if (oid == GCR_OID_PKIX1_DSA) {
-		params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "algorithm", "parameters", NULL), &n_params);
-		key_size = calculate_dsa_params_size (params, n_params);
+		key = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "algorithm", "parameters", NULL));
+		key_size = calculate_dsa_params_size (key);
+		egg_bytes_unref (key);
 
 	} else {
 		g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid));
@@ -495,18 +514,17 @@ gcr_certificate_get_issuer_part (GcrCertificate *self, const char *part)
 	return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL), part);
 }
 
-static gconstpointer
-_gcr_certificate_get_issuer_const (GcrCertificate *self, gsize *n_data)
+static EggBytes *
+_gcr_certificate_get_issuer_const (GcrCertificate *self)
 {
 	GcrCertificateInfo *info;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
-	g_return_val_if_fail (n_data != NULL, NULL);
 
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
 
-	return egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", NULL), n_data);
+	return egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", NULL));
 }
 
 /**
@@ -525,13 +543,21 @@ guchar *
 gcr_certificate_get_issuer_raw (GcrCertificate *self,
                                 gsize *n_data)
 {
-	gconstpointer data;
+	EggBytes *bytes;
+	guchar *result;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
 	g_return_val_if_fail (n_data != NULL, NULL);
 
-	data = _gcr_certificate_get_issuer_const (self, n_data);
-	return g_memdup (data, data ? *n_data : 0);
+	bytes = _gcr_certificate_get_issuer_const (self);
+	if (bytes == NULL)
+		return NULL;
+
+	*n_data = egg_bytes_get_size (bytes);
+	result = g_memdup (egg_bytes_get_data (bytes), *n_data);
+	egg_bytes_unref (bytes);
+
+	return result;
 }
 
 /**
@@ -549,20 +575,25 @@ gcr_certificate_get_issuer_raw (GcrCertificate *self,
 gboolean
 gcr_certificate_is_issuer (GcrCertificate *self, GcrCertificate *issuer)
 {
-	gconstpointer subject_dn, issuer_dn;
-	gsize n_subject_dn, n_issuer_dn;
+	EggBytes *subject_dn;
+	EggBytes *issuer_dn;
+	gboolean ret;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE);
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (issuer), FALSE);
 
-	subject_dn = _gcr_certificate_get_subject_const (issuer, &n_subject_dn);
+	subject_dn = _gcr_certificate_get_subject_const (issuer);
 	g_return_val_if_fail (subject_dn, FALSE);
 
-	issuer_dn = _gcr_certificate_get_issuer_const (self, &n_issuer_dn);
+	issuer_dn = _gcr_certificate_get_issuer_const (self);
 	g_return_val_if_fail (issuer_dn, FALSE);
 
-	return (n_issuer_dn == n_subject_dn &&
-	        memcmp (issuer_dn, subject_dn, n_issuer_dn) == 0);
+	ret = egg_bytes_equal (subject_dn, issuer_dn);
+
+	egg_bytes_unref (subject_dn);
+	egg_bytes_unref (issuer_dn);
+
+	return ret;
 }
 
 /**
@@ -663,18 +694,17 @@ gcr_certificate_get_subject_dn (GcrCertificate *self)
 	return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL));
 }
 
-static gconstpointer
-_gcr_certificate_get_subject_const (GcrCertificate *self, gsize *n_data)
+static EggBytes *
+_gcr_certificate_get_subject_const (GcrCertificate *self)
 {
 	GcrCertificateInfo *info;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
-	g_return_val_if_fail (n_data != NULL, NULL);
 
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
 
-	return egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", NULL), n_data);
+	return egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", NULL));
 }
 
 /**
@@ -692,17 +722,22 @@ _gcr_certificate_get_subject_const (GcrCertificate *self, gsize *n_data)
 guchar *
 gcr_certificate_get_subject_raw (GcrCertificate *self, gsize *n_data)
 {
-	GcrCertificateInfo *info;
-	gconstpointer data;
+	EggBytes *bytes;
+	guchar *result;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
 	g_return_val_if_fail (n_data != NULL, NULL);
 
-	info = certificate_info_load (self);
-	g_return_val_if_fail (info, NULL);
+	bytes = _gcr_certificate_get_subject_const (self);
+	if (bytes == NULL)
+		return NULL;
+
+	*n_data = egg_bytes_get_size (bytes);
+	result = g_memdup (egg_bytes_get_data (bytes), *n_data);
+
+	egg_bytes_unref (bytes);
 
-	data = _gcr_certificate_get_subject_const (self, n_data);
-	return g_memdup (data, data ? *n_data : 0);
+	return result;
 }
 
 /**
@@ -886,7 +921,8 @@ guchar *
 gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
 {
 	GcrCertificateInfo *info;
-	const guchar *serial;
+	EggBytes *bytes;
+	guchar *result;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
 	g_return_val_if_fail (n_length != NULL, NULL);
@@ -894,8 +930,14 @@ gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, NULL);
 
-	serial = egg_asn1x_get_integer_as_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL), n_length);
-	return g_memdup (serial, *n_length);
+	bytes = egg_asn1x_get_integer_as_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL));
+	g_return_val_if_fail (bytes != NULL, NULL);
+
+	*n_length = egg_bytes_get_size (bytes);
+	result = g_memdup (egg_bytes_get_data (bytes), *n_length);
+
+	egg_bytes_unref (bytes);
+	return result;
 }
 
 /**
diff --git a/gcr/gcr-fingerprint.c b/gcr/gcr-fingerprint.c
index 39d9319..c84b977 100644
--- a/gcr/gcr-fingerprint.c
+++ b/gcr/gcr-fingerprint.c
@@ -91,10 +91,11 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
 {
 	GckAttribute *modulus;
 	GckAttribute *exponent;
+	EggBytes *key;
+	EggBytes *params;
 	GNode *key_asn;
 	GNode *params_asn;
-	gpointer key, params;
-	gsize n_key, n_params;
+	EggBytes *usg;
 
 	_gcr_oids_init ();
 
@@ -109,27 +110,34 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
 	params_asn = egg_asn1x_create (pk_asn1_tab, "RSAParameters");
 	g_return_val_if_fail (params_asn, FALSE);
 
-	egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL),
-	                              modulus->value, modulus->length, NULL);
+	usg = egg_bytes_new_with_free_func (modulus->value, modulus->length,
+	                                    gck_attributes_unref,
+	                                    gck_attributes_ref (attrs));
+	egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL), usg);
+	egg_bytes_unref (usg);
 
-	egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL),
-	                              exponent->value, exponent->length, NULL);
+	usg = egg_bytes_new_with_free_func (exponent->value, exponent->length,
+	                                    gck_attributes_unref,
+	                                    gck_attributes_ref (attrs));
+	egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL), usg);
+	egg_bytes_unref (usg);
 
-	key = egg_asn1x_encode (key_asn, g_realloc, &n_key);
+	key = egg_asn1x_encode (key_asn, NULL);
 	egg_asn1x_destroy (key_asn);
 
 	egg_asn1x_set_null (params_asn);
 
-	params = egg_asn1x_encode (params_asn, g_realloc, &n_params);
+	params = egg_asn1x_encode (params_asn, g_realloc);
 	egg_asn1x_destroy (params_asn);
 
 	egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
-	                           key, n_key * 8, g_free);
+	                           key, egg_bytes_get_size (key) * 8);
 
 	egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA);
-	egg_asn1x_set_raw_element (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL),
-	                           params, n_params, g_free);
+	egg_asn1x_set_raw_element (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
 
+	egg_bytes_unref (key);
+	egg_bytes_unref (params);
 	return TRUE;
 }
 
@@ -161,7 +169,8 @@ dsa_subject_public_key_from_private (GNode *key_asn, GckAttribute *ap,
 
 	gcry = gcry_mpi_aprint (GCRYMPI_FMT_STD, &buffer, &n_buffer, my);
 	g_return_val_if_fail (gcry == 0, FALSE);
-	egg_asn1x_set_integer_as_raw (key_asn, buffer, n_buffer, gcry_free);
+	egg_asn1x_take_integer_as_raw (key_asn, egg_bytes_new_with_free_func (buffer, n_buffer,
+	                                                                      gcry_free, buffer));
 
 	gcry_mpi_release (mp);
 	gcry_mpi_release (mq);
@@ -179,8 +188,8 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
 {
 	GckAttribute *value, *g, *q, *p;
 	GNode *key_asn, *params_asn;
-	gpointer key, params;
-	gsize n_key, n_params;
+	EggBytes *key;
+	EggBytes *params;
 
 	_gcr_oids_init ();
 
@@ -198,9 +207,18 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
 	params_asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters");
 	g_return_val_if_fail (params_asn, FALSE);
 
-	egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL), p->value, p->length, NULL);
-	egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL), q->value, q->length, NULL);
-	egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL), g->value, g->length, NULL);
+	egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL),
+	                               egg_bytes_new_with_free_func (p->value, p->length,
+	                                                             gck_attributes_unref,
+	                                                             gck_attributes_ref (attrs)));
+	egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL),
+	                               egg_bytes_new_with_free_func (q->value, q->length,
+	                                                             gck_attributes_unref,
+	                                                             gck_attributes_ref (attrs)));
+	egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL),
+	                               egg_bytes_new_with_free_func (g->value, g->length,
+	                                                             gck_attributes_unref,
+	                                                             gck_attributes_ref (attrs)));
 
 	/* Are these attributes for a public or private key? */
 	if (klass == CKO_PRIVATE_KEY) {
@@ -210,25 +228,29 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
 			g_return_val_if_reached (FALSE);
 
 	} else if (klass == CKO_PUBLIC_KEY) {
-		egg_asn1x_set_integer_as_usg (key_asn, value->value, value->length, NULL);
+		egg_asn1x_take_integer_as_usg (key_asn,
+		                               egg_bytes_new_with_free_func (value->value, value->length,
+		                                                             gck_attributes_unref,
+		                                                             gck_attributes_ref (attrs)));
 
 	} else {
 		g_assert_not_reached ();
 	}
 
-	key = egg_asn1x_encode (key_asn, g_realloc, &n_key);
+	key = egg_asn1x_encode (key_asn, NULL);
 	egg_asn1x_destroy (key_asn);
 
-	params = egg_asn1x_encode (params_asn, g_realloc, &n_params);
+	params = egg_asn1x_encode (params_asn, NULL);
 	egg_asn1x_destroy (params_asn);
 
-	egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
-	                           key, n_key * 8, g_free);
-	egg_asn1x_set_raw_element (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL),
-	                           params, n_params, g_free);
+	egg_asn1x_take_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
+	                            key, egg_bytes_get_size (key) * 8);
+	egg_asn1x_set_raw_element (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
 
 	egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA);
 
+	egg_bytes_unref (key);
+	egg_bytes_unref (params);
 	return TRUE;
 }
 
@@ -241,9 +263,8 @@ fingerprint_from_key_attributes (GckAttributes *attrs,
 	gpointer fingerprint = NULL;
 	gboolean ret = FALSE;
 	GNode *info_asn;
-	gpointer info;
+	EggBytes *info;
 	gulong key_type;
-	gsize n_info;
 
 	if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &key_type))
 		return NULL;
@@ -261,11 +282,12 @@ fingerprint_from_key_attributes (GckAttributes *attrs,
 		ret = FALSE;
 
 	if (ret) {
-		info = egg_asn1x_encode (info_asn, g_realloc, &n_info);
-		fingerprint = gcr_fingerprint_from_subject_public_key_info (info, n_info,
+		info = egg_asn1x_encode (info_asn, NULL);
+		fingerprint = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (info),
+		                                                            egg_bytes_get_size (info),
 		                                                            checksum_type,
 		                                                            n_fingerprint);
-		g_free (info);
+		egg_bytes_unref (info);
 	}
 
 	egg_asn1x_destroy (info_asn);
@@ -273,25 +295,23 @@ fingerprint_from_key_attributes (GckAttributes *attrs,
 }
 
 static guchar *
-fingerprint_from_cert_value (const guchar *der_data,
-                             gsize n_der_data,
+fingerprint_from_cert_value (EggBytes *der_data,
                              GChecksumType checksum_type,
                              gsize *n_fingerprint)
 {
 	guchar *fingerprint;
 	GNode *cert_asn;
-	gconstpointer info;
-	gsize n_info;
+	EggBytes *info;
 
-	cert_asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate",
-	                                        der_data, n_der_data);
+	cert_asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", der_data);
 	if (cert_asn == NULL)
 		return NULL;
 
-	info = egg_asn1x_get_raw_element (egg_asn1x_node (cert_asn, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_info);
+	info = egg_asn1x_get_raw_element (egg_asn1x_node (cert_asn, "tbsCertificate", "subjectPublicKeyInfo", NULL));
 	g_return_val_if_fail (info != NULL, NULL);
 
-	fingerprint = gcr_fingerprint_from_subject_public_key_info (info, n_info,
+	fingerprint = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (info),
+	                                                            egg_bytes_get_size (info),
 	                                                            checksum_type,
 	                                                            n_fingerprint);
 
@@ -305,13 +325,20 @@ fingerprint_from_cert_attributes (GckAttributes *attrs,
                                   gsize *n_fingerprint)
 {
 	GckAttribute *attr;
+	EggBytes *bytes;
+	guchar *fingerprint;
 
 	attr = gck_attributes_find (attrs, CKA_VALUE);
 	if (attr == NULL)
 		return NULL;
 
-	return fingerprint_from_cert_value (attr->value, attr->length, checksum_type,
-	                                    n_fingerprint);
+	bytes = egg_bytes_new_with_free_func (attr->value, attr->length,
+	                                      gck_attributes_unref,
+	                                      gck_attributes_ref (attrs));
+	fingerprint = fingerprint_from_cert_value (bytes, checksum_type, n_fingerprint);
+
+	egg_bytes_unref (bytes);
+	return fingerprint;
 }
 
 /**
@@ -373,12 +400,18 @@ gcr_fingerprint_from_certificate_public_key (GcrCertificate *certificate,
 {
 	const guchar *der_data;
 	gsize n_der_data;
+	EggBytes *bytes;
+	guchar *fingerprint;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), NULL);
 
 	der_data = gcr_certificate_get_der_data (certificate, &n_der_data);
 	g_return_val_if_fail (der_data != NULL, NULL);
 
-	return fingerprint_from_cert_value (der_data, n_der_data, checksum_type,
-	                                    n_fingerprint);
+	bytes = egg_bytes_new_with_free_func (der_data, n_der_data, g_object_unref,
+	                                      g_object_ref (certificate));
+	fingerprint = fingerprint_from_cert_value (bytes, checksum_type, n_fingerprint);
+	egg_bytes_unref (bytes);
+
+	return fingerprint;
 }
diff --git a/gcr/gcr-openpgp.c b/gcr/gcr-openpgp.c
index 3bd41bb..b80f560 100644
--- a/gcr/gcr-openpgp.c
+++ b/gcr/gcr-openpgp.c
@@ -1197,6 +1197,7 @@ typedef struct {
 	GcrOpenpgpCallback callback;
 	gpointer user_data;
 	guint count;
+	EggBytes *backing;
 	GPtrArray *records;
 } openpgp_parse_closure;
 
@@ -1205,6 +1206,7 @@ openpgp_parse_free (gpointer data)
 {
 	openpgp_parse_closure *closure = data;
 	g_ptr_array_unref (closure->records);
+	egg_bytes_unref (closure->backing);
 	g_free (closure);
 }
 
@@ -1213,6 +1215,7 @@ maybe_emit_openpgp_block (openpgp_parse_closure *closure,
                           const guchar *block,
                           const guchar *end)
 {
+	EggBytes *outer;
 	gsize length;
 	GPtrArray *records;
 
@@ -1228,15 +1231,17 @@ maybe_emit_openpgp_block (openpgp_parse_closure *closure,
 	records = closure->records;
 	closure->records = g_ptr_array_new_with_free_func (_gcr_record_free);
 
+	outer = egg_bytes_new_with_free_func (block, length, egg_bytes_unref,
+	                                      egg_bytes_ref (closure->backing));
 	if (closure->callback)
-		(closure->callback) (records, block, length, closure->user_data);
+		(closure->callback) (records, outer, closure->user_data);
+	egg_bytes_unref (outer);
 
 	g_ptr_array_unref (records);
 }
 
 guint
-_gcr_openpgp_parse (gconstpointer data,
-                    gsize n_data,
+_gcr_openpgp_parse (EggBytes *data,
                     GcrOpenpgpParseFlags flags,
                     GcrOpenpgpCallback callback,
                     gpointer user_data)
@@ -1257,13 +1262,14 @@ _gcr_openpgp_parse (gconstpointer data,
 	/* For libgcrypt */
 	_gcr_initialize_library ();
 
-	at = data;
-	end = at + n_data;
+	at = egg_bytes_get_data (data);
+	end = at + egg_bytes_get_size (data);
 	block = NULL;
 
 	closure = g_new0 (openpgp_parse_closure, 1);
 	closure->callback = callback;
 	closure->user_data = user_data;
+	closure->backing = egg_bytes_ref (data);
 	closure->records = g_ptr_array_new_with_free_func (_gcr_record_free);
 
 	while (at != NULL && at != end) {
diff --git a/gcr/gcr-openpgp.h b/gcr/gcr-openpgp.h
index 31fd295..aed7d8d 100644
--- a/gcr/gcr-openpgp.h
+++ b/gcr/gcr-openpgp.h
@@ -30,6 +30,8 @@
 
 #include <glib.h>
 
+#include <egg/egg-bytes.h>
+
 #include <gck/gck.h>
 
 typedef enum {
@@ -51,12 +53,10 @@ typedef enum {
 G_BEGIN_DECLS
 
 typedef void             (*GcrOpenpgpCallback)             (GPtrArray *records,
-                                                            const guchar *outer,
-                                                            gsize n_outer,
+                                                            EggBytes *outer,
                                                             gpointer user_data);
 
-guint                    _gcr_openpgp_parse                (gconstpointer data,
-                                                            gsize n_data,
+guint                    _gcr_openpgp_parse                (EggBytes *data,
                                                             GcrOpenpgpParseFlags flags,
                                                             GcrOpenpgpCallback callback,
                                                             gpointer user_data);
diff --git a/gcr/gcr-openssh.c b/gcr/gcr-openssh.c
index 3a35c60..e8eef4a 100644
--- a/gcr/gcr-openssh.c
+++ b/gcr/gcr-openssh.c
@@ -154,6 +154,7 @@ atoin (const char *p, gint digits)
 static GcrDataError
 parse_v1_public_line (const gchar *line,
                       gsize length,
+                      EggBytes *backing,
                       GcrOpensshPubCallback callback,
                       gpointer user_data)
 {
@@ -161,6 +162,7 @@ parse_v1_public_line (const gchar *line,
 	gsize len_bits, len_exponent, len_modulus, len_options, n_outer;
 	GckAttributes *attrs;
 	gchar *label, *options;
+	EggBytes *bytes;
 	gint bits;
 
 	g_assert (line);
@@ -224,8 +226,13 @@ parse_v1_public_line (const gchar *line,
 	if (word_options)
 		options = g_strndup (word_options, len_options);
 
-	if (callback != NULL)
-		(callback) (attrs, label, options, outer, n_outer, user_data);
+	if (callback != NULL) {
+		bytes = egg_bytes_new_with_free_func (outer, n_outer,
+		                                      egg_bytes_unref,
+		                                      egg_bytes_ref (backing));
+		(callback) (attrs, label, options, bytes, user_data);
+		egg_bytes_unref (bytes);
+	}
 
 	gck_attributes_unref (attrs);
 	g_free (options);
@@ -367,6 +374,7 @@ decode_v2_public_key (gulong algo,
 static GcrDataError
 parse_v2_public_line (const gchar *line,
                       gsize length,
+                      EggBytes *backing,
                       GcrOpensshPubCallback callback,
                       gpointer user_data)
 {
@@ -377,6 +385,7 @@ parse_v2_public_line (const gchar *line,
 	gchar *label = NULL;
 	const gchar *outer = line;
 	gsize n_outer = length;
+	EggBytes *bytes;
 	gulong algo;
 
 	g_assert (line);
@@ -435,8 +444,13 @@ parse_v2_public_line (const gchar *line,
 		gck_attributes_add_string (attrs, CKA_LABEL, label);
 	}
 
-	if (callback != NULL)
-		(callback) (attrs, label, options, outer, n_outer, user_data);
+	if (callback != NULL) {
+		bytes = egg_bytes_new_with_free_func (outer, n_outer,
+		                                      egg_bytes_unref,
+		                                      egg_bytes_ref (backing));
+		(callback) (attrs, label, options, bytes, user_data);
+		egg_bytes_unref (bytes);
+	}
 
 	gck_attributes_unref (attrs);
 	g_free (options);
@@ -445,8 +459,7 @@ parse_v2_public_line (const gchar *line,
 }
 
 guint
-_gcr_openssh_pub_parse (gconstpointer data,
-                        gsize n_data,
+_gcr_openssh_pub_parse (EggBytes *data,
                         GcrOpensshPubCallback callback,
                         gpointer user_data)
 {
@@ -457,10 +470,10 @@ _gcr_openssh_pub_parse (gconstpointer data,
 	GcrDataError res;
 	guint num_parsed;
 
-	g_return_val_if_fail (data, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	line = data;
-	length = n_data;
+	line = egg_bytes_get_data (data);
+	length = egg_bytes_get_size (data);
 	last = FALSE;
 	num_parsed = 0;
 
@@ -472,9 +485,9 @@ _gcr_openssh_pub_parse (gconstpointer data,
 		}
 
 		if (line != end) {
-			res = parse_v2_public_line (line, end - line, callback, user_data);
+			res = parse_v2_public_line (line, end - line, data, callback, user_data);
 			if (res == GCR_ERROR_UNRECOGNIZED)
-				res = parse_v1_public_line (line, end - line, callback, user_data);
+				res = parse_v1_public_line (line, end - line, data, callback, user_data);
 			if (res == GCR_SUCCESS)
 				num_parsed++;
 		}
diff --git a/gcr/gcr-openssh.h b/gcr/gcr-openssh.h
index 2fdac2a..4f4fe9e 100644
--- a/gcr/gcr-openssh.h
+++ b/gcr/gcr-openssh.h
@@ -32,17 +32,17 @@
 
 #include <gck/gck.h>
 
+#include <egg/egg-bytes.h>
+
 G_BEGIN_DECLS
 
 typedef void             (*GcrOpensshPubCallback)          (GckAttributes *attrs,
                                                             const gchar *label,
                                                             const gchar *options,
-                                                            const gchar *outer,
-                                                            gsize n_outer,
+                                                            EggBytes *outer,
                                                             gpointer user_data);
 
-guint                    _gcr_openssh_pub_parse            (gconstpointer data,
-                                                            gsize n_data,
+guint                    _gcr_openssh_pub_parse            (EggBytes *data,
                                                             GcrOpensshPubCallback callback,
                                                             gpointer user_data);
 
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index 096bbfe..ebdc8a3 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -123,10 +123,8 @@ struct _GcrParsed {
 	GckAttributes *attrs;
 	const gchar *description;
 	gchar *label;
-	gpointer data;
-	gsize n_data;
+	EggBytes *data;
 	gboolean sensitive;
-	GDestroyNotify destroy_func;
 	GcrDataFormat format;
 	struct _GcrParsed *next;
 };
@@ -149,7 +147,7 @@ typedef struct {
 
 typedef struct _ParserFormat {
 	gint format_id;
-	gint (*function) (GcrParser *self, const guchar *data, gsize n_data);
+	gint (*function) (GcrParser *self, EggBytes *data);
 } ParserFormat;
 
 /* Forward declarations */
@@ -224,23 +222,35 @@ parsed_attribute (GcrParsed *parsed,
 	gck_attributes_add_data (parsed->attrs, type, data, n_data);
 }
 
+static void
+parsed_attribute_bytes (GcrParsed *parsed,
+                        CK_ATTRIBUTE_TYPE type,
+                        EggBytes *data)
+{
+	g_assert (parsed != NULL);
+	g_assert (parsed->attrs != NULL);
+	gck_attributes_add_data (parsed->attrs, type,
+	                         egg_bytes_get_data (data),
+	                         egg_bytes_get_size (data));
+}
+
 static gboolean
 parsed_asn1_number (GcrParsed *parsed,
                     GNode *asn,
                     const gchar *part,
                     CK_ATTRIBUTE_TYPE type)
 {
-	const guchar *value;
-	gsize n_value;
+	EggBytes *value;
 
 	g_assert (asn);
 	g_assert (parsed);
 
-	value = egg_asn1x_get_integer_as_usg (egg_asn1x_node (asn, part, NULL), &n_value);
+	value = egg_asn1x_get_integer_as_usg (egg_asn1x_node (asn, part, NULL));
 	if (value == NULL)
 		return FALSE;
 
-	parsed_attribute (parsed, type, value, n_value);
+	parsed_attribute_bytes (parsed, type, value);
+	egg_bytes_unref (value);
 	return TRUE;
 }
 
@@ -250,17 +260,17 @@ parsed_asn1_element (GcrParsed *parsed,
                      const gchar *part,
                      CK_ATTRIBUTE_TYPE type)
 {
-	const guchar *value;
-	gsize n_value;
+	EggBytes *value;
 
 	g_assert (asn);
 	g_assert (parsed);
 
-	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, part, NULL), &n_value);
+	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, part, NULL));
 	if (value == NULL)
 		return FALSE;
 
-	parsed_attribute (parsed, type, value, n_value);
+	parsed_attribute_bytes (parsed, type, value);
+	egg_bytes_unref (value);
 	return TRUE;
 }
 
@@ -288,19 +298,15 @@ parsed_boolean_attribute (GcrParsed *parsed,
 static void
 parsing_block (GcrParsed *parsed,
                gint format,
-               gconstpointer data,
-               gsize n_data)
+               EggBytes *data)
 {
 	g_assert (parsed != NULL);
 	g_assert (data != NULL);
-	g_assert (n_data != 0);
-	g_assert (format);
+	g_assert (format != 0);
 	g_assert (parsed->data == NULL);
-	g_assert (parsed->destroy_func == NULL);
 
 	parsed->format = format;
-	parsed->data = (gpointer)data;
-	parsed->n_data = n_data;
+	parsed->data = egg_bytes_ref (data);
 }
 
 static void
@@ -457,7 +463,8 @@ parsed_fire (GcrParser *self,
  */
 
 static gint
-parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_private_key_rsa (GcrParser *self,
+                           EggBytes *data)
 {
 	gint res = GCR_ERROR_UNRECOGNIZED;
 	GNode *asn = NULL;
@@ -466,11 +473,11 @@ parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
 
 	parsed = push_parsed (self, TRUE);
 
-	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;
 
-	parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data, n_data);
+	parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data);
 	parsing_object (parsed, CKO_PRIVATE_KEY);
 	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_RSA);
 	parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE);
@@ -511,7 +518,8 @@ done:
  */
 
 static gint
-parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_private_key_dsa (GcrParser *self,
+                           EggBytes *data)
 {
 	gint ret = GCR_ERROR_UNRECOGNIZED;
 	GNode *asn = NULL;
@@ -519,11 +527,11 @@ parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
 
 	parsed = push_parsed (self, TRUE);
 
-	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;
 
-	parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data, n_data);
+	parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data);
 	parsing_object (parsed, CKO_PRIVATE_KEY);
 	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_DSA);
 	parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE);
@@ -548,8 +556,9 @@ done:
 }
 
 static gint
-parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n_keydata,
-                                 const guchar *params, gsize n_params)
+parse_der_private_key_dsa_parts (GcrParser *self,
+                                 EggBytes *keydata,
+                                 EggBytes *params)
 {
 	gint ret = GCR_ERROR_UNRECOGNIZED;
 	GNode *asn_params = NULL;
@@ -558,8 +567,8 @@ parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n
 
 	parsed = push_parsed (self, TRUE);
 
-	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;
 
@@ -592,13 +601,14 @@ done:
  */
 
 static gint
-parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_private_key (GcrParser *self,
+                       EggBytes *data)
 {
 	gint res;
 
-	res = parse_der_private_key_rsa (self, data, n_data);
+	res = parse_der_private_key_rsa (self, data);
 	if (res == GCR_ERROR_UNRECOGNIZED)
-		res = parse_der_private_key_dsa (self, data, n_data);
+		res = parse_der_private_key_dsa (self, data);
 
 	return res;
 }
@@ -608,26 +618,25 @@ parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data)
  */
 
 static gint
-parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_pkcs8_plain (GcrParser *self,
+                       EggBytes *data)
 {
 	gint ret;
 	CK_KEY_TYPE key_type;
 	GQuark key_algo;
-	const guchar *keydata;
-	gsize n_keydata;
-	const guchar *params;
-	gsize n_params;
+	EggBytes *keydata = NULL;
+	EggBytes *params = NULL;
 	GNode *asn = NULL;
 	GcrParsed *parsed;
 
 	parsed = push_parsed (self, TRUE);
 	ret = GCR_ERROR_UNRECOGNIZED;
 
-	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;
 
-	parsing_block (parsed, GCR_FORMAT_DER_PKCS8_PLAIN, data, n_data);
+	parsing_block (parsed, GCR_FORMAT_DER_PKCS8_PLAIN, data);
 	ret = GCR_ERROR_FAILURE;
 	key_type = GCK_INVALID;
 
@@ -644,11 +653,11 @@ parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
   		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_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL));
 
 	ret = SUCCESS;
 
@@ -656,16 +665,15 @@ done:
 	if (ret == SUCCESS) {
 		switch (key_type) {
 		case CKK_RSA:
-			ret = parse_der_private_key_rsa (self, keydata, n_keydata);
+			ret = parse_der_private_key_rsa (self, keydata);
 			break;
 		case CKK_DSA:
 			/* Try the normal sane format */
-			ret = parse_der_private_key_dsa (self, keydata, n_keydata);
+			ret = parse_der_private_key_dsa (self, keydata);
 
 			/* Otherwise try the two part format that everyone seems to like */
-			if (ret == GCR_ERROR_UNRECOGNIZED && params && n_params)
-				ret = parse_der_private_key_dsa_parts (self, keydata, n_keydata,
-				                                       params, n_params);
+			if (ret == GCR_ERROR_UNRECOGNIZED && params)
+				ret = parse_der_private_key_dsa_parts (self, keydata, params);
 			break;
 		default:
 			g_message ("invalid or unsupported key type in PKCS#8 key");
@@ -677,13 +685,18 @@ done:
 		g_message ("invalid PKCS#8 key");
 	}
 
+	if (keydata)
+		egg_bytes_unref (keydata);
+	if (params)
+		egg_bytes_unref (params);
 	egg_asn1x_destroy (asn);
 	pop_parsed (self, parsed);
 	return ret;
 }
 
 static gint
-parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_pkcs8_encrypted (GcrParser *self,
+                           EggBytes *data)
 {
 	PasswordState pstate = PASSWORD_STATE_INIT;
 	GNode *asn = NULL;
@@ -692,8 +705,9 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 	gint ret, r;
 	GQuark scheme;
 	guchar *crypted = NULL;
-	const guchar *params;
-	gsize n_crypted, n_params;
+	EggBytes *params = NULL;
+	EggBytes *cbytes;
+	gsize n_crypted;
 	const gchar *password;
 	GcrParsed *parsed;
 	gint l;
@@ -701,11 +715,11 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 	parsed = push_parsed (self, FALSE);
 	ret = GCR_ERROR_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;
 
-	parsing_block (parsed, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data, n_data);
+	parsing_block (parsed, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data);
 	ret = GCR_ERROR_FAILURE;
 
 	/* Figure out the type of encryption */
@@ -713,7 +727,7 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 	if (!scheme)
 		goto done;
 
-	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params);
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL));
 
 	/* Loop to try different passwords */
 	for (;;) {
@@ -727,7 +741,7 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 		}
 
 		/* Parse the encryption stuff into a cipher. */
-		if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih))
+		if (!egg_symkey_read_cipher (scheme, password, -1, params, &cih))
 			break;
 
 		crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL), egg_secure_realloc, &n_crypted);
@@ -748,11 +762,14 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 		if (l > 0)
 			n_crypted = l;
 
-		/* Try to parse the resulting key */
-		r = parse_der_pkcs8_plain (self, crypted, n_crypted);
-		egg_secure_free (crypted);
+		cbytes = egg_bytes_new_with_free_func (crypted, n_crypted,
+		                                       egg_secure_free, crypted);
 		crypted = NULL;
 
+		/* Try to parse the resulting key */
+		r = parse_der_pkcs8_plain (self, cbytes);
+		egg_bytes_unref (cbytes);
+
 		if (r != GCR_ERROR_UNRECOGNIZED) {
 			ret = r;
 			break;
@@ -762,6 +779,8 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 	}
 
 done:
+	if (params)
+		egg_bytes_unref (params);
 	if (cih)
 		gcry_cipher_close (cih);
 	egg_asn1x_destroy (asn);
@@ -772,13 +791,14 @@ done:
 }
 
 static gint
-parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_pkcs8 (GcrParser *self,
+                 EggBytes *data)
 {
 	gint ret;
 
-	ret = parse_der_pkcs8_plain (self, data, n_data);
+	ret = parse_der_pkcs8_plain (self, data);
 	if (ret == GCR_ERROR_UNRECOGNIZED)
-		ret = parse_der_pkcs8_encrypted (self, data, n_data);
+		ret = parse_der_pkcs8_encrypted (self, data);
 
 	return ret;
 }
@@ -788,20 +808,21 @@ parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data)
  */
 
 static gint
-parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_certificate (GcrParser *self,
+                       EggBytes *data)
 {
 	gchar *name = NULL;
 	GcrParsed *parsed;
 	GNode *node;
 	GNode *asn;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data);
 	if (asn == NULL)
 		return GCR_ERROR_UNRECOGNIZED;
 
 	parsed = push_parsed (self, FALSE);
 
-	parsing_block (parsed, GCR_FORMAT_DER_CERTIFICATE_X509, data, n_data);
+	parsing_block (parsed, GCR_FORMAT_DER_CERTIFICATE_X509, data);
 	parsing_object (parsed, CKO_CERTIFICATE);
 	parsed_ulong_attribute (parsed, CKA_CERTIFICATE_TYPE, CKC_X_509);
 
@@ -816,7 +837,7 @@ parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
 		g_free (name);
 	}
 
-	parsed_attribute (parsed, CKA_VALUE, data, n_data);
+	parsed_attribute_bytes (parsed, CKA_VALUE, data);
 	parsed_asn1_element (parsed, node, "subject", CKA_SUBJECT);
 	parsed_asn1_element (parsed, node, "issuer", CKA_ISSUER);
 	parsed_asn1_number (parsed, node, "serialNumber", CKA_SERIAL_NUMBER);
@@ -833,18 +854,18 @@ parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
  */
 
 static gint
-handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
+handle_pkcs7_signed_data (GcrParser *self,
+                          EggBytes *data)
 {
 	GNode *asn = NULL;
 	GNode *node;
 	gint ret;
-	const guchar *certificate;
-	gsize n_certificate;
+	EggBytes *certificate;
 	int i;
 
 	ret = GCR_ERROR_UNRECOGNIZED;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data);
 	if (!asn)
 		goto done;
 
@@ -858,9 +879,10 @@ handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
 		if (node == NULL)
 			break;
 
-		certificate = egg_asn1x_get_raw_element (node, &n_certificate);
+		certificate = egg_asn1x_get_raw_element (node);
+		ret = parse_der_certificate (self, certificate);
+		egg_bytes_unref (certificate);
 
-		ret = parse_der_certificate (self, certificate, n_certificate);
 		if (ret != SUCCESS)
 			goto done;
 	}
@@ -875,24 +897,24 @@ done:
 }
 
 static gint
-parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_pkcs7 (GcrParser *self,
+                 EggBytes *data)
 {
 	GNode *asn = NULL;
 	GNode *node;
 	gint ret;
-	const guchar* content = NULL;
-	gsize n_content;
+	EggBytes *content = NULL;
 	GQuark oid;
 	GcrParsed *parsed;
 
 	parsed = push_parsed (self, FALSE);
 	ret = GCR_ERROR_UNRECOGNIZED;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-ContentInfo", data, n_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-ContentInfo", data);
 	if (!asn)
 		goto done;
 
-	parsing_block (parsed, GCR_FORMAT_DER_PKCS7, data, n_data);
+	parsing_block (parsed, GCR_FORMAT_DER_PKCS7, data);
 	ret = GCR_ERROR_FAILURE;
 
 	node = egg_asn1x_node (asn, "contentType", NULL);
@@ -908,13 +930,15 @@ parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
 		goto done;
 	}
 
-	content = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "content", NULL), &n_content);
+	content = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "content", NULL));
 	if (!content)
 		goto done;
 
-	ret = handle_pkcs7_signed_data (self, content, n_content);
+	ret = handle_pkcs7_signed_data (self, content);
 
 done:
+	if (content)
+		egg_bytes_unref (content);
 	egg_asn1x_destroy (asn);
 	pop_parsed (self, parsed);
 	return ret;
@@ -927,8 +951,7 @@ done:
 static GNode *
 decode_pkcs12_asn1_accepting_invalid_crap (const ASN1_ARRAY_TYPE *defs,
                                            const gchar *identifier,
-                                           gconstpointer data,
-                                           gsize n_data)
+                                           EggBytes *data)
 {
 	GNode *asn;
 
@@ -947,7 +970,7 @@ decode_pkcs12_asn1_accepting_invalid_crap (const ASN1_ARRAY_TYPE *defs,
 	g_return_val_if_fail (asn != NULL, NULL);
 
 	/* Passing FALSE as the strictness argument */
-	if (!egg_asn1x_decode_no_validate (asn, data, n_data) ||
+	if (!egg_asn1x_decode_no_validate (asn, data) ||
 	    !egg_asn1x_validate (asn, FALSE)) {
 		egg_asn1x_destroy (asn);
 		asn = NULL;
@@ -957,29 +980,31 @@ decode_pkcs12_asn1_accepting_invalid_crap (const ASN1_ARRAY_TYPE *defs,
 }
 
 static gint
-handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data)
+handle_pkcs12_cert_bag (GcrParser *self,
+                        EggBytes *data)
 {
 	GNode *asn = NULL;
 	GNode *asn_content = NULL;
 	guchar *certificate = NULL;
-	const guchar *element;
-	gsize n_certificate, n_element;
+	EggBytes *element = NULL;
+	gsize n_certificate;
+	EggBytes *bytes;
 	gint ret;
 
 	ret = GCR_ERROR_UNRECOGNIZED;
 	asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
 	                                                 "pkcs-12-CertBag",
-	                                                 data, n_data);
+	                                                 data);
 	if (!asn)
 		goto done;
 
 	ret = GCR_ERROR_FAILURE;
 
-	element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "certValue", NULL), &n_element);
+	element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "certValue", NULL));
 	if (!element)
 		goto done;
 
-	asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element);
+	asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element);
 	if (!asn_content)
 		goto done;
 
@@ -987,12 +1012,15 @@ handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data)
 	if (!certificate)
 		goto done;
 
-	ret = parse_der_certificate (self, certificate, n_certificate);
+	bytes = egg_bytes_new_take (certificate, n_certificate);
+	ret = parse_der_certificate (self, bytes);
+	egg_bytes_unref (bytes);
 
 done:
+	if (element)
+		egg_bytes_unref (element);
 	egg_asn1x_destroy (asn_content);
 	egg_asn1x_destroy (asn);
-	g_free (certificate);
 	return ret;
 }
 
@@ -1002,8 +1030,7 @@ parse_pkcs12_bag_friendly_name (GNode *asn)
 	guint count, i;
 	GQuark oid;
 	GNode *node;
-	gconstpointer element;
-	gsize n_element;
+	EggBytes *element;
 	GNode *asn_str;
 	gchar *result;
 
@@ -1016,9 +1043,10 @@ parse_pkcs12_bag_friendly_name (GNode *asn)
 		if (oid == GCR_OID_PKCS9_ATTRIBUTE_FRIENDLY) {
 			node = egg_asn1x_node (asn, i, "values", 1, NULL);
 			if (node != NULL) {
-				element = egg_asn1x_get_raw_element (node, &n_element);
+				element = egg_asn1x_get_raw_element (node);
 				asn_str = egg_asn1x_create_and_decode (pkix_asn1_tab, "BMPString",
-				                                       element, n_element);
+				                                       element);
+				egg_bytes_unref (element);
 				if (asn_str) {
 					result = egg_asn1x_get_bmpstring_as_utf8 (asn_str);
 					egg_asn1x_destroy (asn_str);
@@ -1032,15 +1060,15 @@ parse_pkcs12_bag_friendly_name (GNode *asn)
 }
 
 static gint
-handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
+handle_pkcs12_bag (GcrParser *self,
+                   EggBytes *data)
 {
 	GNode *asn = NULL;
 	gint ret, r;
 	guint count = 0;
 	GQuark oid;
-	const guchar *element;
+	EggBytes *element = NULL;
 	gchar *friendly;
-	gsize n_element;
 	guint i;
 	GcrParsed *parsed;
 
@@ -1048,7 +1076,7 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
 
 	asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
 	                                                 "pkcs-12-SafeContents",
-	                                                 data, n_data);
+	                                                 data);
 	if (!asn)
 		goto done;
 
@@ -1067,7 +1095,7 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
 		if (!oid)
 			goto done;
 
-		element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, i, "bagValue", NULL), &n_element);
+		element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, i, "bagValue", NULL));
 		if (!element)
 			goto done;
 
@@ -1079,21 +1107,24 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
 
 		/* A normal unencrypted key */
 		if (oid == GCR_OID_PKCS12_BAG_PKCS8_KEY) {
-			r = parse_der_pkcs8_plain (self, element, n_element);
+			r = parse_der_pkcs8_plain (self, element);
 
 		/* A properly encrypted key */
 		} else if (oid == GCR_OID_PKCS12_BAG_PKCS8_ENCRYPTED_KEY) {
-			r = parse_der_pkcs8_encrypted (self, element, n_element);
+			r = parse_der_pkcs8_encrypted (self, element);
 
 		/* A certificate */
 		} else if (oid == GCR_OID_PKCS12_BAG_CERTIFICATE) {
-			r = handle_pkcs12_cert_bag (self, element, n_element);
+			r = handle_pkcs12_cert_bag (self, element);
 
 		/* TODO: GCR_OID_PKCS12_BAG_CRL */
 		} else {
 			r = GCR_ERROR_UNRECOGNIZED;
 		}
 
+		if (element != NULL)
+			egg_bytes_unref (element);
+
 		pop_parsed (self, parsed);
 
 		if (r == GCR_ERROR_FAILURE ||
@@ -1112,16 +1143,18 @@ done:
 }
 
 static gint
-handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
+handle_pkcs12_encrypted_bag (GcrParser *self,
+                             EggBytes *data)
 {
 	PasswordState pstate = PASSWORD_STATE_INIT;
 	GNode *asn = NULL;
 	gcry_cipher_hd_t cih = NULL;
 	gcry_error_t gcry;
 	guchar *crypted = NULL;
-	const guchar *params;
-	gsize n_params, n_crypted;
+	EggBytes *params = NULL;
+	gsize n_crypted;
 	const gchar *password;
+	EggBytes *cbytes;
 	GQuark scheme;
 	gint ret, r;
 	gint l;
@@ -1130,7 +1163,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 
 	asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
 	                                                 "pkcs-7-EncryptedData",
-	                                                 data, n_data);
+	                                                 data);
 	if (!asn)
 		goto done;
 
@@ -1141,7 +1174,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 	if (!scheme)
 		goto done;
 
-	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL), &n_params);
+	params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL));
 	if (!params)
 		goto done;
 
@@ -1157,7 +1190,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 		}
 
 		/* Parse the encryption stuff into a cipher. */
-		if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih)) {
+		if (!egg_symkey_read_cipher (scheme, password, -1, params, &cih)) {
 			ret = GCR_ERROR_FAILURE;
 			goto done;
 		}
@@ -1181,11 +1214,13 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 		if (l > 0)
 			n_crypted = l;
 
-		/* Try to parse the resulting key */
-		r = handle_pkcs12_bag (self, crypted, n_crypted);
-		egg_secure_free (crypted);
+		cbytes = egg_bytes_new_with_free_func (crypted, n_crypted, egg_secure_free, crypted);
 		crypted = NULL;
 
+		/* Try to parse the resulting key */
+		r = handle_pkcs12_bag (self, cbytes);
+		egg_bytes_unref (cbytes);
+
 		if (r != GCR_ERROR_UNRECOGNIZED) {
 			ret = r;
 			break;
@@ -1195,6 +1230,8 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 	}
 
 done:
+	if (params)
+		egg_bytes_unref (params);
 	if (cih)
 		gcry_cipher_close (cih);
 	egg_asn1x_destroy (asn);
@@ -1203,14 +1240,14 @@ done:
 }
 
 static gint
-handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
+handle_pkcs12_safe (GcrParser *self,
+                    EggBytes *data)
 {
 	GNode *asn = NULL;
 	GNode *asn_content = NULL;
 	gint ret, r;
-	const guchar *bag;
-	guchar *content = NULL;
-	gsize n_bag, n_content;
+	EggBytes *bag;
+	EggBytes *content;
 	GQuark oid;
 	guint i;
 	GNode *node;
@@ -1219,7 +1256,7 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 
 	asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
 	                                                 "pkcs-12-AuthenticatedSafe",
-	                                                 data, n_data);
+	                                                 data);
 	if (!asn)
 		goto done;
 
@@ -1241,8 +1278,8 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 		if (!node)
 			goto done;
 
-		bag = egg_asn1x_get_raw_element (node, &n_bag);
-		g_return_val_if_fail (bag, ret);
+		bag = egg_asn1x_get_raw_element (node);
+		g_return_val_if_fail (bag != NULL, ret);
 
 		/* A non encrypted bag, just parse */
 		if (oid == GCR_OID_PKCS7_DATA) {
@@ -1250,20 +1287,20 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 			egg_asn1x_destroy (asn_content);
 			asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
 			                                                         "pkcs-7-Data",
-			                                                         bag, n_bag);
+			                                                         bag);
 			if (!asn_content)
 				goto done;
 
-			g_free (content);
-			content = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_content);
+			content = egg_asn1x_get_string_as_bytes (asn_content);
 			if (!content)
 				goto done;
 
-			r = handle_pkcs12_bag (self, content, n_content);
+			r = handle_pkcs12_bag (self, content);
+			egg_bytes_unref (content);
 
 		/* Encrypted data first needs decryption */
 		} else if (oid == GCR_OID_PKCS7_ENCRYPTED_DATA) {
-			r = handle_pkcs12_encrypted_bag (self, bag, n_bag);
+			r = handle_pkcs12_encrypted_bag (self, bag);
 
 		/* Hmmmm, not sure what this is */
 		} else {
@@ -1271,6 +1308,9 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 			r = GCR_ERROR_UNRECOGNIZED;
 		}
 
+		egg_bytes_unref (bag);
+		bag = NULL;
+
 		if (r == GCR_ERROR_FAILURE ||
 		    r == GCR_ERROR_CANCELLED ||
 		    r == GCR_ERROR_LOCKED) {
@@ -1282,17 +1322,17 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 	ret = SUCCESS;
 
 done:
+	if (bag != NULL)
+		egg_bytes_unref (bag);
 	egg_asn1x_destroy (asn);
 	egg_asn1x_destroy (asn_content);
-	g_free (content);
 	return ret;
 }
 
 static gint
 verify_pkcs12_safe (GcrParser *self,
                     GNode *asn,
-                    gconstpointer content,
-                    gsize n_content)
+                    EggBytes *content)
 {
 	PasswordState pstate = PASSWORD_STATE_INIT;
 	const gchar *password;
@@ -1303,8 +1343,7 @@ verify_pkcs12_safe (GcrParser *self,
 	gsize n_digest;
 	GQuark algorithm;
 	GNode *mac_data;
-	gconstpointer params;
-	gsize n_params;
+	EggBytes *params = NULL;
 	int ret, r;
 
 	ret = GCR_ERROR_FAILURE;
@@ -1323,7 +1362,7 @@ verify_pkcs12_safe (GcrParser *self,
 	if (!algorithm)
 		goto done;
 
-	params = egg_asn1x_get_raw_element (mac_data, &n_params);
+	params = egg_asn1x_get_raw_element (mac_data);
 	if (!params)
 		goto done;
 
@@ -1342,8 +1381,7 @@ verify_pkcs12_safe (GcrParser *self,
 		}
 
 		/* Parse the encryption stuff into a cipher. */
-		if (!egg_symkey_read_mac (algorithm, password, -1, params, n_params,
-		                          &mdh, &mac_len)) {
+		if (!egg_symkey_read_mac (algorithm, password, -1, params, &mdh, &mac_len)) {
 			ret = GCR_ERROR_FAILURE;
 			goto done;
 		}
@@ -1353,7 +1391,7 @@ verify_pkcs12_safe (GcrParser *self,
 			r = GCR_ERROR_FAILURE;
 
 		} else {
-			gcry_md_write (mdh, content, n_content);
+			gcry_md_write (mdh, egg_bytes_get_data (content), egg_bytes_get_size (content));
 			mac_digest = gcry_md_read (mdh, 0);
 			g_return_val_if_fail (mac_digest, GCR_ERROR_FAILURE);
 			r = memcmp (mac_digest, digest, n_digest) == 0 ? SUCCESS : GCR_ERROR_LOCKED;
@@ -1369,6 +1407,8 @@ verify_pkcs12_safe (GcrParser *self,
 	}
 
 done:
+	if (params)
+		egg_bytes_unref (params);
 	if (mdh)
 		gcry_md_close (mdh);
 	g_free (digest);
@@ -1377,26 +1417,25 @@ done:
 }
 
 static gint
-parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
+parse_der_pkcs12 (GcrParser *self,
+                  EggBytes *data)
 {
 	GNode *asn = NULL;
 	GNode *asn_content = NULL;
 	gint ret;
-	const guchar* element = NULL;
-	guchar *content = NULL;
-	gsize n_element, n_content;
+	EggBytes *element = NULL;
+	EggBytes *content = NULL;
 	GQuark oid;
 	GcrParsed *parsed;
 
 	parsed = push_parsed (self, FALSE);
 	ret = GCR_ERROR_UNRECOGNIZED;
 
-	asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-12-PFX",
-	                                                 data, n_data);
+	asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-12-PFX", data);
 	if (!asn)
 		goto done;
 
-	parsing_block (parsed, GCR_FORMAT_DER_PKCS12, data, n_data);
+	parsing_block (parsed, GCR_FORMAT_DER_PKCS12, data);
 
 	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "authSafe", "contentType", NULL));
 	if (!oid)
@@ -1408,25 +1447,27 @@ parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
 		goto done;
 	}
 
-	element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "authSafe", "content", NULL), &n_element);
+	element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "authSafe", "content", NULL));
 	if (!element)
 		goto done;
 
-	asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-7-Data",
-	                                                         element, n_element);
+	asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-7-Data", element);
 	if (!asn_content)
 		goto done;
 
-	content = egg_asn1x_get_string_as_raw (asn_content, g_realloc, &n_content);
+	content = egg_asn1x_get_string_as_bytes (asn_content);
 	if (!content)
 		goto done;
 
-	ret = verify_pkcs12_safe (self, asn, content, n_content);
+	ret = verify_pkcs12_safe (self, asn, content);
 	if (ret == SUCCESS)
-		ret = handle_pkcs12_safe (self, content, n_content);
+		ret = handle_pkcs12_safe (self, content);
 
 done:
-	g_free (content);
+	if (element)
+		egg_bytes_unref (element);
+	if (content)
+		egg_bytes_unref (content);
 	egg_asn1x_destroy (asn_content);
 	egg_asn1x_destroy (asn);
 	pop_parsed (self, parsed);
@@ -1440,8 +1481,7 @@ done:
 
 static void
 on_openpgp_packet (GPtrArray *records,
-                   const guchar *outer,
-                   gsize n_outer,
+                   EggBytes *outer,
                    gpointer user_data)
 {
 	GcrParser *self = GCR_PARSER (user_data);
@@ -1458,7 +1498,7 @@ on_openpgp_packet (GPtrArray *records,
 	parsed = push_parsed (self, FALSE);
 
 	/* All we can do is the packet bounds */
-	parsing_block (parsed, GCR_FORMAT_OPENPGP_PACKET, outer, n_outer);
+	parsing_block (parsed, GCR_FORMAT_OPENPGP_PACKET, outer);
 	parsing_object (parsed, CKO_GCR_GNUPG_RECORDS);
 	string = _gcr_records_format (records);
 	parsed_attribute (parsed, CKA_VALUE, string, strlen (string));
@@ -1470,12 +1510,11 @@ on_openpgp_packet (GPtrArray *records,
 
 static gint
 parse_openpgp_packets (GcrParser *self,
-                       const guchar *data,
-                       gsize n_data)
+                       EggBytes *data)
 {
 	gint num_parsed;
 
-	num_parsed = _gcr_openpgp_parse (data, n_data,
+	num_parsed = _gcr_openpgp_parse (data,
 	                                 GCR_OPENPGP_PARSE_KEYS |
 	                                 GCR_OPENPGP_PARSE_ATTRIBUTES |
 	                                 GCR_OPENPGP_PARSE_SIGNATURES,
@@ -1542,8 +1581,7 @@ static gint
 handle_plain_pem (GcrParser *self,
                   gint format_id,
                   gint want_format,
-                  const guchar *data,
-                  gsize n_data)
+                  EggBytes *data)
 {
 	ParserFormat *format;
 
@@ -1554,7 +1592,7 @@ handle_plain_pem (GcrParser *self,
 	if (format == NULL)
 		return GCR_ERROR_UNRECOGNIZED;
 
-	return (format->function) (self, data, n_data);
+	return (format->function) (self, data);
 }
 
 static gint
@@ -1562,15 +1600,14 @@ handle_encrypted_pem (GcrParser *self,
                       gint format_id,
                       gint want_format,
                       GHashTable *headers,
-                      const guchar *data,
-                      gsize n_data)
+                      EggBytes *data)
 {
 	PasswordState pstate = PASSWORD_STATE_INIT;
 	const gchar *password;
 	guchar *decrypted;
 	gsize n_decrypted;
 	const gchar *val;
-	gboolean ret;
+	EggBytes *dbytes;
 	gint res;
 	gint l;
 
@@ -1590,28 +1627,25 @@ handle_encrypted_pem (GcrParser *self,
 		if (res != SUCCESS)
 			break;
 
-		decrypted = NULL;
-		n_decrypted = 0;
-
 		/* Decrypt, this will result in garble if invalid password */
-		ret = egg_openssl_decrypt_block (val, password, -1, data, n_data,
-		                                 &decrypted, &n_decrypted);
-		if (!ret) {
+		decrypted = egg_openssl_decrypt_block (val, password, -1, data, &n_decrypted);
+		if (!decrypted) {
 			res = GCR_ERROR_FAILURE;
 			break;
 		}
 
-		g_assert (decrypted);
-
 		/* Unpad the DER data */
 		l = egg_asn1x_element_length (decrypted, n_decrypted);
 		if (l > 0)
 			n_decrypted = l;
 
+		dbytes = egg_bytes_new_with_free_func (decrypted, n_decrypted,
+		                                       egg_secure_free, decrypted);
+		decrypted = NULL;
+
 		/* Try to parse */
-		res = handle_plain_pem (self, format_id, want_format,
-		                        decrypted, n_decrypted);
-		egg_secure_free (decrypted);
+		res = handle_plain_pem (self, format_id, want_format, dbytes);
+		egg_bytes_unref (dbytes);
 
 		/* Unrecognized is a bad password */
 		if (res != GCR_ERROR_UNRECOGNIZED)
@@ -1629,10 +1663,8 @@ typedef struct {
 
 static void
 handle_pem_data (GQuark type,
-                 const guchar *data,
-                 gsize n_data,
-                 const gchar *outer,
-                 gsize n_outer,
+                 EggBytes *data,
+                 EggBytes *outer,
                  GHashTable *headers,
                  gpointer user_data)
 {
@@ -1654,7 +1686,7 @@ handle_pem_data (GQuark type,
 	parsed = push_parsed (args->parser, FALSE);
 
 	/* Fill in information necessary for prompting */
-	parsing_block (parsed, outer_format, outer, n_outer);
+	parsing_block (parsed, outer_format, outer);
 
 	/* See if it's encrypted PEM all openssl like*/
 	if (headers) {
@@ -1666,10 +1698,10 @@ handle_pem_data (GQuark type,
 	if (encrypted)
 		res = handle_encrypted_pem (args->parser, inner_format,
 		                            args->want_format, headers,
-		                            data, n_data);
+		                            data);
 	else
 		res = handle_plain_pem (args->parser, inner_format,
-		                        args->want_format, data, n_data);
+		                        args->want_format, data);
 
 	pop_parsed (args->parser, parsed);
 
@@ -1682,15 +1714,17 @@ handle_pem_data (GQuark type,
 }
 
 static gint
-handle_pem_format (GcrParser *self, gint subformat, const guchar *data, gsize n_data)
+handle_pem_format (GcrParser *self,
+                   gint subformat,
+                   EggBytes *data)
 {
 	HandlePemArgs ctx = { self, GCR_ERROR_UNRECOGNIZED, subformat };
 	guint found;
 
-	if (n_data == 0)
+	if (egg_bytes_get_size (data) == 0)
 		return GCR_ERROR_UNRECOGNIZED;
 
-	found = egg_armor_parse (data, n_data, handle_pem_data, &ctx);
+	found = egg_armor_parse (data, handle_pem_data, &ctx);
 
 	if (found == 0)
 		return GCR_ERROR_UNRECOGNIZED;
@@ -1700,59 +1734,66 @@ handle_pem_format (GcrParser *self, gint subformat, const guchar *data, gsize n_
 
 
 static gint
-parse_pem (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem (GcrParser *self,
+           EggBytes *data)
 {
-	return handle_pem_format (self, 0, data, n_data);
+	return handle_pem_format (self, 0, data);
 }
 
 static gint
-parse_pem_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem_private_key_rsa (GcrParser *self,
+                           EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data);
 }
 
 static gint
-parse_pem_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem_private_key_dsa (GcrParser *self,
+                           EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data);
 }
 
 static gint
-parse_pem_certificate (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem_certificate (GcrParser *self,
+                       EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_DER_CERTIFICATE_X509, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_DER_CERTIFICATE_X509, data);
 }
 
 static gint
-parse_pem_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem_pkcs8_plain (GcrParser *self,
+                       EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_PLAIN, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_PLAIN, data);
 }
 
 static gint
-parse_pem_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem_pkcs8_encrypted (GcrParser *self,
+                           EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data);
 }
 
 static gint
-parse_pem_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem_pkcs7 (GcrParser *self,
+                 EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_DER_PKCS7, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_DER_PKCS7, data);
 }
 
 static gint
-parse_pem_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
+parse_pem_pkcs12 (GcrParser *self,
+                  EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_DER_PKCS12, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_DER_PKCS12, data);
 }
 
 static gint
 parse_openpgp_armor (GcrParser *self,
-                     const guchar *data,
-                     gsize n_data)
+                     EggBytes *data)
 {
-	return handle_pem_format (self, GCR_FORMAT_OPENPGP_PACKET, data, n_data);
+	return handle_pem_format (self, GCR_FORMAT_OPENPGP_PACKET, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -1763,15 +1804,14 @@ static void
 on_openssh_public_key_parsed (GckAttributes *attrs,
                               const gchar *label,
                               const gchar *options,
-                              const gchar *outer,
-                              gsize n_outer,
+                              EggBytes *outer,
                               gpointer user_data)
 {
 	GcrParser *self = GCR_PARSER (user_data);
 	GcrParsed *parsed;
 
 	parsed = push_parsed (self, FALSE);
-	parsing_block (parsed, GCR_FORMAT_OPENSSH_PUBLIC, outer, n_outer);
+	parsing_block (parsed, GCR_FORMAT_OPENSSH_PUBLIC, outer);
 	parsed_attributes (parsed, attrs);
 	parsed_label (parsed, label);
 	parsed_fire (self, parsed);
@@ -1780,13 +1820,11 @@ on_openssh_public_key_parsed (GckAttributes *attrs,
 
 static gint
 parse_openssh_public (GcrParser *self,
-                      const guchar *data,
-                      gsize n_data)
+                      EggBytes *data)
 {
 	guint num_parsed;
 
-	num_parsed = _gcr_openssh_pub_parse (data, n_data,
-	                                     on_openssh_public_key_parsed, self);
+	num_parsed = _gcr_openssh_pub_parse (data, on_openssh_public_key_parsed, self);
 
 	if (num_parsed == 0)
 		return GCR_ERROR_UNRECOGNIZED;
@@ -1896,8 +1934,7 @@ compare_pointers (gconstpointer a, gconstpointer b)
 
 typedef struct _ForeachArgs {
 	GcrParser *parser;
-	const guchar *data;
-	gsize n_data;
+	EggBytes *data;
 	gint result;
 } ForeachArgs;
 
@@ -1912,7 +1949,7 @@ parser_format_foreach (gpointer key, gpointer value, gpointer data)
 	g_assert (format->function);
 	g_assert (GCR_IS_PARSER (args->parser));
 
-	result = (format->function) (args->parser, args->data, args->n_data);
+	result = (format->function) (args->parser, args->data);
 	if (result != GCR_ERROR_UNRECOGNIZED) {
 		args->result = result;
 		return TRUE;
@@ -2147,7 +2184,7 @@ gcr_parser_parse_data (GcrParser *self,
                        gsize n_data,
                        GError **error)
 {
-	ForeachArgs args = { self, data, n_data, GCR_ERROR_UNRECOGNIZED };
+	ForeachArgs args = { self, NULL, GCR_ERROR_UNRECOGNIZED };
 	const gchar *message = NULL;
 	gint i;
 
@@ -2156,6 +2193,9 @@ gcr_parser_parse_data (GcrParser *self,
 	g_return_val_if_fail (!error || !*error, FALSE);
 
 	if (data && n_data) {
+		/* TODO: Once GBytes is in the API, copy here */
+		args.data = egg_bytes_new_static (data, n_data);
+
 		/* Just the specific formats requested */
 		if (self->pv->specific_formats) {
 			g_tree_foreach (self->pv->specific_formats, parser_format_foreach, &args);
@@ -2343,15 +2383,7 @@ gcr_parsed_ref (GcrParsed *parsed)
 	/* Find the block of data to copy */
 	while (parsed != NULL) {
 		if (parsed->data != NULL) {
-			if (parsed->sensitive) {
-				copy->data = egg_secure_alloc (parsed->n_data);
-				memcpy (copy->data, parsed->data, parsed->n_data);
-				copy->destroy_func = egg_secure_free;
-			} else {
-				copy->data = g_memdup (parsed->data, parsed->n_data);
-				copy->destroy_func = g_free;
-			}
-			copy->n_data = parsed->n_data;
+			copy->data = egg_bytes_ref (parsed->data);
 			break;
 		}
 		parsed = parsed->next;
@@ -2377,8 +2409,8 @@ gcr_parsed_unref (gpointer parsed)
 		if (par->attrs)
 			gck_attributes_unref (par->attrs);
 		g_free (par->label);
-		if (par->destroy_func)
-			(par->destroy_func) (par->data);
+		if (par->data)
+			egg_bytes_unref (par->data);
 		g_free (par);
 	}
 }
@@ -2542,8 +2574,8 @@ gcr_parsed_get_data (GcrParsed *parsed,
 
 	while (parsed != NULL) {
 		if (parsed->data != NULL) {
-			*n_data = parsed->n_data;
-			return parsed->data;
+			*n_data = egg_bytes_get_size (parsed->data);
+			return egg_bytes_get_data (parsed->data);
 		}
 		parsed = parsed->next;
 	}
diff --git a/gcr/tests/frob-openpgp.c b/gcr/tests/frob-openpgp.c
index b83305a..46748f6 100644
--- a/gcr/tests/frob-openpgp.c
+++ b/gcr/tests/frob-openpgp.c
@@ -31,8 +31,7 @@
 
 static void
 on_packet_print_records (GPtrArray *records,
-                         const guchar *packet,
-                         gsize n_packet,
+                         EggBytes *packet,
                          gpointer user_data)
 {
 	gchar *string;
@@ -46,12 +45,11 @@ on_packet_print_records (GPtrArray *records,
 }
 
 static gboolean
-parse_binary (gconstpointer contents,
-              gsize length)
+parse_binary (EggBytes *contents)
 {
 	guint packets;
 
-	packets = _gcr_openpgp_parse (contents, length,
+	packets = _gcr_openpgp_parse (contents,
 	                              GCR_OPENPGP_PARSE_KEYS |
 	                              GCR_OPENPGP_PARSE_ATTRIBUTES,
 	                              on_packet_print_records, NULL);
@@ -61,10 +59,8 @@ parse_binary (gconstpointer contents,
 
 static void
 on_armor_parsed (GQuark type,
-                 const guchar *data,
-                 gsize n_data,
-                 const gchar *outer,
-                 gsize n_outer,
+                 EggBytes *data,
+                 EggBytes *outer,
                  GHashTable *headers,
                  gpointer user_data)
 {
@@ -74,19 +70,18 @@ on_armor_parsed (GQuark type,
 	value = g_hash_table_lookup (headers, "Version");
 	g_assert_cmpstr (value, ==, "GnuPG v1.4.11 (GNU/Linux)");
 
-	*result = parse_binary (data, n_data);
+	*result = parse_binary (data);
 }
 
 static gboolean
-parse_armor_or_binary (gconstpointer contents,
-                       gsize length)
+parse_armor_or_binary (EggBytes *contents)
 {
 	gboolean result;
 	guint parts;
 
-	parts = egg_armor_parse (contents, length, on_armor_parsed, &result);
+	parts = egg_armor_parse (contents, on_armor_parsed, &result);
 	if (parts == 0)
-		result = parse_binary (contents, length);
+		result = parse_binary (contents);
 	return result;
 }
 
@@ -96,6 +91,7 @@ main(int argc, char *argv[])
 	GError *error = NULL;
 	gchar *contents;
 	gsize length;
+	EggBytes *bytes;
 	int ret;
 
 	g_set_prgname ("frob-openpgp");
@@ -111,12 +107,13 @@ main(int argc, char *argv[])
 		return 1;
 	}
 
+	bytes = egg_bytes_new_take (contents, length);
 	ret = 0;
-	if (!parse_armor_or_binary (contents, length)) {
+	if (!parse_armor_or_binary (bytes)) {
 		g_printerr ("frob-openpgp: no openpgp data found in data");
 		ret = 1;
 	}
 
-	g_free (contents);
+	egg_bytes_unref (bytes);
 	return ret;
 }
diff --git a/gcr/tests/test-fingerprint.c b/gcr/tests/test-fingerprint.c
index d17208b..94564f8 100644
--- a/gcr/tests/test-fingerprint.c
+++ b/gcr/tests/test-fingerprint.c
@@ -39,49 +39,43 @@
 #include <errno.h>
 
 typedef struct {
-	gpointer cert_rsa;
-	gsize n_cert_rsa;
-	gpointer key_rsa;
-	gsize n_key_rsa;
-	gpointer cert_dsa;
-	gsize n_cert_dsa;
-	gpointer key_dsa;
-	gsize n_key_dsa;
+	EggBytes *cert_rsa;
+	EggBytes *key_rsa;
+	EggBytes *cert_dsa;
+	EggBytes *key_dsa;
 } Test;
 
 static void
 setup (Test *test, gconstpointer unused)
 {
 	GError *error = NULL;
+	gchar *contents;
+	gsize length;
 
-	g_file_get_contents (SRCDIR "/files/client.crt", (gchar**)&test->cert_rsa,
-	                     &test->n_cert_rsa, &error);
+	g_file_get_contents (SRCDIR "/files/client.crt", &contents, &length, &error);
 	g_assert_no_error (error);
-	g_assert (test->cert_rsa);
+	test->cert_rsa = egg_bytes_new_take (contents, length);
 
-	g_file_get_contents (SRCDIR "/files/client.key", (gchar**)&test->key_rsa,
-	                     &test->n_key_rsa, &error);
+	g_file_get_contents (SRCDIR "/files/client.key", &contents, &length, &error);
 	g_assert_no_error (error);
-	g_assert (test->key_rsa);
+	test->key_rsa = egg_bytes_new_take (contents, length);
 
-	g_file_get_contents (SRCDIR "/files/generic-dsa.crt", (gchar**)&test->cert_dsa,
-	                     &test->n_cert_dsa, &error);
+	g_file_get_contents (SRCDIR "/files/generic-dsa.crt", &contents, &length, &error);
 	g_assert_no_error (error);
-	g_assert (test->cert_dsa);
+	test->cert_dsa = egg_bytes_new_take (contents, length);
 
-	g_file_get_contents (SRCDIR "/files/generic-dsa.key", (gchar**)&test->key_dsa,
-	                     &test->n_key_dsa, &error);
+	g_file_get_contents (SRCDIR "/files/generic-dsa.key", &contents, &length, &error);
 	g_assert_no_error (error);
-	g_assert (test->key_dsa);
+	test->key_dsa = egg_bytes_new_take (contents, length);
 }
 
 static void
 teardown (Test *test, gconstpointer unused)
 {
-	g_free (test->cert_rsa);
-	g_free (test->key_rsa);
-	g_free (test->cert_dsa);
-	g_free (test->key_dsa);
+	egg_bytes_unref (test->cert_rsa);
+	egg_bytes_unref (test->key_rsa);
+	egg_bytes_unref (test->cert_dsa);
+	egg_bytes_unref (test->key_dsa);
 }
 
 static void
@@ -96,7 +90,7 @@ on_parser_parsed (GcrParser *parser,
 }
 
 static GckAttributes*
-parse_attributes_for_key (gpointer data, gsize n_data)
+parse_attributes_for_key (EggBytes *data)
 {
 	GcrParser *parser;
 	GckAttributes *attrs = NULL;
@@ -104,7 +98,8 @@ parse_attributes_for_key (gpointer data, gsize n_data)
 
 	parser = gcr_parser_new ();
 	g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), &attrs);
-	gcr_parser_parse_data (parser, data, n_data, &error);
+	gcr_parser_parse_data (parser, egg_bytes_get_data (data),
+	                       egg_bytes_get_size (data), &error);
 	g_assert_no_error (error);
 	g_object_unref (parser);
 
@@ -113,30 +108,30 @@ parse_attributes_for_key (gpointer data, gsize n_data)
 }
 
 static GckAttributes *
-build_attributes_for_cert (guchar *data,
-                           gsize n_data)
+build_attributes_for_cert (EggBytes *data)
 {
 	GckAttributes *attrs;
 
 	attrs = gck_attributes_new ();
-	gck_attributes_add_data (attrs, CKA_VALUE, data, n_data);
+	gck_attributes_add_data (attrs, CKA_VALUE, egg_bytes_get_data (data),
+	                         egg_bytes_get_size (data));
 	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
 	gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509);
 
 	return attrs;
 }
 
-static gconstpointer
-parse_subject_public_key_info_for_cert (gpointer data, gsize n_data, gsize *n_info)
+static EggBytes *
+parse_subject_public_key_info_for_cert (EggBytes *data)
 {
-	gconstpointer info;
+	EggBytes *info;
 	GNode *asn;
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
-	g_assert (asn);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data);
+	g_assert (asn != NULL);
 
-	info = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", NULL), n_info);
-	g_assert (info);
+	info = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", NULL));
+	g_assert (info != NULL);
 
 	egg_asn1x_destroy (asn);
 	return info;
@@ -146,16 +141,17 @@ static void
 test_rsa (Test *test, gconstpointer unused)
 {
 	GckAttributes *key, *cert;
-	gconstpointer info;
-	gsize n_info;
+	EggBytes *info;
 	guchar *fingerprint1, *fingerprint2, *fingerprint3;
 	gsize n_fingerprint1, n_fingerprint2, n_fingerprint3;
 
-	key = parse_attributes_for_key (test->key_rsa, test->n_key_rsa);
-	info = parse_subject_public_key_info_for_cert (test->cert_rsa, test->n_cert_rsa, &n_info);
-	cert = build_attributes_for_cert (test->cert_rsa, test->n_cert_rsa);
+	key = parse_attributes_for_key (test->key_rsa);
+	info = parse_subject_public_key_info_for_cert (test->cert_rsa);
+	cert = build_attributes_for_cert (test->cert_rsa);
 
-	fingerprint1 = gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
+	fingerprint1 = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (info),
+	                                                             egg_bytes_get_size (info),
+	                                                             G_CHECKSUM_SHA1, &n_fingerprint1);
 	fingerprint2 = gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
 	fingerprint3 = gcr_fingerprint_from_attributes (cert, G_CHECKSUM_SHA1, &n_fingerprint3);
 
@@ -166,6 +162,7 @@ test_rsa (Test *test, gconstpointer unused)
 	g_free (fingerprint2);
 	g_free (fingerprint3);
 
+	egg_bytes_unref (info);
 	gck_attributes_unref (key);
 	gck_attributes_unref (cert);
 }
@@ -174,16 +171,17 @@ static void
 test_dsa (Test *test, gconstpointer unused)
 {
 	GckAttributes *key, *cert;
-	gconstpointer info;
-	gsize n_info;
+	EggBytes *info;
 	guchar *fingerprint1, *fingerprint2, *fingerprint3;
 	gsize n_fingerprint1, n_fingerprint2, n_fingerprint3;
 
-	key = parse_attributes_for_key (test->key_dsa, test->n_key_dsa);
-	info = parse_subject_public_key_info_for_cert (test->cert_dsa, test->n_cert_dsa, &n_info);
-	cert = build_attributes_for_cert (test->cert_dsa, test->n_cert_dsa);
+	key = parse_attributes_for_key (test->key_dsa);
+	info = parse_subject_public_key_info_for_cert (test->cert_dsa);
+	cert = build_attributes_for_cert (test->cert_dsa);
 
-	fingerprint1 = gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
+	fingerprint1 = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (info),
+	                                                             egg_bytes_get_size (info),
+	                                                             G_CHECKSUM_SHA1, &n_fingerprint1);
 	fingerprint2 = gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
 	fingerprint3 = gcr_fingerprint_from_attributes (cert, G_CHECKSUM_SHA1, &n_fingerprint3);
 
@@ -194,6 +192,7 @@ test_dsa (Test *test, gconstpointer unused)
 	g_free (fingerprint2);
 	g_free (fingerprint3);
 
+	egg_bytes_unref (info);
 	gck_attributes_unref (key);
 	gck_attributes_unref (cert);
 }
diff --git a/gcr/tests/test-openpgp.c b/gcr/tests/test-openpgp.c
index be41f40..cfc1dad 100644
--- a/gcr/tests/test-openpgp.c
+++ b/gcr/tests/test-openpgp.c
@@ -240,15 +240,14 @@ compare_fixture_with_records (const gchar *fixture,
 
 static void
 on_openpgp_packet  (GPtrArray *records,
-                    const guchar *outer,
-                    gsize n_outer,
+                    EggBytes *outer,
                     gpointer user_data)
 {
 	Test *test = user_data;
 	guint seen;
 
 	/* Should be parseable again */
-	seen = _gcr_openpgp_parse (outer, n_outer, test->fixture->flags |
+	seen = _gcr_openpgp_parse (outer, test->fixture->flags |
 	                           GCR_OPENPGP_PARSE_NO_RECORDS, NULL, NULL);
 	g_assert_cmpuint (seen, ==, 1);
 
@@ -263,10 +262,8 @@ on_openpgp_packet  (GPtrArray *records,
 
 static void
 on_armor_parsed (GQuark type,
-                 const guchar *data,
-                 gsize n_data,
-                 const gchar *outer,
-                 gsize n_outer,
+                 EggBytes *data,
+                 EggBytes *outer,
                  GHashTable *headers,
                  gpointer user_data)
 {
@@ -279,7 +276,7 @@ on_armor_parsed (GQuark type,
 		g_assert_cmpstr (value, ==, test->fixture->version);
 	}
 
-	seen = _gcr_openpgp_parse (data, n_data, test->fixture->flags,
+	seen = _gcr_openpgp_parse (data, test->fixture->flags,
 	                           on_openpgp_packet, test);
 	g_assert_cmpuint (seen, >, 0);
 
@@ -294,6 +291,7 @@ test_openpgp_armor (Test *test,
                     gconstpointer data)
 {
 	GError *error = NULL;
+	EggBytes *bytes;
 	gchar *armor;
 	gsize length;
 	guint parts;
@@ -301,10 +299,11 @@ test_openpgp_armor (Test *test,
 	g_file_get_contents (test->fixture->filename, &armor, &length, &error);
 	g_assert_no_error (error);
 
-	parts = egg_armor_parse (armor, length, on_armor_parsed, test);
+	bytes = egg_bytes_new_take (armor, length);
+	parts = egg_armor_parse (bytes, on_armor_parsed, test);
 	g_assert_cmpuint (parts, ==, 1);
 
-	g_free (armor);
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -312,6 +311,7 @@ test_openpgp_binary (Test *test,
                      gconstpointer data)
 {
 	GError *error = NULL;
+	EggBytes *bytes;
 	gchar *binary;
 	gsize length;
 	guint seen;
@@ -319,8 +319,8 @@ test_openpgp_binary (Test *test,
 	g_file_get_contents (test->fixture->filename, &binary, &length, &error);
 	g_assert_no_error (error);
 
-	seen = _gcr_openpgp_parse (binary, length, test->fixture->flags,
-	                           on_openpgp_packet, test);
+	bytes = egg_bytes_new_take (binary, length);
+	seen = _gcr_openpgp_parse (bytes, test->fixture->flags, on_openpgp_packet, test);
 	g_assert_cmpuint (seen, >, 0);
 
 	if (*(test->at) != NULL) {
@@ -328,7 +328,7 @@ test_openpgp_binary (Test *test,
 		g_assert_not_reached ();
 	}
 
-	g_free (binary);
+	egg_bytes_unref (binary);
 }
 
 int
diff --git a/gcr/tests/test-openssh.c b/gcr/tests/test-openssh.c
index 81634da..b7742d9 100644
--- a/gcr/tests/test-openssh.c
+++ b/gcr/tests/test-openssh.c
@@ -91,8 +91,7 @@ static void
 on_openssh_pub_parse (GckAttributes *attrs,
                       const gchar *label,
                       const gchar *options,
-                      const gchar *outer,
-                      gsize n_outer,
+                      EggBytes *outer,
                       gpointer user_data)
 {
 	Test *test = user_data;
@@ -104,7 +103,7 @@ on_openssh_pub_parse (GckAttributes *attrs,
 		g_assert_cmpstr (options, ==, test->expected_options);
 
 	/* The block should parse properly */
-	keys = _gcr_openssh_pub_parse (outer, n_outer, NULL, NULL);
+	keys = _gcr_openssh_pub_parse (outer, NULL, NULL);
 	g_assert_cmpuint (keys, ==, 1);
 }
 
@@ -113,14 +112,16 @@ test_parse_v1_rsa (Test *test,
                    gconstpointer unused)
 {
 	const gchar *data = OPENSSH_PUBLIC_RSA1 EXTRA_LINES_WITHOUT_KEY;
+	EggBytes *bytes;
 	gint keys;
 
 	test->expected_label = "rsa-key example com";
 
-	keys = _gcr_openssh_pub_parse (data, strlen (data),
-	                               on_openssh_pub_parse, test);
+	bytes = egg_bytes_new_static (data, strlen (data));
+	keys = _gcr_openssh_pub_parse (bytes, on_openssh_pub_parse, test);
 	g_assert_cmpint (keys, ==, 1);
 
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -128,13 +129,16 @@ test_parse_v2_rsa (Test *test,
                    gconstpointer unused)
 {
 	const gchar *data = OPENSSH_PUBLIC_RSA2 EXTRA_LINES_WITHOUT_KEY;
+	EggBytes *bytes;
 	gint keys;
 
 	test->expected_label = "rsa-key example com";
 
-	keys = _gcr_openssh_pub_parse (data, strlen (data),
-	                               on_openssh_pub_parse, test);
+	bytes = egg_bytes_new_static (data, strlen (data));
+	keys = _gcr_openssh_pub_parse (bytes, on_openssh_pub_parse, test);
 	g_assert_cmpint (keys, ==, 1);
+
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -142,13 +146,16 @@ test_parse_v2_dsa (Test *test,
                gconstpointer unused)
 {
 	const gchar *data = OPENSSH_PUBLIC_DSA2 EXTRA_LINES_WITHOUT_KEY;
+	EggBytes *bytes;
 	gint keys;
 
 	test->expected_label = "dsa-key example com";
 
-	keys = _gcr_openssh_pub_parse (data, strlen (data),
-	                               on_openssh_pub_parse, test);
+	bytes = egg_bytes_new_static (data, strlen (data));
+	keys = _gcr_openssh_pub_parse (bytes, on_openssh_pub_parse, test);
 	g_assert_cmpint (keys, ==, 1);
+
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -156,13 +163,16 @@ test_parse_v1_options (Test *test,
                        gconstpointer unused)
 {
 	const gchar *data = "option1,option2=\"value 2\",option3 " OPENSSH_PUBLIC_RSA1;
+	EggBytes *bytes;
 	gint keys;
 
 	test->expected_options = "option1,option2=\"value 2\",option3";
 
-	keys = _gcr_openssh_pub_parse (data, strlen (data),
-	                               on_openssh_pub_parse, test);
+	bytes = egg_bytes_new_static (data, strlen (data));
+	keys = _gcr_openssh_pub_parse (bytes, on_openssh_pub_parse, test);
 	g_assert_cmpint (keys, ==, 1);
+
+	egg_bytes_unref (bytes);
 }
 
 static void
@@ -170,13 +180,16 @@ test_parse_v2_options (Test *test,
                        gconstpointer unused)
 {
 	const gchar *data = "option1,option2=\"value 2\",option3 " OPENSSH_PUBLIC_RSA2;
+	EggBytes *bytes;
 	gint keys;
 
 	test->expected_options = "option1,option2=\"value 2\",option3";
 
-	keys = _gcr_openssh_pub_parse (data, strlen (data),
-	                               on_openssh_pub_parse, test);
+	bytes = egg_bytes_new_static (data, strlen (data));
+	keys = _gcr_openssh_pub_parse (bytes, on_openssh_pub_parse, test);
 	g_assert_cmpint (keys, ==, 1);
+
+	egg_bytes_unref (bytes);
 }
 
 int
diff --git a/gcr/tests/test-pkcs11-certificate.c b/gcr/tests/test-pkcs11-certificate.c
index 7c04c07..daf97e1 100644
--- a/gcr/tests/test-pkcs11-certificate.c
+++ b/gcr/tests/test-pkcs11-certificate.c
@@ -53,8 +53,8 @@ setup (Test *test, gconstpointer unused)
 	GckAttributes *attrs;
 	CK_FUNCTION_LIST_PTR f;
 	GckModule *module;
-	gconstpointer subject;
-	gsize n_subject;
+	EggBytes *subject;
+	EggBytes *bytes;
 	GNode *asn, *node;
 	CK_RV rv;
 
@@ -82,20 +82,24 @@ setup (Test *test, gconstpointer unused)
 	gcr_pkcs11_set_modules (modules);
 	gck_list_unref_free (modules);
 
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate",
-	                                   test->cert_data, test->n_cert_data);
+	bytes = egg_bytes_new_static (test->cert_data, test->n_cert_data);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
 	g_assert (asn);
 	node = egg_asn1x_node (asn, "tbsCertificate", "subject", NULL);
-	subject = egg_asn1x_get_raw_element (node, &n_subject);
+	subject = egg_asn1x_get_raw_element (node);
 
 	/* Add a certificate to the module */
 	attrs = gck_attributes_new ();
 	gck_attributes_add_data (attrs, CKA_VALUE, test->cert_data, test->n_cert_data);
 	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
 	gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509);
-	gck_attributes_add_data (attrs, CKA_SUBJECT, subject, n_subject);
+	gck_attributes_add_data (attrs, CKA_SUBJECT,
+	                         egg_bytes_get_data (subject),
+	                         egg_bytes_get_size (subject));
 	gck_mock_module_take_object (attrs);
 
+	egg_bytes_unref (bytes);
+	egg_bytes_unref (subject);
 	egg_asn1x_destroy (asn);
 }
 



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