gcr: Parse and display certificate extensions.
authorStef Walter <stefw@collabora.co.uk>
Wed, 6 Apr 2011 10:22:24 +0000 (12:22 +0200)
committerStef Walter <stefw@collabora.co.uk>
Tue, 24 May 2011 07:46:58 +0000 (09:46 +0200)
 * Subject Alt Name
 * Basic Constraints
 * Extended Key Usage
 * Key Usage
 * Subject Key Identifier

https://bugzilla.gnome.org/show_bug.cgi?id=646907

egg/egg-oid.c
gcr/Makefile.am
gcr/gcr-certificate-extensions.c [new file with mode: 0644]
gcr/gcr-certificate-extensions.h [new file with mode: 0644]
gcr/gcr-certificate-renderer.c
gcr/gcr-display-view.h

index e026c0f..4f2da9c 100644 (file)
@@ -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 }
 };
index 5196618..bec3711 100644 (file)
@@ -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 (file)
index 0000000..2c24466
--- /dev/null
@@ -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 (file)
index 0000000..ab22d42
--- /dev/null
@@ -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 */
index 45a7f40..9f965aa 100644 (file)
@@ -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-fingerprint.h"
@@ -75,6 +76,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
  */
@@ -100,6 +107,173 @@ 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)
 {
@@ -108,8 +282,8 @@ append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
        GQuark oid;
        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);
@@ -120,26 +294,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 */
-       _gcr_display_view_append_hex (view, renderer, _("Value"), value, n_value);
-
+       /* 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 {
@@ -336,6 +516,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));
 
index 5bd85d3..5f0f2ee 100644 (file)
@@ -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))