Exemplo n.º 1
0
/* Copy the data from the GPGME object DAT to a newly created file
   with name OUTFILE.  Returns 0 on success. */
static gpgme_error_t
data_to_file (gpgme_data_t *dat, const char *outfile)
{
  FILE *out;
  char *buf;
  size_t n=0;

  out = fopen (outfile, "wb");
  if (!out)
    return GPG_ERR_UNKNOWN_ERRNO; /* FIXME: We need to check why we
                                     can't use errno here. */
  /* FIXME: Why at all are we using an in memory object wqhen we are
     later going to write to a file anyway. */
  buf = gpgme_data_release_and_get_mem (*dat, &n);
  *dat = NULL;
  if (!n)
    {
      fclose (out);
      return GPG_ERR_EOF; /* FIXME:  wrap this into a gpgme_error() */
    }
  fwrite (buf, 1, n, out);
  fclose (out);
  /* FIXME: We have no error checking above. */
  gpgme_free (buf);
  return 0;
}
Exemplo n.º 2
0
int send_to_server(gpgme_data_t key, char *host, unsigned short port, GPG_CTX *gpg_ctx)
{
	SSL_CTX *ssl_ctx;
	SSL *ssl;
	int sock;

	// connect to server
	init_ssl(&ssl_ctx, &ssl, NULL, NULL);
	sock = create_client_socket(host, port, ssl);
	if (sock < 0)
		return ERROR_SOCKET;

	// C -> S: REG|public key
	// opcode
	SSL_write(ssl, OP_CONNECT, OP_LENGTH);

	// public key
	uint64_t key_length_net;
	size_t key_length_var;
	char *key_buf;
	key_buf = gpgme_data_release_and_get_mem(key, &key_length_var);
	if (key_buf == NULL)
		error_ret("Failed to copy key data\n", ERROR_GPGME);

	// length|data
	key_length_net = htobe64(key_length_var);
	SSL_write(ssl, &key_length_net, sizeof key_length_net);
	SSL_write(ssl, key_buf, key_length_var);

	// TODO: receive challenge from server

	UNUSED(gpg_ctx);

	return ERROR_NO_ERROR;
}
Exemplo n.º 3
0
char *gpg_decrypt_msg(const char *data, long *plain_size) {
    gpgme_ctx_t ctx;
    gpgme_error_t err;
    size_t n = 0;
    char *temp, *str, *msg;
    gpgme_data_t plain, cipher;
    
    msg = add_gpg_headers(data);
    if (!msg) {
        return 0;
    }
    
    err = gpgme_new(&ctx);
    if (err) {
        return 0;
    }
    gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
    gpgme_set_armor(ctx, 1);
//    char *p = getenv("GPG_AGENT_INFO");
//    if (p) {
//        log_write("GPG_AGENT_INFO: %s\n", p);
//    } else {
//        setenv("GPG_AGENT_INFO", "/tmp/gpg-3FhMq6/S.gpg-agent:22765:1", 1);
//        log_write("NO GPG AGENT INFO FOUND\n");
//    }
    gpgme_set_passphrase_cb(ctx, &passphrase_cb, 0);
    
    gpgme_data_new_from_mem(&cipher, msg, strlen(msg), 0);
    gpgme_data_new(&plain);
    
    err = gpgme_op_decrypt(ctx, cipher, plain);
    gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx);
    gpgme_recipient_t recipient = res->recipients;
    while (recipient) {
        log_write(">>> recipient keyid: %s\n", recipient->keyid);
        recipient = recipient->next;
    }
    gpgme_data_release(cipher);
    free(msg);
    
    if (err) {
        log_write("gpgme_op_decrypt error: %s\n", gpgme_strerror(err));
        gpgme_data_release(plain);
        gpgme_release(ctx);
        return 0;
    }
    
    temp = gpgme_data_release_and_get_mem(plain, &n);
    if (!temp) {
        gpgme_release(ctx);
        return 0;
    }
    *plain_size = n;
    str = strndup(temp, n);
    free(temp);
    
    gpgme_release(ctx);
    return str;
}
Exemplo n.º 4
0
/* ------------------
 * get ascii armored public key
 * FREE MEMORY AFTER USAGE OF RETURN VALUE!
 * ------------------ */
char* get_key_armored(const char* fpr)
{	gpgme_error_t error;
	gpgme_ctx_t ctx;
	gpgme_data_t key_data;
	gpgme_key_t key;
	gpgme_key_t key_arr[2];
	key_arr[0] = key_arr[1] = NULL;
	size_t len = 0;
	char* key_str = NULL;
	char* key_str_dup = NULL;

	// connect to gpgme
	gpgme_check_version (NULL);
	error = gpgme_new(&ctx);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		return NULL;
	}

	// get key by fingerprint
	error = gpgme_get_key(ctx,fpr,&key,0);
	if (error || !key)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}
	key_arr[0] = key;

	// create data containers
	gpgme_data_new(&key_data);

	// export key
	gpgme_set_armor(ctx,1);
	error = gpgme_op_export_keys (ctx, key_arr, 0, key_data);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_op_export_keys failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}

	// release memory for data containers
	key_str = gpgme_data_release_and_get_mem(key_data,&len);
	if (key_str != NULL)
	{
		key_str[len] = 0;
		key_str_dup = g_strdup(key_str);
	}
	gpgme_free(key_str);
	// close gpgme connection
	gpgme_release (ctx);

	// we got the key, YEAH :)
	return key_str_dup;
}
Exemplo n.º 5
0
char *gpg_encrypt_msg(const char *msg, const char *fpr) {
    gpgme_ctx_t ctx;
    gpgme_data_t plain, cipher;
    gpgme_error_t err;
    char *temp, *str;
    char *ret = 0;
    gpgme_key_t key_arr[2] = {0, 0};
    size_t n = 0;
    
    err = gpgme_new(&ctx);
    if (err) {
        return 0;
    }
    gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
    gpgme_set_armor(ctx, 1);
    
    err = gpgme_get_key(ctx, fpr, &key_arr[0], 0);
    if (err) {
        gpgme_release(ctx);
        return 0;
    }
    
    err = gpgme_data_new_from_mem(&plain, msg, strlen(msg), 0);
    if (err) {
        goto end;
    }
    gpgme_data_new(&cipher);
    
    err = gpgme_op_encrypt(ctx, key_arr, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher);
    gpgme_data_release(plain);
    if (err) {
        gpgme_data_release(cipher);
        goto end;
    }
    
    temp = gpgme_data_release_and_get_mem(cipher, &n);
    if (!temp) {
        goto end;
    }
    
    str = strndup(temp, n);
    gpgme_free(temp);
    if (!str) {
        goto end;
    }
    
    ret = drop_gpg_headers(str);
    free(str);
    
end:
    gpgme_key_unref(key_arr[0]);
    gpgme_release(ctx);
    return ret;
}
Exemplo n.º 6
0
/* ------------------
 * decrypt a plain string with the key found with fingerprint fpr
 * FREE MEMORY AFTER USAGE OF RETURN VALUE
 * ------------------ */
static char* decrypt(char* cipher_str)
{
	gpgme_error_t error;
	gpgme_ctx_t ctx;
	gpgme_data_t plain,cipher;
	size_t len = 0;
	char* plain_str = NULL;
	char* plain_str_dup = NULL;
	char* armored_buffer;

	// add header and footer:
	armored_buffer = str_armor(cipher_str);

	// connect to gpgme
	gpgme_check_version (NULL);
	error = gpgme_new(&ctx);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		return NULL;
	}

	// create data containers
	gpgme_data_new_from_mem (&cipher, armored_buffer,strlen(armored_buffer),1);
	gpgme_data_new(&plain);

	// decrypt
	error = gpgme_op_decrypt(ctx,cipher,plain);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_op_decrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}

	// release memory for data containers
	gpgme_data_release(cipher);
	plain_str = gpgme_data_release_and_get_mem(plain,&len);
	if (plain_str != NULL)
	{
		plain_str[len] = 0;
		plain_str_dup = g_strdup(plain_str);
	}
	gpgme_free(plain_str);

	// close gpgme connection
	gpgme_release (ctx);

	return plain_str_dup;
}
Exemplo n.º 7
0
/**
* 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;
    }
}
Exemplo n.º 8
0
char *CGPGHelper::Decrypt(const char *szCipher)
{
#ifdef HAVE_LIBGPGME
  if (!mCtx) return 0;

  size_t nRead = 0;
  gpgme_data_t cipher, plain;

  CGPGMEMutex mutex;
  if (!mutex.Lock()) return 0;
  if (gpgme_data_new(&cipher) != GPG_ERR_NO_ERROR) return 0;
  char *buf = strdup(szCipher);
  gpgme_error_t err;
  gpgme_data_write(cipher, buf, strlen(buf));
  free(buf);

  if (gpgme_data_new(&plain) != GPG_ERR_NO_ERROR)
  {
    gpgme_data_release(cipher);
    return 0;
  }

  gpgme_data_seek(cipher, 0, SEEK_SET);
  if ((err = gpgme_op_decrypt(mCtx, cipher, plain)) != GPG_ERR_NO_ERROR)
    gLog.Warn("%s[GPG] gpgme message decryption failed: %s\n", L_WARNxSTR, gpgme_strerror(err));
  
  gpgme_data_release(cipher);
  buf = gpgme_data_release_and_get_mem(plain, &nRead);
  if (!buf) return 0;
  buf = (char *)realloc(buf, nRead+1);
  buf[nRead] = 0;
  return buf;
#else
  return 0;
#endif
}
Exemplo n.º 9
0
/* ------------------
 * encrypt a plain string with the key found with fingerprint fpr
 * ------------------ */
static char* encrypt(const char* plain_str, const char* fpr)
{
	gpgme_error_t error;
	gpgme_ctx_t ctx;
	gpgme_key_t key;
	gpgme_data_t plain,cipher;
	char* cipher_str = NULL;
	char* cipher_str_dup = NULL;
	size_t len;
	gpgme_key_t key_arr[2];

	key_arr[0] = NULL;
	key_arr[1] = NULL;

	// connect to gpgme
	gpgme_check_version (NULL);
	error = gpgme_new(&ctx);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		return NULL;
	}

	// get key by fingerprint
	error = gpgme_get_key(ctx,fpr,&key,0);
	if (error || !key)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}
	key_arr[0] = key;

	// create data containers
	gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1);
	gpgme_data_new(&cipher);

	// encrypt, ascii armored
	gpgme_set_armor(ctx,1);
	error = gpgme_op_encrypt (ctx, key_arr,GPGME_ENCRYPT_ALWAYS_TRUST,plain,cipher);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_op_encrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}

	// release memory for data containers
	gpgme_data_release(plain);
	cipher_str = gpgme_data_release_and_get_mem(cipher,&len);
	if (cipher_str != NULL)
	{
		cipher_str_dup = str_unarmor(cipher_str);
	}
	gpgme_free(cipher_str);

	// close gpgme connection
	gpgme_release (ctx);

	return cipher_str_dup;
}
Exemplo n.º 10
0
/* ------------------
 * sign a plain string with the key found with fingerprint fpr
 * FREE MEMORY AFTER USAGE OF RETURN VALUE!
 * ------------------ */
static char* sign(const char* plain_str,const char* fpr)
{
	gpgme_error_t error;
	gpgme_ctx_t ctx;
	gpgme_key_t key;
	gpgme_data_t plain,sig;
	const int MAX_LEN = 10000;
	char *sig_str = NULL;
	char *sig_str_dup = NULL;
	size_t len = 0;

	// connect to gpgme
	gpgme_check_version (NULL);
	error = gpgme_new(&ctx);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		return NULL;
	}

	// get key by fingerprint
	error = gpgme_get_key(ctx,fpr,&key,1);
	if (error || !key)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}

	// select signers
	gpgme_signers_clear(ctx);
	error = gpgme_signers_add (ctx,key);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_signers_add failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}

	// create data containers
	gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1);
	gpgme_data_new(&sig);

	// sign message, ascii armored
	gpgme_set_armor(ctx,1);
	error = gpgme_op_sign(ctx,plain,sig,GPGME_SIG_MODE_DETACH);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_op_sign failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}

	// release memory for data containers
	gpgme_data_release(plain);
	sig_str = gpgme_data_release_and_get_mem(sig,&len);
	if (sig_str != NULL)
	{
		sig_str[len] = 0;
		sig_str_dup = str_unarmor(sig_str);
	}
	gpgme_free(sig_str);
	
	// close gpgme connection
	gpgme_release (ctx);

	return sig_str_dup;
}
Exemplo n.º 11
0
/* The main GPG encryption routine for libfko.
*/
int
gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len,
        const char *pw, unsigned char **out, size_t *out_len)
{
    char               *tmp_buf;
    int                 res;

    gpgme_ctx_t         gpg_ctx     = NULL;
    gpgme_data_t        cipher      = NULL;
    gpgme_data_t        plaintext   = NULL;
    gpgme_key_t         key[2]      = { NULL, NULL };
    gpgme_error_t       err;

    /* Initialize gpgme
    */
    res = init_gpgme(fko_ctx);
    if(res != FKO_SUCCESS)
        return(res);

    gpg_ctx = fko_ctx->gpg_ctx;

    /* Initialize the plaintext data (place into gpgme_data object)
    */
    err = gpgme_data_new_from_mem(&plaintext, (char*)indata, in_len, 1);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;
        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ);
    }

    /* Set protocol
    */
    err = gpgme_set_protocol(gpg_ctx, GPGME_PROTOCOL_OpenPGP);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_data_release(plaintext);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_SET_PROTOCOL);
    }

    /* Set ascii-armor off (we will be base64-encoding the encrypted data
     * ourselves.
    */
    gpgme_set_armor(gpg_ctx, 0);

    /* The gpgme_encrypt.... functions take a recipient key array, so we add
     * our single key here.
    */
    key[0] = fko_ctx->recipient_key;

    /* Create the buffer for our encrypted data.
    */
    err = gpgme_data_new(&cipher);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_data_release(plaintext);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ);
    }

    /* Here we add the signer to the gpgme context if there is one.
    */
    if(fko_ctx->gpg_signer != NULL) {
        gpgme_signers_clear(gpg_ctx);
        err = gpgme_signers_add(gpg_ctx, fko_ctx->signer_key);
        if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
        {
            gpgme_data_release(plaintext);
            gpgme_data_release(cipher);
            gpgme_release(gpg_ctx);
            fko_ctx->gpg_ctx = NULL;

            fko_ctx->gpg_err = err;

            return(FKO_ERROR_GPGME_ADD_SIGNER);
        }
    }

    /* Set the passphrase callback.
    */
    gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw);

    /* Encrypt and sign (if a sig was provided) the SPA data.
    */
    if(fko_ctx->gpg_signer == NULL)
        err = gpgme_op_encrypt(
            gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher
        );
    else
        err = gpgme_op_encrypt_sign(
            gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher
        );

    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_data_release(plaintext);
        gpgme_data_release(cipher);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        if(gpgme_err_code(err) == GPG_ERR_CANCELED)
            return(FKO_ERROR_GPGME_BAD_PASSPHRASE);

        return(FKO_ERROR_GPGME_ENCRYPT_SIGN);
    }

    /* Done with the plaintext.
    */
    gpgme_data_release(plaintext);

    /* Get the encrypted data and its length from the gpgme data object.
     * BTW, this does free the memory used by cipher.
    */
    tmp_buf = gpgme_data_release_and_get_mem(cipher, out_len);

    *out = malloc(*out_len); /* This is freed upon fko_ctx destruction. */
    if(*out == NULL)
        res = FKO_ERROR_MEMORY_ALLOCATION;
    else
    {
        memcpy(*out, tmp_buf, *out_len);
        res = FKO_SUCCESS;
    }

    gpgme_free(tmp_buf);

    return(res);
}
Exemplo n.º 12
0
retvalue signature_check_inline(const struct signature_requirement *requirements, const char *filename, char **chunk_p) {
	gpg_error_t err;
	gpgme_data_t dh, dh_gpg;
	int fd;

	fd = open(filename, O_RDONLY|O_NOCTTY);
	if (fd < 0) {
		int e = errno;
		fprintf(stderr, "Error opening '%s': %s\n",
				filename, strerror(e));
		return RET_ERRNO(e);
	}
	err = gpgme_data_new_from_fd(&dh_gpg, fd);
	if (err != 0) {
		(void)close(fd);
		return gpgerror(err);
	}

	err = gpgme_data_new(&dh);
	if (err != 0) {
		(void)close(fd);
		gpgme_data_release(dh_gpg);
		return gpgerror(err);
	}
	err = gpgme_op_verify(context, dh_gpg, NULL, dh);
	(void)close(fd);
	if (gpg_err_code(err) == GPG_ERR_NO_DATA) {
		char *chunk; const char *n;
		size_t len;
		retvalue r;

		gpgme_data_release(dh);
		gpgme_data_release(dh_gpg);

		r = readtextfile(filename, filename, &chunk, &len);
		assert (r != RET_NOTHING);
		if (RET_WAS_ERROR(r))
			return r;

		assert (chunk[len] == '\0');
		len = chunk_extract(chunk, chunk, len, false, &n);
		if (chunk[0] == '-' || *n != '\0') {
			fprintf(stderr,
"Cannot parse '%s': found no signature but does not looks safe to be assumed unsigned, either.\n",
				filename);
			free(chunk);
			return RET_ERROR;
		}
		if (requirements != NULL) {
			free(chunk);
			return RET_ERROR_BADSIG;
		}
		fprintf(stderr,
"WARNING: No signature found in %s, assuming it is unsigned!\n",
				filename);
		assert (chunk[len] == '\0');
		*chunk_p = realloc(chunk, len+1);
		if (FAILEDTOALLOC(*chunk_p))
			*chunk_p = chunk;
		return RET_OK;
	} else {
		char *plain_data, *chunk;
		const char *n;
		size_t plain_len, len;
		retvalue r;

		if (err != 0) {
			gpgme_data_release(dh_gpg);
			gpgme_data_release(dh);
			return gpgerror(err);
		}
		gpgme_data_release(dh_gpg);
		plain_data = gpgme_data_release_and_get_mem(dh, &plain_len);
		if (plain_data == NULL) {
			fprintf(stderr,
"Error: libgpgme failed to extract the plain data out of\n"
"'%s'.\n"
"While it did so in a way indicating running out of memory, experience says\n"
"this also happens when gpg returns a error code it does not understand.\n"
"To check this please try running gpg --verify '%s' manually.\n"
"Continuing extracting it ignoring all signatures...",
					filename, filename);
			return RET_ERROR;
		}
		chunk = malloc(plain_len+1);
		if (FAILEDTOALLOC(chunk))
			return RET_ERROR_OOM;
		len = chunk_extract(chunk, plain_data, plain_len, false, &n);
#ifdef HAVE_GPGPME_FREE
		gpgme_free(plain_data);
#else
		free(plain_data);
#endif
		assert (len <= plain_len);
		if (plain_len != (size_t)(n - plain_data)) {
			fprintf(stderr,
"Cannot parse '%s': extraced signed data looks malformed.\n",
				filename);
			r = RET_ERROR;
		} else
			r = verify_signature(requirements, filename, NULL);
		if (RET_IS_OK(r)) {
			*chunk_p = realloc(chunk, len+1);
			if (FAILEDTOALLOC(*chunk_p))
				*chunk_p = chunk;
		} else
			free(chunk);
		return r;
	}
}
Exemplo n.º 13
0
/* ------------------
 * encrypt a plain string with the key found with fingerprint fpr
 * ------------------ */
static char* encrypt(const char* plain_str, const char* fpr)
{
    gpgme_error_t error;
    gpgme_ctx_t ctx;
    gpgme_key_t key;
    gpgme_key_t sender_key;
    gpgme_data_t plain,cipher;
    char* cipher_str = NULL;
    char* cipher_str_dup = NULL;
    size_t len;
    gpgme_key_t key_arr[3];

    key_arr[0] = NULL;
    key_arr[1] = NULL;
    key_arr[2] = NULL;

    // connect to gpgme
    gpgme_check_version (NULL);
    error = gpgme_new(&ctx);
    if (error)
    {
        purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
        return NULL;
    }

    // get key by fingerprint
    error = gpgme_get_key(ctx,fpr,&key,0);
    if (error || !key)
    {
        purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
        gpgme_release (ctx);
        return NULL;
    }
    key_arr[0] = key;

    // check if user selected a main key
    const char* sender_fpr = purple_prefs_get_string(PREF_MY_KEY);
    if ( sender_fpr != NULL && strcmp(sender_fpr,"") != 0)
    {
        // get own key by fingerprint
        error = gpgme_get_key(ctx,sender_fpr,&sender_key,0);
        if (!error && sender_key)
            key_arr[1] = sender_key;
        else
            purple_debug_error(PLUGIN_ID,"gpgme_get_key: sender key for fingerprint %s is missing! error: %s %s\n", sender_fpr, gpgme_strsource (error), gpgme_strerror (error) );
    }
    else
        purple_debug_error(PLUGIN_ID,"purple_prefs_get_string: PREF_MY_KEY was empty\n");

    // create data containers
    gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1);
    gpgme_data_new(&cipher);

    // encrypt, ascii armored
    gpgme_set_armor(ctx,1);
    error = gpgme_op_encrypt (ctx, key_arr,GPGME_ENCRYPT_ALWAYS_TRUST,plain,cipher);
    if (error)
    {
        purple_debug_error(PLUGIN_ID,"gpgme_op_encrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
        gpgme_release (ctx);
        return NULL;
    }

    // release memory for data containers
    gpgme_data_release(plain);
    cipher_str = gpgme_data_release_and_get_mem(cipher,&len);
    if (cipher_str != NULL)
    {
        cipher_str_dup = str_unarmor(cipher_str);
    }
    gpgme_free(cipher_str);

    // close gpgme connection
    gpgme_release (ctx);

    return cipher_str_dup;
}
Exemplo n.º 14
0
char *CGPGHelper::Encrypt(const char *szPlain, const char *szId,
                          unsigned long nPPID)
{
#ifdef HAVE_LIBGPGME
  if (!mCtx) return 0;
  if (!szPlain) return 0;

  char szUser[MAX_LINE_LEN], buf[MAX_LINE_LEN];
  buf[0] = '\0';
  sprintf(szUser, "%s.%lu", szId, nPPID);
  mKeysIni.SetSection("keys");

  ICQUser *u = gUserManager.FetchUser( szId, nPPID, LOCK_R );
  if ( u )
  {
    const char *tmp = u->GPGKey();
    if ( tmp && tmp[0]!='\0' )
      strncpy( buf, tmp, MAX_LINE_LEN-1 );
    gUserManager.DropUser( u );
  }
  if ( !buf[0] && !mKeysIni.ReadStr(szUser, buf) ) return 0;
	
  gLog.Info("[GPG] Encrypting message to %s.\n", szId);

  CGPGMEMutex mutex;
  if (!mutex.Lock()) return 0;
  gpgme_key_t rcps[2];
  gpgme_data_t plain = 0, cipher = 0;
  gpgme_error_t err;
  char *szCipher = 0;
  size_t nRead = 0;

  rcps[1] = 0;
  // Still use the old method, gpgme_get_key requires the fingerprint, which
  // actually isn't very helpful.
  if (gpgme_op_keylist_start (mCtx, buf, 0) != GPG_ERR_NO_ERROR)
    gLog.Error("%s[GPG] Couldn't use gpgme recipient: %s\n", L_ERRORxSTR, buf);
  else
  {
    if (gpgme_op_keylist_next(mCtx, rcps) != GPG_ERR_NO_ERROR)
      gLog.Error("%s[GPG] Couldn't get key: %s\n", L_ERRORxSTR, buf);
    else
    {
      if (gpgme_data_new_from_mem(&plain, szPlain, strlen(szPlain), 0) == GPG_ERR_NO_ERROR &&
          gpgme_data_new(&cipher) == GPG_ERR_NO_ERROR)
      {
        if ((err = gpgme_op_encrypt(mCtx, rcps, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher)) == GPG_ERR_NO_ERROR)
        {
          szCipher = gpgme_data_release_and_get_mem(cipher, &nRead);
          cipher = 0;
          szCipher = (char *)realloc(szCipher, nRead + 1);
          szCipher[nRead] = 0;
        }
        else
          gLog.Error("%s[GPG] Encryption failed: %s\n", L_ERRORxSTR, gpgme_strerror(err));
      }
    }

    if (cipher) gpgme_data_release(cipher);
    if (plain) gpgme_data_release(plain);
  }

  gpgme_key_unref(rcps[0]);
  return szCipher;
#else
  return 0;
#endif
}
Exemplo n.º 15
0
static retvalue extract_signed_data(const char *buffer, size_t bufferlen, const char *filenametoshow, char **chunkread, /*@null@*/ /*@out@*/struct signatures **signatures_p, bool *brokensignature) {
	char *chunk;
	gpg_error_t err;
	gpgme_data_t dh, dh_gpg;
	size_t plain_len;
	char *plain_data;
	retvalue r;
	struct signatures *signatures = NULL;
	bool foundbroken = false;

	r = signature_init(false);
	if (RET_WAS_ERROR(r))
		return r;

	err = gpgme_data_new_from_mem(&dh_gpg, buffer, bufferlen, 0);
	if (err != 0)
		return gpgerror(err);

	err = gpgme_data_new(&dh);
	if (err != 0) {
		gpgme_data_release(dh_gpg);
		return gpgerror(err);
	}
	err = gpgme_op_verify(context, dh_gpg, NULL, dh);
	if (gpg_err_code(err) == GPG_ERR_NO_DATA) {
		if (verbose > 5)
			fprintf(stderr,
"Data seems not to be signed trying to use directly....\n");
		gpgme_data_release(dh);
		gpgme_data_release(dh_gpg);
		return RET_NOTHING;
	} else {
		if (err != 0) {
			gpgme_data_release(dh_gpg);
			gpgme_data_release(dh);
			return gpgerror(err);
		}
		if (signatures_p != NULL || brokensignature != NULL) {
			r = checksigs(filenametoshow,
				(signatures_p!=NULL)?&signatures:NULL,
				(brokensignature!=NULL)?&foundbroken:NULL);
			if (RET_WAS_ERROR(r)) {
				gpgme_data_release(dh_gpg);
				gpgme_data_release(dh);
				return r;
			}
		}
		gpgme_data_release(dh_gpg);
		plain_data = gpgme_data_release_and_get_mem(dh, &plain_len);
		if (plain_data == NULL) {
			fprintf(stderr,
"(not yet fatal) ERROR: libgpgme failed to extract the plain data out of\n"
"'%s'.\n"
"While it did so in a way indicating running out of memory, experience says\n"
"this also happens when gpg returns a error code it does not understand.\n"
"To check this please try running gpg --verify '%s' manually.\n"
"Continuing extracting it ignoring all signatures...",
					filenametoshow, filenametoshow);
			signatures_free(signatures);
			return RET_NOTHING;
		}
		if (signatures != NULL) {
			r = check_primary_keys(signatures);
			if (RET_WAS_ERROR(r)) {
				signatures_free(signatures);
				return r;
			}
		}
	}

	if (FAILEDTOALLOC(plain_data))
		r = RET_ERROR_OOM;
	else {
		size_t len;
		const char *afterchanges;

		chunk = malloc(plain_len + 1);
		len = chunk_extract(chunk, plain_data, plain_len, false,
				&afterchanges);
		if (len == 0) {
			fprintf(stderr,
"Could only find spaces within '%s'!\n",
					filenametoshow);
			free(chunk);
			r = RET_ERROR;
		} else if (afterchanges != plain_data + plain_len) {
			if (*afterchanges == '\0')
				fprintf(stderr,
"Unexpected \\0 character within '%s'!\n",
					filenametoshow);
			else
				fprintf(stderr,
"Unexpected data after ending empty line in '%s'!\n",
					filenametoshow);
			free(chunk);
			r = RET_ERROR;
		} else
			*chunkread = chunk;
	}
#ifdef HAVE_GPGPME_FREE
	gpgme_free(plain_data);
#else
	free(plain_data);
#endif
	if (RET_IS_OK(r)) {
		if (signatures_p != NULL)
			*signatures_p = signatures;
		if (brokensignature != NULL)
			*brokensignature = foundbroken;
	} else {
		signatures_free(signatures);
	}
	return r;
}
Exemplo n.º 16
0
static void
gpa_file_sign_operation_done_cb (GpaContext *context,
                                 gpg_error_t err,
                                 GpaFileSignOperation *op)
{
    gpa_file_item_t file_item = GPA_FILE_OPERATION (op)->current->data;

    if (file_item->direct_in)
    {
        size_t len;
        char *sig_gpgme = gpgme_data_release_and_get_mem (op->sig, &len);
        op->sig = NULL;
        /* Do the memory allocation dance.  */

        if (sig_gpgme)
        {
            /* Conveniently make ASCII stuff into a string.  */
            file_item->direct_out = g_malloc (len + 1);
            memcpy (file_item->direct_out, sig_gpgme, len);
            gpgme_free (sig_gpgme);
            file_item->direct_out[len] = '\0';
            /* Yep, excluding the trailing zero.  */
            file_item->direct_out_len = len;
        }
        else
        {
            file_item->direct_out = NULL;
            file_item->direct_out_len = 0;
        }
    }

    /* Do clean up on the operation */
    gpgme_data_release (op->plain);
    op->plain = NULL;
    close (op->plain_fd);
    op->plain_fd = -1;
    gpgme_data_release (op->sig);
    op->sig = NULL;
    close (op->sig_fd);
    op->sig_fd = -1;
    gtk_widget_hide (GPA_FILE_OPERATION (op)->progress_dialog);

    if (err)
    {
        if (! file_item->direct_in)
        {
            /* If an error happened, (or the user canceled) delete the
               created file and abort further signions.  */
            g_unlink (op->sig_filename);
            g_free (op->sig_filename);
        }
        g_signal_emit_by_name (GPA_OPERATION (op), "completed", err);
    }
    else
    {
        /* We've just created a file */
        g_signal_emit_by_name (GPA_OPERATION (op), "created_file",
                               file_item);
        /* Go to the next file in the list and sign it */
        GPA_FILE_OPERATION (op)->current = g_list_next
                                           (GPA_FILE_OPERATION (op)->current);
        gpa_file_sign_operation_next (op);
    }
}
Exemplo n.º 17
0
char*
p_gpg_sign(const char *const str, const char *const fp)
{
    gpgme_ctx_t ctx;
    gpgme_error_t error = gpgme_new(&ctx);
    if (error) {
        log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        return NULL;
    }

    gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL);

    gpgme_key_t key = NULL;
    error = gpgme_get_key(ctx, fp, &key, 1);

    if (error || key == NULL) {
        log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        gpgme_release(ctx);
        return NULL;
    }

    gpgme_signers_clear(ctx);
    error = gpgme_signers_add(ctx, key);
    gpgme_key_unref(key);

    if (error) {
        log_error("GPG: Failed to load signer. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        gpgme_release(ctx);
        return NULL;
    }

    char *str_or_empty = NULL;
    if (str) {
        str_or_empty = strdup(str);
    } else {
        str_or_empty = strdup("");
    }
    gpgme_data_t str_data;
    gpgme_data_new_from_mem(&str_data, str_or_empty, strlen(str_or_empty), 1);
    free(str_or_empty);

    gpgme_data_t signed_data;
    gpgme_data_new(&signed_data);

    gpgme_set_armor(ctx,1);
    error = gpgme_op_sign(ctx, str_data, signed_data, GPGME_SIG_MODE_DETACH);
    gpgme_data_release(str_data);
    gpgme_release(ctx);

    if (error) {
        log_error("GPG: Failed to sign string. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        gpgme_data_release(signed_data);
        return NULL;
    }

    char *result = NULL;

    size_t len = 0;
    char *signed_str = gpgme_data_release_and_get_mem(signed_data, &len);
    if (signed_str) {
        GString *signed_gstr = g_string_new("");
        g_string_append_len(signed_gstr, signed_str, len);
        result = _remove_header_footer(signed_gstr->str, PGP_SIGNATURE_FOOTER);
        g_string_free(signed_gstr, TRUE);
        gpgme_free(signed_str);
    }

    if (passphrase_attempt) {
        passphrase = strdup(passphrase_attempt);
    }

    return result;
}
Exemplo n.º 18
0
char*
p_gpg_encrypt(const char *const barejid, const char *const message, const char *const fp)
{
    ProfPGPPubKeyId *pubkeyid = g_hash_table_lookup(pubkeys, barejid);
    if (!pubkeyid) {
        return NULL;
    }
    if (!pubkeyid->id) {
        return NULL;
    }

    gpgme_key_t keys[3];

    keys[0] = NULL;
    keys[1] = NULL;
    keys[2] = NULL;

    gpgme_ctx_t ctx;
    gpgme_error_t error = gpgme_new(&ctx);
    if (error) {
        log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        return NULL;
    }

    gpgme_key_t receiver_key;
    error = gpgme_get_key(ctx, pubkeyid->id, &receiver_key, 0);
    if (error || receiver_key == NULL) {
        log_error("GPG: Failed to get receiver_key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        gpgme_release(ctx);
        return NULL;
    }
    keys[0] = receiver_key;

    gpgme_key_t sender_key = NULL;
    error = gpgme_get_key(ctx, fp, &sender_key, 0);
    if (error || sender_key == NULL) {
        log_error("GPG: Failed to get sender_key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        gpgme_release(ctx);
        return NULL;
    }
    keys[1] = sender_key;

    gpgme_data_t plain;
    gpgme_data_new_from_mem(&plain, message, strlen(message), 1);

    gpgme_data_t cipher;
    gpgme_data_new(&cipher);

    gpgme_set_armor(ctx, 1);
    error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher);
    gpgme_data_release(plain);
    gpgme_release(ctx);
    gpgme_key_unref(receiver_key);
    gpgme_key_unref(sender_key);

    if (error) {
        log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        return NULL;
    }

    size_t len;
    char *cipher_str = gpgme_data_release_and_get_mem(cipher, &len);

    char *result = NULL;
    if (cipher_str) {
        GString *cipher_gstr = g_string_new("");
        g_string_append_len(cipher_gstr, cipher_str, len);
        result = _remove_header_footer(cipher_gstr->str, PGP_MESSAGE_FOOTER);
        g_string_free(cipher_gstr, TRUE);
        gpgme_free(cipher_str);
    }

    return result;
}
Exemplo n.º 19
0
char*
p_gpg_decrypt(const char *const cipher)
{
    gpgme_ctx_t ctx;
    gpgme_error_t error = gpgme_new(&ctx);

    if (error) {
        log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        return NULL;
    }

    gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL);

    char *cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER);
    gpgme_data_t cipher_data;
    gpgme_data_new_from_mem(&cipher_data, cipher_with_headers, strlen(cipher_with_headers), 1);
    free(cipher_with_headers);

    gpgme_data_t plain_data;
    gpgme_data_new(&plain_data);

    error = gpgme_op_decrypt(ctx, cipher_data, plain_data);
    gpgme_data_release(cipher_data);

    if (error) {
        log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        gpgme_data_release(plain_data);
        gpgme_release(ctx);
        return NULL;
    }

    gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx);
    if (res) {
        GString *recipients_str = g_string_new("");
        gpgme_recipient_t recipient = res->recipients;
        while (recipient) {
            gpgme_key_t key;
            error = gpgme_get_key(ctx, recipient->keyid, &key, 1);

            if (!error && key) {
                const char *addr = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, NULL, 0);
                if (addr) {
                    g_string_append(recipients_str, addr);
                }
                gpgme_key_unref(key);
            }

            if (recipient->next) {
                g_string_append(recipients_str, ", ");
            }

            recipient = recipient->next;
        }

        log_debug("GPG: Decrypted message for recipients: %s", recipients_str->str);
        g_string_free(recipients_str, TRUE);
    }
    gpgme_release(ctx);

    size_t len = 0;
    char *plain_str = gpgme_data_release_and_get_mem(plain_data, &len);
    char *result = NULL;
    if (plain_str) {
        plain_str[len] = 0;
        result = g_strdup(plain_str);
    }
    gpgme_free(plain_str);

    if (passphrase_attempt) {
        passphrase = strdup(passphrase_attempt);
    }

    return result;
}
Exemplo n.º 20
0
/* The main GPG decryption routine for libfko.
*/
int
gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata,
        size_t in_len, const char *pw, unsigned char **out, size_t *out_len)
{
    char                   *tmp_buf;
    int                     res;

    gpgme_ctx_t             gpg_ctx     = NULL;
    gpgme_data_t            cipher      = NULL;
    gpgme_data_t            plaintext   = NULL;
    gpgme_error_t           err;
    gpgme_decrypt_result_t  decrypt_res;
    gpgme_verify_result_t   verify_res;

    /* Initialize gpgme
    */
    res = init_gpgme(fko_ctx);
    if(res != FKO_SUCCESS)
        return(res);

    gpg_ctx = fko_ctx->gpg_ctx;

    err = gpgme_data_new(&plaintext);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ);
    }

    /* Initialize the cipher data (place into gpgme_data object)
    */
    err = gpgme_data_new_from_mem(&cipher, (char*)indata, in_len, 0);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_data_release(plaintext);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ);
    }

    /* Set the passphrase callback.
    */
    gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw);

    /* Now decrypt and verify.
    */
    err = gpgme_op_decrypt_verify(gpg_ctx, cipher, plaintext);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_data_release(plaintext);
        gpgme_data_release(cipher);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_DECRYPT_FAILED);
    }

    /* Done with the cipher text.
    */
    gpgme_data_release(cipher);

    /* We check the "usupported_algorithm" flag in the decrypt result.
    */
    decrypt_res = gpgme_op_decrypt_result(gpg_ctx);

    if(decrypt_res->unsupported_algorithm)
    {
        gpgme_data_release(plaintext);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        return(FKO_ERROR_GPGME_DECRYPT_UNSUPPORTED_ALGORITHM);
    }

    /* Now verify the signatures if so configured.
    */
    if(fko_ctx->verify_gpg_sigs)
    {
        verify_res  = gpgme_op_verify_result(gpg_ctx);

        res = process_sigs(fko_ctx, verify_res);

        if(res != FKO_SUCCESS)
        {
            gpgme_data_release(plaintext);
            gpgme_release(gpg_ctx);
            fko_ctx->gpg_ctx = NULL;

            return(res);
        }
    }

    /* Get the encrypted data and its length from the gpgme data object.
    */
    tmp_buf = gpgme_data_release_and_get_mem(plaintext, out_len);

    /* Use calloc here with an extra byte because I am not sure if all systems
     * will include the terminating NULL with the decrypted data (which is
     * expected to be a string).
    */
    *out = calloc(1, *out_len+1); /* This is freed upon fko_ctx destruction. */

    if(*out == NULL)
        res = FKO_ERROR_MEMORY_ALLOCATION;
    else
    {
        memcpy(*out, tmp_buf, *out_len);
        res = FKO_SUCCESS;
    }

    gpgme_free(tmp_buf);

    return(res);
}
Exemplo n.º 21
0
static void
gpa_file_decrypt_operation_done_cb (GpaContext *context,
				    gpg_error_t err,
				    GpaFileDecryptOperation *op)
{
  gpa_file_item_t file_item = GPA_FILE_OPERATION (op)->current->data;

  if (file_item->direct_in)
    {
      size_t len;
      char *plain_gpgme = gpgme_data_release_and_get_mem (op->plain, &len);
      op->plain = NULL;
      /* Do the memory allocation dance.  */

      if (plain_gpgme)
	{
	  /* Conveniently make ASCII stuff into a string.  */
	  file_item->direct_out = g_malloc (len + 1);
	  memcpy (file_item->direct_out, plain_gpgme, len);
	  gpgme_free (plain_gpgme);
	  file_item->direct_out[len] = '\0';
	  /* Yep, excluding the trailing zero.  */
	  file_item->direct_out_len = len;
	}
      else
	{
	  file_item->direct_out = NULL;
	  file_item->direct_out_len = 0;
	}
    }

  /* Do clean up on the operation */
  gpgme_data_release (op->plain);
  op->plain = NULL;
  close (op->plain_fd);
  op->plain_fd = -1;
  gpgme_data_release (op->cipher);
  op->cipher = NULL;
  close (op->cipher_fd);
  op->cipher_fd = -1;
  gtk_widget_hide (GPA_FILE_OPERATION (op)->progress_dialog);
  if (err)
    {
      if (! file_item->direct_in)
	{
	  /* If an error happened, (or the user canceled) delete the
	     created file and abort further decryptions.  */
	  g_unlink (file_item->filename_out);
	  g_free (file_item->filename_out);
	  file_item->filename_out = NULL;
	}
      /* FIXME:CLIPBOARD: Server finish?  */
      g_signal_emit_by_name (GPA_OPERATION (op), "completed", err);
    }
  else
    {
      /* We've just created a file */
      g_signal_emit_by_name (GPA_OPERATION (op), "created_file", file_item);

      if (op->verify)
	{
	  gpgme_verify_result_t result;

	  result = gpgme_op_verify_result (GPA_OPERATION (op)->context->ctx);
	  if (result->signatures)
	    {
	      /* Add the file to the result dialog.  FIXME: Maybe we
		 should use the filename without the directory.  */
	      gpa_file_verify_dialog_add_file (GPA_FILE_VERIFY_DIALOG (op->dialog),
					       file_item->direct_name
					       ? file_item->direct_name
					       : file_item->filename_in,
					       NULL, NULL,
					       result->signatures);
	      op->signed_files++;
	    }
	}

      /* Go to the next file in the list and decrypt it */
      GPA_FILE_OPERATION (op)->current = g_list_next
	(GPA_FILE_OPERATION (op)->current);
      gpa_file_decrypt_operation_next (op);
    }
}