From 4e1bce59fa373fd302b994d495427109c9fff121 Mon Sep 17 00:00:00 2001
From: Chris Toshok <toshok@ximian.com>
Date: Wed, 12 Nov 2003 02:07:25 +0000
Subject: 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
---
 smime/lib/Makefile.am |   6 +-
 smime/lib/e-cert-db.c | 822 ++++++++++++++++++++++++++++++++++++++++++++++++++
 smime/lib/e-cert-db.h | 128 ++++++++
 smime/lib/e-cert.c    | 138 ++++++++-
 smime/lib/e-cert.h    |  26 +-
 5 files changed, 1109 insertions(+), 11 deletions(-)
 create mode 100644 smime/lib/e-cert-db.c
 create mode 100644 smime/lib/e-cert-db.h

(limited to 'smime/lib')

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