Esempio n. 1
0
gboolean sgpgme_has_secret_key(void)
{
	gpgme_error_t err = 0;
	gpgme_ctx_t ctx;
	gpgme_key_t key;

	err = gpgme_new (&ctx);
	if (err) {
		debug_print("err : %s\n", gpgme_strerror(err));
		return TRUE;
	}
check_again:
	err = gpgme_op_keylist_start(ctx, NULL, TRUE);
	if (!err)
		err = gpgme_op_keylist_next(ctx, &key);
	gpgme_op_keylist_end(ctx);
	if (gpg_err_code(err) == GPG_ERR_EOF) {
		if (gpgme_get_protocol(ctx) != GPGME_PROTOCOL_CMS) {
			gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
			goto check_again;
		}
		gpgme_release(ctx);
		return FALSE;
	} else {
		gpgme_release(ctx);
		return TRUE;
	}
}
Esempio n. 2
0
/* Not that this closure is called in the context of the
   waiter_thread.  */
static void
verify_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
{
  if (!err)
    {
      gpgme_verify_result_t res;

      res = gpgme_op_verify_result (ctx);
      if (res) 
        verify_dialog_box (gpgme_get_protocol (ctx), res, NULL);
    }
  gpgme_data_release (cld->sigobj);
  engine_private_finished (cld->filter, err);
}
Esempio n. 3
0
/* Not that this closure is called in the context of the
   waiter_thread.  */
static void
decrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
{
  update_passphrase_cache (err, &cld->pw_cb);

  if (!err && !cld->with_verify) 
    ;
  else if (!err) 
    {
      gpgme_verify_result_t res;

      /* Decryption succeeded.  Now check the state of the signatures. */
      res = gpgme_op_verify_result (ctx);
      if (res && res->signatures)
        verify_dialog_box (gpgme_get_protocol (ctx), res, NULL);
    }
  else if (gpg_err_code (err) == GPG_ERR_DECRYPT_FAILED)
    {
      /* The decryption failed.  See whether we can figure out a more
         suitable error code.  */
      gpgme_decrypt_result_t res;

      res = gpgme_op_decrypt_result (ctx);
      if (res && res->recipients 
          && gpgme_err_code (res->recipients->status) == GPG_ERR_NO_SECKEY)
        err = gpg_error (GPG_ERR_NO_SECKEY);
      /* Fixme: return the keyids */
    }
  else
    {
      /* Decryption failed for other reasons. */
    }

  /* If the passphrase callback indicated a cancel operation, change
     the the error code accordingly. */
  if (err && (cld->pw_cb.opts & OPT_FLAG_CANCEL))
    err = gpg_error (GPG_ERR_CANCELED);

  engine_private_finished (cld->filter, err);
}
Esempio n. 4
0
gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account,
			      const gchar *from_addr)
{
	GPGAccountConfig *config;
	const gchar *signer_addr = account->address;

	gpgme_signers_clear(ctx);

	if (from_addr)
		signer_addr = from_addr;
	config = prefs_gpg_account_get_config(account);

	switch(config->sign_key) {
	case SIGN_KEY_DEFAULT:
		debug_print("using default gnupg key\n");
		break;
	case SIGN_KEY_BY_FROM:
		debug_print("using key for %s\n", signer_addr);
		break;
	case SIGN_KEY_CUSTOM:
		debug_print("using key for %s\n", config->sign_key_id);
		break;
	}

	if (config->sign_key != SIGN_KEY_DEFAULT) {
		const gchar *keyid;
		gpgme_key_t key, found_key;
		gpgme_error_t err;

		if (config->sign_key == SIGN_KEY_BY_FROM)
			keyid = signer_addr;
		else if (config->sign_key == SIGN_KEY_CUSTOM)
			keyid = config->sign_key_id;
		else
			goto bail;

                found_key = NULL;
		/* Look for any key, not just private ones, or GPGMe doesn't
		 * correctly set the revoked flag. */
		err = gpgme_op_keylist_start(ctx, keyid, 0);
		while ((err = gpgme_op_keylist_next(ctx, &key)) == 0) {
			if (key == NULL)
				continue;

			if (!key->can_sign)
				continue;

			if (key->protocol != gpgme_get_protocol(ctx)) {
				debug_print("skipping a key (wrong protocol %d)\n", key->protocol);
				gpgme_key_release(key);
				continue;
			}

			if (key->expired) {
				debug_print("skipping a key, expired");
				gpgme_key_release(key);
				continue;
			}
			if (key->revoked) {
				debug_print("skipping a key, revoked");
				gpgme_key_release(key);
				continue;
			}
			if (key->disabled) {
				debug_print("skipping a key, disabled");
				gpgme_key_release(key);
				continue;
			}

			if (found_key != NULL) {
				gpgme_key_release(key);
				gpgme_op_keylist_end(ctx);
				g_warning("ambiguous specification of secret key '%s'\n", keyid);
				privacy_set_error(_("Secret key specification is ambiguous"));
				goto bail;
			}

			found_key = key;
                }
		gpgme_op_keylist_end(ctx);

		if (found_key == NULL) {
			g_warning("setup_signers start: %s", gpgme_strerror(err));
			privacy_set_error(_("Secret key not found (%s)"), gpgme_strerror(err));
			goto bail;
                }

		err = gpgme_signers_add(ctx, found_key);
		debug_print("got key (proto %d (pgp %d, smime %d).\n",
			    found_key->protocol, GPGME_PROTOCOL_OpenPGP,
			    GPGME_PROTOCOL_CMS);
		gpgme_key_release(found_key);

		if (err) {
			g_warning("error adding secret key: %s\n",
				  gpgme_strerror(err));
			privacy_set_error(_("Error setting secret key: %s"),
					  gpgme_strerror(err));
			goto bail;
		}
        }

	prefs_gpg_account_free_config(config);

	return TRUE;
bail:
	prefs_gpg_account_free_config(config);
	return FALSE;
}
Esempio n. 5
0
gpgme_data_t sgpgme_decrypt_verify(gpgme_data_t cipher, gpgme_verify_result_t *status, gpgme_ctx_t ctx)
{
	struct passphrase_cb_info_s info;
	gpgme_data_t plain;
	gpgme_error_t err;

	memset (&info, 0, sizeof info);
	
	if ((err = gpgme_data_new(&plain)) != GPG_ERR_NO_ERROR) {
		gpgme_release(ctx);
		privacy_set_error(_("Couldn't initialize data, %s"), gpgme_strerror(err));
		return NULL;
	}
	
	if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
		prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent);
    		if (!getenv("GPG_AGENT_INFO") || !prefs_gpg_get_config()->use_gpg_agent) {
        		info.c = ctx;
        		gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
    		}
	} else {
		prefs_gpg_enable_agent(TRUE);
        	info.c = ctx;
        	gpgme_set_passphrase_cb (ctx, NULL, &info);
	}
	
	
	if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
		err = gpgme_op_decrypt_verify(ctx, cipher, plain);
		if (err != GPG_ERR_NO_ERROR) {
			debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
			privacy_set_error("%s", gpgme_strerror(err));
			gpgmegtk_free_passphrase();
			gpgme_data_release(plain);
			return NULL;
		}

		err = cm_gpgme_data_rewind(plain);
		if (err) {
			debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
		}

		debug_print("decrypted.\n");
		*status = gpgme_op_verify_result (ctx);
	} else {
		err = gpgme_op_decrypt(ctx, cipher, plain);
		if (err != GPG_ERR_NO_ERROR) {
			debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
			privacy_set_error("%s", gpgme_strerror(err));
			gpgmegtk_free_passphrase();
			gpgme_data_release(plain);
			return NULL;
		}

		err = cm_gpgme_data_rewind(plain);
		if (err) {
			debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
		}

		debug_print("decrypted.\n");
		*status = gpgme_op_verify_result (ctx);
	}
	return plain;
}
Esempio n. 6
0
static gpgme_key_t
get_key_from_name(gpgme_ctx_t ctx, const gchar * name, gboolean secret,
		  gboolean accept_all, GtkWindow * parent, GError ** error)
{
    GList *keys = NULL;
    gpgme_key_t key;
    gpgme_error_t err;
    gboolean found_bad;
    time_t now = time(NULL);

    /* let gpgme list keys */
    if ((err =
	 gpgme_op_keylist_start(ctx, name, secret)) != GPG_ERR_NO_ERROR) {
	gchar *msg =
	    g_strdup_printf(_("could not list keys for \"%s\""), name);

	g_set_error_from_gpgme(error, err, msg);
	g_free(msg);
	return NULL;
    }

    found_bad = FALSE;
    while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) {
	/* check if this key and the relevant subkey are usable */
	if (KEY_IS_OK(key)) {
	    gpgme_subkey_t subkey = key->subkeys;

	    while (subkey && ((secret && !subkey->can_sign) ||
			      (!secret && !subkey->can_encrypt)))
		subkey = subkey->next;

	    if (subkey && KEY_IS_OK(subkey) &&
		(subkey->expires == 0 || subkey->expires > now))
		keys = g_list_append(keys, key);
	    else
		found_bad = TRUE;
	} else
	    found_bad = TRUE;
    }

    if (gpg_err_code(err) != GPG_ERR_EOF) {
	gchar *msg =
	    g_strdup_printf(_("could not list keys for \"%s\""), name);

	g_set_error_from_gpgme(error, err, msg);
	g_free(msg);
	gpgme_op_keylist_end(ctx);
	g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL);
	g_list_free(keys);
	return NULL;
    }
    gpgme_op_keylist_end(ctx);

    if (!keys) {
	if (error) {
	    if (strchr(name, '@')) {
		if (found_bad)
		    g_set_error(error, GPGME_ERROR_QUARK,
				GPG_ERR_KEY_SELECTION,
				_
				("%s: a key for %s is present, but it is expired, disabled, revoked or invalid"),
				"gmime-gpgme", name);
		else
		    g_set_error(error, GPGME_ERROR_QUARK,
				GPG_ERR_KEY_SELECTION,
				_("%s: could not find a key for %s"),
				"gmime-gpgme", name);
	    } else {
		if (found_bad)
		    g_set_error(error, GPGME_ERROR_QUARK,
				GPG_ERR_KEY_SELECTION,
				_
				("%s: a key with id %s is present, but it is expired, disabled, revoked or invalid"),
				"gmime-gpgme", name);
		else
		    g_set_error(error, GPGME_ERROR_QUARK,
				GPG_ERR_KEY_SELECTION,
				_("%s: could not find a key with id %s"),
				"gmime-gpgme", name);
	    }
	}
	return NULL;
    }

    /* let the user select a key from the list if there is more than one */
    if (g_list_length(keys) > 1) {
	if (select_key_cb)
	    key =
		select_key_cb(name, secret, keys, gpgme_get_protocol(ctx),
			      parent);
	else {
	    if (error)
		g_set_error(error, GPGME_ERROR_QUARK,
			    GPG_ERR_KEY_SELECTION,
			    _("%s: multiple keys for %s"), "gmime-gpgme",
			    name);
	    key = NULL;
	}
	if (key)
	    gpgme_key_ref(key);
	g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL);
    } else
	key = (gpgme_key_t) keys->data;
    g_list_free(keys);

    /* OpenPGP: ask the user if a low-validity key should be trusted for
     * encryption */
    // FIXME - shouldn't we do the same for S/MIME?
    if (key && !secret && !accept_all
	&& gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
	gpgme_user_id_t uid = key->uids;
	gchar *upcase_name = g_ascii_strup(name, -1);
	gboolean found = FALSE;

	while (!found && uid) {
	    /* check the email field which may or may not be present */
	    if (uid->email && !g_ascii_strcasecmp(uid->email, name))
		found = TRUE;
	    else {
		/* no email or no match, check the uid */
		gchar *upcase_uid = g_ascii_strup(uid->uid, -1);

		if (strstr(upcase_uid, upcase_name))
		    found = TRUE;
		else
		    uid = uid->next;
		g_free(upcase_uid);
	    }
	}
	g_free(upcase_name);

	/* ask the user if a low-validity key shall be used */
	if (uid && uid->validity < GPGME_VALIDITY_FULL) {
	    if (!accept_low_trust_cb
		|| !accept_low_trust_cb(name, uid, parent)) {
		gpgme_key_unref(key);
		key = NULL;
		if (error)
		    g_set_error(error, GPGME_ERROR_QUARK,
				GPG_ERR_KEY_SELECTION,
				_("%s: insufficient validity for uid %s"),
				"gmime-gpgme", name);
	    }
	}
    }

    return key;
}
Esempio n. 7
0
/** \brief Verify a signature
 *
 * \param content GMime stream of the signed matter.
 * \param sig_plain GMime signature stream for a detached signature, or the
 *        output stream for the checked matter in single-part mode.
 * \param protocol GpgME crypto protocol of the signature.
 * \param singlepart_mode TRUE indicates single-part mode (i.e. sig_plain
 *        an output stream).
 * \param error Filled with error information on error.
 * \return A new signature status object on success, or NULL on error.
 *
 * Verify a signature by calling GpgME on the passed streams, and create a
 * new signature object on success.
 */
GMimeGpgmeSigstat *
libbalsa_gpgme_verify(GMimeStream * content, GMimeStream * sig_plain,
		      gpgme_protocol_t protocol, gboolean singlepart_mode,
		      GError ** error)
{
    gpgme_error_t err;
    gpgme_ctx_t ctx;
    struct gpgme_data_cbs cbs = {
	(gpgme_data_read_cb_t) g_mime_gpgme_stream_rd,	/* read method */
	(gpgme_data_write_cb_t) g_mime_gpgme_stream_wr,	/* write method */
	NULL,			/* seek method */
	cb_data_release		/* release method */
    };
    gpgme_data_t cont_data;
    gpgme_data_t sig_plain_data;
    GMimeGpgmeSigstat *result;

    /* paranoia checks */
    g_return_val_if_fail(GMIME_IS_STREAM(content), NULL);
    g_return_val_if_fail(GMIME_IS_STREAM(sig_plain), NULL);
    g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP ||
			 protocol == GPGME_PROTOCOL_CMS, NULL);

    /* create the GpgME context */
    if ((err =
	 gpgme_new_with_protocol(&ctx, protocol, NULL,
				 error)) != GPG_ERR_NO_ERROR)
	return NULL;

    /* create the message stream */
    if ((err =
	 gpgme_data_new_from_cbs(&cont_data, &cbs,
				 content)) != GPG_ERR_NO_ERROR) {
	g_set_error_from_gpgme(error, err,
			       _("could not get data from stream"));
	gpgme_release(ctx);
	return NULL;
    }

    /* create data object for the detached signature stream or the
     * "decrypted" plaintext */
    if ((err =
	 gpgme_data_new_from_cbs(&sig_plain_data, &cbs,
				 sig_plain)) != GPG_ERR_NO_ERROR) {
	g_set_error_from_gpgme(error, err,
			       _("could not get data from stream"));
	gpgme_data_release(cont_data);
	gpgme_release(ctx);
	return NULL;
    }

    /* verify the signature */
    if (singlepart_mode)
	err = gpgme_op_verify(ctx, cont_data, NULL, sig_plain_data);
    else
	err = gpgme_op_verify(ctx, sig_plain_data, cont_data, NULL);
    if (err != GPG_ERR_NO_ERROR) {
	g_set_error_from_gpgme(error, err,
			       _("signature verification failed"));
	result = g_mime_gpgme_sigstat_new();
	result->status = err;
	result->protocol = gpgme_get_protocol(ctx);
    } else
	result = g_mime_gpgme_sigstat_new_from_gpgme_ctx(ctx);

    /* release gmgme data buffers, destroy the context and return the
     * signature object */
    gpgme_data_release(cont_data);
    gpgme_data_release(sig_plain_data);
    gpgme_release(ctx);
    return result;
}
Esempio n. 8
0
static gpg_error_t
gpa_file_sign_operation_start (GpaFileSignOperation *op,
                               gpa_file_item_t file_item)
{
    gpg_error_t err;

    if (file_item->direct_in)
    {
        /* No copy is made.  */
        err = gpgme_data_new_from_mem (&op->plain, file_item->direct_in,
                                       file_item->direct_in_len, 0);
        if (err)
        {
            gpa_gpgme_warning (err);
            return err;
        }

        err = gpgme_data_new (&op->sig);
        if (err)
        {
            gpa_gpgme_warning (err);
            gpgme_data_release (op->plain);
            op->plain = NULL;
            return err;
        }
    }
    else
    {
        gchar *plain_filename = file_item->filename_in;
        char *filename_used;

        file_item->filename_out = destination_filename
                                  (plain_filename, gpgme_get_armor (GPA_OPERATION (op)->context->ctx),
                                   gpgme_get_protocol (GPA_OPERATION (op)->context->ctx), op->sign_type);

        /* Open the files */
        op->plain_fd = gpa_open_input (plain_filename, &op->plain,
                                       GPA_OPERATION (op)->window);
        if (op->plain_fd == -1)
            /* FIXME: Error value.  */
            return gpg_error (GPG_ERR_GENERAL);

        op->sig_fd = gpa_open_output (file_item->filename_out, &op->sig,
                                      GPA_OPERATION (op)->window,
                                      &filename_used);
        if (op->sig_fd == -1)
        {
            gpgme_data_release (op->plain);
            close (op->plain_fd);
            xfree (filename_used);
            /* FIXME: Error value.  */
            return gpg_error (GPG_ERR_GENERAL);
        }

        xfree (file_item->filename_out);
        file_item->filename_out = filename_used;
    }

    /* Start the operation */
    err = gpgme_op_sign_start (GPA_OPERATION (op)->context->ctx, op->plain,
                               op->sig, op->sign_type);
    if (err)
    {
        gpa_gpgme_warning (err);
        return err;
    }
    /* Show and update the progress dialog */
    gtk_widget_show_all (GPA_FILE_OPERATION (op)->progress_dialog);
    gpa_progress_dialog_set_label (GPA_PROGRESS_DIALOG
                                   (GPA_FILE_OPERATION (op)->progress_dialog),
                                   file_item->direct_name
                                   ? file_item->direct_name
                                   : file_item->filename_in);

    return 0;
}
Esempio n. 9
0
gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account,
			      const gchar *from_addr)
{
	GPGAccountConfig *config;
	const gchar *signer_addr = account->address;

	gpgme_signers_clear(ctx);

	if (from_addr)
		signer_addr = from_addr;
	config = prefs_gpg_account_get_config(account);

	switch(config->sign_key) {
	case SIGN_KEY_DEFAULT:
		debug_print("using default gnupg key\n");
		break;
	case SIGN_KEY_BY_FROM:
		debug_print("using key for %s\n", signer_addr);
		break;
	case SIGN_KEY_CUSTOM:
		debug_print("using key for %s\n", config->sign_key_id);
		break;
	}

	if (config->sign_key != SIGN_KEY_DEFAULT) {
		const gchar *keyid;
		gpgme_key_t key, key2;
		gpgme_error_t err;

		if (config->sign_key == SIGN_KEY_BY_FROM)
			keyid = signer_addr;
		else if (config->sign_key == SIGN_KEY_CUSTOM)
			keyid = config->sign_key_id;
		else
			goto bail;

		err = gpgme_op_keylist_start(ctx, keyid, 1);
		if (!err) {
			do {
				err = gpgme_op_keylist_next(ctx, &key);
				if (!err && key && key->protocol == gpgme_get_protocol(ctx) &&
				    !key->expired && !key->revoked && !key->disabled)
					break;
				if (!err && key && key->protocol != gpgme_get_protocol(ctx)) {
					debug_print("skipping a key (wrong protocol %d)\n", key->protocol);
					gpgme_key_release(key);
				}
				if (!err && key && (key->expired || key->revoked || key->disabled)) {
					
					debug_print("skipping a key");
					if (key->expired) 
						debug_print(" expired");
					if (key->revoked) 
						debug_print(" revoked");
					if (key->disabled) 
						debug_print(" disabled");
					debug_print("\n");
					gpgme_key_release(key);
				}
			} while (!err);
		}
		if (err) {
			g_warning("setup_signers start: %s", gpgme_strerror(err));
			privacy_set_error(_("Secret key not found (%s)"), gpgme_strerror(err));
			goto bail;
		}
		
		do {
			err = gpgme_op_keylist_next(ctx, &key2);
			if (!err && key2 && key2->protocol == gpgme_get_protocol(ctx) &&
			    !key2->expired && !key2->revoked && !key2->disabled)
				break;
			if (!err && key2 && key2->protocol != gpgme_get_protocol(ctx)) {
				debug_print("skipping a key (wrong protocol %d)\n", key2->protocol);
				gpgme_key_release(key2);
			}
			if (!err && key2 && (key2->expired || key2->revoked || key2->disabled)) {
					debug_print("skipping a key");
					if (key2->expired) 
						debug_print(" expired");
					if (key2->revoked) 
						debug_print(" revoked");
					if (key2->disabled) 
						debug_print(" disabled");
					debug_print("\n");
				gpgme_key_release(key2);
			}
		} while (!err);
		if (!err) {
			gpgme_key_release(key2);
			g_warning("ambiguous specification of secret key '%s'\n",
				keyid);
			privacy_set_error(_("Secret key specification is ambiguous"));
			goto bail;
		}
		
		gpgme_op_keylist_end(ctx);
		err = gpgme_signers_add(ctx, key);
		debug_print("got key (proto %d (pgp %d, smime %d).\n", key->protocol,
				GPGME_PROTOCOL_OpenPGP, GPGME_PROTOCOL_CMS);
		gpgme_key_release(key);
		
		if (err) {
			g_warning("error adding secret key: %s\n", gpgme_strerror(err));
			privacy_set_error(_("Error setting secret key: %s"), gpgme_strerror(err));
			goto bail;
		}
	}

	prefs_gpg_account_free_config(config);

	return TRUE;
bail:
	prefs_gpg_account_free_config(config);
	return FALSE;
}
Esempio n. 10
0
gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *from_addr)
{
	MimeInfo *msgcontent, *sigmultipart, *newinfo;
	gchar *textstr, *micalg = NULL;
	FILE *fp;
	gchar *boundary = NULL;
	gchar *sigcontent;
	gpgme_ctx_t ctx;
	gpgme_data_t gpgtext, gpgsig;
	gpgme_error_t err;
	size_t len;
	struct passphrase_cb_info_s info;
	gpgme_sign_result_t result = NULL;
	gchar *test_msg;
	
	fp = my_tmpfile();
	if (fp == NULL) {
		perror("my_tmpfile");
		privacy_set_error(_("Couldn't create temporary file: %s"), g_strerror(errno));
		return FALSE;
	}
	procmime_write_mimeinfo(mimeinfo, fp);
	rewind(fp);

	/* read temporary file into memory */
	test_msg = file_read_stream_to_str(fp);
	claws_fclose(fp);
	
	memset (&info, 0, sizeof info);

	/* remove content node from message */
	msgcontent = (MimeInfo *) mimeinfo->node->children->data;
	g_node_unlink(msgcontent->node);

	/* create temporary multipart for content */
	sigmultipart = procmime_mimeinfo_new();
	sigmultipart->type = MIMETYPE_MULTIPART;
	sigmultipart->subtype = g_strdup("signed");
	
	do {
		g_free(boundary);
		boundary = generate_mime_boundary("Sig");
	} while (strstr(test_msg, boundary) != NULL);
	
	g_free(test_msg);

	g_hash_table_insert(sigmultipart->typeparameters, g_strdup("boundary"),
                            g_strdup(boundary));
	g_hash_table_insert(sigmultipart->typeparameters, g_strdup("protocol"),
                            g_strdup("application/pgp-signature"));
	g_node_append(sigmultipart->node, msgcontent->node);
	g_node_append(mimeinfo->node, sigmultipart->node);

	/* write message content to temporary file */
	fp = my_tmpfile();
	if (fp == NULL) {
		perror("my_tmpfile");
		privacy_set_error(_("Couldn't create temporary file: %s"), g_strerror(errno));
		return FALSE;
	}
	procmime_write_mimeinfo(sigmultipart, fp);
	rewind(fp);

	/* read temporary file into memory */
	textstr = get_canonical_content(fp, boundary);

	g_free(boundary);
	claws_fclose(fp);

	gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0);
	gpgme_data_new(&gpgsig);
	if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) {
		debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err));
		privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
		return FALSE;
	}
	gpgme_set_textmode(ctx, 1);
	gpgme_set_armor(ctx, 1);
	gpgme_signers_clear (ctx);

	if (!sgpgme_setup_signers(ctx, account, from_addr)) {
		gpgme_release(ctx);
		return FALSE;
	}

	prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent);
	if (g_getenv("GPG_AGENT_INFO") && prefs_gpg_get_config()->use_gpg_agent) {
		debug_print("GPG_AGENT_INFO environment defined, running without passphrase callback\n");
	} else {
   		info.c = ctx;
    		gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
	}

	err = gpgme_op_sign(ctx, gpgtext, gpgsig, GPGME_SIG_MODE_DETACH);
	if (err != GPG_ERR_NO_ERROR) {
		if (err == GPG_ERR_CANCELED) {
			/* ignore cancelled signing */
			privacy_reset_error();
			debug_print("gpgme_op_sign cancelled\n");
		} else {
			privacy_set_error(_("Data signing failed, %s"), gpgme_strerror(err));
			debug_print("gpgme_op_sign error : %x\n", err);
		}
		gpgme_release(ctx);
		return FALSE;
	}
	result = gpgme_op_sign_result(ctx);
	if (result && result->signatures) {
		gpgme_new_signature_t sig = result->signatures;
		if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
			gchar *down_algo = g_ascii_strdown(gpgme_hash_algo_name(
				result->signatures->hash_algo), -1);
			micalg = g_strdup_printf("pgp-%s", down_algo);
			g_free(down_algo);
		} else {
			micalg = g_strdup(gpgme_hash_algo_name(
				result->signatures->hash_algo));
		}
		while (sig) {
			debug_print("valid signature: %s\n", sig->fpr);
			sig = sig->next;
		}
	} else if (result && result->invalid_signers) {
		gpgme_invalid_key_t invalid = result->invalid_signers;
		while (invalid) {
			g_warning("invalid signer: %s (%s)", invalid->fpr, 
				gpgme_strerror(invalid->reason));
			privacy_set_error(_("Data signing failed due to invalid signer: %s"), 
				gpgme_strerror(invalid->reason));
			invalid = invalid->next;
		}
		gpgme_release(ctx);
		return FALSE;
	} else {
		/* can't get result (maybe no signing key?) */
		debug_print("gpgme_op_sign_result error\n");
		privacy_set_error(_("Data signing failed, no results."));
		gpgme_release(ctx);
		return FALSE;
	}

	sigcontent = sgpgme_data_release_and_get_mem(gpgsig, &len);
	gpgme_data_release(gpgtext);
	g_free(textstr);

	if (sigcontent == NULL || len <= 0) {
		g_warning("sgpgme_data_release_and_get_mem failed");
		privacy_set_error(_("Data signing failed, no contents."));
		g_free(micalg);
		g_free(sigcontent);
		return FALSE;
	}

	/* add signature */
	g_hash_table_insert(sigmultipart->typeparameters, g_strdup("micalg"),
                            micalg);

	newinfo = procmime_mimeinfo_new();
	newinfo->type = MIMETYPE_APPLICATION;
	newinfo->subtype = g_strdup("pgp-signature");
	newinfo->description = g_strdup(_("OpenPGP digital signature"));
	newinfo->content = MIMECONTENT_MEM;
	newinfo->data.mem = g_malloc(len + 1);
	g_memmove(newinfo->data.mem, sigcontent, len);
	newinfo->data.mem[len] = '\0';
	g_node_append(sigmultipart->node, newinfo->node);

	g_free(sigcontent);
	gpgme_release(ctx);

	return TRUE;
}
Esempio n. 11
0
static PyObject *
pygpgme_context_get_protocol(PyGpgmeContext *self)
{
    return PyInt_FromLong(gpgme_get_protocol(self->ctx));
}