diff --git a/.gitignore b/.gitignore
index d504d07..cf6dad0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -110,6 +110,7 @@ run-tests
 /gcr/tests/frob-unlock-options
 /gcr/tests/test-certificate
 /gcr/tests/test-certificate-chain
+/gcr/tests/test-fingerprint
 /gcr/tests/test-parser
 /gcr/tests/test-pkcs11-certificate
 /gcr/tests/test-simple-certificate
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index 55c73ce..aae8ddd 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -1263,6 +1263,7 @@ anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
 	case TYPE_TIME:
 	case TYPE_ENUMERATED:
 	case TYPE_GENERALSTRING:
+	case TYPE_NULL:
 		tlv.cls = ASN1_CLASS_UNIVERSAL;
 		break;
 	/* Container types */
@@ -1656,6 +1657,7 @@ anode_encode_prepare (GNode *node, gboolean want)
 	case TYPE_ENUMERATED:
 	case TYPE_GENERALSTRING:
 	case TYPE_ANY:
+	case TYPE_NULL:
 		return anode_encode_prepare_simple (node, want);
 		break;
 	case TYPE_SEQUENCE:
@@ -2451,6 +2453,17 @@ egg_asn1x_set_boolean (GNode *node, gboolean value)
 	return TRUE;
 }
 
+gboolean
+egg_asn1x_set_null (GNode *node)
+{
+	g_return_val_if_fail (node, FALSE);
+	g_return_val_if_fail (anode_def_type (node) == TYPE_NULL, FALSE);
+
+	/* Encode zero characters */
+	anode_encode_tlv_and_enc (node, 0, anode_encoder_simple, "", NULL);
+	return TRUE;
+}
+
 GQuark
 egg_asn1x_get_enumerated (GNode *node)
 {
@@ -2606,7 +2619,7 @@ egg_asn1x_get_integer_as_raw (GNode *node, EggAllocator allocator, gsize *n_data
 }
 
 gboolean
-egg_asn1x_set_integer_as_raw (GNode *node, gpointer data, gsize n_data, GDestroyNotify destroy)
+egg_asn1x_set_integer_as_raw (GNode *node, gconstpointer data, gsize n_data, GDestroyNotify destroy)
 {
 	gboolean sign;
 	guchar *p;
@@ -2624,7 +2637,7 @@ egg_asn1x_set_integer_as_raw (GNode *node, gpointer data, gsize n_data, GDestroy
 		return FALSE;
 	}
 
-	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, destroy);
+	anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, (gpointer)data, destroy);
 	return TRUE;
 }
 
diff --git a/egg/egg-asn1x.h b/egg/egg-asn1x.h
index f987f9d..06e94e3 100644
--- a/egg/egg-asn1x.h
+++ b/egg/egg-asn1x.h
@@ -84,6 +84,8 @@ gboolean            egg_asn1x_get_boolean            (GNode *node,
 gboolean            egg_asn1x_set_boolean            (GNode *node,
                                                       gboolean value);
 
+gboolean            egg_asn1x_set_null               (GNode *node);
+
 GQuark              egg_asn1x_get_enumerated         (GNode *node);
 
 gboolean            egg_asn1x_set_enumerated         (GNode *node,
@@ -100,7 +102,7 @@ gpointer            egg_asn1x_get_integer_as_raw     (GNode *node,
                                                       gsize *n_data);
 
 gboolean            egg_asn1x_set_integer_as_raw     (GNode *node,
-                                                      gpointer data,
+                                                      gconstpointer data,
                                                       gsize n_data,
                                                       GDestroyNotify destroy);
 
diff --git a/egg/pk.asn b/egg/pk.asn
index f347c19..347323c 100644
--- a/egg/pk.asn
+++ b/egg/pk.asn
@@ -32,6 +32,8 @@ RSAPrivateKey ::= SEQUENCE {
 Version ::= INTEGER { two-prime(0), multi(1) }
 -- version must be multi if otherPrimeInfos present --
 
+RSAParameters ::= NULL
+
 OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
 
 OtherPrimeInfo ::= SEQUENCE {
diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c
index 39f188d..6b7058b 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -46,6 +46,7 @@ const gchar TGENERALIZED[] =  "\x18\x0F""20070725130528Z";
 const gchar BITS_TEST[] =  "\x03\x04\x06\x6e\x5d\xc0";
 const gchar BITS_BAD[] =  "\x03\x04\x06\x6e\x5d\xc1";
 const gchar BITS_ZERO[] =  "\x03\x01\x00";
+const gchar NULL_TEST[] =  "\x05\x00";
 
 /* ENUM with value = 2 */
 const gchar ENUM_TWO[] =           "\x0A\x01\x02";
@@ -94,6 +95,29 @@ test_boolean (void)
 }
 
 static void
+test_null (void)
+{
+	GNode *asn;
+	gpointer data;
+	gsize n_data;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestNull");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_null (asn))
+		g_assert_not_reached ();
+
+	data = egg_asn1x_encode (asn, g_realloc, &n_data);
+	egg_assert_cmpmem (NULL_TEST, XL (NULL_TEST), ==, data, n_data);
+
+	if (!egg_asn1x_decode (asn, data, n_data))
+		g_assert_not_reached ();
+
+	egg_asn1x_destroy (asn);
+	g_free (data);
+}
+
+static void
 test_integer (void)
 {
 	GNode *asn;
@@ -1130,6 +1154,7 @@ main (int argc, char **argv)
 	g_test_init (&argc, &argv, NULL);
 
 	g_test_add_func ("/asn1/boolean", test_boolean);
+	g_test_add_func ("/asn1/null", test_null);
 	g_test_add_func ("/asn1/integer", test_integer);
 	g_test_add_func ("/asn1/octet_string", test_octet_string);
 	g_test_add_func ("/asn1/generalized_time", test_generalized_time);
diff --git a/egg/tests/test.asn b/egg/tests/test.asn
index 9779b37..28cb176 100644
--- a/egg/tests/test.asn
+++ b/egg/tests/test.asn
@@ -8,6 +8,8 @@ TestInteger ::= INTEGER
 
 TestBoolean ::= BOOLEAN
 
+TestNull ::= NULL
+
 TestOctetString ::= OCTET STRING
 
 TestGeneralized ::= GeneralizedTime
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index e55df6c..8b706d1 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -65,9 +65,10 @@ LIB_SOURCES = \
 	gcr-certificate-widget.c gcr-certificate-widget.h \
 	gcr-collection.c gcr-collection.h \
 	gcr-collection-model.c gcr-collection-model.h \
-	gcr-display-scrolled.c gcr-display-scrolled.h \
 	gcr-comparable.c gcr-comparable.h \
+	gcr-display-scrolled.c gcr-display-scrolled.h \
 	gcr-display-view.c gcr-display-view.h \
+	gcr-fingerprint.c gcr-fingerprint.h \
 	gcr-icons.c gcr-icons.h \
 	gcr-import-dialog.c gcr-import-dialog.h \
 	gcr-importer.c gcr-importer.h  \
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
index f553048..45a7f40 100644
--- a/gcr/gcr-certificate-renderer.c
+++ b/gcr/gcr-certificate-renderer.c
@@ -23,6 +23,7 @@
 #include "gcr-certificate-exporter.h"
 #include "gcr-certificate-renderer.h"
 #include "gcr-display-view.h"
+#include "gcr-fingerprint.h"
 #include "gcr-icons.h"
 #include "gcr-simple-certificate.h"
 #include "gcr-renderer.h"
@@ -485,6 +486,12 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	}
 	g_free (display);
 
+	/* Fingerprints */
+	_gcr_display_view_append_heading (view, renderer, _("Certificate Fingerprints"));
+
+	_gcr_display_view_append_fingerprint (view, renderer, data, n_data, "SHA1", G_CHECKSUM_SHA1);
+	_gcr_display_view_append_fingerprint (view, renderer, data, n_data, "MD5", G_CHECKSUM_MD5);
+
 	/* Signature */
 	_gcr_display_view_append_heading (view, renderer, _("Signature"));
 
@@ -521,18 +528,18 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 		g_free (display);
 	}
 
+	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);
+	_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);
 
-	/* Fingerprints */
-	_gcr_display_view_append_heading (view, renderer, _("Fingerprints"));
-
-	_gcr_display_view_append_fingerprint (view, renderer, data, n_data, "SHA1", G_CHECKSUM_SHA1);
-	_gcr_display_view_append_fingerprint (view, renderer, data, n_data, "MD5", G_CHECKSUM_MD5);
-
 	/* Extensions */
 	for (index = 1; TRUE; ++index) {
 		if (!append_extension (self, view, asn, data, n_data, index))
diff --git a/gcr/gcr-fingerprint.c b/gcr/gcr-fingerprint.c
new file mode 100644
index 0000000..4f93d61
--- /dev/null
+++ b/gcr/gcr-fingerprint.c
@@ -0,0 +1,266 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General  License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gcr-fingerprint.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+
+#include <glib.h>
+#include <gcrypt.h>
+
+static GQuark OID_PKIX1_RSA = 0;
+static GQuark OID_PKIX1_DSA = 0;
+
+static void
+init_quarks (void)
+{
+	static volatile gsize quarks_inited = 0;
+
+	if (g_once_init_enter (&quarks_inited)) {
+
+		#define QUARK(name, value) \
+			name = g_quark_from_static_string(value)
+
+		QUARK (OID_PKIX1_RSA, "1.2.840.113549.1.1.1");
+		QUARK (OID_PKIX1_DSA, "1.2.840.10040.4.1");
+
+		#undef QUARK
+
+		g_once_init_leave (&quarks_inited, 1);
+	}
+}
+
+gpointer
+_gcr_fingerprint_from_subject_public_key_info (gconstpointer key_info, gsize n_key_info,
+                                               GChecksumType checksum_type,
+                                               gsize *n_fingerprint)
+{
+	GChecksum *check;
+	guint8 *fingerprint;
+
+	g_return_val_if_fail (key_info, NULL);
+	g_return_val_if_fail (n_key_info, NULL);
+	g_return_val_if_fail (n_fingerprint, NULL);
+
+	check = g_checksum_new (checksum_type);
+	g_return_val_if_fail (check, NULL);
+
+	g_checksum_update (check, key_info, n_key_info);
+
+	*n_fingerprint = g_checksum_type_get_length (checksum_type);
+	fingerprint = g_malloc (*n_fingerprint);
+	g_checksum_get_digest (check, fingerprint, n_fingerprint);
+
+	g_checksum_free (check);
+	return fingerprint;
+}
+
+static gboolean
+rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
+{
+	GckAttribute *attr;
+	GNode *key_asn;
+	GNode *params_asn;
+	gpointer key, params;
+	gsize n_key, n_params;
+
+	init_quarks ();
+
+	key_asn = egg_asn1x_create (pk_asn1_tab, "RSAPublicKey");
+	g_return_val_if_fail (key_asn, FALSE);
+
+	params_asn = egg_asn1x_create (pk_asn1_tab, "RSAParameters");
+	g_return_val_if_fail (params_asn, FALSE);
+
+	attr = gck_attributes_find (attrs, CKA_MODULUS);
+	g_return_val_if_fail (attr, FALSE);
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (key_asn, "modulus", NULL),
+	                              attr->value, attr->length, NULL);
+
+	attr = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
+	g_return_val_if_fail (attr, FALSE);
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (key_asn, "publicExponent", NULL),
+	                              attr->value, attr->length, NULL);
+
+	key = egg_asn1x_encode (key_asn, g_realloc, &n_key);
+	egg_asn1x_destroy (key_asn);
+
+	egg_asn1x_set_null (params_asn);
+
+	params = egg_asn1x_encode (params_asn, g_realloc, &n_params);
+	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_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), OID_PKIX1_RSA);
+	egg_asn1x_set_raw_element (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL),
+	                           params, n_params, g_free);
+
+	return TRUE;
+}
+
+static gboolean
+dsa_subject_public_key_from_private (GNode *key_asn, GckAttribute *ap,
+                                     GckAttribute *aq, GckAttribute *ag, GckAttribute *ax)
+{
+	gcry_mpi_t mp, mq, mg, mx, my;
+	size_t n_buffer;
+	gcry_error_t gcry;
+	unsigned char *buffer;
+
+	gcry = gcry_mpi_scan (&mp, GCRYMPI_FMT_USG, ap->value, ap->length, NULL);
+	g_return_val_if_fail (gcry == 0, FALSE);
+
+	gcry = gcry_mpi_scan (&mq, GCRYMPI_FMT_USG, aq->value, aq->length, NULL);
+	g_return_val_if_fail (gcry == 0, FALSE);
+
+	gcry = gcry_mpi_scan (&mg, GCRYMPI_FMT_USG, ag->value, ag->length, NULL);
+	g_return_val_if_fail (gcry == 0, FALSE);
+
+	gcry = gcry_mpi_scan (&mx, GCRYMPI_FMT_USG, ax->value, ax->length, NULL);
+	g_return_val_if_fail (gcry == 0, FALSE);
+
+	/* Calculate the public part from the private */
+	my = gcry_mpi_snew (gcry_mpi_get_nbits (mx));
+	g_return_val_if_fail (my, FALSE);
+	gcry_mpi_powm (my, mg, mx, mp);
+
+	gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &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);
+
+	gcry_mpi_release (mp);
+	gcry_mpi_release (mq);
+	gcry_mpi_release (mg);
+	gcry_mpi_release (mx);
+	gcry_mpi_release (my);
+
+	return TRUE;
+}
+
+static gboolean
+dsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
+{
+	GckAttribute *value, *g, *q, *p;
+	GNode *key_asn, *params_asn;
+	gpointer key, params;
+	gsize n_key, n_params;
+	gulong klass;
+
+	init_quarks ();
+
+	key_asn = egg_asn1x_create (pk_asn1_tab, "DSAPublicPart");
+	g_return_val_if_fail (key_asn, FALSE);
+
+	params_asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters");
+	g_return_val_if_fail (params_asn, FALSE);
+
+	if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
+		klass = CKO_PUBLIC_KEY;
+
+	p = gck_attributes_find (attrs, CKA_PRIME);
+	g_return_val_if_fail (p, FALSE);
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (params_asn, "p", NULL), p->value, p->length, NULL);
+
+	q = gck_attributes_find (attrs, CKA_SUBPRIME);
+	g_return_val_if_fail (q, FALSE);
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (params_asn, "q", NULL), q->value, q->length, NULL);
+
+	g = gck_attributes_find (attrs, CKA_BASE);
+	g_return_val_if_fail (g, FALSE);
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (params_asn, "g", NULL), g->value, g->length, NULL);
+
+	value = gck_attributes_find (attrs, CKA_VALUE);
+	g_return_val_if_fail (value, FALSE);
+
+	/* Are these attributes for a public or private key? */
+	if (klass == CKO_PRIVATE_KEY) {
+
+		/* We need to calculate the public from the private key */
+		if (!dsa_subject_public_key_from_private (key_asn, p, q, g, value))
+			g_return_val_if_reached (FALSE);
+
+	} else if (klass == CKO_PUBLIC_KEY) {
+		egg_asn1x_set_integer_as_raw (key_asn, value->value, value->length, NULL);
+	}
+
+	key = egg_asn1x_encode (key_asn, g_realloc, &n_key);
+	egg_asn1x_destroy (key_asn);
+
+	params = egg_asn1x_encode (params_asn, g_realloc, &n_params);
+	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_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), OID_PKIX1_DSA);
+
+	return TRUE;
+}
+
+gpointer
+_gcr_fingerprint_from_attributes (GckAttributes *attrs, GChecksumType checksum_type,
+                                  gsize *n_fingerprint)
+{
+	gpointer fingerprint = NULL;
+	gboolean ret = FALSE;
+	GNode *info_asn;
+	gpointer info;
+	gulong key_type;
+	gsize n_info;
+
+	g_return_val_if_fail (attrs, FALSE);
+	g_return_val_if_fail (n_fingerprint, FALSE);
+
+	if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &key_type))
+		g_return_val_if_reached (FALSE);
+
+	info_asn = egg_asn1x_create (pkix_asn1_tab, "SubjectPublicKeyInfo");
+	g_return_val_if_fail (info_asn, FALSE);
+
+	if (key_type == CKK_RSA)
+		ret = rsa_subject_public_key_from_attributes (attrs, info_asn);
+
+	else if (key_type == CKK_DSA)
+		ret = dsa_subject_public_key_from_attributes (attrs, info_asn);
+
+	else
+		g_return_val_if_reached (FALSE);
+
+	if (ret) {
+		info = egg_asn1x_encode (info_asn, g_realloc, &n_info);
+		fingerprint = _gcr_fingerprint_from_subject_public_key_info (info, n_info,
+		                                                             checksum_type,
+		                                                             n_fingerprint);
+		g_free (info);
+	}
+
+	egg_asn1x_destroy (info_asn);
+	return fingerprint;
+}
diff --git a/gcr/gcr-fingerprint.h b/gcr/gcr-fingerprint.h
new file mode 100644
index 0000000..091bd81
--- /dev/null
+++ b/gcr/gcr-fingerprint.h
@@ -0,0 +1,40 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General  License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#ifndef GCR_FINGERPRINT_H
+#define GCR_FINGERPRINT_H
+
+#include <glib.h>
+
+#include "gcr-types.h"
+
+gpointer        _gcr_fingerprint_from_subject_public_key_info    (gconstpointer key_info,
+                                                                  gsize n_key_info,
+                                                                  GChecksumType checksum_type,
+                                                                  gsize *n_fingerprint);
+
+gpointer        _gcr_fingerprint_from_attributes                 (GckAttributes *attrs,
+                                                                  GChecksumType checksum_type,
+                                                                  gsize *n_fingerprint);
+
+#endif /* GCR_FINGERPRINT_H_ */
diff --git a/gcr/gcr-key-renderer.c b/gcr/gcr-key-renderer.c
index bf3934c..2273079 100644
--- a/gcr/gcr-key-renderer.c
+++ b/gcr/gcr-key-renderer.c
@@ -21,6 +21,7 @@
 
 #include "gcr-key-renderer.h"
 #include "gcr-display-view.h"
+#include "gcr-fingerprint.h"
 #include "gcr-icons.h"
 #include "gcr-renderer.h"
 #include "gcr-viewer.h"
@@ -239,6 +240,8 @@ gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer)
 	GcrKeyRenderer *self;
 	GcrDisplayView *view;
 	const gchar *text = "";
+	gpointer fingerprint;
+	gsize n_fingerprint;
 	gchar *display;
 	gulong klass;
 	gulong key_type;
@@ -316,8 +319,21 @@ gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer)
 	_gcr_display_view_append_value (view, renderer, _("Size"), display, FALSE);
 	g_free (display);
 
-	/* TODO: We need to have consistent key fingerprints. */
-	_gcr_display_view_append_value (view, renderer, _("Fingerprint"), "XX XX XX XX XX XX XX XX XX XX", TRUE);
+	/* Fingerprints */
+	_gcr_display_view_append_heading (view, renderer, _("Fingerprints"));
+
+	fingerprint = _gcr_fingerprint_from_attributes (self->pv->attributes,
+	                                                G_CHECKSUM_SHA1, &n_fingerprint);
+	if (fingerprint) {
+		_gcr_display_view_append_hex (view, renderer, _("SHA1"), fingerprint, n_fingerprint);
+		g_free (fingerprint);
+	}
+	fingerprint = _gcr_fingerprint_from_attributes (self->pv->attributes,
+	                                                G_CHECKSUM_SHA256, &n_fingerprint);
+	if (fingerprint) {
+		_gcr_display_view_append_hex (view, renderer, _("SHA256"), fingerprint, n_fingerprint);
+		g_free (fingerprint);
+	}
 }
 
 static void
diff --git a/gcr/gcr-key-widget.c b/gcr/gcr-key-widget.c
index 5d8f28f..59eb04f 100644
--- a/gcr/gcr-key-widget.c
+++ b/gcr/gcr-key-widget.c
@@ -89,21 +89,14 @@ gcr_key_widget_constructor (GType type, guint n_props, GObjectConstructParam *pr
 {
 	GObject *obj = G_OBJECT_CLASS (gcr_key_widget_parent_class)->constructor (type, n_props, props);
 	GcrKeyWidget *self = NULL;
-	GtkWidget *scroll;
 
 	g_return_val_if_fail (obj, NULL);
 
 	self = GCR_KEY_WIDGET (obj);
 
-	self->pv->viewer = gcr_viewer_new ();
-
-	scroll = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
-	gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->pv->viewer));
-
-	gtk_container_add (GTK_CONTAINER (self), scroll);
-	gtk_widget_show_all (scroll);
+	self->pv->viewer = gcr_viewer_new_scrolled ();
+	gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->pv->viewer));
+	gtk_widget_show (GTK_WIDGET (self->pv->viewer));
 
 	gcr_viewer_add_renderer (self->pv->viewer, GCR_RENDERER (self->pv->renderer));
 	return obj;
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index b5ff961..3bc7f41 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -21,6 +21,7 @@ LDADD = \
 TEST_PROGS = \
 	test-certificate \
 	test-certificate-chain \
+	test-fingerprint \
 	test-pkcs11-certificate \
 	test-simple-certificate \
 	test-trust \
diff --git a/gcr/tests/files/client.crt b/gcr/tests/files/client.crt
new file mode 100644
index 0000000..a4bc2fc
Binary files /dev/null and b/gcr/tests/files/client.crt differ
diff --git a/gcr/tests/files/client.key b/gcr/tests/files/client.key
new file mode 100644
index 0000000..206f527
--- /dev/null
+++ b/gcr/tests/files/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAwSA0Mz92De30Mc0A/P9vzstLERoqGhnwBw0HKbcsQ50KdcYS
+cp/Rv2WRPlxpe7kYAzzhqFMInufv1FU2uoYozuNsF1Jf5lR+SolA+E5cPb7SeJhC
+Jwf3afPvyTGaOVuLO93d8zUGU74L/741Z/YQCE5FUCO8msc2iQmnc9M1EnVZa14d
+5T0/B8aZYcpVzUiC9EUwfTzrTghnNfkJzEiD9vnqDbsDsIE+H8o7+opMMsUU0ZzV
+PZqy9j8/f4943rL6V4UdK0JO7tEGL+XiFzNl2fCrcEZPqaeMQ3vBq7azukDTrtJe
+KY06RiLl+DCykweLx8laZjIHKlSZAFHPB+bvsQIDAQABAoIBAQCQUI1RYnHIdPFO
+qZ+8bvDQ+g8tR30ApjM8QZsBrDRyjg579bhhWVY2jSJdFFdqseTkvoDt9KZzgGQy
+Kj9MYOZru3xRbSfmiWsaLbiUFJJPPaIvpa+BVS2oSjX8BYn2pJbF9MRfclc5CsIS
+qMNl3XUbj8mx2hKdIpJ5EvLD1adKE4Se6peqSZAmEHONNCsrMrQ0GSQqV3viInJr
+tc3kp3HcPffSROWqmc6jAJ77Cs3ApgJavL5RGjx30Kd+dKVq4PXZ+IhWM8dOSput
+wcyxEosiP/W2g0rDgNW2mGOVOwa/D5SnOolicHifdV7idjwLAjkyYgvmBMNSsECj
+yKBkE0gxAoGBAN8iHMumyvriHuj9bSLZ1bcyYFz7jIwUxpHTT7VqN/j/Y1BoBIBy
+ZZLDGMa+ID/brpRHzJQAKSNtbFQ0S1HTSKcFud5OWE8Rp3pQJU+sdeO3pCMWAD1z
+Q4ggF07JjTSSnK+4fcXgEN9P2OdfXy7Rj3HFpSahql55Kp5udoUdzUVFAoGBAN2S
+krlcEuqsEYjqsCJw5pctIwPMvCM51JgirrdETwSGquMklSrobH0PHMlR67gsA/9I
+UGShT0LL4UWYpBn/4xLrLbua5aHIBfQQZp9K6jDZddWS+EFL5JkO/Up4/qM6fUbH
+CuweVv1gd6i2Ti35K60mgx6MqVunaB1k8Q9P3Pl9AoGALSVtxha9Qv21W1bLWh3R
+C/v5W1baHQ2nD6I9omsXYB3sLjydjI+Y1ZT70lptk/4S2JWeYuOVb0GYhYD/LFMf
+hAu4i642V+kuhaTpp7ExOR3S6/ZrngNQSp6TmLFXDKgNY9BkQkEPqN8y971oOMTV
+zSM8QxC6s9q4MM4Q1OYuvjECgYEAsO2V1AW95T45Ukd1FktpFlaomyQlJ0vKgyFO
+unEFV+vhETfpFTY7SzGCHxAXVh1vo62u5Gwayo/a9qQIhepa/IRnJGNv8luyxU1D
+ZPeBQjija0PMkPd1NvNNNuafDuBpoNbX1ev0MqeRZVsN2pAZXE5gbUiNA+8NqEsu
+Yre3EFECgYEA13rXE76zZgsefx+2spjqJDUWEmTDd1460xTtxCCgL9dy4rW5bgwo
+MvINphSUXOwSkn8Oja/IvpN28zSj9W/ci5wU52P5w4blkBmuj8UoCjP2FN1b1OBa
+86mkwVsCYUyyI2apuwrHP77yeb8jXZb+reqSns3hU+HyO/nUTVmnews=
+-----END RSA PRIVATE KEY-----
diff --git a/gcr/tests/files/client.pem b/gcr/tests/files/client.pem
new file mode 100644
index 0000000..04bc8ac
--- /dev/null
+++ b/gcr/tests/files/client.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAkUCAQkwDQYJKoZIhvcNAQEFBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND
+T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLExVDZXJ0aWZpY2F0
+ZSBBdXRob3JpdHkxFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN
+AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0xMTAxMTgwNjA0MTFaFw0yMTAxMTUwNjA0
+MTFaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN
+UExFMQ8wDQYDVQQDEwZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEgNDM/dg3t
+9DHNAPz/b87LSxEaKhoZ8AcNBym3LEOdCnXGEnKf0b9lkT5caXu5GAM84ahTCJ7n
+79RVNrqGKM7jbBdSX+ZUfkqJQPhOXD2+0niYQicH92nz78kxmjlbizvd3fM1BlO+
+C/++NWf2EAhORVAjvJrHNokJp3PTNRJ1WWteHeU9PwfGmWHKVc1IgvRFMH08604I
+ZzX5CcxIg/b56g27A7CBPh/KO/qKTDLFFNGc1T2asvY/P3+PeN6y+leFHStCTu7R
+Bi/l4hczZdnwq3BGT6mnjEN7wau2s7pA067SXimNOkYi5fgwspMHi8fJWmYyBypU
+mQBRzwfm77ECAwEAATANBgkqhkiG9w0BAQUFAAOBgQA3LuElj2QB9wQvmIxk2Jmb
+IPP2/WS8dwPoCv/N3+6nTx8yRsrILf4QsnEbbsxoYO5jW4r9Kt8m8B/M7YgnBDE9
+zlm7JbXKZf2isSm5TyT627Ymzxrzs5d+7o2eS7SN1DB6PyvRh2ye7EMbyEYD8ULi
+itDUkYkssNCVivYwVvJoMg==
+-----END CERTIFICATE-----
diff --git a/gcr/tests/files/generic-dsa.crt b/gcr/tests/files/generic-dsa.crt
new file mode 100644
index 0000000..5658a20
Binary files /dev/null and b/gcr/tests/files/generic-dsa.crt differ
diff --git a/gcr/tests/files/generic-dsa.key b/gcr/tests/files/generic-dsa.key
new file mode 100644
index 0000000..cdd7ca5
--- /dev/null
+++ b/gcr/tests/files/generic-dsa.key
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCdLeaVVA8HNMKFr0UUQe/bj6mJvO+I67hxn/KzCWnMjw9h6vtu
+TI06OI4XXmEHCVdUxykTkp1NSaTanoV8seEbJyyUgFQFBVaFOE8xDHp5RZghAKpd
+XFP2Yn8wj8y2VYSOveFKXj9ySj9A38nbG8mF0imBXNg/nL/EPCynR7JBVwIVAM1D
+KUetENlaaH+QeAO3IwcENMSZAoGBAJFujxH2WB5bU+sjjePwBTRev6qtYzPAXPd+
+srC747afIasS0Q/+pE0Q40bjdGNipf3fs5Cq8s0tYTYeNzAqUej1X5YI7TP+uJyR
+L7QdD06pg1BbdaAzSxnnGjf2b25IvPRdxgy1XetgOmT+qA8nXeLROgTLNOQqxG83
+ymuMi/w7AoGAfXLlo8mCQgAGy7y32k/2Onv8LXAL5hcQUEM7WQhHkU2QaXgh7sqm
+Ol4vvM97YZi5JIlR0wjP7+dZiJJnYSY5PMaGpAIk7hLGsPbJW6TnozAXwCPli1Xu
+ocubvrDWjZ/zSesnO3siGPCIuP97IqVbBKGQG/vJUwFL0ewb/+FUa78CFHgQdcw2
+4vVlnuMrqdmrfXMvzbrw
+-----END DSA PRIVATE KEY-----
diff --git a/gcr/tests/files/generic-dsa.pem b/gcr/tests/files/generic-dsa.pem
new file mode 100644
index 0000000..0d81ef2
--- /dev/null
+++ b/gcr/tests/files/generic-dsa.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAvugAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk
+ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp
+ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq
+hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTA3MTIyMDE4NDc0N1oXDTA4MDEx
+OTE4NDc0N1owbDETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW
+B0VYQU1QTEUxFDASBgNVBAMTC0dlbmVyaWMgRFNBMSYwJAYJKoZIhvcNAQkBFhdn
+ZW5lcmljLWRzYUBleGFtcGxlLmNvbTCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCd
+LeaVVA8HNMKFr0UUQe/bj6mJvO+I67hxn/KzCWnMjw9h6vtuTI06OI4XXmEHCVdU
+xykTkp1NSaTanoV8seEbJyyUgFQFBVaFOE8xDHp5RZghAKpdXFP2Yn8wj8y2VYSO
+veFKXj9ySj9A38nbG8mF0imBXNg/nL/EPCynR7JBVwIVAM1DKUetENlaaH+QeAO3
+IwcENMSZAoGBAJFujxH2WB5bU+sjjePwBTRev6qtYzPAXPd+srC747afIasS0Q/+
+pE0Q40bjdGNipf3fs5Cq8s0tYTYeNzAqUej1X5YI7TP+uJyRL7QdD06pg1BbdaAz
+SxnnGjf2b25IvPRdxgy1XetgOmT+qA8nXeLROgTLNOQqxG83ymuMi/w7A4GEAAKB
+gH1y5aPJgkIABsu8t9pP9jp7/C1wC+YXEFBDO1kIR5FNkGl4Ie7KpjpeL7zPe2GY
+uSSJUdMIz+/nWYiSZ2EmOTzGhqQCJO4SxrD2yVuk56MwF8Aj5YtV7qHLm76w1o2f
+80nrJzt7IhjwiLj/eyKlWwShkBv7yVMBS9HsG//hVGu/oxAwDjAMBgNVHRMBAf8E
+AjAAMA0GCSqGSIb3DQEBBQUAA4GBAPRyHCHjWKKVHZ7wSJQOS/Ve8e4DWFiuP9J8
+X4/sXEg59yWjScy9EovZVj5iELZI6OqUArvwVV6w6tewK0BAed4UGp+TyTHjPuJG
+WGxBm2AhtZUlYmpHQ+gA+E9weeFNQWP1QOATmFQ+r18eNH0rUONnR3G0XUYQTgd1
+LgEYxM4t
+-----END CERTIFICATE-----
diff --git a/gcr/tests/test-fingerprint.c b/gcr/tests/test-fingerprint.c
new file mode 100644
index 0000000..14ff5f3
--- /dev/null
+++ b/gcr/tests/test-fingerprint.c
@@ -0,0 +1,181 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+   Copyright (C) 2010 Collabora Ltd
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stefw@collabora.co.uk>
+*/
+
+#include "config.h"
+#define GCR_COMPILATION 1
+
+#include "gcr.h"
+#include "gcr/gcr-internal.h"
+#include "gcr/gcr-fingerprint.h"
+
+#include "gck/gck-test.h"
+
+#include "pkcs11/pkcs11n.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-testing.h"
+
+#include <glib.h>
+
+#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;
+} Test;
+
+static void
+setup (Test *test, gconstpointer unused)
+{
+	if (!g_file_get_contents ("files/client.crt", (gchar**)&test->cert_rsa,
+	                          &test->n_cert_rsa, NULL))
+		g_assert_not_reached ();
+	g_assert (test->cert_rsa);
+
+	if (!g_file_get_contents ("files/client.key", (gchar**)&test->key_rsa,
+	                          &test->n_key_rsa, NULL))
+		g_assert_not_reached ();
+	g_assert (test->key_rsa);
+
+	if (!g_file_get_contents ("files/generic-dsa.crt", (gchar**)&test->cert_dsa,
+	                          &test->n_cert_dsa, NULL))
+		g_assert_not_reached ();
+	g_assert (test->cert_dsa);
+
+	if (!g_file_get_contents ("files/generic-dsa.key", (gchar**)&test->key_dsa,
+	                          &test->n_key_dsa, NULL))
+		g_assert_not_reached ();
+	g_assert (test->key_dsa);
+}
+
+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);
+}
+
+static GckAttributes*
+parse_attributes_for_key (gpointer data, gsize n_data)
+{
+	GcrParser *parser;
+	GckAttributes *attrs;
+	GError *error = NULL;
+
+	parser = gcr_parser_new ();
+	gcr_parser_parse_data (parser, data, n_data, &error);
+	g_assert_no_error (error);
+
+	attrs = gcr_parser_get_parsed_attributes (parser);
+	g_assert (attrs);
+	gck_attributes_ref (attrs);
+
+	g_object_unref (parser);
+	return attrs;
+}
+
+static gconstpointer
+parse_subject_public_key_info_for_cert (gpointer data, gsize n_data, gsize *n_info)
+{
+	gconstpointer info;
+	GNode *asn;
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
+	g_assert (asn);
+
+	info = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", NULL), n_info);
+	g_assert (info);
+
+	egg_asn1x_destroy (asn);
+	return info;
+}
+
+static void
+test_rsa (Test *test, gconstpointer unused)
+{
+	GckAttributes *key;
+	gconstpointer info;
+	gsize n_info;
+	gpointer fingerprint1, fingerprint2;
+	gsize n_fingerprint1, n_fingerprint2;
+
+	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);
+
+	fingerprint1 = _gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
+	fingerprint2 = _gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
+
+	egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint2, n_fingerprint2);
+
+	g_free (fingerprint1);
+	g_free (fingerprint2);
+	gck_attributes_unref (key);
+}
+
+static void
+test_dsa (Test *test, gconstpointer unused)
+{
+	GckAttributes *key;
+	gconstpointer info;
+	gsize n_info;
+	gpointer fingerprint1, fingerprint2;
+	gsize n_fingerprint1, n_fingerprint2;
+
+	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);
+
+	fingerprint1 = _gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
+	fingerprint2 = _gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
+
+	egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint2, n_fingerprint2);
+
+	g_free (fingerprint1);
+	g_free (fingerprint2);
+	gck_attributes_unref (key);
+}
+
+int
+main (int argc, char **argv)
+{
+	const gchar *srcdir;
+
+	g_type_init ();
+	g_test_init (&argc, &argv, NULL);
+
+	srcdir = g_getenv ("SRCDIR");
+	if (srcdir && chdir (srcdir) < 0)
+		g_error ("couldn't change directory to: %s: %s", srcdir, g_strerror (errno));
+
+	g_test_add ("/gcr/fingerprint/rsa", Test, NULL, setup, test_rsa, teardown);
+	g_test_add ("/gcr/fingerprint/dsa", Test, NULL, setup, test_dsa, teardown);
+
+	return g_test_run ();
+}
