/** * seahorse_service_crypto_sign_text: * @crypto: SeahorseServiceCrypto * @signer: the signer keyid * @flags: 0 (ignored) * @cleartext: the text to sign * @crypttext: the clear text signature (out) (GPGME_SIG_MODE_CLEAR) * @error: an error to return * * DBus: SignText * * Signs the @cleartext and returns the signature in @crypttext * * Returns: TRUE on success */ gboolean seahorse_service_crypto_sign_text (SeahorseServiceCrypto *crypto, const char *signer, int flags, const char *cleartext, char **crypttext, GError **error) { SeahorseObject *signkey = NULL; gpgme_error_t gerr; SeahorseGpgmeOperation *pop; gpgme_data_t plain, cipher; gboolean ret = TRUE; /* * TODO: Once we support different kinds of keys that support encryption * then all this logic will need to change. */ /* The signer */ if (!signer || !signer[0]) g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("No signer specified")); signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer); if (!signkey) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized signer: %s"), signer); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (signkey) || !(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not valid for signing: %s"), signer); return FALSE; } pop = seahorse_gpgme_operation_new (NULL); /* new data from text */ gerr = gpgme_data_new_from_mem (&plain, cleartext, strlen (cleartext), FALSE); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); gerr = gpgme_data_new (&cipher); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); /* encrypt with armor */ gpgme_set_textmode (pop->gctx, TRUE); gpgme_set_armor (pop->gctx, TRUE); /* Do the signage */ gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey))); gerr = gpgme_op_sign_start (pop->gctx, plain, cipher, GPGME_SIG_MODE_CLEAR); /* Frees cipher */ ret = process_crypto_result (pop, gerr, cipher, crypttext, NULL, error); g_object_unref (pop); gpgme_data_release (plain); return ret; }
/** * gpgme_generate_key: * @sksrc: the bastile source * @name: the user's full name * @email: the user's email address * @comment: a comment, added to the key * @type: key type like DSA_ELGAMAL * @bits: the number of bits for the key to generate (2048) * @expires: expiry date can be 0 * * Displays a password generation box and creates a key afterwards. For the key * data it uses @name @email and @comment ncryption is chosen by @type and @bits * @expire sets the expiry date * */ void bastile_gpgme_generate_key (BastileGpgmeSource *sksrc, const gchar *name, const gchar *email, const gchar *comment, guint type, guint bits, time_t expires) { BastileOperation *op; const gchar *pass; gpgme_error_t gerr; GtkDialog *dialog; dialog = bastile_passphrase_prompt_show (_("Passphrase for New PGP Key"), _("Enter the passphrase for your new key twice."), NULL, NULL, TRUE); if (gtk_dialog_run (dialog) == GTK_RESPONSE_ACCEPT) { pass = bastile_passphrase_prompt_get (dialog); op = bastile_gpgme_key_op_generate (sksrc, name, email, comment, pass, type, bits, expires, &gerr); if (!GPG_IS_OK (gerr)) { bastile_gpgme_handle_error (gerr, _("Couldn't generate key")); } else { bastile_progress_show (op, _("Generating key"), TRUE); bastile_operation_watch (op, (BastileDoneFunc)completion_handler, NULL, NULL, NULL); g_object_unref (op); } } gtk_widget_destroy (GTK_WIDGET (dialog)); }
void seahorse_gpgme_add_revoker_new (SeahorseGpgmeKey *pkey, GtkWindow *parent) { SeahorseGpgmeKey *revoker; GtkWidget *dialog; gint response; gpgme_error_t err; const gchar *userid1, *userid2; g_return_if_fail (pkey != NULL && SEAHORSE_IS_GPGME_KEY (pkey)); revoker = SEAHORSE_GPGME_KEY (seahorse_signer_get (parent)); if (revoker == NULL) return; userid1 = seahorse_object_get_label (SEAHORSE_OBJECT (revoker)); userid2 = seahorse_object_get_label (SEAHORSE_OBJECT (pkey)); dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("You are about to add %s as a revoker for %s." " This operation cannot be undone! Are you sure you want to continue?"), userid1, userid2); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (response != GTK_RESPONSE_YES) return; err = seahorse_gpgme_key_op_add_revoker (pkey, revoker); if (!GPG_IS_OK (err)) seahorse_gpgme_handle_error (err, _("Couldn't add revoker")); }
G_MODULE_EXPORT void on_gpgme_revoke_ok_clicked (GtkButton *button, gpointer user_data) { SeahorseWidget *swidget = SEAHORSE_WIDGET (user_data); SeahorseRevokeReason reason; SeahorseGpgmeSubkey *subkey; const gchar *description; gpgme_error_t err; GtkWidget *widget; GtkTreeModel *model; GtkTreeIter iter; GValue value; widget = GTK_WIDGET (seahorse_widget_get_widget (swidget, "reason")); model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter); memset (&value, 0, sizeof(value)); gtk_tree_model_get_value (model, &iter, COLUMN_INT, &value); reason = g_value_get_int (&value); g_value_unset (&value); description = gtk_entry_get_text (GTK_ENTRY (seahorse_widget_get_widget (swidget, "description"))); subkey = g_object_get_data (G_OBJECT (swidget), "subkey"); g_return_if_fail (SEAHORSE_IS_GPGME_SUBKEY (subkey)); err = seahorse_gpgme_key_op_revoke_subkey (subkey, reason, description); if (!GPG_IS_OK (err)) seahorse_gpgme_handle_error (err, _("Couldn't revoke subkey")); seahorse_widget_destroy (swidget); }
/* Create a data on the given uri, remote uris get gnome-vfs backends, * local uris get normal file access. */ static gpgme_data_t create_vfs_data (GFile *file, guint mode, SeahorseVfsProgressCb progcb, gpointer userdata, gpg_error_t* err) { gpgme_error_t gerr; gpgme_data_t ret = NULL; VfsAsyncHandle* handle = NULL; if (!err) err = &gerr; handle = vfs_data_open (file, mode & SEAHORSE_VFS_WRITE, mode & SEAHORSE_VFS_DELAY); if (handle) { *err = gpgme_data_new_from_cbs (&ret, &vfs_data_cbs, handle); if (!GPG_IS_OK (*err)) { vfs_data_cbs.release (handle); ret = NULL; } handle->progcb = progcb; handle->userdata = userdata; handle->gdata = ret; } return ret; }
/** * seahorse_gpgme_get_keytype_table: * * @table: The requested keytype table * * Based on the gpg version in use, sets @table * to contain the numbers that gpg uses in its CLI * for adding new subkeys. This tends to get broken * at random by new versions of gpg, but there's no good * API for this. * * Returns GPG_ERR_USER_2 if gpg is too old. * * Returns: gpgme_error_t **/ gpgme_error_t seahorse_gpgme_get_keytype_table (SeahorseKeyTypeTable *table) { gpgme_error_t gerr; gpgme_engine_info_t engine; SeahorseVersion ver; gerr = gpgme_get_engine_info (&engine); g_return_val_if_fail (GPG_IS_OK (gerr), gerr); while (engine && engine->protocol != GPGME_PROTOCOL_OpenPGP) engine = engine->next; g_return_val_if_fail (engine != NULL, GPG_E (GPG_ERR_GENERAL)); ver = seahorse_util_parse_version (engine->version); if (ver >= VER_2012 || (ver >= VER_1410 && ver < VER_190)) *table = &KEYTYPES_2012; else if (ver >= VER_140 || ver >= VER_190) *table = &KEYTYPES_140; else if (ver >= VER_124) *table = &KEYTYPES_124; else if (ver >= VER_120) *table = &KEYTYPES_120; else // older versions not supported gerr = GPG_E (GPG_ERR_USER_2); return gerr; }
/* Initializes the gpg-options static info */ static gboolean gpg_options_init (GError **err) { if (!gpg_options_inited) { gpgme_error_t gerr; gpgme_engine_info_t engine; gerr = gpgme_get_engine_info (&engine); g_return_val_if_fail (GPG_IS_OK (gerr), (bastile_gpgme_to_error (gerr, err), FALSE)); /* Look for the OpenPGP engine */ while (engine && engine->protocol != GPGME_PROTOCOL_OpenPGP) engine = engine->next; /* * Make sure it's the right version for us to be messing * around with the configuration file. */ g_return_val_if_fail (engine && engine->version && engine->file_name && (g_str_has_prefix (engine->version, GPG_VERSION_PREFIX1) || g_str_has_prefix (engine->version, GPG_VERSION_PREFIX2)), (bastile_gpgme_to_error (GPG_E (GPG_ERR_INV_ENGINE), err), FALSE)); /* Now run the binary and read in the home directory */ if (!parse_home_directory (engine, err)) return FALSE; gpg_options_inited = TRUE; } return TRUE; }
gpgme_data_t seahorse_vfs_data_read_multi (const gchar **uris, GError **err) { gpgme_error_t gerr; gpgme_data_t data; GList *datas = NULL; const gchar **u; for (u = uris; *u; u++) { if(!(*u)[0]) continue; data = seahorse_vfs_data_create (*u, SEAHORSE_VFS_READ, err); if (!data) break; datas = g_list_prepend (datas, data); } /* Failed somewhere */ if (!data) { multi_data_release (datas); return NULL; } datas = g_list_reverse (datas); gerr = gpgme_data_new_from_cbs (&data, &multi_data_cbs, datas); if (!GPG_IS_OK (gerr)) { seahorse_util_gpgme_to_error (gerr, err); multi_data_release (datas); return NULL; } return data; }
gboolean seahorse_gpgme_photo_delete (SeahorseGpgmePhoto *photo, GtkWindow *parent) { gpgme_error_t gerr; GtkWidget *dlg; gint response; g_return_val_if_fail (SEAHORSE_IS_GPGME_PHOTO (photo), FALSE); dlg = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Are you sure you want to remove the current photo from your key?")); gtk_dialog_add_button (GTK_DIALOG (dlg), GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT); gtk_dialog_add_button (GTK_DIALOG (dlg), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT); response = gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); if (response != GTK_RESPONSE_ACCEPT) return FALSE; gerr = seahorse_gpgme_key_op_photo_delete (photo); if (!GPG_IS_OK (gerr)) { seahorse_gpgme_handle_error (gerr, _("Couldn’t delete photo")); return FALSE; } return TRUE; }
gpgme_data_t seahorse_gpgme_data_input (GInputStream* input) { gpgme_error_t gerr; gpgme_data_t ret = NULL; g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL); gerr = gpgme_data_new_from_cbs (&ret, &input_cbs, input); if (!GPG_IS_OK (gerr)) return NULL; g_object_ref (input); return ret; }
gpgme_data_t seahorse_gpgme_data_output (GOutputStream* output) { gpgme_error_t gerr; gpgme_data_t ret = NULL; g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL); gerr = gpgme_data_new_from_cbs (&ret, &output_cbs, output); if (!GPG_IS_OK (gerr)) return NULL; g_object_ref (output); return ret; }
G_MODULE_EXPORT void on_gpgme_expire_ok_clicked (GtkButton *button, gpointer user_data) { SeahorseWidget *swidget = SEAHORSE_WIDGET (user_data); GtkWidget *widget; SeahorseGpgmeSubkey *subkey; gpgme_error_t err; time_t expiry = 0; struct tm when; subkey = SEAHORSE_GPGME_SUBKEY (g_object_get_data (G_OBJECT (swidget), "subkey")); widget = GTK_WIDGET (seahorse_widget_get_widget (swidget, "expire")); if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) { memset (&when, 0, sizeof (when)); widget = GTK_WIDGET (seahorse_widget_get_widget (swidget, "calendar")); gtk_calendar_get_date (GTK_CALENDAR (widget), (guint*)&(when.tm_year), (guint*)&(when.tm_mon), (guint*)&(when.tm_mday)); when.tm_year -= 1900; expiry = mktime (&when); if (expiry <= time (NULL)) { seahorse_util_show_error (widget, _("Invalid expiry date"), _("The expiry date must be in the future")); return; } } widget = seahorse_widget_get_widget (swidget, "all-controls"); gtk_widget_set_sensitive (widget, FALSE); g_object_ref (swidget); g_object_ref (subkey); if (expiry != (time_t)seahorse_pgp_subkey_get_expires (SEAHORSE_PGP_SUBKEY (subkey))) { err = seahorse_gpgme_key_op_set_expires (subkey, expiry); if (!GPG_IS_OK (err)) seahorse_gpgme_handle_error (err, _("Couldn't change expiry date")); } g_object_unref (subkey); g_object_unref (swidget); seahorse_widget_destroy (swidget); }
/** * pop: a seahorse operation * gstarterr: the gpgme error that could have occured earlier * cryptdata: gpgme cryptdata * result: the result of the gpgme operation (out) * resultlength: length of the created buffer (out) (can be NULL) * error: will be set on error * * Finishes the gpgme processing and returns the result * * returns: TRUE on successful operation, FALSE else */ static gboolean process_crypto_result (SeahorseGpgmeOperation *pop, gpgme_error_t gstarterr, gpgme_data_t cryptdata, gchar **result, gsize *resultlength, GError **error) { size_t len; char *data; /* Starting the operation failed? */ if (!GPG_IS_OK (gstarterr)) { gpgme_data_release (cryptdata); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_CRYPTO, "%s", gpgme_strerror (gstarterr)); return FALSE; } /* Wait for it to finish (can run main loop stuff) */ seahorse_operation_wait (SEAHORSE_OPERATION (pop)); if (seahorse_operation_is_cancelled (SEAHORSE_OPERATION (pop))) { g_set_error (error, SEAHORSE_DBUS_CANCELLED, 0, "%s", ""); return FALSE; } else if (seahorse_operation_is_successful (SEAHORSE_OPERATION (pop))) { data = gpgme_data_release_and_get_mem (cryptdata, &len); *result = g_strndup (data, len); if (resultlength != NULL) *resultlength = (gsize)len; g_free (data); return TRUE; } else { /* A failed operation always has an error */ g_assert (seahorse_operation_get_error (SEAHORSE_OPERATION (pop))); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_CRYPTO, "%s", seahorse_operation_get_error (SEAHORSE_OPERATION (pop))->message); gpgme_data_release (cryptdata); return FALSE; } }
gpgme_data_t seahorse_gpgme_data_new_from_mem (const char *buffer, size_t size, gboolean copy) { gpgme_data_t data; gpgme_error_t gerr; gerr = gpgme_data_new_from_mem (&data, buffer, size, copy ? 1 : 0); if (!GPG_IS_OK (gerr)) { if (gpgme_err_code_to_errno (gerr) == ENOMEM || gpgme_err_code (gerr) == GPG_ERR_ENOMEM) { g_error ("%s: failed to allocate gpgme_data_t", G_STRLOC); } else { /* The only reason this should fail is above */ g_assert_not_reached (); /* Just in case */ abort (); } } return data; }
gpgme_data_t seahorse_gpgme_data_new () { gpgme_error_t gerr; gpgme_data_t data; gerr = gpgme_data_new (&data); if (!GPG_IS_OK (gerr)) { if (gpgme_err_code_to_errno (gerr) == ENOMEM || gpgme_err_code (gerr) == GPG_ERR_ENOMEM) { g_error ("%s: failed to allocate gpgme_data_t", G_STRLOC); } else { /* The only reason this should fail is above */ g_assert_not_reached (); /* Just in case */ abort (); } } return data; }
/** * crypto: the crypto service (#SeahorseServiceCrypto) * recipients: A list of recipients (keyids "openpgp:B8098FB063E2C811") * Must be empty when symmetric encryption is used. * signer: optional, the keyid of the signer * flags: FLAG_SYMMETRIC to perform symmetric encryption * cleartext: the text to encrypt * clearlength: Length of the cleartext * crypttext: the encrypted text (out) * cryptlength: the length of this text (out) * textmode: TRUE if gpgme should use textmode * ascii_armor: TRUE if GPGME should use ascii armor * error: The Error * * Handles encryption in a generic way. Can be used by several DBus APIs * * Returns TRUE on success **/ static gboolean crypto_encrypt_generic (SeahorseServiceCrypto *crypto, const char **recipients, const char *signer, int flags, const char *cleartext, gsize clearlength, char **crypttext, gsize *cryptlength, gboolean textmode, gboolean ascii_armor, GError **error) { GList *recipkeys = NULL; SeahorseGpgmeOperation *pop; SeahorseObject *signkey = NULL; SeahorseObject *skey; gpgme_key_t *recips; gboolean symmetric = FALSE; gpgme_data_t plain, cipher; gpgme_error_t gerr; gboolean ret = TRUE; GSettings *settings; gchar *keyid; if ((flags & FLAG_SYMMETRIC) == FLAG_SYMMETRIC) symmetric = TRUE; if (symmetric && recipients[0] != NULL) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Recipients specified for symmetric encryption")); return FALSE; } /* The signer */ if (signer && signer[0]) { signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer); if (!signkey) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized signer: %s"), signer); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (signkey) || !(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not valid for signing: %s"), signer); return FALSE; } } if (!symmetric) { /* The recipients */ for( ; recipients[0]; recipients++) { skey = seahorse_context_object_from_dbus (SCTX_APP (), recipients[0]); if (!skey) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized recipient: %s"), recipients[0]); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (skey) || !(seahorse_object_get_flags (skey) & SEAHORSE_FLAG_CAN_ENCRYPT)) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not a valid recipient for encryption: %s"), recipients[0]); return FALSE; } recipkeys = g_list_prepend (recipkeys, SEAHORSE_PGP_KEY (skey)); } if (!recipkeys) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("No recipients specified")); return FALSE; } } pop = seahorse_gpgme_operation_new (NULL); /* new data form text */ gerr = gpgme_data_new_from_mem (&plain, cleartext, clearlength, FALSE); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); gerr = gpgme_data_new (&cipher); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); /* encrypt with armor */ gpgme_set_textmode (pop->gctx, textmode); gpgme_set_armor (pop->gctx, ascii_armor); if (symmetric) { /* gpgme_op_encrypt{_sign,}_start() will perform symmetric encryption * when no recipients are specified. */ recips = NULL; } else { /* Add the default key if set and necessary */ settings = g_settings_new ("org.gnome.crypto.pgp"); if (g_settings_get_boolean (settings, "encrypt-to-self")) { keyid = g_settings_get_string (settings, "default-key"); if (keyid && keyid[0]) { skey = seahorse_context_find_object (NULL, g_quark_from_string (keyid), SEAHORSE_LOCATION_LOCAL); if (SEAHORSE_IS_PGP_KEY (skey)) recipkeys = g_list_append (recipkeys, skey); } g_free (keyid); } g_object_unref (settings); /* Make keys into the right format for GPGME */ recips = keylist_to_keys (recipkeys); g_list_free (recipkeys); } /* Do the encryption */ if (signkey) { gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey))); gerr = gpgme_op_encrypt_sign_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } else { gerr = gpgme_op_encrypt_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } free_keys (recips); /* Frees cipher */ ret = process_crypto_result (pop, gerr, cipher, crypttext, cryptlength, error); g_object_unref (pop); gpgme_data_release (plain); return ret; }
/** * data: optional, will be added to the title, can be NULL * status: the gpgme status * * Basing on the status a notification is created an displayed * */ static void notify_signatures (const gchar* data, gpgme_verify_result_t status) { const gchar *icon = NULL; SeahorseObject *object; gchar *title, *body, *unesc_data; gboolean sig = FALSE; GSList *rawids; GList *keys; /* Discover the key in question */ rawids = g_slist_append (NULL, status->signatures->fpr); keys = seahorse_context_discover_objects (SCTX_APP (), SEAHORSE_PGP, rawids); g_slist_free (rawids); g_return_if_fail (keys != NULL); object = SEAHORSE_OBJECT (keys->data); g_list_free (keys); /* Figure out what to display */ switch (gpgme_err_code (status->signatures->status)) { case GPG_ERR_KEY_EXPIRED: /* TRANSLATORS: <key id='xxx'> is a custom markup tag, do not translate. */ body = _("Signed by <i><key id='%s'/> <b>expired</b></i> on %s."); title = _("Invalid Signature"); icon = ICON_PREFIX "seahorse-sign-bad.png"; sig = TRUE; break; /* TRANSLATORS: <key id='xxx'> is a custom markup tag, do not translate. */ case GPG_ERR_SIG_EXPIRED: body = _("Signed by <i><key id='%s'/></i> on %s <b>Expired</b>."); title = _("Expired Signature"); icon = ICON_PREFIX "seahorse-sign-bad.png"; sig = TRUE; break; /* TRANSLATORS: <key id='xxx'> is a custom markup tag, do not translate. */ case GPG_ERR_CERT_REVOKED: body = _("Signed by <i><key id='%s'/> <b>Revoked</b></i> on %s."); title = _("Revoked Signature"); icon = ICON_PREFIX "seahorse-sign-bad.png"; sig = TRUE; break; case GPG_ERR_NO_ERROR: /* TRANSLATORS: <key id='xxx'> is a custom markup tag, do not translate. */ body = _("Signed by <i><key id='%s'/></i> on %s."); title = _("Good Signature"); icon = ICON_PREFIX "seahorse-sign-ok.png"; sig = TRUE; break; case GPG_ERR_NO_PUBKEY: body = _("Signing key not in keyring."); title = _("Unknown Signature"); icon = ICON_PREFIX "seahorse-sign-unknown.png"; break; case GPG_ERR_BAD_SIGNATURE: body = _("Bad or forged signature. The signed data was modified."); title = _("Bad Signature"); icon = ICON_PREFIX "seahorse-sign-bad.png"; break; case GPG_ERR_NO_DATA: return; default: if (!GPG_IS_OK (status->signatures->status)) seahorse_gpgme_handle_error (status->signatures->status, _("Couldn't verify signature.")); return; }; if (sig) { gchar *date = seahorse_util_get_display_date_string (status->signatures->timestamp); gchar *id = seahorse_context_id_to_dbus (SCTX_APP (), seahorse_object_get_id (object)); body = g_markup_printf_escaped (body, id, date); g_free (date); g_free (id); } else { body = g_strdup (body); } if (data) { data = seahorse_util_uri_get_last (data); unesc_data = g_uri_unescape_string (data, NULL); title = g_strdup_printf ("%s: %s", unesc_data, title); g_free (unesc_data); } else { title = g_strdup (title); } seahorse_notification_display (title, body, !sig, icon, NULL); g_free(title); g_free(body); }
G_MODULE_EXPORT void on_gpgme_add_subkey_ok_clicked (GtkButton *button, gpointer user_data) { SeahorseWidget *swidget = SEAHORSE_WIDGET (user_data); SeahorseObjectWidget *skwidget; SeahorseKeyEncType real_type; gint type; guint length; time_t expires; gpgme_error_t err; GtkWidget *widget; GtkComboBox *combo; GtkTreeModel *model; GtkTreeIter iter; skwidget = SEAHORSE_OBJECT_WIDGET (swidget); combo = GTK_COMBO_BOX (seahorse_widget_get_widget (swidget, "type")); gtk_combo_box_get_active_iter (combo, &iter); model = gtk_combo_box_get_model (combo); gtk_tree_model_get (model, &iter, COMBO_INT, &type, -1); length = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON ( seahorse_widget_get_widget (swidget, LENGTH))); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ( seahorse_widget_get_widget (swidget, "never_expires")))) expires = 0; else { widget = GTK_WIDGET (g_object_get_data (G_OBJECT (swidget), "expires-datetime")); g_return_if_fail (widget); egg_datetime_get_as_time_t (EGG_DATETIME (widget), &expires); } switch (type) { case 0: real_type = DSA; break; case 1: real_type = ELGAMAL; break; case 2: real_type = RSA_SIGN; break; default: real_type = RSA_ENCRYPT; break; } widget = GTK_WIDGET (seahorse_widget_get_widget (swidget, swidget->name)); gtk_widget_set_sensitive (widget, FALSE); err = seahorse_gpgme_key_op_add_subkey (SEAHORSE_GPGME_KEY (skwidget->object), real_type, length, expires); gtk_widget_set_sensitive (widget, TRUE); if (!GPG_IS_OK (err)) seahorse_gpgme_handle_error (err, _("Couldn't add subkey")); seahorse_widget_destroy (swidget); }
/** * seahorse_service_crypto_verify_text: * @crypto: #SeahorseServiceCrypto context * @ktype: "openpgp" * @flags: FLAG_QUIET for no notification * @crypttext: the text to decrypt * @cleartext: the plaintext after verification (out) * @signer: the signer if the text is signed (out) * @error: a potential error (out) * * DBus: VerifyText * * Decrypts the @crypttext and returns it in @cleartext. If the text * was signed, the signed is returned. * * Returns: TRUE on success */ gboolean seahorse_service_crypto_verify_text (SeahorseServiceCrypto *crypto, const gchar *ktype, int flags, const gchar *crypttext, gchar **cleartext, char **signer, GError **error) { gpgme_verify_result_t status; gpgme_error_t gerr; SeahorseGpgmeOperation *pop; gpgme_data_t plain, cipher; gboolean ret = TRUE; GQuark keyid; if (!g_str_equal (ktype, g_quark_to_string (SEAHORSE_PGP))) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid key type for verifying: %s"), ktype); return FALSE; } /* * TODO: Once we support different kinds of keys that support encryption * then all this logic will need to change. */ pop = seahorse_gpgme_operation_new (NULL); /* new data from text */ gerr = gpgme_data_new_from_mem (&cipher, crypttext, strlen (crypttext), FALSE); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); gerr = gpgme_data_new (&plain); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); /* encrypt with armor */ gpgme_set_textmode (pop->gctx, TRUE); gpgme_set_armor (pop->gctx, TRUE); /* Do the decryption */ gerr = gpgme_op_verify_start (pop->gctx, cipher, NULL, plain); /* Frees plain */ ret = process_crypto_result (pop, gerr, plain, cleartext, NULL, error); if (ret) { *signer = NULL; status = gpgme_op_verify_result (pop->gctx); if (status->signatures) { if (!(flags & FLAG_QUIET)) notify_signatures (NULL, status); if (status->signatures->summary & GPGME_SIGSUM_GREEN || status->signatures->summary & GPGME_SIGSUM_VALID || status->signatures->summary & GPGME_SIGSUM_KEY_MISSING) { keyid = seahorse_pgp_key_canonize_id (status->signatures->fpr); *signer = seahorse_context_id_to_dbus (SCTX_APP (), keyid); } } } g_object_unref (pop); gpgme_data_release (cipher); return TRUE; }
/** * crypto: the crypto service (#SeahorseServiceCrypto) * recipients: A list of recipients (keyids "openpgp:B8098FB063E2C811") * signer: optional, the keyid of the signer * flags: 0, not used * cleartext: the text to encrypt * clearlength: Length of the cleartext * crypttext: the encrypted text (out) * cryptlength: the length of this text (out) * textmode: TRUE if gpgme should use textmode * ascii_armor: TRUE if GPGME should use ascii armor * error: The Error * * Handles encryption in a generic way. Can be used by several DBus APIs * * Returns TRUE on success **/ static gboolean crypto_encrypt_generic (SeahorseServiceCrypto *crypto, const char **recipients, const char *signer, int flags, const char *cleartext, gsize clearlength, char **crypttext, gsize *cryptlength, gboolean textmode, gboolean ascii_armor, GError **error) { GList *recipkeys = NULL; SeahorseGpgmeOperation *pop; SeahorseObject *signkey = NULL; SeahorseObject *skey; gpgme_key_t *recips; gpgme_data_t plain, cipher; gpgme_error_t gerr; gboolean ret = TRUE; /* * TODO: Once we support different kinds of keys that support encryption * then all this logic will need to change. */ /* The signer */ if (signer && signer[0]) { signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer); if (!signkey) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized signer: %s"), signer); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (signkey) || !(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not valid for signing: %s"), signer); return FALSE; } } /* The recipients */ for( ; recipients[0]; recipients++) { skey = seahorse_context_object_from_dbus (SCTX_APP (), recipients[0]); if (!skey) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized recipient: %s"), recipients[0]); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (skey) || !(seahorse_object_get_flags (skey) & SEAHORSE_FLAG_CAN_ENCRYPT)) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not a valid recipient for encryption: %s"), recipients[0]); return FALSE; } recipkeys = g_list_prepend (recipkeys, SEAHORSE_PGP_KEY (skey)); } if (!recipkeys) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("No recipients specified")); return FALSE; } pop = seahorse_gpgme_operation_new (NULL); /* new data form text */ gerr = gpgme_data_new_from_mem (&plain, cleartext, clearlength, FALSE); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); gerr = gpgme_data_new (&cipher); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); /* encrypt with armor */ gpgme_set_textmode (pop->gctx, textmode); gpgme_set_armor (pop->gctx, ascii_armor); /* Add the default key if set and necessary */ if (seahorse_gconf_get_boolean (ENCRYPTSELF_KEY)) { skey = SEAHORSE_OBJECT (seahorse_context_get_default_key (SCTX_APP ())); if (SEAHORSE_IS_PGP_KEY (skey)) recipkeys = g_list_append (recipkeys, skey); } /* Make keys into the right format for GPGME */ recips = keylist_to_keys (recipkeys); g_list_free (recipkeys); /* Do the encryption */ if (signkey) { gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey))); gerr = gpgme_op_encrypt_sign_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } else { gerr = gpgme_op_encrypt_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } free_keys (recips); /* Frees cipher */ ret = process_crypto_result (pop, gerr, cipher, crypttext, cryptlength, error); g_object_unref (pop); gpgme_data_release (plain); return ret; }
G_MODULE_EXPORT gboolean on_gpgme_sign_ok_clicked (BastileWidget *swidget, GtkWindow *parent) { BastileSignCheck check; BastileSignOptions options = 0; BastileObject *signer; GtkWidget *w; gpgme_error_t err; BastileObject *to_sign; /* Figure out choice */ check = SIGN_CHECK_NO_ANSWER; w = GTK_WIDGET (bastile_widget_get_widget (swidget, "sign-choice-not")); g_return_val_if_fail (w != NULL, FALSE); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) check = SIGN_CHECK_NONE; else { w = GTK_WIDGET (bastile_widget_get_widget (swidget, "sign-choice-casual")); g_return_val_if_fail (w != NULL, FALSE); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) check = SIGN_CHECK_CASUAL; else { w = GTK_WIDGET (bastile_widget_get_widget (swidget, "sign-choice-careful")); g_return_val_if_fail (w != NULL, FALSE); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) check = SIGN_CHECK_CAREFUL; } } /* Local signature */ w = GTK_WIDGET (bastile_widget_get_widget (swidget, "sign-option-local")); g_return_val_if_fail (w != NULL, FALSE); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) options |= SIGN_LOCAL; /* Revocable signature */ w = GTK_WIDGET (bastile_widget_get_widget (swidget, "sign-option-revocable")); g_return_val_if_fail (w != NULL, FALSE); if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) options |= SIGN_NO_REVOKE; /* Signer */ w = GTK_WIDGET (bastile_widget_get_widget (swidget, "signer-select")); g_return_val_if_fail (w != NULL, FALSE); signer = bastile_combo_keys_get_active (GTK_COMBO_BOX (w)); g_assert (!signer || (BASTILE_IS_GPGME_KEY (signer) && bastile_object_get_usage (BASTILE_OBJECT (signer)) == BASTILE_USAGE_PRIVATE_KEY)); to_sign = g_object_get_data (G_OBJECT (swidget), "to-sign"); if (BASTILE_IS_GPGME_UID (to_sign)) err = bastile_gpgme_key_op_sign_uid (BASTILE_GPGME_UID (to_sign), BASTILE_GPGME_KEY (signer), check, options); else if (BASTILE_IS_GPGME_KEY (to_sign)) err = bastile_gpgme_key_op_sign (BASTILE_GPGME_KEY (to_sign), BASTILE_GPGME_KEY (signer), check, options); else g_assert (FALSE); if (!GPG_IS_OK (err)) { if (gpgme_err_code (err) == GPG_ERR_EALREADY) { w = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _("This key was already signed by\n\"%s\""), bastile_object_get_label (signer)); gtk_dialog_run (GTK_DIALOG (w)); gtk_widget_destroy (w); } else bastile_gpgme_handle_error (err, _("Couldn't sign key")); } bastile_widget_destroy (swidget); return TRUE; }
gboolean seahorse_gpgme_photo_add (SeahorseGpgmeKey *pkey, GtkWindow *parent, const gchar *path) { gchar *filename = NULL; gchar *tempfile = NULL; GError *error = NULL; gpgme_error_t gerr; GtkWidget *chooser; gboolean res = TRUE; g_return_val_if_fail (SEAHORSE_IS_GPGME_KEY (pkey), FALSE); if (NULL == path) { chooser = gtk_file_chooser_dialog_new (_("Choose Photo to Add to Key"), parent, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE); add_image_files (chooser); if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); gtk_widget_destroy (chooser); if (!filename) return FALSE; } else { filename = g_strdup (path); } if (!prepare_photo_id (parent, filename, &tempfile, &error)) { seahorse_util_handle_error (&error, NULL, _("Couldn’t prepare photo")); return FALSE; } gerr = seahorse_gpgme_key_op_photo_add (pkey, tempfile ? tempfile : filename); if (!GPG_IS_OK (gerr)) { /* A special error value set by seahorse_key_op_photoid_add to denote an invalid format file */ if (gerr == GPG_E (GPG_ERR_USER_1)) seahorse_util_show_error (NULL, _("Couldn’t add photo"), _("The file could not be loaded. It may be in an invalid format")); else seahorse_gpgme_handle_error (gerr, _("Couldn’t add photo")); res = FALSE; } g_free (filename); if (tempfile) { unlink (tempfile); g_free (tempfile); } return res; }