diff options
Diffstat (limited to 'smime')
-rw-r--r-- | smime/gui/ca-trust-dialog.c | 8 | ||||
-rw-r--r-- | smime/gui/ca-trust-dialog.h | 6 | ||||
-rw-r--r-- | smime/gui/certificate-manager.c | 33 | ||||
-rw-r--r-- | smime/gui/certificate-manager.h | 4 | ||||
-rw-r--r-- | smime/gui/certificate-viewer.c | 725 | ||||
-rw-r--r-- | smime/gui/certificate-viewer.h | 13 | ||||
-rw-r--r-- | smime/gui/smime-ui.ui | 708 | ||||
-rw-r--r-- | smime/lib/e-asn1-object.c | 916 | ||||
-rw-r--r-- | smime/lib/e-asn1-object.h | 45 | ||||
-rw-r--r-- | smime/lib/e-cert.c | 769 | ||||
-rw-r--r-- | smime/lib/e-cert.h | 2 |
11 files changed, 1358 insertions, 1871 deletions
diff --git a/smime/gui/ca-trust-dialog.c b/smime/gui/ca-trust-dialog.c index 7037b26677..332b92bcd1 100644 --- a/smime/gui/ca-trust-dialog.c +++ b/smime/gui/ca-trust-dialog.c @@ -26,7 +26,7 @@ #endif #include "ca-trust-dialog.h" -#include "certificate-viewer.h" +#include "certificate-manager.h" #include <glib/gi18n.h> @@ -60,12 +60,14 @@ catd_response (GtkWidget *w, { switch (id) { case GTK_RESPONSE_ACCEPT: { - GtkWidget *dialog = certificate_viewer_show (data->cert); + GtkWidget *dialog; + + dialog = e_cert_manager_new_certificate_viewer (GTK_WINDOW (data->dialog), data->cert); g_signal_stop_emission_by_name (w, "response"); - gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (data->dialog)); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); + break; } } } diff --git a/smime/gui/ca-trust-dialog.h b/smime/gui/ca-trust-dialog.h index 8b7d945c00..62b842d945 100644 --- a/smime/gui/ca-trust-dialog.h +++ b/smime/gui/ca-trust-dialog.h @@ -21,8 +21,8 @@ * */ -#ifndef _CA_TRUST_DIALOG_H_ -#define _CA_TRUST_DIALOG_H +#ifndef CA_TRUST_DIALOG_H +#define CA_TRUST_DIALOG_H #include <gtk/gtk.h> #include "e-cert.h" @@ -32,4 +32,4 @@ GtkWidget * ca_trust_dialog_show (ECert *cert, gboolean importing); void ca_trust_dialog_set_trust (GtkWidget *widget, gboolean ssl, gboolean email, gboolean objsign); void ca_trust_dialog_get_trust (GtkWidget *widget, gboolean *ssl, gboolean *email, gboolean *objsign); -#endif /* _CA_TRUST_DIALOG_H_ */ +#endif /* CA_TRUST_DIALOG_H */ diff --git a/smime/gui/certificate-manager.c b/smime/gui/certificate-manager.c index 548c9c7d79..109bbba515 100644 --- a/smime/gui/certificate-manager.c +++ b/smime/gui/certificate-manager.c @@ -531,7 +531,13 @@ view_cert (GtkWidget *button, -1); if (cert) { - GtkWidget *dialog = certificate_viewer_show (cert); + GtkWidget *dialog, *parent; + + parent = gtk_widget_get_toplevel (button); + if (!parent || !GTK_IS_WINDOW (parent)) + parent = NULL; + + dialog = e_cert_manager_new_certificate_viewer ((GtkWindow *) parent, cert); g_signal_connect ( dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); @@ -1107,3 +1113,28 @@ e_cert_manager_config_new (EPreferencesWindow *window) return GTK_WIDGET (ecmc); } + +GtkWidget * +e_cert_manager_new_certificate_viewer (GtkWindow *parent, + ECert *cert) +{ + GtkWidget *dialog; + GList *chain, *citer; + GSList *issuers = NULL; + + g_return_val_if_fail (cert != NULL, NULL); + + chain = e_cert_get_issuers_chain (cert); + for (citer = chain; citer; citer = g_list_next (citer)) { + issuers = g_slist_append (issuers, e_cert_get_internal_cert (citer->data)); + } + + dialog = certificate_viewer_new ((GtkWindow *) parent, + e_cert_get_internal_cert (cert), + issuers); + + g_list_free_full (chain, g_object_unref); + g_slist_free (issuers); + + return dialog; +} diff --git a/smime/gui/certificate-manager.h b/smime/gui/certificate-manager.h index 2eba92cd01..0f74d30694 100644 --- a/smime/gui/certificate-manager.h +++ b/smime/gui/certificate-manager.h @@ -65,6 +65,10 @@ GType e_cert_manager_config_get_type (void) G_GNUC_CONST; GtkWidget *e_cert_manager_config_new (EPreferencesWindow *window); +struct _ECert; /* forward declaration */ +GtkWidget *e_cert_manager_new_certificate_viewer (GtkWindow *parent, + struct _ECert *cert); + G_END_DECLS #endif /* _CERTIFICATE_MANAGER_H_ */ diff --git a/smime/gui/certificate-viewer.c b/smime/gui/certificate-viewer.c index 9f140cadaa..ce96e50d35 100644 --- a/smime/gui/certificate-viewer.c +++ b/smime/gui/certificate-viewer.c @@ -17,359 +17,662 @@ * Chris Toshok <toshok@ximian.com> * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#include "certificate-viewer.h" +#include <glib/gi18n.h> -#include "e-asn1-object.h" +#include "pk11pub.h" +#include "hasht.h" -#include <glib/gi18n.h> +#include <libedataserver/libedataserver.h> -#include "e-util/e-util.h" -#include "e-util/e-util-private.h" +#include "e-asn1-object.h" +#include "certificate-viewer.h" -typedef struct { - GtkBuilder *builder; - GtkWidget *dialog; - GtkTreeStore *hierarchy_store, *fields_store; - GtkWidget *hierarchy_tree, *fields_tree; - GtkWidget *field_text; - GtkTextTag *text_tag; +#define CERTIFICATE_VIEWER_PRIV_KEY "CertificateViewerPriv-key" - GList *cert_chain; -} CertificateViewerData; +typedef struct _CertificateViewerPriv +{ + GtkWidget *issued_to_cn; + GtkWidget *issued_to_o; + GtkWidget *issued_to_ou; + GtkWidget *issued_to_serial; + GtkWidget *issued_by_cn; + GtkWidget *issued_by_o; + GtkWidget *issued_by_ou; + GtkWidget *validity_issued_on; + GtkWidget *validity_expires_on; + GtkWidget *fingerprints_sha1; + GtkWidget *fingerprints_md5; + GtkWidget *cert_hierarchy_treeview; + GtkWidget *cert_fields_treeview; + GtkWidget *cert_field_value_textview; + + CERTCertificate *cert; + GSList *issuers; + GtkTextTag *monospace_tag; +} CertificateViewerPriv; static void -free_data (gpointer data, - GObject *where_the_object_was) +free_priv_struct (gpointer ptr) { - CertificateViewerData *cvm = data; + CertificateViewerPriv *priv = ptr; + GSList *iter; - g_list_foreach (cvm->cert_chain, (GFunc) g_object_unref, NULL); - g_list_free (cvm->cert_chain); + if (!priv) + return; - g_object_unref (cvm->builder); - g_free (cvm); -} + if (priv->cert) + CERT_DestroyCertificate (priv->cert); -#define NOT_PART_OF_CERT_MARKUP "<i><Not part of certificate></i>" + for (iter = priv->issuers; iter; iter = iter->next) { + CERTCertificate *cert = iter->data; + + if (cert) + CERT_DestroyCertificate (cert); + } + + g_slist_free (priv->issuers); + + g_free (priv); +} static void -fill_in_general (CertificateViewerData *cvm_data, - ECert *cert) +begin_section (GtkGrid *add_to, + const gchar *caption, + gint *from_row, + gint for_rows) { - GtkWidget *label; - const gchar *text; - gchar *markup; - - /* issued to */ - label = e_builder_get_widget (cvm_data->builder, "issued-to-cn"); - if (e_cert_get_cn (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_cn (cert)); - } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); - } + GtkWidget *widget; + PangoAttribute *attr; + PangoAttrList *bold; + + g_return_if_fail (add_to != NULL); + g_return_if_fail (caption != NULL); + g_return_if_fail (from_row != NULL); + + bold = pango_attr_list_new (); + attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + pango_attr_list_insert (bold, attr); + + widget = gtk_label_new (caption); + g_object_set (G_OBJECT (widget), + "hexpand", TRUE, + "halign", GTK_ALIGN_START, + "justify", GTK_JUSTIFY_LEFT, + "attributes", bold, + "ellipsize", PANGO_ELLIPSIZE_NONE, + NULL); - label = e_builder_get_widget (cvm_data->builder, "issued-to-o"); - if (e_cert_get_org (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_org (cert)); - } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); - } + pango_attr_list_unref (bold); - label = e_builder_get_widget (cvm_data->builder, "issued-to-ou"); - if (e_cert_get_org_unit (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_org_unit (cert)); - } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); - } + gtk_grid_attach (add_to, widget, 0, *from_row, 3, 1); + (*from_row)++; - text = e_cert_get_serial_number (cert); - label = e_builder_get_widget (cvm_data->builder, "issued-to-serial"); - gtk_label_set_text (GTK_LABEL (label), text); + widget = gtk_alignment_new (0.0, 0.0, 0.0, 0.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0); - /* issued by */ - label = e_builder_get_widget (cvm_data->builder, "issued-by-cn"); - if (e_cert_get_issuer_cn (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_issuer_cn (cert)); - } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); - } + gtk_grid_attach (add_to, widget, 0, *from_row, 1, for_rows); +} - label = e_builder_get_widget (cvm_data->builder, "issued-by-o"); - if (e_cert_get_issuer_org (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_issuer_org (cert)); - } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); - } +static GtkWidget * +add_info_label (GtkGrid *add_to, + const gchar *caption, + gint *at_row) +{ + GtkWidget *widget; - label = e_builder_get_widget (cvm_data->builder, "issued-by-ou"); - if (e_cert_get_issuer_org_unit (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_issuer_org_unit (cert)); - } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); - } + g_return_val_if_fail (add_to != NULL, NULL); + g_return_val_if_fail (at_row != NULL, NULL); - /* validity */ - label = e_builder_get_widget (cvm_data->builder, "validity-issued-on"); - if (e_cert_get_issued_on (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_issued_on (cert)); - } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); - } + if (caption) { + widget = gtk_label_new (caption); + g_object_set (G_OBJECT (widget), + "hexpand", FALSE, + "halign", GTK_ALIGN_START, + "justify", GTK_JUSTIFY_LEFT, + "ellipsize", PANGO_ELLIPSIZE_NONE, + NULL); - label = e_builder_get_widget (cvm_data->builder, "validity-expires-on"); - if (e_cert_get_expires_on (cert)) { - gtk_label_set_text (GTK_LABEL (label), e_cert_get_expires_on (cert)); + gtk_grid_attach (add_to, widget, 1, *at_row, 1, 1); } - else { - gtk_label_set_markup (GTK_LABEL (label), NOT_PART_OF_CERT_MARKUP); + + widget = gtk_label_new (""); + g_object_set (G_OBJECT (widget), + "hexpand", TRUE, + "halign", GTK_ALIGN_START, + "justify", GTK_JUSTIFY_LEFT, + "ellipsize", PANGO_ELLIPSIZE_NONE, + "selectable", caption != NULL, + NULL); + + gtk_grid_attach (add_to, widget, caption ? 2 : 1, *at_row, caption ? 1 : 2, 1); + + (*at_row)++; + + return widget; +} + +static GtkWidget * +add_scrolled_window (GtkGrid *add_to, + const gchar *caption, + gint *at_row, + GtkWidget *add_widget) +{ + GtkWidget *widget; + PangoAttribute *attr; + PangoAttrList *bold; + + g_return_val_if_fail (add_to != NULL, NULL); + g_return_val_if_fail (caption != NULL, NULL); + g_return_val_if_fail (at_row != NULL, NULL); + + bold = pango_attr_list_new (); + attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + pango_attr_list_insert (bold, attr); + + widget = gtk_label_new (caption); + g_object_set (G_OBJECT (widget), + "hexpand", TRUE, + "halign", GTK_ALIGN_START, + "justify", GTK_JUSTIFY_LEFT, + "attributes", bold, + "ellipsize", PANGO_ELLIPSIZE_NONE, + NULL); + + pango_attr_list_unref (bold); + + gtk_grid_attach (add_to, widget, 0, *at_row, 1, 1); + (*at_row)++; + + widget = gtk_scrolled_window_new (NULL, NULL); + g_object_set (G_OBJECT (widget), + "hexpand", TRUE, + "halign", GTK_ALIGN_FILL, + "vexpand", TRUE, + "valign", GTK_ALIGN_FILL, + "hscrollbar-policy", GTK_POLICY_AUTOMATIC, + "vscrollbar-policy", GTK_POLICY_AUTOMATIC, + "shadow-type", GTK_SHADOW_ETCHED_IN, + NULL); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (widget), add_widget); + + gtk_grid_attach (add_to, widget, 0, *at_row, 1, 1); + (*at_row)++; + + return add_widget; +} + +#define FLAG_NONE (0) +#define FLAG_PORT_MEMORY (1 << 0) +#define FLAG_MARKUP (1 << 1) + +static void +set_label_text (GtkWidget *label, + const gchar *not_part_markup, + gchar *text, + guint32 flags) +{ + if (text) { + if ((flags & FLAG_MARKUP) != 0) + gtk_label_set_markup (GTK_LABEL (label), text); + else + gtk_label_set_text (GTK_LABEL (label), text); + + if ((flags & FLAG_PORT_MEMORY) != 0) + PORT_Free (text); + else + g_free (text); + } else { + gtk_label_set_markup (GTK_LABEL (label), not_part_markup); } +} - /* fingerprints */ - markup = g_strdup_printf ("<tt>%s</tt>", e_cert_get_sha1_fingerprint (cert)); - label = e_builder_get_widget (cvm_data->builder, "fingerprints-sha1"); - gtk_label_set_markup (GTK_LABEL (label), markup); - g_free (markup); +static void +get_cert_times (CERTCertificate *cert, + gchar **issued_on, + gchar **expires_on) +{ + PRTime time_issued_on; + PRTime time_expires_on; + PRExplodedTime explodedTime; + struct tm exploded_tm; + gchar buf[128]; + + g_return_if_fail (cert != NULL); + g_return_if_fail (issued_on != NULL); + g_return_if_fail (expires_on != NULL); + + if (SECSuccess != CERT_GetCertTimes (cert, &time_issued_on, &time_expires_on)) + return; + + PR_ExplodeTime (time_issued_on, PR_LocalTimeParameters, &explodedTime); + exploded_tm.tm_sec = explodedTime.tm_sec; + exploded_tm.tm_min = explodedTime.tm_min; + exploded_tm.tm_hour = explodedTime.tm_hour; + exploded_tm.tm_mday = explodedTime.tm_mday; + exploded_tm.tm_mon = explodedTime.tm_month; + exploded_tm.tm_year = explodedTime.tm_year - 1900; + e_utf8_strftime (buf, sizeof (buf), "%x", &exploded_tm); + *issued_on = g_strdup (buf); + + PR_ExplodeTime (time_expires_on, PR_LocalTimeParameters, &explodedTime); + exploded_tm.tm_sec = explodedTime.tm_sec; + exploded_tm.tm_min = explodedTime.tm_min; + exploded_tm.tm_hour = explodedTime.tm_hour; + exploded_tm.tm_mday = explodedTime.tm_mday; + exploded_tm.tm_mon = explodedTime.tm_month; + exploded_tm.tm_year = explodedTime.tm_year - 1900; + e_utf8_strftime (buf, sizeof (buf), "%x", &exploded_tm); + *expires_on = g_strdup (buf); +} - markup = g_strdup_printf ("<tt>%s</tt>", e_cert_get_md5_fingerprint (cert)); - label = e_builder_get_widget (cvm_data->builder, "fingerprints-md5"); - gtk_label_set_markup (GTK_LABEL (label), markup); - g_free (markup); +static void +fill_general_page (CertificateViewerPriv *priv) +{ + gchar *not_part_markup; + gchar *issued_on = NULL; + gchar *expires_on = NULL; + gchar *port_str; + guchar fingerprint[128]; + SECItem fpItem; + + g_return_if_fail (priv != NULL); + + not_part_markup = g_strconcat ("<i><", _("Not part of certificate"), "></i>", NULL); + + set_label_text (priv->issued_to_cn, not_part_markup, CERT_GetCommonName (&priv->cert->subject), FLAG_PORT_MEMORY); + set_label_text (priv->issued_to_o, not_part_markup, CERT_GetOrgName (&priv->cert->subject), FLAG_PORT_MEMORY); + set_label_text (priv->issued_to_ou, not_part_markup, CERT_GetOrgUnitName (&priv->cert->subject), FLAG_PORT_MEMORY); + set_label_text (priv->issued_to_serial, not_part_markup, CERT_Hexify (&priv->cert->serialNumber, TRUE), FLAG_PORT_MEMORY); + + set_label_text (priv->issued_by_cn, not_part_markup, CERT_GetCommonName (&priv->cert->issuer), FLAG_PORT_MEMORY); + set_label_text (priv->issued_by_o, not_part_markup, CERT_GetOrgName (&priv->cert->issuer), FLAG_PORT_MEMORY); + set_label_text (priv->issued_by_ou, not_part_markup, CERT_GetOrgUnitName (&priv->cert->issuer), FLAG_PORT_MEMORY); + + get_cert_times (priv->cert, &issued_on, &expires_on); + set_label_text (priv->validity_issued_on, not_part_markup, issued_on, FLAG_NONE); + set_label_text (priv->validity_expires_on, not_part_markup, expires_on, FLAG_NONE); + + memset (fingerprint, 0, sizeof fingerprint); + PK11_HashBuf ( + SEC_OID_SHA1, fingerprint, + priv->cert->derCert.data, + priv->cert->derCert.len); + fpItem.data = fingerprint; + fpItem.len = SHA1_LENGTH; + port_str = CERT_Hexify (&fpItem, TRUE); + set_label_text (priv->fingerprints_sha1, not_part_markup, g_strconcat ("<tt>", port_str, "</tt>", NULL), FLAG_MARKUP); + PORT_Free (port_str); + + memset (fingerprint, 0, sizeof fingerprint); + PK11_HashBuf ( + SEC_OID_MD5, fingerprint, + priv->cert->derCert.data, + priv->cert->derCert.len); + fpItem.data = fingerprint; + fpItem.len = MD5_LENGTH; + port_str = CERT_Hexify (&fpItem, TRUE); + set_label_text (priv->fingerprints_md5, not_part_markup, g_strconcat ("<tt>", port_str, "</tt>", NULL), FLAG_MARKUP); + PORT_Free (port_str); + + g_free (not_part_markup); } static void -populate_fields_tree (CertificateViewerData *cvm_data, +populate_fields_tree (CertificateViewerPriv *priv, EASN1Object *asn1, GtkTreeIter *root) { + GtkTreeStore *fields_store; GtkTreeIter new_iter; + if (!asn1) + return; + + fields_store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->cert_fields_treeview))); + /* first insert a node for the current asn1 */ - gtk_tree_store_insert (cvm_data->fields_store, &new_iter, root, -1); + gtk_tree_store_insert (fields_store, &new_iter, root, -1); gtk_tree_store_set ( - cvm_data->fields_store, &new_iter, + fields_store, &new_iter, 0, e_asn1_object_get_display_name (asn1), 1, asn1, -1); if (e_asn1_object_is_valid_container (asn1)) { GList *children = e_asn1_object_get_children (asn1); + if (children) { - GList *l; - for (l = children; l; l = l->next) { - EASN1Object *subasn1 = l->data; - populate_fields_tree (cvm_data, subasn1, &new_iter); + GList *iter; + for (iter = children; iter; iter = iter->next) { + EASN1Object *subasn1 = iter->data; + + populate_fields_tree (priv, subasn1, &new_iter); } } - g_list_foreach (children, (GFunc) g_object_unref, NULL); - g_list_free (children); + + g_list_free_full (children, g_object_unref); } } static void -hierarchy_selection_changed (GtkTreeSelection *selection, - CertificateViewerData *cvm_data) +hierarchy_selection_changed_cb (GtkTreeSelection *selection, + CertificateViewerPriv *priv) { GtkTreeIter iter; GtkTreeModel *model; - if (gtk_tree_selection_get_selected (selection, - &model, - &iter)) { - EASN1Object *asn1_object; - ECert *cert; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + CERTCertificate *cert; + EASN1Object *asn1; + GtkTreeStore *fields_store; - gtk_tree_model_get ( - model, - &iter, - 1, &cert, - -1); + gtk_tree_model_get (model, &iter, 1, &cert, -1); if (!cert) return; /* display the cert's ASN1 structure */ - asn1_object = e_cert_get_asn1_struct (cert); + asn1 = e_asn1_object_new_from_cert (cert); /* wipe out the old model */ - cvm_data->fields_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); + fields_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT); gtk_tree_view_set_model ( - GTK_TREE_VIEW (cvm_data->fields_tree), - GTK_TREE_MODEL (cvm_data->fields_store)); + GTK_TREE_VIEW (priv->cert_fields_treeview), + GTK_TREE_MODEL (fields_store)); /* populate the fields from the newly selected cert */ - populate_fields_tree (cvm_data, asn1_object, NULL); - gtk_tree_view_expand_all (GTK_TREE_VIEW (cvm_data->fields_tree)); - g_object_unref (asn1_object); + populate_fields_tree (priv, asn1, NULL); + gtk_tree_view_expand_all (GTK_TREE_VIEW (priv->cert_fields_treeview)); + if (asn1) + g_object_unref (asn1); /* and blow away the field value */ gtk_text_buffer_set_text ( - gtk_text_view_get_buffer (GTK_TEXT_VIEW (cvm_data->field_text)), + gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->cert_field_value_textview)), "", 0); } } static void -fields_selection_changed (GtkTreeSelection *selection, - CertificateViewerData *cvm_data) +fields_selection_changed_cb (GtkTreeSelection *selection, + CertificateViewerPriv *priv) { GtkTreeIter iter; GtkTreeModel *model; - if (gtk_tree_selection_get_selected (selection, - &model, - &iter)) { - EASN1Object *asn1_object; - const gchar *value; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + EASN1Object *asn1 = NULL; + const gchar *value = NULL; + GtkTextView *textview; + GtkTextBuffer *textbuffer; - gtk_tree_model_get ( - model, - &iter, - 1, &asn1_object, - -1); + gtk_tree_model_get (model, &iter, 1, &asn1, -1); - value = e_asn1_object_get_display_value (asn1_object); + if (asn1) + value = e_asn1_object_get_display_value (asn1); - gtk_text_buffer_set_text ( - gtk_text_view_get_buffer (GTK_TEXT_VIEW (cvm_data->field_text)), - "", 0); + textview = GTK_TEXT_VIEW (priv->cert_field_value_textview); + textbuffer = gtk_text_view_get_buffer (textview); + + gtk_text_buffer_set_text (textbuffer, "", 0); if (value) { GtkTextIter text_iter; - gtk_text_buffer_get_start_iter ( - gtk_text_view_get_buffer (GTK_TEXT_VIEW (cvm_data->field_text)), - &text_iter); + gtk_text_buffer_get_start_iter (textbuffer, &text_iter); - gtk_text_buffer_insert_with_tags ( - gtk_text_view_get_buffer (GTK_TEXT_VIEW (cvm_data->field_text)), - &text_iter, + gtk_text_buffer_insert_with_tags (textbuffer, &text_iter, value, strlen (value), - cvm_data->text_tag, NULL); + priv->monospace_tag, NULL); } + + if (asn1) + g_object_unref (asn1); } } static void -fill_in_details (CertificateViewerData *cvm_data, - ECert *cert) +fill_details_page (CertificateViewerPriv *priv) { - GList *l; + GSList *iter; GtkTreeIter root; GtkTreeSelection *selection; gboolean root_set = FALSE; + GtkTreeStore *hierarchy_store; - /* hook up all the hierarchy tree foo */ - cvm_data->hierarchy_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT); - cvm_data->hierarchy_tree = e_builder_get_widget (cvm_data->builder, "cert-hierarchy-treeview"); + g_return_if_fail (priv != NULL); + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->cert_hierarchy_treeview), FALSE); + + hierarchy_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_view_set_model ( - GTK_TREE_VIEW (cvm_data->hierarchy_tree), - GTK_TREE_MODEL (cvm_data->hierarchy_store)); + GTK_TREE_VIEW (priv->cert_hierarchy_treeview), + GTK_TREE_MODEL (hierarchy_store)); gtk_tree_view_insert_column_with_attributes ( - GTK_TREE_VIEW (cvm_data->hierarchy_tree), + GTK_TREE_VIEW (priv->cert_hierarchy_treeview), -1, "Cert", gtk_cell_renderer_text_new (), "text", 0, NULL); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cvm_data->hierarchy_tree)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->cert_hierarchy_treeview)); g_signal_connect ( selection, "changed", - G_CALLBACK (hierarchy_selection_changed), cvm_data); + G_CALLBACK (hierarchy_selection_changed_cb), priv); - /* hook up all the fields tree foo */ - cvm_data->fields_tree = e_builder_get_widget (cvm_data->builder, "cert-fields-treeview"); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->cert_fields_treeview), FALSE); gtk_tree_view_insert_column_with_attributes ( - GTK_TREE_VIEW (cvm_data->fields_tree), + GTK_TREE_VIEW (priv->cert_fields_treeview), -1, "Field", gtk_cell_renderer_text_new (), "text", 0, NULL); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cvm_data->fields_tree)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->cert_fields_treeview)); g_signal_connect ( selection, "changed", - G_CALLBACK (fields_selection_changed), cvm_data); - - /* hook up all the field display foo */ - cvm_data->field_text = e_builder_get_widget (cvm_data->builder, "cert-field-value-textview"); + G_CALLBACK (fields_selection_changed_cb), priv); /* set the font of the field value viewer to be some fixed - * width font to the hex display doesn't look like ass. */ - cvm_data->text_tag = gtk_text_buffer_create_tag ( - gtk_text_view_get_buffer (GTK_TEXT_VIEW (cvm_data->field_text)), - "mono", - "font", "Mono", - NULL); - - /* initially populate the hierarchy from the cert's chain */ - cvm_data->cert_chain = e_cert_get_chain (cert); - cvm_data->cert_chain = g_list_reverse (cvm_data->cert_chain); - for (l = cvm_data->cert_chain; l; l = l->next) { - ECert *c = l->data; - const gchar *str; + * width font to the hex display looks nice. */ + priv->monospace_tag = gtk_text_buffer_create_tag ( + gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->cert_field_value_textview)), + "mono", "font", "Mono", NULL); + + /* initially populate the hierarchy from the issuers' chain */ + for (iter = priv->issuers; iter; iter = g_slist_next (iter)) { + CERTCertificate *cert = iter->data; + gchar *str; GtkTreeIter new_iter; - str = e_cert_get_cn (c); - if (!str) - str = e_cert_get_subject_name (c); + if (!cert) + continue; + + str = CERT_GetCommonName (&cert->subject); - gtk_tree_store_insert (cvm_data->hierarchy_store, &new_iter, root_set ? &root : NULL, -1); + gtk_tree_store_insert (hierarchy_store, &new_iter, root_set ? &root : NULL, -1); gtk_tree_store_set ( - cvm_data->hierarchy_store, &new_iter, - 0, str, - 1, c, + hierarchy_store, &new_iter, + 0, str ? str : cert->subjectName, + 1, cert, -1); root = new_iter; root_set = TRUE; + + if (str) + PORT_Free (str); + } + + gtk_tree_view_expand_all (GTK_TREE_VIEW (priv->cert_hierarchy_treeview)); +} + +static gchar * +get_window_title (CERTCertificate *cert) +{ + gchar *str; + + g_return_val_if_fail (cert != NULL, NULL); + + if (cert->nickname) + return g_strdup (cert->nickname); + + str = CERT_GetCommonName (&cert->subject); + if (str) { + gchar *title; + + title = g_strdup (str); + PORT_Free (str); + + return title; } - gtk_tree_view_expand_all (GTK_TREE_VIEW (cvm_data->hierarchy_tree)); + return cert->subjectName; } GtkWidget * -certificate_viewer_show (ECert *cert) +certificate_viewer_new (GtkWindow *parent, + const CERTCertificate *cert, + const GSList *issuers_chain_certs) { - CertificateViewerData *cvm_data; - GtkDialog *dialog; - GtkWidget *action_area; + CertificateViewerPriv *priv; + GtkWidget *dialog, *notebook, *widget; + GtkGrid *grid; + gint row; + GSList *iter; gchar *title; - cvm_data = g_new0 (CertificateViewerData, 1); + g_return_val_if_fail (cert != NULL, NULL); + + priv = g_new0 (CertificateViewerPriv, 1); + priv->cert = CERT_DupCertificate ((CERTCertificate *) cert); + priv->issuers = g_slist_copy ((GSList *) issuers_chain_certs); - cvm_data->builder = gtk_builder_new (); - e_load_ui_builder_definition (cvm_data->builder, "smime-ui.ui"); + /* root issuer first, then bottom down to certificate itself */ + priv->issuers = g_slist_reverse (priv->issuers); + priv->issuers = g_slist_append (priv->issuers, priv->cert); - cvm_data->dialog = e_builder_get_widget (cvm_data->builder, "certificate-viewer-dialog"); + for (iter = priv->issuers; iter; iter = g_slist_next (iter)) { + iter->data = CERT_DupCertificate (iter->data); + } - gtk_widget_realize (cvm_data->dialog); + title = get_window_title (priv->cert); - dialog = GTK_DIALOG (cvm_data->dialog); - action_area = gtk_dialog_get_action_area (dialog); - gtk_container_set_border_width (GTK_CONTAINER (action_area), 12); + dialog = gtk_dialog_new_with_buttons (title, parent, + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + NULL); - title = g_strdup_printf ( - _("Certificate Viewer: %s"), e_cert_get_window_title (cert)); - gtk_window_set_title (GTK_WINDOW (cvm_data->dialog), title); g_free (title); - fill_in_general (cvm_data, cert); - fill_in_details (cvm_data, cert); + g_object_set_data_full (G_OBJECT (dialog), CERTIFICATE_VIEWER_PRIV_KEY, priv, free_priv_struct); + + notebook = gtk_notebook_new (); + gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), notebook); + gtk_container_set_border_width (GTK_CONTAINER (notebook), 12); + + /* General page */ + row = 0; + grid = GTK_GRID (gtk_grid_new ()); + g_object_set (G_OBJECT (grid), + "hexpand", TRUE, + "halign", GTK_ALIGN_FILL, + "vexpand", FALSE, + "valign", GTK_ALIGN_START, + "border-width", 12, + "row-spacing", 6, + "column-spacing", 6, + NULL); + + begin_section (grid, _("This certificate has been verified for the following uses:"), &row, 4); + + if (!priv->cert->keyUsagePresent || (priv->cert->keyUsage & certificateUsageSSLClient) != 0) { + widget = add_info_label (grid, NULL, &row); + gtk_label_set_text (GTK_LABEL (widget), _("SSL Client Certificate")); + } + + if (!priv->cert->keyUsagePresent || (priv->cert->keyUsage & (certificateUsageSSLServer | certificateUsageSSLCA)) != 0) { + widget = add_info_label (grid, NULL, &row); + gtk_label_set_text (GTK_LABEL (widget), _("SSL Server Certificate")); + } + + if (!priv->cert->keyUsagePresent || (priv->cert->keyUsage & certificateUsageEmailSigner) != 0) { + widget = add_info_label (grid, NULL, &row); + gtk_label_set_text (GTK_LABEL (widget), _("Email Signer Certificate")); + } + + if (!priv->cert->keyUsagePresent || (priv->cert->keyUsage & certificateUsageEmailRecipient) != 0) { + widget = add_info_label (grid, NULL, &row); + gtk_label_set_text (GTK_LABEL (widget), _("Email Recipient Certificate")); + } + + widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + g_object_set (G_OBJECT (widget), + "hexpand", TRUE, + "halign", GTK_ALIGN_FILL, + "vexpand", FALSE, + "valign", GTK_ALIGN_START, + NULL); + + gtk_grid_attach (grid, widget, 0, row, 3, 1); + row++; + + begin_section (grid, _("Issued To"), &row, 4); + priv->issued_to_cn = add_info_label (grid, _("Common Name (CN)"), &row); + priv->issued_to_o = add_info_label (grid, _("Organization (O)"), &row); + priv->issued_to_ou = add_info_label (grid, _("Organizational Unit (OU)"), &row); + priv->issued_to_serial = add_info_label (grid, _("Serial Number"), &row); + + begin_section (grid, _("Issued By"), &row, 3); + priv->issued_by_cn = add_info_label (grid, _("Common Name (CN)"), &row); + priv->issued_by_o = add_info_label (grid, _("Organization (O)"), &row); + priv->issued_by_ou = add_info_label (grid, _("Organizational Unit (OU)"), &row); + + begin_section (grid, _("Validity"), &row, 2); + priv->validity_issued_on = add_info_label (grid, _("Issued On"), &row); + priv->validity_expires_on = add_info_label (grid, _("Expires On"), &row); + + begin_section (grid, _("Fingerprints"), &row, 2); + priv->fingerprints_sha1 = add_info_label (grid, _("SHA1 Fingerprint"), &row); + priv->fingerprints_md5 = add_info_label (grid, _("MD5 Fingerprint"), &row); + + widget = gtk_label_new (_("General")); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), GTK_WIDGET (grid), widget); + + /* Details page */ + row = 0; + grid = GTK_GRID (gtk_grid_new ()); + g_object_set (G_OBJECT (grid), + "hexpand", TRUE, + "halign", GTK_ALIGN_FILL, + "vexpand", TRUE, + "valign", GTK_ALIGN_FILL, + "border-width", 12, + "row-spacing", 6, + "column-spacing", 6, + NULL); + + priv->cert_hierarchy_treeview = add_scrolled_window (grid, + _("Certificate Hierarchy"), &row, gtk_tree_view_new ()); + + priv->cert_fields_treeview = add_scrolled_window (grid, + _("Certificate Fields"), &row, gtk_tree_view_new ()); + + priv->cert_field_value_textview = add_scrolled_window (grid, + _("Field Value"), &row, gtk_text_view_new ()); + + widget = gtk_label_new (_("Details")); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), GTK_WIDGET (grid), widget); + + gtk_widget_show_all (notebook); - g_object_weak_ref (G_OBJECT (cvm_data->dialog), free_data, cvm_data); + fill_general_page (priv); + fill_details_page (priv); - /* gtk_widget_show (cvm_data->dialog);*/ - return cvm_data->dialog; + return dialog; } diff --git a/smime/gui/certificate-viewer.h b/smime/gui/certificate-viewer.h index d452b76c2c..41f2c83c7b 100644 --- a/smime/gui/certificate-viewer.h +++ b/smime/gui/certificate-viewer.h @@ -17,15 +17,16 @@ * Chris Toshok <toshok@ximian.com> * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * */ -#ifndef _CERTIFICATE_VIEWER_H_ -#define _CERTIFICATE_VIEWER_H +#ifndef CERTIFICATE_VIEWER_H +#define CERTIFICATE_VIEWER_H #include <gtk/gtk.h> -#include "e-cert.h" +#include <cert.h> -GtkWidget * certificate_viewer_show (ECert *cert); +GtkWidget * certificate_viewer_new (GtkWindow *parent, + const CERTCertificate *cert, + const GSList *issuers_chain_certs); -#endif /* _CERTIFICATE_VIEWER_H_ */ +#endif /* CERTIFICATE_VIEWER_H */ diff --git a/smime/gui/smime-ui.ui b/smime/gui/smime-ui.ui index 0ad3f47d81..5622c4d0e5 100644 --- a/smime/gui/smime-ui.ui +++ b/smime/gui/smime-ui.ui @@ -16,714 +16,6 @@ </row> </data> </object> - <object class="GtkDialog" id="certificate-viewer-dialog"> - <property name="title">dialog1</property> - <property name="window_position">center</property> - <property name="type_hint">dialog</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox1"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkNotebook" id="notebook1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="border_width">12</property> - <child> - <object class="GtkVBox" id="vbox1"> - <property name="visible">True</property> - <property name="border_width">6</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkFrame" id="frame1"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkVBox" id="vbox2"> - <property name="visible">True</property> - <property name="border_width">6</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkLabel" id="ssl-client-cert-verified-label"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">SSL Client Certificate</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="ssl-server-cert-verified-label"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">SSL Server Certificate</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="email-signer-cert-verified-label"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Email Signer Certificate</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="email-recipient-cert-verified-label"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Email Recipient Certificate</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="label" translatable="yes">This certificate has been verified for the following uses:</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkHSeparator" id="hseparator1"> - <property name="visible">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkTable" id="table3"> - <property name="visible">True</property> - <property name="border_width">3</property> - <property name="n_rows">15</property> - <property name="n_columns">2</property> - <property name="column_spacing">6</property> - <child> - <object class="GtkLabel" id="label25"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">1</property> - <property name="ypad">3</property> - <property name="label" translatable="yes">Issued To</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label26"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Common Name (CN)</property> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label27"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Organization (O)</property> - </object> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label28"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Organizational Unit (OU)</property> - </object> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label29"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Serial Number</property> - </object> - <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label31"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Common Name (CN)</property> - </object> - <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label32"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Organization (O)</property> - </object> - <packing> - <property name="top_attach">7</property> - <property name="bottom_attach">8</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label33"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Organizational Unit (OU)</property> - </object> - <packing> - <property name="top_attach">8</property> - <property name="bottom_attach">9</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label36"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Issued On</property> - </object> - <packing> - <property name="top_attach">10</property> - <property name="bottom_attach">11</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label37"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">Expires On</property> - </object> - <packing> - <property name="top_attach">11</property> - <property name="bottom_attach">12</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label30"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">1</property> - <property name="ypad">3</property> - <property name="label" translatable="yes">Issued By</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label35"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="ypad">3</property> - <property name="label" translatable="yes">Fingerprints</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="right_attach">2</property> - <property name="top_attach">12</property> - <property name="bottom_attach">13</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label38"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">SHA1 Fingerprint</property> - </object> - <packing> - <property name="top_attach">13</property> - <property name="bottom_attach">14</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label39"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">6</property> - <property name="label" translatable="yes">MD5 Fingerprint</property> - </object> - <packing> - <property name="top_attach">14</property> - <property name="bottom_attach">15</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="issued-to-o"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="issued-to-ou"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="issued-to-serial"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="issued-by-cn"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="issued-by-o"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">7</property> - <property name="bottom_attach">8</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="issued-by-ou"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">8</property> - <property name="bottom_attach">9</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="validity-issued-on"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">10</property> - <property name="bottom_attach">11</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="validity-expires-on"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">11</property> - <property name="bottom_attach">12</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="fingerprints-sha1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">13</property> - <property name="bottom_attach">14</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="fingerprints-md5"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">14</property> - <property name="bottom_attach">15</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="issued-to-cn"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><Not Part of Certificate></property> - <property name="selectable">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label34"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="ypad">3</property> - <property name="label" translatable="yes">Validity</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="right_attach">2</property> - <property name="top_attach">9</property> - <property name="bottom_attach">10</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> - </object> - </child> - <child type="tab"> - <object class="GtkLabel" id="label1"> - <property name="visible">True</property> - <property name="label" translatable="yes">General</property> - </object> - <packing> - <property name="tab_fill">False</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="vbox3"> - <property name="visible">True</property> - <property name="border_width">6</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkFrame" id="frame4"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="border_width">6</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <property name="shadow_type">in</property> - <child> - <object class="GtkTreeView" id="cert-hierarchy-treeview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="headers_visible">False</property> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label51"> - <property name="visible">True</property> - <property name="label" translatable="yes">Certificate Hierarchy</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkFrame" id="frame5"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="border_width">6</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <property name="shadow_type">in</property> - <child> - <object class="GtkTreeView" id="cert-fields-treeview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="headers_visible">False</property> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label52"> - <property name="visible">True</property> - <property name="label" translatable="yes">Certificate Fields</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkFrame" id="frame6"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow3"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="border_width">6</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <property name="shadow_type">etched-in</property> - <child> - <object class="GtkTextView" id="cert-field-value-textview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">False</property> - <property name="cursor_visible">False</property> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label53"> - <property name="visible">True</property> - <property name="label" translatable="yes">Field Value</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child type="tab"> - <object class="GtkLabel" id="label2"> - <property name="visible">True</property> - <property name="label" translatable="yes">Details</property> - </object> - <packing> - <property name="position">1</property> - <property name="tab_fill">False</property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area1"> - <property name="visible">True</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="closebutton1"> - <property name="label">gtk-close</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-7">closebutton1</action-widget> - </action-widgets> - </object> <object class="GtkWindow" id="cert-manager-config-control"> <property name="title">window1</property> <child> diff --git a/smime/lib/e-asn1-object.c b/smime/lib/e-asn1-object.c index 53441516f5..7e5f27ca0c 100644 --- a/smime/lib/e-asn1-object.c +++ b/smime/lib/e-asn1-object.c @@ -39,13 +39,18 @@ * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif +#include <glib/gi18n.h> + #include "e-asn1-object.h" -#include "secasn1.h" +#include "pk11func.h" +#include "certdb.h" +#include "hasht.h" #define E_ASN1_OBJECT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -67,220 +72,793 @@ struct _EASN1ObjectPrivate { G_DEFINE_TYPE (EASN1Object, e_asn1_object, G_TYPE_OBJECT) -static void -e_asn1_object_finalize (GObject *object) +static gboolean +get_int_value (SECItem *versionItem, + gulong *version) { - EASN1ObjectPrivate *priv; + SECStatus srv; + srv = SEC_ASN1DecodeInteger (versionItem,version); + if (srv != SECSuccess) { + g_warning ("could not decode version of cert"); + return FALSE; + } + return TRUE; +} - priv = E_ASN1_OBJECT_GET_PRIVATE (object); +static gboolean +process_version (SECItem *versionItem, + EASN1Object **retItem) +{ + EASN1Object *item = e_asn1_object_new (); + gulong version; - g_free (priv->display_name); - g_free (priv->value); + e_asn1_object_set_display_name (item, _("Version")); - g_list_free_full (priv->children, (GDestroyNotify) g_object_unref); + /* Now to figure out what version this certificate is. */ - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_asn1_object_parent_class)->finalize (object); + if (versionItem->data) { + if (!get_int_value (versionItem, &version)) + return FALSE; + } else { + /* If there is no version present in the cert, then rfc2459 + * says we default to v1 (0) */ + version = 0; + } + + switch (version) { + case 0: + e_asn1_object_set_display_value (item, _("Version 1")); + break; + case 1: + e_asn1_object_set_display_value (item, _("Version 2")); + break; + case 2: + e_asn1_object_set_display_value (item, _("Version 3")); + break; + default: + g_warning ("Bad value for cert version"); + return FALSE; + } + + *retItem = item; + return TRUE; } -static void -e_asn1_object_class_init (EASN1ObjectClass *class) +static gboolean +process_serial_number_der (SECItem *serialItem, + EASN1Object **retItem) { - GObjectClass *object_class; + gchar *serialNumber; + EASN1Object *item = e_asn1_object_new (); - g_type_class_add_private (class, sizeof (EASN1ObjectPrivate)); + e_asn1_object_set_display_name (item, _("Serial Number")); - object_class = G_OBJECT_CLASS (class); - object_class->finalize = e_asn1_object_finalize; + serialNumber = CERT_Hexify (serialItem, 1); + + e_asn1_object_set_display_value (item, serialNumber); + PORT_Free (serialNumber); /* XXX the right free to use? */ + + *retItem = item; + return TRUE; } -static void -e_asn1_object_init (EASN1Object *asn1) +static gboolean +get_default_oid_format (SECItem *oid, + gchar **text) { - asn1->priv = E_ASN1_OBJECT_GET_PRIVATE (asn1); - - asn1->priv->valid_container = TRUE; + GString *str; + gulong val = oid->data[0]; + guint ii = val % 40; + + val /= 40; + + str = g_string_new (""); + g_string_append_printf (str, "%lu %u ", val, ii); + + val = 0; + for (ii = 1; ii < oid->len; ii++) { + /* In this loop, we have to parse a DER formatted + * If the first bit is a 1, then the integer is + * represented by more than one byte. If the + * first bit is set then we continue on and add + * the values of the later bytes until we get + * a byte without the first bit set. + */ + gulong jj; + + jj = oid->data[ii]; + val = (val << 7) | (jj & 0x7f); + if (jj & 0x80) + continue; + g_string_append_printf (str, "%lu ", val); + + val = 0; + } + + *text = g_string_free (str, FALSE); + + return TRUE; } -/* This function is used to interpret an integer that - * was encoded in a DER buffer. This function is used - * when converting a DER buffer into a nsIASN1Object - * structure. This interprets the buffer in data - * as defined by the DER (Distinguised Encoding Rules) of - * ASN1. -*/ -static gint -get_integer_256 (guchar *data, - guint nb) +static gboolean +get_oid_text (SECItem *oid, + gchar **text) { - gint val; + SECOidTag oidTag = SECOID_FindOIDTag (oid); + gchar *temp; - switch (nb) { - case 1: - val = data[0]; + switch (oidTag) { + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 MD2 With RSA Encryption")); break; - case 2: - val = (data[0] << 8) | data[1]; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 MD5 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-1 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-256 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-384 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-512 With RSA Encryption")); + break; + case SEC_OID_AVA_COUNTRY_NAME: + *text = g_strdup ("C"); + break; + case SEC_OID_AVA_COMMON_NAME: + *text = g_strdup ("CN"); + break; + case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: + *text = g_strdup ("OU"); + break; + case SEC_OID_AVA_ORGANIZATION_NAME: + *text = g_strdup ("O"); + break; + case SEC_OID_AVA_LOCALITY: + *text = g_strdup ("L"); + break; + case SEC_OID_AVA_DN_QUALIFIER: + *text = g_strdup ("DN"); + break; + case SEC_OID_AVA_DC: + *text = g_strdup ("DC"); + break; + case SEC_OID_AVA_STATE_OR_PROVINCE: + *text = g_strdup ("ST"); + break; + case SEC_OID_PKCS1_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 RSA Encryption")); + break; + case SEC_OID_X509_KEY_USAGE: + *text = g_strdup (_("Certificate Key Usage")); break; - case 3: - val = (data[0] << 16) | (data[1] << 8) | data[2]; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + *text = g_strdup (_("Netscape Certificate Type")); break; - case 4: - val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + case SEC_OID_X509_AUTH_KEY_ID: + *text = g_strdup (_("Certificate Authority Key Identifier")); + break; + case SEC_OID_RFC1274_UID: + *text = g_strdup ("UID"); + break; + case SEC_OID_PKCS9_EMAIL_ADDRESS: + *text = g_strdup ("E"); break; default: - return -1; - } + if (!get_default_oid_format (oid, &temp)) + return FALSE; - return val; + *text = g_strdup_printf (_("Object Identifier (%s)"), temp); + g_free (temp); + + break; + } + return TRUE; } -/* This function is used to retrieve the lenght of a DER encoded - * item. It looks to see if this a multibyte length and then - * interprets the buffer accordingly to get the actual length value. - * This funciton is used mostly while parsing the DER headers. - * - * A DER encoded item has the following structure: - * - * <tag><length<data consisting of lenght bytes> - */ -static guint32 -get_der_item_length (guchar *data, - guchar *end, - gulong *bytesUsed, - gboolean *indefinite) -{ - guchar lbyte = *data++; - PRInt32 length = -1; - - *indefinite = FALSE; - if (lbyte >= 0x80) { - /* Multibyte length */ - guint nb = (guint) (lbyte & 0x7f); - if (nb > 4) { - return -1; +static gboolean +process_raw_bytes (SECItem *data, + gchar **text) +{ + /* This function is used to display some DER bytes + * that we have not added support for decoding. + * It prints the value of the byte out into a + * string that can later be displayed as a byte + * string. We place a new line after 24 bytes + * to break up extermaly long sequence of bytes. + */ + GString *str = g_string_new (""); + PRUint32 i; + + for (i = 0; i < data->len; i++) { + g_string_append_printf (str, "%02x ", data->data[i]); + if ((i + 1) % 16 == 0) { + g_string_append (str, "\n"); } - if (nb > 0) { + } + *text = g_string_free (str, FALSE); + return TRUE; +} - if ((data + nb) > end) { - return -1; - } - length = get_integer_256 (data, nb); - if (length < 0) - return -1; - } else { - *indefinite = TRUE; - length = 0; - } - *bytesUsed = nb+1; +static gboolean +process_sec_algorithm_id (SECAlgorithmID *algID, + EASN1Object **retSequence) +{ + EASN1Object *sequence = e_asn1_object_new (); + gchar *text = NULL; + + *retSequence = NULL; + + get_oid_text (&algID->algorithm, &text); + + if (!algID->parameters.len || + algID->parameters.data[0] == E_ASN1_OBJECT_TYPE_NULL) { + e_asn1_object_set_display_value (sequence, text); + e_asn1_object_set_valid_container (sequence, FALSE); } else { - length = lbyte; - *bytesUsed = 1; + EASN1Object *subitem; + + subitem = e_asn1_object_new (); + e_asn1_object_set_display_name (subitem, _("Algorithm Identifier")); + e_asn1_object_set_display_value (subitem, text); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + g_free (text); + + subitem = e_asn1_object_new (); + e_asn1_object_set_display_name (subitem, _("Algorithm Parameters")); + process_raw_bytes (&algID->parameters, &text); + e_asn1_object_set_display_value (subitem, text); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); } - return length; + + g_free (text); + *retSequence = sequence; + return TRUE; } static gboolean -build_from_der (EASN1Object *parent, - gchar *data, - gchar *end) +process_subject_public_key_info (CERTSubjectPublicKeyInfo *spki, + EASN1Object *parentSequence) { - gulong bytesUsed; - gboolean indefinite; - PRInt32 len; - PRUint32 type; - guchar code, tagnum; - EASN1Object *asn1object = NULL; + EASN1Object *spkiSequence = e_asn1_object_new (); + EASN1Object *sequenceItem; + EASN1Object *printableItem; + SECItem data; + gchar *text = NULL; + + e_asn1_object_set_display_name (spkiSequence, _("Subject Public Key Info")); + + if (!process_sec_algorithm_id (&spki->algorithm, &sequenceItem)) + return FALSE; + + e_asn1_object_set_display_name (sequenceItem, _("Subject Public Key Algorithm")); + + e_asn1_object_append_child (spkiSequence, sequenceItem); - if (data >= end) + /* The subjectPublicKey field is encoded as a bit string. + * ProcessRawBytes expects the lenght to be in bytes, so + * let's convert the lenght into a temporary SECItem. + */ + data.data = spki->subjectPublicKey.data; + data.len = spki->subjectPublicKey.len / 8; + + process_raw_bytes (&data, &text); + printableItem = e_asn1_object_new (); + + e_asn1_object_set_display_value (printableItem, text); + e_asn1_object_set_display_name (printableItem, _("Subject's Public Key")); + e_asn1_object_append_child (spkiSequence, printableItem); + g_object_unref (printableItem); + g_free (text); + + e_asn1_object_append_child (parentSequence, spkiSequence); + g_object_unref (spkiSequence); + + return TRUE; +} + +static gboolean +process_ns_cert_type_extensions (SECItem *extData, + GString *text) +{ + SECItem decoded; + guchar nsCertType; + + decoded.data = NULL; + decoded.len = 0; + if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, + SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { + g_string_append (text, _("Error: Unable to process extension")); return TRUE; + } - /* - * A DER item has the form of |tag|len|data - * tag is one byte and describes the type of elment - * we are dealing with. - * len is a DER encoded gint telling us how long the data is - * data is a buffer that is len bytes long and has to be - * interpreted according to its type. - */ + nsCertType = decoded.data[0]; - while (data < end) { - code = *data; - tagnum = code & SEC_ASN1_TAGNUM_MASK; + PORT_Free (decoded.data); /* XXX right free? */ - /* - * NOTE: This code does not (yet) handle the high-tag-number form! - */ - if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) { - return FALSE; + if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) { + g_string_append (text, _("SSL Client Certificate")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_SSL_SERVER) { + g_string_append (text, _("SSL Server Certificate")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_EMAIL) { + g_string_append (text, _("Email")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) { + g_string_append (text, _("Object Signer")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_SSL_CA) { + g_string_append (text, _("SSL Certificate Authority")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_EMAIL_CA) { + g_string_append (text, _("Email Certificate Authority")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) { + g_string_append (text, _("Object Signer")); + g_string_append (text, "\n"); + } + return TRUE; +} + +static gboolean +process_key_usage_extensions (SECItem *extData, + GString *text) +{ + SECItem decoded; + guchar keyUsage; + + decoded.data = NULL; + decoded.len = 0; + if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, + SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { + g_string_append (text, _("Error: Unable to process extension")); + return TRUE; + } + + keyUsage = decoded.data[0]; + PORT_Free (decoded.data); /* XXX right free? */ + + if (keyUsage & KU_DIGITAL_SIGNATURE) { + g_string_append (text, _("Signing")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_NON_REPUDIATION) { + g_string_append (text, _("Non-repudiation")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_KEY_ENCIPHERMENT) { + g_string_append (text, _("Key Encipherment")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_DATA_ENCIPHERMENT) { + g_string_append (text, _("Data Encipherment")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_KEY_AGREEMENT) { + g_string_append (text, _("Key Agreement")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_KEY_CERT_SIGN) { + g_string_append (text, _("Certificate Signer")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_CRL_SIGN) { + g_string_append (text, _("CRL Signer")); + g_string_append (text, "\n"); + } + + return TRUE; +} + +static gboolean +process_extension_data (SECOidTag oidTag, + SECItem *extData, + GString *str) +{ + gboolean rv; + switch (oidTag) { + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + rv = process_ns_cert_type_extensions (extData, str); + break; + case SEC_OID_X509_KEY_USAGE: + rv = process_key_usage_extensions (extData, str); + break; + default: { + gchar *text; + rv = process_raw_bytes (extData, &text); + g_string_append (str, text); + g_free (text); + break; + } + } + return rv; +} + +static gboolean +process_single_extension (CERTCertExtension *extension, + EASN1Object **retExtension) +{ + GString *str = g_string_new (""); + gchar *text; + EASN1Object *extensionItem; + SECOidTag oidTag = SECOID_FindOIDTag (&extension->id); + + get_oid_text (&extension->id, &text); + + extensionItem = e_asn1_object_new (); + + e_asn1_object_set_display_name (extensionItem, text); + g_free (text); + + if (extension->critical.data != NULL) { + if (extension->critical.data[0]) { + g_string_append (str, _("Critical")); + } else { + g_string_append (str, _("Not Critical")); } - data++; - len = get_der_item_length ( - (guchar *) data, (guchar *) end, - &bytesUsed, &indefinite); - data += bytesUsed; - if ((len < 0) || ((data + len) > end)) + } else { + g_string_append (str, _("Not Critical")); + } + g_string_append (str, "\n"); + if (!process_extension_data (oidTag, &extension->value, str)) { + g_string_free (str, TRUE); + return FALSE; + } + + e_asn1_object_set_display_value (extensionItem, str->str); + g_string_free (str, TRUE); + *retExtension = extensionItem; + return TRUE; +} + +static gboolean +process_extensions (CERTCertExtension **extensions, + EASN1Object *parentSequence) +{ + EASN1Object *extensionSequence = e_asn1_object_new (); + PRInt32 i; + + e_asn1_object_set_display_name (extensionSequence, _("Extensions")); + + for (i = 0; extensions[i] != NULL; i++) { + EASN1Object *newExtension; + + if (!process_single_extension (extensions[i], + &newExtension)) return FALSE; - if (code & SEC_ASN1_CONSTRUCTED) { - if (len > 0 || indefinite) { - switch (code & SEC_ASN1_CLASS_MASK) { - case SEC_ASN1_UNIVERSAL: - type = tagnum; - break; - case SEC_ASN1_APPLICATION: - type = E_ASN1_OBJECT_TYPE_APPLICATION; - break; - case SEC_ASN1_CONTEXT_SPECIFIC: - type = E_ASN1_OBJECT_TYPE_CONTEXT_SPECIFIC; - break; - case SEC_ASN1_PRIVATE: - type = E_ASN1_OBJECT_TYPE_PRIVATE; - break; - default: - g_warning ("bad DER"); - return FALSE; - } - - asn1object = e_asn1_object_new (); - asn1object->priv->tag = tagnum; - asn1object->priv->type = type; - - if (!build_from_der ( - asn1object, data, - (len == 0) ? end : data + len)) { - g_object_unref (asn1object); - return FALSE; - } - } - } else { - asn1object = e_asn1_object_new (); + e_asn1_object_append_child (extensionSequence, newExtension); + } + e_asn1_object_append_child (parentSequence, extensionSequence); + return TRUE; +} - asn1object->priv->type = tagnum; - asn1object->priv->tag = tagnum; +static gboolean +process_name (CERTName *name, + gchar **value) +{ + CERTRDN ** rdns; + CERTRDN ** rdn; + CERTAVA ** avas; + CERTAVA * ava; + SECItem *decodeItem = NULL; + GString *final_string = g_string_new (""); + + gchar *type; + GString *avavalue; + gchar *temp; + CERTRDN **lastRdn; + + rdns = name->rdns; + + /* find last RDN */ + lastRdn = rdns; + while (*lastRdn) lastRdn++; + + /* The above whille loop will put us at the last member + * of the array which is a NULL pointer. So let's back + * up one spot so that we have the last non-NULL entry in + * the array in preparation for traversing the + * RDN's (Relative Distinguished Name) in reverse order. + */ + lastRdn--; - /*printableItem->SetData((gchar *)data, len);*/ + /* + * Loop over name contents in _reverse_ RDN order appending to string + * When building the Ascii string, NSS loops over these entries in + * reverse order, so I will as well. The difference is that NSS + * will always place them in a one line string separated by commas, + * where I want each entry on a single line. I can't just use a comma + * as my delimitter because it is a valid character to have in the + * value portion of the AVA and could cause trouble when parsing. + */ + for (rdn = lastRdn; rdn >= rdns; rdn--) { + avas = (*rdn)->avas; + while ((ava = *avas++) != 0) { + if (!get_oid_text (&ava->type, &type)) + return FALSE; + + /* This function returns a string in UTF8 format. */ + decodeItem = CERT_DecodeAVAValue (&ava->value); + if (!decodeItem) { + g_free (type); + return FALSE; + } + + avavalue = g_string_new_len ( + (gchar *) decodeItem->data, decodeItem->len); + + SECITEM_FreeItem (decodeItem, PR_TRUE); + + /* Translators: This string is used in Certificate + * details for fields like Issuer or Subject, which + * shows the field name on the left and its respective + * value on the right, both as stored in the + * certificate itself. You probably do not need to + * change this string, unless changing the order of + * name and value. As a result example: + * "OU = VeriSign Trust Network" */ + temp = g_strdup_printf (_("%s = %s"), type, avavalue->str); + + g_string_append (final_string, temp); + g_string_append (final_string, "\n"); + g_string_free (avavalue, TRUE); + g_free (temp); + g_free (type); } - data += len; + } + *value = g_string_free (final_string, FALSE); + return TRUE; +} + +static gboolean +create_tbs_certificate_asn1_struct (CERTCertificate *cert, + EASN1Object **seq) +{ + /* + ** TBSCertificate ::= SEQUENCE { + ** version [0] EXPLICIT Version DEFAULT v1, + ** serialNumber CertificateSerialNumber, + ** signature AlgorithmIdentifier, + ** issuer Name, + ** validity Validity, + ** subject Name, + ** subjectPublicKeyInfo SubjectPublicKeyInfo, + ** issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + ** -- If present, version shall be v2 or v3 + ** subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + ** -- If present, version shall be v2 or v3 + ** extensions [3] EXPLICIT Extensions OPTIONAL + ** -- If present, version shall be v3 + ** } + ** + ** This is the ASN1 structure we should be dealing with at this point. + ** The code in this method will assert this is the structure we're dealing + ** and then add more user friendly text for that field. + */ + EASN1Object *sequence = e_asn1_object_new (); + gchar *text; + EASN1Object *subitem; + SECItem data; + + e_asn1_object_set_display_name (sequence, _("Certificate")); + + if (!process_version (&cert->version, &subitem)) + return FALSE; + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + if (!process_serial_number_der (&cert->serialNumber, &subitem)) + return FALSE; + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + if (!process_sec_algorithm_id (&cert->signature, &subitem)) + return FALSE; + e_asn1_object_set_display_name (subitem, _("Certificate Signature Algorithm")); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + process_name (&cert->issuer, &text); + subitem = e_asn1_object_new (); + e_asn1_object_set_display_value (subitem, text); + g_free (text); + + e_asn1_object_set_display_name (subitem, _("Issuer")); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + +#ifdef notyet + nsCOMPtr < nsIASN1Sequence> validitySequence = new nsNSSASN1Sequence (); + nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpValidity").get (), + text); + validitySequence->SetDisplayName (text); + asn1Objects->AppendElement (validitySequence, PR_FALSE); + nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotBefore").get (), + text); + nsCOMPtr < nsIX509CertValidity> validityData; + GetValidity (getter_AddRefs (validityData)); + PRTime notBefore, notAfter; + + validityData->GetNotBefore (¬Before); + validityData->GetNotAfter (¬After); + validityData = 0; + rv = ProcessTime (notBefore, text.get (), validitySequence); + if (NS_FAILED (rv)) + return rv; + + nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotAfter").get (), + text); + rv = ProcessTime (notAfter, text.get (), validitySequence); + if (NS_FAILED (rv)) + return rv; +#endif + + subitem = e_asn1_object_new (); + e_asn1_object_set_display_name (subitem, _("Subject")); + + process_name (&cert->subject, &text); + e_asn1_object_set_display_value (subitem, text); + g_free (text); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + if (!process_subject_public_key_info (&cert->subjectPublicKeyInfo, sequence)) + return FALSE; + + /* Is there an issuerUniqueID? */ + if (cert->issuerID.data) { + /* The issuerID is encoded as a bit string. + * The function ProcessRawBytes expects the + * length to be in bytes, so let's convert the + * length in a temporary SECItem + */ + data.data = cert->issuerID.data; + data.len = cert->issuerID.len / 8; + + subitem = e_asn1_object_new (); + + e_asn1_object_set_display_name (subitem, _("Issuer Unique ID")); + process_raw_bytes (&data, &text); + e_asn1_object_set_display_value (subitem, text); + g_free (text); - parent->priv->children = g_list_append (parent->priv->children, asn1object); + e_asn1_object_append_child (sequence, subitem); } + if (cert->subjectID.data) { + /* The subjectID is encoded as a bit string. + * The function ProcessRawBytes expects the + * length to be in bytes, so let's convert the + * length in a temporary SECItem + */ + data.data = cert->issuerID.data; + data.len = cert->issuerID.len / 8; + + subitem = e_asn1_object_new (); + + e_asn1_object_set_display_name (subitem, _("Subject Unique ID")); + process_raw_bytes (&data, &text); + e_asn1_object_set_display_value (subitem, text); + g_free (text); + + e_asn1_object_append_child (sequence, subitem); + } + if (cert->extensions) { + if (!process_extensions (cert->extensions, sequence)) + return FALSE; + } + + *seq = sequence; + return TRUE; } -EASN1Object * -e_asn1_object_new_from_der (gchar *data, - guint32 len) +static gboolean +fill_asn1_from_cert (EASN1Object *asn1, + CERTCertificate *cert) { - EASN1Object *obj = g_object_new (E_TYPE_ASN1_OBJECT, NULL); + EASN1Object *sequence; + SECItem temp; + gchar *text; - if (!build_from_der (obj, data, data + len)) { - g_object_unref (obj); - return NULL; + g_return_val_if_fail (asn1 != NULL, FALSE); + g_return_val_if_fail (cert != NULL, FALSE); + + if (cert->nickname) { + e_asn1_object_set_display_name (asn1, cert->nickname); + } else { + gchar *str; + + str = CERT_GetCommonName (&cert->subject); + if (str) { + e_asn1_object_set_display_name (asn1, str); + PORT_Free (str); + } else { + e_asn1_object_set_display_name (asn1, cert->subjectName); + } } - return obj; + /* This sequence will be contain the tbsCertificate, signatureAlgorithm, + * and signatureValue. */ + + if (!create_tbs_certificate_asn1_struct (cert, &sequence)) + return FALSE; + e_asn1_object_append_child (asn1, sequence); + g_object_unref (sequence); + + if (!process_sec_algorithm_id (&cert->signatureWrap.signatureAlgorithm, &sequence)) + return FALSE; + e_asn1_object_set_display_name ( + sequence, _("Certificate Signature Algorithm")); + e_asn1_object_append_child (asn1, sequence); + g_object_unref (sequence); + + sequence = e_asn1_object_new (); + e_asn1_object_set_display_name ( + sequence, _("Certificate Signature Value")); + + /* The signatureWrap is encoded as a bit string. + * The function ProcessRawBytes expects the + * length to be in bytes, so let's convert the + * length in a temporary SECItem */ + temp.data = cert->signatureWrap.signature.data; + temp.len = cert->signatureWrap.signature.len / 8; + process_raw_bytes (&temp, &text); + e_asn1_object_set_display_value (sequence, text); + e_asn1_object_append_child (asn1, sequence); + g_free (text); + + return TRUE; +} + +static void +e_asn1_object_finalize (GObject *object) +{ + EASN1ObjectPrivate *priv; + + priv = E_ASN1_OBJECT_GET_PRIVATE (object); + + g_free (priv->display_name); + g_free (priv->value); + + g_list_free_full (priv->children, (GDestroyNotify) g_object_unref); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_asn1_object_parent_class)->finalize (object); +} + +static void +e_asn1_object_class_init (EASN1ObjectClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EASN1ObjectPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = e_asn1_object_finalize; +} + +static void +e_asn1_object_init (EASN1Object *asn1) +{ + asn1->priv = E_ASN1_OBJECT_GET_PRIVATE (asn1); + + asn1->priv->valid_container = TRUE; } EASN1Object * @@ -289,6 +867,22 @@ e_asn1_object_new (void) return E_ASN1_OBJECT (g_object_new (E_TYPE_ASN1_OBJECT, NULL)); } +EASN1Object * +e_asn1_object_new_from_cert (CERTCertificate *cert) +{ + EASN1Object *asn1; + + g_return_val_if_fail (cert != NULL, NULL); + + asn1 = e_asn1_object_new (); + if (!fill_asn1_from_cert (asn1, cert)) { + g_object_unref (asn1); + return NULL; + } + + return asn1; +} + void e_asn1_object_set_valid_container (EASN1Object *obj, gboolean flag) diff --git a/smime/lib/e-asn1-object.h b/smime/lib/e-asn1-object.h index 35824967d4..39b79a7b1e 100644 --- a/smime/lib/e-asn1-object.h +++ b/smime/lib/e-asn1-object.h @@ -1,5 +1,4 @@ /* - * * 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 @@ -18,15 +17,14 @@ * Chris Toshok <toshok@ximian.com> * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * */ -#ifndef _E_ASN1_OBJECT_H_ -#define _E_ASN1_OBJECT_H_ +#ifndef E_ASN1_OBJECT_H +#define E_ASN1_OBJECT_H #include <glib-object.h> -#include <nspr.h> +#include <cert.h> #define E_TYPE_ASN1_OBJECT (e_asn1_object_get_type ()) #define E_ASN1_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ASN1_OBJECT, EASN1Object)) @@ -85,22 +83,27 @@ struct _EASN1ObjectClass { void (*_ecert_reserved4) (void); }; -EASN1Object *e_asn1_object_new_from_der (gchar *data, guint32 len); -EASN1Object *e_asn1_object_new (void); - -void e_asn1_object_set_valid_container (EASN1Object *obj, gboolean flag); -gboolean e_asn1_object_is_valid_container (EASN1Object *obj); -PRUint32 e_asn1_object_get_asn1_type (EASN1Object *obj); -PRUint32 e_asn1_object_get_asn1_tag (EASN1Object *obj); -GList *e_asn1_object_get_children (EASN1Object *obj); -void e_asn1_object_append_child (EASN1Object *parent, EASN1Object *child); -void e_asn1_object_set_display_name (EASN1Object *obj, const gchar *name); -const gchar *e_asn1_object_get_display_name (EASN1Object *obj); -void e_asn1_object_set_display_value (EASN1Object *obj, const gchar *value); -const gchar *e_asn1_object_get_display_value (EASN1Object *obj); +GType e_asn1_object_get_type (void); +EASN1Object * e_asn1_object_new (void); +EASN1Object * e_asn1_object_new_from_cert (CERTCertificate *cert); -void e_asn1_object_get_data (EASN1Object *obj, gchar **data, guint32 *len); +void e_asn1_object_set_valid_container (EASN1Object *obj, + gboolean flag); +gboolean e_asn1_object_is_valid_container (EASN1Object *obj); +PRUint32 e_asn1_object_get_asn1_type (EASN1Object *obj); +PRUint32 e_asn1_object_get_asn1_tag (EASN1Object *obj); +GList * e_asn1_object_get_children (EASN1Object *obj); +void e_asn1_object_append_child (EASN1Object *parent, + EASN1Object *child); +void e_asn1_object_set_display_name (EASN1Object *obj, + const gchar *name); +const gchar * e_asn1_object_get_display_name (EASN1Object *obj); +void e_asn1_object_set_display_value (EASN1Object *obj, + const gchar *value); +const gchar * e_asn1_object_get_display_value (EASN1Object *obj); -GType e_asn1_object_get_type (void); +void e_asn1_object_get_data (EASN1Object *obj, + gchar **data, + guint32 *len); -#endif /* _E_ASN1_OBJECT_H_ */ +#endif /* E_ASN1_OBJECT_H */ diff --git a/smime/lib/e-cert.c b/smime/lib/e-cert.c index cd92062779..969b43c9ed 100644 --- a/smime/lib/e-cert.c +++ b/smime/lib/e-cert.c @@ -435,18 +435,14 @@ e_cert_get_md5_fingerprint (ECert *cert) } GList * -e_cert_get_chain (ECert *ecert) +e_cert_get_issuers_chain (ECert *ecert) { - GList *l = NULL; - - g_object_ref (ecert); + GList *issuers = NULL; while (ecert) { CERTCertificate *cert = e_cert_get_internal_cert (ecert); CERTCertificate *next_cert; - l = g_list_append (l, ecert); - if (SECITEM_CompareItem (&cert->derIssuer, &cert->derSubject) == SECEqual) break; @@ -456,9 +452,14 @@ e_cert_get_chain (ECert *ecert) /* next_cert has a reference already */ ecert = e_cert_new (next_cert); + + if (ecert) { + /* the first is issuer of the original ecert */ + issuers = g_list_append (issuers, ecert); + } } - return l; + return issuers; } ECert * @@ -482,760 +483,16 @@ e_cert_get_ca_cert (ECert *ecert) return e_cert_new (cert); } -static gboolean -get_int_value (SECItem *versionItem, - gulong *version) -{ - SECStatus srv; - srv = SEC_ASN1DecodeInteger (versionItem,version); - if (srv != SECSuccess) { - g_warning ("could not decode version of cert"); - return FALSE; - } - return TRUE; -} - -static gboolean -process_version (SECItem *versionItem, - EASN1Object **retItem) -{ - EASN1Object *item = e_asn1_object_new (); - gulong version; - - e_asn1_object_set_display_name (item, _("Version")); - - /* Now to figure out what version this certificate is. */ - - if (versionItem->data) { - if (!get_int_value (versionItem, &version)) - return FALSE; - } else { - /* If there is no version present in the cert, then rfc2459 - * says we default to v1 (0) */ - version = 0; - } - - switch (version) { - case 0: - e_asn1_object_set_display_value (item, _("Version 1")); - break; - case 1: - e_asn1_object_set_display_value (item, _("Version 2")); - break; - case 2: - e_asn1_object_set_display_value (item, _("Version 3")); - break; - default: - g_warning ("Bad value for cert version"); - return FALSE; - } - - *retItem = item; - return TRUE; -} - -static gboolean -process_serial_number_der (SECItem *serialItem, - EASN1Object **retItem) -{ - gchar *serialNumber; - EASN1Object *item = e_asn1_object_new (); - - e_asn1_object_set_display_name (item, _("Serial Number")); - - serialNumber = CERT_Hexify (serialItem, 1); - - e_asn1_object_set_display_value (item, serialNumber); - PORT_Free (serialNumber); /* XXX the right free to use? */ - - *retItem = item; - return TRUE; -} - -static gboolean -get_default_oid_format (SECItem *oid, - gchar **text) -{ - gchar buf[300]; - guint len; - gint written; - - gulong val = oid->data[0]; - guint i = val % 40; - val /= 40; - written = PR_snprintf (buf, 300, "%lu %u ", val, i); - if (written < 0) - return FALSE; - len = written; - - val = 0; - for (i = 1; i < oid->len; ++i) { - /* In this loop, we have to parse a DER formatted - * If the first bit is a 1, then the integer is - * represented by more than one byte. If the - * first bit is set then we continue on and add - * the values of the later bytes until we get - * a byte without the first bit set. - */ - gulong j; - - j = oid->data[i]; - val = (val << 7) | (j & 0x7f); - if (j & 0x80) - continue; - written = PR_snprintf (&buf[len], sizeof (buf) - len, "%lu ", val); - if (written < 0) - return FALSE; - - len += written; - if (len >= sizeof (buf)) - g_warning ("OID data to big to display in 300 chars."); - val = 0; - } - - *text = g_strdup (buf); - return TRUE; -} - -static gboolean -get_oid_text (SECItem *oid, - gchar **text) -{ - SECOidTag oidTag = SECOID_FindOIDTag (oid); - gchar *temp; - - switch (oidTag) { - case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 MD2 With RSA Encryption")); - break; - case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 MD5 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-1 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-256 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-384 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-512 With RSA Encryption")); - break; - case SEC_OID_AVA_COUNTRY_NAME: - *text = g_strdup ("C"); - break; - case SEC_OID_AVA_COMMON_NAME: - *text = g_strdup ("CN"); - break; - case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: - *text = g_strdup ("OU"); - break; - case SEC_OID_AVA_ORGANIZATION_NAME: - *text = g_strdup ("O"); - break; - case SEC_OID_AVA_LOCALITY: - *text = g_strdup ("L"); - break; - case SEC_OID_AVA_DN_QUALIFIER: - *text = g_strdup ("DN"); - break; - case SEC_OID_AVA_DC: - *text = g_strdup ("DC"); - break; - case SEC_OID_AVA_STATE_OR_PROVINCE: - *text = g_strdup ("ST"); - break; - case SEC_OID_PKCS1_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 RSA Encryption")); - break; - case SEC_OID_X509_KEY_USAGE: - *text = g_strdup (_("Certificate Key Usage")); - break; - case SEC_OID_NS_CERT_EXT_CERT_TYPE: - *text = g_strdup (_("Netscape Certificate Type")); - break; - case SEC_OID_X509_AUTH_KEY_ID: - *text = g_strdup (_("Certificate Authority Key Identifier")); - break; - case SEC_OID_RFC1274_UID: - *text = g_strdup ("UID"); - break; - case SEC_OID_PKCS9_EMAIL_ADDRESS: - *text = g_strdup ("E"); - break; - default: - if (!get_default_oid_format (oid, &temp)) - return FALSE; - - *text = g_strdup_printf (_("Object Identifier (%s)"), temp); - g_free (temp); - - break; - } - return TRUE; -} - -static gboolean -process_raw_bytes (SECItem *data, - gchar **text) -{ - /* This function is used to display some DER bytes - * that we have not added support for decoding. - * It prints the value of the byte out into a - * string that can later be displayed as a byte - * string. We place a new line after 24 bytes - * to break up extermaly long sequence of bytes. - */ - GString *str = g_string_new (""); - PRUint32 i; - gchar buffer[5]; - for (i = 0; i < data->len; i++) { - PR_snprintf (buffer, 5, "%02x ", data->data[i]); - g_string_append (str, buffer); - if ((i + 1) % 16 == 0) { - g_string_append (str, "\n"); - } - } - *text = g_string_free (str, FALSE); - return TRUE; -} - -static gboolean -process_sec_algorithm_id (SECAlgorithmID *algID, - EASN1Object **retSequence) -{ - EASN1Object *sequence = e_asn1_object_new (); - gchar *text; - - *retSequence = NULL; - - get_oid_text (&algID->algorithm, &text); - - if (!algID->parameters.len || - algID->parameters.data[0] == E_ASN1_OBJECT_TYPE_NULL) { - e_asn1_object_set_display_value (sequence, text); - e_asn1_object_set_valid_container (sequence, FALSE); - } else { - EASN1Object *subitem; - - subitem = e_asn1_object_new (); - e_asn1_object_set_display_name (subitem, _("Algorithm Identifier")); - e_asn1_object_set_display_value (subitem, text); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - g_free (text); - - subitem = e_asn1_object_new (); - e_asn1_object_set_display_name (subitem, _("Algorithm Parameters")); - process_raw_bytes (&algID->parameters, &text); - e_asn1_object_set_display_value (subitem, text); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - } - - g_free (text); - *retSequence = sequence; - return TRUE; -} - -static gboolean -process_subject_public_key_info (CERTSubjectPublicKeyInfo *spki, - EASN1Object *parentSequence) -{ - EASN1Object *spkiSequence = e_asn1_object_new (); - EASN1Object *sequenceItem; - EASN1Object *printableItem; - SECItem data; - gchar *text; - - e_asn1_object_set_display_name (spkiSequence, _("Subject Public Key Info")); - - if (!process_sec_algorithm_id (&spki->algorithm, &sequenceItem)) - return FALSE; - - e_asn1_object_set_display_name (sequenceItem, _("Subject Public Key Algorithm")); - - e_asn1_object_append_child (spkiSequence, sequenceItem); - - /* The subjectPublicKey field is encoded as a bit string. - * ProcessRawBytes expects the lenght to be in bytes, so - * let's convert the lenght into a temporary SECItem. - */ - data.data = spki->subjectPublicKey.data; - data.len = spki->subjectPublicKey.len / 8; - - process_raw_bytes (&data, &text); - printableItem = e_asn1_object_new (); - - e_asn1_object_set_display_value (printableItem, text); - e_asn1_object_set_display_name (printableItem, _("Subject's Public Key")); - e_asn1_object_append_child (spkiSequence, printableItem); - g_object_unref (printableItem); - - e_asn1_object_append_child (parentSequence, spkiSequence); - g_object_unref (spkiSequence); - - return TRUE; -} - -static gboolean -process_ns_cert_type_extensions (SECItem *extData, - GString *text) -{ - SECItem decoded; - guchar nsCertType; - - decoded.data = NULL; - decoded.len = 0; - if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, - SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { - g_string_append (text, _("Error: Unable to process extension")); - return TRUE; - } - - nsCertType = decoded.data[0]; - - PORT_Free (decoded.data); /* XXX right free? */ - - if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) { - g_string_append (text, _("SSL Client Certificate")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_SSL_SERVER) { - g_string_append (text, _("SSL Server Certificate")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_EMAIL) { - g_string_append (text, _("Email")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) { - g_string_append (text, _("Object Signer")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_SSL_CA) { - g_string_append (text, _("SSL Certificate Authority")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_EMAIL_CA) { - g_string_append (text, _("Email Certificate Authority")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) { - g_string_append (text, _("Object Signer")); - g_string_append (text, "\n"); - } - return TRUE; -} - -static gboolean -process_key_usage_extensions (SECItem *extData, - GString *text) -{ - SECItem decoded; - guchar keyUsage; - - decoded.data = NULL; - decoded.len = 0; - if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, - SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { - g_string_append (text, _("Error: Unable to process extension")); - return TRUE; - } - - keyUsage = decoded.data[0]; - PORT_Free (decoded.data); /* XXX right free? */ - - if (keyUsage & KU_DIGITAL_SIGNATURE) { - g_string_append (text, _("Signing")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_NON_REPUDIATION) { - g_string_append (text, _("Non-repudiation")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_KEY_ENCIPHERMENT) { - g_string_append (text, _("Key Encipherment")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_DATA_ENCIPHERMENT) { - g_string_append (text, _("Data Encipherment")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_KEY_AGREEMENT) { - g_string_append (text, _("Key Agreement")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_KEY_CERT_SIGN) { - g_string_append (text, _("Certificate Signer")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_CRL_SIGN) { - g_string_append (text, _("CRL Signer")); - g_string_append (text, "\n"); - } - - return TRUE; -} - -static gboolean -process_extension_data (SECOidTag oidTag, - SECItem *extData, - GString *str) -{ - gboolean rv; - switch (oidTag) { - case SEC_OID_NS_CERT_EXT_CERT_TYPE: - rv = process_ns_cert_type_extensions (extData, str); - break; - case SEC_OID_X509_KEY_USAGE: - rv = process_key_usage_extensions (extData, str); - break; - default: { - gchar *text; - rv = process_raw_bytes (extData, &text); - g_string_append (str, text); - g_free (text); - break; - } - } - return rv; -} - -static gboolean -process_single_extension (CERTCertExtension *extension, - EASN1Object **retExtension) -{ - GString *str = g_string_new (""); - gchar *text; - EASN1Object *extensionItem; - SECOidTag oidTag = SECOID_FindOIDTag (&extension->id); - - get_oid_text (&extension->id, &text); - - extensionItem = e_asn1_object_new (); - - e_asn1_object_set_display_name (extensionItem, text); - g_free (text); - - if (extension->critical.data != NULL) { - if (extension->critical.data[0]) { - g_string_append (str, _("Critical")); - } else { - g_string_append (str, _("Not Critical")); - } - } else { - g_string_append (str, _("Not Critical")); - } - g_string_append (str, "\n"); - if (!process_extension_data (oidTag, &extension->value, str)) { - g_string_free (str, TRUE); - return FALSE; - } - - e_asn1_object_set_display_value (extensionItem, str->str); - g_string_free (str, TRUE); - *retExtension = extensionItem; - return TRUE; -} - -static gboolean -process_extensions (CERTCertExtension **extensions, - EASN1Object *parentSequence) -{ - EASN1Object *extensionSequence = e_asn1_object_new (); - PRInt32 i; - - e_asn1_object_set_display_name (extensionSequence, _("Extensions")); - - for (i = 0; extensions[i] != NULL; i++) { - EASN1Object *newExtension; - - if (!process_single_extension (extensions[i], - &newExtension)) - return FALSE; - - e_asn1_object_append_child (extensionSequence, newExtension); - } - e_asn1_object_append_child (parentSequence, extensionSequence); - return TRUE; -} - -static gboolean -process_name (CERTName *name, - gchar **value) -{ - CERTRDN ** rdns; - CERTRDN ** rdn; - CERTAVA ** avas; - CERTAVA * ava; - SECItem *decodeItem = NULL; - GString *final_string = g_string_new (""); - - gchar *type; - GString *avavalue; - gchar *temp; - CERTRDN **lastRdn; - - rdns = name->rdns; - - /* find last RDN */ - lastRdn = rdns; - while (*lastRdn) lastRdn++; - - /* The above whille loop will put us at the last member - * of the array which is a NULL pointer. So let's back - * up one spot so that we have the last non-NULL entry in - * the array in preparation for traversing the - * RDN's (Relative Distinguished Name) in reverse order. - */ - lastRdn--; - - /* - * Loop over name contents in _reverse_ RDN order appending to string - * When building the Ascii string, NSS loops over these entries in - * reverse order, so I will as well. The difference is that NSS - * will always place them in a one line string separated by commas, - * where I want each entry on a single line. I can't just use a comma - * as my delimitter because it is a valid character to have in the - * value portion of the AVA and could cause trouble when parsing. - */ - for (rdn = lastRdn; rdn >= rdns; rdn--) { - avas = (*rdn)->avas; - while ((ava = *avas++) != 0) { - if (!get_oid_text (&ava->type, &type)) - return FALSE; - - /* This function returns a string in UTF8 format. */ - decodeItem = CERT_DecodeAVAValue (&ava->value); - if (!decodeItem) { - return FALSE; - } - - avavalue = g_string_new_len ( - (gchar *) decodeItem->data, decodeItem->len); - - SECITEM_FreeItem (decodeItem, PR_TRUE); - - /* Translators: This string is used in Certificate - * details for fields like Issuer or Subject, which - * shows the field name on the left and its respective - * value on the right, both as stored in the - * certificate itself. You probably do not need to - * change this string, unless changing the order of - * name and value. As a result example: - * "OU = VeriSign Trust Network" */ - temp = g_strdup_printf (_("%s = %s"), type, avavalue->str); - - g_string_append (final_string, temp); - g_string_append (final_string, "\n"); - g_string_free (avavalue, TRUE); - g_free (temp); - } - } - *value = g_string_free (final_string, FALSE); - return TRUE; -} - -static gboolean -create_tbs_certificate_asn1_struct (ECert *cert, - EASN1Object **seq) -{ - /* - ** TBSCertificate ::= SEQUENCE { - ** version [0] EXPLICIT Version DEFAULT v1, - ** serialNumber CertificateSerialNumber, - ** signature AlgorithmIdentifier, - ** issuer Name, - ** validity Validity, - ** subject Name, - ** subjectPublicKeyInfo SubjectPublicKeyInfo, - ** issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - ** -- If present, version shall be v2 or v3 - ** subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - ** -- If present, version shall be v2 or v3 - ** extensions [3] EXPLICIT Extensions OPTIONAL - ** -- If present, version shall be v3 - ** } - ** - ** This is the ASN1 structure we should be dealing with at this point. - ** The code in this method will assert this is the structure we're dealing - ** and then add more user friendly text for that field. - */ - EASN1Object *sequence = e_asn1_object_new (); - gchar *text; - EASN1Object *subitem; - SECItem data; - - e_asn1_object_set_display_name (sequence, _("Certificate")); - - if (!process_version (&cert->priv->cert->version, &subitem)) - return FALSE; - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - if (!process_serial_number_der (&cert->priv->cert->serialNumber, &subitem)) - return FALSE; - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - if (!process_sec_algorithm_id (&cert->priv->cert->signature, &subitem)) - return FALSE; - e_asn1_object_set_display_name (subitem, _("Certificate Signature Algorithm")); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - process_name (&cert->priv->cert->issuer, &text); - subitem = e_asn1_object_new (); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - - e_asn1_object_set_display_name (subitem, _("Issuer")); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - -#ifdef notyet - nsCOMPtr < nsIASN1Sequence> validitySequence = new nsNSSASN1Sequence (); - nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpValidity").get (), - text); - validitySequence->SetDisplayName (text); - asn1Objects->AppendElement (validitySequence, PR_FALSE); - nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotBefore").get (), - text); - nsCOMPtr < nsIX509CertValidity> validityData; - GetValidity (getter_AddRefs (validityData)); - PRTime notBefore, notAfter; - - validityData->GetNotBefore (¬Before); - validityData->GetNotAfter (¬After); - validityData = 0; - rv = ProcessTime (notBefore, text.get (), validitySequence); - if (NS_FAILED (rv)) - return rv; - - nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotAfter").get (), - text); - rv = ProcessTime (notAfter, text.get (), validitySequence); - if (NS_FAILED (rv)) - return rv; -#endif - - subitem = e_asn1_object_new (); - e_asn1_object_set_display_name (subitem, _("Subject")); - - process_name (&cert->priv->cert->subject, &text); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - if (!process_subject_public_key_info ( - &cert->priv->cert->subjectPublicKeyInfo, sequence)) - return FALSE; - - /* Is there an issuerUniqueID? */ - if (cert->priv->cert->issuerID.data) { - /* The issuerID is encoded as a bit string. - * The function ProcessRawBytes expects the - * length to be in bytes, so let's convert the - * length in a temporary SECItem - */ - data.data = cert->priv->cert->issuerID.data; - data.len = cert->priv->cert->issuerID.len / 8; - - subitem = e_asn1_object_new (); - - e_asn1_object_set_display_name (subitem, _("Issuer Unique ID")); - process_raw_bytes (&data, &text); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - - e_asn1_object_append_child (sequence, subitem); - } - - if (cert->priv->cert->subjectID.data) { - /* The subjectID is encoded as a bit string. - * The function ProcessRawBytes expects the - * length to be in bytes, so let's convert the - * length in a temporary SECItem - */ - data.data = cert->priv->cert->issuerID.data; - data.len = cert->priv->cert->issuerID.len / 8; - - subitem = e_asn1_object_new (); - - e_asn1_object_set_display_name (subitem, _("Subject Unique ID")); - process_raw_bytes (&data, &text); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - - e_asn1_object_append_child (sequence, subitem); - } - if (cert->priv->cert->extensions) { - if (!process_extensions (cert->priv->cert->extensions, sequence)) - return FALSE; - } - - *seq = sequence; - - return TRUE; -} - -static gboolean -create_asn1_struct (ECert *cert) -{ - EASN1Object *sequence; - SECItem temp; - gchar *text; - - cert->priv->asn1 = e_asn1_object_new (); - - e_asn1_object_set_display_name (cert->priv->asn1, e_cert_get_window_title (cert)); - - /* This sequence will be contain the tbsCertificate, signatureAlgorithm, - * and signatureValue. */ - - if (!create_tbs_certificate_asn1_struct (cert, &sequence)) - return FALSE; - e_asn1_object_append_child (cert->priv->asn1, sequence); - g_object_unref (sequence); - - if (!process_sec_algorithm_id ( - &cert->priv->cert->signatureWrap.signatureAlgorithm, &sequence)) - return FALSE; - e_asn1_object_set_display_name ( - sequence, _("Certificate Signature Algorithm")); - e_asn1_object_append_child (cert->priv->asn1, sequence); - g_object_unref (sequence); - - sequence = e_asn1_object_new (); - e_asn1_object_set_display_name ( - sequence, _("Certificate Signature Value")); - - /* The signatureWrap is encoded as a bit string. - * The function ProcessRawBytes expects the - * length to be in bytes, so let's convert the - * length in a temporary SECItem */ - temp.data = cert->priv->cert->signatureWrap.signature.data; - temp.len = cert->priv->cert->signatureWrap.signature.len / 8; - process_raw_bytes (&temp, &text); - e_asn1_object_set_display_value (sequence, text); - e_asn1_object_append_child (cert->priv->asn1, sequence); - g_free (text); - - return TRUE; -} - EASN1Object * e_cert_get_asn1_struct (ECert *cert) { if (!cert->priv->asn1) - create_asn1_struct (cert); + cert->priv->asn1 = e_asn1_object_new_from_cert (cert->priv->cert); + + if (cert->priv->asn1) + return g_object_ref (cert->priv->asn1); - return g_object_ref (cert->priv->asn1); + return NULL; } gboolean diff --git a/smime/lib/e-cert.h b/smime/lib/e-cert.h index 4159c40cb9..0096336741 100644 --- a/smime/lib/e-cert.h +++ b/smime/lib/e-cert.h @@ -95,7 +95,7 @@ const gchar * e_cert_get_serial_number (ECert *cert); const gchar * e_cert_get_sha1_fingerprint (ECert *cert); const gchar * e_cert_get_md5_fingerprint (ECert *cert); -GList * e_cert_get_chain (ECert *cert); +GList * e_cert_get_issuers_chain (ECert *cert); ECert * e_cert_get_ca_cert (ECert *ecert); EASN1Object * e_cert_get_asn1_struct (ECert *cert); |