aboutsummaryrefslogtreecommitdiffstats
path: root/smime
diff options
context:
space:
mode:
Diffstat (limited to 'smime')
-rw-r--r--smime/Makefile.am3
-rw-r--r--smime/gui/Makefile.am54
-rw-r--r--smime/gui/ca-trust-dialog.c154
-rw-r--r--smime/gui/ca-trust-dialog.h35
-rw-r--r--smime/gui/cert-trust-dialog.c162
-rw-r--r--smime/gui/cert-trust-dialog.h35
-rw-r--r--smime/gui/certificate-manager.c1139
-rw-r--r--smime/gui/certificate-manager.h73
-rw-r--r--smime/gui/certificate-viewer.c688
-rw-r--r--smime/gui/certificate-viewer.h32
-rw-r--r--smime/gui/component.c141
-rw-r--r--smime/gui/component.h28
-rw-r--r--smime/gui/e-cert-selector.c277
-rw-r--r--smime/gui/e-cert-selector.h76
-rw-r--r--smime/gui/smime-ui.ui799
-rw-r--r--smime/lib/Makefile.am41
-rw-r--r--smime/lib/e-asn1-object.c964
-rw-r--r--smime/lib/e-asn1-object.h109
-rw-r--r--smime/lib/e-cert-db.c1521
-rw-r--r--smime/lib/e-cert-db.h148
-rw-r--r--smime/lib/e-cert-trust.c471
-rw-r--r--smime/lib/e-cert-trust.h87
-rw-r--r--smime/lib/e-cert.c542
-rw-r--r--smime/lib/e-cert.h106
-rw-r--r--smime/lib/e-pkcs12.c371
-rw-r--r--smime/lib/e-pkcs12.h68
-rw-r--r--smime/tests/Makefile.am20
-rw-r--r--smime/tests/import-cert.c57
28 files changed, 8201 insertions, 0 deletions
diff --git a/smime/Makefile.am b/smime/Makefile.am
new file mode 100644
index 0000000000..a358fdf7ea
--- /dev/null
+++ b/smime/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = lib gui
+
+-include $(top_srcdir)/git.mk
diff --git a/smime/gui/Makefile.am b/smime/gui/Makefile.am
new file mode 100644
index 0000000000..09c9fa8924
--- /dev/null
+++ b/smime/gui/Makefile.am
@@ -0,0 +1,54 @@
+privsolib_LTLIBRARIES = libevolution-smime.la
+
+libevolution_smime_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DG_LOG_DOMAIN=\"evolution-smime\" \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/smime/lib \
+ -I$(top_builddir)/smime/lib \
+ -I$(top_srcdir)/shell \
+ -I$(top_builddir)/shell \
+ -DEVOLUTION_DATADIR=\""$(datadir)"\" \
+ -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
+ -DEVOLUTION_LOCALEDIR=\""$(localedir)"\" \
+ -DEVOLUTION_UIDIR=\""$(uidir)"\" \
+ -DPREFIX=\""$(prefix)"\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(GTKHTML_CFLAGS) \
+ $(CERT_UI_CFLAGS)
+
+libevolution_smime_la_SOURCES = \
+ ca-trust-dialog.c \
+ ca-trust-dialog.h \
+ cert-trust-dialog.c \
+ cert-trust-dialog.h \
+ certificate-manager.c \
+ certificate-manager.h \
+ certificate-viewer.c \
+ certificate-viewer.h \
+ e-cert-selector.c \
+ e-cert-selector.h \
+ component.c \
+ component.h
+
+
+libevolution_smime_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(top_builddir)/shell/libevolution-shell.la \
+ $(top_builddir)/smime/lib/libessmime.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(GTKHTML_LIBS) \
+ $(CERT_UI_LIBS)
+
+libevolution_smime_la_LDFLAGS = -avoid-version $(NO_UNDEFINED)
+
+ui_DATA = smime-ui.ui
+
+EXTRA_DIST = \
+ $(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/smime/gui/ca-trust-dialog.c b/smime/gui/ca-trust-dialog.c
new file mode 100644
index 0000000000..332b92bcd1
--- /dev/null
+++ b/smime/gui/ca-trust-dialog.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ca-trust-dialog.h"
+#include "certificate-manager.h"
+
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+
+typedef struct {
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GtkWidget *ssl_checkbutton;
+ GtkWidget *email_checkbutton;
+ GtkWidget *objsign_checkbutton;
+
+ ECert *cert;
+} CATrustDialogData;
+
+static void
+free_data (gpointer data)
+{
+ CATrustDialogData *ctd = data;
+
+ g_object_unref (ctd->cert);
+ g_object_unref (ctd->builder);
+ g_free (ctd);
+}
+
+static void
+catd_response (GtkWidget *w,
+ guint id,
+ CATrustDialogData *data)
+{
+ switch (id) {
+ case GTK_RESPONSE_ACCEPT: {
+ GtkWidget *dialog;
+
+ dialog = e_cert_manager_new_certificate_viewer (GTK_WINDOW (data->dialog), data->cert);
+
+ g_signal_stop_emission_by_name (w, "response");
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ break; }
+ }
+}
+
+GtkWidget *
+ca_trust_dialog_show (ECert *cert,
+ gboolean importing)
+{
+ CATrustDialogData *ctd_data;
+ GtkDialog *dialog;
+ GtkWidget *action_area;
+ GtkWidget *content_area;
+ GtkWidget *w;
+ gchar *txt;
+
+ ctd_data = g_new0 (CATrustDialogData, 1);
+
+ ctd_data->builder = gtk_builder_new ();
+ e_load_ui_builder_definition (ctd_data->builder, "smime-ui.ui");
+
+ ctd_data->dialog = e_builder_get_widget (ctd_data->builder, "ca-trust-dialog");
+
+ gtk_widget_ensure_style (ctd_data->dialog);
+
+ dialog = GTK_DIALOG (ctd_data->dialog);
+ action_area = gtk_dialog_get_action_area (dialog);
+ content_area = gtk_dialog_get_content_area (dialog);
+
+ gtk_container_set_border_width (GTK_CONTAINER (action_area), 12);
+ gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
+
+ ctd_data->cert = g_object_ref (cert);
+
+ ctd_data->ssl_checkbutton = e_builder_get_widget (ctd_data->builder, "ssl_trust_checkbutton");
+ ctd_data->email_checkbutton = e_builder_get_widget (ctd_data->builder, "email_trust_checkbutton");
+ ctd_data->objsign_checkbutton = e_builder_get_widget (ctd_data->builder, "objsign_trust_checkbutton");
+
+ w = e_builder_get_widget (ctd_data->builder, "ca-trust-label");
+ txt = g_strdup_printf (_("Certificate '%s' is a CA certificate.\n\nEdit trust settings:"), e_cert_get_cn (cert));
+ gtk_label_set_text ((GtkLabel *) w, txt);
+ g_free (txt);
+
+ g_signal_connect (
+ ctd_data->dialog, "response",
+ G_CALLBACK (catd_response), ctd_data);
+
+ g_object_set_data_full (G_OBJECT (ctd_data->dialog), "CATrustDialogData", ctd_data, free_data);
+
+ return ctd_data->dialog;
+}
+
+void
+ca_trust_dialog_set_trust (GtkWidget *widget,
+ gboolean ssl,
+ gboolean email,
+ gboolean objsign)
+{
+ CATrustDialogData *ctd_data;
+
+ ctd_data = g_object_get_data (G_OBJECT (widget), "CATrustDialogData");
+ if (!ctd_data)
+ return;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ctd_data->ssl_checkbutton), ssl);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ctd_data->email_checkbutton), email);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ctd_data->objsign_checkbutton), objsign);
+}
+
+void
+ca_trust_dialog_get_trust (GtkWidget *widget,
+ gboolean *ssl,
+ gboolean *email,
+ gboolean *objsign)
+{
+ CATrustDialogData *ctd_data;
+
+ ctd_data = g_object_get_data (G_OBJECT (widget), "CATrustDialogData");
+ if (!ctd_data)
+ return;
+
+ *ssl = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ctd_data->ssl_checkbutton));
+ *email = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ctd_data->email_checkbutton));
+ *objsign = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ctd_data->objsign_checkbutton));
+}
diff --git a/smime/gui/ca-trust-dialog.h b/smime/gui/ca-trust-dialog.h
new file mode 100644
index 0000000000..62b842d945
--- /dev/null
+++ b/smime/gui/ca-trust-dialog.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef CA_TRUST_DIALOG_H
+#define CA_TRUST_DIALOG_H
+
+#include <gtk/gtk.h>
+#include "e-cert.h"
+
+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 */
diff --git a/smime/gui/cert-trust-dialog.c b/smime/gui/cert-trust-dialog.c
new file mode 100644
index 0000000000..366a79748e
--- /dev/null
+++ b/smime/gui/cert-trust-dialog.c
@@ -0,0 +1,162 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cert.h"
+#include "e-cert-trust.h"
+#include "e-cert-db.h"
+#include "cert-trust-dialog.h"
+#include "ca-trust-dialog.h"
+
+#include <gtk/gtk.h>
+
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+
+typedef struct {
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GtkWidget *trust_button;
+ GtkWidget *notrust_button;
+ GtkWidget *label;
+
+ ECert *cert, *cacert;
+} CertTrustDialogData;
+
+static void
+free_data (gpointer data)
+{
+ CertTrustDialogData *ctd = data;
+
+ g_object_unref (ctd->cert);
+ g_object_unref (ctd->cacert);
+ g_object_unref (ctd->builder);
+ g_free (ctd);
+}
+
+static void
+ctd_response (GtkWidget *w,
+ guint id,
+ CertTrustDialogData *data)
+{
+ CERTCertTrust trust;
+ CERTCertificate *icert;
+
+ switch (id) {
+ case GTK_RESPONSE_OK:
+ icert = e_cert_get_internal_cert (data->cert);
+ e_cert_trust_init (&trust);
+ e_cert_trust_set_valid_peer (&trust);
+ e_cert_trust_add_peer_trust (
+ &trust, FALSE,
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->trust_button)),
+ FALSE);
+ e_cert_db_change_cert_trust (icert, &trust);
+ break;
+ case GTK_RESPONSE_ACCEPT: {
+ /* just *what on earth* was chris thinking here!?!?! copied from certificate-manager.c */
+ GtkWidget *dialog = ca_trust_dialog_show (data->cacert, FALSE);
+ /* *icert is already declared earlier in this function? */
+ CERTCertificate *icert = e_cert_get_internal_cert (data->cacert);
+
+ g_signal_stop_emission_by_name (w, "response");
+
+ ca_trust_dialog_set_trust (
+ dialog,
+ e_cert_trust_has_trusted_ca (icert->trust, TRUE, FALSE, FALSE),
+ e_cert_trust_has_trusted_ca (icert->trust, FALSE, TRUE, FALSE),
+ e_cert_trust_has_trusted_ca (icert->trust, FALSE, FALSE, TRUE));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ gboolean trust_ssl, trust_email, trust_objsign;
+
+ ca_trust_dialog_get_trust (
+ dialog,
+ &trust_ssl, &trust_email, &trust_objsign);
+
+ e_cert_trust_init (&trust);
+ e_cert_trust_set_valid_ca (&trust);
+ e_cert_trust_add_ca_trust (
+ &trust,
+ trust_ssl,
+ trust_email,
+ trust_objsign);
+
+ e_cert_db_change_cert_trust (icert, &trust);
+ }
+
+ gtk_widget_destroy (dialog);
+ break; }
+ }
+}
+
+GtkWidget *
+cert_trust_dialog_show (ECert *cert)
+{
+ CertTrustDialogData *ctd_data;
+ CERTCertificate *icert;
+
+ ctd_data = g_new0 (CertTrustDialogData, 1);
+
+ ctd_data->builder = gtk_builder_new ();
+ e_load_ui_builder_definition (ctd_data->builder, "smime-ui.ui");
+
+ ctd_data->dialog = e_builder_get_widget (ctd_data->builder, "cert-trust-dialog");
+ ctd_data->cert = g_object_ref (cert);
+ ctd_data->cacert = e_cert_get_ca_cert (cert);
+ ctd_data->trust_button = e_builder_get_widget (ctd_data->builder, "cert-trust");
+ ctd_data->notrust_button = e_builder_get_widget (ctd_data->builder, "cert-notrust");
+
+ ctd_data->label = e_builder_get_widget (ctd_data->builder, "trust-label");
+
+ g_signal_connect (
+ ctd_data->dialog, "response",
+ G_CALLBACK (ctd_response), ctd_data);
+
+ g_object_set_data_full (G_OBJECT (ctd_data->dialog), "CertTrustDialogData", ctd_data, free_data);
+
+ icert = e_cert_get_internal_cert (cert);
+ if (e_cert_trust_has_trusted_peer (icert->trust, FALSE, TRUE, FALSE))
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ctd_data->trust_button), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ctd_data->notrust_button), TRUE);
+
+ icert = e_cert_get_internal_cert (ctd_data->cacert);
+ if (e_cert_trust_has_trusted_ca (icert->trust, FALSE, TRUE, FALSE))
+ gtk_label_set_text (
+ (GtkLabel *) ctd_data->label,
+ _("Because you trust the certificate authority that issued this certificate, "
+ "then you trust the authenticity of this certificate unless otherwise indicated here"));
+ else
+ gtk_label_set_text (
+ (GtkLabel *) ctd_data->label,
+ _("Because you do not trust the certificate authority that issued this certificate, "
+ "then you do not trust the authenticity of this certificate unless otherwise indicated here"));
+
+ return ctd_data->dialog;
+}
diff --git a/smime/gui/cert-trust-dialog.h b/smime/gui/cert-trust-dialog.h
new file mode 100644
index 0000000000..20a076b7e9
--- /dev/null
+++ b/smime/gui/cert-trust-dialog.h
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _CERT_TRUST_DIALOG_H_
+#define _CERT_TRUST_DIALOG_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+GtkWidget * cert_trust_dialog_show (ECert *cert);
+
+G_END_DECLS
+
+#endif /* _CERT_TRUST_DIALOG_H_ */
diff --git a/smime/gui/certificate-manager.c b/smime/gui/certificate-manager.c
new file mode 100644
index 0000000000..38645d2cdf
--- /dev/null
+++ b/smime/gui/certificate-manager.c
@@ -0,0 +1,1139 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#include <glib/gi18n.h>
+
+#include "ca-trust-dialog.h"
+#include "cert-trust-dialog.h"
+#include "certificate-manager.h"
+#include "certificate-viewer.h"
+
+#include "e-cert.h"
+#include "e-cert-trust.h"
+#include "e-cert-db.h"
+
+#include "nss.h"
+#include <cms.h>
+#include <cert.h>
+#include <certdb.h>
+#include <pkcs11.h>
+#include <pk11func.h>
+
+#include "shell/e-shell.h"
+
+#define E_CERT_MANAGER_CONFIG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CERT_MANAGER_CONFIG, ECertManagerConfigPrivate))
+
+G_DEFINE_TYPE (ECertManagerConfig, e_cert_manager_config, GTK_TYPE_BOX);
+
+enum {
+ PROP_0,
+ PROP_PREFERENCES_WINDOW
+};
+
+#define ECMC_TREE_VIEW(o) ecmc->priv->o->treeview
+#define PAGE_TREE_VIEW(o) o->treeview
+
+typedef struct {
+ GType type;
+ const gchar *column_title;
+ const gchar * (*get_cert_data_func) (ECert *cert); /* Prototype to e_cert_get_ * functions */
+ gboolean visible; /* Default visibility of column */
+} CertTreeColumn;
+
+static CertTreeColumn yourcerts_columns[] = {
+
+ { G_TYPE_STRING, N_("Certificate Name"), e_cert_get_cn, TRUE },
+ { G_TYPE_STRING, N_("Issued To Organization"), e_cert_get_org, FALSE },
+ { G_TYPE_STRING, N_("Issued To Organizational Unit"), e_cert_get_org_unit, FALSE },
+ { G_TYPE_STRING, N_("Serial Number"), e_cert_get_serial_number, TRUE },
+ { G_TYPE_STRING, N_("Purposes"), e_cert_get_usage, TRUE },
+ { G_TYPE_STRING, N_("Issued By"), e_cert_get_issuer_cn, TRUE },
+ { G_TYPE_STRING, N_("Issued By Organization"), e_cert_get_issuer_org, FALSE },
+ { G_TYPE_STRING, N_("Issued By Organizational Unit"), e_cert_get_issuer_org_unit, FALSE },
+ { G_TYPE_STRING, N_("Issued"), e_cert_get_issued_on, FALSE },
+ { G_TYPE_STRING, N_("Expires"), e_cert_get_expires_on, TRUE },
+ { G_TYPE_STRING, N_("SHA1 Fingerprint"), e_cert_get_sha1_fingerprint, FALSE },
+ { G_TYPE_STRING, N_("MD5 Fingerprint"), e_cert_get_md5_fingerprint, FALSE },
+ { G_TYPE_OBJECT, NULL, NULL, FALSE } /* Hidden column for ECert * object */
+
+};
+static const gchar * yourcerts_mime_types[] = { "application/x-x509-user-cert", "application/x-pkcs12", NULL };
+
+static CertTreeColumn contactcerts_columns[] = {
+
+ { G_TYPE_STRING, N_("Certificate Name"), e_cert_get_cn, TRUE },
+ { G_TYPE_STRING, N_("Email Address"), e_cert_get_email, TRUE },
+ { G_TYPE_STRING, N_("Issued To Organization"), e_cert_get_org, FALSE },
+ { G_TYPE_STRING, N_("Issued To Organizational Unit"), e_cert_get_org_unit, FALSE },
+ { G_TYPE_STRING, N_("Serial Number"), e_cert_get_serial_number, TRUE },
+ { G_TYPE_STRING, N_("Purposes"), e_cert_get_usage, TRUE },
+ { G_TYPE_STRING, N_("Issued By"), e_cert_get_issuer_cn, TRUE },
+ { G_TYPE_STRING, N_("Issued By Organization"), e_cert_get_issuer_org, FALSE },
+ { G_TYPE_STRING, N_("Issued By Organizational Unit"), e_cert_get_issuer_org_unit, FALSE },
+ { G_TYPE_STRING, N_("Issued"), e_cert_get_issued_on, FALSE },
+ { G_TYPE_STRING, N_("Expires"), e_cert_get_expires_on, TRUE },
+ { G_TYPE_STRING, N_("SHA1 Fingerprint"), e_cert_get_sha1_fingerprint, FALSE },
+ { G_TYPE_STRING, N_("MD5 Fingerprint"), e_cert_get_md5_fingerprint, FALSE },
+ { G_TYPE_OBJECT, NULL, NULL, FALSE }
+
+};
+static const gchar * contactcerts_mime_types[] = { "application/x-x509-email-cert", "application/x-x509-ca-cert", NULL };
+
+static CertTreeColumn authoritycerts_columns[] = {
+
+ { G_TYPE_STRING, N_("Certificate Name"), e_cert_get_cn, TRUE },
+ { G_TYPE_STRING, N_("Email Address"), e_cert_get_email, TRUE },
+ { G_TYPE_STRING, N_("Serial Number"), e_cert_get_serial_number, TRUE },
+ { G_TYPE_STRING, N_("Purposes"), e_cert_get_usage, TRUE },
+ { G_TYPE_STRING, N_("Issued By"), e_cert_get_issuer_cn, FALSE },
+ { G_TYPE_STRING, N_("Issued By Organization"), e_cert_get_issuer_org, FALSE },
+ { G_TYPE_STRING, N_("Issued By Organizational Unit"), e_cert_get_issuer_org_unit, FALSE },
+ { G_TYPE_STRING, N_("Issued"), e_cert_get_issued_on, FALSE },
+ { G_TYPE_STRING, N_("Expires"), e_cert_get_expires_on, TRUE },
+ { G_TYPE_STRING, N_("SHA1 Fingerprint"), e_cert_get_sha1_fingerprint, FALSE },
+ { G_TYPE_STRING, N_("MD5 Fingerprint"), e_cert_get_md5_fingerprint, FALSE },
+ { G_TYPE_OBJECT, NULL, NULL, FALSE }
+
+};
+static const gchar * authoritycerts_mime_types[] = { "application/x-x509-ca-cert", NULL };
+
+typedef struct {
+ GtkTreeView *treeview;
+ GtkTreeModel *streemodel;
+ GHashTable *root_hash;
+ GtkMenu *popup_menu;
+ GtkWidget *view_button;
+ GtkWidget *edit_button;
+ GtkWidget *backup_button;
+ GtkWidget *backup_all_button;
+ GtkWidget *import_button;
+ GtkWidget *delete_button;
+
+ CertTreeColumn *columns;
+ gint columns_count;
+
+ ECertType cert_type;
+ const gchar *cert_filter_name;
+ const gchar **cert_mime_types;
+} CertPage;
+
+struct _ECertManagerConfigPrivate {
+ GtkBuilder *builder;
+
+ EPreferencesWindow *pref_window;
+
+ CertPage *yourcerts_page;
+ CertPage *contactcerts_page;
+ CertPage *authoritycerts_page;
+};
+
+static void view_cert (GtkWidget *button, CertPage *cp);
+static void edit_cert (GtkWidget *button, CertPage *cp);
+static void delete_cert (GtkWidget *button, CertPage *cp);
+static void import_cert (GtkWidget *button, CertPage *cp);
+
+static void load_certs (CertPage *cp);
+static void unload_certs (CertPage *cp);
+
+static void
+save_treeview_state (GtkTreeView *treeview)
+{
+ GKeyFile *keyfile;
+ GtkTreeModel *model;
+ GtkTreeSortable *sortable;
+ GtkSortType sort_type;
+ gint columns_count;
+ gint i = 0;
+ gint *list;
+ gchar *cfg_file, *data;
+ const gchar *tree_name;
+
+ g_return_if_fail (treeview && GTK_IS_TREE_VIEW (treeview));
+
+ model = gtk_tree_view_get_model (treeview);
+ g_return_if_fail (model && GTK_IS_TREE_MODEL_SORT (model));
+
+ keyfile = g_key_file_new ();
+ cfg_file = g_build_filename (e_get_user_config_dir (), "cert_trees.ini", NULL);
+ g_key_file_load_from_file (keyfile, cfg_file, 0, NULL);
+
+ tree_name = gtk_widget_get_name (GTK_WIDGET (treeview));
+ sortable = GTK_TREE_SORTABLE (model);
+
+ columns_count = gtk_tree_model_get_n_columns (model) - 1; /* Ignore the last column - the ECert * holder */
+ list = g_new0 (gint, columns_count);
+
+ for (i = 0; i < columns_count; i++) {
+ GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
+ if (gtk_tree_view_column_get_visible (column)) {
+ list[gtk_tree_view_column_get_sort_column_id (column)] = gtk_tree_view_column_get_width (column);
+ } else {
+ list[gtk_tree_view_column_get_sort_column_id (column)] = 0;
+ }
+ }
+ g_key_file_set_integer_list (keyfile, tree_name, "columns", list, columns_count);
+ g_free (list);
+
+ list = g_new0 (gint, columns_count);
+ for (i = 0; i < columns_count; i++) {
+ GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
+ list[i] = gtk_tree_view_column_get_sort_column_id (column);
+ }
+ g_key_file_set_integer_list (keyfile, tree_name, "columns-order", list, columns_count);
+ g_free (list);
+
+ gtk_tree_sortable_get_sort_column_id (sortable, &i, &sort_type);
+ g_key_file_set_integer (keyfile, tree_name, "sort-column", i);
+
+ g_key_file_set_integer (keyfile, tree_name, "sort-order", sort_type);
+
+ data = g_key_file_to_data (keyfile, NULL, NULL);
+ g_file_set_contents (cfg_file, data, -1, NULL);
+
+ g_free (data);
+ g_free (cfg_file);
+ g_key_file_free (keyfile);
+}
+
+static void
+load_treeview_state (GtkTreeView *treeview)
+{
+ GKeyFile *keyfile;
+ gint i, *list;
+ gsize length;
+ GtkTreeSortable *sortable;
+ GtkTreeModel *model;
+ gchar *cfg_file;
+ const gchar *tree_name;
+
+ g_return_if_fail (treeview && GTK_IS_TREE_VIEW (treeview));
+
+ keyfile = g_key_file_new ();
+ cfg_file = g_build_filename (e_get_user_config_dir (), "cert_trees.ini", NULL);
+
+ if (!g_key_file_load_from_file (keyfile, cfg_file, 0, NULL)) {
+ g_key_file_free (keyfile);
+ g_free (cfg_file);
+ return;
+ }
+
+ model = GTK_TREE_MODEL (gtk_tree_view_get_model (treeview));
+ tree_name = gtk_widget_get_name (GTK_WIDGET (treeview));
+ list = g_key_file_get_integer_list (keyfile, tree_name, "columns", &length, NULL);
+
+ if (list) {
+ gboolean all_hidden = TRUE;
+
+ if (length != (gtk_tree_model_get_n_columns (model) - 1)) {
+ g_debug ("%s: Unexpected number of columns in config file", G_STRFUNC);
+ g_free (list);
+ goto exit;
+ }
+
+ for (i = 0; all_hidden && i < length; i++) {
+ all_hidden = list[i] == 0;
+ }
+
+ for (i = 0; !all_hidden && i < length; i++) {
+ GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
+ if (list[i]) {
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ gtk_tree_view_column_set_fixed_width (column, list[i]);
+ gtk_tree_view_column_set_visible (column, TRUE);
+ } else {
+ gtk_tree_view_column_set_visible (column, FALSE);
+ }
+ }
+ g_free (list);
+ }
+
+ list = g_key_file_get_integer_list (keyfile, tree_name, "columns-order", &length, NULL);
+
+ if (list) {
+ GList *columns = gtk_tree_view_get_columns (treeview);
+
+ if (length != g_list_length (columns)) {
+ g_debug ("%s: Unexpected number of columns in config file", G_STRFUNC);
+ g_free (list);
+ goto exit;
+ }
+
+ for (i = (length - 1); i >= 0; i--) {
+ if ((list[i] >= 0) && (list[i] < length)) {
+ GtkTreeViewColumn *column = g_list_nth (columns, list[i])->data;
+ gtk_tree_view_move_column_after (treeview, column, NULL);
+ } else {
+ g_warning ("%s: Invalid column number", G_STRFUNC);
+ }
+ }
+ g_free (list);
+ g_list_free (columns);
+ }
+
+ sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (treeview));
+ gtk_tree_sortable_set_sort_column_id (
+ sortable,
+ g_key_file_get_integer (keyfile, tree_name, "sort-column", 0),
+ g_key_file_get_integer (keyfile, tree_name, "sort-order", GTK_SORT_ASCENDING));
+
+ exit:
+ g_free (cfg_file);
+ g_key_file_free (keyfile);
+}
+
+static void
+report_and_free_error (CertPage *cp,
+ const gchar *where,
+ GError *error)
+{
+ g_return_if_fail (cp != NULL);
+
+ e_notice (
+ gtk_widget_get_toplevel (GTK_WIDGET (cp->treeview)),
+ GTK_MESSAGE_ERROR, "%s: %s", where,
+ error ? error->message : _("Unknown error"));
+
+ if (error)
+ g_error_free (error);
+}
+
+static gboolean
+treeview_header_clicked (GtkWidget *widget,
+ GdkEvent *button_event,
+ gpointer user_data)
+{
+ GtkMenu *menu = user_data;
+ guint event_button = 0;
+ guint32 event_time;
+
+ gdk_event_get_button (button_event, &event_button);
+ event_time = gdk_event_get_time (button_event);
+
+ if (event_button != 3)
+ return FALSE;
+
+ gtk_widget_show_all (GTK_WIDGET (menu));
+ gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event_button, event_time);
+
+ return TRUE;
+}
+
+static void
+header_popup_item_toggled (GtkCheckMenuItem *item,
+ gpointer user_data)
+{
+ GtkTreeViewColumn *column = user_data;
+
+ gtk_tree_view_column_set_visible (
+ column,
+ gtk_check_menu_item_get_active (item));
+}
+
+static void
+treeview_column_visibility_changed (GtkTreeViewColumn *column,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GtkCheckMenuItem *menu_item = user_data;
+
+ gtk_check_menu_item_set_active (
+ menu_item,
+ gtk_tree_view_column_get_visible (column));
+
+}
+
+static void
+treeview_selection_changed (GtkTreeSelection *selection,
+ CertPage *cp)
+{
+ GtkTreeIter iter;
+ gboolean cert_selected = FALSE;
+ GtkTreeModel *model;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ ECert *cert;
+
+ gtk_tree_model_get (
+ model, &iter,
+ cp->columns_count - 1, &cert,
+ -1);
+
+ if (cert) {
+ cert_selected = TRUE;
+ g_object_unref (cert);
+ }
+ }
+
+ if (cp->delete_button)
+ gtk_widget_set_sensitive (cp->delete_button, cert_selected);
+ if (cp->edit_button)
+ gtk_widget_set_sensitive (cp->edit_button, cert_selected);
+ if (cp->view_button)
+ gtk_widget_set_sensitive (cp->view_button, cert_selected);
+}
+
+static void
+treeview_add_column (CertPage *cp,
+ gint column_index)
+{
+ GtkCellRenderer *cell;
+ GtkTreeViewColumn *column;
+ GtkWidget *header, *item;
+
+ if (cp->columns[column_index].type != G_TYPE_STRING)
+ return;
+
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ column = gtk_tree_view_column_new_with_attributes (
+ gettext (cp->columns[column_index].column_title),
+ cell, "text", column_index, NULL);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, column_index);
+ gtk_tree_view_column_set_visible (column, cp->columns[column_index].visible);
+ gtk_tree_view_append_column (cp->treeview, column);
+
+ header = gtk_tree_view_column_get_button (column);
+ g_signal_connect (
+ header, "button-release-event",
+ G_CALLBACK (treeview_header_clicked), cp->popup_menu);
+
+ /* The first column should not be concealable so there's no point in displaying
+ * it in the popup menu */
+ if (column_index == 0)
+ return;
+
+ /* Add item to header popup */
+ item = gtk_check_menu_item_new_with_label (
+ gettext (cp->columns[column_index].column_title));
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), cp->columns[column_index].visible);
+ gtk_menu_attach (cp->popup_menu, item, 0, 1, column_index - 1, column_index);
+ g_signal_connect (
+ item, "toggled",
+ G_CALLBACK (header_popup_item_toggled), column);
+ g_signal_connect (
+ column, "notify::visible",
+ G_CALLBACK (treeview_column_visibility_changed), item);
+}
+
+struct find_cert_data {
+ ECert *cert;
+ GtkTreePath *path;
+ CertPage *cp;
+};
+
+static gboolean
+find_cert_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ struct find_cert_data *fcd = data;
+ ECert *cert = NULL;
+
+ g_return_val_if_fail (model != NULL, TRUE);
+ g_return_val_if_fail (iter != NULL, TRUE);
+ g_return_val_if_fail (data != NULL, TRUE);
+
+ /* Get the certificate object from model */
+ gtk_tree_model_get (model, iter, (fcd->cp->columns_count - 1), &cert, -1);
+
+ if (cert && g_strcmp0 (e_cert_get_serial_number (cert), e_cert_get_serial_number (fcd->cert)) == 0
+ && g_strcmp0 (e_cert_get_subject_name (cert), e_cert_get_subject_name (fcd->cert)) == 0
+ && g_strcmp0 (e_cert_get_sha1_fingerprint (cert), e_cert_get_sha1_fingerprint (fcd->cert)) == 0
+ && g_strcmp0 (e_cert_get_md5_fingerprint (cert), e_cert_get_md5_fingerprint (fcd->cert)) == 0) {
+ fcd->path = gtk_tree_path_copy (path);
+ }
+
+ if (cert)
+ g_object_unref (cert);
+
+ return fcd->path != NULL;
+}
+
+static void
+select_certificate (CertPage *cp,
+ ECert *cert)
+{
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ struct find_cert_data fcd;
+
+ g_return_if_fail (cp != NULL);
+ g_return_if_fail (cert != NULL);
+ g_return_if_fail (E_IS_CERT (cert));
+
+ model = gtk_tree_view_get_model (cp->treeview);
+ g_return_if_fail (model != NULL);
+
+ fcd.cp = cp;
+ fcd.cert = cert;
+ fcd.path = NULL;
+
+ gtk_tree_model_foreach (model, find_cert_cb, &fcd);
+
+ if (fcd.path) {
+ gtk_tree_view_expand_to_path (cp->treeview, fcd.path);
+
+ selection = gtk_tree_view_get_selection (cp->treeview);
+ gtk_tree_selection_select_path (selection, fcd.path);
+
+ gtk_tree_view_scroll_to_cell (cp->treeview, fcd.path, NULL, TRUE, 0.5, 0.5);
+ gtk_tree_path_free (fcd.path);
+ }
+}
+
+static void
+view_cert (GtkWidget *button,
+ CertPage *cp)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (cp->treeview), NULL, &iter)) {
+ ECert *cert;
+
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (cp->streemodel), &iter,
+ cp->columns_count - 1, &cert,
+ -1);
+
+ if (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);
+ gtk_widget_show (dialog);
+ g_object_unref (cert);
+ }
+ }
+}
+
+static void
+edit_cert (GtkWidget *button,
+ CertPage *cp)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (cp->treeview), NULL, &iter)) {
+ ECert *cert;
+
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (cp->streemodel), &iter,
+ cp->columns_count - 1, &cert,
+ -1);
+
+ if (cert) {
+ GtkWidget *dialog;
+ CERTCertificate *icert = e_cert_get_internal_cert (cert);
+
+ switch (cp->cert_type) {
+ case E_CERT_CA:
+ dialog = ca_trust_dialog_show (cert, FALSE);
+ ca_trust_dialog_set_trust (
+ dialog,
+ e_cert_trust_has_trusted_ca (icert->trust, TRUE, FALSE, FALSE),
+ e_cert_trust_has_trusted_ca (icert->trust, FALSE, TRUE, FALSE),
+ e_cert_trust_has_trusted_ca (icert->trust, FALSE, FALSE, TRUE));
+ break;
+ case E_CERT_CONTACT:
+ dialog = cert_trust_dialog_show (cert);
+ break;
+ default:
+ /* Other cert types cannot be edited */
+ return;
+ }
+
+ if ((gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) &&
+ (cp->cert_type == E_CERT_CA)) {
+ gboolean trust_ssl, trust_email, trust_objsign;
+ CERTCertTrust trust;
+
+ ca_trust_dialog_get_trust (
+ dialog,
+ &trust_ssl, &trust_email, &trust_objsign);
+
+ e_cert_trust_init (&trust);
+ e_cert_trust_set_valid_ca (&trust);
+ e_cert_trust_add_ca_trust (
+ &trust,
+ trust_ssl, trust_email, trust_objsign);
+
+ e_cert_db_change_cert_trust (icert, &trust);
+ }
+
+ gtk_widget_destroy (dialog);
+ g_object_unref (cert);
+ }
+ }
+}
+
+static void
+import_cert (GtkWidget *button,
+ CertPage *cp)
+{
+ GtkWidget *filesel;
+ GtkFileFilter *filter;
+ gint i;
+
+ filesel = gtk_file_chooser_dialog_new (
+ _("Select a certificate to import..."), NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, cp->cert_filter_name);
+ for (i = 0; cp->cert_mime_types[i] != NULL; i++) {
+ gtk_file_filter_add_mime_type (filter, cp->cert_mime_types[i]);
+ }
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All files"));
+ gtk_file_filter_add_pattern (filter, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter);
+
+ if (gtk_dialog_run (GTK_DIALOG (filesel)) == GTK_RESPONSE_OK) {
+ gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel));
+ GSList *imported_certs = NULL;
+ GError *error = NULL;
+ gboolean import;
+
+ /* destroy dialog to get rid of it in the GUI */
+ gtk_widget_destroy (filesel);
+
+ switch (cp->cert_type) {
+ case E_CERT_USER:
+ import = e_cert_db_import_pkcs12_file (e_cert_db_peek (), filename, &error);
+ break;
+ case E_CERT_CONTACT:
+ case E_CERT_CA:
+ import = e_cert_db_import_certs_from_file (
+ e_cert_db_peek (), filename,
+ cp->cert_type, &imported_certs, &error);
+ break;
+ default:
+ g_free (filename);
+ return;
+ }
+
+ if (import) {
+ unload_certs (cp);
+ load_certs (cp);
+
+ if (imported_certs)
+ select_certificate (cp, imported_certs->data);
+
+ } else {
+ report_and_free_error (cp, _("Failed to import certificate"), error);
+ }
+
+ g_slist_foreach (imported_certs, (GFunc) g_object_unref, NULL);
+ g_slist_free (imported_certs);
+ g_free (filename);
+ } else
+ gtk_widget_destroy (filesel);
+}
+
+static void
+delete_cert (GtkWidget *button,
+ CertPage *cp)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (cp->treeview), NULL, &iter)) {
+ ECert *cert;
+
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (cp->streemodel), &iter,
+ cp->columns_count - 1, &cert,
+ -1);
+
+ if (cert && e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
+ GtkTreeIter child_iter, parent_iter;
+ gboolean has_parent;
+ GtkTreeStore *store = GTK_TREE_STORE (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cp->streemodel)));
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cp->streemodel), &child_iter, &iter);
+ has_parent = gtk_tree_model_iter_parent (GTK_TREE_MODEL (store), &parent_iter, &child_iter);
+ gtk_tree_store_remove (store, &child_iter);
+
+ /* Remove parent if it became empty */
+ if (has_parent && gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &parent_iter) == 0)
+ gtk_tree_store_remove (store, &parent_iter);
+
+ /* we need two unrefs here, one to unref the
+ * gtk_tree_model_get above, and one to unref
+ * the initial ref when we created the cert
+ * and added it to the tree */
+ g_object_unref (cert);
+ g_object_unref (cert);
+ } else if (cert) {
+ g_object_unref (cert);
+ }
+ }
+
+}
+
+static void
+add_cert (CertPage *cp,
+ ECert *cert)
+{
+ GtkTreeIter iter;
+ GtkTreeIter *parent_iter = NULL;
+ const gchar *organization = e_cert_get_org (cert);
+ GtkTreeModel *model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cp->streemodel));
+ gint i;
+
+ if (organization) {
+ parent_iter = g_hash_table_lookup (cp->root_hash, organization);
+ if (!parent_iter) {
+ /* create a new toplevel node */
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &iter,
+ 0, organization, -1);
+
+ /* now copy it off into parent_iter and insert it into
+ * the hashtable */
+ parent_iter = gtk_tree_iter_copy (&iter);
+ g_hash_table_insert (cp->root_hash, g_strdup (organization), parent_iter);
+ }
+ }
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent_iter);
+
+ for (i = 0; i < cp->columns_count; i++) {
+ const gchar * (*get_cert_data_func) (ECert *cert);
+
+ /* When e_cert_get_cn() is empty, use _get_nickname() */
+ if ((cp->columns[i].get_cert_data_func == e_cert_get_cn) && (!e_cert_get_cn (cert))) {
+ get_cert_data_func = e_cert_get_nickname;
+ } else {
+ get_cert_data_func = cp->columns[i].get_cert_data_func;
+ }
+
+ if (cp->columns[i].type == G_TYPE_STRING) {
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &iter,
+ i, get_cert_data_func (cert), -1);
+ } else if (cp->columns[i].type == G_TYPE_OBJECT) {
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &iter,
+ i, cert, -1);
+ }
+ }
+}
+
+static void
+unload_certs (CertPage *cp)
+{
+ GtkTreeStore *treemodel;
+ GType types[cp->columns_count];
+ gint i;
+
+ g_return_if_fail (cp != NULL);
+
+ for (i = 0; i < cp->columns_count; i++)
+ types[i] = cp->columns[i].type;
+ treemodel = gtk_tree_store_newv (cp->columns_count, types);
+
+ if (cp->streemodel)
+ g_object_unref (cp->streemodel);
+
+ cp->streemodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (treemodel));
+
+ g_object_unref (treemodel);
+ gtk_tree_view_set_model (cp->treeview, cp->streemodel);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (cp->streemodel), 0, GTK_SORT_ASCENDING);
+
+ if (cp->root_hash)
+ g_hash_table_destroy (cp->root_hash);
+
+ cp->root_hash = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gtk_tree_iter_free);
+}
+
+static void
+load_certs (CertPage *cp)
+{
+ CERTCertList *certList;
+ CERTCertListNode *node;
+
+ g_return_if_fail (cp != NULL);
+
+ certList = PK11_ListCerts (PK11CertListUnique, NULL);
+
+ for (node = CERT_LIST_HEAD (certList);
+ !CERT_LIST_END (node, certList);
+ node = CERT_LIST_NEXT (node)) {
+ ECert *cert = e_cert_new (CERT_DupCertificate ((CERTCertificate *) node->cert));
+ ECertType ct = e_cert_get_cert_type (cert);
+
+ /* show everything else in a contact tab */
+ if (ct == cp->cert_type || (cp->cert_type == E_CERT_CONTACT && ct != E_CERT_CA && ct != E_CERT_USER)) {
+ add_cert (cp, cert);
+ } else {
+ g_object_unref (cert);
+ }
+ }
+
+ CERT_DestroyCertList (certList);
+}
+
+static gboolean
+populate_ui (ECertManagerConfig *ecmc)
+{
+ /* This is an idle callback. */
+
+ ECertManagerConfigPrivate *priv = ecmc->priv;
+
+ unload_certs (priv->yourcerts_page);
+ load_certs (priv->yourcerts_page);
+
+ unload_certs (priv->contactcerts_page);
+ load_certs (priv->contactcerts_page);
+
+ unload_certs (priv->authoritycerts_page);
+ load_certs (priv->authoritycerts_page);
+
+ /* expand all three trees */
+ gtk_tree_view_expand_all (ECMC_TREE_VIEW (yourcerts_page));
+ gtk_tree_view_expand_all (ECMC_TREE_VIEW (contactcerts_page));
+ gtk_tree_view_expand_all (ECMC_TREE_VIEW (authoritycerts_page));
+
+ /* Now load settings of each treeview */
+ load_treeview_state (ECMC_TREE_VIEW (yourcerts_page));
+ load_treeview_state (ECMC_TREE_VIEW (contactcerts_page));
+ load_treeview_state (ECMC_TREE_VIEW (authoritycerts_page));
+
+ return FALSE;
+}
+
+static void
+initialize_ui (CertPage *cp)
+{
+ GtkTreeSelection *selection;
+ gint i;
+
+ cp->popup_menu = GTK_MENU (gtk_menu_new ());
+
+ /* Add columns to treeview */
+ for (i = 0; i < cp->columns_count; i++)
+ treeview_add_column (cp, i);
+
+ selection = gtk_tree_view_get_selection (cp->treeview);
+ g_signal_connect (
+ selection, "changed",
+ G_CALLBACK (treeview_selection_changed), cp);
+
+ if (cp->import_button)
+ g_signal_connect (
+ cp->import_button, "clicked",
+ G_CALLBACK (import_cert), cp);
+
+ if (cp->edit_button)
+ g_signal_connect (
+ cp->edit_button, "clicked",
+ G_CALLBACK (edit_cert), cp);
+
+ if (cp->delete_button)
+ g_signal_connect (
+ cp->delete_button, "clicked",
+ G_CALLBACK (delete_cert), cp);
+
+ if (cp->view_button)
+ g_signal_connect (
+ cp->view_button, "clicked",
+ G_CALLBACK (view_cert), cp);
+}
+
+static void
+cert_manager_config_window_hide (ECertManagerConfig *ecmc,
+ EPreferencesWindow *epw)
+{
+ g_return_if_fail (ecmc);
+
+ save_treeview_state (ECMC_TREE_VIEW (yourcerts_page));
+ save_treeview_state (ECMC_TREE_VIEW (contactcerts_page));
+ save_treeview_state (ECMC_TREE_VIEW (authoritycerts_page));
+}
+
+static void
+free_cert (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ CertPage *cp = user_data;
+ ECert *cert;
+
+ gtk_tree_model_get (model, iter, cp->columns_count - 1, &cert, -1);
+
+ /* Double unref: one for gtk_tree_model_get() and one for e_cert_new() */
+ g_object_unref (cert);
+ g_object_unref (cert);
+}
+
+static void
+cert_page_free (CertPage *cp)
+{
+ if (!cp)
+ return;
+
+ if (cp->streemodel) {
+ gtk_tree_model_foreach (GTK_TREE_MODEL (cp->streemodel),
+ (GtkTreeModelForeachFunc) free_cert, cp);
+ g_object_unref (cp->streemodel);
+ cp->streemodel = NULL;
+ }
+
+ if (cp->root_hash) {
+ g_hash_table_unref (cp->root_hash);
+ cp->root_hash = NULL;
+ }
+
+ g_free (cp);
+}
+
+static void
+cert_manager_config_dispose (GObject *object)
+{
+ ECertManagerConfig *ecmc = E_CERT_MANAGER_CONFIG (object);
+
+ if (ecmc->priv->yourcerts_page) {
+ cert_page_free (ecmc->priv->yourcerts_page);
+ ecmc->priv->yourcerts_page = NULL;
+ }
+
+ if (ecmc->priv->contactcerts_page) {
+ cert_page_free (ecmc->priv->contactcerts_page);
+ ecmc->priv->contactcerts_page = NULL;
+ }
+
+ if (ecmc->priv->authoritycerts_page) {
+ cert_page_free (ecmc->priv->authoritycerts_page);
+ ecmc->priv->authoritycerts_page = NULL;
+ }
+
+ if (ecmc->priv->builder) {
+ g_object_unref (ecmc->priv->builder);
+ ecmc->priv->builder = NULL;
+ }
+
+ if (ecmc->priv->pref_window) {
+ g_signal_handlers_disconnect_matched (ecmc->priv->pref_window, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ecmc);
+ ecmc->priv->pref_window = NULL;
+ }
+
+ G_OBJECT_CLASS (e_cert_manager_config_parent_class)->dispose (object);
+}
+
+static void
+cert_manager_config_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ECertManagerConfig *ecmc = E_CERT_MANAGER_CONFIG (object);
+
+ switch (property_id) {
+ case PROP_PREFERENCES_WINDOW:
+ ecmc->priv->pref_window = g_value_get_object (value);
+ /* When the preferences window is "closed" (= hidden), save
+ * state of all treeviews. */
+ g_signal_connect_swapped (
+ ecmc->priv->pref_window, "hide",
+ G_CALLBACK (cert_manager_config_window_hide), ecmc);
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_cert_manager_config_class_init (ECertManagerConfigClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (ECertManagerConfigPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = cert_manager_config_set_property;
+ object_class->dispose = cert_manager_config_dispose;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREFERENCES_WINDOW,
+ g_param_spec_object (
+ "preferences-window",
+ NULL,
+ NULL,
+ E_TYPE_PREFERENCES_WINDOW,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
+}
+
+static void
+e_cert_manager_config_init (ECertManagerConfig *ecmc)
+{
+ ECertManagerConfigPrivate *priv;
+ GtkWidget *parent, *widget;
+ CertPage *cp;
+
+ priv = E_CERT_MANAGER_CONFIG_GET_PRIVATE (ecmc);
+ ecmc->priv = priv;
+
+ /* We need to peek the db here to make sure it (and NSS) are fully initialized. */
+ e_cert_db_peek ();
+
+ priv->builder = gtk_builder_new ();
+ e_load_ui_builder_definition (priv->builder, "smime-ui.ui");
+
+ cp = g_new0 (CertPage, 1);
+ priv->yourcerts_page = cp;
+ cp->treeview = GTK_TREE_VIEW (e_builder_get_widget (priv->builder, "yourcerts-treeview"));
+ cp->streemodel = NULL;
+ cp->view_button = e_builder_get_widget (priv->builder, "your-view-button");
+ cp->backup_button = e_builder_get_widget (priv->builder, "your-backup-button");
+ cp->backup_all_button = e_builder_get_widget (priv->builder, "your-backup-all-button");
+ cp->edit_button = NULL;
+ cp->import_button = e_builder_get_widget (priv->builder, "your-import-button");
+ cp->delete_button = e_builder_get_widget (priv->builder, "your-delete-button");
+ cp->columns = yourcerts_columns;
+ cp->columns_count = G_N_ELEMENTS (yourcerts_columns);
+ cp->cert_type = E_CERT_USER;
+ cp->cert_filter_name = _("All PKCS12 files");
+ cp->cert_mime_types = yourcerts_mime_types;
+ initialize_ui (cp);
+
+ cp = g_new0 (CertPage, 1);
+ priv->contactcerts_page = cp;
+ cp->treeview = GTK_TREE_VIEW (e_builder_get_widget (priv->builder, "contactcerts-treeview"));
+ cp->streemodel = NULL;
+ cp->view_button = e_builder_get_widget (priv->builder, "contact-view-button");
+ cp->backup_button = NULL;
+ cp->backup_all_button = NULL;
+ cp->edit_button = e_builder_get_widget (priv->builder, "contact-edit-button");
+ cp->import_button = e_builder_get_widget (priv->builder, "contact-import-button");
+ cp->delete_button = e_builder_get_widget (priv->builder, "contact-delete-button");
+ cp->columns = contactcerts_columns;
+ cp->columns_count = G_N_ELEMENTS (contactcerts_columns);
+ cp->cert_type = E_CERT_CONTACT;
+ cp->cert_filter_name = _("All email certificate files");
+ cp->cert_mime_types = contactcerts_mime_types;
+ initialize_ui (cp);
+
+ cp = g_new0 (CertPage, 1);
+ priv->authoritycerts_page = cp;
+ cp->treeview = GTK_TREE_VIEW (e_builder_get_widget (priv->builder, "authoritycerts-treeview"));
+ cp->streemodel = NULL;
+ cp->view_button = e_builder_get_widget (priv->builder, "authority-view-button");
+ cp->backup_button = NULL;
+ cp->backup_all_button = NULL;
+ cp->edit_button = e_builder_get_widget (priv->builder, "authority-edit-button");
+ cp->import_button = e_builder_get_widget (priv->builder, "authority-import-button");
+ cp->delete_button = e_builder_get_widget (priv->builder, "authority-delete-button");
+ cp->columns = authoritycerts_columns;
+ cp->columns_count = G_N_ELEMENTS (authoritycerts_columns);
+ cp->cert_type = E_CERT_CA;
+ cp->cert_filter_name = _("All CA certificate files");
+ cp->cert_mime_types = authoritycerts_mime_types;
+ initialize_ui (cp);
+
+ /* Run this in an idle callback so Evolution has a chance to
+ * fully initialize itself and start its main loop before we
+ * load certificates, since doing so may trigger a password
+ * dialog, and dialogs require a main loop.
+ * Schedule with priority higher than gtk+ uses for animations
+ * (check docs for G_PRIORITY_HIGH_IDLE). */
+ g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) populate_ui, ecmc, NULL);
+
+ /* Disconnect cert-manager-notebook from it's window and attach it
+ * to this ECertManagerConfig */
+ widget = e_builder_get_widget (priv->builder, "cert-manager-notebook");
+ parent = gtk_widget_get_parent (widget);
+ gtk_container_remove (GTK_CONTAINER (parent), widget);
+ gtk_box_pack_start (GTK_BOX (ecmc), widget, TRUE, TRUE, 0);
+ gtk_widget_show_all (widget);
+
+ /* FIXME: remove when implemented */
+ gtk_widget_set_sensitive (priv->yourcerts_page->backup_button, FALSE);
+ gtk_widget_set_sensitive (priv->yourcerts_page->backup_all_button, FALSE);
+}
+
+GtkWidget *
+e_cert_manager_config_new (EPreferencesWindow *window)
+{
+ ECertManagerConfig *ecmc;
+
+ ecmc = g_object_new (E_TYPE_CERT_MANAGER_CONFIG, "preferences-window", window, NULL);
+
+ 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
new file mode 100644
index 0000000000..0b873f81da
--- /dev/null
+++ b/smime/gui/certificate-manager.h
@@ -0,0 +1,73 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _CERTIFICATE_MANAGER_H_
+#define _CERTIFICATE_MANAGER_H
+
+#include <gtk/gtk.h>
+#include <shell/e-shell.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CERT_MANAGER_CONFIG \
+ (e_cert_manager_config_get_type ())
+#define E_CERT_MANAGER_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CERT_MANAGER_CONFIG, ECertManagerConfig))
+#define E_CERT_MANAGER_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CERT_MANAGER_CONFIG, ECertManagerConfigClass))
+#define E_IS_CERT_MANAGER_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CERT_MANAGER_CONFIG))
+#define E_IS_CERT_MANAGER_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CERT_MANAGER_CONFIG))
+#define E_CERT_MANAGER_CONFIG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CERT_MANAGER_CONFIG, ECertManagerConfigClass))
+
+typedef struct _ECertManagerConfig ECertManagerConfig;
+typedef struct _ECertManagerConfigClass ECertManagerConfigClass;
+typedef struct _ECertManagerConfigPrivate ECertManagerConfigPrivate;
+
+struct _ECertManagerConfig {
+ GtkBox parent;
+ ECertManagerConfigPrivate *priv;
+};
+
+struct _ECertManagerConfigClass {
+ GtkBoxClass parent_class;
+};
+
+G_BEGIN_DECLS
+
+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
new file mode 100644
index 0000000000..4fdd15e473
--- /dev/null
+++ b/smime/gui/certificate-viewer.c
@@ -0,0 +1,688 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include "pk11pub.h"
+#include "hasht.h"
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-asn1-object.h"
+#include "certificate-viewer.h"
+
+#define CERTIFICATE_VIEWER_PRIV_KEY "CertificateViewerPriv-key"
+
+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_priv_struct (gpointer ptr)
+{
+ CertificateViewerPriv *priv = ptr;
+ GSList *iter;
+
+ if (!priv)
+ return;
+
+ if (priv->cert)
+ CERT_DestroyCertificate (priv->cert);
+
+ 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
+begin_section (GtkGrid *add_to,
+ const gchar *caption,
+ gint *from_row,
+ gint for_rows)
+{
+ 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);
+
+ pango_attr_list_unref (bold);
+
+ gtk_grid_attach (add_to, widget, 0, *from_row, 3, 1);
+ (*from_row)++;
+
+ widget = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0);
+
+ gtk_grid_attach (add_to, widget, 0, *from_row, 1, for_rows);
+}
+
+static GtkWidget *
+add_info_label (GtkGrid *add_to,
+ const gchar *caption,
+ gint *at_row)
+{
+ GtkWidget *widget;
+
+ g_return_val_if_fail (add_to != NULL, NULL);
+ g_return_val_if_fail (at_row != NULL, NULL);
+
+ 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);
+
+ gtk_grid_attach (add_to, widget, 1, *at_row, 1, 1);
+ }
+
+ 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);
+ }
+}
+
+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);
+}
+
+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>&lt;", _("Not part of certificate"), "&gt;</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 (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 (fields_store, &new_iter, root, -1);
+ gtk_tree_store_set (
+ 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 *iter;
+ for (iter = children; iter; iter = iter->next) {
+ EASN1Object *subasn1 = iter->data;
+
+ populate_fields_tree (priv, subasn1, &new_iter);
+ }
+ }
+
+ g_list_free_full (children, g_object_unref);
+ }
+}
+
+static void
+hierarchy_selection_changed_cb (GtkTreeSelection *selection,
+ CertificateViewerPriv *priv)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ 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);
+
+ if (!cert)
+ return;
+
+ /* display the cert's ASN1 structure */
+ asn1 = e_asn1_object_new_from_cert (cert);
+
+ /* wipe out the old model */
+ fields_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT);
+ gtk_tree_view_set_model (
+ GTK_TREE_VIEW (priv->cert_fields_treeview),
+ GTK_TREE_MODEL (fields_store));
+
+ /* populate the fields from the newly selected cert */
+ 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 (priv->cert_field_value_textview)),
+ "", 0);
+ }
+}
+
+static void
+fields_selection_changed_cb (GtkTreeSelection *selection,
+ CertificateViewerPriv *priv)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ 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, -1);
+
+ if (asn1)
+ value = e_asn1_object_get_display_value (asn1);
+
+ 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 (textbuffer, &text_iter);
+
+ gtk_text_buffer_insert_with_tags (
+ textbuffer, &text_iter,
+ value, strlen (value),
+ priv->monospace_tag, NULL);
+ }
+
+ if (asn1)
+ g_object_unref (asn1);
+ }
+}
+
+static void
+fill_details_page (CertificateViewerPriv *priv)
+{
+ GSList *iter;
+ GtkTreeIter root;
+ GtkTreeSelection *selection;
+ gboolean root_set = FALSE;
+ GtkTreeStore *hierarchy_store;
+
+ 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 (priv->cert_hierarchy_treeview),
+ GTK_TREE_MODEL (hierarchy_store));
+
+ gtk_tree_view_insert_column_with_attributes (
+ 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 (priv->cert_hierarchy_treeview));
+ g_signal_connect (
+ selection, "changed",
+ G_CALLBACK (hierarchy_selection_changed_cb), priv);
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->cert_fields_treeview), FALSE);
+
+ gtk_tree_view_insert_column_with_attributes (
+ 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 (priv->cert_fields_treeview));
+ g_signal_connect (
+ selection, "changed",
+ 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 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;
+
+ if (!cert)
+ continue;
+
+ str = CERT_GetCommonName (&cert->subject);
+
+ gtk_tree_store_insert (hierarchy_store, &new_iter, root_set ? &root : NULL, -1);
+ gtk_tree_store_set (
+ 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;
+ }
+
+ return cert->subjectName;
+}
+
+GtkWidget *
+certificate_viewer_new (GtkWindow *parent,
+ const CERTCertificate *cert,
+ const GSList *issuers_chain_certs)
+{
+ CertificateViewerPriv *priv;
+ GtkWidget *dialog, *notebook, *widget;
+ GtkGrid *grid;
+ gint row;
+ GSList *iter;
+ gchar *title;
+
+ 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);
+
+ /* 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);
+
+ for (iter = priv->issuers; iter; iter = g_slist_next (iter)) {
+ iter->data = CERT_DupCertificate (iter->data);
+ }
+
+ title = get_window_title (priv->cert);
+
+ dialog = gtk_dialog_new_with_buttons (
+ title, parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+ NULL);
+
+ g_free (title);
+
+ 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);
+
+ fill_general_page (priv);
+ fill_details_page (priv);
+
+ return dialog;
+}
diff --git a/smime/gui/certificate-viewer.h b/smime/gui/certificate-viewer.h
new file mode 100644
index 0000000000..41f2c83c7b
--- /dev/null
+++ b/smime/gui/certificate-viewer.h
@@ -0,0 +1,32 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifndef CERTIFICATE_VIEWER_H
+#define CERTIFICATE_VIEWER_H
+
+#include <gtk/gtk.h>
+#include <cert.h>
+
+GtkWidget * certificate_viewer_new (GtkWindow *parent,
+ const CERTCertificate *cert,
+ const GSList *issuers_chain_certs);
+
+#endif /* CERTIFICATE_VIEWER_H */
diff --git a/smime/gui/component.c b/smime/gui/component.c
new file mode 100644
index 0000000000..790bb68ff5
--- /dev/null
+++ b/smime/gui/component.c
@@ -0,0 +1,141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "component.h"
+
+#include <gtk/gtk.h>
+
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+
+#include "ca-trust-dialog.h"
+#include "e-cert-db.h"
+#include "pk11func.h"
+
+static gboolean
+smime_pk11_passwd (ECertDB *db,
+ PK11SlotInfo *slot,
+ gboolean retry,
+ gchar **passwd,
+ gpointer arg)
+{
+ gchar *prompt;
+ gchar *slot_name = g_strdup (PK11_GetSlotName (slot));
+ gchar *token_name = g_strdup (PK11_GetTokenName (slot));
+
+ g_strchomp (slot_name);
+
+ if (token_name)
+ g_strchomp (token_name);
+
+ if (token_name && *token_name && g_ascii_strcasecmp (slot_name, token_name) != 0)
+ prompt = g_strdup_printf (_("Enter the password for '%s', token '%s'"), slot_name, token_name);
+ else
+ prompt = g_strdup_printf (_("Enter the password for '%s'"), slot_name);
+
+ g_free (slot_name);
+ g_free (token_name);
+
+ *passwd = e_passwords_ask_password (
+ _("Enter password"), "", prompt,
+ E_PASSWORDS_REMEMBER_NEVER | E_PASSWORDS_SECRET,
+ NULL, NULL);
+
+ g_free (prompt);
+
+ /* this should return FALSE if they canceled. */
+ return TRUE;
+}
+
+static gboolean
+smime_pk11_change_passwd (ECertDB *db,
+ gchar **old_passwd,
+ gchar **passwd,
+ gpointer arg)
+{
+ gchar *prompt;
+
+ /* XXX need better strings here, just copy mozilla's? */
+
+ if (!old_passwd) {
+ /* we're setting the password initially */
+ prompt = _("Enter new password for certificate database");
+
+ *passwd = e_passwords_ask_password (
+ _("Enter new password"), "", prompt,
+ E_PASSWORDS_REMEMBER_NEVER | E_PASSWORDS_SECRET,
+ NULL, NULL);
+ }
+ else {
+ /* we're changing the password */
+ /* XXX implement this... */
+ }
+
+ /* this should return FALSE if they canceled. */
+ return TRUE;
+}
+
+static gboolean
+smime_confirm_ca_cert_import (ECertDB *db,
+ ECert *cert,
+ gboolean *trust_ssl,
+ gboolean *trust_email,
+ gboolean *trust_objsign,
+ gpointer arg)
+{
+ GtkWidget *dialog = ca_trust_dialog_show (cert, TRUE);
+ gint response;
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ ca_trust_dialog_get_trust (dialog, trust_ssl, trust_email, trust_objsign);
+
+ gtk_widget_destroy (dialog);
+
+ return response != GTK_RESPONSE_CANCEL;
+}
+
+void
+smime_component_init (void)
+{
+ static gboolean init_done = FALSE;
+ if (init_done)
+ return;
+
+ init_done = TRUE;
+ g_signal_connect (
+ e_cert_db_peek (), "pk11_passwd",
+ G_CALLBACK (smime_pk11_passwd), NULL);
+
+ g_signal_connect (
+ e_cert_db_peek (), "pk11_change_passwd",
+ G_CALLBACK (smime_pk11_change_passwd), NULL);
+
+ g_signal_connect (
+ e_cert_db_peek (), "confirm_ca_cert_import",
+ G_CALLBACK (smime_confirm_ca_cert_import), NULL);
+}
diff --git a/smime/gui/component.h b/smime/gui/component.h
new file mode 100644
index 0000000000..a41c4d1209
--- /dev/null
+++ b/smime/gui/component.h
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _SMIME_COMPONENT_H_
+#define _SMIME_COMPONENT_H_
+
+void smime_component_init (void);
+
+#endif /* _SMIME_COMPONENT_H_ */
diff --git a/smime/gui/e-cert-selector.c b/smime/gui/e-cert-selector.c
new file mode 100644
index 0000000000..2928b550ab
--- /dev/null
+++ b/smime/gui/e-cert-selector.c
@@ -0,0 +1,277 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include "nss.h"
+#include "pk11func.h"
+#include "certdb.h"
+#include "cert.h"
+
+#include "e-cert-selector.h"
+
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+
+#define E_CERT_SELECTOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CERT_SELECTOR, ECertSelectorPrivate))
+
+struct _ECertSelectorPrivate {
+ CERTCertList *certlist;
+
+ GtkWidget *combobox, *description;
+};
+
+enum {
+ ECS_SELECTED,
+ ECS_LAST_SIGNAL
+};
+
+static guint ecs_signals[ECS_LAST_SIGNAL];
+
+G_DEFINE_TYPE (ECertSelector, e_cert_selector, GTK_TYPE_DIALOG)
+
+/* (this is what mozilla shows)
+ * Issued to:
+ * Subject: E=notzed@ximian.com, CN=notzed@ximian.com, O=My Company Ltd, L=Adelaide, ST=SA, C=AU
+ * Serial Number: 03
+ * Valid from 23/10/03 06:35:29 to 22/10/04 06:35:29
+ * Purposes: Sign,Encrypt
+ * Issued by:
+ * Subject: E=notzed@ximian.com, O=company, L=there, ST=Here, C=AU
+ */
+
+static CERTCertListNode *
+ecs_find_current (ECertSelector *ecs)
+{
+ struct _ECertSelectorPrivate *p = ecs->priv;
+ CERTCertListNode *node;
+ gint n;
+
+ if (p->certlist == NULL || CERT_LIST_EMPTY (p->certlist))
+ return NULL;
+
+ n = gtk_combo_box_get_active (GTK_COMBO_BOX (p->combobox));
+ node = CERT_LIST_HEAD (p->certlist);
+ while (n > 0 && !CERT_LIST_END (node, p->certlist)) {
+ n--;
+ node = CERT_LIST_NEXT (node);
+ }
+
+ g_return_val_if_fail (!CERT_LIST_END (node, p->certlist), NULL);
+
+ return node;
+}
+
+static void
+e_cert_selector_response (GtkDialog *dialog,
+ gint button)
+{
+ CERTCertListNode *node;
+
+ switch (button) {
+ case GTK_RESPONSE_OK:
+ node = ecs_find_current ((ECertSelector *) dialog);
+ break;
+ default:
+ node = NULL;
+ break;
+ }
+
+ g_signal_emit (dialog, ecs_signals[ECS_SELECTED], 0, node ? node->cert->nickname : NULL);
+}
+
+static void
+ecs_cert_changed (GtkWidget *w,
+ ECertSelector *ecs)
+{
+ struct _ECertSelectorPrivate *p = ecs->priv;
+ CERTCertListNode *node;
+ GtkTextBuffer *buffer;
+ GString *text;
+
+ text = g_string_new ("");
+ node = ecs_find_current (ecs);
+ if (node) {
+ /* FIXME: add serial no, validity date, uses */
+ g_string_append_printf (text, _("Issued to:\n Subject: %s\n"), node->cert->subjectName);
+ g_string_append_printf (text, _("Issued by:\n Subject: %s\n"), node->cert->issuerName);
+ }
+
+ buffer = gtk_text_view_get_buffer ((GtkTextView *) p->description);
+ gtk_text_buffer_set_text (buffer, text->str, text->len);
+ g_string_free (text, TRUE);
+}
+
+/**
+ * e_cert_selector_new:
+ * @type:
+ * @currentid:
+ *
+ * Create a new ECertSelector dialog. @type specifies which type of cert to
+ * be selected, E_CERT_SELECTOR_SIGNER for signing certs, and
+ * E_CERT_SELECTOR_RECIPIENT for encrypting certs.
+ *
+ * @currentid is the nickname of the cert currently selected for this user.
+ *
+ * You only need to connect to a single signal "selected" which will
+ * be called with either a NULL nickname if cancelled, or the newly
+ * selected nickname otherwise.
+ *
+ * Return value: A dialogue to be shown.
+ **/
+GtkWidget *
+e_cert_selector_new (gint type,
+ const gchar *currentid)
+{
+ ECertSelector *ecs;
+ struct _ECertSelectorPrivate *p;
+ SECCertUsage usage;
+ CERTCertList *certlist;
+ CERTCertListNode *node;
+ GtkBuilder *builder;
+ GtkWidget *content_area;
+ GtkWidget *w;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ gint n = 0, active = 0;
+
+ ecs = g_object_new (e_cert_selector_get_type (), NULL);
+ p = ecs->priv;
+
+ builder = gtk_builder_new ();
+ e_load_ui_builder_definition (builder, "smime-ui.ui");
+
+ p->combobox = e_builder_get_widget (builder, "cert_combobox");
+ p->description = e_builder_get_widget (builder, "cert_description");
+
+ w = e_builder_get_widget (builder, "cert_selector_vbox");
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (ecs));
+ gtk_box_pack_start (GTK_BOX (content_area), w, TRUE, TRUE, 3);
+ gtk_window_set_title (GTK_WINDOW (ecs), _("Select certificate"));
+
+ switch (type) {
+ case E_CERT_SELECTOR_SIGNER:
+ default:
+ usage = certUsageEmailSigner;
+ break;
+ case E_CERT_SELECTOR_RECIPIENT:
+ usage = certUsageEmailRecipient;
+ break;
+ }
+
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (p->combobox)));
+ gtk_list_store_clear (store);
+
+ certlist = CERT_FindUserCertsByUsage (CERT_GetDefaultCertDB (), usage, FALSE, TRUE, NULL);
+ ecs->priv->certlist = certlist;
+ if (certlist != NULL) {
+ node = CERT_LIST_HEAD (certlist);
+ while (!CERT_LIST_END (node, certlist)) {
+ if (node->cert->nickname || node->cert->emailAddr) {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (
+ store, &iter,
+ 0, node->cert->nickname ? node->cert->nickname : node->cert->emailAddr,
+ -1);
+
+ if (currentid != NULL
+ && ((node->cert->nickname != NULL && strcmp (node->cert->nickname, currentid) == 0)
+ || (node->cert->emailAddr != NULL && strcmp (node->cert->emailAddr, currentid) == 0)))
+ active = n;
+
+ n++;
+ }
+
+ node = CERT_LIST_NEXT (node);
+ }
+ }
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (p->combobox), active);
+
+ g_signal_connect (
+ p->combobox, "changed",
+ G_CALLBACK (ecs_cert_changed), ecs);
+
+ g_object_unref (builder);
+
+ ecs_cert_changed (p->combobox, ecs);
+
+ return GTK_WIDGET (ecs);
+}
+
+static void
+e_cert_selector_init (ECertSelector *ecs)
+{
+ gtk_dialog_add_buttons (
+ GTK_DIALOG (ecs),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ ecs->priv = E_CERT_SELECTOR_GET_PRIVATE (ecs);
+}
+
+static void
+e_cert_selector_finalize (GObject *object)
+{
+ ECertSelectorPrivate *priv;
+
+ priv = E_CERT_SELECTOR_GET_PRIVATE (object);
+
+ if (priv->certlist)
+ CERT_DestroyCertList (priv->certlist);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_cert_selector_parent_class)->finalize (object);
+}
+
+static void
+e_cert_selector_class_init (ECertSelectorClass *class)
+{
+ GObjectClass *object_class;
+ GtkDialogClass *dialog_class;
+
+ g_type_class_add_private (class, sizeof (ECertSelectorPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = e_cert_selector_finalize;
+
+ dialog_class = GTK_DIALOG_CLASS (class);
+ dialog_class->response = e_cert_selector_response;
+
+ ecs_signals[ECS_SELECTED] = g_signal_new (
+ "selected",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECertSelectorClass, selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+}
+
diff --git a/smime/gui/e-cert-selector.h b/smime/gui/e-cert-selector.h
new file mode 100644
index 0000000000..e51f1263ef
--- /dev/null
+++ b/smime/gui/e-cert-selector.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Michael Zucchi <notzed@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CERT_SELECTOR_H
+#define E_CERT_SELECTOR_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CERT_SELECTOR \
+ (e_cert_selector_get_type ())
+#define E_CERT_SELECTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CERT_SELECTOR, ECertSelector))
+#define E_CERT_SELECTOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CERT_SELECTOR, ECertSelectorClass))
+#define E_IS_CERT_SELECTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CERT_SELECTOR))
+#define E_IS_CERT_SELECTOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CERT_SELECTOR))
+#define E_CERT_SELECTOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CERT_SELECTOR, ECertSelectorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECertSelector ECertSelector;
+typedef struct _ECertSelectorClass ECertSelectorClass;
+typedef struct _ECertSelectorPrivate ECertSelectorPrivate;
+
+struct _ECertSelector {
+ GtkDialog parent;
+ ECertSelectorPrivate *priv;
+};
+
+struct _ECertSelectorClass {
+ GtkDialogClass parent_class;
+
+ void (*selected)(ECertSelector *, const gchar *certid);
+};
+
+enum _e_cert_selector_type {
+ E_CERT_SELECTOR_SIGNER,
+ E_CERT_SELECTOR_RECIPIENT
+};
+
+GType e_cert_selector_get_type (void);
+GtkWidget *e_cert_selector_new (gint type, const gchar *currentid);
+
+G_END_DECLS
+
+#endif /* E_CERT_SELECTOR_H */
+
diff --git a/smime/gui/smime-ui.ui b/smime/gui/smime-ui.ui
new file mode 100644
index 0000000000..5622c4d0e5
--- /dev/null
+++ b/smime/gui/smime-ui.ui
@@ -0,0 +1,799 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkListStore" id="model1">
+ <columns>
+ <!-- column-name gchararray -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">a</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">b</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkWindow" id="cert-manager-config-control">
+ <property name="title">window1</property>
+ <child>
+ <object class="GtkNotebook" id="cert-manager-notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label57">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">You have certificates from these organizations that identify you:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="yourcerts-treeview">
+ <property name="name">yourcerts</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="yourcerts-treeview-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Certificates Table</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVButtonBox" id="vbuttonbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="your-view-button">
+ <property name="label" translatable="yes">_View</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="your-backup-button">
+ <property name="label" translatable="yes" comments="This is a verb, as in &quot;make a backup&quot;.">_Backup</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">backup-image</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="your-backup-all-button">
+ <property name="label" translatable="yes">Backup _All</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="image">backup-all-image</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="your-import-button">
+ <property name="label" translatable="yes">I_mport</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_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="your-delete-button">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</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">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label54">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Your Certificates</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label60">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">You have certificates on file that identify these people:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="contactcerts-treeview">
+ <property name="name">contactcerts</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="contactcerts-treeview-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Certificates Table</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVButtonBox" id="vbuttonbox2">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="contact-view-button">
+ <property name="label" translatable="yes">_View</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="contact-edit-button">
+ <property name="label">gtk-edit</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</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">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="contact-import-button">
+ <property name="label" translatable="yes">I_mport</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_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="contact-delete-button">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</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">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label55">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Contact Certificates</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label62">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">You have certificates on file that identify these certificate authorities:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow6">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="authoritycerts-treeview">
+ <property name="name">authoritycerts</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVButtonBox" id="vbuttonbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="authority-view-button">
+ <property name="label" translatable="yes">_View</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="authority-edit-button">
+ <property name="label">gtk-edit</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</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">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="authority-import-button">
+ <property name="label" translatable="yes">I_mport</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_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="authority-delete-button">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</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">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label56">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Authorities</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkDialog" id="ca-trust-dialog">
+ <property name="title" translatable="yes">Certificate Authority Trust</property>
+ <property name="window_position">center</property>
+ <property name="type_hint">normal</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="ca-trust-label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="ssl_trust_checkbutton">
+ <property name="label" translatable="yes">Trust this CA to identify _websites.</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="email_trust_checkbutton">
+ <property name="label" translatable="yes">Trust this CA to identify _email users.</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="objsign_trust_checkbutton">
+ <property name="label" translatable="yes">Trust this CA to identify _software developers.</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label66">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Before trusting this CA for any purpose, you should examine its certificate and its policy and procedures (if available).</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="view_certificate_button">
+ <property name="label" translatable="yes">_View Certificate</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_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancelbutton">
+ <property name="label">gtk-cancel</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">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="okbutton">
+ <property name="label">gtk-ok</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">2</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="-3">view_certificate_button</action-widget>
+ <action-widget response="-6">cancelbutton</action-widget>
+ <action-widget response="-5">okbutton</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkVBox" id="cert_selector_vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label67">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Certificate</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="cert_combobox">
+ <property name="visible">True</property>
+ <property name="model">model1</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame7">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow7">
+ <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="GtkTextView" id="cert_description">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label68">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Certificate details</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkDialog" id="cert-trust-dialog">
+ <property name="title" translatable="yes">Email Certificate Trust Settings</property>
+ <property name="window_position">center</property>
+ <property name="type_hint">normal</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="trust-label">
+ <property name="visible">True</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="cert-trust">
+ <property name="label" translatable="yes">Trust the authenticity of this certificate</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="cert-notrust">
+ <property name="label" translatable="yes">Do not trust the authenticity of this certificate</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">cert-trust</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="editca">
+ <property name="label" translatable="yes">_Edit CA Trust</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_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="editok">
+ <property name="label">gtk-ok</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">1</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="-3">editca</action-widget>
+ <action-widget response="-5">editok</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkImage" id="backup-image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ </object>
+ <object class="GtkImage" id="backup-all-image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ </object>
+</interface>
diff --git a/smime/lib/Makefile.am b/smime/lib/Makefile.am
new file mode 100644
index 0000000000..a8e2bfbbba
--- /dev/null
+++ b/smime/lib/Makefile.am
@@ -0,0 +1,41 @@
+privsolib_LTLIBRARIES = libessmime.la
+
+libessmime_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DG_LOG_DOMAIN=\"evolution-smime\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/shell \
+ -I$(top_builddir) \
+ -DEVOLUTION_DATADIR=\""$(datadir)"\" \
+ -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
+ -DEVOLUTION_LOCALEDIR=\""$(localedir)"\" \
+ -DEVOLUTION_UIDIR=\""$(uidir)"\" \
+ -DPREFIX=\""$(prefix)"\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(GTKHTML_CFLAGS) \
+ $(CERT_UI_CFLAGS)
+
+libessmime_la_SOURCES = \
+ e-asn1-object.c \
+ e-asn1-object.h \
+ e-cert.c \
+ e-cert.h \
+ e-cert-trust.c \
+ e-cert-trust.h \
+ e-cert-db.c \
+ e-cert-db.h \
+ e-pkcs12.c \
+ e-pkcs12.h
+
+libessmime_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(GTKHTML_LIBS) \
+ $(CERT_UI_LIBS)
+
+libessmime_la_LDFLAGS = -avoid-version $(NO_UNDEFINED)
+
+-include $(top_srcdir)/git.mk
diff --git a/smime/lib/e-asn1-object.c b/smime/lib/e-asn1-object.c
new file mode 100644
index 0000000000..90411d0395
--- /dev/null
+++ b/smime/lib/e-asn1-object.c
@@ -0,0 +1,964 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* The following is the mozilla license blurb, as the bodies some of
+ * these functions were derived from the mozilla source. */
+/*
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+/*
+ * Author: Chris Toshok (toshok@ximian.com)
+ *
+ * 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 "pk11func.h"
+#include "certdb.h"
+#include "hasht.h"
+
+#define E_ASN1_OBJECT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ASN1_OBJECT, EASN1ObjectPrivate))
+
+struct _EASN1ObjectPrivate {
+ PRUint32 tag;
+ PRUint32 type;
+ gboolean valid_container;
+
+ GList *children;
+
+ gchar *display_name;
+ gchar *value;
+
+ gchar *data;
+ guint data_len;
+};
+
+G_DEFINE_TYPE (EASN1Object, e_asn1_object, G_TYPE_OBJECT)
+
+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)
+{
+ 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;
+}
+
+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;
+
+ 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");
+ }
+ }
+ *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 = 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 {
+ 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 = 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);
+
+ /* 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;
+ }
+
+ 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) {
+ 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);
+ }
+ }
+ *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 (&notBefore);
+ validityData->GetNotAfter (&notAfter);
+ 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);
+
+ 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;
+}
+
+static gboolean
+fill_asn1_from_cert (EASN1Object *asn1,
+ CERTCertificate *cert)
+{
+ EASN1Object *sequence;
+ SECItem temp;
+ gchar *text;
+
+ 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);
+ }
+ }
+
+ /* 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 *
+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)
+{
+ obj->priv->valid_container = flag;
+}
+
+gboolean
+e_asn1_object_is_valid_container (EASN1Object *obj)
+{
+ return obj->priv->valid_container;
+}
+
+PRUint32
+e_asn1_object_get_asn1_type (EASN1Object *obj)
+{
+ return obj->priv->type;
+}
+
+PRUint32
+e_asn1_object_get_asn1_tag (EASN1Object *obj)
+{
+ return obj->priv->tag;
+}
+
+GList *
+e_asn1_object_get_children (EASN1Object *obj)
+{
+ GList *children = g_list_copy (obj->priv->children);
+
+ g_list_foreach (children, (GFunc) g_object_ref, NULL);
+
+ return children;
+}
+
+void
+e_asn1_object_append_child (EASN1Object *parent,
+ EASN1Object *child)
+{
+ parent->priv->children = g_list_append (
+ parent->priv->children, g_object_ref (child));
+}
+
+void
+e_asn1_object_set_display_name (EASN1Object *obj,
+ const gchar *name)
+{
+ g_free (obj->priv->display_name);
+ obj->priv->display_name = g_strdup (name);
+}
+
+const gchar *
+e_asn1_object_get_display_name (EASN1Object *obj)
+{
+ return obj->priv->display_name;
+}
+
+void
+e_asn1_object_set_display_value (EASN1Object *obj,
+ const gchar *value)
+{
+ g_free (obj->priv->value);
+ obj->priv->value = g_strdup (value);
+}
+
+const gchar *
+e_asn1_object_get_display_value (EASN1Object *obj)
+{
+ return obj->priv->value;
+}
+
+void
+e_asn1_object_get_data (EASN1Object *obj,
+ gchar **data,
+ guint32 *len)
+{
+ *data = obj->priv->data;
+ *len = obj->priv->data_len;
+}
diff --git a/smime/lib/e-asn1-object.h b/smime/lib/e-asn1-object.h
new file mode 100644
index 0000000000..39b79a7b1e
--- /dev/null
+++ b/smime/lib/e-asn1-object.h
@@ -0,0 +1,109 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifndef E_ASN1_OBJECT_H
+#define E_ASN1_OBJECT_H
+
+#include <glib-object.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))
+#define E_ASN1_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ASN1_OBJECT, EASN1ObjectClass))
+#define E_IS_ASN1_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ASN1_OBJECT))
+#define E_IS_ASN1_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_ASN1_OBJECT))
+#define E_ASN1_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_ASN1_OBJECT, EASN1ObjectClass))
+
+typedef struct _EASN1Object EASN1Object;
+typedef struct _EASN1ObjectClass EASN1ObjectClass;
+typedef struct _EASN1ObjectPrivate EASN1ObjectPrivate;
+
+enum {
+ /*
+ * Identifiers for the possible types of object.
+ */
+ E_ASN1_OBJECT_TYPE_END_CONTENTS = 0,
+ E_ASN1_OBJECT_TYPE_BOOLEAN = 1,
+ E_ASN1_OBJECT_TYPE_INTEGER = 2,
+ E_ASN1_OBJECT_TYPE_BIT_STRING = 3,
+ E_ASN1_OBJECT_TYPE_OCTET_STRING = 4,
+ E_ASN1_OBJECT_TYPE_NULL = 5,
+ E_ASN1_OBJECT_TYPE_OBJECT_ID = 6,
+ E_ASN1_OBJECT_TYPE_ENUMERATED = 10,
+ E_ASN1_OBJECT_TYPE_UTF8_STRING = 12,
+ E_ASN1_OBJECT_TYPE_SEQUENCE = 16,
+ E_ASN1_OBJECT_TYPE_SET = 17,
+ E_ASN1_OBJECT_TYPE_PRINTABLE_STRING = 19,
+ E_ASN1_OBJECT_TYPE_T61_STRING = 20,
+ E_ASN1_OBJECT_TYPE_IA5_STRING = 22,
+ E_ASN1_OBJECT_TYPE_UTC_TIME = 23,
+ E_ASN1_OBJECT_TYPE_GEN_TIME = 24,
+ E_ASN1_OBJECT_TYPE_VISIBLE_STRING = 26,
+ E_ASN1_OBJECT_TYPE_UNIVERSAL_STRING = 28,
+ E_ASN1_OBJECT_TYPE_BMP_STRING = 30,
+ E_ASN1_OBJECT_TYPE_HIGH_TAG_NUMBER = 31,
+ E_ASN1_OBJECT_TYPE_CONTEXT_SPECIFIC = 32,
+ E_ASN1_OBJECT_TYPE_APPLICATION = 33,
+ E_ASN1_OBJECT_TYPE_PRIVATE = 34
+};
+
+struct _EASN1Object {
+ GObject parent;
+
+ EASN1ObjectPrivate *priv;
+};
+
+struct _EASN1ObjectClass {
+ GObjectClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_ecert_reserved0) (void);
+ void (*_ecert_reserved1) (void);
+ void (*_ecert_reserved2) (void);
+ void (*_ecert_reserved3) (void);
+ void (*_ecert_reserved4) (void);
+};
+
+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_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);
+
+void e_asn1_object_get_data (EASN1Object *obj,
+ gchar **data,
+ guint32 *len);
+
+#endif /* E_ASN1_OBJECT_H */
diff --git a/smime/lib/e-cert-db.c b/smime/lib/e-cert-db.c
new file mode 100644
index 0000000000..bb4a68e61d
--- /dev/null
+++ b/smime/lib/e-cert-db.c
@@ -0,0 +1,1521 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* The following is the mozilla license blurb, as the bodies some of
+ * these functions were derived from the mozilla source. */
+/* e-cert-db.c
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+/*
+ * Author: Chris Toshok (toshok@ximian.com)
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <camel/camel.h>
+
+/* private NSS defines used by PSM */
+/* (must be declated before cert.h) */
+#define CERT_NewTempCertificate __CERT_NewTempCertificate
+#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
+
+#include "e-cert-db.h"
+#include "e-cert-trust.h"
+#include "e-pkcs12.h"
+
+#include "gmodule.h"
+
+#include "nss.h"
+#include "ssl.h"
+#include "p12plcy.h"
+#include "pk11func.h"
+#include "nssckbi.h"
+#include <secerr.h>
+#include "secmod.h"
+#include "certdb.h"
+#include "plstr.h"
+#include "prprf.h"
+#include "prmem.h"
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+enum {
+ PK11_PASSWD,
+ PK11_CHANGE_PASSWD,
+ CONFIRM_CA_CERT_IMPORT,
+ LAST_SIGNAL
+};
+
+static guint e_cert_db_signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (ECertDB, e_cert_db, G_TYPE_OBJECT)
+
+GQuark
+e_certdb_error_quark (void)
+{
+ static GQuark q = 0;
+ if (q == 0)
+ q = g_quark_from_static_string ("e-certdb-error-quark");
+
+ return q;
+}
+
+static const gchar *
+nss_error_to_string (glong errorcode)
+{
+#define cs(a,b) case a: return b;
+
+ switch (errorcode) {
+ cs (SEC_ERROR_IO, "An I/O error occurred during security authorization.")
+ cs (SEC_ERROR_LIBRARY_FAILURE, "security library failure.")
+ cs (SEC_ERROR_BAD_DATA, "security library: received bad data.")
+ cs (SEC_ERROR_OUTPUT_LEN, "security library: output length error.")
+ cs (SEC_ERROR_INPUT_LEN, "security library has experienced an input length error.")
+ cs (SEC_ERROR_INVALID_ARGS, "security library: invalid arguments.")
+ cs (SEC_ERROR_INVALID_ALGORITHM, "security library: invalid algorithm.")
+ cs (SEC_ERROR_INVALID_AVA, "security library: invalid AVA.")
+ cs (SEC_ERROR_INVALID_TIME, "Improperly formatted time string.")
+ cs (SEC_ERROR_BAD_DER, "security library: improperly formatted DER-encoded message.")
+ cs (SEC_ERROR_BAD_SIGNATURE, "Peer's certificate has an invalid signature.")
+ cs (SEC_ERROR_EXPIRED_CERTIFICATE, "Peer's Certificate has expired.")
+ cs (SEC_ERROR_REVOKED_CERTIFICATE, "Peer's Certificate has been revoked.")
+ cs (SEC_ERROR_UNKNOWN_ISSUER, "Peer's Certificate issuer is not recognized.")
+ cs (SEC_ERROR_BAD_KEY, "Peer's public key is invalid.")
+ cs (SEC_ERROR_BAD_PASSWORD, "The security password entered is incorrect.")
+ cs (SEC_ERROR_RETRY_PASSWORD, "New password entered incorrectly. Please try again.")
+ cs (SEC_ERROR_NO_NODELOCK, "security library: no nodelock.")
+ cs (SEC_ERROR_BAD_DATABASE, "security library: bad database.")
+ cs (SEC_ERROR_NO_MEMORY, "security library: memory allocation failure.")
+ cs (SEC_ERROR_UNTRUSTED_ISSUER, "Peer's certificate issuer has been marked as not trusted by the user.")
+ cs (SEC_ERROR_UNTRUSTED_CERT, "Peer's certificate has been marked as not trusted by the user.")
+ cs (SEC_ERROR_DUPLICATE_CERT, "Certificate already exists in your database.")
+ cs (SEC_ERROR_DUPLICATE_CERT_NAME, "Downloaded certificate's name duplicates one already in your database.")
+ cs (SEC_ERROR_ADDING_CERT, "Error adding certificate to database.")
+ cs (SEC_ERROR_FILING_KEY, "Error refiling the key for this certificate.")
+ cs (SEC_ERROR_NO_KEY, "The private key for this certificate cannot be found in key database")
+ cs (SEC_ERROR_CERT_VALID, "This certificate is valid.")
+ cs (SEC_ERROR_CERT_NOT_VALID, "This certificate is not valid.")
+ cs (SEC_ERROR_CERT_NO_RESPONSE, "Cert Library: No Response")
+ cs (SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, "The certificate issuer's certificate has expired. Check your system date and time.")
+ cs (SEC_ERROR_CRL_EXPIRED, "The CRL for the certificate's issuer has expired. Update it or check your system date and time.")
+ cs (SEC_ERROR_CRL_BAD_SIGNATURE, "The CRL for the certificate's issuer has an invalid signature.")
+ cs (SEC_ERROR_CRL_INVALID, "New CRL has an invalid format.")
+ cs (SEC_ERROR_EXTENSION_VALUE_INVALID, "Certificate extension value is invalid.")
+ cs (SEC_ERROR_EXTENSION_NOT_FOUND, "Certificate extension not found.")
+ cs (SEC_ERROR_CA_CERT_INVALID, "Issuer certificate is invalid.")
+ cs (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, "Certificate path length constraint is invalid.")
+ cs (SEC_ERROR_CERT_USAGES_INVALID, "Certificate usages field is invalid.")
+ cs (SEC_INTERNAL_ONLY, "**Internal ONLY module**")
+ cs (SEC_ERROR_INVALID_KEY, "The key does not support the requested operation.")
+ cs (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, "Certificate contains unknown critical extension.")
+ cs (SEC_ERROR_OLD_CRL, "New CRL is not later than the current one.")
+ cs (SEC_ERROR_NO_EMAIL_CERT, "Not encrypted or signed: you do not yet have an email certificate.")
+ cs (SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, "Not encrypted: you do not have certificates for each of the recipients.")
+ cs (SEC_ERROR_NOT_A_RECIPIENT, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found.")
+ cs (SEC_ERROR_PKCS7_KEYALG_MISMATCH, "Cannot decrypt: key encryption algorithm does not match your certificate.")
+ cs (SEC_ERROR_PKCS7_BAD_SIGNATURE, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data.")
+ cs (SEC_ERROR_UNSUPPORTED_KEYALG, "Unsupported or unknown key algorithm.")
+ cs (SEC_ERROR_DECRYPTION_DISALLOWED, "Cannot decrypt: encrypted using a disallowed algorithm or key size.")
+ cs (XP_SEC_FORTEZZA_BAD_CARD, "Fortezza card has not been properly initialized. Please remove it and return it to your issuer.")
+ cs (XP_SEC_FORTEZZA_NO_CARD, "No Fortezza cards Found")
+ cs (XP_SEC_FORTEZZA_NONE_SELECTED, "No Fortezza card selected")
+ cs (XP_SEC_FORTEZZA_MORE_INFO, "Please select a personality to get more info on")
+ cs (XP_SEC_FORTEZZA_PERSON_NOT_FOUND, "Personality not found")
+ cs (XP_SEC_FORTEZZA_NO_MORE_INFO, "No more information on that Personality")
+ cs (XP_SEC_FORTEZZA_BAD_PIN, "Invalid Pin")
+ cs (XP_SEC_FORTEZZA_PERSON_ERROR, "Couldn't initialize Fortezza personalities.")
+ cs (SEC_ERROR_NO_KRL, "No KRL for this site's certificate has been found.")
+ cs (SEC_ERROR_KRL_EXPIRED, "The KRL for this site's certificate has expired.")
+ cs (SEC_ERROR_KRL_BAD_SIGNATURE, "The KRL for this site's certificate has an invalid signature.")
+ cs (SEC_ERROR_REVOKED_KEY, "The key for this site's certificate has been revoked.")
+ cs (SEC_ERROR_KRL_INVALID, "New KRL has an invalid format.")
+ cs (SEC_ERROR_NEED_RANDOM, "security library: need random data.")
+ cs (SEC_ERROR_NO_MODULE, "security library: no security module can perform the requested operation.")
+ cs (SEC_ERROR_NO_TOKEN, "The security card or token does not exist, needs to be initialized, or has been removed.")
+ cs (SEC_ERROR_READ_ONLY, "security library: read-only database.")
+ cs (SEC_ERROR_NO_SLOT_SELECTED, "No slot or token was selected.")
+ cs (SEC_ERROR_CERT_NICKNAME_COLLISION, "A certificate with the same nickname already exists.")
+ cs (SEC_ERROR_KEY_NICKNAME_COLLISION, "A key with the same nickname already exists.")
+ cs (SEC_ERROR_SAFE_NOT_CREATED, "error while creating safe object")
+ cs (SEC_ERROR_BAGGAGE_NOT_CREATED, "error while creating baggage object")
+ cs (XP_JAVA_REMOVE_PRINCIPAL_ERROR, "Couldn't remove the principal")
+ cs (XP_JAVA_DELETE_PRIVILEGE_ERROR, "Couldn't delete the privilege")
+ cs (XP_JAVA_CERT_NOT_EXISTS_ERROR, "This principal doesn't have a certificate")
+ cs (SEC_ERROR_BAD_EXPORT_ALGORITHM, "Required algorithm is not allowed.")
+ cs (SEC_ERROR_EXPORTING_CERTIFICATES, "Error attempting to export certificates.")
+ cs (SEC_ERROR_IMPORTING_CERTIFICATES, "Error attempting to import certificates.")
+ cs (SEC_ERROR_PKCS12_DECODING_PFX, "Unable to import. Decoding error. File not valid.")
+ cs (SEC_ERROR_PKCS12_INVALID_MAC, "Unable to import. Invalid MAC. Incorrect password or corrupt file.")
+ cs (SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, "Unable to import. MAC algorithm not supported.")
+ cs (SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, "Unable to import. Only password integrity and privacy modes supported.")
+ cs (SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, "Unable to import. File structure is corrupt.")
+ cs (SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, "Unable to import. Encryption algorithm not supported.")
+ cs (SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, "Unable to import. File version not supported.")
+ cs (SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, "Unable to import. Incorrect privacy password.")
+ cs (SEC_ERROR_PKCS12_CERT_COLLISION, "Unable to import. Same nickname already exists in database.")
+ cs (SEC_ERROR_USER_CANCELLED, "The user pressed cancel.")
+ cs (SEC_ERROR_PKCS12_DUPLICATE_DATA, "Not imported, already in database.")
+ cs (SEC_ERROR_MESSAGE_SEND_ABORTED, "Message not sent.")
+ cs (SEC_ERROR_INADEQUATE_KEY_USAGE, "Certificate key usage inadequate for attempted operation.")
+ cs (SEC_ERROR_INADEQUATE_CERT_TYPE, "Certificate type not approved for application.")
+ cs (SEC_ERROR_CERT_ADDR_MISMATCH, "Address in signing certificate does not match address in message headers.")
+ cs (SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, "Unable to import. Error attempting to import private key.")
+ cs (SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, "Unable to import. Error attempting to import certificate chain.")
+ cs (SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, "Unable to export. Unable to locate certificate or key by nickname.")
+ cs (SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, "Unable to export. Private Key could not be located and exported.")
+ cs (SEC_ERROR_PKCS12_UNABLE_TO_WRITE, "Unable to export. Unable to write the export file.")
+ cs (SEC_ERROR_PKCS12_UNABLE_TO_READ, "Unable to import. Unable to read the import file.")
+ cs (SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, "Unable to export. Key database corrupt or deleted.")
+ cs (SEC_ERROR_KEYGEN_FAIL, "Unable to generate public/private key pair.")
+ cs (SEC_ERROR_INVALID_PASSWORD, "Password entered is invalid. Please pick a different one.")
+ cs (SEC_ERROR_RETRY_OLD_PASSWORD, "Old password entered incorrectly. Please try again.")
+ cs (SEC_ERROR_BAD_NICKNAME, "Certificate nickname already in use.")
+ cs (SEC_ERROR_NOT_FORTEZZA_ISSUER, "Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
+ cs (SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, "A sensitive key cannot be moved to the slot where it is needed.")
+ cs (SEC_ERROR_JS_INVALID_MODULE_NAME, "Invalid module name.")
+ cs (SEC_ERROR_JS_INVALID_DLL, "Invalid module path/filename")
+ cs (SEC_ERROR_JS_ADD_MOD_FAILURE, "Unable to add module")
+ cs (SEC_ERROR_JS_DEL_MOD_FAILURE, "Unable to delete module")
+ cs (SEC_ERROR_OLD_KRL, "New KRL is not later than the current one.")
+ cs (SEC_ERROR_CKL_CONFLICT, "New CKL has different issuer than current CKL. Delete current CKL.")
+ cs (SEC_ERROR_CERT_NOT_IN_NAME_SPACE, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name.")
+ cs (SEC_ERROR_KRL_NOT_YET_VALID, "The key revocation list for this certificate is not yet valid.")
+ cs (SEC_ERROR_CRL_NOT_YET_VALID, "The certificate revocation list for this certificate is not yet valid.")
+ cs (SEC_ERROR_UNKNOWN_CERT, "The requested certificate could not be found.")
+ cs (SEC_ERROR_UNKNOWN_SIGNER, "The signer's certificate could not be found.")
+ cs (SEC_ERROR_CERT_BAD_ACCESS_LOCATION, "The location for the certificate status server has invalid format.")
+ cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, "The OCSP response cannot be fully decoded; it is of an unknown type.")
+ cs (SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, "The OCSP server returned unexpected/invalid HTTP data.")
+ cs (SEC_ERROR_OCSP_MALFORMED_REQUEST, "The OCSP server found the request to be corrupted or improperly formed.")
+ cs (SEC_ERROR_OCSP_SERVER_ERROR, "The OCSP server experienced an internal error.")
+ cs (SEC_ERROR_OCSP_TRY_SERVER_LATER, "The OCSP server suggests trying again later.")
+ cs (SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, "The OCSP server requires a signature on this request.")
+ cs (SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, "The OCSP server has refused this request as unauthorized.")
+ cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, "The OCSP server returned an unrecognizable status.")
+ cs (SEC_ERROR_OCSP_UNKNOWN_CERT, "The OCSP server has no status for the certificate.")
+ cs (SEC_ERROR_OCSP_NOT_ENABLED, "You must enable OCSP before performing this operation.")
+ cs (SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, "You must set the OCSP default responder before performing this operation.")
+ cs (SEC_ERROR_OCSP_MALFORMED_RESPONSE, "The response from the OCSP server was corrupted or improperly formed.")
+ cs (SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, "The signer of the OCSP response is not authorized to give status for this certificate.")
+ cs (SEC_ERROR_OCSP_FUTURE_RESPONSE, "The OCSP response is not yet valid (contains a date in the future).")
+ cs (SEC_ERROR_OCSP_OLD_RESPONSE, "The OCSP response contains out-of-date information.")
+ cs (SEC_ERROR_DIGEST_NOT_FOUND, "The CMS or PKCS #7 Digest was not found in signed message.")
+ cs (SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, "The CMS or PKCS #7 Message type is unsupported.")
+ cs (SEC_ERROR_MODULE_STUCK, "PKCS #11 module could not be removed because it is still in use.")
+ cs (SEC_ERROR_BAD_TEMPLATE, "Could not decode ASN.1 data. Specified template was invalid.")
+ cs (SEC_ERROR_CRL_NOT_FOUND, "No matching CRL was found.")
+ cs (SEC_ERROR_REUSED_ISSUER_AND_SERIAL, "You are attempting to import a cert with the same issuer/serial as an existing cert, but that is not the same cert.")
+ cs (SEC_ERROR_BUSY, "NSS could not shutdown. Objects are still in use.")
+ cs (SEC_ERROR_EXTRA_INPUT, "DER-encoded message contained extra unused data.")
+ cs (SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, "Unsupported elliptic curve.")
+ cs (SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, "Unsupported elliptic curve point form.")
+ cs (SEC_ERROR_UNRECOGNIZED_OID, "Unrecognized Object Identifier.")
+ cs (SEC_ERROR_OCSP_INVALID_SIGNING_CERT, "Invalid OCSP signing certificate in OCSP response.")
+ cs (SEC_ERROR_REVOKED_CERTIFICATE_CRL, "Certificate is revoked in issuer's certificate revocation list.")
+ cs (SEC_ERROR_REVOKED_CERTIFICATE_OCSP, "Issuer's OCSP responder reports certificate is revoked.")
+ cs (SEC_ERROR_CRL_INVALID_VERSION, "Issuer's Certificate Revocation List has an unknown version number.")
+ cs (SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, "Issuer's V1 Certificate Revocation List has a critical extension.")
+ cs (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, "Issuer's V2 Certificate Revocation List has an unknown critical extension.")
+ cs (SEC_ERROR_UNKNOWN_OBJECT_TYPE, "Unknown object type specified.")
+ cs (SEC_ERROR_INCOMPATIBLE_PKCS11, "PKCS #11 driver violates the spec in an incompatible way.")
+ cs (SEC_ERROR_NO_EVENT, "No new slot event is available at this time.")
+ cs (SEC_ERROR_CRL_ALREADY_EXISTS, "CRL already exists.")
+ cs (SEC_ERROR_NOT_INITIALIZED, "NSS is not initialized.")
+ cs (SEC_ERROR_TOKEN_NOT_LOGGED_IN, "The operation failed because the PKCS#11 token is not logged in.")
+ cs (SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, "Configured OCSP responder's certificate is invalid.")
+ cs (SEC_ERROR_OCSP_BAD_SIGNATURE, "OCSP response has an invalid signature.")
+
+ #if defined (NSS_VMAJOR) && defined (NSS_VMINOR) && defined (NSS_VPATCH) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 2))
+ cs (SEC_ERROR_OUT_OF_SEARCH_LIMITS, "Cert validation search is out of search limits")
+ cs (SEC_ERROR_INVALID_POLICY_MAPPING, "Policy mapping contains anypolicy")
+ cs (SEC_ERROR_POLICY_VALIDATION_FAILED, "Cert chain fails policy validation")
+ cs (SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, "Unknown location type in cert AIA extension")
+ cs (SEC_ERROR_BAD_HTTP_RESPONSE, "Server returned bad HTTP response")
+ cs (SEC_ERROR_BAD_LDAP_RESPONSE, "Server returned bad LDAP response")
+ cs (SEC_ERROR_FAILED_TO_ENCODE_DATA, "Failed to encode data with ASN1 encoder")
+ cs (SEC_ERROR_BAD_INFO_ACCESS_LOCATION, "Bad information access location in cert extension")
+ cs (SEC_ERROR_LIBPKIX_INTERNAL, "Libpkix internal error occured during cert validation.")
+ cs (SEC_ERROR_PKCS11_GENERAL_ERROR, "A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
+ cs (SEC_ERROR_PKCS11_FUNCTION_FAILED, "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.")
+ cs (SEC_ERROR_PKCS11_DEVICE_ERROR, "A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.")
+ #endif
+ }
+
+ #undef cs
+
+ return NULL;
+}
+
+static void
+set_nss_error (GError **error)
+{
+ glong err_code;
+ const gchar *err_str;
+
+ if (!error)
+ return;
+
+ g_return_if_fail (*error == NULL);
+
+ err_code = PORT_GetError ();
+
+ if (!err_code)
+ return;
+
+ err_str = nss_error_to_string (err_code);
+ if (!err_str)
+ return;
+
+ *error = g_error_new_literal (E_CERTDB_ERROR, err_code, err_str);
+}
+
+static SECStatus PR_CALLBACK
+collect_certs (gpointer arg,
+ SECItem **certs,
+ gint numcerts)
+{
+ CERTDERCerts *collectArgs;
+ SECItem *cert;
+ SECStatus rv;
+
+ collectArgs = (CERTDERCerts *) arg;
+
+ collectArgs->numcerts = numcerts;
+ collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc (
+ collectArgs->arena, sizeof (SECItem) * numcerts);
+ if (collectArgs->rawCerts == NULL)
+ return (SECFailure);
+
+ cert = collectArgs->rawCerts;
+
+ while (numcerts--) {
+ rv = SECITEM_CopyItem (collectArgs->arena, cert, *certs);
+ if (rv == SECFailure)
+ return (SECFailure);
+ cert++;
+ certs++;
+ }
+
+ return (SECSuccess);
+}
+
+static CERTDERCerts *
+e_cert_db_get_certs_from_package (PRArenaPool *arena,
+ gchar *data,
+ guint32 length)
+{
+ /*nsNSSShutDownPreventionLock locker;*/
+ CERTDERCerts *collectArgs =
+ (CERTDERCerts *) PORT_ArenaZAlloc (arena, sizeof (CERTDERCerts));
+ SECStatus sec_rv;
+
+ if (!collectArgs)
+ return NULL;
+
+ collectArgs->arena = arena;
+ sec_rv = CERT_DecodeCertPackage (
+ data,
+ length, collect_certs,
+ (gpointer) collectArgs);
+
+ if (sec_rv != SECSuccess)
+ return NULL;
+
+ return collectArgs;
+}
+
+#ifdef notyet
+PRBool
+ucs2_ascii_conversion_fn (PRBool toUnicode,
+ guchar *inBuf,
+ guint inBufLen,
+ guchar *outBuf,
+ guint maxOutBufLen,
+ guint *outBufLen,
+ PRBool swapBytes)
+{
+ printf ("in ucs2_ascii_conversion_fn\n");
+}
+#endif
+
+static gchar * PR_CALLBACK
+pk11_password (PK11SlotInfo *slot,
+ PRBool retry,
+ gpointer arg)
+{
+ gchar *pwd;
+ gchar *nsspwd;
+
+ gboolean rv = FALSE;
+
+ g_signal_emit (
+ e_cert_db_peek (),
+ e_cert_db_signals[PK11_PASSWD], 0,
+ slot,
+ retry,
+ &pwd,
+ &rv);
+
+ if (pwd == NULL)
+ return NULL;
+
+ nsspwd = PORT_Strdup (pwd);
+ memset (pwd, 0, strlen (pwd));
+ g_free (pwd);
+ return nsspwd;
+}
+
+static void
+initialize_nss (void)
+{
+ /* Use camel_init() to initialise NSS consistently... */
+ camel_init (e_get_user_data_dir (), TRUE);
+
+ /* ... except for the bits we only seem to do here. FIXME */
+ PK11_SetPasswordFunc (pk11_password);
+
+ /* Enable ciphers for PKCS#12 */
+ SEC_PKCS12EnableCipher (PKCS12_RC4_40, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC4_128, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_40, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_128, 1);
+ SEC_PKCS12EnableCipher (PKCS12_DES_56, 1);
+ SEC_PKCS12EnableCipher (PKCS12_DES_EDE3_168, 1);
+ SEC_PKCS12SetPreferredCipher (PKCS12_DES_EDE3_168, 1);
+#ifdef notyet
+ PORT_SetUCS2_ASCIIConversionFunction (ucs2_ascii_conversion_fn);
+#endif
+}
+
+static void
+install_loadable_roots (void)
+{
+ SECMODModuleList *list = SECMOD_GetDefaultModuleList ();
+ SECMODListLock *lock = SECMOD_GetDefaultModuleListLock ();
+ SECMODModule *RootsModule = NULL;
+ gint i;
+
+ SECMOD_GetReadLock (lock);
+ while (!RootsModule && list) {
+ SECMODModule *module = list->module;
+
+ for (i = 0; i < module->slotCount; i++) {
+ PK11SlotInfo *slot = module->slots[i];
+ if (PK11_IsPresent (slot)) {
+ if (PK11_HasRootCerts (slot)) {
+ RootsModule = module;
+ break;
+ }
+ }
+ }
+
+ list = list->next;
+ }
+ SECMOD_ReleaseReadLock (lock);
+
+ if (RootsModule) {
+ /* Check version, and unload module if it is too old */
+ CK_INFO info;
+
+ if (PK11_GetModInfo (RootsModule, &info) != SECSuccess) {
+ /* Do not use this module */
+ RootsModule = NULL;
+ } else {
+ /* NSS_BUILTINS_LIBRARY_VERSION_MAJOR and NSS_BUILTINS_LIBRARY_VERSION_MINOR
+ * define the version we expect to have.
+ * Later version are fine.
+ * Older versions are not ok, and we will replace with our own version.
+ */
+ if ((info.libraryVersion.major < NSS_BUILTINS_LIBRARY_VERSION_MAJOR)
+ || (info.libraryVersion.major == NSS_BUILTINS_LIBRARY_VERSION_MAJOR
+ && info.libraryVersion.minor < NSS_BUILTINS_LIBRARY_VERSION_MINOR)) {
+ PRInt32 modType;
+
+ SECMOD_DeleteModule (RootsModule->commonName, &modType);
+
+ RootsModule = NULL;
+ }
+ }
+ }
+
+ if (!RootsModule) {
+#ifndef G_OS_WIN32
+ /* grovel in various places for mozilla's built-in
+ * cert module.
+ *
+ * XXX yes this is gross. *sigh *
+ */
+ const gchar *paths_to_check[] = {
+#ifdef MOZILLA_NSS_LIB_DIR
+ MOZILLA_NSS_LIB_DIR,
+#endif
+ "/usr/lib",
+ "/usr/lib/mozilla",
+ "/opt/mozilla/lib",
+ "/opt/mozilla/lib/mozilla"
+ };
+
+ for (i = 0; i < G_N_ELEMENTS (paths_to_check); i++) {
+ gchar *dll_path = g_module_build_path (paths_to_check[i], "nssckbi");
+
+ if (g_file_test (dll_path, G_FILE_TEST_EXISTS)) {
+ PRInt32 modType;
+
+ /* Delete the existing module */
+ SECMOD_DeleteModule ("Mozilla Root Certs", &modType);
+
+ SECMOD_AddNewModule ("Mozilla Root Certs",dll_path, 0, 0);
+ g_free (dll_path);
+ break;
+ }
+
+ g_free (dll_path);
+ }
+#else
+ /* FIXME: Might be useful to look up if there is a
+ * Mozilla installation on the machine and use the
+ * nssckbi.dll from there.
+ */
+#endif
+ }
+}
+
+static void
+e_cert_db_class_init (ECertDBClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ initialize_nss ();
+ /* check to see if you have a rootcert module installed */
+ install_loadable_roots ();
+
+ e_cert_db_signals[PK11_PASSWD] = g_signal_new (
+ "pk11_passwd",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECertDBClass, pk11_passwd),
+ NULL, NULL,
+ e_marshal_BOOLEAN__POINTER_BOOLEAN_POINTER,
+ G_TYPE_BOOLEAN, 3,
+ G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER);
+
+ e_cert_db_signals[PK11_CHANGE_PASSWD] = g_signal_new (
+ "pk11_change_passwd",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECertDBClass, pk11_change_passwd),
+ NULL, NULL,
+ e_marshal_BOOLEAN__POINTER_POINTER,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_POINTER, G_TYPE_POINTER);
+
+ e_cert_db_signals[CONFIRM_CA_CERT_IMPORT] = g_signal_new (
+ "confirm_ca_cert_import",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECertDBClass, confirm_ca_cert_import),
+ NULL, NULL,
+ e_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER,
+ G_TYPE_BOOLEAN, 4,
+ G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
+}
+
+static void
+e_cert_db_init (ECertDB *ec)
+{
+}
+
+GMutex init_mutex;
+static ECertDB *cert_db = NULL;
+
+ECertDB *
+e_cert_db_peek (void)
+{
+ g_mutex_lock (&init_mutex);
+ if (!cert_db)
+ cert_db = g_object_new (E_TYPE_CERT_DB, NULL);
+ g_mutex_unlock (&init_mutex);
+
+ return cert_db;
+}
+
+void
+e_cert_db_shutdown (void)
+{
+ /* XXX */
+}
+
+/* searching for certificates */
+ECert *
+e_cert_db_find_cert_by_nickname (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker;*/
+ CERTCertificate *cert = NULL;
+
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));*/
+ cert = PK11_FindCertFromNickname ((gchar *) nickname, NULL);
+ if (!cert) {
+ cert = CERT_FindCertByNickname (CERT_GetDefaultCertDB (), (gchar *) nickname);
+ }
+
+ if (cert) {
+ /* PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));*/
+ ECert *ecert = e_cert_new (cert);
+ return ecert;
+ }
+ else {
+ set_nss_error (error);
+ return NULL;
+ }
+}
+
+#ifdef notyet
+ECert *
+e_cert_db_find_cert_by_key (ECertDB *certdb,
+ const gchar *db_key,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker;*/
+ SECItem keyItem = {siBuffer, NULL, 0};
+ SECItem *dummy;
+ CERTIssuerAndSN issuerSN;
+ gulong moduleID,slotID;
+ CERTCertificate *cert;
+
+ if (!db_key) {
+ set_nss_error (error);
+ return NULL;
+ }
+
+ dummy = NSSBase64_DecodeBuffer (
+ NULL, &keyItem, db_key,
+ (PRUint32) PL_strlen (db_key));
+
+ /* someday maybe we can speed up the search using the moduleID and slotID*/
+ moduleID = NS_NSS_GET_LONG (keyItem.data);
+ slotID = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG]);
+
+ /* build the issuer/SN structure*/
+ issuerSN.serialNumber.len = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG *2]);
+ issuerSN.derIssuer.len = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG *3]);
+ issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG *4];
+ issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG *4+
+ issuerSN.serialNumber.len];
+
+ cert = CERT_FindCertByIssuerAndSN (CERT_GetDefaultCertDB (), &issuerSN);
+ PR_FREEIF (keyItem.data);
+ if (cert) {
+ ECert *ecert = e_cert_new (cert);
+ return e_cert;
+ }
+
+ set_nss_error (error);
+ return NULL;
+}
+
+GList *
+e_cert_db_get_cert_nicknames (ECertDB *certdb,
+ ECertType cert_type,
+ GError **error)
+{
+}
+
+ECert *
+e_cert_db_find_email_encryption_cert (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error)
+{
+}
+
+ECert *
+e_cert_db_find_email_signing_cert (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error)
+{
+}
+#endif
+
+ECert *
+e_cert_db_find_cert_by_email_address (ECertDB *certdb,
+ const gchar *email,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+ ECert *cert;
+ CERTCertificate *any_cert;
+ CERTCertList *certlist;
+
+ any_cert = CERT_FindCertByNicknameOrEmailAddr (
+ CERT_GetDefaultCertDB (), (gchar *) email);
+
+ if (!any_cert) {
+ set_nss_error (error);
+ return NULL;
+ }
+
+ /* any_cert now contains a cert with the right subject,
+ * but it might not have the correct usage. */
+ certlist = CERT_CreateSubjectCertList (
+ NULL,
+ CERT_GetDefaultCertDB (),
+ &any_cert->derSubject,
+ PR_Now (), PR_TRUE);
+ if (!certlist) {
+ set_nss_error (error);
+ CERT_DestroyCertificate (any_cert);
+ return NULL;
+ }
+
+ if (SECSuccess != CERT_FilterCertListByUsage (
+ certlist, certUsageEmailRecipient, PR_FALSE)) {
+ set_nss_error (error);
+ CERT_DestroyCertificate (any_cert);
+ CERT_DestroyCertList (certlist);
+ return NULL;
+ }
+
+ if (CERT_LIST_END (CERT_LIST_HEAD (certlist), certlist)) {
+ set_nss_error (error);
+ CERT_DestroyCertificate (any_cert);
+ CERT_DestroyCertList (certlist);
+ return NULL;
+ }
+
+ cert = e_cert_new (CERT_DupCertificate (CERT_LIST_HEAD (certlist)->cert));
+
+ CERT_DestroyCertList (certlist);
+ CERT_DestroyCertificate (any_cert);
+
+ return cert;
+}
+
+static gboolean
+confirm_download_ca_cert (ECertDB *cert_db,
+ ECert *cert,
+ gboolean *trust_ssl,
+ gboolean *trust_email,
+ gboolean *trust_objsign)
+{
+ gboolean rv = FALSE;
+
+ *trust_ssl =
+ *trust_email =
+ *trust_objsign = FALSE;
+
+ g_signal_emit (
+ e_cert_db_peek (),
+ e_cert_db_signals[CONFIRM_CA_CERT_IMPORT], 0,
+ cert,
+ trust_ssl,
+ trust_email,
+ trust_objsign,
+ &rv);
+
+ return rv;
+}
+
+static gboolean
+handle_ca_cert_download (ECertDB *cert_db,
+ GList *certs,
+ GError **error)
+{
+ ECert *certToShow;
+ SECItem der;
+ gchar *raw_der = NULL;
+ CERTCertificate *tmpCert;
+
+ /* First thing we have to do is figure out which certificate
+ * we're gonna present to the user. The CA may have sent down
+ * a list of certs which may or may not be a chained list of
+ * certs. Until the day we can design some solid UI for the
+ * general case, we'll code to the > 90% case. That case is
+ * where a CA sends down a list that is a chain up to its root
+ * in either ascending or descending order. What we're gonna
+ * do is compare the first 2 entries, if the first was signed
+ * by the second, we assume the leaf cert is the first cert
+ * and display it. If the second cert was signed by the first
+ * cert, then we assume the first cert is the root and the
+ * last cert in the array is the leaf. In this case we
+ * display the last cert.
+ */
+
+ /* nsNSSShutDownPreventionLock locker;*/
+
+ if (certs == NULL) {
+ g_warning ("Didn't get any certs to import.");
+ return TRUE;
+ }
+ else if (certs->next == NULL) {
+ /* there's 1 cert */
+ certToShow = E_CERT (certs->data);
+ }
+ else {
+ /* there are multiple certs */
+ ECert *cert0;
+ ECert *cert1;
+ const gchar * cert0SubjectName;
+ const gchar * cert0IssuerName;
+ const gchar * cert1SubjectName;
+ const gchar * cert1IssuerName;
+
+ cert0 = E_CERT (certs->data);
+ cert1 = E_CERT (certs->next->data);
+
+ cert0IssuerName = e_cert_get_issuer_name (cert0);
+ cert0SubjectName = e_cert_get_subject_name (cert0);
+
+ cert1IssuerName = e_cert_get_issuer_name (cert1);
+ cert1SubjectName = e_cert_get_subject_name (cert1);
+
+ if (!strcmp (cert1IssuerName, cert0SubjectName)) {
+ /* In this case, the first cert in the list signed the second,
+ * so the first cert is the root. Let's display the last cert
+ * in the list. */
+ certToShow = E_CERT (g_list_last (certs)->data);
+ }
+ else if (!strcmp (cert0IssuerName, cert1SubjectName)) {
+ /* In this case the second cert has signed the first cert. The
+ * first cert is the leaf, so let's display it. */
+ certToShow = cert0;
+ } else {
+ /* It's not a chain, so let's just show the first one in the
+ * downloaded list. */
+ certToShow = cert0;
+ }
+ }
+
+ if (!certToShow) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ if (!e_cert_get_raw_der (certToShow, &raw_der, &der.len)) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ der.data = (guchar *) raw_der;
+
+ {
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));*/
+ CERTCertDBHandle *certdb = CERT_GetDefaultCertDB ();
+ tmpCert = CERT_FindCertByDERCert (certdb, &der);
+ if (!tmpCert) {
+ tmpCert = CERT_NewTempCertificate (
+ certdb, &der,
+ NULL, PR_FALSE, PR_TRUE);
+ }
+ if (!tmpCert) {
+ g_warning ("Couldn't create cert from DER blob");
+ set_nss_error (error);
+ return FALSE;
+ }
+ }
+
+#if 0
+ CERTCertificateCleaner tmpCertCleaner (tmpCert);
+#endif
+
+ if (tmpCert->isperm) {
+ if (error && !*error)
+ *error = g_error_new_literal (E_CERTDB_ERROR, 0, _("Certificate already exists"));
+ return FALSE;
+ }
+ else {
+ gboolean trust_ssl, trust_email, trust_objsign;
+ gchar *nickname;
+ SECStatus srv;
+ CERTCertTrust trust;
+
+ if (!confirm_download_ca_cert (
+ cert_db, certToShow, &trust_ssl,
+ &trust_email, &trust_objsign)) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));*/
+
+ nickname = CERT_MakeCANickname (tmpCert);
+
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));*/
+
+ e_cert_trust_init (&trust);
+ e_cert_trust_set_valid_ca (&trust);
+ e_cert_trust_add_ca_trust (
+ &trust,
+ trust_ssl,
+ trust_email,
+ trust_objsign);
+
+ srv = CERT_AddTempCertToPerm (
+ tmpCert,
+ nickname,
+ &trust);
+
+ /* If we aren't logged into the token, then what *should*
+ * happen is the above call should fail, and we should
+ * authenticate and then try again. But see NSS bug #595861.
+ * With NSS 3.12.6 at least, the above call will fail, but
+ * it *will* have added the cert to the database, with
+ * random trust bits. We have to authenticate and then set
+ * the trust bits correctly. And calling
+ * CERT_AddTempCertToPerm() again doesn't work either -- it'll
+ * fail even though it arguably ought to succeed (which is
+ * probably another NSS bug).
+ * So if we get SEC_ERROR_TOKEN_NOT_LOGGED_IN, we first try
+ * CERT_ChangeCertTrust(), and if that doesn't work we hope
+ * we're on a fixed version of NSS and we try calling
+ * CERT_AddTempCertToPerm() again instead. */
+ if (srv != SECSuccess &&
+ PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
+ e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ())) {
+ srv = CERT_ChangeCertTrust (
+ CERT_GetDefaultCertDB (),
+ tmpCert, &trust);
+ if (srv != SECSuccess)
+ srv = CERT_AddTempCertToPerm (
+ tmpCert,
+ nickname,
+ &trust);
+ }
+ if (srv != SECSuccess) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+#if 0
+ /* Now it's time to add the rest of the certs we just downloaded.
+ * Since we didn't prompt the user about any of these certs, we
+ * won't set any trust bits for them. */
+ e_cert_trust_init (&trust);
+ e_cert_trust_set_valid_ca (&trust);
+ e_cert_trusts_add_ca_trust (&trust, 0, 0, 0);
+ for (PRUint32 i = 0; i < numCerts; i++) {
+ if (i == selCertIndex)
+ continue;
+
+ certToShow = do_QueryElementAt (x509Certs, i);
+ certToShow->GetRawDER (&der.len, (PRUint8 **) &der.data);
+
+ CERTCertificate *tmpCert2 =
+ CERT_NewTempCertificate (certdb, &der, nsnull, PR_FALSE, PR_TRUE);
+
+ if (!tmpCert2) {
+ NS_ASSERTION (0, "Couldn't create temp cert from DER blob\n");
+ continue; /* Let's try to import the rest of 'em */
+ }
+ nickname.Adopt (CERT_MakeCANickname (tmpCert2));
+ CERT_AddTempCertToPerm (
+ tmpCert2, NS_CONST_CAST (gchar *,nickname.get ()),
+ defaultTrust.GetTrust ());
+ CERT_DestroyCertificate (tmpCert2);
+ }
+#endif
+ return TRUE;
+ }
+}
+gboolean e_cert_db_change_cert_trust (CERTCertificate *cert, CERTCertTrust *trust)
+{
+ SECStatus srv;
+
+ srv = CERT_ChangeCertTrust (
+ CERT_GetDefaultCertDB (),
+ cert, trust);
+ if (srv != SECSuccess &&
+ PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
+ e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ()))
+ srv = CERT_ChangeCertTrust (
+ CERT_GetDefaultCertDB (),
+ cert, trust);
+
+ if (srv != SECSuccess) {
+ glong err = PORT_GetError ();
+ g_warning (
+ "CERT_ChangeCertTrust() failed: %s\n",
+ nss_error_to_string (err));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* deleting certificates */
+gboolean
+e_cert_db_delete_cert (ECertDB *certdb,
+ ECert *ecert)
+{
+ /* nsNSSShutDownPreventionLock locker;
+ * nsNSSCertificate *nssCert = NS_STATIC_CAST (nsNSSCertificate *, aCert); */
+
+ CERTCertificate *cert;
+
+ if (!e_cert_mark_for_deletion (ecert)) {
+ return FALSE;
+ }
+
+ cert = e_cert_get_internal_cert (ecert);
+ if (cert->slot && e_cert_get_cert_type (ecert) != E_CERT_USER) {
+ /* To delete a cert of a slot (builtin, most likely), mark it as
+ * completely untrusted. This way we keep a copy cached in the
+ * local database, and next time we try to load it off of the
+ * external token/slot, we'll know not to trust it. We don't
+ * want to do that with user certs, because a user may re-store
+ * the cert onto the card again at which point we *will* want to
+ * trust that cert if it chains up properly. */
+ CERTCertTrust trust;
+
+ e_cert_trust_init_with_values (&trust, 0, 0, 0);
+ return e_cert_db_change_cert_trust (cert, &trust);
+ }
+
+ return TRUE;
+}
+
+/* importing certificates */
+gboolean
+e_cert_db_import_certs (ECertDB *certdb,
+ gchar *data,
+ guint32 length,
+ ECertType cert_type,
+ GSList **imported_certs,
+ GError **error)
+{
+ /*nsNSSShutDownPreventionLock locker;*/
+ PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+ GList *certs = NULL;
+ CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
+ gint i;
+ gboolean rv;
+
+ if (!certCollection) {
+ set_nss_error (error);
+ PORT_FreeArena (arena, PR_FALSE);
+ return FALSE;
+ }
+
+ /* Now let's create some certs to work with */
+ for (i = 0; i < certCollection->numcerts; i++) {
+ SECItem *currItem = &certCollection->rawCerts[i];
+ ECert *cert;
+
+ cert = e_cert_new_from_der ((gchar *) currItem->data, currItem->len);
+ if (!cert) {
+ set_nss_error (error);
+ g_list_foreach (certs, (GFunc) g_object_unref, NULL);
+ g_list_free (certs);
+ PORT_FreeArena (arena, PR_FALSE);
+ return FALSE;
+ }
+ certs = g_list_append (certs, cert);
+ }
+ switch (cert_type) {
+ case E_CERT_CA:
+ rv = handle_ca_cert_download (certdb, certs, error);
+ if (rv && imported_certs) {
+ GList *l;
+
+ /* copy certificates to the caller */
+ *imported_certs = NULL;
+ for (l = certs; l; l = l->next) {
+ ECert *cert = l->data;
+
+ if (cert)
+ *imported_certs = g_slist_prepend (*imported_certs, g_object_ref (cert));
+ }
+
+ *imported_certs = g_slist_reverse (*imported_certs);
+ }
+ break;
+ default:
+ /* We only deal with import CA certs in this method currently.*/
+ set_nss_error (error);
+ PORT_FreeArena (arena, PR_FALSE);
+ rv = FALSE;
+ }
+
+ g_list_foreach (certs, (GFunc) g_object_unref, NULL);
+ g_list_free (certs);
+ PORT_FreeArena (arena, PR_FALSE);
+ return rv;
+}
+
+gboolean
+e_cert_db_import_email_cert (ECertDB *certdb,
+ gchar *data,
+ guint32 length,
+ GSList **imported_certs,
+ GError **error)
+{
+ /*nsNSSShutDownPreventionLock locker;*/
+ SECStatus srv = SECFailure;
+ gboolean rv = TRUE;
+ CERTCertificate * cert;
+ SECItem **rawCerts;
+ gint numcerts;
+ gint i;
+ PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+ CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
+
+ if (!certCollection) {
+ set_nss_error (error);
+ PORT_FreeArena (arena, PR_FALSE);
+ return FALSE;
+ }
+
+ cert = CERT_NewTempCertificate (
+ CERT_GetDefaultCertDB (), certCollection->rawCerts,
+ (gchar *) NULL, PR_FALSE, PR_TRUE);
+ if (!cert) {
+ set_nss_error (error);
+ rv = FALSE;
+ goto loser;
+ }
+ numcerts = certCollection->numcerts;
+ rawCerts = (SECItem **) PORT_Alloc (sizeof (SECItem *) * numcerts);
+ if (!rawCerts) {
+ set_nss_error (error);
+ rv = FALSE;
+ goto loser;
+ }
+
+ for (i = 0; i < numcerts; i++) {
+ rawCerts[i] = &certCollection->rawCerts[i];
+ }
+
+ srv = CERT_ImportCerts (
+ CERT_GetDefaultCertDB (), certUsageEmailSigner,
+ numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
+ NULL);
+ if (srv != SECSuccess) {
+ set_nss_error (error);
+ rv = FALSE;
+ goto loser;
+ }
+ CERT_SaveSMimeProfile (cert, NULL, NULL);
+
+ if (imported_certs) {
+ *imported_certs = NULL;
+ for (i = 0; i < certCollection->numcerts; i++) {
+ SECItem *currItem = &certCollection->rawCerts[i];
+ ECert *cert;
+
+ cert = e_cert_new_from_der ((gchar *) currItem->data, currItem->len);
+ if (cert)
+ *imported_certs = g_slist_prepend (*imported_certs, cert);
+ }
+
+ *imported_certs = g_slist_reverse (*imported_certs);
+ }
+
+ PORT_Free (rawCerts);
+ loser:
+ if (cert)
+ CERT_DestroyCertificate (cert);
+ if (arena)
+ PORT_FreeArena (arena, PR_TRUE);
+ return rv;
+}
+
+static gchar *
+default_nickname (CERTCertificate *cert)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+ gchar *username = NULL;
+ gchar *caname = NULL;
+ gchar *nickname = NULL;
+ gchar *tmp = NULL;
+ gint count;
+ const gchar *nickFmt = NULL;
+ CERTCertificate *dummycert;
+ PK11SlotInfo *slot = NULL;
+ CK_OBJECT_HANDLE keyHandle;
+
+ CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB ();
+
+ username = CERT_GetCommonName (&cert->subject);
+ if (username == NULL)
+ username = PL_strdup ("");
+
+ if (username == NULL)
+ goto loser;
+
+ caname = CERT_GetOrgName (&cert->issuer);
+ if (caname == NULL)
+ caname = PL_strdup ("");
+
+ if (caname == NULL)
+ goto loser;
+
+ count = 1;
+
+ nickFmt = "%1$s's %2$s ID";
+
+ nickname = PR_smprintf (nickFmt, username, caname);
+ /*
+ * We need to see if the private key exists on a token, if it does
+ * then we need to check for nicknames that already exist on the smart
+ * card.
+ */
+ slot = PK11_KeyForCertExists (cert, &keyHandle, NULL);
+ if (slot == NULL) {
+ goto loser;
+ }
+ if (!PK11_IsInternal (slot)) {
+ tmp = PR_smprintf ("%s:%s", PK11_GetTokenName (slot), nickname);
+ PR_Free (nickname);
+ nickname = tmp;
+ tmp = NULL;
+ }
+ tmp = nickname;
+ while (1) {
+ if (count > 1) {
+ nickname = PR_smprintf ("%s #%d", tmp, count);
+ }
+
+ if (nickname == NULL)
+ goto loser;
+
+ if (PK11_IsInternal (slot)) {
+ /* look up the nickname to make sure it isn't in use already */
+ dummycert = CERT_FindCertByNickname (defaultcertdb, nickname);
+
+ } else {
+ /*
+ * Check the cert against others that already live on the smart
+ * card.
+ */
+ dummycert = PK11_FindCertFromNickname (nickname, NULL);
+ if (dummycert != NULL) {
+ /*
+ * Make sure the subject names are different.
+ */
+ if (CERT_CompareName (&cert->subject, &dummycert->subject) == SECEqual) {
+ /*
+ * There is another certificate with the same nickname and
+ * the same subject name on the smart card, so let's use this
+ * nickname.
+ */
+ CERT_DestroyCertificate (dummycert);
+ dummycert = NULL;
+ }
+ }
+ }
+ if (dummycert == NULL)
+ goto done;
+
+ /* found a cert, destroy it and loop */
+ CERT_DestroyCertificate (dummycert);
+ if (tmp != nickname) PR_Free (nickname);
+ count++;
+ } /* end of while (1) */
+
+ loser:
+ if (nickname) {
+ PR_Free (nickname);
+ }
+ nickname = NULL;
+ done:
+ if (caname) {
+ PR_Free (caname);
+ }
+ if (username) {
+ PR_Free (username);
+ }
+ if (slot != NULL) {
+ PK11_FreeSlot (slot);
+ if (nickname != NULL) {
+ tmp = nickname;
+ nickname = strchr (tmp, ':');
+ if (nickname != NULL) {
+ nickname++;
+ nickname = PL_strdup (nickname);
+ PR_Free (tmp);
+ tmp = NULL;
+ } else {
+ nickname = tmp;
+ tmp = NULL;
+ }
+ }
+ }
+ PR_FREEIF (tmp);
+ return (nickname);
+}
+
+gboolean
+e_cert_db_import_user_cert (ECertDB *certdb,
+ gchar *data,
+ guint32 length,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker;*/
+ PK11SlotInfo *slot;
+ gchar * nickname = NULL;
+ gboolean rv = FALSE;
+ gint numCACerts;
+ SECItem *CACerts;
+ CERTDERCerts * collectArgs;
+ PRArenaPool *arena;
+ CERTCertificate * cert = NULL;
+
+ arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ set_nss_error (error);
+ goto loser;
+ }
+
+ collectArgs = e_cert_db_get_certs_from_package (arena, data, length);
+ if (!collectArgs) {
+ set_nss_error (error);
+ goto loser;
+ }
+
+ cert = CERT_NewTempCertificate (
+ CERT_GetDefaultCertDB (), collectArgs->rawCerts,
+ (gchar *) NULL, PR_FALSE, PR_TRUE);
+ if (!cert) {
+ set_nss_error (error);
+ goto loser;
+ }
+
+ slot = PK11_KeyForCertExists (cert, NULL, NULL);
+ if (slot == NULL) {
+ set_nss_error (error);
+ goto loser;
+ }
+ PK11_FreeSlot (slot);
+
+ /* pick a nickname for the cert */
+ if (cert->nickname) {
+ /* sigh, we need a call to look up other certs with this subject and
+ * identify nicknames from them. We can no longer walk down internal
+ * database structures rjr */
+ nickname = cert->nickname;
+ }
+ else {
+ nickname = default_nickname (cert);
+ }
+
+ /* user wants to import the cert */
+ slot = PK11_ImportCertForKey (cert, nickname, NULL);
+ if (!slot) {
+ set_nss_error (error);
+ goto loser;
+ }
+ PK11_FreeSlot (slot);
+ numCACerts = collectArgs->numcerts - 1;
+
+ if (numCACerts) {
+ CACerts = collectArgs->rawCerts + 1;
+ if (!CERT_ImportCAChain (CACerts, numCACerts, certUsageUserCertImport)) {
+ rv = TRUE;
+ }
+ }
+
+ loser:
+ if (arena) {
+ PORT_FreeArena (arena, PR_FALSE);
+ }
+ if (cert) {
+ CERT_DestroyCertificate (cert);
+ }
+ return rv;
+}
+
+gboolean
+e_cert_db_import_server_cert (ECertDB *certdb,
+ gchar *data,
+ guint32 length,
+ GSList **imported_certs,
+ GError **error)
+{
+ /* not c&p'ing this over at the moment, as we don't have a UI
+ * for server certs anyway */
+ return FALSE;
+}
+
+gboolean
+e_cert_db_import_certs_from_file (ECertDB *cert_db,
+ const gchar *file_path,
+ ECertType cert_type,
+ GSList **imported_certs,
+ GError **error)
+{
+ gboolean rv;
+ gint fd;
+ struct stat sb;
+ gchar *buf;
+ gint bytes_read;
+
+ switch (cert_type) {
+ case E_CERT_CA:
+ case E_CERT_CONTACT:
+ case E_CERT_SITE:
+ /* good */
+ break;
+
+ default:
+ /* not supported (yet) */
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ fd = g_open (file_path, O_RDONLY | O_BINARY, 0);
+ if (fd == -1) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ if (-1 == fstat (fd, &sb)) {
+ set_nss_error (error);
+ close (fd);
+ return FALSE;
+ }
+
+ buf = g_malloc (sb.st_size);
+ if (!buf) {
+ set_nss_error (error);
+ close (fd);
+ return FALSE;
+ }
+
+ bytes_read = read (fd, buf, sb.st_size);
+
+ close (fd);
+
+ if (bytes_read != sb.st_size) {
+ set_nss_error (error);
+ rv = FALSE;
+ }
+ else {
+ printf ("importing %d bytes from '%s'\n", bytes_read, file_path);
+
+ switch (cert_type) {
+ case E_CERT_CA:
+ rv = e_cert_db_import_certs (cert_db, buf, bytes_read, cert_type, imported_certs, error);
+ break;
+
+ case E_CERT_SITE:
+ rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, imported_certs, error);
+ break;
+
+ case E_CERT_CONTACT:
+ rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, imported_certs, error);
+ break;
+
+ default:
+ rv = FALSE;
+ break;
+ }
+ }
+
+ g_free (buf);
+ return rv;
+}
+
+gboolean
+e_cert_db_import_pkcs12_file (ECertDB *cert_db,
+ const gchar *file_path,
+ GError **error)
+{
+ EPKCS12 *pkcs12 = e_pkcs12_new ();
+ GError *e = NULL;
+
+ if (!e_pkcs12_import_from_file (pkcs12, file_path, &e)) {
+ g_propagate_error (error, e);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#ifdef notyet
+gboolean
+e_cert_db_export_pkcs12_file (ECertDB *cert_db,
+ const gchar *file_path,
+ GList *certs,
+ GError **error)
+{
+}
+#endif
+
+gboolean
+e_cert_db_login_to_slot (ECertDB *cert_db,
+ PK11SlotInfo *slot)
+{
+ if (PK11_NeedLogin (slot)) {
+ PK11_Logout (slot);
+
+ if (PK11_NeedUserInit (slot)) {
+ gchar *pwd;
+ gboolean rv = FALSE;
+
+ printf ("initializing slot password\n");
+
+ g_signal_emit (
+ e_cert_db_peek (),
+ e_cert_db_signals[PK11_CHANGE_PASSWD], 0,
+ NULL,
+ &pwd,
+ &rv);
+
+ if (!rv)
+ return FALSE;
+
+ /* the user needs to specify the initial password */
+ PK11_InitPin (slot, "", pwd);
+ }
+
+ PK11_SetPasswordFunc (pk11_password);
+ if (PK11_Authenticate (slot, PR_TRUE, NULL) != SECSuccess) {
+ printf (
+ "PK11_Authenticate failed (err = %d/%d)\n",
+ PORT_GetError (), PORT_GetError () + 0x2000);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/smime/lib/e-cert-db.h b/smime/lib/e-cert-db.h
new file mode 100644
index 0000000000..26d0a25c2a
--- /dev/null
+++ b/smime/lib/e-cert-db.h
@@ -0,0 +1,148 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _E_CERT_DB_H_
+#define _E_CERT_DB_H_
+
+#include <glib-object.h>
+#include "e-cert.h"
+#include <cert.h>
+
+#define E_TYPE_CERT_DB (e_cert_db_get_type ())
+#define E_CERT_DB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CERT_DB, ECertDB))
+#define E_CERT_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CERT_DB, ECertDBClass))
+#define E_IS_CERT_DB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CERT_DB))
+#define E_IS_CERT_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CERT_DB))
+#define E_CERT_DB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CERT_DB, ECertDBClass))
+
+#define E_CERTDB_ERROR e_certdb_error_quark()
+GQuark e_certdb_error_quark (void) G_GNUC_CONST;
+
+typedef struct _ECertDB ECertDB;
+typedef struct _ECertDBClass ECertDBClass;
+typedef struct _ECertDBPrivate ECertDBPrivate;
+
+struct _ECertDB {
+ GObject parent;
+
+ ECertDBPrivate *priv;
+};
+
+struct _ECertDBClass {
+ GObjectClass parent_class;
+
+ /* signals */
+ gboolean (*pk11_passwd) (ECertDB *db, PK11SlotInfo *slot, gboolean retry, gchar **passwd);
+ gboolean (*pk11_change_passwd) (ECertDB *db, gchar **orig_passwd, gchar **passwd);
+ gboolean (*confirm_ca_cert_import) (ECertDB *db, ECert *cert, gboolean *trust_ssl, gboolean *trust_email, gboolean *trust_objsign);
+
+ /* Padding for future expansion */
+ void (*_ecert_reserved0) (void);
+ void (*_ecert_reserved1) (void);
+ void (*_ecert_reserved2) (void);
+ void (*_ecert_reserved3) (void);
+ void (*_ecert_reserved4) (void);
+};
+
+GType e_cert_db_get_type (void);
+
+/* single instance */
+ECertDB * e_cert_db_peek (void);
+
+void e_cert_db_shutdown (void);
+
+/* searching for certificates */
+ECert * e_cert_db_find_cert_by_nickname (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error);
+
+#ifdef notyet
+ECert * e_cert_db_find_cert_by_key (ECertDB *certdb,
+ const gchar *db_key,
+ GError **error);
+
+GList * e_cert_db_get_cert_nicknames (ECertDB *certdb,
+ ECertType cert_type,
+ GError **error);
+
+ECert * e_cert_db_find_email_encryption_cert (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error);
+
+ECert * e_cert_db_find_email_signing_cert (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error);
+#endif
+
+ECert * e_cert_db_find_cert_by_email_address (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error);
+
+/* deleting certificates */
+gboolean e_cert_db_delete_cert (ECertDB *certdb,
+ ECert *cert);
+
+/* importing certificates */
+gboolean e_cert_db_import_certs (ECertDB *certdb,
+ gchar *data, guint32 length,
+ ECertType cert_type,
+ GSList **imported_certs,
+ GError **error);
+
+gboolean e_cert_db_import_email_cert (ECertDB *certdb,
+ gchar *data, guint32 length,
+ GSList **imported_certs,
+ GError **error);
+
+gboolean e_cert_db_import_user_cert (ECertDB *certdb,
+ gchar *data, guint32 length,
+ GError **error);
+
+gboolean e_cert_db_import_server_cert (ECertDB *certdb,
+ gchar *data, guint32 length,
+ GSList **imported_certs,
+ GError **error);
+
+gboolean e_cert_db_import_certs_from_file (ECertDB *cert_db,
+ const gchar *file_path,
+ ECertType cert_type,
+ GSList **imported_certs,
+ GError **error);
+
+gboolean e_cert_db_import_pkcs12_file (ECertDB *cert_db,
+ const gchar *file_path,
+ GError **error);
+
+#ifdef notyet
+gboolean e_cert_db_export_pkcs12_file (ECertDB *cert_db,
+ const gchar *file_path,
+ GList *certs,
+ GError **error);
+#endif
+
+gboolean e_cert_db_login_to_slot (ECertDB *cert_db,
+ PK11SlotInfo *slot);
+
+gboolean e_cert_db_change_cert_trust (CERTCertificate *cert,
+ CERTCertTrust *trust);
+
+#endif /* _E_CERT_DB_H_ */
diff --git a/smime/lib/e-cert-trust.c b/smime/lib/e-cert-trust.c
new file mode 100644
index 0000000000..e99c5c4047
--- /dev/null
+++ b/smime/lib/e-cert-trust.c
@@ -0,0 +1,471 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* The following is the mozilla license blurb, as the bodies some of
+ * these functions were derived from the mozilla source. */
+/*
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+/*
+ * Author: Chris Toshok (toshok@ximian.com)
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cert-trust.h"
+
+void
+e_cert_trust_init (CERTCertTrust *trust)
+{
+ memset (trust, 0, sizeof (CERTCertTrust));
+}
+
+void
+e_cert_trust_init_with_values (CERTCertTrust *trust,
+ guint ssl,
+ guint email,
+ guint objsign)
+{
+ memset (trust, 0, sizeof (CERTCertTrust));
+ e_cert_trust_add_trust (&trust->sslFlags, ssl);
+ e_cert_trust_add_trust (&trust->emailFlags, email);
+ e_cert_trust_add_trust (&trust->objectSigningFlags, objsign);
+}
+
+void
+e_cert_trust_copy (CERTCertTrust *trust,
+ CERTCertTrust *t)
+{
+ if (t)
+ memcpy (trust, t, sizeof (CERTCertTrust));
+ else
+ memset (trust, 0, sizeof (CERTCertTrust));
+}
+
+void
+e_cert_trust_add_ca_trust (CERTCertTrust *trust,
+ PRBool ssl,
+ PRBool email,
+ PRBool objSign)
+{
+ if (ssl) {
+ e_cert_trust_add_trust (
+ &trust->sslFlags, CERTDB_TRUSTED_CA);
+ e_cert_trust_add_trust (
+ &trust->sslFlags, CERTDB_TRUSTED_CLIENT_CA);
+ }
+
+ if (email) {
+ e_cert_trust_add_trust (
+ &trust->emailFlags, CERTDB_TRUSTED_CA);
+ e_cert_trust_add_trust (
+ &trust->emailFlags, CERTDB_TRUSTED_CLIENT_CA);
+ }
+
+ if (objSign) {
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags, CERTDB_TRUSTED_CA);
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags, CERTDB_TRUSTED_CLIENT_CA);
+ }
+}
+
+void
+e_cert_trust_add_peer_trust (CERTCertTrust *trust,
+ PRBool ssl,
+ PRBool email,
+ PRBool objSign)
+{
+ if (ssl)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_TRUSTED);
+ if (email)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_TRUSTED);
+ if (objSign)
+ e_cert_trust_add_trust (&trust->objectSigningFlags, CERTDB_TRUSTED);
+}
+
+void
+e_cert_trust_set_ssl_trust (CERTCertTrust *trust,
+ PRBool peer,
+ PRBool tPeer,
+ PRBool ca,
+ PRBool tCA,
+ PRBool tClientCA,
+ PRBool user,
+ PRBool warn)
+{
+ trust->sslFlags = 0;
+ if (peer || tPeer)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_TERMINAL_RECORD);
+ if (tPeer)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_TRUSTED);
+ if (ca || tCA)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_VALID_CA);
+ if (tClientCA)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_TRUSTED_CLIENT_CA);
+ if (tCA)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_TRUSTED_CA);
+ if (user)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_USER);
+ if (warn)
+ e_cert_trust_add_trust (&trust->sslFlags, CERTDB_SEND_WARN);
+}
+
+void
+e_cert_trust_set_email_trust (CERTCertTrust *trust,
+ PRBool peer,
+ PRBool tPeer,
+ PRBool ca,
+ PRBool tCA,
+ PRBool tClientCA,
+ PRBool user,
+ PRBool warn)
+{
+ trust->emailFlags = 0;
+ if (peer || tPeer)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_TERMINAL_RECORD);
+ if (tPeer)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_TRUSTED);
+ if (ca || tCA)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_VALID_CA);
+ if (tClientCA)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_TRUSTED_CLIENT_CA);
+ if (tCA)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_TRUSTED_CA);
+ if (user)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_USER);
+ if (warn)
+ e_cert_trust_add_trust (&trust->emailFlags, CERTDB_SEND_WARN);
+}
+
+void
+e_cert_trust_set_objsign_trust (CERTCertTrust *trust,
+ PRBool peer,
+ PRBool tPeer,
+ PRBool ca,
+ PRBool tCA,
+ PRBool tClientCA,
+ PRBool user,
+ PRBool warn)
+{
+ trust->objectSigningFlags = 0;
+ if (peer || tPeer)
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags,
+ CERTDB_TERMINAL_RECORD);
+ if (tPeer)
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags,
+ CERTDB_TRUSTED);
+ if (ca || tCA)
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags,
+ CERTDB_VALID_CA);
+ if (tClientCA)
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags,
+ CERTDB_TRUSTED_CLIENT_CA);
+ if (tCA)
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags,
+ CERTDB_TRUSTED_CA);
+ if (user)
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags,
+ CERTDB_USER);
+ if (warn)
+ e_cert_trust_add_trust (
+ &trust->objectSigningFlags,
+ CERTDB_SEND_WARN);
+}
+
+void
+e_cert_trust_set_valid_ca (CERTCertTrust *trust)
+{
+ e_cert_trust_set_ssl_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_email_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_objsign_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+}
+
+void
+e_cert_trust_set_trusted_server_ca (CERTCertTrust *trust)
+{
+ e_cert_trust_set_ssl_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_email_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_objsign_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
+}
+
+void
+e_cert_trust_set_trusted_ca (CERTCertTrust *trust)
+{
+ e_cert_trust_set_ssl_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_TRUE, PR_TRUE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_email_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_TRUE, PR_TRUE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_objsign_trust (
+ trust, PR_FALSE, PR_FALSE, PR_TRUE,
+ PR_TRUE, PR_TRUE, PR_FALSE, PR_FALSE);
+}
+
+void
+e_cert_trust_set_valid_peer (CERTCertTrust *trust)
+{
+ e_cert_trust_set_ssl_trust (
+ trust, PR_TRUE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_email_trust (
+ trust, PR_TRUE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_objsign_trust (
+ trust, PR_TRUE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+}
+
+void
+e_cert_trust_set_valid_server_peer (CERTCertTrust *trust)
+{
+ e_cert_trust_set_ssl_trust (
+ trust, PR_TRUE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_email_trust (
+ trust, PR_FALSE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_objsign_trust (
+ trust, PR_FALSE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+}
+
+void
+e_cert_trust_set_trusted_peer (CERTCertTrust *trust)
+{
+ e_cert_trust_set_ssl_trust (
+ trust, PR_TRUE, PR_TRUE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_email_trust (
+ trust, PR_TRUE, PR_TRUE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+
+ e_cert_trust_set_objsign_trust (
+ trust, PR_TRUE, PR_TRUE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE);
+}
+
+void
+e_cert_trust_set_user (CERTCertTrust *trust)
+{
+ e_cert_trust_set_ssl_trust (
+ trust, PR_FALSE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE);
+
+ e_cert_trust_set_email_trust (
+ trust, PR_FALSE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE);
+
+ e_cert_trust_set_objsign_trust (
+ trust, PR_FALSE, PR_FALSE, PR_FALSE,
+ PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE);
+}
+
+PRBool
+e_cert_trust_has_any_ca (CERTCertTrust *trust)
+{
+ if (e_cert_trust_has_trust (trust->sslFlags, CERTDB_VALID_CA) ||
+ e_cert_trust_has_trust (trust->emailFlags, CERTDB_VALID_CA) ||
+ e_cert_trust_has_trust (trust->objectSigningFlags, CERTDB_VALID_CA))
+ return PR_TRUE;
+
+ return PR_FALSE;
+}
+
+PRBool
+e_cert_trust_has_ca (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign)
+{
+ if (checkSSL && !e_cert_trust_has_trust (
+ trust->sslFlags, CERTDB_VALID_CA))
+ return PR_FALSE;
+
+ if (checkEmail && !e_cert_trust_has_trust (
+ trust->emailFlags, CERTDB_VALID_CA))
+ return PR_FALSE;
+
+ if (checkObjSign && !e_cert_trust_has_trust (
+ trust->objectSigningFlags, CERTDB_VALID_CA))
+ return PR_FALSE;
+
+ return PR_TRUE;
+}
+
+PRBool
+e_cert_trust_has_peer (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign)
+{
+ if (checkSSL && !e_cert_trust_has_trust (
+ trust->sslFlags, CERTDB_TERMINAL_RECORD))
+ return PR_FALSE;
+
+ if (checkEmail && !e_cert_trust_has_trust (
+ trust->emailFlags, CERTDB_TERMINAL_RECORD))
+ return PR_FALSE;
+
+ if (checkObjSign && !e_cert_trust_has_trust (
+ trust->objectSigningFlags, CERTDB_TERMINAL_RECORD))
+ return PR_FALSE;
+
+ return PR_TRUE;
+}
+
+PRBool
+e_cert_trust_has_any_user (CERTCertTrust *trust)
+{
+ if (e_cert_trust_has_trust (trust->sslFlags, CERTDB_USER) ||
+ e_cert_trust_has_trust (trust->emailFlags, CERTDB_USER) ||
+ e_cert_trust_has_trust (trust->objectSigningFlags, CERTDB_USER))
+ return PR_TRUE;
+
+ return PR_FALSE;
+}
+
+PRBool
+e_cert_trust_has_user (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign)
+{
+ if (checkSSL && !e_cert_trust_has_trust (
+ trust->sslFlags, CERTDB_USER))
+ return PR_FALSE;
+
+ if (checkEmail && !e_cert_trust_has_trust (
+ trust->emailFlags, CERTDB_USER))
+ return PR_FALSE;
+
+ if (checkObjSign && !e_cert_trust_has_trust (
+ trust->objectSigningFlags, CERTDB_USER))
+ return PR_FALSE;
+
+ return PR_TRUE;
+}
+
+PRBool
+e_cert_trust_has_trusted_ca (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign)
+{
+ if (checkSSL && !(e_cert_trust_has_trust (
+ trust->sslFlags, CERTDB_TRUSTED_CA) ||
+ e_cert_trust_has_trust (
+ trust->sslFlags, CERTDB_TRUSTED_CLIENT_CA)))
+ return PR_FALSE;
+
+ if (checkEmail && !(e_cert_trust_has_trust (
+ trust->emailFlags, CERTDB_TRUSTED_CA) ||
+ e_cert_trust_has_trust (
+ trust->emailFlags, CERTDB_TRUSTED_CLIENT_CA)))
+ return PR_FALSE;
+
+ if (checkObjSign && !(e_cert_trust_has_trust (
+ trust->objectSigningFlags, CERTDB_TRUSTED_CA) ||
+ e_cert_trust_has_trust (
+ trust->objectSigningFlags, CERTDB_TRUSTED_CLIENT_CA)))
+ return PR_FALSE;
+
+ return PR_TRUE;
+}
+
+PRBool
+e_cert_trust_has_trusted_peer (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign)
+{
+ if (checkSSL && !(e_cert_trust_has_trust (
+ trust->sslFlags, CERTDB_TRUSTED)))
+ return PR_FALSE;
+
+ if (checkEmail && !(e_cert_trust_has_trust (
+ trust->emailFlags, CERTDB_TRUSTED)))
+ return PR_FALSE;
+
+ if (checkObjSign && !(e_cert_trust_has_trust (
+ trust->objectSigningFlags, CERTDB_TRUSTED)))
+ return PR_FALSE;
+
+ return PR_TRUE;
+}
+
+void
+e_cert_trust_add_trust (guint *t,
+ guint v)
+{
+ *t |= v;
+}
+
+PRBool
+e_cert_trust_has_trust (guint t,
+ guint v)
+{
+ return (t & v);
+}
+
diff --git a/smime/lib/e-cert-trust.h b/smime/lib/e-cert-trust.h
new file mode 100644
index 0000000000..71608f8415
--- /dev/null
+++ b/smime/lib/e-cert-trust.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _E_CERT_TRUST_H_
+#define _E_CERT_TRUST_H_
+
+#include <glib.h>
+#include <cert.h>
+#include <certdb.h>
+
+G_BEGIN_DECLS
+
+void e_cert_trust_init (CERTCertTrust *trust);
+void e_cert_trust_init_with_values (CERTCertTrust *trust,
+ guint ssl,
+ guint email,
+ guint objsign);
+void e_cert_trust_copy (CERTCertTrust *dst_trust, CERTCertTrust *src_trust);
+void e_cert_trust_add_ca_trust (CERTCertTrust *trust, PRBool ssl, PRBool email, PRBool objSign);
+void e_cert_trust_add_peer_trust (CERTCertTrust *trust, PRBool ssl, PRBool email, PRBool objSign);
+void e_cert_trust_set_ssl_trust (CERTCertTrust *trust,
+ PRBool peer, PRBool tPeer,
+ PRBool ca, PRBool tCA, PRBool tClientCA,
+ PRBool user, PRBool warn);
+void e_cert_trust_set_email_trust (CERTCertTrust *trust,
+ PRBool peer, PRBool tPeer,
+ PRBool ca, PRBool tCA, PRBool tClientCA,
+ PRBool user, PRBool warn);
+void e_cert_trust_set_objsign_trust (CERTCertTrust *trust,
+ PRBool peer, PRBool tPeer,
+ PRBool ca, PRBool tCA, PRBool tClientCA,
+ PRBool user, PRBool warn);
+void e_cert_trust_set_valid_ca (CERTCertTrust *trust);
+void e_cert_trust_set_trusted_server_ca (CERTCertTrust *trust);
+void e_cert_trust_set_trusted_ca (CERTCertTrust *trust);
+void e_cert_trust_set_valid_peer (CERTCertTrust *trust);
+void e_cert_trust_set_valid_server_peer (CERTCertTrust *trust);
+void e_cert_trust_set_trusted_peer (CERTCertTrust *trust);
+void e_cert_trust_set_user (CERTCertTrust *trust);
+PRBool e_cert_trust_has_any_ca (CERTCertTrust *trust);
+PRBool e_cert_trust_has_ca (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign);
+PRBool e_cert_trust_has_peer (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign);
+PRBool e_cert_trust_has_any_user (CERTCertTrust *trust);
+PRBool e_cert_trust_has_user (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign);
+PRBool e_cert_trust_has_trusted_ca (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign);
+PRBool e_cert_trust_has_trusted_peer (CERTCertTrust *trust,
+ PRBool checkSSL,
+ PRBool checkEmail,
+ PRBool checkObjSign);
+void e_cert_trust_add_trust (guint *t, guint v);
+PRBool e_cert_trust_has_trust (guint t, guint v);
+
+G_END_DECLS
+
+#endif /* _E_CERT_H_ */
diff --git a/smime/lib/e-cert.c b/smime/lib/e-cert.c
new file mode 100644
index 0000000000..969b43c9ed
--- /dev/null
+++ b/smime/lib/e-cert.c
@@ -0,0 +1,542 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* The following is the mozilla license blurb, as the bodies some of
+ * these functions were derived from the mozilla source. */
+/*
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+/*
+ * Author: Chris Toshok (toshok@ximian.com)
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <time.h>
+
+#include <glib/gi18n.h>
+
+/* for e_utf8_strftime, what about e_time_format_time? */
+#include <e-util/e-util.h>
+
+#include "e-cert.h"
+#include "e-cert-trust.h"
+#include "pk11func.h"
+#include "certdb.h"
+#include "hasht.h"
+
+#define E_CERT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CERT, ECertPrivate))
+
+struct _ECertPrivate {
+ CERTCertificate *cert;
+
+ /* pointers we cache since the nss implementation allocs the
+ * string */
+ gchar *org_name;
+ gchar *org_unit_name;
+ gchar *cn;
+
+ gchar *issuer_org_name;
+ gchar *issuer_org_unit_name;
+ gchar *issuer_cn;
+
+ PRTime issued_on;
+ PRTime expires_on;
+
+ gchar *issued_on_string;
+ gchar *expires_on_string;
+
+ gchar *serial_number;
+
+ gchar *usage_string;
+
+ gchar *sha1_fingerprint;
+ gchar *md5_fingerprint;
+
+ EASN1Object *asn1;
+
+ gboolean delete;
+};
+
+G_DEFINE_TYPE (ECert, e_cert, G_TYPE_OBJECT)
+
+static void
+e_cert_finalize (GObject *object)
+{
+ ECertPrivate *priv;
+
+ priv = E_CERT_GET_PRIVATE (object);
+
+ if (priv->org_name)
+ PORT_Free (priv->org_name);
+ if (priv->org_unit_name)
+ PORT_Free (priv->org_unit_name);
+ if (priv->cn)
+ PORT_Free (priv->cn);
+
+ if (priv->issuer_org_name)
+ PORT_Free (priv->issuer_org_name);
+ if (priv->issuer_org_unit_name)
+ PORT_Free (priv->issuer_org_unit_name);
+ if (priv->issuer_cn)
+ PORT_Free (priv->issuer_cn);
+
+ if (priv->issued_on_string)
+ PORT_Free (priv->issued_on_string);
+ if (priv->expires_on_string)
+ PORT_Free (priv->expires_on_string);
+ if (priv->serial_number)
+ PORT_Free (priv->serial_number);
+
+ g_free (priv->usage_string);
+
+ if (priv->sha1_fingerprint)
+ PORT_Free (priv->sha1_fingerprint);
+ if (priv->md5_fingerprint)
+ PORT_Free (priv->md5_fingerprint);
+
+ if (priv->asn1)
+ g_object_unref (priv->asn1);
+
+ if (priv->delete) {
+ printf ("attempting to delete cert marked for deletion\n");
+ if (e_cert_get_cert_type (E_CERT (object)) == E_CERT_USER) {
+ PK11_DeleteTokenCertAndKey (priv->cert, NULL);
+ } else if (!PK11_IsReadOnly (priv->cert->slot)) {
+ /* If the list of built-ins does contain a non-removable
+ * copy of this certificate, our call will not remove
+ * the certificate permanently, but rather remove all trust. */
+ SEC_DeletePermCertificate (priv->cert);
+ }
+ }
+
+ if (priv->cert)
+ CERT_DestroyCertificate (priv->cert);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_cert_parent_class)->finalize (object);
+}
+
+static void
+e_cert_class_init (ECertClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (ECertPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = e_cert_finalize;
+}
+
+static void
+e_cert_init (ECert *ec)
+{
+ ec->priv = E_CERT_GET_PRIVATE (ec);
+}
+
+static void
+e_cert_populate (ECert *cert)
+{
+ CERTCertificate *c = cert->priv->cert;
+ guchar fingerprint[20];
+ SECItem fpItem;
+
+ cert->priv->org_name = CERT_GetOrgName (&c->subject);
+ cert->priv->org_unit_name = CERT_GetOrgUnitName (&c->subject);
+
+ cert->priv->issuer_org_name = CERT_GetOrgName (&c->issuer);
+ cert->priv->issuer_org_unit_name = CERT_GetOrgUnitName (&c->issuer);
+
+ cert->priv->cn = CERT_GetCommonName (&c->subject);
+ cert->priv->issuer_cn = CERT_GetCommonName (&c->issuer);
+
+ if (SECSuccess == CERT_GetCertTimes (
+ c, &cert->priv->issued_on, &cert->priv->expires_on)) {
+ PRExplodedTime explodedTime;
+ struct tm exploded_tm;
+ gchar buf[32];
+
+ PR_ExplodeTime (
+ cert->priv->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), _("%d/%m/%Y"), &exploded_tm);
+ cert->priv->issued_on_string = g_strdup (buf);
+
+ PR_ExplodeTime (
+ cert->priv->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), _("%d/%m/%Y"), &exploded_tm);
+ cert->priv->expires_on_string = g_strdup (buf);
+ }
+
+ cert->priv->serial_number = CERT_Hexify (&cert->priv->cert->serialNumber, TRUE);
+
+ memset (fingerprint, 0, sizeof fingerprint);
+ PK11_HashBuf (
+ SEC_OID_SHA1, fingerprint,
+ cert->priv->cert->derCert.data,
+ cert->priv->cert->derCert.len);
+ fpItem.data = fingerprint;
+ fpItem.len = SHA1_LENGTH;
+ cert->priv->sha1_fingerprint = CERT_Hexify (&fpItem, TRUE);
+
+ memset (fingerprint, 0, sizeof fingerprint);
+ PK11_HashBuf (
+ SEC_OID_MD5, fingerprint,
+ cert->priv->cert->derCert.data,
+ cert->priv->cert->derCert.len);
+ fpItem.data = fingerprint;
+ fpItem.len = MD5_LENGTH;
+ cert->priv->md5_fingerprint = CERT_Hexify (&fpItem, TRUE);
+}
+
+ECert *
+e_cert_new (CERTCertificate *cert)
+{
+ ECert *ecert = E_CERT (g_object_new (E_TYPE_CERT, NULL));
+
+ /* ECert owns a reference to the 'cert', which will be freed on ECert finalize */
+ ecert->priv->cert = cert;
+
+ e_cert_populate (ecert);
+
+ return ecert;
+}
+
+ECert *
+e_cert_new_from_der (gchar *data,
+ guint32 len)
+{
+ CERTCertificate *cert = CERT_DecodeCertFromPackage (data, len);
+
+ if (!cert)
+ return NULL;
+
+ if (cert->dbhandle == NULL)
+ cert->dbhandle = CERT_GetDefaultCertDB ();
+
+ return e_cert_new (cert);
+}
+
+CERTCertificate *
+e_cert_get_internal_cert (ECert *cert)
+{
+ /* XXX should this refcnt it? */
+ return cert->priv->cert;
+}
+
+gboolean
+e_cert_get_raw_der (ECert *cert,
+ gchar **data,
+ guint32 *len)
+{
+ /* XXX do we really need to check if cert->priv->cert is NULL
+ * here? it should always be non - null if we have the
+ * ECert.. */
+ if (cert->priv->cert) {
+ *data = (gchar *)cert->priv->cert->derCert.data;
+ *len = (guint32)cert->priv->cert->derCert.len;
+ return TRUE;
+ }
+
+ *len = 0;
+ return FALSE;
+
+}
+
+const gchar *
+e_cert_get_window_title (ECert *cert)
+{
+ if (cert->priv->cert->nickname)
+ return cert->priv->cert->nickname;
+ else if (cert->priv->cn)
+ return cert->priv->cn;
+ else
+ return cert->priv->cert->subjectName;
+}
+
+const gchar *
+e_cert_get_nickname (ECert *cert)
+{
+ return cert->priv->cert->nickname;
+}
+
+const gchar *
+e_cert_get_email (ECert *cert)
+{
+ return cert->priv->cert->emailAddr;
+}
+
+const gchar *
+e_cert_get_org (ECert *cert)
+{
+ return cert->priv->org_name;
+}
+
+const gchar *
+e_cert_get_org_unit (ECert *cert)
+{
+ return cert->priv->org_unit_name;
+}
+
+const gchar *
+e_cert_get_cn (ECert *cert)
+{
+ return cert->priv->cn;
+}
+
+const gchar *
+e_cert_get_issuer_name (ECert *cert)
+{
+ return cert->priv->cert->issuerName;
+}
+
+const gchar *
+e_cert_get_issuer_cn (ECert *cert)
+{
+ return cert->priv->issuer_cn;
+}
+
+const gchar *
+e_cert_get_issuer_org (ECert *cert)
+{
+ return cert->priv->issuer_org_name;
+}
+
+const gchar *
+e_cert_get_issuer_org_unit (ECert *cert)
+{
+ return cert->priv->issuer_org_unit_name;
+}
+
+const gchar *
+e_cert_get_subject_name (ECert *cert)
+{
+ return cert->priv->cert->subjectName;
+}
+
+PRTime
+e_cert_get_issued_on_time (ECert *cert)
+{
+ return cert->priv->issued_on;
+}
+
+const gchar *
+e_cert_get_issued_on (ECert *cert)
+{
+ return cert->priv->issued_on_string;
+}
+
+PRTime
+e_cert_get_expires_on_time (ECert *cert)
+{
+ return cert->priv->expires_on;
+}
+
+const gchar *
+e_cert_get_expires_on (ECert *cert)
+{
+ return cert->priv->expires_on_string;
+}
+
+static struct {
+ gint bit;
+ const gchar *text;
+} usageinfo[] = {
+ /* x509 certificate usage types */
+ { certificateUsageEmailSigner, N_("Sign") },
+ { certificateUsageEmailRecipient, N_("Encrypt") },
+};
+
+const gchar *
+e_cert_get_usage (ECert *cert)
+{
+ if (cert->priv->usage_string == NULL) {
+ gint i;
+ GString *str = g_string_new ("");
+ CERTCertificate *icert = e_cert_get_internal_cert (cert);
+
+ for (i = 0; i < G_N_ELEMENTS (usageinfo); i++) {
+ if (icert->keyUsage & usageinfo[i].bit) {
+ if (str->len != 0)
+ g_string_append (str, ", ");
+ g_string_append (str, _(usageinfo[i].text));
+ }
+ }
+
+ cert->priv->usage_string = str->str;
+ g_string_free (str, FALSE);
+ }
+
+ return cert->priv->usage_string;
+}
+
+const gchar *
+e_cert_get_serial_number (ECert *cert)
+{
+ return cert->priv->serial_number;
+}
+
+const gchar *
+e_cert_get_sha1_fingerprint (ECert *cert)
+{
+ return cert->priv->sha1_fingerprint;
+}
+
+const gchar *
+e_cert_get_md5_fingerprint (ECert *cert)
+{
+ return cert->priv->md5_fingerprint;
+}
+
+GList *
+e_cert_get_issuers_chain (ECert *ecert)
+{
+ GList *issuers = NULL;
+
+ while (ecert) {
+ CERTCertificate *cert = e_cert_get_internal_cert (ecert);
+ CERTCertificate *next_cert;
+
+ if (SECITEM_CompareItem (&cert->derIssuer, &cert->derSubject) == SECEqual)
+ break;
+
+ next_cert = CERT_FindCertIssuer (cert, PR_Now (), certUsageSSLClient);
+ if (!next_cert)
+ break;
+
+ /* 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 issuers;
+}
+
+ECert *
+e_cert_get_ca_cert (ECert *ecert)
+{
+ CERTCertificate *cert, *next = e_cert_get_internal_cert (ecert), *internal;
+
+ cert = next;
+ internal = cert;
+ do {
+ if (cert != next && cert != internal)
+ CERT_DestroyCertificate (cert);
+
+ cert = next;
+ next = CERT_FindCertIssuer (cert, PR_Now (), certUsageAnyCA);
+ } while (next && next != cert);
+
+ if (cert == internal)
+ return g_object_ref (ecert);
+ else
+ return e_cert_new (cert);
+}
+
+EASN1Object *
+e_cert_get_asn1_struct (ECert *cert)
+{
+ if (!cert->priv->asn1)
+ cert->priv->asn1 = e_asn1_object_new_from_cert (cert->priv->cert);
+
+ if (cert->priv->asn1)
+ return g_object_ref (cert->priv->asn1);
+
+ return NULL;
+}
+
+gboolean
+e_cert_mark_for_deletion (ECert *cert)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+
+#if 0
+ /* make sure user is logged in to the token */
+ nsCOMPtr < nsIInterfaceRequestor> ctx = new PipUIContext ();
+#endif
+
+ if (PK11_NeedLogin (cert->priv->cert->slot)
+ && !PK11_NeedUserInit (cert->priv->cert->slot)
+ && !PK11_IsInternal (cert->priv->cert->slot)) {
+ if (PK11_Authenticate (
+ cert->priv->cert->slot, PR_TRUE, NULL) != SECSuccess) {
+ return FALSE;
+ }
+ }
+
+ cert->priv->delete = TRUE;
+
+ return TRUE;
+}
+
+ECertType
+e_cert_get_cert_type (ECert *ecert)
+{
+ const gchar *nick = e_cert_get_nickname (ecert);
+ const gchar *email = e_cert_get_email (ecert);
+ CERTCertificate *cert = ecert->priv->cert;
+
+ if (nick) {
+ if (e_cert_trust_has_any_user (cert->trust))
+ return E_CERT_USER;
+ if (e_cert_trust_has_any_ca (cert->trust)
+ || CERT_IsCACert (cert,NULL))
+ return E_CERT_CA;
+ if (e_cert_trust_has_peer (cert->trust, PR_TRUE, PR_FALSE, PR_FALSE))
+ return E_CERT_SITE;
+ }
+ if (email && e_cert_trust_has_peer (cert->trust, PR_FALSE, PR_TRUE, PR_FALSE))
+ return E_CERT_CONTACT;
+
+ return E_CERT_UNKNOWN;
+}
diff --git a/smime/lib/e-cert.h b/smime/lib/e-cert.h
new file mode 100644
index 0000000000..0096336741
--- /dev/null
+++ b/smime/lib/e-cert.h
@@ -0,0 +1,106 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _E_CERT_H_
+#define _E_CERT_H_
+
+#include <glib-object.h>
+#include <cert.h>
+#include "e-asn1-object.h"
+
+#define E_TYPE_CERT (e_cert_get_type ())
+#define E_CERT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CERT, ECert))
+#define E_CERT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CERT, ECertClass))
+#define E_IS_CERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CERT))
+#define E_IS_CERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CERT))
+#define E_CERT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CERT, ECertClass))
+
+typedef struct _ECert ECert;
+typedef struct _ECertClass ECertClass;
+typedef struct _ECertPrivate ECertPrivate;
+
+typedef enum {
+ E_CERT_CA,
+ E_CERT_CONTACT,
+ E_CERT_SITE,
+ E_CERT_USER,
+ E_CERT_UNKNOWN
+} ECertType;
+
+struct _ECert {
+ GObject parent;
+
+ ECertPrivate *priv;
+};
+
+struct _ECertClass {
+ GObjectClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_ecert_reserved0) (void);
+ void (*_ecert_reserved1) (void);
+ void (*_ecert_reserved2) (void);
+ void (*_ecert_reserved3) (void);
+ void (*_ecert_reserved4) (void);
+};
+
+GType e_cert_get_type (void);
+
+ECert * e_cert_new (CERTCertificate *cert);
+ECert * e_cert_new_from_der (gchar *data, guint32 len);
+
+CERTCertificate * e_cert_get_internal_cert (ECert *cert);
+
+gboolean e_cert_get_raw_der (ECert *cert, gchar **data, guint32 *len);
+const gchar * e_cert_get_window_title (ECert *cert);
+const gchar * e_cert_get_nickname (ECert *cert);
+const gchar * e_cert_get_email (ECert *cert);
+const gchar * e_cert_get_org (ECert *cert);
+const gchar * e_cert_get_org_unit (ECert *cert);
+const gchar * e_cert_get_cn (ECert *cert);
+const gchar * e_cert_get_subject_name (ECert *cert);
+
+const gchar * e_cert_get_issuer_name (ECert *cert);
+const gchar * e_cert_get_issuer_cn (ECert *cert);
+const gchar * e_cert_get_issuer_org (ECert *cert);
+const gchar * e_cert_get_issuer_org_unit (ECert *cert);
+
+PRTime e_cert_get_issued_on_time (ECert *cert);
+const gchar * e_cert_get_issued_on (ECert *cert);
+PRTime e_cert_get_expires_on_time (ECert *cert);
+const gchar * e_cert_get_expires_on (ECert *cert);
+const gchar * e_cert_get_usage (ECert *cert);
+
+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_issuers_chain (ECert *cert);
+ECert * e_cert_get_ca_cert (ECert *ecert);
+EASN1Object * e_cert_get_asn1_struct (ECert *cert);
+
+gboolean e_cert_mark_for_deletion (ECert *cert);
+
+ECertType e_cert_get_cert_type (ECert *cert);
+
+#endif /* _E_CERT_H_ */
diff --git a/smime/lib/e-pkcs12.c b/smime/lib/e-pkcs12.c
new file mode 100644
index 0000000000..3cf2cb6479
--- /dev/null
+++ b/smime/lib/e-pkcs12.c
@@ -0,0 +1,371 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* The following is the mozilla license blurb, as the bodies some of
+ * these functions were derived from the mozilla source. */
+/*
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+/*
+ * Author: Chris Toshok (toshok@ximian.com)
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "e-util/e-util.h"
+
+#include "e-cert-db.h"
+#include "e-pkcs12.h"
+
+#include "prmem.h"
+#include "nss.h"
+#include "ssl.h"
+#include "pkcs12.h"
+#include "p12plcy.h"
+#include "pk11func.h"
+#include "secerr.h"
+
+/* static callback functions for the NSS PKCS#12 library */
+static SECItem * PR_CALLBACK nickname_collision (SECItem *, PRBool *, gpointer);
+
+static gboolean handle_error (gint myerr);
+
+#define PKCS12_BUFFER_SIZE 2048
+#define PKCS12_RESTORE_OK 1
+#define PKCS12_BACKUP_OK 2
+#define PKCS12_USER_CANCELED 3
+#define PKCS12_NOSMARTCARD_EXPORT 4
+#define PKCS12_RESTORE_FAILED 5
+#define PKCS12_BACKUP_FAILED 6
+#define PKCS12_NSS_ERROR 7
+
+G_DEFINE_TYPE (EPKCS12, e_pkcs12, G_TYPE_OBJECT)
+
+static void
+e_pkcs12_class_init (EPKCS12Class *class)
+{
+}
+
+static void
+e_pkcs12_init (EPKCS12 *ec)
+{
+}
+
+EPKCS12 *
+e_pkcs12_new (void)
+{
+ return g_object_new (E_TYPE_PKCS12, NULL);
+}
+
+static gboolean
+input_to_decoder (SEC_PKCS12DecoderContext *dcx,
+ const gchar *path,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+ SECStatus srv;
+ gint amount;
+ gchar buf[PKCS12_BUFFER_SIZE];
+ FILE *fp;
+
+ /* open path */
+ fp = g_fopen (path, "rb");
+ if (!fp) {
+ /* XXX gerror */
+ printf ("couldn't open '%s'\n", path);
+ return FALSE;
+ }
+
+ while (TRUE) {
+ amount = fread (buf, 1, sizeof (buf), fp);
+ if (amount < 0) {
+ fclose (fp);
+ return FALSE;
+ }
+
+ /* feed the file data into the decoder */
+ srv = SEC_PKCS12DecoderUpdate (
+ dcx, (guchar *) buf, amount);
+ if (srv) {
+ /* XXX g_error */
+ fclose (fp);
+ return FALSE;
+ }
+ if (amount < PKCS12_BUFFER_SIZE)
+ break;
+ }
+ fclose (fp);
+ return TRUE;
+}
+
+/* XXX toshok - this needs to be done using a signal as in the
+ * e_cert_db_login_to_slot stuff, instead of a direct gui dep here..
+ * for now, though, it stays. */
+static gboolean
+prompt_for_password (gchar *title,
+ gchar *prompt,
+ SECItem *pwd)
+{
+ gchar *passwd;
+
+ passwd = e_passwords_ask_password (
+ title, "", prompt,
+ E_PASSWORDS_REMEMBER_NEVER | E_PASSWORDS_SECRET,
+ NULL, NULL);
+
+ if (passwd) {
+ gsize len = strlen (passwd);
+ const gchar *inptr = passwd;
+ guchar *outptr;
+ gunichar2 c;
+
+ SECITEM_AllocItem (NULL, pwd, sizeof (gunichar2) * (len + 1));
+
+ outptr = pwd->data;
+ while (inptr && (c = (gunichar2) (g_utf8_get_char (inptr) & 0xffff))) {
+ inptr = g_utf8_next_char (inptr);
+ c = GUINT16_TO_BE (c);
+ *outptr++ = ((gchar *) &c)[0];
+ *outptr++ = ((gchar *) &c)[1];
+ }
+
+ outptr[0] = 0;
+ outptr[1] = 0;
+
+ memset (passwd, 0, strlen (passwd));
+ g_free (passwd);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+import_from_file_helper (EPKCS12 *pkcs12,
+ PK11SlotInfo *slot,
+ const gchar *path,
+ gboolean *aWantRetry,
+ GError **error)
+{
+ /*nsNSSShutDownPreventionLock locker; */
+ gboolean rv;
+ SECStatus srv = SECSuccess;
+ SEC_PKCS12DecoderContext *dcx = NULL;
+ SECItem passwd;
+ GError *err = NULL;
+
+ *aWantRetry = FALSE;
+
+ passwd.data = NULL;
+ rv = prompt_for_password (
+ _("PKCS12 File Password"),
+ _("Enter password for PKCS12 file:"), &passwd);
+ if (!rv) goto finish;
+ if (passwd.data == NULL) {
+ handle_error (PKCS12_USER_CANCELED);
+ return TRUE;
+ }
+
+ /* initialize the decoder */
+ dcx = SEC_PKCS12DecoderStart (
+ &passwd,
+ slot,
+ /* we specify NULL for all the
+ * funcs + data so it'll use the
+ * default pk11wrap functions */
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (!dcx) {
+ srv = SECFailure;
+ goto finish;
+ }
+ /* read input file and feed it to the decoder */
+ rv = input_to_decoder (dcx, path, &err);
+ if (!rv) {
+#ifdef notyet
+ /* XXX we need this to check the gerror */
+ if (NS_ERROR_ABORT == rv) {
+ /* inputToDecoder indicated a NSS error */
+ srv = SECFailure;
+ }
+#else
+ srv = SECFailure;
+#endif
+ goto finish;
+ }
+
+ /* verify the blob */
+ srv = SEC_PKCS12DecoderVerify (dcx);
+ if (srv) goto finish;
+ /* validate bags */
+ srv = SEC_PKCS12DecoderValidateBags (dcx, nickname_collision);
+ if (srv) goto finish;
+ /* import cert and key */
+ srv = SEC_PKCS12DecoderImportBags (dcx);
+ if (srv) goto finish;
+ /* Later - check to see if this should become default email cert */
+ handle_error (PKCS12_RESTORE_OK);
+ finish:
+ /* If srv != SECSuccess, NSS probably set a specific error code.
+ * We should use that error code instead of inventing a new one
+ * for every error possible. */
+ if (srv != SECSuccess) {
+ if (SEC_ERROR_BAD_PASSWORD == PORT_GetError ()) {
+ *aWantRetry = TRUE;
+ }
+ handle_error (PKCS12_NSS_ERROR);
+ } else if (!rv) {
+ handle_error (PKCS12_RESTORE_FAILED);
+ }
+ /* finish the decoder */
+ if (dcx)
+ SEC_PKCS12DecoderFinish (dcx);
+ return TRUE;
+}
+
+gboolean
+e_pkcs12_import_from_file (EPKCS12 *pkcs12,
+ const gchar *path,
+ GError **error)
+{
+ /*nsNSSShutDownPreventionLock locker;*/
+ gboolean rv = TRUE;
+ gboolean wantRetry;
+ PK11SlotInfo *slot;
+
+ printf ("importing pkcs12 from '%s'\n", path);
+
+ slot = PK11_GetInternalKeySlot ();
+
+ if (!e_cert_db_login_to_slot (e_cert_db_peek (), slot))
+ return FALSE;
+
+ do {
+ rv = import_from_file_helper (pkcs12, slot, path, &wantRetry, error);
+ } while (rv && wantRetry);
+
+ return rv;
+}
+
+gboolean
+e_pkcs12_export_to_file (EPKCS12 *pkcs12,
+ const gchar *path,
+ GList *certs,
+ GError **error)
+{
+ return FALSE;
+}
+
+/* what to do when the nickname collides with one already in the db.
+ * TODO: not handled, throw a dialog allowing the nick to be changed? */
+static SECItem * PR_CALLBACK
+nickname_collision (SECItem *oldNick,
+ PRBool *cancel,
+ gpointer wincx)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+ gint count = 1;
+ gchar *nickname = NULL;
+ gchar *default_nickname = _("Imported Certificate");
+ SECItem *new_nick;
+
+ *cancel = PR_FALSE;
+ printf ("nickname_collision\n");
+
+ /* The user is trying to import a PKCS#12 file that doesn't have the
+ * attribute we use to set the nickname. So in order to reduce the
+ * number of interactions we require with the user, we'll build a nickname
+ * for the user. The nickname isn't prominently displayed in the UI,
+ * so it's OK if we generate one on our own here.
+ * XXX If the NSS API were smarter and actually passed a pointer to
+ * the CERTCertificate * we're importing we could actually just
+ * call default_nickname (which is what the issuance code path
+ * does) and come up with a reasonable nickname. Alas, the NSS
+ * API limits our ability to produce a useful nickname without
+ * bugging the user. :(
+ */
+ while (1) {
+ CERTCertificate *cert;
+
+ /* If we've gotten this far, that means there isn't a certificate
+ * in the database that has the same subject name as the cert we're
+ * trying to import. So we need to come up with a "nickname" to
+ * satisfy the NSS requirement or fail in trying to import.
+ * Basically we use a default nickname from a properties file and
+ * see if a certificate exists with that nickname. If there isn't, then
+ * create update the count by one and append the string '#1' Or
+ * whatever the count currently is, and look for a cert with
+ * that nickname. Keep updating the count until we find a nickname
+ * without a corresponding cert.
+ * XXX If a user imports *many * certs without the 'friendly name'
+ * attribute, then this may take a long time. :(
+ */
+ if (count > 1) {
+ g_free (nickname);
+ nickname = g_strdup_printf ("%s #%d", default_nickname, count);
+ } else {
+ g_free (nickname);
+ nickname = g_strdup (default_nickname);
+ }
+ cert = CERT_FindCertByNickname (
+ CERT_GetDefaultCertDB (),
+ nickname);
+ if (!cert) {
+ break;
+ }
+ CERT_DestroyCertificate (cert);
+ count++;
+ }
+
+ new_nick = PR_Malloc (sizeof (SECItem));
+ new_nick->type = siAsciiString;
+ new_nick->data = (guchar *) nickname;
+ new_nick->len = strlen ((gchar *) new_nick->data);
+ return new_nick;
+}
+
+static gboolean
+handle_error (gint myerr)
+{
+ printf ("handle_error (%d)\n", myerr);
+
+ return FALSE;
+}
diff --git a/smime/lib/e-pkcs12.h b/smime/lib/e-pkcs12.h
new file mode 100644
index 0000000000..940187bc18
--- /dev/null
+++ b/smime/lib/e-pkcs12.h
@@ -0,0 +1,68 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Authors:
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifndef _E_PKCS12_H_
+#define _E_PKCS12_H_
+
+#include <glib-object.h>
+
+#define E_TYPE_PKCS12 (e_pkcs12_get_type ())
+#define E_PKCS12(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_PKCS12, EPKCS12))
+#define E_PKCS12_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_PKCS12, EPKCS12Class))
+#define E_IS_PKCS12(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_PKCS12))
+#define E_IS_PKCS12_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_PKCS12))
+#define E_PKCS12_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_PKCS12, EPKCS12Class))
+
+typedef struct _EPKCS12 EPKCS12;
+typedef struct _EPKCS12Class EPKCS12Class;
+typedef struct _EPKCS12Private EPKCS12Private;
+
+struct _EPKCS12 {
+ GObject parent;
+
+ EPKCS12Private *priv;
+};
+
+struct _EPKCS12Class {
+ GObjectClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_epkcs12_reserved0) (void);
+ void (*_epkcs12_reserved1) (void);
+ void (*_epkcs12_reserved2) (void);
+ void (*_epkcs12_reserved3) (void);
+ void (*_epkcs12_reserved4) (void);
+};
+
+GType e_pkcs12_get_type (void);
+
+EPKCS12 * e_pkcs12_new (void);
+
+#if 0
+/* XXX we're not going to support additional slots in the initial ssl
+ * stuff, so we just always default to the internal token (and thus
+ * don't need this function yet. */
+gboolean e_pkcs12_set_token (void);
+#endif
+
+gboolean e_pkcs12_import_from_file (EPKCS12 *pkcs12, const gchar *path, GError **error);
+gboolean e_pkcs12_export_to_file (EPKCS12 *pkcs12, const gchar *path, GList *certs, GError **error);
+
+#endif /* _E_CERT_H_ */
diff --git a/smime/tests/Makefile.am b/smime/tests/Makefile.am
new file mode 100644
index 0000000000..211042d9e1
--- /dev/null
+++ b/smime/tests/Makefile.am
@@ -0,0 +1,20 @@
+noinst_PROGRAMS=import-cert
+
+TEST_CPPFLAGS= \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir)/smime/lib \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(CERT_UI_CFLAGS)
+
+TEST_LIBS= \
+ $(top_builddir)/smime/lib/libessmime.la \
+ -L/home/toshok/src/mozilla/mozilla/dist/lib \
+ $(CERT_UI_LIBS) \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS)
+
+import_cert_LDADD=$(TEST_LIBS)
+
+-include $(top_srcdir)/git.mk
diff --git a/smime/tests/import-cert.c b/smime/tests/import-cert.c
new file mode 100644
index 0000000000..dfd368da46
--- /dev/null
+++ b/smime/tests/import-cert.c
@@ -0,0 +1,57 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <gtk/gtk.h>
+
+#include "e-cert-db.h"
+#include "e-pkcs12.h"
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ ECertDB *db;
+ EPKCS12 *pkcs12;
+
+ gtk_init (&argc, &argv);
+
+ db = e_cert_db_peek ();
+
+ if (!e_cert_db_import_certs_from_file (db, "ca.crt", E_CERT_CA, NULL /* XXX */)) {
+ g_warning ("CA cert import failed");
+ }
+
+ if (!e_cert_db_import_certs_from_file (db, "", E_CERT_CONTACT, NULL /* XXX */)) {
+ g_warning ("contact cert import failed");
+ }
+
+ if (!e_cert_db_import_certs_from_file (db, "", E_CERT_SITE, NULL /* XXX */)) {
+ g_warning ("server cert import failed");
+ }
+
+ pkcs12 = e_pkcs12_new ();
+ if (!e_pkcs12_import_from_file (pkcs12, "newcert.p12", NULL /* XXX */)) {
+ g_warning ("PKCS12 import failed");
+ }
+
+ e_cert_db_shutdown ();
+
+ return 0;
+}