[evolution] Bug 268592 - Allow user certificate backup
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] Bug 268592 - Allow user certificate backup
- Date: Thu, 18 Sep 2014 06:46:57 +0000 (UTC)
commit 9c26a8dfa16396cfc65c24b066ed8e1c421ba3c4
Author: Christian Schaarschmidt <schaarsc gmx de>
Date: Thu Sep 18 08:43:37 2014 +0200
Bug 268592 - Allow user certificate backup
configure.ac | 4 +-
smime/gui/certificate-manager.c | 326 ++++++++++++++++++++++++++++++++++++++-
smime/lib/e-cert-db.c | 114 ++++++++++++--
smime/lib/e-cert-db.h | 7 +
smime/lib/e-pkcs12.c | 108 +++++++++++++-
smime/lib/e-pkcs12.h | 16 ++-
6 files changed, 554 insertions(+), 21 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 6d1e782..a83cba3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,8 +37,8 @@ m4_define([glib_minimum_version], [2.36.0])
m4_define([glib_encoded_version], [GLIB_VERSION_2_36])
dnl Keep these two definitions in agreement.
-m4_define([gdk_minimum_version], [3.8.0])
-m4_define([gdk_encoded_version], [GDK_VERSION_3_4])
+m4_define([gdk_minimum_version], [3.10.0])
+m4_define([gdk_encoded_version], [GDK_VERSION_3_10])
dnl Keep these two definitions in agreement.
m4_define([soup_minimum_version], [2.42])
diff --git a/smime/gui/certificate-manager.c b/smime/gui/certificate-manager.c
index b67577e..cbdc9d4 100644
--- a/smime/gui/certificate-manager.c
+++ b/smime/gui/certificate-manager.c
@@ -68,6 +68,8 @@ enum {
#define ECMC_TREE_VIEW(o) ecmc->priv->o->treeview
#define PAGE_TREE_VIEW(o) o->treeview
+#define STRING_IS_EMPTY(x) (!(x) || !(*(x)))
+
typedef struct {
GType type;
const gchar *column_title;
@@ -162,6 +164,16 @@ struct _ECertManagerConfigPrivate {
CertPage *authoritycerts_page;
};
+typedef struct {
+ GFile **file;
+ GtkWidget *entry1;
+ GtkWidget *entry2;
+ GtkWidget *match_label;
+ GtkWidget *save_button;
+ CertPage *cp;
+ ECert *cert;
+} BackupData;
+
static void view_cert (GtkWidget *button, CertPage *cp);
static void edit_cert (GtkWidget *button, CertPage *cp);
static void delete_cert (GtkWidget *button, CertPage *cp);
@@ -405,6 +417,8 @@ treeview_selection_changed (GtkTreeSelection *selection,
gtk_widget_set_sensitive (cp->edit_button, cert_selected);
if (cp->view_button)
gtk_widget_set_sensitive (cp->view_button, cert_selected);
+ if (cp->backup_button)
+ gtk_widget_set_sensitive (cp->backup_button, cert_selected);
}
static void
@@ -550,6 +564,309 @@ view_cert (GtkWidget *button,
}
}
+static gboolean
+cert_backup_dialog_sensitize (GtkWidget *widget,
+ GdkEvent *event,
+ BackupData *data)
+{
+
+ const gchar *txt1, *txt2;
+ gboolean is_sensitive = TRUE;
+
+ txt1 = gtk_entry_get_text (GTK_ENTRY (data->entry1));
+ txt2 = gtk_entry_get_text (GTK_ENTRY (data->entry2));
+
+ if (*data->file == NULL)
+ is_sensitive = FALSE;
+
+ if (STRING_IS_EMPTY (txt1) && STRING_IS_EMPTY (txt2)) {
+ gtk_widget_set_visible (data->match_label, FALSE);
+ is_sensitive = FALSE;
+ } else if (g_strcmp0 (txt1, txt2) == 0) {
+ gtk_widget_set_visible (data->match_label, FALSE);
+ } else {
+ gtk_widget_set_visible (data->match_label, TRUE);
+ is_sensitive = FALSE;
+ }
+
+ gtk_widget_set_sensitive (data->save_button, is_sensitive);
+
+ return FALSE;
+}
+
+static void
+cert_backup_dialog_maybe_correct_extension (GtkFileChooser *file_chooser)
+{
+ gchar *name = gtk_file_chooser_get_current_name (file_chooser);
+
+ if (!g_str_has_suffix (name, ".p12")) {
+ gchar *new_name = g_strconcat (name, ".p12", NULL);
+ gtk_file_chooser_set_current_name (file_chooser, new_name);
+ g_free (new_name);
+ }
+
+ g_free (name);
+}
+
+static void
+cert_backup_dialog_file_chooser_save_activate_cb (GtkWidget *button,
+ GtkFileChooser *file_chooser)
+{
+ cert_backup_dialog_maybe_correct_extension (file_chooser);
+}
+
+static gboolean
+cert_backup_dialog_file_chooser_save_event_cb (GtkWidget *button,
+ GdkEvent *event,
+ GtkFileChooser *file_chooser)
+{
+ cert_backup_dialog_maybe_correct_extension (file_chooser);
+
+ return FALSE;
+}
+
+static void
+run_cert_backup_dialog_file_chooser (GtkButton *file_button,
+ BackupData *data)
+{
+ GtkWidget *filesel, *button;
+ GtkFileFilter *filter;
+ gchar *filename;
+
+ filesel = gtk_file_chooser_dialog_new (
+ _("Select a file to backup your key and certificate..."), NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Save"), GTK_RESPONSE_OK,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (filesel), TRUE);
+ /* To Translators:
+ * %s-backup.p12 is the default file name suggested by the file selection dialog,
+ * when a user wants to backup one of her/his private keys/certificates.
+ * For example: gnomedev-backup.p12
+ */
+ filename = g_strdup_printf (_("%s-backup.p12"), e_cert_get_nickname (data->cert));
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filesel), filename);
+ g_free (filename);
+
+ if (*data->file) {
+ gtk_file_chooser_set_file (GTK_FILE_CHOOSER (filesel), *data->file, NULL);
+ }
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, data->cp->cert_filter_name);
+ gtk_file_filter_add_mime_type (filter, "application/x-pkcs12");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All files"));
+ gtk_file_filter_add_pattern (filter, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter);
+
+ button = gtk_dialog_get_widget_for_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
+ g_signal_connect (button, "activate",
+ G_CALLBACK (cert_backup_dialog_file_chooser_save_activate_cb), filesel);
+ g_signal_connect (button, "enter-notify-event",
+ G_CALLBACK (cert_backup_dialog_file_chooser_save_event_cb), filesel);
+
+ if (gtk_dialog_run (GTK_DIALOG (filesel)) == GTK_RESPONSE_OK) {
+ gchar *basename;
+
+ if (*data->file) {
+ g_object_unref (*data->file);
+ *data->file = NULL;
+ }
+
+ *data->file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (filesel));
+
+ basename = g_file_get_basename (*data->file);
+ gtk_button_set_label (file_button, basename);
+ g_free (basename);
+ }
+
+ /* destroy dialog to get rid of it in the GUI */
+ gtk_widget_destroy (filesel);
+
+ cert_backup_dialog_sensitize (GTK_WIDGET (file_button), NULL, data);
+ gtk_widget_grab_focus (GTK_WIDGET (data->entry1));
+}
+
+static gint
+run_cert_backup_dialog (CertPage *cp,
+ ECert *cert,
+ GFile **file,
+ gchar **password,
+ gboolean *save_chain)
+{
+ gint row = 0, col = 0, response;
+ const gchar *format = "<span foreground=\"red\">%s</span>";
+ gchar *markup;
+ GtkWidget *dialog, *content_area, *button, *label, *chain;
+ GtkGrid *grid;
+ GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
+ BackupData data;
+
+ data.cp = cp;
+ data.cert = cert;
+ data.file = file;
+
+ dialog = gtk_dialog_new_with_buttons (
+ "Backup Certificate", NULL, flags,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Save"), GTK_RESPONSE_OK,
+ NULL);
+ g_object_set (dialog, "resizable", FALSE, NULL);
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+ g_object_set (content_area, "border-width", 6, NULL);
+
+ grid = GTK_GRID (gtk_grid_new ());
+ g_object_set (grid, "column-spacing", 12, NULL);
+ g_object_set (grid, "row-spacing", 6, NULL);
+
+ /* filename selection */
+ label = gtk_label_new_with_mnemonic (_("_File name:"));
+ g_object_set (label, "halign", GTK_ALIGN_START, NULL);
+ gtk_grid_attach (grid, label, col++, row, 1, 1);
+
+ /* FIXME when gtk_file_chooser_button allows GTK_FILE_CHOOSER_ACTION_SAVE use it */
+ button = gtk_button_new_with_label (_("Please select a file..."));
+ g_signal_connect (
+ button, "clicked",
+ G_CALLBACK (run_cert_backup_dialog_file_chooser),
+ &data);
+ g_signal_connect (
+ button, "focus-in-event",
+ G_CALLBACK (cert_backup_dialog_sensitize),
+ &data);
+ gtk_grid_attach (grid, button, col++, row++, 1, 1);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
+
+ /* cert chain option */
+ col = 1;
+ chain = gtk_check_button_new_with_mnemonic (_("_Include certificate chain in the backup"));
+ gtk_grid_attach (grid, chain, col, row++, 1, 1);
+
+ /* password */
+ col = 0;
+ /* To Translators: this text was copied from Firefox */
+ label = gtk_label_new (_("The certificate backup password you set here protects "
+ "the backup file that you are about to create.\nYou must set this password to proceed with
the backup."));
+ gtk_grid_attach (grid, label, col, row++, 2, 1);
+
+ col = 0;
+ label = gtk_label_new_with_mnemonic (_("_Password:"));
+ g_object_set (label, "halign", GTK_ALIGN_START, NULL);
+ gtk_grid_attach (grid, label, col++, row, 1, 1);
+
+ data.entry1 = gtk_entry_new ();
+ g_signal_connect(
+ data.entry1, "key-release-event",
+ G_CALLBACK (cert_backup_dialog_sensitize),
+ &data);
+ gtk_entry_set_visibility (GTK_ENTRY (data.entry1), FALSE);
+ gtk_grid_attach (grid, data.entry1, col++, row++, 1, 1);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (data.entry1));
+
+ col = 0;
+ label = gtk_label_new_with_mnemonic (_("_Repeat Password:"));
+ g_object_set (label, "halign", GTK_ALIGN_START, NULL);
+ gtk_grid_attach (grid, label, col++, row, 1, 1);
+
+ data.entry2 = gtk_entry_new ();
+ g_signal_connect(
+ data.entry2, "key-release-event",
+ G_CALLBACK (cert_backup_dialog_sensitize),
+ &data);
+ gtk_entry_set_visibility (GTK_ENTRY (data.entry2), FALSE);
+ gtk_grid_attach (grid, data.entry2, col++, row++, 1, 1);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (data.entry2));
+
+ col = 0;
+ label = gtk_label_new (""); /* force grid to create a row for match_label */
+ gtk_grid_attach (grid, label, col++, row, 1, 1);
+
+ data.match_label = gtk_label_new ("");
+ g_object_set (data.match_label, "halign", GTK_ALIGN_START, NULL);
+ markup = g_markup_printf_escaped (format, _("Passwords do not match"));
+ gtk_label_set_markup (GTK_LABEL (data.match_label), markup);
+ g_free (markup);
+ gtk_grid_attach (grid, data.match_label, col, row++, 1, 1);
+ gtk_widget_set_visible (data.match_label, FALSE);
+
+ col = 0;
+ /* To Translators: this text was copied from Firefox */
+ label = gtk_label_new (_("Important:\nIf you forget your certificate backup password, "
+ "you will not be able to restore this backup later.\nPlease record it in a safe location."));
+ gtk_grid_attach (grid, label, col, row++, 2, 1);
+
+ /* add widget to dialog and show all */
+ gtk_widget_show_all (GTK_WIDGET (grid));
+ gtk_container_add (GTK_CONTAINER (content_area), GTK_WIDGET (grid));
+
+ data.save_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_widget_set_sensitive (data.save_button, FALSE);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ *password = strdup (gtk_entry_get_text (GTK_ENTRY (data.entry1)));
+ *save_chain = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chain));
+
+ gtk_widget_destroy (dialog);
+
+ return response;
+}
+
+static void
+backup_cert (GtkWidget *button,
+ CertPage *cp)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (cp->treeview), NULL, &iter)) {
+ ECert *cert;
+
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (cp->streemodel),
+ &iter,
+ cp->columns_count - 1,
+ &cert,
+ -1);
+
+ if (cert) {
+ GFile *file = NULL;
+ gchar *password = NULL;
+ gboolean save_chain = FALSE;
+
+ if (run_cert_backup_dialog (cp, cert, &file, &password, &save_chain) ==
GTK_RESPONSE_OK) {
+ if (!file) {
+ e_notice (
+ gtk_widget_get_toplevel (GTK_WIDGET (cp->treeview)),
+ GTK_MESSAGE_ERROR, "%s", _("No file name provided"));
+ } else if (cp->cert_type == E_CERT_USER) {
+ GError *error = NULL;
+ if (!e_cert_db_export_pkcs12_file (cert, file, password, save_chain,
&error)) {
+ report_and_free_error (cp, _("Failed to backup key and
certificate"), error);
+ }
+ } else {
+ g_warn_if_reached ()
+ ;
+ }
+ }
+
+ if (file)
+ g_object_unref (file);
+ if (password) {
+ memset (password, 0, strlen (password));
+ g_free (password);
+ }
+
+ g_object_unref (cert);
+ }
+ }
+
+}
+
static void
edit_cert (GtkWidget *button,
CertPage *cp)
@@ -894,6 +1211,12 @@ initialize_ui (CertPage *cp)
g_signal_connect (
cp->view_button, "clicked",
G_CALLBACK (view_cert), cp);
+
+ if (cp->backup_button)
+ g_signal_connect(
+ cp->backup_button, "clicked",
+ G_CALLBACK (backup_cert),
+ cp);
}
static void
@@ -1105,8 +1428,7 @@ e_cert_manager_config_init (ECertManagerConfig *ecmc)
gtk_widget_show_all (widget);
/* FIXME: remove when implemented */
- gtk_widget_set_sensitive (priv->yourcerts_page->backup_button, FALSE);
- gtk_widget_set_sensitive (priv->yourcerts_page->backup_all_button, FALSE);
+ gtk_widget_set_visible (priv->yourcerts_page->backup_all_button, FALSE);
}
GtkWidget *
diff --git a/smime/lib/e-cert-db.c b/smime/lib/e-cert-db.c
index abb07be..3aeb047 100644
--- a/smime/lib/e-cert-db.c
+++ b/smime/lib/e-cert-db.c
@@ -363,20 +363,86 @@ e_cert_db_get_certs_from_package (PRArenaPool *arena,
return collectArgs;
}
-#ifdef notyet
-PRBool
-ucs2_ascii_conversion_fn (PRBool toUnicode,
- guchar *inBuf,
- guint inBufLen,
- guchar *outBuf,
- guint maxOutBufLen,
- guint *outBufLen,
- PRBool swapBytes)
+/*
+ * copy from pk12util.c
+ */
+static SECStatus
+p12u_SwapUnicodeBytes(SECItem *uniItem)
{
- printf ("in ucs2_ascii_conversion_fn\n");
+ unsigned int i;
+ unsigned char a;
+ if ((uniItem == NULL) || (uniItem->len % 2)) {
+ return SECFailure;
+ }
+ for (i = 0; i < uniItem->len; i += 2) {
+ a = uniItem->data[i];
+ uniItem->data[i] = uniItem->data[i+1];
+ uniItem->data[i+1] = a;
+ }
+ return SECSuccess;
}
+
+/*
+ * copy from pk12util.c
+ */
+static PRBool
+p12u_ucs2_ascii_conversion_function(PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen,
+ PRBool swapBytes)
+{
+ SECItem it = { 0 };
+ SECItem *dup = NULL;
+ PRBool ret;
+
+#ifdef DEBUG_CONVERSION
+ if (pk12_debugging) {
+ unsigned int i;
+ printf ("Converted from:\n");
+ for (i = 0; i < inBufLen; i++) {
+ printf("%2x ", inBuf[i]);
+ /*if ((i % 60) == 0) printf ("\n");*/
+ }
+ printf ("\n");
+ }
+#endif
+
+ it.data = inBuf;
+ it.len = inBufLen;
+ dup = SECITEM_DupItem(&it);
+ /* If converting Unicode to ASCII, swap bytes before conversion
+ * as neccessary.
+ */
+ if (!toUnicode && swapBytes) {
+ if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
+ SECITEM_ZfreeItem(dup, PR_TRUE);
+ return PR_FALSE;
+ }
+ }
+ /* Perform the conversion. */
+ ret = PORT_UCS2_UTF8Conversion (toUnicode, dup->data, dup->len,
+ outBuf, maxOutBufLen, outBufLen);
+ if (dup)
+ SECITEM_ZfreeItem(dup, PR_TRUE);
+
+#ifdef DEBUG_CONVERSION
+ if (pk12_debugging) {
+ unsigned int ii;
+ printf ("Converted to:\n");
+ for (ii = 0; ii < *outBufLen; ii++) {
+ printf ("%2x ", outBuf[ii]);
+ /*if ((i % 60) == 0) printf ("\n");*/
+ }
+ printf ("\n");
+ }
#endif
+ return ret;
+}
+
static gchar * PR_CALLBACK
pk11_password (PK11SlotInfo *slot,
PRBool retry,
@@ -421,9 +487,7 @@ initialize_nss (void)
SEC_PKCS12EnableCipher (PKCS12_DES_56, 1);
SEC_PKCS12EnableCipher (PKCS12_DES_EDE3_168, 1);
SEC_PKCS12SetPreferredCipher (PKCS12_DES_EDE3_168, 1);
-#ifdef notyet
- PORT_SetUCS2_ASCIIConversionFunction (ucs2_ascii_conversion_fn);
-#endif
+ PORT_SetUCS2_ASCIIConversionFunction (p12u_ucs2_ascii_conversion_function);
}
static void
@@ -1122,6 +1186,30 @@ e_cert_db_import_pkcs12_file (ECertDB *cert_db,
}
gboolean
+e_cert_db_export_pkcs12_file (ECert *cert,
+ GFile *file,
+ const gchar *password,
+ gboolean save_chain,
+ GError **error)
+{
+ GError *e = NULL;
+ GList *list = NULL;
+
+ g_return_val_if_fail (cert != NULL, FALSE);
+ list = g_list_append (list, cert);
+
+ if (!e_pkcs12_export_to_file (list, file, password, save_chain, &e)) {
+ g_list_free (list);
+ g_propagate_error (error, e);
+ return FALSE;
+ }
+
+ g_list_free (list);
+
+ return TRUE;
+}
+
+gboolean
e_cert_db_login_to_slot (ECertDB *cert_db,
PK11SlotInfo *slot)
{
diff --git a/smime/lib/e-cert-db.h b/smime/lib/e-cert-db.h
index 34ef6ca..016cfd9 100644
--- a/smime/lib/e-cert-db.h
+++ b/smime/lib/e-cert-db.h
@@ -23,6 +23,7 @@
#define _E_CERT_DB_H_
#include <glib-object.h>
+#include <gio/gio.h>
#include "e-cert.h"
#include <cert.h>
@@ -100,6 +101,12 @@ gboolean e_cert_db_import_pkcs12_file (ECertDB *cert_db,
const gchar *file_path,
GError **error);
+gboolean e_cert_db_export_pkcs12_file (ECert *cert,
+ GFile *file,
+ const gchar *password,
+ gboolean save_chain,
+ GError **error);
+
gboolean e_cert_db_login_to_slot (ECertDB *cert_db,
PK11SlotInfo *slot);
diff --git a/smime/lib/e-pkcs12.c b/smime/lib/e-pkcs12.c
index 98fe181..9e5e2ff 100644
--- a/smime/lib/e-pkcs12.c
+++ b/smime/lib/e-pkcs12.c
@@ -80,6 +80,8 @@ static gboolean handle_error (gint myerr);
G_DEFINE_TYPE (EPKCS12, e_pkcs12, G_TYPE_OBJECT)
+G_DEFINE_QUARK (e-pkcs12-error-quark, e_pkcs12_error)
+
static void
e_pkcs12_class_init (EPKCS12Class *class)
{
@@ -285,12 +287,112 @@ e_pkcs12_import_from_file (EPKCS12 *pkcs12,
return rv;
}
+static void
+encoder_output_cb (void *arg,
+ const char *buf,
+ unsigned long len)
+{
+ GError *error = NULL;
+
+ g_output_stream_write (G_OUTPUT_STREAM (arg), buf, len, NULL, &error);
+
+ if (error != NULL) {
+ g_warning ("I/O error during certificate backup, error message: %s", error->message);
+ g_error_free (error);
+ }
+}
+
gboolean
-e_pkcs12_export_to_file (EPKCS12 *pkcs12,
- const gchar *path,
- GList *certs,
+e_pkcs12_export_to_file (GList *certs,
+ GFile *file,
+ const gchar *pwd,
+ gboolean save_chain,
GError **error)
{
+ GList *link;
+ SECStatus srv = SECSuccess;
+ GFileOutputStream *output_stream;
+ SEC_PKCS12ExportContext *p12exp = NULL;
+ SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
+ SECItem password;
+
+ password.data = (guchar *) strdup (pwd);
+ password.len = strlen (pwd);
+
+ p12exp = SEC_PKCS12CreateExportContext (
+ NULL /* SECKEYGetPasswordKey pwfn*/,
+ NULL /* void *pwfnarg */,
+ NULL /* slot */,
+ NULL /* void *wincx*/);
+ if (!p12exp) {
+ gint err_code = PORT_GetError ();
+ *error = g_error_new (E_PKCS12_ERROR, E_PKCS12_ERROR_NSS_FAILED, _("Unable to create export
context, err_code: %i"), err_code);
+ goto error;
+ }
+
+ srv = SEC_PKCS12AddPasswordIntegrity (p12exp, &password, SEC_OID_SHA1);
+ if (srv != SECSuccess) {
+ gint err_code = PORT_GetError();
+ *error = g_error_new (E_PKCS12_ERROR, E_PKCS12_ERROR_NSS_FAILED, _("Unable to setup password
integrity, err_code: %i"), err_code);
+ goto error;
+ }
+
+ for (link = certs; link; link = g_list_next (link)) {
+ keySafe = NULL, certSafe = NULL;
+ keySafe = SEC_PKCS12CreateUnencryptedSafe (p12exp);
+ certSafe = SEC_PKCS12CreatePasswordPrivSafe (p12exp, &password,
SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
+ if (!keySafe || !certSafe) {
+ gint err_code = PORT_GetError();
+ *error = g_error_new (E_PKCS12_ERROR, E_PKCS12_ERROR_NSS_FAILED, _("Unable to create
safe bag, err_code: %i"), err_code);
+ goto error;
+ }
+
+ srv = SEC_PKCS12AddCertOrChainAndKey (
+ p12exp /* SEC_PKCS12ExportContext *p12ctxt */,
+ certSafe,
+ NULL /* void *certNestedDest */,
+ e_cert_get_internal_cert (E_CERT (link->data)),
+ CERT_GetDefaultCertDB () /* CERTCertDBHandle *certDb */,
+ keySafe,
+ NULL /* void *keyNestedDest*/,
+ PR_TRUE /* PRBool shroudKey */,
+ &password /* SECItem *pwItem */,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC/* SECOidTag algorithm
*/,
+ save_chain /* includeCertChain */);
+ if (srv != SECSuccess) {
+ gint err_code = PORT_GetError ();
+ *error = g_error_new (E_PKCS12_ERROR, E_PKCS12_ERROR_NSS_FAILED, _("Unable to add
key/cert to the store, err_code: %i"), err_code);
+ goto error;
+ }
+ }
+
+ output_stream = g_file_replace (file, NULL, TRUE, G_FILE_CREATE_PRIVATE, NULL, error);
+ if (!output_stream) {
+ goto error;
+ }
+ srv = SEC_PKCS12Encode (
+ p12exp,
+ encoder_output_cb /* SEC_PKCS12EncoderOutputCallback output */,
+ output_stream /* void *outputarg */);
+ if (!g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, error))
+ goto error;
+
+ if (srv != SECSuccess) {
+ gint err_code = PORT_GetError ();
+ *error = g_error_new (E_PKCS12_ERROR, E_PKCS12_ERROR_NSS_FAILED, _("Unable to write store to
disk, err_code: %i"), err_code);
+ goto error;
+ }
+
+ SEC_PKCS12DestroyExportContext (p12exp);
+ SECITEM_ZfreeItem (&password, PR_FALSE); /* free password.data */
+
+ return TRUE;
+
+ error:
+ SECITEM_ZfreeItem (&password, PR_FALSE); /* free password.data */
+ if (p12exp)
+ SEC_PKCS12DestroyExportContext (p12exp);
+
return FALSE;
}
diff --git a/smime/lib/e-pkcs12.h b/smime/lib/e-pkcs12.h
index 54431b5..bb627e4 100644
--- a/smime/lib/e-pkcs12.h
+++ b/smime/lib/e-pkcs12.h
@@ -50,6 +50,16 @@ struct _EPKCS12Class {
void (*_epkcs12_reserved4) (void);
};
+#define E_PKCS12_ERROR e_pkcs12_error_quark ()
+GQuark e_pkcs12_error_quark (void) G_GNUC_CONST;
+
+typedef enum
+{
+ E_PKCS12_ERROR_CANCELED,
+ E_PKCS12_ERROR_NSS_FAILED,
+ E_PKCS12_ERROR_FAILED
+} EPKCS12Errors;
+
GType e_pkcs12_get_type (void);
EPKCS12 * e_pkcs12_new (void);
@@ -62,6 +72,10 @@ gboolean e_pkcs12_set_token (void);
#endif
gboolean e_pkcs12_import_from_file (EPKCS12 *pkcs12, const gchar *path, GError **error);
-gboolean e_pkcs12_export_to_file (EPKCS12 *pkcs12, const gchar *path, GList *certs, GError
**error);
+gboolean e_pkcs12_export_to_file (GList *certs,
+ GFile *file,
+ const gchar *pwd,
+ gboolean save_chain,
+ GError **error);
#endif /* _E_CERT_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]