don't init NSS here. it's done in e_cert_db_peek.

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.

svn path=/trunk/; revision=23292
This commit is contained in:
Chris Toshok 2003-11-12 02:07:25 +00:00 committed by Chris Toshok
parent 747e7843d1
commit 4e1bce59fa
10 changed files with 1658 additions and 78 deletions

View File

@ -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.

View File

@ -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
@ -159,10 +256,85 @@ iter_string_compare (GtkTreeModel *model,
return g_utf8_collate (string1, string2);
}
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);
if (cfm->import_ca_button)
g_signal_connect (cfm->import_ca_button, "clicked", G_CALLBACK (import_ca), cfm);
if (cfm->delete_ca_button)
g_signal_connect (cfm->delete_ca_button, "clicked", G_CALLBACK (delete_ca), cfm);
}
static CertType
get_cert_type (ECert *cert)
{
const char *nick = e_cert_get_nickname (cert);
const char *email = e_cert_get_email (cert);
if (e_cert_is_ca_cert (cert))
return CA_CERT;
/* XXX more stuff in here */
else
return USER_CERT;
}
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);

View File

@ -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>

View File

@ -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

822
smime/lib/e-cert-db.c Normal file
View File

@ -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;
}

128
smime/lib/e-cert-db.h Normal file
View File

@ -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_ */

View File

@ -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;
}
gboolean
e_cert_is_ca_cert (ECert *cert)
const char*
e_cert_get_issuer_name (ECert *cert)
{
return CERT_IsCACert (cert->priv->cert, NULL);
return cert->priv->cert->issuerName;
}
const char*
e_cert_get_subject_name (ECert *cert)
{
return cert->priv->cert->subjectName;
}
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 (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)
{
if (CERT_IsCACert (cert->priv->cert, NULL))
return E_CERT_CA;
else /* XXX more here */
return E_CERT_USER;
}

View File

@ -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);
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);
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);
ECertType e_cert_get_cert_type (ECert *cert);
gboolean e_cert_is_ca_cert (ECert *cert);
#endif /* _E_CERT_H_ */

View File

@ -7,6 +7,7 @@ INCLUDES= \
TEST_LIBS= \
$(top_builddir)/smime/lib/libessmime.la \
-L/home/toshok/src/mozilla/mozilla/dist/lib \
$(CERT_UI_LIBS)

View File

@ -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;
gnome_program_init ();
g_type_init ();
if (SECSuccess != NSS_InitReadWrite ("/home/toshok/.mozilla/default/xuvq7jx3.slt")) {
g_error ("NSS_InitReadWrite failed");
}
STAN_LoadDefaultNSS3TrustDomain();
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");
}