[gcr] gcr: Add support for viewing certificate requests



commit b189cedc1a41703dedd3e9a256e7689c34e38705
Author: Stef Walter <stefw collabora co uk>
Date:   Tue Nov 8 09:32:32 2011 +0100

    gcr: Add support for viewing certificate requests
    
     * Both PKCS#10/CSR and SPKAC
     * Update mime database for SPKAC and CSR
     * Associate viewer with these files
    
    https://bugzilla.gnome.org/show_bug.cgi?id=663604

 egg/pkix.asn                            |    5 +
 gcr/Makefile.am                         |    3 +
 gcr/gcr-certificate-renderer-private.h  |   51 +++
 gcr/gcr-certificate-renderer.c          |  392 ++++++++++++-----------
 gcr/gcr-certificate-req-renderer.c      |  550 +++++++++++++++++++++++++++++++
 gcr/gcr-certificate-req-renderer.h      |   70 ++++
 gcr/gcr-certificate.c                   |  100 +------
 gcr/gcr-crypto-types.xml                |   16 +
 gcr/gcr-key-size.c                      |  106 ++++++
 gcr/gcr-key-size.h                      |   33 ++
 gcr/gcr-oids.list                       |    1 +
 gcr/gcr-renderer.c                      |    2 +
 gcr/gcr-types.h                         |    2 +-
 gcr/gcr-viewer.desktop.in               |    2 +-
 gcr/gcr-viewer.desktop.in.in            |    2 +-
 gcr/tests/Makefile.am                   |    1 +
 gcr/tests/files/pem-with-attributes.req |   64 ++++
 gcr/tests/frob-request.c                |   96 ++++++
 po/POTFILES.in                          |    1 +
 19 files changed, 1217 insertions(+), 280 deletions(-)
---
diff --git a/egg/pkix.asn b/egg/pkix.asn
index 6cf966b..02c2732 100644
--- a/egg/pkix.asn
+++ b/egg/pkix.asn
@@ -1240,4 +1240,9 @@ SignedPublicKeyAndChallenge ::= SEQUENCE {
 	signature BIT STRING
 }
 
+-- pkcs-9 extension requests: added by gnome-keyring
+-- http://mirror.switch.ch/ftp/doc/standard/pkcs/pkcs-9/pkcs-9.txt
+
+ExtensionRequest ::= SEQUENCE OF Extension
+
 END
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index ebb4cc8..2045125 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -113,6 +113,7 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
 	gcr-importer.c gcr-importer.h \
 	gcr-import-interaction.c gcr-import-interaction.h \
 	gcr-internal.h \
+	gcr-key-size.c gcr-key-size.h \
 	gcr-library.c gcr-library.h \
 	gcr-memory.c \
 	gcr-memory-icon.c gcr-memory-icon.h \
@@ -138,6 +139,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
 	gcr-certificate-exporter.c gcr-certificate-exporter.h \
 	gcr-certificate-extensions.c gcr-certificate-extensions.h \
 	gcr-certificate-renderer.c gcr-certificate-renderer.h \
+	gcr-certificate-req-renderer.c gcr-certificate-req-renderer.h \
 	gcr-certificate-widget.c gcr-certificate-widget.h \
 	gcr-collection-model.c gcr-collection-model.h \
 	gcr-combo-selector.c gcr-combo-selector.h \
@@ -150,6 +152,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
 	gcr-gnupg-records.c gcr-gnupg-records.h \
 	gcr-import-button.c gcr-import-button.h \
 	gcr-key-renderer.c gcr-key-renderer.h \
+	gcr-key-size.c gcr-key-size.h \
 	gcr-key-widget.c gcr-key-widget.h \
 	gcr-list-selector.c gcr-list-selector.h gcr-list-selector-private.h \
 	gcr-live-search.c gcr-live-search.h \
diff --git a/gcr/gcr-certificate-renderer-private.h b/gcr/gcr-certificate-renderer-private.h
new file mode 100644
index 0000000..f7dadbf
--- /dev/null
+++ b/gcr/gcr-certificate-renderer-private.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly."
+#endif
+
+#ifndef __GCR_CERTIFICATE_RENDERER_PRIVATE_H__
+#define __GCR_CERTIFICATE_RENDERER_PRIVATE_H__
+
+#include "gcr-display-view.h"
+#include "gcr-renderer.h"
+
+G_BEGIN_DECLS
+
+void      _gcr_certificate_renderer_append_distinguished_name        (GcrRenderer *renderer,
+                                                                      GcrDisplayView *view,
+                                                                      GNode *dn);
+
+void      _gcr_certificate_renderer_append_subject_public_key        (GcrRenderer *renderer,
+                                                                      GcrDisplayView *view,
+                                                                      guint key_size,
+                                                                      GNode *subject_public_key);
+
+void      _gcr_certificate_renderer_append_signature                 (GcrRenderer *renderer,
+                                                                      GcrDisplayView *view,
+                                                                      GNode *asn);
+
+void      _gcr_certificate_renderer_append_extension                 (GcrRenderer *renderer,
+                                                                      GcrDisplayView *view,
+                                                                      GNode *asn);
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_RENDERER_PRIVATE_H__ */
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
index ebceda3..ae3f73c 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-extensions.h"
 #include "gcr-certificate-renderer.h"
+#include "gcr-certificate-renderer-private.h"
 #include "gcr-display-view.h"
 #include "gcr-fingerprint.h"
 #include "gcr-icons.h"
@@ -102,11 +103,10 @@ calculate_label (GcrCertificateRenderer *self)
 }
 
 static gboolean
-append_extension_basic_constraints (GcrCertificateRenderer *self,
+append_extension_basic_constraints (GcrRenderer *renderer,
                                     GcrDisplayView *view,
                                     EggBytes *data)
 {
-	GcrRenderer *renderer = GCR_RENDERER (self);
 	gboolean is_ca = FALSE;
 	gint path_len = -1;
 	gchar *number;
@@ -128,11 +128,10 @@ append_extension_basic_constraints (GcrCertificateRenderer *self,
 }
 
 static gboolean
-append_extension_extended_key_usage (GcrCertificateRenderer *self,
+append_extension_extended_key_usage (GcrRenderer *renderer,
                                      GcrDisplayView *view,
                                      EggBytes *data)
 {
-	GcrRenderer *renderer = GCR_RENDERER (self);
 	GQuark *oids;
 	GString *text;
 	guint i;
@@ -161,11 +160,10 @@ append_extension_extended_key_usage (GcrCertificateRenderer *self,
 }
 
 static gboolean
-append_extension_subject_key_identifier (GcrCertificateRenderer *self,
+append_extension_subject_key_identifier (GcrRenderer *renderer,
                                          GcrDisplayView *view,
                                          EggBytes *data)
 {
-	GcrRenderer *renderer = GCR_RENDERER (self);
 	gpointer keyid;
 	gsize n_keyid;
 
@@ -194,11 +192,10 @@ static const struct {
 };
 
 static gboolean
-append_extension_key_usage (GcrCertificateRenderer *self,
+append_extension_key_usage (GcrRenderer *renderer,
                             GcrDisplayView *view,
                             EggBytes *data)
 {
-	GcrRenderer *renderer = GCR_RENDERER (self);
 	gulong key_usage;
 	GString *text;
 	guint i;
@@ -225,11 +222,10 @@ append_extension_key_usage (GcrCertificateRenderer *self,
 }
 
 static gboolean
-append_extension_subject_alt_name (GcrCertificateRenderer *self,
+append_extension_subject_alt_name (GcrRenderer *renderer,
                                    GcrDisplayView *view,
                                    EggBytes *data)
 {
-	GcrRenderer *renderer = GCR_RENDERER (self);
 	GArray *general_names;
 	GcrGeneralName *general;
 	guint i;
@@ -256,12 +252,13 @@ append_extension_subject_alt_name (GcrCertificateRenderer *self,
 	return TRUE;
 }
 
-
 static gboolean
-append_extension_hex (GcrCertificateRenderer *self, GcrDisplayView *view,
-                      GQuark oid, gconstpointer data, gsize n_data)
+append_extension_hex (GcrRenderer *renderer,
+                      GcrDisplayView *view,
+                      GQuark oid,
+                      gconstpointer data,
+                      gsize n_data)
 {
-	GcrRenderer *renderer = GCR_RENDERER (self);
 	const gchar *text;
 
 	_gcr_display_view_append_heading (view, renderer, _("Extension"));
@@ -275,107 +272,6 @@ append_extension_hex (GcrCertificateRenderer *self, GcrDisplayView *view,
 }
 
 static gboolean
-append_extension (GcrCertificateRenderer *self,
-                  GcrDisplayView *view,
-                  GNode *asn,
-                  gint index)
-{
-	GcrRenderer *renderer = GCR_RENDERER (self);
-	GNode *node;
-	GQuark oid;
-	EggBytes *value;
-	gboolean critical;
-	gboolean ret = FALSE;
-
-	/* Make sure it is present */
-	node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
-	if (node == NULL)
-		return FALSE;
-
-	/* Dig out the OID */
-	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
-	g_return_val_if_fail (oid, FALSE);
-
-	/* Extension 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);
-	else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
-		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);
-	else if (oid == GCR_OID_KEY_USAGE)
-		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);
-
-	/* Otherwise the default raw display */
-	if (ret == FALSE)
-		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)) {
-		_gcr_display_view_append_value (view, renderer, _("Critical"),
-		                                critical ? _("Yes") : _("No"), FALSE);
-	}
-
-	egg_bytes_unref (value);
-	return ret;
-}
-
-typedef struct _on_parsed_dn_args {
-	GcrCertificateRenderer *renderer;
-	GcrDisplayView *view;
-} on_parsed_dn_args;
-
-static void
-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;
-	const gchar *attr;
-	const gchar *desc;
-	gchar *field = NULL;
-	gchar *display;
-
-	g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
-
-	attr = egg_oid_get_name (oid);
-	desc = egg_oid_get_description (oid);
-
-	/* Combine them into something sane */
-	if (attr && desc) {
-		if (strcmp (attr, desc) == 0)
-			field = g_strdup (attr);
-		else
-			field = g_strdup_printf ("%s (%s)", attr, desc);
-	} else if (!attr && !desc) {
-		field = g_strdup ("");
-	} else if (attr) {
-		field = g_strdup (attr);
-	} else if (desc) {
-		field = g_strdup (desc);
-	} else {
-		g_assert_not_reached ();
-	}
-
-	display = egg_dn_print_value (oid, value);
-	if (display == NULL)
-		display = g_strdup ("");
-
-	_gcr_display_view_append_value (view, GCR_RENDERER (self), field, display, FALSE);
-	g_free (field);
-	g_free (display);
-}
-
-static gboolean
 on_delete_unref_dialog (GtkWidget *widget, GdkEvent *event, gpointer data)
 {
 	g_object_unref (widget);
@@ -574,21 +470,17 @@ static void
 gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 {
 	GcrCertificateRenderer *self;
+	GNode *extension;
 	gconstpointer data;
-	gsize n_data, n_raw;
+	gsize n_data;
 	GcrDisplayView *view;
-	on_parsed_dn_args args;
-	const gchar *text;
 	GcrCertificate *cert;
-	gpointer raw;
 	EggBytes *number;
 	gulong version;
 	guint bits, index;
 	gchar *display;
 	EggBytes *bytes;
-	EggBytes *value;
 	GNode *asn;
-	GQuark oid;
 	GDate date;
 	GIcon *icon;
 
@@ -643,16 +535,15 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 
 	_gcr_display_view_start_details (view, renderer);
 
-	args.renderer = self;
-	args.view = view;
-
 	/* The subject */
 	_gcr_display_view_append_heading (view, renderer, _("Subject Name"));
-	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, &args);
+	_gcr_certificate_renderer_append_distinguished_name (renderer, view,
+	                                                     egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL));
 
 	/* The Issuer */
 	_gcr_display_view_append_heading (view, renderer, _("Issuer Name"));
-	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, &args);
+	_gcr_certificate_renderer_append_distinguished_name (renderer, view,
+	                                                     egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL));
 
 	/* The Issued Parameters */
 	_gcr_display_view_append_heading (view, renderer, _("Issued Certificate"));
@@ -689,73 +580,25 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	_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"));
-
-	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
-	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));
-	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);
-	}
-
-	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"));
-
-	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
-	                                                  "algorithm", "algorithm", NULL));
-	text = egg_oid_get_description (oid);
-	_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));
-	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) {
-		display = g_strdup_printf ("%u", bits);
-		_gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE);
-		g_free (display);
-	}
-
-	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate",
-	                                                   "subjectPublicKeyInfo", NULL));
-	raw = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (value),
-	                                                    egg_bytes_get_size (value),
-	                                                    G_CHECKSUM_SHA1, &n_raw);
-	_gcr_display_view_append_hex (view, renderer, _("Key SHA1 Fingerprint"), raw, n_raw);
-	egg_bytes_unref (value);
-	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);
+	_gcr_certificate_renderer_append_subject_public_key (renderer, view, bits,
+	                                                     egg_asn1x_node (asn, "tbsCertificate",
+	                                                                     "subjectPublicKeyInfo", NULL));
 
 	/* Extensions */
 	for (index = 1; TRUE; ++index) {
-		if (!append_extension (self, view, asn, index))
+		extension = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
+		if (extension == NULL)
 			break;
+		_gcr_certificate_renderer_append_extension (renderer, view, extension);
 	}
 
+	/* Signature */
+	_gcr_display_view_append_heading (view, renderer, _("Signature"));
+	_gcr_certificate_renderer_append_signature (renderer, view, asn);
+
 	egg_asn1x_destroy (asn);
 	_gcr_display_view_end (view, renderer);
 }
@@ -939,3 +782,184 @@ gcr_certificate_renderer_set_attributes (GcrCertificateRenderer *self, GckAttrib
 	g_object_notify (G_OBJECT (self), "attributes");
 
 }
+
+typedef struct {
+	GcrRenderer *renderer;
+	GcrDisplayView *view;
+} AppendDnClosure;
+
+static void
+on_parsed_dn_part (guint index,
+                   GQuark oid,
+                   EggBytes *value,
+                   gpointer user_data)
+{
+	GcrRenderer *renderer = ((AppendDnClosure *)user_data)->renderer;
+	GcrDisplayView *view = ((AppendDnClosure *)user_data)->view;
+	const gchar *attr;
+	const gchar *desc;
+	gchar *field = NULL;
+	gchar *display;
+
+	attr = egg_oid_get_name (oid);
+	desc = egg_oid_get_description (oid);
+
+	/* Combine them into something sane */
+	if (attr && desc) {
+		if (strcmp (attr, desc) == 0)
+			field = g_strdup (attr);
+		else
+			field = g_strdup_printf ("%s (%s)", attr, desc);
+	} else if (!attr && !desc) {
+		field = g_strdup ("");
+	} else if (attr) {
+		field = g_strdup (attr);
+	} else if (desc) {
+		field = g_strdup (desc);
+	} else {
+		g_assert_not_reached ();
+	}
+
+	display = egg_dn_print_value (oid, value);
+	if (display == NULL)
+		display = g_strdup ("");
+
+	_gcr_display_view_append_value (view, renderer, field, display, FALSE);
+	g_free (field);
+	g_free (display);
+}
+
+
+void
+_gcr_certificate_renderer_append_distinguished_name (GcrRenderer *renderer,
+                                                     GcrDisplayView *view,
+                                                     GNode *dn)
+{
+	AppendDnClosure closure;
+
+	g_return_if_fail (GCR_IS_RENDERER (renderer));
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (view));
+	g_return_if_fail (dn != NULL);
+
+	closure.renderer = renderer;
+	closure.view = view;
+	egg_dn_parse (dn, on_parsed_dn_part, &closure);
+}
+
+void
+_gcr_certificate_renderer_append_subject_public_key (GcrRenderer *renderer,
+                                                     GcrDisplayView *view,
+                                                     guint key_nbits,
+                                                     GNode *subject_public_key)
+{
+	const gchar *text;
+	gchar *display;
+	EggBytes *value;
+	guchar *raw;
+	gsize n_raw;
+	GQuark oid;
+	guint bits;
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
+	                                                  "algorithm", "algorithm", NULL));
+	text = egg_oid_get_description (oid);
+	_gcr_display_view_append_value (view, renderer, _("Key Algorithm"), text, FALSE);
+
+	value = egg_asn1x_get_raw_element (egg_asn1x_node (subject_public_key,
+	                                                   "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);
+	}
+
+	if (key_nbits > 0) {
+		display = g_strdup_printf ("%u", key_nbits);
+		_gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE);
+		g_free (display);
+	}
+
+	value = egg_asn1x_get_raw_element (subject_public_key);
+	raw = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (value),
+	                                                    egg_bytes_get_size (value),
+	                                                    G_CHECKSUM_SHA1, &n_raw);
+	_gcr_display_view_append_hex (view, renderer, _("Key SHA1 Fingerprint"), raw, n_raw);
+	egg_bytes_unref (value);
+	g_free (raw);
+
+	value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL), &bits);
+	_gcr_display_view_append_hex (view, renderer, _("Public Key"),
+	                              egg_bytes_get_data (value), bits / 8);
+	egg_bytes_unref (value);
+}
+
+void
+_gcr_certificate_renderer_append_signature (GcrRenderer *renderer,
+                                            GcrDisplayView *view,
+                                            GNode *asn)
+{
+	const gchar *text;
+	EggBytes *value;
+	GQuark oid;
+	guint bits;
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
+	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));
+	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);
+	}
+
+	value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), &bits);
+	_gcr_display_view_append_hex (view, renderer, _("Signature"),
+	                              egg_bytes_get_data (value), bits / 8);
+	egg_bytes_unref (value);
+}
+
+void
+_gcr_certificate_renderer_append_extension (GcrRenderer *renderer,
+                                            GcrDisplayView *view,
+                                            GNode *node)
+{
+	GQuark oid;
+	EggBytes *value;
+	gboolean critical;
+	gboolean ret = FALSE;
+
+	/* Dig out the OID */
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
+	g_return_if_fail (oid);
+
+	/* Extension 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 (renderer, view, value);
+	else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
+		ret = append_extension_extended_key_usage (renderer, view, value);
+	else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER)
+		ret = append_extension_subject_key_identifier (renderer, view, value);
+	else if (oid == GCR_OID_KEY_USAGE)
+		ret = append_extension_key_usage (renderer, view, value);
+	else if (oid == GCR_OID_SUBJECT_ALT_NAME)
+		ret = append_extension_subject_alt_name (renderer, view, value);
+
+	/* Otherwise the default raw display */
+	if (ret == FALSE)
+		ret = append_extension_hex (renderer, 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)) {
+		_gcr_display_view_append_value (view, renderer, _("Critical"),
+		                                critical ? _("Yes") : _("No"), FALSE);
+	}
+}
diff --git a/gcr/gcr-certificate-req-renderer.c b/gcr/gcr-certificate-req-renderer.c
new file mode 100644
index 0000000..78ebad6
--- /dev/null
+++ b/gcr/gcr-certificate-req-renderer.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gcr-certificate-renderer-private.h"
+#include "gcr-certificate-req-renderer.h"
+#include "gcr-display-view.h"
+#include "gcr-key-size.h"
+#include "gcr-oids.h"
+
+#if 0
+#include "gcr-certificate.h"
+#include "gcr-certificate-exporter.h"
+#include "gcr-certificate-extensions.h"
+#include "gcr-certificate-renderer.h"
+#include "gcr-fingerprint.h"
+#include "gcr-icons.h"
+#include "gcr-oids.h"
+#include "gcr-simple-certificate.h"
+#include "gcr-renderer.h"
+#endif
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-dn.h"
+#include "egg/egg-oid.h"
+
+#include "gck/gck.h"
+
+#include <glib/gi18n-lib.h>
+
+/**
+ * GcrCertificateReqRenderer:
+ *
+ * An implementation of #GcrRenderer which renders certificate requests
+ */
+
+/**
+ * GcrCertificateReqRendererClass:
+ * @parent_class: The parent class
+ *
+ * The class for #GcrCertificateReqRenderer
+ */
+
+enum {
+	PROP_0,
+	PROP_LABEL,
+	PROP_ATTRIBUTES
+};
+
+struct _GcrCertificateReqRendererPrivate {
+	GckAttributes *attrs;
+	gchar *label;
+
+	guint key_size;
+	gulong type;
+	GNode *asn;
+};
+
+static void     _gcr_certificate_req_renderer_iface    (GcrRendererIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrCertificateReqRenderer, _gcr_certificate_req_renderer, G_TYPE_OBJECT,
+	G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, _gcr_certificate_req_renderer_iface);
+);
+
+static gchar*
+calculate_label (GcrCertificateReqRenderer *self)
+{
+	gchar *label = NULL;
+
+	if (self->pv->label)
+		return g_strdup (self->pv->label);
+
+	if (self->pv->attrs) {
+		if (gck_attributes_find_string (self->pv->attrs, CKA_LABEL, &label))
+			return label;
+	}
+
+	if (self->pv->asn && self->pv->type == CKQ_GCR_PKCS10) {
+		label = egg_dn_read_part (egg_asn1x_node (self->pv->asn,
+		                                          "certificationRequestInfo",
+		                                          "subject",
+		                                          "rdnSequence",
+		                                          NULL), "CN");
+	}
+
+	if (label != NULL)
+		return label;
+
+	return g_strdup (_("Certificate request"));
+}
+
+static void
+_gcr_certificate_req_renderer_init (GcrCertificateReqRenderer *self)
+{
+	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_REQ_RENDERER,
+	                                         GcrCertificateReqRendererPrivate));
+}
+
+static void
+_gcr_certificate_req_renderer_finalize (GObject *obj)
+{
+	GcrCertificateReqRenderer *self = GCR_CERTIFICATE_REQ_RENDERER (obj);
+
+	if (self->pv->attrs)
+		gck_attributes_unref (self->pv->attrs);
+	self->pv->attrs = NULL;
+
+	g_free (self->pv->label);
+	self->pv->label = NULL;
+
+	egg_asn1x_destroy (self->pv->asn);
+
+	G_OBJECT_CLASS (_gcr_certificate_req_renderer_parent_class)->finalize (obj);
+}
+
+static void
+_gcr_certificate_req_renderer_set_property (GObject *obj,
+                                            guint prop_id,
+                                            const GValue *value,
+                                            GParamSpec *pspec)
+{
+	GcrCertificateReqRenderer *self = GCR_CERTIFICATE_REQ_RENDERER (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_free (self->pv->label);
+		self->pv->label = g_value_dup_string (value);
+		g_object_notify (obj, "label");
+		gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+		break;
+	case PROP_ATTRIBUTES:
+		_gcr_certificate_req_renderer_set_attributes (self, g_value_get_boxed (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+_gcr_certificate_req_renderer_get_property (GObject *obj,
+                                            guint prop_id,
+                                            GValue *value,
+                                            GParamSpec *pspec)
+{
+	GcrCertificateReqRenderer *self = GCR_CERTIFICATE_REQ_RENDERER (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_take_string (value, calculate_label (self));
+		break;
+	case PROP_ATTRIBUTES:
+		g_value_set_boxed (value, self->pv->attrs);
+		break;
+	default:
+		gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
+		break;
+	}
+}
+
+static void
+_gcr_certificate_req_renderer_class_init (GcrCertificateReqRendererClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckAttributes *registered;
+
+	_gcr_oids_init ();
+
+	g_type_class_add_private (klass, sizeof (GcrCertificateReqRendererPrivate));
+
+	gobject_class->finalize = _gcr_certificate_req_renderer_finalize;
+	gobject_class->set_property = _gcr_certificate_req_renderer_set_property;
+	gobject_class->get_property = _gcr_certificate_req_renderer_get_property;
+
+	/**
+	 * GcrCertificateReqRenderer:attributes:
+	 *
+	 * The certificate attributes to display. One of the attributes must be
+	 * a CKA_VALUE type attribute which contains a DER encoded certificate.
+	 */
+	g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
+	           g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes",
+	                               GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
+
+	/**
+	 * GcrCertificateReqRenderer:label:
+	 *
+	 * The label to display.
+	 */
+	g_object_class_install_property (gobject_class, PROP_LABEL,
+	           g_param_spec_string ("label", "Label", "Certificate Label",
+	                                "", G_PARAM_READWRITE));
+
+	/* Register this as a renderer which can be loaded */
+	registered = gck_attributes_new ();
+	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_CERTIFICATE_REQUEST);
+	gck_attributes_add_ulong (registered, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_PKCS10);
+	gcr_renderer_register (GCR_TYPE_CERTIFICATE_REQ_RENDERER, registered);
+	gck_attributes_unref (registered);
+
+	registered = gck_attributes_new ();
+	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_CERTIFICATE_REQUEST);
+	gck_attributes_add_ulong (registered, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_SPKAC);
+	gcr_renderer_register (GCR_TYPE_CERTIFICATE_REQ_RENDERER, registered);
+	gck_attributes_unref (registered);
+}
+
+static gboolean
+append_extension_request (GcrRenderer *renderer,
+                          GcrDisplayView *view,
+                          GNode *attribute)
+{
+	EggBytes *value;
+	GNode *node;
+	GNode *asn;
+	guint i;
+
+	node = egg_asn1x_node (attribute, "values", 1, NULL);
+	if (node == NULL)
+		return FALSE;
+
+	value = egg_asn1x_get_raw_element (node);
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtensionRequest", value);
+	if (asn == NULL)
+		return FALSE;
+
+	for (i = 1; TRUE; i++) {
+		node = egg_asn1x_node (asn, i, NULL);
+		if (node == NULL)
+			break;
+		_gcr_certificate_renderer_append_extension (renderer, view, node);
+	}
+
+	egg_asn1x_destroy (asn);
+	return TRUE;
+}
+
+static void
+append_attribute (GcrRenderer *renderer,
+                  GcrDisplayView *view,
+                  GNode *attribute)
+{
+	GQuark oid;
+	EggBytes *value;
+	const gchar *text;
+	GNode *node;
+	gboolean ret = FALSE;
+	gint i;
+
+	/* Dig out the OID */
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (attribute, "type", NULL));
+	g_return_if_fail (oid);
+
+	if (oid == GCR_OID_PKCS9_ATTRIBUTE_EXTENSION_REQ)
+		ret = append_extension_request (renderer, view, attribute);
+
+	if (!ret) {
+		_gcr_display_view_append_heading (view, renderer, _("Attribute"));
+
+		/* Extension type */
+		text = egg_oid_get_description (oid);
+		_gcr_display_view_append_value (view, renderer, _("Type"), text, FALSE);
+
+		for (i = 1; TRUE; i++) {
+			node = egg_asn1x_node (attribute, "values", i, NULL);
+			if (node == NULL)
+				break;
+			value = egg_asn1x_get_raw_element (node);
+			_gcr_display_view_append_hex (view, renderer, _("Value"),
+			                              egg_bytes_get_data (value),
+			                              egg_bytes_get_size (value));
+			egg_bytes_unref (value);
+		}
+	}
+}
+
+static guint
+ensure_key_size (GcrCertificateReqRenderer *self,
+                 GNode *public_key)
+{
+	if (self->pv->key_size)
+		return self->pv->key_size;
+
+	self->pv->key_size = _gcr_key_size_calculate (public_key);
+	return self->pv->key_size;
+}
+
+static void
+render_pkcs10_certificate_req (GcrCertificateReqRenderer *self,
+                               GcrDisplayView *view)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	GNode *public_key;
+	GNode *attribute;
+	GNode *subject;
+	gchar *display;
+	gulong version;
+	guint bits;
+	guint i;
+
+	display = calculate_label (self);
+	_gcr_display_view_append_title (view, renderer, display);
+	g_free (display);
+
+	_gcr_display_view_append_content (view, renderer, _("Certificate request"), NULL);
+
+	subject = egg_asn1x_node (self->pv->asn, "certificationRequestInfo",
+	                          "subject", "rdnSequence", NULL);
+	display = egg_dn_read_part (subject, "CN");
+	_gcr_display_view_append_content (view, renderer, _("Identity"), display);
+	g_free (display);
+
+	_gcr_display_view_start_details (view, renderer);
+
+	/* The subject */
+	_gcr_display_view_append_heading (view, renderer, _("Subject Name"));
+	_gcr_certificate_renderer_append_distinguished_name (renderer, view, subject);
+
+	/* The certificate request type */
+	_gcr_display_view_append_heading (view, renderer, _("Certificate request"));
+	_gcr_display_view_append_value (view, renderer, _("Type"), "PKCS#10", FALSE);
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (self->pv->asn,
+	                                                     "certificationRequestInfo",
+	                                                     "version", NULL), &version))
+		g_return_if_reached ();
+	display = g_strdup_printf ("%lu", version + 1);
+	_gcr_display_view_append_value (view, renderer, _("Version"), display, FALSE);
+	g_free (display);
+
+	_gcr_display_view_append_heading (view, renderer, _("Public Key Info"));
+	public_key = egg_asn1x_node (self->pv->asn, "certificationRequestInfo", "subjectPKInfo", NULL);
+	bits = ensure_key_size (self, public_key);
+	_gcr_certificate_renderer_append_subject_public_key (renderer, view,
+	                                                     bits, public_key);
+
+	/* Attributes */
+	for (i = 1; TRUE; ++i) {
+		/* Make sure it is present */
+		attribute = egg_asn1x_node (self->pv->asn, "certificationRequestInfo", "attributes", i, NULL);
+		if (attribute == NULL)
+			break;
+		append_attribute (renderer, view, attribute);
+	}
+
+	/* Signature */
+	_gcr_display_view_append_heading (view, renderer, _("Signature"));
+	_gcr_certificate_renderer_append_signature (renderer, view, self->pv->asn);
+}
+
+static void
+render_spkac_certificate_req (GcrCertificateReqRenderer *self,
+                              GcrDisplayView *view)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	GNode *public_key;
+	gchar *display;
+	guint bits;
+
+	display = calculate_label (self);
+	_gcr_display_view_append_title (view, renderer, display);
+	g_free (display);
+
+	_gcr_display_view_append_content (view, renderer, _("Certificate request"), NULL);
+
+	_gcr_display_view_start_details (view, renderer);
+
+	/* The certificate request type */
+	_gcr_display_view_append_heading (view, renderer, _("Certificate request"));
+	_gcr_display_view_append_value (view, renderer, _("Type"), "SPKAC", FALSE);
+
+	display = egg_asn1x_get_string_as_utf8 (egg_asn1x_node (self->pv->asn, "publicKeyAndChallenge",
+	                                                        "challenge", NULL), NULL);
+	_gcr_display_view_append_value (view, renderer, _("Challenge"), display, FALSE);
+	g_free (display);
+
+	_gcr_display_view_append_heading (view, renderer, _("Public Key Info"));
+	public_key = egg_asn1x_node (self->pv->asn, "publicKeyAndChallenge", "spki", NULL);
+	bits = ensure_key_size (self, public_key);
+	_gcr_certificate_renderer_append_subject_public_key (renderer, view,
+	                                                     bits, public_key);
+
+	/* Signature */
+	_gcr_display_view_append_heading (view, renderer, _("Signature"));
+	_gcr_certificate_renderer_append_signature (renderer, view, self->pv->asn);
+}
+
+static void
+gcr_certificate_req_renderer_render (GcrRenderer *renderer,
+                                     GcrViewer *viewer)
+{
+	GcrCertificateReqRenderer *self;
+	GcrDisplayView *view;
+	GIcon *icon;
+
+	self = GCR_CERTIFICATE_REQ_RENDERER (renderer);
+
+	if (GCR_IS_DISPLAY_VIEW (viewer)) {
+		view = GCR_DISPLAY_VIEW (viewer);
+
+	} else {
+		g_warning ("GcrCertificateReqRenderer only works with internal specific "
+		           "GcrViewer returned by gcr_viewer_new().");
+		return;
+	}
+
+	_gcr_display_view_begin (view, renderer);
+
+	icon = g_themed_icon_new ("dialog-question");
+	_gcr_display_view_set_icon (view, GCR_RENDERER (self), icon);
+	g_object_unref (icon);
+
+	switch (self->pv->type) {
+	case CKQ_GCR_PKCS10:
+		render_pkcs10_certificate_req (self, view);
+		break;
+	case CKQ_GCR_SPKAC:
+		render_spkac_certificate_req (self, view);
+		break;
+	default:
+		g_warning ("unknown request type in GcrCertificateReqRenderer");
+		break;
+	}
+
+	_gcr_display_view_end (view, renderer);
+}
+
+static void
+_gcr_certificate_req_renderer_iface (GcrRendererIface *iface)
+{
+	iface->render_view = gcr_certificate_req_renderer_render;
+}
+
+/**
+ * gcr_certificate_req_renderer_new_for_attributes:
+ * @label: (allow-none): the label to display
+ * @attrs: the attributes to display
+ *
+ * Create a new certificate request renderer to display the label and attributes.
+ * One of the attributes should be a CKA_VALUE type attribute containing a DER
+ * encoded PKCS\#10 certificate request or an SPKAC request.
+ *
+ * Returns: (transfer full): a newly allocated #GcrCertificateReqRenderer, which
+ *          should be released with g_object_unref()
+ */
+GcrRenderer *
+_gcr_certificate_req_renderer_new_for_attributes (const gchar *label,
+                                                  GckAttributes *attrs)
+{
+	return g_object_new (GCR_TYPE_CERTIFICATE_REQ_RENDERER,
+	                     "label", label,
+	                     "attributes", attrs,
+	                     NULL);
+}
+
+/**
+ * gcr_certificate_req_renderer_get_attributes:
+ * @self: the renderer
+ *
+ * Get the PKCS\#11 attributes, if any, set for this renderer to display.
+ *
+ * Returns: (allow-none) (transfer none): the attributes, owned by the renderer
+ */
+GckAttributes *
+_gcr_certificate_req_renderer_get_attributes (GcrCertificateReqRenderer *self)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_REQ_RENDERER (self), NULL);
+	return self->pv->attrs;
+}
+
+/**
+ * gcr_certificate_req_renderer_set_attributes:
+ * @self: the renderer
+ * @attrs: (allow-none): attributes to set
+ *
+ * Set the PKCS\#11 attributes for this renderer to display. One of the attributes
+ * should be a CKA_VALUE type attribute containing a DER encoded PKCS\#10
+ * certificate request or an SPKAC request.
+ */
+void
+_gcr_certificate_req_renderer_set_attributes (GcrCertificateReqRenderer *self,
+                                              GckAttributes *attrs)
+{
+	GckAttribute *value;
+	GNode *asn = NULL;
+	gulong type = 0;
+	EggBytes *bytes;
+
+	g_return_if_fail (GCR_IS_CERTIFICATE_REQ_RENDERER (self));
+
+	if (attrs) {
+		value = gck_attributes_find (attrs, CKA_VALUE);
+		if (value == NULL) {
+			g_warning ("no CKA_VALUE found in attributes passed to "
+				   "GcrCertificateReqRenderer attributes property");
+			return;
+		}
+
+		bytes = egg_bytes_new_with_free_func (value->value, value->length,
+		                                      gck_attributes_unref, gck_attributes_ref (attrs));
+
+		asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-10-CertificationRequest", bytes);
+		if (asn != NULL) {
+			type = CKQ_GCR_PKCS10;
+		} else {
+			asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SignedPublicKeyAndChallenge", bytes);
+			if (asn != NULL) {
+				type = CKQ_GCR_SPKAC;
+			} else {
+				g_warning ("the data contained in the CKA_VALUE attribute passed to "
+				           "GcrCertificateReqRenderer was not valid DER encoded PKCS#10 "
+				           "or SPKAC");
+			}
+		}
+
+		egg_bytes_unref (bytes);
+
+		if (type == 0)
+			return;
+
+		gck_attributes_ref (attrs);
+	}
+
+	if (self->pv->attrs)
+		gck_attributes_unref (self->pv->attrs);
+	self->pv->attrs = attrs;
+	self->pv->asn = asn;
+	self->pv->type = type;
+	self->pv->key_size = 0; /* calculated later */
+
+	gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+	g_object_notify (G_OBJECT (self), "attributes");
+}
diff --git a/gcr/gcr-certificate-req-renderer.h b/gcr/gcr-certificate-req-renderer.h
new file mode 100644
index 0000000..856f925
--- /dev/null
+++ b/gcr/gcr-certificate-req-renderer.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly."
+#endif
+
+#ifndef __GCR_CERTIFICATE_REQ_RENDERER_H__
+#define __GCR_CERTIFICATE_REQ_RENDERER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-certificate.h"
+#include "gcr-renderer.h"
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_CERTIFICATE_REQ_RENDERER               (_gcr_certificate_req_renderer_get_type ())
+#define GCR_CERTIFICATE_REQ_RENDERER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_REQ_RENDERER, GcrCertificateReqRenderer))
+#define GCR_CERTIFICATE_REQ_RENDERER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_REQ_RENDERER, GcrCertificateReqRendererClass))
+#define GCR_IS_CERTIFICATE_REQ_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_REQ_RENDERER))
+#define GCR_IS_CERTIFICATE_REQ_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_REQ_RENDERER))
+#define GCR_CERTIFICATE_REQ_RENDERER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_REQ_RENDERER, GcrCertificateReqRendererClass))
+
+typedef struct _GcrCertificateReqRenderer GcrCertificateReqRenderer;
+typedef struct _GcrCertificateReqRendererClass GcrCertificateReqRendererClass;
+typedef struct _GcrCertificateReqRendererPrivate GcrCertificateReqRendererPrivate;
+
+struct _GcrCertificateReqRenderer {
+	GObject parent;
+
+	/*< private >*/
+	GcrCertificateReqRendererPrivate *pv;
+};
+
+struct _GcrCertificateReqRendererClass {
+	GObjectClass parent_class;
+};
+
+GType             _gcr_certificate_req_renderer_get_type              (void);
+
+GcrRenderer *     _gcr_certificate_req_renderer_new_for_attributes    (const gchar *label,
+                                                                       struct _GckAttributes *attrs);
+
+GckAttributes *   _gcr_certificate_req_renderer_get_attributes        (GcrCertificateReqRenderer *self);
+
+void              _gcr_certificate_req_renderer_set_attributes        (GcrCertificateReqRenderer *self,
+                                                                       GckAttributes *attrs);
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_REQ_RENDERER_H__ */
diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c
index 889c67a..75860b5 100644
--- a/gcr/gcr-certificate.c
+++ b/gcr/gcr-certificate.c
@@ -25,6 +25,7 @@
 #include "gcr-comparable.h"
 #include "gcr-icons.h"
 #include "gcr-internal.h"
+#include "gcr-key-size.h"
 #include "gcr-oids.h"
 
 #include "egg/egg-asn1x.h"
@@ -177,97 +178,6 @@ certificate_info_load (GcrCertificate *cert)
 	return info;
 }
 
-static guint
-calculate_rsa_key_size (EggBytes *data)
-{
-	EggBytes *content;
-	guint key_size;
-	GNode *asn;
-
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
-	g_return_val_if_fail (asn != NULL, 0);
-
-	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 */
-	key_size = (egg_bytes_get_size (content) / 2) * 2 * 8;
-
-	egg_bytes_unref (content);
-	return key_size;
-}
-
-static guint
-calculate_dsa_params_size (EggBytes *data)
-{
-	EggBytes *content;
-	gsize params_size;
-	GNode *asn;
-
-	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data);
-	g_return_val_if_fail (asn != NULL, 0);
-
-	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 */
-	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;
-	EggBytes *data;
-	guint key_size = 0, n_bits;
-	EggBytes *key;
-	GQuark oid;
-
-	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);
-	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));
-	g_return_val_if_fail (oid, 0);
-
-	/* RSA keys are stored in the main subjectPublicKey field */
-	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), &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) {
-		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));
-	}
-
-	egg_asn1x_destroy (asn);
-
-	return key_size;
-}
-
 static GChecksum*
 digest_certificate (GcrCertificate *self, GChecksumType type)
 {
@@ -815,14 +725,18 @@ guint
 gcr_certificate_get_key_size (GcrCertificate *self)
 {
 	GcrCertificateInfo *info;
+	GNode *subject_public_key;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), 0);
 
 	info = certificate_info_load (self);
 	g_return_val_if_fail (info, 0);
 
-	if (!info->key_size)
-		info->key_size = calculate_key_size (info);
+	if (!info->key_size) {
+		subject_public_key = egg_asn1x_node (info->asn1, "tbsCertificate",
+		                                     "subjectPublicKeyInfo", NULL);
+		info->key_size = _gcr_key_size_calculate (subject_public_key);
+	}
 
 	return info->key_size;
 }
diff --git a/gcr/gcr-crypto-types.xml b/gcr/gcr-crypto-types.xml
index b911ccd..c92577c 100644
--- a/gcr/gcr-crypto-types.xml
+++ b/gcr/gcr-crypto-types.xml
@@ -127,6 +127,7 @@
 		<comment>PKCS#10 Certificate Request</comment>
 		<acronym>PKCS#10</acronym>
 		<glob pattern="*.p10"/>
+		<glob pattern="*.csr"/>
 	</mime-type>
 
 	<!-- Non standard: OpenSSL PEM format -->
@@ -139,6 +140,21 @@
 		</magic>
 	</mime-type>
 
+	<!-- Non standard: SPKAC DER format -->
+	<mime-type type="application/x-spkac">
+		<comment>SPKAC Certificate Request</comment>
+		<glob pattern="*.spkac"/>
+	</mime-type>
+
+	<!-- Non standard: SPKAC DER format -->
+	<mime-type type="application/x-spkac+base64">
+		<comment>SPKAC Certificate Request in OpenSSL format</comment>
+		<sub-class-of type="text/plain"/>
+		<magic priority="75">
+			<match type="string" value="SPKAC=" offset="0"/>
+		</magic>
+	</mime-type>
+
 	<!-- Non standard: OpenSSL PEM format -->
 	<mime-type type="application/x-pem-key">
 		<comment>Private Key in PEM format</comment>
diff --git a/gcr/gcr-key-size.c b/gcr/gcr-key-size.c
new file mode 100644
index 0000000..06c5c09
--- /dev/null
+++ b/gcr/gcr-key-size.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gcr-key-size.h"
+#include "gcr-oids.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+
+static guint
+calculate_rsa_key_size (EggBytes *data)
+{
+	GNode *asn;
+	EggBytes *content;
+	guint key_size;
+
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
+	g_return_val_if_fail (asn, 0);
+
+	content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL));
+	if (!content)
+		g_return_val_if_reached (0);
+
+	egg_asn1x_destroy (asn);
+
+	/* Removes the complement */
+	key_size = (egg_bytes_get_size (content) / 2) * 2 * 8;
+
+	egg_bytes_unref (content);
+	return key_size;
+}
+
+static guint
+calculate_dsa_params_size (EggBytes *data)
+{
+	GNode *asn;
+	EggBytes *content;
+	guint key_size;
+
+	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data);
+	g_return_val_if_fail (asn, 0);
+
+	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 */
+	key_size = (egg_bytes_get_size (content) / 2) * 2 * 8;
+
+	egg_bytes_unref (content);
+	return key_size;
+}
+
+guint
+_gcr_key_size_calculate (GNode *subject_public_key)
+{
+	EggBytes *key;
+	guint key_size = 0, n_bits;
+	GQuark oid;
+
+	/* Figure out the algorithm */
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
+	                                                  "algorithm", "algorithm", NULL));
+	g_return_val_if_fail (oid, 0);
+
+	/* RSA keys are stored in the main subjectPublicKey field */
+	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 (subject_public_key, "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) {
+		key = egg_asn1x_get_raw_element (egg_asn1x_node (subject_public_key, "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));
+	}
+
+	return key_size;
+}
diff --git a/gcr/gcr-key-size.h b/gcr/gcr-key-size.h
new file mode 100644
index 0000000..8232cd3
--- /dev/null
+++ b/gcr/gcr-key-size.h
@@ -0,0 +1,33 @@
+/*
+ * 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 Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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_KEY_SIZE_H__
+#define __GCR_KEY_SIZE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+guint       _gcr_key_size_calculate           (GNode *subject_public_key);
+
+G_END_DECLS
+
+#endif /* __GCR_KEY_RENDERER_H__ */
diff --git a/gcr/gcr-oids.list b/gcr/gcr-oids.list
index 552c601..2fe3364 100644
--- a/gcr/gcr-oids.list
+++ b/gcr/gcr-oids.list
@@ -12,6 +12,7 @@ PKCS7_SIGNED_DATA		1.2.840.113549.1.7.2
 PKCS7_ENCRYPTED_DATA		1.2.840.113549.1.7.6
 PKCS9_ATTRIBUTE_FRIENDLY	1.2.840.113549.1.9.20
 PKCS9_ATTRIBUTE_LOCAL_KEY_ID	1.2.840.113549.1.9.21
+PKCS9_ATTRIBUTE_EXTENSION_REQ	1.2.840.113549.1.9.14
 PKCS12_BAG_PKCS8_KEY		1.2.840.113549.1.12.10.1.1
 PKCS12_BAG_PKCS8_ENCRYPTED_KEY	1.2.840.113549.1.12.10.1.2
 PKCS12_BAG_CERTIFICATE		1.2.840.113549.1.12.10.1.3
diff --git a/gcr/gcr-renderer.c b/gcr/gcr-renderer.c
index c98376b..296bcf0 100644
--- a/gcr/gcr-renderer.c
+++ b/gcr/gcr-renderer.c
@@ -25,6 +25,7 @@
 #include "gcr-renderer.h"
 
 #include "gcr-certificate-renderer.h"
+#include "gcr-certificate-req-renderer.h"
 #include "gcr-gnupg-renderer.h"
 #include "gcr-key-renderer.h"
 
@@ -289,6 +290,7 @@ void
 gcr_renderer_register_well_known (void)
 {
 	g_type_class_unref (g_type_class_ref (GCR_TYPE_CERTIFICATE_RENDERER));
+	g_type_class_unref (g_type_class_ref (GCR_TYPE_CERTIFICATE_REQ_RENDERER));
 	g_type_class_unref (g_type_class_ref (GCR_TYPE_KEY_RENDERER));
 	g_type_class_unref (g_type_class_ref (GCR_TYPE_GNUPG_RENDERER));
 }
diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h
index e43e7ef..dd522be 100644
--- a/gcr/gcr-types.h
+++ b/gcr/gcr-types.h
@@ -120,7 +120,7 @@ enum {
 };
 
 enum {
-	CKQ_GCR_PKCS10,
+	CKQ_GCR_PKCS10 = 1,
 	CKQ_GCR_SPKAC
 };
 
diff --git a/gcr/gcr-viewer.desktop.in b/gcr/gcr-viewer.desktop.in
index 4d4a432..3f45c8a 100644
--- a/gcr/gcr-viewer.desktop.in
+++ b/gcr/gcr-viewer.desktop.in
@@ -1,6 +1,6 @@
 [Desktop Entry]
 Name=View file
-MimeType=application/pkcs12;application/pkcs12+pem;application/pkcs7-mime;application/pkcs7-mime+pem;application/pkcs8;application/pkcs8+pem;application/pkix-cert;application/pkix-cert+pem;application/pkix-crl;application/pkix-crl+pem;application/x-pem-file;application/x-pem-key;application/x-pkcs12;application/x-pkcs7-certificates;application/x-x509-ca-cert;application/x-x509-user-cert;
+MimeType=application/pkcs12;application/pkcs12+pem;application/pkcs7-mime;application/pkcs7-mime+pem;application/pkcs8;application/pkcs8+pem;application/pkix-cert;application/pkix-cert+pem;application/pkix-crl;application/pkix-crl+pem;application/x-pem-file;application/x-pem-key;application/x-pkcs12;application/x-pkcs7-certificates;application/x-x509-ca-cert;application/x-x509-user-cert;application/pkcs10;application/pkcs10+pem;application/x-spkac;application/x-spkac+base64;
 Exec=gcr-viewer
 Type=Application
 Terminal=false
diff --git a/gcr/gcr-viewer.desktop.in.in b/gcr/gcr-viewer.desktop.in.in
index 6cd913a..a9622ac 100644
--- a/gcr/gcr-viewer.desktop.in.in
+++ b/gcr/gcr-viewer.desktop.in.in
@@ -1,6 +1,6 @@
 [Desktop Entry]
 Name=View file
-MimeType=application/pkcs12;application/pkcs12+pem;application/pkcs7-mime;application/pkcs7-mime+pem;application/pkcs8;application/pkcs8+pem;application/pkix-cert;application/pkix-cert+pem;application/pkix-crl;application/pkix-crl+pem;application/x-pem-file;application/x-pem-key;application/x-pkcs12;application/x-pkcs7-certificates;application/x-x509-ca-cert;application/x-x509-user-cert;
+MimeType=application/pkcs12;application/pkcs12+pem;application/pkcs7-mime;application/pkcs7-mime+pem;application/pkcs8;application/pkcs8+pem;application/pkix-cert;application/pkix-cert+pem;application/pkix-crl;application/pkix-crl+pem;application/x-pem-file;application/x-pem-key;application/x-pkcs12;application/x-pkcs7-certificates;application/x-x509-ca-cert;application/x-x509-user-cert;application/pkcs10;application/pkcs10+pem;application/x-spkac;application/x-spkac+base64;
 Exec=gcr-viewer
 Type=Application
 Terminal=false
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 5ac8369..c133c17 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -64,6 +64,7 @@ noinst_PROGRAMS = \
 	frob-tree-selector \
 	frob-openpgp \
 	frob-parser \
+	frob-request \
 	frob-unlock \
 	frob-unlock-options
 
diff --git a/gcr/tests/files/pem-with-attributes.req b/gcr/tests/files/pem-with-attributes.req
new file mode 100644
index 0000000..bcbe8f5
--- /dev/null
+++ b/gcr/tests/files/pem-with-attributes.req
@@ -0,0 +1,64 @@
+Certificate Request:
+    Data:
+        Version: 0 (0x0)
+        Subject: CN=test.example.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c9:45:f5:a6:a6:f6:d1:96:1a:4d:1b:2b:18:a7:
+                    ba:69:4e:90:3b:64:9d:14:71:9a:38:0d:fe:66:89:
+                    cd:c6:34:05:c0:c9:2a:02:22:5f:3e:c9:10:c2:df:
+                    e8:c8:a5:d9:78:20:6a:81:ad:80:b0:16:a2:d1:6b:
+                    e9:ed:2f:95:69:c2:52:2b:db:76:48:00:c9:56:44:
+                    fa:a7:f4:64:a6:7b:08:58:14:b6:2d:3c:c3:6a:80:
+                    3e:25:48:a8:52:2a:a0:ff:fc:4a:5e:01:05:f8:c3:
+                    58:db:26:58:8f:42:85:f0:7a:e8:8d:cd:28:a8:c7:
+                    24:cd:65:6d:26:86:88:f0:8b:ab:a2:58:8b:fc:91:
+                    45:66:49:03:79:44:f3:d9:d6:0b:49:6c:e6:d2:25:
+                    83:0c:1e:1f:61:e4:b8:53:ab:c7:8a:58:a6:c1:ce:
+                    a4:04:b4:3f:36:48:d5:02:50:85:b3:2c:4c:af:f7:
+                    88:85:be:f1:cf:32:db:cd:52:23:90:71:2b:ad:04:
+                    be:18:be:7d:67:4d:0b:bc:d6:92:82:ae:a4:27:98:
+                    f1:72:cc:16:f2:5d:f3:78:fa:76:0d:c5:13:88:a5:
+                    87:02:3e:41:a2:a2:36:b9:90:07:4f:53:b9:9c:17:
+                    05:65:9b:da:6d:f4:62:ab:3d:05:7a:8a:fe:e3:c3:
+                    1e:31
+                Exponent: 65537 (0x10001)
+        Attributes:
+        Requested Extensions:
+            X509v3 Subject Alternative Name:
+                DNS:test.example.com, DNS:other.example.com
+    Signature Algorithm: sha1WithRSAEncryption
+        b9:97:4a:53:7e:0f:14:46:ae:d7:6f:fc:1a:33:b1:40:c7:ae:
+        64:06:c8:2d:b5:5a:a0:e8:bf:8e:af:92:e1:7d:ad:3c:6b:c0:
+        c6:d2:cb:c4:98:e7:2c:fa:d6:d5:ee:77:dc:5e:99:9d:33:23:
+        d0:f7:61:30:ef:86:00:b3:08:4a:24:ce:5a:86:8d:91:95:84:
+        bc:4b:16:33:46:1e:92:3f:7a:fb:f0:f2:27:c3:07:e3:b0:b6:
+        1c:a4:88:ef:69:69:9f:16:fd:4c:79:46:63:f9:84:8a:a7:16:
+        8d:80:ee:a5:a8:54:a2:a4:0b:4b:0b:a7:38:a3:e9:d5:14:0f:
+        0c:1a:5d:25:93:fa:6e:29:95:71:30:90:ca:15:a2:41:2d:e0:
+        97:0b:36:b2:4c:36:66:16:24:3d:26:c0:26:6a:c8:10:57:ca:
+        79:b1:b7:ae:e4:95:38:b9:75:66:09:3b:40:31:87:7f:6d:73:
+        1f:ee:18:b3:de:c8:9c:11:78:00:eb:56:63:5d:f8:a3:58:aa:
+        44:d1:94:50:46:ff:19:77:7e:85:f8:7c:ba:a4:b9:25:3c:8a:
+        ba:19:c1:10:bc:b6:43:af:ad:60:76:2d:cd:5d:ef:86:4a:1d:
+        b0:0a:91:8a:20:98:cd:c8:9e:43:d5:7c:9c:a9:e2:8b:f3:86:
+        fe:a4:00:1a
+-----BEGIN CERTIFICATE REQUEST-----
+MIICoTCCAYkCAQAwGzEZMBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMlF9aam9tGWGk0bKxinumlOkDtknRRx
+mjgN/maJzcY0BcDJKgIiXz7JEMLf6Mil2XggaoGtgLAWotFr6e0vlWnCUivbdkgA
+yVZE+qf0ZKZ7CFgUti08w2qAPiVIqFIqoP/8Sl4BBfjDWNsmWI9ChfB66I3NKKjH
+JM1lbSaGiPCLq6JYi/yRRWZJA3lE89nWC0ls5tIlgwweH2HkuFOrx4pYpsHOpAS0
+PzZI1QJQhbMsTK/3iIW+8c8y281SI5BxK60Evhi+fWdNC7zWkoKupCeY8XLMFvJd
+83j6dg3FE4ilhwI+QaKiNrmQB09TuZwXBWWb2m30Yqs9BXqK/uPDHjECAwEAAaBB
+MD8GCSqGSIb3DQEJDjEyMDAwLgYDVR0RBCcwJYIQdGVzdC5leGFtcGxlLmNvbYIR
+b3RoZXIuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBALmXSlN+DxRGrtdv
+/BozsUDHrmQGyC21WqDov46vkuF9rTxrwMbSy8SY5yz61tXud9xemZ0zI9D3YTDv
+hgCzCEokzlqGjZGVhLxLFjNGHpI/evvw8ifDB+OwthykiO9paZ8W/Ux5RmP5hIqn
+Fo2A7qWoVKKkC0sLpzij6dUUDwwaXSWT+m4plXEwkMoVokEt4JcLNrJMNmYWJD0m
+wCZqyBBXynmxt67klTi5dWYJO0Axh39tcx/uGLPeyJwReADrVmNd+KNYqkTRlFBG
+/xl3foX4fLqkuSU8iroZwRC8tkOvrWB2Lc1d74ZKHbAKkYogmM3InkPVfJyp4ovz
+hv6kABo=
+-----END CERTIFICATE REQUEST-----
diff --git a/gcr/tests/frob-request.c b/gcr/tests/frob-request.c
new file mode 100644
index 0000000..68b5d0e
--- /dev/null
+++ b/gcr/tests/frob-request.c
@@ -0,0 +1,96 @@
+/*
+ * 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 Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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/gcr.h"
+#include "gcr/gcr-certificate-req-renderer.h"
+
+#include <gtk/gtk.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static void
+on_parser_parsed (GcrParser *parser,
+                  gpointer user_data)
+{
+	GcrViewer *viewer;
+	GcrRenderer *renderer;
+	GtkDialog *dialog = GTK_DIALOG (user_data);
+
+	viewer = gcr_viewer_new_scrolled ();
+	renderer = _gcr_certificate_req_renderer_new_for_attributes (gcr_parser_get_parsed_label (parser),
+	                                                             gcr_parser_get_parsed_attributes (parser));
+	gcr_viewer_add_renderer (viewer, renderer);
+	g_object_unref (renderer);
+	gtk_widget_show (GTK_WIDGET (viewer));
+	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (viewer));
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 20);
+}
+
+static void
+test_request (const gchar *path)
+{
+	GcrParser *parser;
+	GError *err = NULL;
+	guchar *data;
+	gsize n_data;
+	GtkWidget *dialog;
+
+	if (!g_file_get_contents (path, (gchar**)&data, &n_data, NULL))
+		g_error ("couldn't read file: %s", path);
+
+	dialog = gtk_dialog_new ();
+	g_object_ref_sink (dialog);
+
+	parser = gcr_parser_new ();
+	g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), dialog);
+	if (!gcr_parser_parse_data (parser, data, n_data, &err))
+		g_error ("couldn't parse data: %s", err->message);
+
+	g_object_unref (parser);
+	g_free (data);
+
+	gtk_widget_show (dialog);
+	g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
+	gtk_main ();
+
+	g_object_unref (dialog);
+}
+
+int
+main(int argc, char *argv[])
+{
+	gtk_init (&argc, &argv);
+	g_set_prgname ("frob-request");
+
+	if (argc > 1)
+		test_request (argv[1]);
+	else
+		test_request (SRCDIR "/files/der-rsa-2048.p10");
+
+	return 0;
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a3a74eb..c5c8b38 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,7 @@ gcr/gcr-callback-output-stream.c
 gcr/gcr-certificate.c
 gcr/gcr-certificate-exporter.c
 gcr/gcr-certificate-extensions.c
+gcr/gcr-certificate-req-renderer.c
 gcr/gcr-certificate-renderer.c
 gcr/gcr-certificate-widget.c
 gcr/gcr-display-view.c



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