core: New data flags "io-buffer-size" and "sensitive".
* src/data.c (_gpgme_data_release): Free buffers. (gpgme_data_seek): Adjust from renamed fields. (gpgme_data_set_flag): Implement new flags. (_gpgme_data_inbound_handler): Allow the use of a malloced buffer. (_gpgme_data_outbound_handler): Ditto. * src/data.h (BUFFER_SIZE): Move out of the struct definition. (struct gpgme_data): Remove pending filed and introduce inbound and outbound fields. * src/conversion.c (_gpgme_wipememory): New. Taken from GnuPG. * src/cJSON.c (wipememory): Use this here too. * tests/run-decrypt.c (main): Add options "--large-buffers" and "--sensitive". -- GnuPG-bug-id: 5478 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
ea290108e4
commit
fde20940b5
@ -2253,6 +2253,22 @@ the data. If this is set the OpenPGP engine may use this to decide on
|
|||||||
buffer allocation strategies and to provide a total value for its
|
buffer allocation strategies and to provide a total value for its
|
||||||
progress information.
|
progress information.
|
||||||
|
|
||||||
|
@item io-buffer-size
|
||||||
|
The value is a decimal number with the length of internal buffers to
|
||||||
|
used for internal I/O operations. The value is capped at 1048576 (1
|
||||||
|
MiB). In certain environments large buffers can yield a performance
|
||||||
|
boost for callback bases data object, but the details depend a lot on
|
||||||
|
the circumstances and the operating system. This flag may only be set
|
||||||
|
once and must be set before any actual I/O happens ion the data
|
||||||
|
objects.
|
||||||
|
|
||||||
|
@item sensitive
|
||||||
|
If the numeric value is not 0 the data object is considered to contain
|
||||||
|
sensitive information like passwords or key material. If this is set
|
||||||
|
the internal buffers are securely overwritten with zeroes by
|
||||||
|
gpgme_data_release.
|
||||||
|
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
This function returns @code{0} on success.
|
This function returns @code{0} on success.
|
||||||
|
20
src/cJSON.c
20
src/cJSON.c
@ -50,21 +50,13 @@
|
|||||||
|
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
|
|
||||||
|
|
||||||
/* Only use calloc. */
|
/* Only use calloc. */
|
||||||
#define CALLOC_ONLY 1
|
#define CALLOC_ONLY 1
|
||||||
|
|
||||||
/* Maximum recursion depth */
|
/* Maximum recursion depth */
|
||||||
#define MAX_DEPTH 512
|
#define MAX_DEPTH 512
|
||||||
|
|
||||||
/* To avoid that a compiler optimizes certain memset calls away, these
|
|
||||||
macros may be used instead. */
|
|
||||||
#define wipememory2(_ptr,_set,_len) do { \
|
|
||||||
volatile char *_vptr=(volatile char *)(_ptr); \
|
|
||||||
size_t _vlen=(_len); \
|
|
||||||
while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
|
|
||||||
} while(0)
|
|
||||||
#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
|
|
||||||
|
|
||||||
/* We use malloc function wrappers from gpgrt (aka libgpg-error). */
|
/* We use malloc function wrappers from gpgrt (aka libgpg-error). */
|
||||||
#include <gpgrt.h>
|
#include <gpgrt.h>
|
||||||
#define xtrycalloc(a,b) gpgrt_calloc ((a), (b))
|
#define xtrycalloc(a,b) gpgrt_calloc ((a), (b))
|
||||||
@ -77,6 +69,16 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
wipememory (void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
/* Prevent compiler from optimizing away the call to memset by accessing
|
||||||
|
* memset through volatile pointer. */
|
||||||
|
static void *(*volatile memset_ptr)(void *, int, size_t) = (void *)memset;
|
||||||
|
memset_ptr (ptr, 0, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cJSON_strcasecmp (const char *s1, const char *s2)
|
cJSON_strcasecmp (const char *s1, const char *s2)
|
||||||
{
|
{
|
||||||
|
@ -43,6 +43,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
_gpgme_wipememory (void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
/* Prevent compiler from optimizing away the call to memset by accessing
|
||||||
|
* memset through volatile pointer. */
|
||||||
|
static void *(*volatile memset_ptr)(void *, int, size_t) = (void *)memset;
|
||||||
|
memset_ptr (ptr, 0, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
do_strconcat (const char *s1, va_list arg_ptr)
|
do_strconcat (const char *s1, va_list arg_ptr)
|
||||||
{
|
{
|
||||||
|
116
src/data.c
116
src/data.c
@ -339,6 +339,21 @@ _gpgme_data_release (gpgme_data_t dh)
|
|||||||
remove_from_property_table (dh, dh->propidx);
|
remove_from_property_table (dh, dh->propidx);
|
||||||
if (dh->file_name)
|
if (dh->file_name)
|
||||||
free (dh->file_name);
|
free (dh->file_name);
|
||||||
|
if (dh->inbound_buffer)
|
||||||
|
{
|
||||||
|
if (dh->sensitive)
|
||||||
|
_gpgme_wipememory (dh->inbound_buffer, dh->io_buffer_size);
|
||||||
|
free (dh->inbound_buffer);
|
||||||
|
}
|
||||||
|
if (dh->outbound_buffer)
|
||||||
|
{
|
||||||
|
if (dh->sensitive)
|
||||||
|
_gpgme_wipememory (dh->outbound_buffer, dh->io_buffer_size);
|
||||||
|
free (dh->outbound_buffer);
|
||||||
|
}
|
||||||
|
if (dh->sensitive)
|
||||||
|
_gpgme_wipememory (dh->outboundspace, BUFFER_SIZE);
|
||||||
|
|
||||||
free (dh);
|
free (dh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,11 +446,11 @@ gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
|
|||||||
/* For relative movement, we must take into account the actual
|
/* For relative movement, we must take into account the actual
|
||||||
position of the read counter. */
|
position of the read counter. */
|
||||||
if (whence == SEEK_CUR)
|
if (whence == SEEK_CUR)
|
||||||
offset -= dh->pending_len;
|
offset -= dh->outbound_pending;
|
||||||
|
|
||||||
offset = (*dh->cbs->seek) (dh, offset, whence);
|
offset = (*dh->cbs->seek) (dh, offset, whence);
|
||||||
if (offset >= 0)
|
if (offset >= 0)
|
||||||
dh->pending_len = 0;
|
dh->outbound_pending = 0;
|
||||||
|
|
||||||
return TRACE_SYSRES ((int)offset);
|
return TRACE_SYSRES ((int)offset);
|
||||||
}
|
}
|
||||||
@ -555,6 +570,28 @@ gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
|
|||||||
{
|
{
|
||||||
dh->size_hint= value? _gpgme_string_to_off (value) : 0;
|
dh->size_hint= value? _gpgme_string_to_off (value) : 0;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (name, "io-buffer-size"))
|
||||||
|
{
|
||||||
|
gpgme_off_t val;
|
||||||
|
|
||||||
|
/* We may set this only once. */
|
||||||
|
if (dh->io_buffer_size)
|
||||||
|
return gpg_error (GPG_ERR_CONFLICT);
|
||||||
|
|
||||||
|
val = value? _gpgme_string_to_off (value) : 0;
|
||||||
|
if (val > 1024*1024)
|
||||||
|
val = 1024*1024; /* Cap at 1MiB */
|
||||||
|
else if (val < BUFFER_SIZE)
|
||||||
|
val = 0; /* We can use the default buffer. */
|
||||||
|
|
||||||
|
/* Actual allocation happens as needed but we round it to a
|
||||||
|
* multiple of 1k. */
|
||||||
|
dh->io_buffer_size = ((val + 1023)/1024)*1024;
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "sensitive"))
|
||||||
|
{
|
||||||
|
dh->sensitive = (value && *value)? !!atoi (value) : 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return gpg_error (GPG_ERR_UNKNOWN_NAME);
|
return gpg_error (GPG_ERR_UNKNOWN_NAME);
|
||||||
|
|
||||||
@ -569,14 +606,35 @@ gpgme_error_t
|
|||||||
_gpgme_data_inbound_handler (void *opaque, int fd)
|
_gpgme_data_inbound_handler (void *opaque, int fd)
|
||||||
{
|
{
|
||||||
struct io_cb_data *data = (struct io_cb_data *) opaque;
|
struct io_cb_data *data = (struct io_cb_data *) opaque;
|
||||||
|
gpg_error_t err;
|
||||||
gpgme_data_t dh = (gpgme_data_t) data->handler_value;
|
gpgme_data_t dh = (gpgme_data_t) data->handler_value;
|
||||||
char buffer[BUFFER_SIZE];
|
char bufferspace[BUFFER_SIZE];
|
||||||
char *bufp = buffer;
|
char *buffer;
|
||||||
|
size_t buffer_size;
|
||||||
|
char *bufp;
|
||||||
gpgme_ssize_t buflen;
|
gpgme_ssize_t buflen;
|
||||||
TRACE_BEG (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
|
TRACE_BEG (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
|
||||||
"fd=%d", fd);
|
"fd=%d", fd);
|
||||||
|
|
||||||
buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
|
if (dh->io_buffer_size)
|
||||||
|
{
|
||||||
|
if (!dh->inbound_buffer)
|
||||||
|
{
|
||||||
|
dh->inbound_buffer = malloc (dh->io_buffer_size);
|
||||||
|
if (!dh->inbound_buffer)
|
||||||
|
return TRACE_ERR (gpg_error_from_syserror ());
|
||||||
|
}
|
||||||
|
buffer_size = dh->io_buffer_size;
|
||||||
|
buffer = dh->inbound_buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer_size = BUFFER_SIZE;
|
||||||
|
buffer = bufferspace;
|
||||||
|
}
|
||||||
|
bufp = buffer;
|
||||||
|
|
||||||
|
buflen = _gpgme_io_read (fd, buffer, buffer_size);
|
||||||
if (buflen < 0)
|
if (buflen < 0)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
if (buflen == 0)
|
if (buflen == 0)
|
||||||
@ -589,12 +647,21 @@ _gpgme_data_inbound_handler (void *opaque, int fd)
|
|||||||
{
|
{
|
||||||
gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
|
gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
|
||||||
if (amt == 0 || (amt < 0 && errno != EINTR))
|
if (amt == 0 || (amt < 0 && errno != EINTR))
|
||||||
return TRACE_ERR (gpg_error_from_syserror ());
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
bufp += amt;
|
bufp += amt;
|
||||||
buflen -= amt;
|
buflen -= amt;
|
||||||
}
|
}
|
||||||
while (buflen > 0);
|
while (buflen > 0);
|
||||||
return TRACE_ERR (0);
|
err = 0;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (dh->sensitive && buffer == bufferspace)
|
||||||
|
_gpgme_wipememory (bufferspace, BUFFER_SIZE);
|
||||||
|
|
||||||
|
return TRACE_ERR (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -603,13 +670,34 @@ _gpgme_data_outbound_handler (void *opaque, int fd)
|
|||||||
{
|
{
|
||||||
struct io_cb_data *data = (struct io_cb_data *) opaque;
|
struct io_cb_data *data = (struct io_cb_data *) opaque;
|
||||||
gpgme_data_t dh = (gpgme_data_t) data->handler_value;
|
gpgme_data_t dh = (gpgme_data_t) data->handler_value;
|
||||||
|
char *buffer;
|
||||||
|
size_t buffer_size;
|
||||||
gpgme_ssize_t nwritten;
|
gpgme_ssize_t nwritten;
|
||||||
TRACE_BEG (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
|
TRACE_BEG (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
|
||||||
"fd=%d", fd);
|
"fd=%d", fd);
|
||||||
|
|
||||||
if (!dh->pending_len)
|
if (dh->io_buffer_size)
|
||||||
{
|
{
|
||||||
gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
|
if (!dh->outbound_buffer)
|
||||||
|
{
|
||||||
|
dh->outbound_buffer = malloc (dh->io_buffer_size);
|
||||||
|
if (!dh->outbound_buffer)
|
||||||
|
return TRACE_ERR (gpg_error_from_syserror ());
|
||||||
|
dh->outbound_pending = 0;
|
||||||
|
}
|
||||||
|
buffer_size = dh->io_buffer_size;
|
||||||
|
buffer = dh->outbound_buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer_size = BUFFER_SIZE;
|
||||||
|
buffer = dh->outboundspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!dh->outbound_pending)
|
||||||
|
{
|
||||||
|
gpgme_ssize_t amt = gpgme_data_read (dh, buffer, buffer_size);
|
||||||
if (amt < 0)
|
if (amt < 0)
|
||||||
return TRACE_ERR (gpg_error_from_syserror ());
|
return TRACE_ERR (gpg_error_from_syserror ());
|
||||||
if (amt == 0)
|
if (amt == 0)
|
||||||
@ -617,10 +705,10 @@ _gpgme_data_outbound_handler (void *opaque, int fd)
|
|||||||
_gpgme_io_close (fd);
|
_gpgme_io_close (fd);
|
||||||
return TRACE_ERR (0);
|
return TRACE_ERR (0);
|
||||||
}
|
}
|
||||||
dh->pending_len = amt;
|
dh->outbound_pending = amt;
|
||||||
}
|
}
|
||||||
|
|
||||||
nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
|
nwritten = _gpgme_io_write (fd, buffer, dh->outbound_pending);
|
||||||
if (nwritten == -1 && errno == EAGAIN)
|
if (nwritten == -1 && errno == EAGAIN)
|
||||||
return TRACE_ERR (0);
|
return TRACE_ERR (0);
|
||||||
|
|
||||||
@ -637,9 +725,9 @@ _gpgme_data_outbound_handler (void *opaque, int fd)
|
|||||||
if (nwritten <= 0)
|
if (nwritten <= 0)
|
||||||
return TRACE_ERR (gpg_error_from_syserror ());
|
return TRACE_ERR (gpg_error_from_syserror ());
|
||||||
|
|
||||||
if (nwritten < dh->pending_len)
|
if (nwritten < dh->outbound_pending)
|
||||||
memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
|
memmove (buffer, buffer + nwritten, dh->outbound_pending - nwritten);
|
||||||
dh->pending_len -= nwritten;
|
dh->outbound_pending -= nwritten;
|
||||||
return TRACE_ERR (0);
|
return TRACE_ERR (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
src/data.h
53
src/data.h
@ -33,6 +33,22 @@
|
|||||||
|
|
||||||
#include "gpgme.h"
|
#include "gpgme.h"
|
||||||
|
|
||||||
|
/* Figure out the standard size for internal data buffers. */
|
||||||
|
#ifdef PIPE_BUF
|
||||||
|
# define BUFFER_SIZE PIPE_BUF
|
||||||
|
#else
|
||||||
|
# ifdef _POSIX_PIPE_BUF
|
||||||
|
# define BUFFER_SIZE _POSIX_PIPE_BUF
|
||||||
|
# else
|
||||||
|
# ifdef HAVE_W32_SYSTEM
|
||||||
|
# define BUFFER_SIZE 4096
|
||||||
|
# else
|
||||||
|
# define BUFFER_SIZE 512
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Read up to SIZE bytes into buffer BUFFER from the data object with
|
/* Read up to SIZE bytes into buffer BUFFER from the data object with
|
||||||
the handle DH. Return the number of characters read, 0 on EOF and
|
the handle DH. Return the number of characters read, 0 on EOF and
|
||||||
@ -76,28 +92,33 @@ struct gpgme_data
|
|||||||
gpgme_data_encoding_t encoding;
|
gpgme_data_encoding_t encoding;
|
||||||
unsigned int propidx; /* Index into the property table. */
|
unsigned int propidx; /* Index into the property table. */
|
||||||
|
|
||||||
#ifdef PIPE_BUF
|
|
||||||
#define BUFFER_SIZE PIPE_BUF
|
|
||||||
#else
|
|
||||||
#ifdef _POSIX_PIPE_BUF
|
|
||||||
#define BUFFER_SIZE _POSIX_PIPE_BUF
|
|
||||||
#else
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
#define BUFFER_SIZE 4096
|
|
||||||
#else
|
|
||||||
#define BUFFER_SIZE 512
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
char pending[BUFFER_SIZE];
|
|
||||||
int pending_len;
|
|
||||||
|
|
||||||
/* File name of the data object. */
|
/* File name of the data object. */
|
||||||
char *file_name;
|
char *file_name;
|
||||||
|
|
||||||
/* Hint on the to be expected total size of the data. */
|
/* Hint on the to be expected total size of the data. */
|
||||||
gpgme_off_t size_hint;
|
gpgme_off_t size_hint;
|
||||||
|
|
||||||
|
/* If no 0 the size of an allocated inbound or outpund buffers. The
|
||||||
|
* value is at least BUFFER_SIZE and capped at 1MiB. */
|
||||||
|
unsigned int io_buffer_size;
|
||||||
|
|
||||||
|
/* If not NULL a malloced buffer used for inbound data used instead
|
||||||
|
* of the handler's static buffer. Its size is io_buffer_size. */
|
||||||
|
char *inbound_buffer;
|
||||||
|
|
||||||
|
/* A default memory space for the outbound handler and the number of
|
||||||
|
* actual pending bytes. If outbound_buffer is not NULL, this is a
|
||||||
|
* malloced buffer used instead of the outboundspace. Its malloced
|
||||||
|
* size is io_buffer_size. */
|
||||||
|
char outboundspace[BUFFER_SIZE];
|
||||||
|
unsigned int outbound_pending;
|
||||||
|
char *outbound_buffer;
|
||||||
|
|
||||||
|
/* If set sensitive data is conveyed via the internal buffer. This
|
||||||
|
* flags overwrites the memory of the buffers with zero before they
|
||||||
|
* are released. */
|
||||||
|
unsigned int sensitive:1;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
/* For gpgme_data_new_from_fd. */
|
/* For gpgme_data_new_from_fd. */
|
||||||
|
@ -96,6 +96,9 @@ int _gpgme_ttyname_r (int fd, char *buf, size_t buflen);
|
|||||||
|
|
||||||
/*-- conversion.c --*/
|
/*-- conversion.c --*/
|
||||||
|
|
||||||
|
/* Make sure to to erase the memory (PTR,LEN). */
|
||||||
|
void _gpgme_wipememory (void *ptr, size_t len);
|
||||||
|
|
||||||
/* Concatenate the string S1 with all the following strings up to a
|
/* Concatenate the string S1 with all the following strings up to a
|
||||||
NULL. Returns a malloced buffer with the new string or NULL on a
|
NULL. Returns a malloced buffer with the new string or NULL on a
|
||||||
malloc error or if too many arguments are given. */
|
malloc error or if too many arguments are given. */
|
||||||
|
@ -89,6 +89,8 @@ show_usage (int ex)
|
|||||||
" --no-symkey-cache disable the use of that cache\n"
|
" --no-symkey-cache disable the use of that cache\n"
|
||||||
" --ignore-mdc-error allow decryption of legacy data\n"
|
" --ignore-mdc-error allow decryption of legacy data\n"
|
||||||
" --unwrap remove only the encryption layer\n"
|
" --unwrap remove only the encryption layer\n"
|
||||||
|
" --large-buffers use large I/O buffer\n"
|
||||||
|
" --sensitive mark data objects as sensitive\n"
|
||||||
" --diagnostics print diagnostics\n"
|
" --diagnostics print diagnostics\n"
|
||||||
, stderr);
|
, stderr);
|
||||||
exit (ex);
|
exit (ex);
|
||||||
@ -114,6 +116,8 @@ main (int argc, char **argv)
|
|||||||
int no_symkey_cache = 0;
|
int no_symkey_cache = 0;
|
||||||
int ignore_mdc_error = 0;
|
int ignore_mdc_error = 0;
|
||||||
int raw_output = 0;
|
int raw_output = 0;
|
||||||
|
int large_buffers = 0;
|
||||||
|
int sensitive = 0;
|
||||||
int diagnostics = 0;
|
int diagnostics = 0;
|
||||||
|
|
||||||
if (argc)
|
if (argc)
|
||||||
@ -185,6 +189,16 @@ main (int argc, char **argv)
|
|||||||
diagnostics = 1;
|
diagnostics = 1;
|
||||||
argc--; argv++;
|
argc--; argv++;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (*argv, "--large-buffers"))
|
||||||
|
{
|
||||||
|
large_buffers = 1;
|
||||||
|
argc--; argv++;
|
||||||
|
}
|
||||||
|
else if (!strcmp (*argv, "--sensitive"))
|
||||||
|
{
|
||||||
|
sensitive = 1;
|
||||||
|
argc--; argv++;
|
||||||
|
}
|
||||||
else if (!strcmp (*argv, "--unwrap"))
|
else if (!strcmp (*argv, "--unwrap"))
|
||||||
{
|
{
|
||||||
flags |= GPGME_DECRYPT_UNWRAP;
|
flags |= GPGME_DECRYPT_UNWRAP;
|
||||||
@ -288,6 +302,26 @@ main (int argc, char **argv)
|
|||||||
gpgme_strerror (err));
|
gpgme_strerror (err));
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
if (large_buffers)
|
||||||
|
{
|
||||||
|
err = gpgme_data_set_flag (out, "io-buffer-size", "1000000");
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
fprintf (stderr, PGM ": error setting io-buffer-size (out): %s\n",
|
||||||
|
gpgme_strerror (err));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sensitive)
|
||||||
|
{
|
||||||
|
err = gpgme_data_set_flag (out, "sensitive", "1");
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
fprintf (stderr, PGM ": error setting sensitive flag (out): %s\n",
|
||||||
|
gpgme_strerror (err));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = gpgme_op_decrypt_ext (ctx, flags, in, out);
|
err = gpgme_op_decrypt_ext (ctx, flags, in, out);
|
||||||
result = gpgme_op_decrypt_result (ctx);
|
result = gpgme_op_decrypt_result (ctx);
|
||||||
|
Loading…
Reference in New Issue
Block a user