aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--smime/ChangeLog57
-rw-r--r--smime/gui/certificate-manager.c323
-rw-r--r--smime/gui/smime-ui.glade219
-rw-r--r--smime/lib/Makefile.am6
-rw-r--r--smime/lib/e-cert-db.c822
-rw-r--r--smime/lib/e-cert-db.h128
-rw-r--r--smime/lib/e-cert.c138
-rw-r--r--smime/lib/e-cert.h26
-rw-r--r--smime/tests/Makefile.am1
-rw-r--r--smime/tests/import-cert.c12
10 files changed, 1656 insertions, 76 deletions
diff --git a/smime/ChangeLog b/smime/ChangeLog
index 5123fbff1c..181825ad3f 100644
--- a/smime/ChangeLog
+++ b/smime/ChangeLog
@@ -1,3 +1,60 @@
+2003-11-11 Chris Toshok <toshok@ximian.com>
+
+ * tests/import-cert.c (main): don't init NSS here. it's done in
+ e_cert_db_peek.
+
+ * lib/Makefile.am (libessmime_la_SOURCES): add e-cert-db.[ch]
+
+ * gui/smime-ui.glade: set the initial sensitivity of the buttons
+ here, and add the beginnings of the CA import dialog (where you
+ assign trust levels to it.)
+
+ * gui/certificate-manager.c (handle_selection_changed):
+ sensitize/desensitize all the various buttons correctly when the
+ GtkTreeView's selection changes.
+ (yourcerts_selection_changed): new, selection change handler for
+ the Your Certs tab.
+ (initialize_yourcerts_ui): hook up the tree selection, and add a
+ model column for the ECert.
+ (contactcerts_selection_changed): new, selection change handler
+ for the Contact Certs tab.
+ (initialize_contactcerts_ui): hook up the tree selection, and add
+ a model column for the ECert.
+ (import_ca): new function.
+ (delete_ca): new function.
+ (authoritycerts_selection_changed): new, selection change handler
+ for the Authority Certs tab.
+ (create_authoritycerts_treemodel): new function for creating the
+ authority cert tree model. the other tabs will eventually use a
+ separate function for this too, as unload_certs gets fleshed out.
+ (initialize_authoritycerts_ui): hook up the tree selection, and
+ add import/delete buttons.
+ (destroy_key): dtor for the keys in our hashes.
+ (destroy_value): dtor for the values in our hashes.
+ (unload_certs): new function. basically destroy/recreate the
+ model and hash for the particular cert type/tab.
+ (load_certs): use e_cert_get_cert_type.
+ (populate_ui): use unload_certs as well as load_certs.
+ (certificate_manager_config_control_new): call e_cert_db_peek
+ ,which will initialize all of NSS. hook up all the widgets from
+ libglade.
+
+ * lib/e-cert.h: add prototypes for all the new methods, and add
+ the ECertType enum.
+
+ * lib/e-cert.c (e_cert_dispose): handle deletion from the DB here.
+ (e_cert_new_from_der): new function.
+ (e_cert_get_internal_cert): new function.
+ (e_cert_get_raw_der): new function.
+ (e_cert_get_issuer_name): new
+ (e_cert_get_subject_name): new
+ (e_cert_mark_for_deletion): new
+ (e_cert_get_cert_type): new.
+ (e_cert_is_ca_cert): nuke.
+
+ * lib/e-cert-db.[ch]: new, partly implemented, derived from
+ mozilla's nsNSSCertificateDB code.
+
2003-10-30 Chris Toshok <toshok@ximian.com>
* gui/certificate-manager.h: add boilerplate.
diff --git a/smime/gui/certificate-manager.c b/smime/gui/certificate-manager.c
index 7e4e1b1e1d..e49617a2db 100644
--- a/smime/gui/certificate-manager.c
+++ b/smime/gui/certificate-manager.c
@@ -22,11 +22,7 @@
#define GLADE_FILE_NAME "smime-ui.glade"
-#include <gtk/gtkcontainer.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtktreestore.h>
-#include <gtk/gtktreemodelsort.h>
-#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtk.h>
#include <libgnome/gnome-i18n.h>
@@ -35,6 +31,7 @@
#include "certificate-manager.h"
#include "e-cert.h"
+#include "e-cert-db.h"
#include "nss.h"
#include <cms.h>
@@ -49,6 +46,11 @@ typedef struct {
GtkWidget *yourcerts_treeview;
GtkTreeStore *yourcerts_treemodel;
GHashTable *yourcerts_root_hash;
+ GtkWidget *view_your_button;
+ GtkWidget *backup_your_button;
+ GtkWidget *backup_all_your_button;
+ GtkWidget *import_your_button;
+ GtkWidget *delete_your_button;
GtkWidget *contactcerts_treeview;
GtkTreeStore *contactcerts_treemodel;
@@ -57,18 +59,72 @@ typedef struct {
GtkWidget *authoritycerts_treeview;
GtkTreeStore *authoritycerts_treemodel;
GHashTable *authoritycerts_root_hash;
+ GtkWidget *view_ca_button;
+ GtkWidget *edit_ca_button;
+ GtkWidget *import_ca_button;
+ GtkWidget *delete_ca_button;
+
} CertificateManagerData;
-typedef enum {
- USER_CERT,
- CONTACT_CERT,
- CA_CERT
-} CertType;
+typedef void (*AddCertCb)(CertificateManagerData *cfm, ECert *cert);
+
+static void unload_certs (CertificateManagerData *cfm, ECertType type);
+static void load_certs (CertificateManagerData *cfm, ECertType type, AddCertCb add_cert);
+
+static void add_user_cert (CertificateManagerData *cfm, ECert *cert);
+static void add_contact_cert (CertificateManagerData *cfm, ECert *cert);
+static void add_ca_cert (CertificateManagerData *cfm, ECert *cert);
+
+static void
+handle_selection_changed (GtkTreeSelection *selection,
+ int cert_column,
+ GtkWidget *view_button,
+ GtkWidget *edit_button,
+ GtkWidget *delete_button)
+{
+ 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,
+ cert_column, &cert,
+ -1);
+
+ if (cert) {
+ cert_selected = TRUE;
+ g_object_unref (cert);
+ }
+ }
+
+ if (delete_button)
+ gtk_widget_set_sensitive (delete_button, cert_selected);
+ if (edit_button)
+ gtk_widget_set_sensitive (edit_button, cert_selected);
+ if (view_button)
+ gtk_widget_set_sensitive (view_button, cert_selected);
+}
+
+static void
+yourcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm)
+{
+ handle_selection_changed (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->yourcerts_treeview)),
+ 4,
+ cfm->view_your_button,
+ cfm->backup_your_button, /* yes yes, not really "edit", it's a hack :) */
+ cfm->delete_your_button);
+}
static void
initialize_yourcerts_ui (CertificateManagerData *cfm)
{
GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
+ GtkTreeSelection *selection;
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->yourcerts_treeview),
gtk_tree_view_column_new_with_attributes (_("Certificate Name"),
@@ -94,22 +150,59 @@ initialize_yourcerts_ui (CertificateManagerData *cfm)
"text", 3,
NULL));
- cfm->yourcerts_treemodel = gtk_tree_store_new (4,
+ cfm->yourcerts_treemodel = gtk_tree_store_new (5,
+ G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
- G_TYPE_STRING);
+ G_TYPE_OBJECT);
gtk_tree_view_set_model (GTK_TREE_VIEW (cfm->yourcerts_treeview),
GTK_TREE_MODEL (cfm->yourcerts_treemodel));
cfm->yourcerts_root_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->yourcerts_treeview));
+ g_signal_connect (selection, "changed", G_CALLBACK (yourcerts_selection_changed), cfm);
+
+ if (cfm->import_your_button) {
+ /* g_signal_connect */
+ }
+
+ if (cfm->delete_your_button) {
+ /* g_signal_connect */
+ }
+
+ if (cfm->view_your_button) {
+ /* g_signal_connect */
+ }
+
+ if (cfm->backup_your_button) {
+ /* g_signal_connect */
+ }
+
+ if (cfm->backup_all_your_button) {
+ /* g_signal_connect */
+ }
+}
+
+static void
+contactcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm)
+{
+#if 0
+ handle_selection_changed (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->contactcerts_treeview)),
+ 1 /* XXX */,
+ NULL,
+ NULL,
+ NULL);
+#endif
}
static void
initialize_contactcerts_ui (CertificateManagerData *cfm)
{
GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
+ GtkTreeSelection *selection;
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->contactcerts_treeview),
gtk_tree_view_column_new_with_attributes (_("Certificate Name"),
@@ -132,12 +225,16 @@ initialize_contactcerts_ui (CertificateManagerData *cfm)
cfm->contactcerts_treemodel = gtk_tree_store_new (3,
G_TYPE_STRING,
G_TYPE_STRING,
- G_TYPE_STRING);
+ G_TYPE_STRING,
+ G_TYPE_OBJECT);
gtk_tree_view_set_model (GTK_TREE_VIEW (cfm->contactcerts_treeview),
GTK_TREE_MODEL (cfm->contactcerts_treemodel));
cfm->contactcerts_root_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->contactcerts_treeview));
+ g_signal_connect (selection, "changed", G_CALLBACK (contactcerts_selection_changed), cfm);
}
static gint
@@ -160,9 +257,84 @@ iter_string_compare (GtkTreeModel *model,
}
static void
+import_ca (GtkWidget *widget, CertificateManagerData *cfm)
+{
+ GtkWidget *filesel = gtk_file_selection_new (_("Select a cert to import..."));
+
+ if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) {
+ const char *filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel));
+
+ if (e_cert_db_import_certs_from_file (e_cert_db_peek (),
+ filename,
+ E_CERT_CA,
+ NULL)) {
+
+ /* there's no telling how many certificates were added during the import,
+ so we blow away the CA cert display and regenerate it. */
+ unload_certs (cfm, E_CERT_CA);
+ load_certs (cfm, E_CERT_CA, add_ca_cert);
+ }
+ }
+
+ gtk_widget_destroy (filesel);
+}
+
+static void
+delete_ca (GtkWidget *widget, CertificateManagerData *cfm)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->authoritycerts_treeview)),
+ NULL,
+ &iter)) {
+ ECert *cert;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (cfm->authoritycerts_treemodel),
+ &iter,
+ 1, &cert,
+ -1);
+
+ if (cert) {
+ printf ("DELETE\n");
+ e_cert_db_delete_cert (e_cert_db_peek (), cert);
+ gtk_tree_store_remove (cfm->authoritycerts_treemodel,
+ &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);
+ }
+ }
+
+}
+
+static void
+authoritycerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm)
+{
+ handle_selection_changed (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->authoritycerts_treeview)),
+ 1,
+ cfm->view_ca_button,
+ cfm->edit_ca_button,
+ cfm->delete_ca_button);
+}
+
+static GtkTreeStore*
+create_authoritycerts_treemodel (void)
+{
+ return gtk_tree_store_new (2,
+ G_TYPE_STRING,
+ G_TYPE_OBJECT);
+
+}
+
+static void
initialize_authoritycerts_ui (CertificateManagerData *cfm)
{
GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
+ GtkTreeSelection *selection;
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->authoritycerts_treeview),
gtk_tree_view_column_new_with_attributes (_("Certificate Name"),
@@ -170,9 +342,6 @@ initialize_authoritycerts_ui (CertificateManagerData *cfm)
"text", 0,
NULL));
- cfm->authoritycerts_treemodel = gtk_tree_store_new (1,
- G_TYPE_STRING);
-
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (cfm->authoritycerts_treemodel),
0,
iter_string_compare, NULL, NULL);
@@ -181,35 +350,22 @@ initialize_authoritycerts_ui (CertificateManagerData *cfm)
0,
GTK_SORT_ASCENDING);
- gtk_tree_view_set_model (GTK_TREE_VIEW (cfm->authoritycerts_treeview),
- GTK_TREE_MODEL (cfm->authoritycerts_treemodel));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->authoritycerts_treeview));
+ g_signal_connect (selection, "changed", G_CALLBACK (authoritycerts_selection_changed), cfm);
- cfm->authoritycerts_root_hash = g_hash_table_new (g_str_hash, g_str_equal);
-}
-
-static CertType
-get_cert_type (ECert *cert)
-{
- const char *nick = e_cert_get_nickname (cert);
- const char *email = e_cert_get_email (cert);
+ if (cfm->import_ca_button)
+ g_signal_connect (cfm->import_ca_button, "clicked", G_CALLBACK (import_ca), cfm);
- if (e_cert_is_ca_cert (cert))
- return CA_CERT;
-
- /* XXX more stuff in here */
- else
- return USER_CERT;
+ if (cfm->delete_ca_button)
+ g_signal_connect (cfm->delete_ca_button, "clicked", G_CALLBACK (delete_ca), cfm);
}
-typedef void (*AddCertCb)(CertificateManagerData *cfm, ECert *cert);
-
static void
add_user_cert (CertificateManagerData *cfm, ECert *cert)
{
GtkTreeIter iter;
GtkTreeIter *parent_iter = NULL;
const char *organization = e_cert_get_org (cert);
- const char *common_name;
if (organization) {
parent_iter = g_hash_table_lookup (cfm->yourcerts_root_hash, organization);
@@ -229,14 +385,16 @@ add_user_cert (CertificateManagerData *cfm, ECert *cert)
gtk_tree_store_append (GTK_TREE_STORE (cfm->yourcerts_treemodel), &iter, parent_iter);
- common_name = e_cert_get_cn (cert);
- if (common_name) {
+ if (e_cert_get_cn (cert))
gtk_tree_store_set (GTK_TREE_STORE (cfm->yourcerts_treemodel), &iter,
- 0, common_name, -1);
- }
+ 0, e_cert_get_cn (cert),
+ 4, cert,
+ -1);
else
gtk_tree_store_set (GTK_TREE_STORE (cfm->yourcerts_treemodel), &iter,
- 0, e_cert_get_nickname (cert), -1);
+ 0, e_cert_get_nickname (cert),
+ 4, cert,
+ -1);
}
static void
@@ -251,7 +409,6 @@ add_ca_cert (CertificateManagerData *cfm, ECert *cert)
GtkTreeIter iter;
GtkTreeIter *parent_iter = NULL;
const char *organization = e_cert_get_org (cert);
- const char *common_name;
if (organization) {
parent_iter = g_hash_table_lookup (cfm->authoritycerts_root_hash, organization);
@@ -272,19 +429,60 @@ add_ca_cert (CertificateManagerData *cfm, ECert *cert)
gtk_tree_store_append (GTK_TREE_STORE (cfm->authoritycerts_treemodel), &iter, parent_iter);
- common_name = e_cert_get_cn (cert);
- if (common_name) {
+ if (e_cert_get_cn (cert))
gtk_tree_store_set (GTK_TREE_STORE (cfm->authoritycerts_treemodel), &iter,
- 0, common_name, -1);
- }
+ 0, e_cert_get_cn (cert),
+ 1, cert,
+ -1);
else
gtk_tree_store_set (GTK_TREE_STORE (cfm->authoritycerts_treemodel), &iter,
- 0, e_cert_get_nickname (cert), -1);
+ 0, e_cert_get_nickname (cert),
+ 1, cert,
+ -1);
+}
+
+static void
+destroy_key (gpointer data)
+{
+ g_free (data);
+}
+
+static void
+destroy_value (gpointer data)
+{
+ gtk_tree_iter_free (data);
+}
+
+static void
+unload_certs (CertificateManagerData *cfm,
+ ECertType type)
+{
+ switch (type) {
+ case E_CERT_USER:
+ break;
+ case E_CERT_CONTACT:
+ break;
+ case E_CERT_SITE:
+ break;
+ case E_CERT_CA:
+ cfm->authoritycerts_treemodel = create_authoritycerts_treemodel ();
+ gtk_tree_view_set_model (GTK_TREE_VIEW (cfm->authoritycerts_treeview),
+ GTK_TREE_MODEL (cfm->authoritycerts_treemodel));
+
+ if (cfm->authoritycerts_root_hash)
+ g_hash_table_destroy (cfm->authoritycerts_root_hash);
+
+ cfm->authoritycerts_root_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+ destroy_key, destroy_value);
+
+
+ break;
+ }
}
static void
load_certs (CertificateManagerData *cfm,
- CertType type,
+ ECertType type,
AddCertCb add_cert)
{
CERTCertList *certList;
@@ -298,11 +496,10 @@ load_certs (CertificateManagerData *cfm,
!CERT_LIST_END(node, certList);
node = CERT_LIST_NEXT(node)) {
ECert *cert = e_cert_new ((CERTCertificate*)node->cert);
- if (get_cert_type(cert) == type) {
+ if (e_cert_get_cert_type(cert) == type) {
printf ("cert (nickname = '%s') matches\n", e_cert_get_nickname (cert));
add_cert (cfm, cert);
}
- /* XXX we leak cert */
}
}
@@ -310,9 +507,14 @@ load_certs (CertificateManagerData *cfm,
static void
populate_ui (CertificateManagerData *cfm)
{
- load_certs (cfm, USER_CERT, add_user_cert);
- load_certs (cfm, CONTACT_CERT, add_contact_cert);
- load_certs (cfm, CA_CERT, add_ca_cert);
+ unload_certs (cfm, E_CERT_USER);
+ load_certs (cfm, E_CERT_USER, add_user_cert);
+
+ unload_certs (cfm, E_CERT_CONTACT);
+ load_certs (cfm, E_CERT_CONTACT, add_contact_cert);
+
+ unload_certs (cfm, E_CERT_CA);
+ load_certs (cfm, E_CERT_CA, add_ca_cert);
}
EvolutionConfigControl*
@@ -321,10 +523,8 @@ certificate_manager_config_control_new (void)
CertificateManagerData *cfm_data;
GtkWidget *control_widget;
- /* XXX this should happen someplace else, and shouldn't
- reference my default mozilla profile :) */
- if (SECSuccess != NSS_InitReadWrite ("/home/toshok/.mozilla/default/xuvq7jx3.slt"))
- return NULL;
+ /* We need to peek the db here to make sure it (and NSS) are fully initialized. */
+ e_cert_db_peek ();
cfm_data = g_new0 (CertificateManagerData, 1);
cfm_data->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, NULL, NULL);
@@ -333,6 +533,17 @@ certificate_manager_config_control_new (void)
cfm_data->contactcerts_treeview = glade_xml_get_widget (cfm_data->gui, "contactcerts-treeview");
cfm_data->authoritycerts_treeview = glade_xml_get_widget (cfm_data->gui, "authoritycerts-treeview");
+ cfm_data->view_your_button = glade_xml_get_widget (cfm_data->gui, "your-view-button");
+ cfm_data->backup_your_button = glade_xml_get_widget (cfm_data->gui, "your-backup-button");
+ cfm_data->backup_all_your_button = glade_xml_get_widget (cfm_data->gui, "your-backup-all-button");
+ cfm_data->import_your_button = glade_xml_get_widget (cfm_data->gui, "your-import-button");
+ cfm_data->delete_your_button = glade_xml_get_widget (cfm_data->gui, "your-delete-button");
+
+ cfm_data->view_ca_button = glade_xml_get_widget (cfm_data->gui, "authority-view-button");
+ cfm_data->edit_ca_button = glade_xml_get_widget (cfm_data->gui, "authority-edit-button");
+ cfm_data->import_ca_button = glade_xml_get_widget (cfm_data->gui, "authority-import-button");
+ cfm_data->delete_ca_button = glade_xml_get_widget (cfm_data->gui, "authority-delete-button");
+
initialize_yourcerts_ui(cfm_data);
initialize_contactcerts_ui(cfm_data);
initialize_authoritycerts_ui(cfm_data);
diff --git a/smime/gui/smime-ui.glade b/smime/gui/smime-ui.glade
index a3475d21b6..338e927470 100644
--- a/smime/gui/smime-ui.glade
+++ b/smime/gui/smime-ui.glade
@@ -1173,6 +1173,7 @@
<child>
<widget class="GtkButton" id="your-view-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">View</property>
@@ -1184,6 +1185,7 @@
<child>
<widget class="GtkButton" id="your-backup-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
@@ -1325,6 +1327,7 @@
<child>
<widget class="GtkButton" id="your-delete-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-delete</property>
@@ -1429,6 +1432,7 @@
<child>
<widget class="GtkButton" id="contact-view-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">View</property>
@@ -1440,6 +1444,7 @@
<child>
<widget class="GtkButton" id="contact-edit-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
@@ -1516,6 +1521,7 @@
<child>
<widget class="GtkButton" id="contact-delete-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-delete</property>
@@ -1620,6 +1626,7 @@
<child>
<widget class="GtkButton" id="authority-view-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">View</property>
@@ -1631,6 +1638,7 @@
<child>
<widget class="GtkButton" id="authority-edit-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
@@ -1707,6 +1715,7 @@
<child>
<widget class="GtkButton" id="authority-delete-button">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-delete</property>
@@ -1750,4 +1759,214 @@
</child>
</widget>
+<widget class="GtkDialog" id="dialog1">
+ <property name="title" translatable="yes">dialog1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancelbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="okbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label64">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">You have been asked to trust a new Certificate Authority (CA).</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label65">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Do you want to trust &quot;%s&quot; for the following purposes?</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Trust this CA to identify web sites.</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Trust this CA to identify email users.</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Trust this CA to identify software developers.</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label66">
+ <property name="visible">True</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="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">1</property>
+
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">View Certificate</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
</glade-interface>
diff --git a/smime/lib/Makefile.am b/smime/lib/Makefile.am
index 4af28f2994..260238ba35 100644
--- a/smime/lib/Makefile.am
+++ b/smime/lib/Makefile.am
@@ -15,10 +15,12 @@ INCLUDES = \
-DLIBGNOME_DISABLE_DEPRECATED \
-DLIBGNOMEUI_DISABLE_DEPRECATED \
$(EVOLUTION_ADDRESSBOOK_CFLAGS) \
- $(CAMEL_CFLAGS)
+ $(CERT_UI_CFLAGS)
noinst_LTLIBRARIES = libessmime.la
libessmime_la_SOURCES = \
e-cert.c \
- e-cert.h
+ e-cert.h \
+ e-cert-db.c \
+ e-cert-db.h
diff --git a/smime/lib/e-cert-db.c b/smime/lib/e-cert-db.c
new file mode 100644
index 0000000000..8e98124a14
--- /dev/null
+++ b/smime/lib/e-cert-db.c
@@ -0,0 +1,822 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-cert-db.c
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Chris Toshok (toshok@ximian.com)
+ */
+
+/* The following is the mozilla license blurb, as the bodies of most
+ of these functions were derived from the mozilla source. */
+
+/*
+ * 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 Netscape are
+ * Copyright (C) 2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ *
+ */
+
+#include "e-cert-db.h"
+
+#include "nss.h"
+#include "pk11func.h"
+#include "certdb.h"
+#include <e-util/e-dialog-utils.h>
+#include <gtk/gtkmessagedialog.h>
+#include <libgnome/gnome-i18n.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+struct _ECertDBPrivate {
+};
+
+#define PARENT_TYPE G_TYPE_OBJECT
+static GObjectClass *parent_class;
+
+static CERTDERCerts* e_cert_db_get_certs_from_package (PRArenaPool *arena, char *data, guint32 length);
+
+
+
+static void
+e_cert_db_dispose (GObject *object)
+{
+ ECertDB *ec = E_CERT_DB (object);
+
+ if (!ec->priv)
+ return;
+
+ /* XXX free instance specific data */
+
+ g_free (ec->priv);
+ ec->priv = NULL;
+
+ if (G_OBJECT_CLASS (parent_class)->dispose)
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+e_cert_db_class_init (ECertDBClass *klass)
+{
+ GObjectClass *object_class;
+ char *evolution_dir_path;
+ gboolean success;
+
+ object_class = G_OBJECT_CLASS(klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ object_class->dispose = e_cert_db_dispose;
+
+ evolution_dir_path = g_build_path ("/", g_get_home_dir (), ".evolution", NULL);
+
+ /* we initialize NSS here to make sure it only happens once */
+ success = (SECSuccess == NSS_InitReadWrite (evolution_dir_path));
+ if (!success) {
+ success = (SECSuccess == NSS_Init (evolution_dir_path));
+ if (success)
+ g_warning ("opening cert databases read-only");
+ }
+ if (!success) {
+ success = (SECSuccess == NSS_NoDB_Init (evolution_dir_path));
+ if (success)
+ g_warning ("initializing security library without cert databases.");
+ }
+ g_free (evolution_dir_path);
+
+ if (!success) {
+ g_warning ("Failed all methods for initializing NSS");
+ }
+}
+
+static void
+e_cert_db_init (ECertDB *ec)
+{
+ ec->priv = g_new0 (ECertDBPrivate, 1);
+}
+
+GType
+e_cert_db_get_type (void)
+{
+ static GType cert_type = 0;
+
+ if (!cert_type) {
+ static const GTypeInfo cert_info = {
+ sizeof (ECertDBClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) e_cert_db_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ECertDB),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) e_cert_db_init,
+ };
+
+ cert_type = g_type_register_static (PARENT_TYPE, "ECertDB", &cert_info, 0);
+ }
+
+ return cert_type;
+}
+
+
+
+GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
+static ECertDB *cert_db = NULL;
+
+ECertDB*
+e_cert_db_peek (void)
+{
+ g_static_mutex_lock (&init_mutex);
+ if (!cert_db)
+ cert_db = g_object_new (E_TYPE_CERT_DB, NULL);
+ g_static_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 char *nickname,
+ GError **error)
+{
+ // nsNSSShutDownPreventionLock locker;
+ CERTCertificate *cert = NULL;
+
+ //PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
+#if 0
+ // what it should be, but for now...
+ if (aToken) {
+ cert = PK11_FindCertFromNickname(asciiname, NULL);
+ } else {
+ cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
+ }
+#endif
+ cert = PK11_FindCertFromNickname((char*)nickname, NULL);
+ if (!cert) {
+ cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), (char*)nickname);
+ }
+
+
+ if (cert) {
+ // PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));
+ ECert *ecert = e_cert_new (cert);
+ return ecert;
+ }
+ else {
+ /* XXX gerror */
+ return NULL;
+ }
+}
+
+ECert*
+e_cert_db_find_cert_by_key (ECertDB *certdb,
+ const char *db_key,
+ GError **error)
+{
+#if 0
+ // nsNSSShutDownPreventionLock locker;
+ SECItem keyItem = {siBuffer, NULL, 0};
+ SECItem *dummy;
+ CERTIssuerAndSN issuerSN;
+ unsigned long moduleID,slotID;
+ CERTCertificate *cert;
+
+ if (!db_key) {
+ /* XXX gerror */
+ 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;
+ }
+
+ /* XXX gerror */
+ return NULL;
+#endif
+}
+
+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 char *nickname,
+ GError **error)
+{
+}
+
+ECert*
+e_cert_db_find_email_signing_cert (ECertDB *certdb,
+ const char *nickname,
+ GError **error)
+{
+}
+
+ECert*
+e_cert_db_find_cert_by_email_address (ECertDB *certdb,
+ const char *email,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+ ECert *cert;
+ CERTCertificate *any_cert = CERT_FindCertByNicknameOrEmailAddr(CERT_GetDefaultCertDB(),
+ (char*)email);
+ CERTCertList *certlist;
+
+ if (!any_cert) {
+ /* XXX gerror */
+ 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) {
+ /* XXX gerror */
+ /* XXX free any_cert */
+ return NULL;
+ }
+
+ if (SECSuccess != CERT_FilterCertListByUsage(certlist, certUsageEmailRecipient, PR_FALSE)) {
+ /* XXX gerror */
+ /* XXX free any_cert */
+ /* XXX free certlist */
+ return NULL;
+ }
+
+ if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) {
+ /* XXX gerror */
+ /* XXX free any_cert */
+ /* XXX free certlist */
+ return NULL;
+ }
+
+ cert = e_cert_new (CERT_LIST_HEAD(certlist)->cert);
+
+ return cert;
+}
+
+static gboolean
+_confirm_download_ca_cert (ECert *cert, guint32 *trustBits, gboolean *allow)
+{
+ /* right now just allow it and set the trustBits to 0 */
+ *trustBits = 0;
+ *allow = TRUE;
+ return TRUE;
+}
+
+static gboolean
+handle_ca_cert_download(GList *certs, GError **error)
+{
+ ECert *certToShow;
+ SECItem der;
+ 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 char* cert0SubjectName;
+ const char* cert0IssuerName;
+ const char* cert1SubjectName;
+ const char* 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) {
+ /* XXX gerror */
+ return FALSE;
+ }
+
+ if (!e_cert_get_raw_der (certToShow, (char**)&der.data, &der.len)) {
+ /* XXX gerror */
+ return FALSE;
+ }
+
+ {
+ /*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");
+ return FALSE;
+ }
+ }
+
+#if 0
+ CERTCertificateCleaner tmpCertCleaner(tmpCert);
+#endif
+
+ if (tmpCert->isperm) {
+ e_notice (NULL, GTK_MESSAGE_WARNING, _("Certificate already exists"));
+ /* XXX gerror */
+ return FALSE;
+ }
+ else {
+ guint32 trustBits;
+ gboolean allow;
+ char *nickname;
+ SECStatus srv;
+
+ if (!_confirm_download_ca_cert (certToShow, &trustBits, &allow)) {
+ /* XXX gerror */
+ return FALSE;
+ }
+
+ if (!allow) {
+ /* XXX gerror */
+ 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()));
+
+#if 0
+ nsNSSCertTrust trust;
+ trust.SetValidCA();
+ trust.AddCATrust(trustBits & nsIX509CertDB::TRUSTED_SSL,
+ trustBits & nsIX509CertDB::TRUSTED_EMAIL,
+ trustBits & nsIX509CertDB::TRUSTED_OBJSIGN);
+#endif
+
+ srv = CERT_AddTempCertToPerm(tmpCert,
+ nickname,
+ /*XXX trust.GetTrust()*/ 0);
+
+ if (srv != SECSuccess) {
+ /* XXX gerror */
+ 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. */
+ nsNSSCertTrust defaultTrust;
+ defaultTrust.SetValidCA();
+ defaultTrust.AddCATrust(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(char*,nickname.get()),
+ defaultTrust.GetTrust());
+ CERT_DestroyCertificate(tmpCert2);
+ }
+#endif
+ 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;
+ SECStatus srv = SECSuccess;
+ 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. */
+#if 0
+ nsNSSCertTrust trust(0, 0, 0);
+ srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
+ cert, trust.GetTrust());
+#endif
+ }
+
+#if 0
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));
+#endif
+ return (srv) ? FALSE : TRUE;
+}
+
+/* importing certificates */
+gboolean
+e_cert_db_import_certs (ECertDB *certdb,
+ char *data, guint32 length,
+ ECertType cert_type,
+ 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);
+ int i;
+ gboolean rv;
+
+ if (!certCollection) {
+ /* XXX gerror */
+ 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 ((char*)currItem->data, currItem->len);
+ if (!cert) {
+ /* XXX gerror */
+ 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(certs, error);
+ break;
+ default:
+ // We only deal with import CA certs in this method currently.
+ /* XXX gerror */
+ 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,
+ char *data, guint32 length,
+ GError **error)
+{
+}
+
+gboolean
+e_cert_db_import_user_cert (ECertDB *certdb,
+ char *data, guint32 length,
+ GError **error)
+{
+#if 0
+ /* nsNSSShutDownPreventionLock locker;*/
+ PK11SlotInfo *slot;
+ char * nickname = NULL;
+ gboolean rv = FALSE;
+ int numCACerts;
+ SECItem *CACerts;
+ CERTDERCerts * collectArgs;
+ CERTCertificate * cert=NULL;
+
+ collectArgs = e_cert_db_get_certs_from_package(data, length);
+ if (!collectArgs) {
+ goto loser;
+ }
+
+ cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
+ (char *)NULL, PR_FALSE, PR_TRUE);
+ if (!cert) {
+ goto loser;
+ }
+
+ slot = PK11_KeyForCertExists(cert, NULL, NULL);
+ if ( slot == NULL ) {
+ 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 {
+ g_assert_not_reached ();
+ /* nickname = default_nickname(cert, NULL); */
+ }
+
+ /* user wants to import the cert */
+ slot = PK11_ImportCertForKey(cert, nickname, NULL);
+ if (!slot) {
+ 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 ( cert ) {
+ CERT_DestroyCertificate(cert);
+ }
+ return rv;
+#endif
+}
+
+gboolean
+e_cert_db_import_server_cert (ECertDB *certdb,
+ char *data, guint32 length,
+ GError **error)
+{
+}
+
+gboolean
+e_cert_db_import_certs_from_file (ECertDB *cert_db,
+ const char *file_path,
+ ECertType cert_type,
+ GError **error)
+{
+ gboolean rv;
+ int fd;
+ struct stat sb;
+ char *buf;
+ int bytes_read;
+
+ switch (cert_type) {
+ case E_CERT_CA:
+ case E_CERT_CONTACT:
+ case E_CERT_SITE:
+ /* good */
+ break;
+
+ default:
+ /* not supported (yet) */
+ /* XXX gerror */
+ return FALSE;
+ }
+
+ fd = open (file_path, O_RDONLY);
+ if (fd == -1) {
+ /* XXX gerror */
+ return FALSE;
+ }
+
+ if (-1 == fstat (fd, &sb)) {
+ /* XXX gerror */
+ close (fd);
+ return FALSE;
+ }
+
+ buf = g_malloc (sb.st_size);
+ if (!buf) {
+ /* XXX gerror */
+ close (fd);
+ return FALSE;
+ }
+
+ bytes_read = read (fd, buf, sb.st_size);
+
+ close (fd);
+
+ if (bytes_read != sb.st_size) {
+ /* XXX gerror */
+ 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, error);
+ break;
+
+ case E_CERT_SITE:
+ rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, error);
+ break;
+
+ case E_CERT_CONTACT:
+ rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, error);
+ break;
+
+ default:
+ rv = FALSE;
+ break;
+ }
+ }
+
+ g_free (buf);
+ return rv;
+}
+
+gboolean
+e_cert_db_import_pkcs12_file (ECertDB *cert_db,
+ const char *file_path,
+ GError **error)
+{
+}
+
+gboolean
+e_cert_db_export_pkcs12_file (ECertDB *cert_db,
+ const char *file_path,
+ GList *certs,
+ GError **error)
+{
+}
+
+
+
+static SECStatus PR_CALLBACK
+collect_certs(void *arg, SECItem **certs, int 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,
+ char *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,
+ (void *)collectArgs);
+
+ if (sec_rv != SECSuccess)
+ return NULL;
+
+ return collectArgs;
+}
diff --git a/smime/lib/e-cert-db.h b/smime/lib/e-cert-db.h
new file mode 100644
index 0000000000..ffc381587a
--- /dev/null
+++ b/smime/lib/e-cert-db.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#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))
+
+typedef struct _ECertDB ECertDB;
+typedef struct _ECertDBClass ECertDBClass;
+typedef struct _ECertDBPrivate ECertDBPrivate;
+
+struct _ECertDB {
+ GObject parent;
+
+ ECertDBPrivate *priv;
+};
+
+struct _ECertDBClass {
+ 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_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 char *nickname,
+ GError **error);
+
+ECert* e_cert_db_find_cert_by_key (ECertDB *certdb,
+ const char *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 char *nickname,
+ GError **error);
+
+ECert* e_cert_db_find_email_signing_cert (ECertDB *certdb,
+ const char *nickname,
+ GError **error);
+
+ECert* e_cert_db_find_cert_by_email_address (ECertDB *certdb,
+ const char *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,
+ char *data, guint32 length,
+ ECertType cert_type,
+ GError **error);
+
+gboolean e_cert_db_import_email_cert (ECertDB *certdb,
+ char *data, guint32 length,
+ GError **error);
+
+gboolean e_cert_db_import_user_cert (ECertDB *certdb,
+ char *data, guint32 length,
+ GError **error);
+
+gboolean e_cert_db_import_server_cert (ECertDB *certdb,
+ char *data, guint32 length,
+ GError **error);
+
+gboolean e_cert_db_import_certs_from_file (ECertDB *cert_db,
+ const char *file_path,
+ ECertType cert_type,
+ GError **error);
+
+gboolean e_cert_db_import_pkcs12_file (ECertDB *cert_db,
+ const char *file_path,
+ GError **error);
+
+gboolean e_cert_db_export_pkcs12_file (ECertDB *cert_db,
+ const char *file_path,
+ GList *certs,
+ GError **error);
+
+
+#endif /* _E_CERT_DB_H_ */
diff --git a/smime/lib/e-cert.c b/smime/lib/e-cert.c
index 5636730401..7db638b884 100644
--- a/smime/lib/e-cert.c
+++ b/smime/lib/e-cert.c
@@ -20,12 +20,54 @@
* Author: Chris Toshok (toshok@ximian.com)
*/
+/* The following is the mozilla license blurb, as the bodies some of
+ these functions were derived from the mozilla source. */
+
+/*
+ * 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 Netscape are
+ * Copyright (C) 2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ *
+ */
+
#include "e-cert.h"
+#include "pk11func.h"
+#include "certdb.h"
struct _ECertPrivate {
CERTCertificate *cert;
+
+ /* pointers we cache since the nss implementation allocs the
+ string */
char *org_name;
char *cn;
+
+ gboolean delete;
};
#define PARENT_TYPE G_TYPE_OBJECT
@@ -42,11 +84,23 @@ e_cert_dispose (GObject *object)
if (ec->priv->org_name)
PORT_Free (ec->priv->org_name);
if (ec->priv->cn)
- PORT_Free (ec->priv->org_name);
+ PORT_Free (ec->priv->cn);
+
+ if (ec->priv->delete) {
+ printf ("attempting to delete cert marked for deletion\n");
+ if (e_cert_get_cert_type (ec) == E_CERT_USER) {
+ PK11_DeleteTokenCertAndKey(ec->priv->cert, NULL);
+ } else if (!PK11_IsReadOnly(ec->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(ec->priv->cert);
+ }
+ }
g_free (ec->priv);
ec->priv = NULL;
-
+
if (G_OBJECT_CLASS (parent_class)->dispose)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -115,9 +169,47 @@ e_cert_new (CERTCertificate *cert)
return ecert;
}
+ECert*
+e_cert_new_from_der (char *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, char **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 = (char*)cert->priv->cert->derCert.data;
+ *len = (guint32)cert->priv->cert->derCert.len;
+ return TRUE;
+ }
+
+ *len = 0;
+ return FALSE;
+
+}
+
const char*
e_cert_get_nickname (ECert *cert)
{
@@ -141,8 +233,46 @@ e_cert_get_cn (ECert *cert)
return cert->priv->cn;
}
+const char*
+e_cert_get_issuer_name (ECert *cert)
+{
+ return cert->priv->cert->issuerName;
+}
+
+const char*
+e_cert_get_subject_name (ECert *cert)
+{
+ return cert->priv->cert->subjectName;
+}
+
gboolean
-e_cert_is_ca_cert (ECert *cert)
+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 (SECSuccess != PK11_Authenticate(cert->priv->cert->slot, PR_TRUE, NULL)) {
+ return FALSE;
+ }
+ }
+
+ cert->priv->delete = TRUE;
+
+ return TRUE;
+}
+
+ECertType
+e_cert_get_cert_type (ECert *cert)
{
- return CERT_IsCACert (cert->priv->cert, NULL);
+ if (CERT_IsCACert (cert->priv->cert, NULL))
+ return E_CERT_CA;
+ else /* XXX more here */
+ return E_CERT_USER;
}
diff --git a/smime/lib/e-cert.h b/smime/lib/e-cert.h
index 86517dad79..06b44f23ad 100644
--- a/smime/lib/e-cert.h
+++ b/smime/lib/e-cert.h
@@ -37,6 +37,13 @@ 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
+} ECertType;
+
struct _ECert {
GObject parent;
@@ -57,11 +64,20 @@ struct _ECertClass {
GType e_cert_get_type (void);
ECert* e_cert_new (CERTCertificate *cert);
+ECert* e_cert_new_from_der (char *data, guint32 len);
+
+CERTCertificate* e_cert_get_internal_cert (ECert *cert);
+
+gboolean e_cert_get_raw_der (ECert *cert, char **data, guint32 *len);
+const char* e_cert_get_nickname (ECert *cert);
+const char* e_cert_get_email (ECert *cert);
+const char* e_cert_get_org (ECert *cert);
+const char* e_cert_get_cn (ECert *cert);
+const char* e_cert_get_subject_name (ECert *cert);
+const char* e_cert_get_issuer_name (ECert *cert);
+
+gboolean e_cert_mark_for_deletion (ECert *cert);
-const char* e_cert_get_nickname (ECert *cert);
-const char* e_cert_get_email (ECert *cert);
-const char* e_cert_get_org (ECert *cert);
-const char* e_cert_get_cn (ECert *cert);
+ECertType e_cert_get_cert_type (ECert *cert);
-gboolean e_cert_is_ca_cert (ECert *cert);
#endif /* _E_CERT_H_ */
diff --git a/smime/tests/Makefile.am b/smime/tests/Makefile.am
index c07d048824..0fd1064b00 100644
--- a/smime/tests/Makefile.am
+++ b/smime/tests/Makefile.am
@@ -7,6 +7,7 @@ INCLUDES= \
TEST_LIBS= \
$(top_builddir)/smime/lib/libessmime.la \
+ -L/home/toshok/src/mozilla/mozilla/dist/lib \
$(CERT_UI_LIBS)
diff --git a/smime/tests/import-cert.c b/smime/tests/import-cert.c
index 63eb5a63f3..76e8dc6ccd 100644
--- a/smime/tests/import-cert.c
+++ b/smime/tests/import-cert.c
@@ -1,4 +1,5 @@
+#include <libgnomeui/gnome-ui-init.h>
#include "e-cert-db.h"
int
@@ -6,19 +7,12 @@ main (int argc, char **argv)
{
ECertDB *db;
- g_type_init ();
-
- if (SECSuccess != NSS_InitReadWrite ("/home/toshok/.mozilla/default/xuvq7jx3.slt")) {
- g_error ("NSS_InitReadWrite failed");
- }
+ gnome_program_init ();
- STAN_LoadDefaultNSS3TrustDomain();
+ g_type_init ();
db = e_cert_db_peek ();
- printf ("default_trust_domain = %p\n", STAN_GetDefaultTrustDomain());
- printf ("default_crypto_context = %p\n", STAN_GetDefaultCryptoContext());
-
if (!e_cert_db_import_certs_from_file (db, "ca.crt", E_CERT_CA, NULL /* XXX */)) {
g_warning ("CA cert import failed");
}