aboutsummaryrefslogtreecommitdiffstats
path: root/smime/lib
diff options
context:
space:
mode:
Diffstat (limited to 'smime/lib')
-rw-r--r--smime/lib/Makefile.am6
-rw-r--r--smime/lib/e-cert-db.c822
-rw-r--r--smime/lib/e-cert-db.h128
-rw-r--r--smime/lib/e-cert.c138
-rw-r--r--smime/lib/e-cert.h26
5 files changed, 1109 insertions, 11 deletions
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_ */