[gnome-keyring/subject-alt-name] gcr: Parse and display certificate extensions.



commit 00fdff07b0487aaecb11a6c7f2bf1093de5589c2
Author: Stef Walter <stefw collabora co uk>
Date:   Wed Apr 6 12:22:24 2011 +0200

    gcr: Parse and display certificate extensions.
    
     * Subject Alt Name
     * Basic Constraints
     * Extended Key Usage
     * Key Usage
     * Subject Key Identifier

 egg/egg-oid.c                    |   31 +++--
 gcr/Makefile.am                  |    1 +
 gcr/gcr-certificate-extensions.c |  269 ++++++++++++++++++++++++++++++++++++++
 gcr/gcr-certificate-extensions.h |   88 +++++++++++++
 gcr/gcr-certificate-renderer.c   |  245 +++++++++++++++++++++++++++++-----
 gcr/gcr-display-view.c           |   16 ++-
 gcr/gcr-display-view.h           |    8 +
 po/POTFILES.in                   |    1 +
 8 files changed, 603 insertions(+), 56 deletions(-)
---
diff --git a/egg/egg-oid.c b/egg/egg-oid.c
index d0bc6bf..5ab7ea6 100644
--- a/egg/egg-oid.c
+++ b/egg/egg-oid.c
@@ -57,9 +57,9 @@ static OidInfo oid_info[] = {
 		EGG_OID_PRINTABLE },
 	{ 0, "1.3.6.1.5.5.7.9.3", "gender", N_("Gender"), 
 		EGG_OID_PRINTABLE },
-        { 0, "1.3.6.1.5.5.7.9.4", "countryOfCitizenship", N_("Country of Citizenship"), 
+	{ 0, "1.3.6.1.5.5.7.9.4", "countryOfCitizenship", N_("Country of Citizenship"),
 		EGG_OID_PRINTABLE },
-        { 0, "1.3.6.1.5.5.7.9.5", "countryOfResidence", N_("Country of Residence"), 
+	{ 0, "1.3.6.1.5.5.7.9.5", "countryOfResidence", N_("Country of Residence"),
 		EGG_OID_PRINTABLE },
 
 	{ 0, "2.5.4.3", "CN", N_("Common Name"), 
@@ -95,19 +95,20 @@ static OidInfo oid_info[] = {
 	{ 0, "2.5.4.65", "pseudonym", N_("Pseudonym"), 
 		EGG_OID_PRINTABLE | EGG_OID_IS_CHOICE },
 
-	{ 0, "1.2.840.113549.1.1.1", "rsaEncryption", N_("RSA"),
-	        0 },
-	{ 0, "1.2.840.113549.1.1.2", "md2WithRSAEncryption", N_("MD2 with RSA"),
-	        0 },
-	{ 0, "1.2.840.113549.1.1.4", "md5WithRSAEncryption", N_("MD5 with RSA"),
-		0 },
-	{ 0, "1.2.840.113549.1.1.5", "sha1WithRSAEncryption", N_("SHA1 with RSA"),
-		0 },
-
-	{ 0, "1.2.840.10040.4.1", "dsa", N_("DSA"),
-		0 },
-	{ 0, "1.2.840.10040.4.3", "sha1WithDSA", N_("SHA1 with DSA"),
-		0 },
+	{ 0, "1.2.840.113549.1.1.1", "rsaEncryption", N_("RSA"), 0 },
+	{ 0, "1.2.840.113549.1.1.2", "md2WithRSAEncryption", N_("MD2 with RSA"), 0 },
+	{ 0, "1.2.840.113549.1.1.4", "md5WithRSAEncryption", N_("MD5 with RSA"), 0 },
+	{ 0, "1.2.840.113549.1.1.5", "sha1WithRSAEncryption", N_("SHA1 with RSA"), 0 },
+
+	{ 0, "1.2.840.10040.4.1", "dsa", N_("DSA"), 0 },
+	{ 0, "1.2.840.10040.4.3", "sha1WithDSA", N_("SHA1 with DSA"), 0 },
+
+	/* Extended Key Usages */
+	{ 0, "1.3.6.1.5.5.7.3.1", NULL, N_("Server Authentication"), 0 },
+	{ 0, "1.3.6.1.5.5.7.3.2", NULL, N_("Client Authentication"), 0 },
+	{ 0, "1.3.6.1.5.5.7.3.3", NULL, N_("Code Signing"), 0 },
+	{ 0, "1.3.6.1.5.5.7.3.4", NULL, N_("Email Protection"), 0 },
+	{ 0, "1.3.6.1.5.5.7.3.8", NULL, N_("Time Stamping"), 0 },
 
 	{ 0, NULL, NULL, NULL, FALSE }
 };
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index bfecc9a..246fe8f 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -75,6 +75,7 @@ libgcr GCR_VERSION_SUFFIX@_la_SOURCES = \
 	gcr-certificate-chain.c gcr-certificate-chain.h \
 	gcr-certificate-renderer.c gcr-certificate-renderer.h \
 	gcr-certificate-exporter.c gcr-certificate-exporter.h \
+	gcr-certificate-extensions.c gcr-certificate-extensions.h \
 	gcr-certificate-widget.c gcr-certificate-widget.h \
 	gcr-collection.c gcr-collection.h \
 	gcr-collection-model.c gcr-collection-model.h \
diff --git a/gcr/gcr-certificate-extensions.c b/gcr/gcr-certificate-extensions.c
new file mode 100644
index 0000000..2c24466
--- /dev/null
+++ b/gcr/gcr-certificate-extensions.c
@@ -0,0 +1,269 @@
+/*
+ * 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-certificate-extensions.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-dn.h"
+
+#include <glib/gi18n-lib.h>
+
+gboolean
+_gcr_certificate_extension_basic_constraints (gconstpointer data, gsize n_data,
+                                              gboolean *is_ca, gint *path_len)
+{
+	gboolean ret = TRUE;
+	GNode *asn = NULL;
+	GNode *node;
+	gulong value;
+
+	g_return_val_if_fail (data, FALSE);
+	g_return_val_if_fail (n_data, FALSE);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data, n_data);
+	if (asn == NULL)
+		return FALSE;
+
+	if (path_len) {
+		node = egg_asn1x_node (asn, "pathLenConstraint", NULL);
+		if (!egg_asn1x_have (node))
+			*path_len = -1;
+		else if (!egg_asn1x_get_integer_as_ulong (node, &value))
+			ret = FALSE;
+		else
+			*path_len = value;
+	}
+
+	if (is_ca) {
+		node = egg_asn1x_node (asn, "cA", NULL);
+		if (!egg_asn1x_have (node))
+			*is_ca = FALSE;
+		else if (!egg_asn1x_get_boolean (node, is_ca))
+			ret = FALSE;
+	}
+
+	egg_asn1x_destroy (asn);
+	return ret;
+}
+
+GQuark*
+_gcr_certificate_extension_extended_key_usage (gconstpointer data, gsize n_data)
+{
+	GNode *asn = NULL;
+	GNode *node;
+	GArray *array;
+	GQuark oid;
+	int i;
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data, n_data);
+	if (asn == NULL)
+		return NULL;
+
+	array = g_array_new (TRUE, TRUE, sizeof (GQuark));
+	for (i = 0; TRUE; ++i) {
+		node = egg_asn1x_node (asn, i + 1, NULL);
+		if (node == NULL)
+			break;
+		oid = egg_asn1x_get_oid_as_quark (node);
+		g_array_append_val (array, oid);
+	}
+
+	egg_asn1x_destroy (asn);
+	return (GQuark*)g_array_free (array, FALSE);
+}
+
+gpointer
+_gcr_certificate_extension_subject_key_identifier (gconstpointer data, gsize n_data,
+                                                   gsize *n_keyid)
+{
+	GNode *asn = NULL;
+	gpointer result;
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectKeyIdentifier", data, n_data);
+	if (asn == NULL)
+		return NULL;
+
+	result = egg_asn1x_get_string_as_raw (asn, g_realloc, n_keyid);
+	egg_asn1x_destroy (asn);
+
+	return result;
+}
+
+gboolean
+_gcr_certificate_extension_key_usage (gconstpointer data, gsize n_data,
+                                      gulong *key_usage)
+{
+	GNode *asn = NULL;
+	gboolean ret = TRUE;
+	guint n_bits;
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data, n_data);
+	if (asn == NULL)
+		return FALSE;
+
+	ret = egg_asn1x_get_bits_as_ulong (asn, key_usage, &n_bits);
+	egg_asn1x_destroy (asn);
+	return ret;
+}
+
+static void
+general_name_parse_other (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_OTHER;
+	general->description = _("Other Name");
+}
+
+static void
+general_name_parse_rfc822 (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_RFC822;
+	general->description = _("Email");
+	general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
+}
+
+static void
+general_name_parse_dns (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_DNS;
+	general->description = _("DNS");
+	general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
+}
+
+static void
+general_name_parse_x400 (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_X400;
+	general->description = _("X400 Address");
+}
+
+static void
+general_name_parse_dn (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_DNS;
+	general->description = _("Directory Name");
+	general->display = egg_dn_read (node);
+}
+
+static void
+general_name_parse_edi (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_EDI;
+	general->description = _("EDI Party Name");
+}
+
+static void
+general_name_parse_uri (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_URI;
+	general->description = _("URI");
+	general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
+}
+
+static void
+general_name_parse_ip (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_IP;
+	general->description = _("IP Address");
+	general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
+}
+
+static void
+general_name_parse_registered (GNode *node, GcrGeneralName *general)
+{
+	general->type = GCR_GENERAL_NAME_REGISTERED_ID;
+	general->description = _("Registered ID");
+	general->display = egg_asn1x_get_oid_as_string (node);
+}
+
+GArray*
+_gcr_certificate_extension_subject_alt_name (gconstpointer data, gsize n_data)
+{
+	GNode *asn = NULL;
+	guint count, i;
+	const gchar *node_name;
+	GArray *names;
+	GcrGeneralName general;
+	GNode *choice;
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectAltName", data, n_data);
+	if (asn == NULL)
+		return NULL;
+
+	names = g_array_new (FALSE, TRUE, sizeof (GcrGeneralName));
+	count = egg_asn1x_count (asn);
+
+	for (i = 0; i < count; i++) {
+		choice = egg_asn1x_get_choice (egg_asn1x_node (asn, i + 1, NULL));
+		g_return_val_if_fail (choice, NULL);
+
+		node_name = egg_asn1x_name (choice);
+		g_return_val_if_fail (node_name, NULL);
+
+		memset (&general, 0, sizeof (general));
+
+		if (g_str_equal (node_name, "otherName"))
+			general_name_parse_other (choice, &general);
+
+		else if (g_str_equal (node_name, "rfc822Name"))
+			general_name_parse_rfc822 (choice, &general);
+
+		else if (g_str_equal (node_name, "dNSName"))
+			general_name_parse_dns (choice, &general);
+
+		else if (g_str_equal (node_name, "x400Address"))
+			general_name_parse_x400 (choice, &general);
+
+		else if (g_str_equal (node_name, "directoryName"))
+			general_name_parse_dn (choice, &general);
+
+		else if (g_str_equal (node_name, "ediPartyName"))
+			general_name_parse_edi (choice, &general);
+
+		else if (g_str_equal (node_name, "uniformResourceIdentifier"))
+			general_name_parse_uri (choice, &general);
+
+		else if (g_str_equal (node_name, "IPAddress"))
+			general_name_parse_ip (choice, &general);
+
+		else if (g_str_equal (node_name, "registeredID"))
+			general_name_parse_registered (choice, &general);
+
+		general.raw = egg_asn1x_get_raw_value (choice, &general.n_raw);
+		g_array_append_val (names, general);
+	}
+
+	egg_asn1x_destroy (asn);
+	return names;
+}
+
+void
+_gcr_general_names_free (GArray *names)
+{
+	guint i;
+
+	for (i = 0; names && i < names->len; i++)
+		g_free (g_array_index (names, GcrGeneralName, i).display);
+	g_array_free (names, TRUE);
+}
diff --git a/gcr/gcr-certificate-extensions.h b/gcr/gcr-certificate-extensions.h
new file mode 100644
index 0000000..ab22d42
--- /dev/null
+++ b/gcr/gcr-certificate-extensions.h
@@ -0,0 +1,88 @@
+/*
+ * 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>
+ */
+
+#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#ifndef GCR_CERTIFICATE_EXTENSIONS_H
+#define GCR_CERTIFICATE_EXTENSIONS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean   _gcr_certificate_extension_basic_constraints       (gconstpointer data,
+                                                               gsize n_data,
+                                                               gboolean *is_ca,
+                                                               gint *path_len);
+
+GQuark*    _gcr_certificate_extension_extended_key_usage      (gconstpointer data,
+                                                               gsize n_data);
+
+gpointer   _gcr_certificate_extension_subject_key_identifier  (gconstpointer data,
+                                                               gsize n_data,
+                                                               gsize *n_keyid);
+
+typedef enum {
+	GCR_KEY_USAGE_DIGITAL_SIGNATURE = 1 << 0,
+	GCR_KEY_USAGE_NON_REPUDIATION = 1 << 1,
+	GCR_KEY_USAGE_KEY_ENCIPHERMENT = 1 << 2,
+	GCR_KEY_USAGE_DATA_ENCIPHERMENT = 1 << 3,
+	GCR_KEY_USAGE_KEY_AGREEMENT = 1 << 4,
+	GCR_KEY_USAGE_KEY_CERT_SIGN = 1 << 5,
+	GCR_KEY_USAGE_CRL_SIGN = 1 << 6,
+} GcrCertificateExtensionKeyUsage;
+
+gboolean   _gcr_certificate_extension_key_usage               (gconstpointer data,
+                                                               gsize n_data,
+                                                               gulong *key_usage);
+
+typedef enum {
+	GCR_GENERAL_NAME_OTHER,
+	GCR_GENERAL_NAME_RFC822,
+	GCR_GENERAL_NAME_DNS,
+	GCR_GENERAL_NAME_X400,
+	GCR_GENERAL_NAME_DN,
+	GCR_GENERAL_NAME_EDI,
+	GCR_GENERAL_NAME_URI,
+	GCR_GENERAL_NAME_IP,
+	GCR_GENERAL_NAME_REGISTERED_ID,
+} GcrGeneralNameType;
+
+typedef struct {
+	GcrGeneralNameType type;
+	const gchar *description;
+	gchar *display;
+	gconstpointer raw;
+	gsize n_raw;
+} GcrGeneralName;
+
+GArray *   _gcr_certificate_extension_subject_alt_name        (gconstpointer data,
+                                                               gsize n_data);
+
+void       _gcr_general_names_free                            (GArray *names);
+
+G_END_DECLS
+
+#endif /* GCR_CERTIFICATE_H */
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
index 6029e58..a26b611 100644
--- a/gcr/gcr-certificate-renderer.c
+++ b/gcr/gcr-certificate-renderer.c
@@ -21,6 +21,7 @@
 
 #include "gcr-certificate.h"
 #include "gcr-certificate-exporter.h"
+#include "gcr-certificate-extensions.h"
 #include "gcr-certificate-renderer.h"
 #include "gcr-display-view.h"
 #include "gcr-icons.h"
@@ -61,6 +62,12 @@ G_DEFINE_TYPE_WITH_CODE (GcrCertificateRenderer, gcr_certificate_renderer, G_TYP
 	G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_renderer_certificate_iface_init);
 );
 
+static GQuark OID_BASIC_CONSTRAINTS = 0;
+static GQuark OID_EXTENDED_KEY_USAGE = 0;
+static GQuark OID_SUBJECT_KEY_IDENTIFIER = 0;
+static GQuark OID_KEY_USAGE = 0;
+static GQuark OID_SUBJECT_ALT_NAME = 0;
+
 /* -----------------------------------------------------------------------------
  * INTERNAL
  */
@@ -86,17 +93,183 @@ calculate_label (GcrCertificateRenderer *self)
 }
 
 static gboolean
+append_extension_basic_constraints (GcrCertificateRenderer *self, GcrDisplayView *view,
+                                    gconstpointer data, gsize n_data)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	gboolean is_ca = FALSE;
+	gint path_len = -1;
+	gchar *number;
+
+	if (!_gcr_certificate_extension_basic_constraints (data, n_data, &is_ca, &path_len))
+		return FALSE;
+
+	_gcr_display_view_append_heading (view, renderer, _("Basic Constraints"));
+
+	_gcr_display_view_append_value (view, renderer, _("Certificate Authority"),
+	                                is_ca ? _("Yes") : _("No"), FALSE);
+
+	number = g_strdup_printf ("%d", path_len);
+	_gcr_display_view_append_value (view, renderer, _("Max Path Length"),
+	                                path_len < 0 ? _("Unlimited") : number, FALSE);
+	g_free (number);
+
+	return TRUE;
+}
+
+static gboolean
+append_extension_extended_key_usage (GcrCertificateRenderer *self, GcrDisplayView *view,
+                                     gconstpointer data, gsize n_data)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	GQuark *oids;
+	GString *text;
+	guint i;
+
+	oids = _gcr_certificate_extension_extended_key_usage (data, n_data);
+	if (oids == NULL)
+		return FALSE;
+
+	_gcr_display_view_append_heading (view, renderer, _("Extended Key Usage"));
+
+	text = g_string_new ("");
+	for (i = 0; oids[i] != 0; i++) {
+		if (i > 0)
+			g_string_append_unichar (text, GCR_DISPLAY_VIEW_LINE_BREAK);
+		g_string_append (text, egg_oid_get_description (oids[i]));
+	}
+
+	g_free (oids);
+
+	_gcr_display_view_append_value (view, renderer, _("Allowed Purposes"),
+	                                text->str, FALSE);
+
+	g_string_free (text, TRUE);
+
+	return TRUE;
+}
+
+static gboolean
+append_extension_subject_key_identifier (GcrCertificateRenderer *self, GcrDisplayView *view,
+                                         gconstpointer data, gsize n_data)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	gpointer keyid;
+	gsize n_keyid;
+
+	keyid = _gcr_certificate_extension_subject_key_identifier (data, n_data, &n_keyid);
+	if (keyid == NULL)
+		return FALSE;
+
+	_gcr_display_view_append_heading (view, renderer, _("Subject Key Identifier"));
+	_gcr_display_view_append_hex (view, renderer, _("Key Identifier"), keyid, n_keyid);
+
+	g_free (keyid);
+
+	return TRUE;
+}
+
+static const struct {
+	guint usage;
+	const gchar *description;
+} usage_descriptions[] = {
+	{ GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") },
+	{ GCR_KEY_USAGE_KEY_ENCIPHERMENT, N_("Key encipherment") },
+	{ GCR_KEY_USAGE_DATA_ENCIPHERMENT, N_("Data encipherment") },
+	{ GCR_KEY_USAGE_KEY_AGREEMENT, N_("Key agreement") },
+	{ GCR_KEY_USAGE_KEY_CERT_SIGN, N_("Certificate signature") },
+	{ GCR_KEY_USAGE_CRL_SIGN, N_("Revocation list signature") }
+};
+
+static gboolean
+append_extension_key_usage (GcrCertificateRenderer *self, GcrDisplayView *view,
+                            gconstpointer data, gsize n_data)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	gulong key_usage;
+	GString *text;
+	guint i;
+
+	if (!_gcr_certificate_extension_key_usage (data, n_data, &key_usage))
+		return FALSE;
+
+	text = g_string_new ("");
+
+	for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) {
+		if (key_usage & usage_descriptions[i].usage) {
+			if (text->len > 0)
+				g_string_append_unichar (text, GCR_DISPLAY_VIEW_LINE_BREAK);
+			g_string_append (text, gettext (usage_descriptions[i].description));
+		}
+	}
+
+	_gcr_display_view_append_heading (view, renderer, _("Key Usage"));
+	_gcr_display_view_append_value (view, renderer, _("Usages"), text->str, FALSE);
+
+	g_string_free (text, TRUE);
+
+	return TRUE;
+}
+
+static gboolean
+append_extension_subject_alt_name (GcrCertificateRenderer *self, GcrDisplayView *view,
+                                   gconstpointer data, gsize n_data)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	GArray *general_names;
+	GcrGeneralName *general;
+	guint i;
+
+	general_names = _gcr_certificate_extension_subject_alt_name (data, n_data);
+	if (general_names == NULL)
+		return FALSE;
+
+	_gcr_display_view_append_heading (view, renderer, _("Subject Alternative Names"));
+
+	for (i = 0; i < general_names->len; i++) {
+		general = &g_array_index (general_names, GcrGeneralName, i);
+		if (general->display == NULL)
+			_gcr_display_view_append_hex (view, renderer, general->description,
+			                              general->raw, general->n_raw);
+		else
+			_gcr_display_view_append_value (view, renderer, general->description,
+			                                general->display, FALSE);
+	}
+
+	_gcr_general_names_free (general_names);
+
+	return TRUE;
+}
+
+
+static gboolean
+append_extension_hex (GcrCertificateRenderer *self, 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"));
+
+	/* Extension type */
+	text = egg_oid_get_description (oid);
+	_gcr_display_view_append_value (view, renderer, _("Identifier"), text, FALSE);
+	_gcr_display_view_append_hex (view, renderer, _("Value"), data, n_data);
+
+	return TRUE;
+}
+
+static gboolean
 append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
                   GNode *asn, const guchar *data, gsize n_data, gint index)
 {
 	GcrRenderer *renderer = GCR_RENDERER (self);
 	GNode *node;
 	GQuark oid;
-	gchar *display;
 	gsize n_value;
 	const guchar *value;
-	const gchar *text;
 	gboolean critical;
+	gboolean ret = FALSE;
 
 	/* Make sure it is present */
 	node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
@@ -107,28 +280,32 @@ append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
 	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
 	g_return_val_if_fail (oid, FALSE);
 
-	_gcr_display_view_append_heading (view, renderer, _("Extension"));
-
-
-	/* Extension type */
-	text = egg_oid_get_description (oid);
-	_gcr_display_view_append_value (view, renderer, _("Identifier"), text, FALSE);
-
-
 	/* Extension value */
 	value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL), &n_value);
 
-	/* TODO: Parsing of extensions that we understand */
-	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
-	_gcr_display_view_append_value (view, renderer, _("Value"), display, TRUE);
-	g_free (display);
-
+	/* The custom parsers */
+	if (oid == OID_BASIC_CONSTRAINTS)
+		ret = append_extension_basic_constraints (self, view, value, n_value);
+	else if (oid == OID_EXTENDED_KEY_USAGE)
+		ret = append_extension_extended_key_usage (self, view, value, n_value);
+	else if (oid == OID_SUBJECT_KEY_IDENTIFIER)
+		ret = append_extension_subject_key_identifier (self, view, value, n_value);
+	else if (oid == OID_KEY_USAGE)
+		ret = append_extension_key_usage (self, view, value, n_value);
+	else if (oid == OID_SUBJECT_ALT_NAME)
+		ret = append_extension_subject_alt_name (self, view, value, n_value);
+
+	/* Otherwise the default raw display */
+	if (ret == FALSE)
+		ret = append_extension_hex (self, view, oid, value, n_value);
 
 	/* Critical */
-	if (egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical))
-		_gcr_display_view_append_value (view, renderer, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
+	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);
+	}
 
-	return TRUE;
+	return ret;
 }
 
 typedef struct _on_parsed_dn_args {
@@ -325,6 +502,12 @@ gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass)
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 	GckAttributes *registered;
 
+	OID_SUBJECT_KEY_IDENTIFIER = g_quark_from_static_string ("2.5.29.14");
+	OID_BASIC_CONSTRAINTS = g_quark_from_static_string ("2.5.29.19");
+	OID_EXTENDED_KEY_USAGE = g_quark_from_static_string ("2.5.29.37");
+	OID_KEY_USAGE = g_quark_from_static_string ("2.5.29.15");
+	OID_SUBJECT_ALT_NAME = g_quark_from_static_string ("2.5.29.17");
+
 	gcr_certificate_renderer_parent_class = g_type_class_peek_parent (klass);
 	g_type_class_add_private (klass, sizeof (GcrCertificateRendererPrivate));
 
@@ -443,9 +626,7 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 
 	raw = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), NULL, &n_raw);
 	g_return_if_fail (raw);
-	display = egg_hex_encode_full (raw, n_raw, TRUE, ' ', 1);
-	_gcr_display_view_append_value (view, renderer, _("Serial Number"), display, TRUE);
-	g_free (display);
+	_gcr_display_view_append_hex (view, renderer, _("Serial Number"), raw, n_raw);
 	g_free (raw);
 
 	display = g_malloc0 (128);
@@ -469,17 +650,12 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	_gcr_display_view_append_value (view, renderer, _("Signature Algorithm"), text, FALSE);
 
 	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value);
-	if (value && n_value) {
-		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
-		_gcr_display_view_append_value (view, renderer, _("Signature Parameters"), display, TRUE);
-		g_free (display);
-	}
+	if (value && n_value)
+		_gcr_display_view_append_hex (view, renderer, _("Signature Parameters"), value, n_value);
 
 	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), NULL, &bits);
 	g_return_if_fail (raw);
-	display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
-	_gcr_display_view_append_value (view, renderer, _("Signature"), display, TRUE);
-	g_free (display);
+	_gcr_display_view_append_hex (view, renderer, _("Signature"), raw, bits / 8);
 	g_free (raw);
 
 	/* Public Key Info */
@@ -492,11 +668,8 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 
 	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
 	                                                   "algorithm", "parameters", NULL), &n_value);
-	if (value && n_value) {
-		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
-		_gcr_display_view_append_value (view, renderer, _("Key Parameters"), display, TRUE);
-		g_free (display);
-	}
+	if (value && n_value)
+		_gcr_display_view_append_hex (view, renderer, _("Key Parameters"), value, n_value);
 
 	bits = gcr_certificate_get_key_size (cert);
 	if (bits > 0) {
@@ -508,9 +681,7 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
 	                                                 "subjectPublicKey", NULL), NULL, &bits);
 	g_return_if_fail (raw);
-	display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
-	_gcr_display_view_append_value (view, renderer, _("Public Key"), display, TRUE);
-	g_free (display);
+	_gcr_display_view_append_hex (view, renderer, _("Public Key"), raw, bits / 8);
 	g_free (raw);
 
 	/* Fingerprints */
diff --git a/gcr/gcr-display-view.c b/gcr/gcr-display-view.c
index 6c5fb61..bf7b606 100644
--- a/gcr/gcr-display-view.c
+++ b/gcr/gcr-display-view.c
@@ -889,6 +889,17 @@ _gcr_display_view_append_value (GcrDisplayView *self, GcrRenderer *renderer, con
 }
 
 void
+_gcr_display_view_append_hex (GcrDisplayView *self, GcrRenderer *renderer,
+                              const gchar *field, gconstpointer value, gsize n_value)
+{
+	gchar *display;
+
+	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+	_gcr_display_view_append_value (self, renderer, field, display, TRUE);
+	g_free (display);
+}
+
+void
 _gcr_display_view_append_title (GcrDisplayView *self, GcrRenderer *renderer, const gchar *title)
 {
 	GcrDisplayItem *item;
@@ -939,7 +950,6 @@ _gcr_display_view_append_fingerprint (GcrDisplayView *self, GcrRenderer *rendere
 	GChecksum *checksum;
 	guint8 *buffer;
 	gsize n_buffer;
-	gchar *display;
 
 	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
 
@@ -954,9 +964,7 @@ _gcr_display_view_append_fingerprint (GcrDisplayView *self, GcrRenderer *rendere
 	g_checksum_get_digest (checksum, buffer, &n_buffer);
 	g_checksum_free (checksum);
 
-	display = egg_hex_encode_full (buffer, n_buffer, TRUE, ' ', 1);
-	_gcr_display_view_append_value (self, renderer, name, display, TRUE);
-	g_free (display);
+	_gcr_display_view_append_hex (self, renderer, name, buffer, n_buffer);
 
 	g_free (buffer);
 }
diff --git a/gcr/gcr-display-view.h b/gcr/gcr-display-view.h
index be237bb..5f0f2ee 100644
--- a/gcr/gcr-display-view.h
+++ b/gcr/gcr-display-view.h
@@ -29,6 +29,8 @@
 
 G_BEGIN_DECLS
 
+#define GCR_DISPLAY_VIEW_LINE_BREAK   0x2028
+
 #define GCR_TYPE_DISPLAY_VIEW               (_gcr_display_view_get_type ())
 #define GCR_DISPLAY_VIEW(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_DISPLAY_VIEW, GcrDisplayView))
 #define GCR_DISPLAY_VIEW_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewClass))
@@ -62,6 +64,12 @@ void             _gcr_display_view_append_value                (GcrDisplayView *
                                                                 const gchar *value,
                                                                 gboolean monospace);
 
+void             _gcr_display_view_append_hex                  (GcrDisplayView *self,
+                                                                GcrRenderer *renderer,
+                                                                const gchar *field,
+                                                                gconstpointer value,
+                                                                gsize n_value);
+
 void             _gcr_display_view_append_title                (GcrDisplayView *self,
                                                                 GcrRenderer *renderer,
                                                                 const gchar *title);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6779f8d..248b605 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -13,6 +13,7 @@ daemon/org.gnome.keyring.service.in
 egg/egg-oid.c
 egg/egg-spawn.c
 gcr/gcr-certificate-exporter.c
+gcr/gcr-certificate-extensions.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]