コード例 #1
0
ファイル: sgpgme.c プロジェクト: SpOOnman/claws
gpgme_data_t sgpgme_data_from_mimeinfo(MimeInfo *mimeinfo)
{
	gpgme_data_t data = NULL;
	gpgme_error_t err;
	FILE *fp = g_fopen(mimeinfo->data.filename, "rb");
	gchar *tmp_file = NULL;

	if (!fp) 
		return NULL;

	tmp_file = get_tmp_file();
	copy_file_part(fp, mimeinfo->offset, mimeinfo->length, tmp_file);
	fclose(fp);
	fp = NULL;
	debug_print("tmp file %s\n", tmp_file);
	
	err = gpgme_data_new_from_file(&data, tmp_file, 1);
	claws_unlink(tmp_file);
	g_free(tmp_file);

	debug_print("data %p (%d %d)\n", (void *)&data, mimeinfo->offset, mimeinfo->length);
	if (err) {
		debug_print ("gpgme_data_new_from_file failed: %s\n",
			     gpgme_strerror (err));
		privacy_set_error(_("Couldn't get data from message, %s"), gpgme_strerror(err));
		return NULL;
	}
	return data;
}
コード例 #2
0
ファイル: sgpgme.c プロジェクト: mishamehra/claws-mail
gpgme_verify_result_t sgpgme_verify_signature(gpgme_ctx_t ctx, gpgme_data_t sig, 
					gpgme_data_t plain, gpgme_data_t dummy)
{
	gpgme_verify_result_t status = NULL;
	gpgme_error_t err;

	if ((err = gpgme_op_verify(ctx, sig, plain, dummy)) != GPG_ERR_NO_ERROR) {
		debug_print("op_verify err %s\n", gpgme_strerror(err));
		privacy_set_error("%s", gpgme_strerror(err));
		return GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR);
	}
	status = gpgme_op_verify_result(ctx);
	if (status && status->signatures == NULL) {
		debug_print("no signature found\n");
		privacy_set_error(_("No signature found"));
		return GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR);
	}
	return status;
}
コード例 #3
0
ファイル: sgpgme.c プロジェクト: mishamehra/claws-mail
gpgme_data_t sgpgme_data_from_mimeinfo(MimeInfo *mimeinfo)
{
	gpgme_data_t data = NULL;
	gpgme_error_t err;
	FILE *fp = g_fopen(mimeinfo->data.filename, "rb");

	if (!fp) 
		return NULL;

	err = gpgme_data_new_from_filepart(&data, NULL, fp, mimeinfo->offset, mimeinfo->length);
	fclose(fp);

	debug_print("data %p (%d %d)\n", (void *)&data, mimeinfo->offset, mimeinfo->length);
	if (err) {
		debug_print ("gpgme_data_new_from_file failed: %s\n",
			     gpgme_strerror (err));
		privacy_set_error(_("Couldn't get data from message, %s"), gpgme_strerror(err));
		return NULL;
	}
	return data;
}
コード例 #4
0
ファイル: privacy.c プロジェクト: Mortal/claws
gboolean privacy_encrypt(const gchar *id, MimeInfo *mimeinfo, const gchar *encdata)
{
	PrivacySystem *system;

	cm_return_val_if_fail(id != NULL, FALSE);
	cm_return_val_if_fail(mimeinfo != NULL, FALSE);
	if (encdata == NULL) {
		privacy_set_error(_("No recipient keys defined."));
		return FALSE;
	}

	system = privacy_get_system(id);
	if (system == NULL)
		return FALSE;
	if (!system->can_encrypt)
		return FALSE;
	if (system->encrypt == NULL)
		return FALSE;

	return system->encrypt(mimeinfo, encdata);
}
コード例 #5
0
ファイル: sgpgme.c プロジェクト: mishamehra/claws-mail
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;
}
コード例 #6
0
ファイル: sgpgme.c プロジェクト: mishamehra/claws-mail
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;
}
コード例 #7
0
ファイル: pgpinline.c プロジェクト: buzz/claws
static gboolean pgpinline_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
{
    MimeInfo *msgcontent;
    FILE *fp;
    gchar *enccontent;
    size_t len;
    gchar *textstr, *tmp;
    gpgme_data_t gpgtext, gpgenc;
    gpgme_ctx_t ctx;
    gpgme_key_t *kset = NULL;
    gchar **fprs = g_strsplit(encrypt_data, " ", -1);
    gpgme_error_t err;
    gint i = 0;

    while (fprs[i] && strlen(fprs[i])) {
        i++;
    }

    kset = g_malloc(sizeof(gpgme_key_t)*(i+1));
    memset(kset, 0, sizeof(gpgme_key_t)*(i+1));
    if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) {
        debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
        privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
        g_free(kset);
        return FALSE;
    }
    i = 0;
    while (fprs[i] && strlen(fprs[i])) {
        gpgme_key_t key;
        err = gpgme_get_key(ctx, fprs[i], &key, 0);
        if (err) {
            debug_print("can't add key '%s'[%d] (%s)\n", fprs[i],i, gpgme_strerror(err));
            privacy_set_error(_("Couldn't add GPG key %s, %s"), fprs[i], gpgme_strerror(err));
            g_free(kset);
            return FALSE;
        }
        debug_print("found %s at %d\n", fprs[i], i);
        kset[i] = key;
        i++;
    }


    debug_print("Encrypting message content\n");

    /* get content node from message */
    msgcontent = (MimeInfo *) mimeinfo->node->children->data;
    if (msgcontent->type == MIMETYPE_MULTIPART) {
        if (!msgcontent->node->children) {
            debug_print("msgcontent->node->children NULL, bailing\n");
            privacy_set_error(_("Malformed message"));
            g_free(kset);
            return FALSE;
        }
        msgcontent = (MimeInfo *) msgcontent->node->children->data;
    }
    /* get rid of quoted-printable or anything */
    procmime_decode_content(msgcontent);

    fp = my_tmpfile();
    if (fp == NULL) {
        privacy_set_error(_("Couldn't create temporary file, %s"), g_strerror(errno));
        perror("my_tmpfile");
        g_free(kset);
        return FALSE;
    }
    procmime_write_mimeinfo(msgcontent, fp);
    rewind(fp);

    /* read temporary file into memory */
    textstr = fp_read_noconv(fp);

    fclose(fp);

    /* encrypt data */
    gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0);
    gpgme_data_new(&gpgenc);
    if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) {
        debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
        privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
        g_free(kset);
        return FALSE;
    }
    gpgme_set_armor(ctx, 1);

    err = gpgme_op_encrypt(ctx, kset, GPGME_ENCRYPT_ALWAYS_TRUST, gpgtext, gpgenc);

    enccontent = sgpgme_data_release_and_get_mem(gpgenc, &len);
    g_free(kset);

    if (enccontent == NULL || len <= 0) {
        g_warning("sgpgme_data_release_and_get_mem failed");
        privacy_set_error(_("Encryption failed, %s"), gpgme_strerror(err));
        gpgme_data_release(gpgtext);
        g_free(textstr);
        gpgme_release(ctx);
        g_free(enccontent);
        return FALSE;
    }

    tmp = g_malloc(len+1);
    g_memmove(tmp, enccontent, len+1);
    tmp[len] = '\0';
    g_free(enccontent);

    gpgme_data_release(gpgtext);
    g_free(textstr);

    if (msgcontent->content == MIMECONTENT_FILE &&
            msgcontent->data.filename != NULL) {
        if (msgcontent->tmp == TRUE)
            claws_unlink(msgcontent->data.filename);
        g_free(msgcontent->data.filename);
    }
    msgcontent->data.mem = g_strdup(tmp);
    msgcontent->content = MIMECONTENT_MEM;
    g_free(tmp);
    gpgme_release(ctx);

    return TRUE;
}
コード例 #8
0
ファイル: pgpinline.c プロジェクト: buzz/claws
static gboolean pgpinline_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *from_addr)
{
    MimeInfo *msgcontent;
    gchar *textstr, *tmp;
    FILE *fp;
    gchar *sigcontent;
    gpgme_ctx_t ctx;
    gpgme_data_t gpgtext, gpgsig;
    size_t len;
    gpgme_error_t err;
    struct passphrase_cb_info_s info;
    gpgme_sign_result_t result = NULL;

    memset (&info, 0, sizeof info);

    /* get content node from message */
    msgcontent = (MimeInfo *) mimeinfo->node->children->data;
    if (msgcontent->type == MIMETYPE_MULTIPART) {
        if (!msgcontent->node->children) {
            debug_print("msgcontent->node->children NULL, bailing\n");
            privacy_set_error(_("Malformed message"));
            return FALSE;
        }
        msgcontent = (MimeInfo *) msgcontent->node->children->data;
    }
    /* get rid of quoted-printable or anything */
    procmime_decode_content(msgcontent);

    fp = my_tmpfile();
    if (fp == NULL) {
        perror("my_tmpfile");
        privacy_set_error(_("Couldn't create temporary file."));
        return FALSE;
    }
    procmime_write_mimeinfo(msgcontent, fp);
    rewind(fp);

    /* read temporary file into memory */
    textstr = fp_read_noconv(fp);

    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"), 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);

    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 (!getenv("GPG_AGENT_INFO") || !prefs_gpg_get_config()->use_gpg_agent) {
        info.c = ctx;
        gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
    }

    err = gpgme_op_sign(ctx, gpgtext, gpgsig, GPGME_SIG_MODE_CLEAR);
    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;
        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);

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

    tmp = g_malloc(len+1);
    g_memmove(tmp, sigcontent, len+1);
    tmp[len] = '\0';
    gpgme_data_release(gpgtext);
    g_free(textstr);
    g_free(sigcontent);

    if (msgcontent->content == MIMECONTENT_FILE &&
            msgcontent->data.filename != NULL) {
        if (msgcontent->tmp == TRUE)
            claws_unlink(msgcontent->data.filename);
        g_free(msgcontent->data.filename);
    }
    msgcontent->data.mem = g_strdup(tmp);
    msgcontent->content = MIMECONTENT_MEM;
    g_free(tmp);

    /* avoid all sorts of clear-signing problems with non ascii
     * chars
     */
    procmime_encode_content(msgcontent, ENC_BASE64);
    gpgme_release(ctx);

    return TRUE;
}
コード例 #9
0
ファイル: pgpinline.c プロジェクト: buzz/claws
static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
{
    MimeInfo *decinfo, *parseinfo;
    gpgme_data_t cipher, plain;
    FILE *dstfp;
    gchar *fname;
    gchar *textdata = NULL;
    static gint id = 0;
    const gchar *src_codeset = NULL;
    gpgme_verify_result_t sigstat = 0;
    PrivacyDataPGP *data = NULL;
    gpgme_ctx_t ctx;
    gchar *chars;
    size_t len;
    const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----";
    const gchar *end_indicator = "-----END PGP MESSAGE-----";
    gchar *pos;

    if (gpgme_new(&ctx) != GPG_ERR_NO_ERROR)
        return NULL;

    gpgme_set_textmode(ctx, 1);
    gpgme_set_armor(ctx, 1);

    cm_return_val_if_fail(mimeinfo != NULL, NULL);
    cm_return_val_if_fail(pgpinline_is_encrypted(mimeinfo), NULL);

    if (procmime_mimeinfo_parent(mimeinfo) == NULL ||
            mimeinfo->type != MIMETYPE_TEXT) {
        gpgme_release(ctx);
        privacy_set_error(_("Couldn't parse mime part."));
        return NULL;
    }

    textdata = get_part_as_string(mimeinfo);
    if (!textdata) {
        gpgme_release(ctx);
        privacy_set_error(_("Couldn't get text data."));
        return NULL;
    }

    debug_print("decrypting '%s'\n", textdata);
    gpgme_data_new_from_mem(&cipher, textdata, (size_t)strlen(textdata), 1);

    plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx);
    if (sigstat && !sigstat->signatures)
        sigstat = NULL;

    gpgme_data_release(cipher);

    if (plain == NULL) {
        gpgme_release(ctx);
        return NULL;
    }

    fname = g_strdup_printf("%s%cplaintext.%08x",
                            get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);

    if ((dstfp = g_fopen(fname, "wb")) == NULL) {
        FILE_OP_ERROR(fname, "fopen");
        privacy_set_error(_("Couldn't open decrypted file %s"), fname);
        g_free(fname);
        gpgme_data_release(plain);
        gpgme_release(ctx);
        return NULL;
    }

    src_codeset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
    if (src_codeset == NULL)
        src_codeset = CS_ISO_8859_1;

    if (fprintf(dstfp, "MIME-Version: 1.0\r\n"
                "Content-Type: text/plain; charset=%s\r\n"
                "Content-Transfer-Encoding: 8bit\r\n"
                "\r\n",
                src_codeset) < 0) {
        FILE_OP_ERROR(fname, "fprintf");
        privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
        goto FILE_ERROR;
    }

    /* Store any part before encrypted text */
    pos = pgp_locate_armor_header(textdata, begin_indicator);
    if (pos != NULL && (pos - textdata) > 0) {
        if (fwrite(textdata, 1, pos - textdata, dstfp) < pos - textdata) {
            FILE_OP_ERROR(fname, "fwrite");
            privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
            goto FILE_ERROR;
        }
    }

    if (fwrite(_("\n--- Start of PGP/Inline encrypted data ---\n"), 1,
               strlen(_("\n--- Start of PGP/Inline encrypted data ---\n")),
               dstfp) < strlen(_("\n--- Start of PGP/Inline encrypted data ---\n"))) {
        FILE_OP_ERROR(fname, "fwrite");
        privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
        goto FILE_ERROR;
    }
    chars = sgpgme_data_release_and_get_mem(plain, &len);
    if (len > 0) {
        if (fwrite(chars, 1, len, dstfp) < len) {
            FILE_OP_ERROR(fname, "fwrite");
            g_free(chars);
            privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
            goto FILE_ERROR;
        }
    }
    g_free(chars);
    /* Store any part after encrypted text */
    if (fwrite(_("--- End of PGP/Inline encrypted data ---\n"), 1,
               strlen(_("--- End of PGP/Inline encrypted data ---\n")),
               dstfp) < strlen(_("--- End of PGP/Inline encrypted data ---\n"))) {
        FILE_OP_ERROR(fname, "fwrite");
        privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
        goto FILE_ERROR;
    }
    if (pos != NULL) {
        pos = pgp_locate_armor_header(pos, end_indicator);
        if (pos != NULL && *pos != '\0') {
            pos += strlen(end_indicator);
            if (fwrite(pos, 1, strlen(pos), dstfp) < strlen(pos)) {
                FILE_OP_ERROR(fname, "fwrite");
                privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
                goto FILE_ERROR;
            }
        }
    }

    if (fclose(dstfp) == EOF) {
        FILE_OP_ERROR(fname, "fclose");
        privacy_set_error(_("Couldn't close decrypted file %s"), fname);
        g_free(fname);
        gpgme_data_release(plain);
        gpgme_release(ctx);
        return NULL;
    }

    parseinfo = procmime_scan_file(fname);
    g_free(fname);

    if (parseinfo == NULL) {
        gpgme_release(ctx);
        privacy_set_error(_("Couldn't scan decrypted file."));
        return NULL;
    }
    decinfo = g_node_first_child(parseinfo->node) != NULL ?
              g_node_first_child(parseinfo->node)->data : NULL;

    if (decinfo == NULL) {
        gpgme_release(ctx);
        privacy_set_error(_("Couldn't scan decrypted file parts."));
        return NULL;
    }

    g_node_unlink(decinfo->node);
    procmime_mimeinfo_free_all(parseinfo);

    decinfo->tmp = TRUE;

    if (sigstat != GPGME_SIG_STAT_NONE) {
        if (decinfo->privacy != NULL) {
            data = (PrivacyDataPGP *) decinfo->privacy;
        } else {
            data = pgpinline_new_privacydata();
            decinfo->privacy = (PrivacyData *) data;
        }
        if (data != NULL) {
            data->done_sigtest = TRUE;
            data->is_signed = TRUE;
            data->sigstatus = sigstat;
            if (data->ctx)
                gpgme_release(data->ctx);
            data->ctx = ctx;
        }
    } else
        gpgme_release(ctx);

    return decinfo;

FILE_ERROR:
    fclose(dstfp);
    g_free(fname);
    gpgme_data_release(plain);
    gpgme_release(ctx);
    return NULL;
}
コード例 #10
0
ファイル: pgpinline.c プロジェクト: buzz/claws
static gint pgpinline_check_signature(MimeInfo *mimeinfo)
{
    PrivacyDataPGP *data = NULL;
    gchar *textdata = NULL, *tmp = NULL;
    gpgme_data_t plain = NULL, cipher = NULL;
    gpgme_error_t err;

    cm_return_val_if_fail(mimeinfo != NULL, 0);

    if (procmime_mimeinfo_parent(mimeinfo) == NULL) {
        privacy_set_error(_("Incorrect part"));
        return 0; /* not parent */
    }
    if (mimeinfo->type != MIMETYPE_TEXT) {
        privacy_set_error(_("Not a text part"));
        debug_print("type %d\n", mimeinfo->type);
        return 0;
    }
    cm_return_val_if_fail(mimeinfo->privacy != NULL, 0);
    data = (PrivacyDataPGP *) mimeinfo->privacy;

    textdata = get_part_as_string(mimeinfo);

    if (!textdata) {
        g_free(textdata);
        privacy_set_error(_("Couldn't get text data."));
        return 0;
    }

    /* gtk2: convert back from utf8 */
    tmp = conv_codeset_strdup(textdata, CS_UTF_8,
                              procmime_mimeinfo_get_parameter(mimeinfo, "charset"));
    if (!tmp) {
        tmp = conv_codeset_strdup(textdata, CS_UTF_8,
                                  conv_get_locale_charset_str_no_utf8());
    }
    if (!tmp) {
        g_warning("Can't convert charset to anything sane");
        tmp = conv_codeset_strdup(textdata, CS_UTF_8, CS_US_ASCII);
    }
    g_free(textdata);

    if (!tmp) {
        privacy_set_error(_("Couldn't convert text data to any sane charset."));
        return 0;
    }
    textdata = g_strdup(tmp);
    g_free(tmp);

    if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) {
        debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
        privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
        g_free(textdata);
        return 0;
    }
    gpgme_set_textmode(data->ctx, 1);
    gpgme_set_armor(data->ctx, 1);

    gpgme_data_new_from_mem(&plain, textdata, (size_t)strlen(textdata), 1);
    gpgme_data_new(&cipher);

    data->sigstatus = sgpgme_verify_signature(data->ctx, plain, NULL, cipher);

    gpgme_data_release(plain);
    gpgme_data_release(cipher);

    g_free(textdata);

    return 0;
}
コード例 #11
0
ファイル: sgpgme.c プロジェクト: mrvdb/claws-mail
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;
}
コード例 #12
0
ファイル: pgpmime.c プロジェクト: kuba-moo/claws-mail
gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
{
	MimeInfo *msgcontent, *encmultipart, *newinfo;
	FILE *fp;
	gchar *boundary, *enccontent;
	size_t len;
	gchar *textstr;
	gpgme_data_t gpgtext = NULL, gpgenc = NULL;
	gpgme_ctx_t ctx = NULL;
	gpgme_key_t *kset = NULL;
	gchar **fprs = g_strsplit(encrypt_data, " ", -1);
	gint i = 0;
	gpgme_error_t err;
	
	while (fprs[i] && strlen(fprs[i])) {
		i++;
	}
	
	kset = g_malloc(sizeof(gpgme_key_t)*(i+1));
	memset(kset, 0, sizeof(gpgme_key_t)*(i+1));
	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));
		g_free(kset);
		return FALSE;
	}
	i = 0;
	while (fprs[i] && strlen(fprs[i])) {
		gpgme_key_t key;
		err = gpgme_get_key(ctx, fprs[i], &key, 0);
		if (err) {
			debug_print("can't add key '%s'[%d] (%s)\n", fprs[i],i, gpgme_strerror(err));
			privacy_set_error(_("Couldn't add GPG key %s, %s"), fprs[i], gpgme_strerror(err));
			g_free(kset);
			return FALSE;
		}
		debug_print("found %s at %d\n", fprs[i], i);
		kset[i] = key;
		i++;
	}
	
	debug_print("Encrypting message content\n");

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

	/* create temporary multipart for content */
	encmultipart = procmime_mimeinfo_new();
	encmultipart->type = MIMETYPE_MULTIPART;
	encmultipart->subtype = g_strdup("encrypted");
	boundary = generate_mime_boundary("Encrypt");
	g_hash_table_insert(encmultipart->typeparameters, g_strdup("boundary"),
                            g_strdup(boundary));
	g_hash_table_insert(encmultipart->typeparameters, g_strdup("protocol"),
                            g_strdup("application/pgp-encrypted"));
	g_node_append(encmultipart->node, msgcontent->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));
		g_free(kset);
		return FALSE;
	}
	procmime_write_mimeinfo(encmultipart, fp);
	rewind(fp);

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

	g_free(boundary);
	claws_fclose(fp);

	/* encrypt data */
	gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0);
	gpgme_data_new(&gpgenc);
	gpgme_set_armor(ctx, 1);
	cm_gpgme_data_rewind(gpgtext);
	
	err = gpgme_op_encrypt(ctx, kset, GPGME_ENCRYPT_ALWAYS_TRUST, gpgtext, gpgenc);

	enccontent = sgpgme_data_release_and_get_mem(gpgenc, &len);
	gpgme_data_release(gpgtext);
	g_free(textstr);
	g_free(kset);

	if (enccontent == NULL || len <= 0) {
		g_warning("sgpgme_data_release_and_get_mem failed");
		privacy_set_error(_("Encryption failed, %s"), gpgme_strerror(err));
		gpgme_release(ctx);
		g_free(enccontent);
		return FALSE;
	}

	/* create encrypted multipart */
	g_node_unlink(msgcontent->node);
	procmime_mimeinfo_free_all(&msgcontent);
	g_node_append(mimeinfo->node, encmultipart->node);

	newinfo = procmime_mimeinfo_new();
	newinfo->type = MIMETYPE_APPLICATION;
	newinfo->subtype = g_strdup("pgp-encrypted");
	newinfo->content = MIMECONTENT_MEM;
	newinfo->data.mem = g_strdup("Version: 1\n");
	g_node_append(encmultipart->node, newinfo->node);

	newinfo = procmime_mimeinfo_new();
	newinfo->type = MIMETYPE_APPLICATION;
	newinfo->subtype = g_strdup("octet-stream");
	newinfo->content = MIMECONTENT_MEM;
	newinfo->data.mem = g_malloc(len + 1);
	g_memmove(newinfo->data.mem, enccontent, len);
	newinfo->data.mem[len] = '\0';
	g_node_append(encmultipart->node, newinfo->node);

	g_free(enccontent);
	gpgme_release(ctx);

	return TRUE;
}
コード例 #13
0
ファイル: pgpmime.c プロジェクト: kuba-moo/claws-mail
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;
}
コード例 #14
0
ファイル: pgpmime.c プロジェクト: kuba-moo/claws-mail
static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
{
	MimeInfo *encinfo, *decinfo, *parseinfo;
	gpgme_data_t cipher = NULL, plain = NULL;
	static gint id = 0;
	FILE *dstfp;
	gchar *fname;
	gpgme_verify_result_t sigstat = NULL;
	PrivacyDataPGP *data = NULL;
	gpgme_ctx_t ctx;
	gchar *chars;
	size_t len;
	gpgme_error_t err;

	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 NULL;
	}
	
	cm_return_val_if_fail(pgpmime_is_encrypted(mimeinfo), NULL);
	
	encinfo = (MimeInfo *) g_node_nth_child(mimeinfo->node, 1)->data;

	cipher = sgpgme_data_from_mimeinfo(encinfo);
	plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx);

	gpgme_data_release(cipher);
	if (plain == NULL) {
		debug_print("plain is null!\n");
		gpgme_release(ctx);
		return NULL;
	}

    	fname = g_strdup_printf("%s%cplaintext.%08x",
		get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);

    	if ((dstfp = claws_fopen(fname, "wb")) == NULL) {
        	FILE_OP_ERROR(fname, "claws_fopen");
		privacy_set_error(_("Couldn't open decrypted file %s"), fname);
        	g_free(fname);
        	gpgme_data_release(plain);
		gpgme_release(ctx);
		debug_print("can't open!\n");
		return NULL;
    	}

	if (fprintf(dstfp, "MIME-Version: 1.0\n") < 0) {
        	FILE_OP_ERROR(fname, "fprintf");
		claws_fclose(dstfp);
		privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
        	g_free(fname);
        	gpgme_data_release(plain);
		gpgme_release(ctx);
		debug_print("can't open!\n");
		return NULL;
	}

	chars = sgpgme_data_release_and_get_mem(plain, &len);
	if (len > 0) {
		if (claws_fwrite(chars, 1, len, dstfp) < len) {
        		FILE_OP_ERROR(fname, "claws_fwrite");
			g_free(chars);
			claws_fclose(dstfp);
			privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
        		g_free(fname);
        		gpgme_data_release(plain);
			gpgme_release(ctx);
			debug_print("can't open!\n");
			return NULL;
		}
	}
	g_free(chars);

	if (claws_safe_fclose(dstfp) == EOF) {
        	FILE_OP_ERROR(fname, "claws_fclose");
		privacy_set_error(_("Couldn't close decrypted file %s"), fname);
        	g_free(fname);
        	gpgme_data_release(plain);
		gpgme_release(ctx);
		debug_print("can't open!\n");
		return NULL;
	}

	parseinfo = procmime_scan_file(fname);
	g_free(fname);
	if (parseinfo == NULL) {
		gpgme_release(ctx);
		privacy_set_error(_("Couldn't parse decrypted file."));
		return NULL;
	}
	decinfo = g_node_first_child(parseinfo->node) != NULL ?
		g_node_first_child(parseinfo->node)->data : NULL;
	if (decinfo == NULL) {
		privacy_set_error(_("Couldn't parse decrypted file parts."));
		gpgme_release(ctx);
		return NULL;
	}

	g_node_unlink(decinfo->node);
	procmime_mimeinfo_free_all(&parseinfo);

	decinfo->tmp = TRUE;

	if (sigstat != NULL && sigstat->signatures != NULL) {
		if (decinfo->privacy != NULL) {
			data = (PrivacyDataPGP *) decinfo->privacy;
		} else {
			data = pgpmime_new_privacydata();
			decinfo->privacy = (PrivacyData *) data;	
		}
		if (data != NULL) {
			data->done_sigtest = TRUE;
			data->is_signed = TRUE;
			data->sigstatus = sigstat;
			if (data->ctx)
				gpgme_release(data->ctx);
			data->ctx = ctx;
		}
	} else
		gpgme_release(ctx);

	return decinfo;
}
コード例 #15
0
ファイル: pgpmime.c プロジェクト: kuba-moo/claws-mail
static gint pgpmime_check_signature(MimeInfo *mimeinfo)
{
	PrivacyDataPGP *data;
	MimeInfo *parent, *signature;
	FILE *fp;
	gchar *boundary;
	gchar *textstr;
	gpgme_data_t sigdata = NULL, textdata = NULL;
	gpgme_error_t err;
	cm_return_val_if_fail(mimeinfo != NULL, -1);
	cm_return_val_if_fail(mimeinfo->privacy != NULL, -1);
	data = (PrivacyDataPGP *) mimeinfo->privacy;
	if ((err = gpgme_new(&data->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 0;
	}

	
	debug_print("Checking PGP/MIME signature\n");

	err = gpgme_set_protocol(data->ctx, GPGME_PROTOCOL_OpenPGP);

	if (err) {
		debug_print ("gpgme_set_protocol failed: %s\n",
                   gpgme_strerror (err));
	}
	parent = procmime_mimeinfo_parent(mimeinfo);

	fp = claws_fopen(parent->data.filename, "rb");
	cm_return_val_if_fail(fp != NULL, SIGNATURE_INVALID);
	
	boundary = g_hash_table_lookup(parent->typeparameters, "boundary");
	if (!boundary) {
		privacy_set_error(_("Signature boundary not found."));
		claws_fclose(fp);
		return 0;
	}
	textstr = get_canonical_content(fp, boundary);

	err = gpgme_data_new_from_mem(&textdata, textstr, (size_t)strlen(textstr), 0);
	if (err) {
		debug_print ("gpgme_data_new_from_mem failed: %s\n",
                   gpgme_strerror (err));
	}
	signature = (MimeInfo *) mimeinfo->node->next->data;
	sigdata = sgpgme_data_from_mimeinfo(signature);

	err = 0;
	if (signature->encoding_type == ENC_BASE64) {
		err = gpgme_data_set_encoding (sigdata, GPGME_DATA_ENCODING_BASE64);
	}
	
	if (err) {
		debug_print ("gpgme_data_set_encoding failed: %s\n",
			gpgme_strerror (err));
	}

	data->sigstatus =
		sgpgme_verify_signature	(data->ctx, sigdata, textdata, NULL);

	gpgme_data_release(sigdata);
	gpgme_data_release(textdata);
	g_free(textstr);
	claws_fclose(fp);
	
	return 0;
}