From 4e1bce59fa373fd302b994d495427109c9fff121 Mon Sep 17 00:00:00 2001 From: Chris Toshok 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 * 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 +#include +#include +#include +#include +#include +#include + +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; iGetRawDER(&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; inumcerts; 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 + * + * 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 +#include "e-cert.h" +#include + +#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 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