summaryrefslogtreecommitdiff
path: root/src/engine-gpgsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine-gpgsm.c')
-rw-r--r--src/engine-gpgsm.c133
1 files changed, 113 insertions, 20 deletions
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index 9ab0555..24b142c 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -68,6 +68,7 @@ typedef struct
struct engine_gpgsm
{
assuan_context_t assuan_ctx;
+ char *version;
int lc_ctype_set;
int lc_messages_set;
@@ -113,6 +114,10 @@ struct engine_gpgsm
/* Memory data containing diagnostics (--logger-fd) of gpgsm */
gpgme_data_t diagnostics;
+
+ struct {
+ unsigned int offline : 1;
+ } flags;
};
typedef struct engine_gpgsm *engine_gpgsm_t;
@@ -122,6 +127,13 @@ static void gpgsm_io_event (void *engine,
gpgme_event_io_t type, void *type_data);
+/* Return true if the engine's version is at least VERSION. */
+static int
+have_gpgsm_version (engine_gpgsm_t gpgsm, const char *version)
+{
+ return _gpgme_compare_versions (gpgsm->version, version);
+}
+
static char *
gpgsm_get_version (const char *file_name)
@@ -254,6 +266,9 @@ gpgsm_release (void *engine)
gpgsm_cancel (engine);
+ if (gpgsm->version)
+ free (gpgsm->version);
+
gpgme_data_release (gpgsm->diagnostics);
free (gpgsm->colon.attic.line);
@@ -281,12 +296,20 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir,
char *optstr;
unsigned int connect_flags;
- (void)version; /* Not yet used. */
-
gpgsm = calloc (1, sizeof *gpgsm);
if (!gpgsm)
return gpg_error_from_syserror ();
+ if (version)
+ {
+ gpgsm->version = strdup (version);
+ if (!gpgsm->version)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ }
+
gpgsm->status_cb.fd = -1;
gpgsm->status_cb.dir = 1;
gpgsm->status_cb.tag = 0;
@@ -601,6 +624,8 @@ gpgsm_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
}
else
*gpgsm->request_origin = 0;
+
+ gpgsm->flags.offline = (ctx->offline && have_gpgsm_version (gpgsm, "2.1.6"));
}
@@ -1163,6 +1188,12 @@ start (engine_gpgsm_t gpgsm, const char *command)
return err;
}
+ gpgsm_assuan_simple_command (gpgsm,
+ gpgsm->flags.offline ?
+ "OPTION offline=1":
+ "OPTION offline=0" ,
+ NULL, NULL);
+
/* We need to know the fd used by assuan for reads. We do this by
using the assumption that the first returned fd from
assuan_get_active_fds() is always this one. */
@@ -1224,7 +1255,7 @@ gpgsm_reset (void *engine)
/* IF we have an active connection we must send a reset because we
need to reset the list of signers. Note that RESET does not
- reset OPTION commands. */
+ reset all OPTION commands. */
return (gpgsm->assuan_ctx
? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
: 0);
@@ -1232,6 +1263,38 @@ gpgsm_reset (void *engine)
#endif
+/* Send the input-size-hint option. Note that we need to send it
+ * always so that we don't actually use a wrong hint from the last
+ * command. */
+static gpgme_error_t
+send_input_size_hint (engine_gpgsm_t gpgsm, gpgme_data_t data)
+{
+ gpg_error_t err;
+ uint64_t value;
+ char numbuf[50]; /* Large enough for even 2^128 in base-10. */
+ char cmd[100];
+ char *p;
+
+ value = _gpgme_data_get_size_hint (data);
+ if (!value)
+ value = 0;
+
+ p = numbuf + sizeof numbuf;
+ *--p = 0;
+ do
+ {
+ *--p = '0' + (value % 10);
+ value /= 10;
+ }
+ while (value);
+
+ snprintf (cmd, sizeof cmd, "OPTION input-size-hint=%s", p);
+ err = gpgsm_assuan_simple_command (gpgsm, cmd, NULL, NULL);
+ if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
+ err = 0; /* Ignore error from older gpgsm versions. */
+ return err;
+}
+
static gpgme_error_t
gpgsm_decrypt (void *engine,
@@ -1256,6 +1319,10 @@ gpgsm_decrypt (void *engine,
if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);
+ err = send_input_size_hint (gpgsm, ciph);
+ if (err)
+ return err;
+
gpgsm->input_cb.data = ciph;
err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
if (err)
@@ -1469,6 +1536,9 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
if (!recp && !recpstring) /* Symmetric only */
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ if (flags & GPGME_ENCRYPT_ARCHIVE)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
{
err = gpgsm_assuan_simple_command (gpgsm,
@@ -1477,6 +1547,21 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
return err;
}
+ if ((flags & GPGME_ENCRYPT_ALWAYS_TRUST))
+ {
+ /* Note that a RESET and the actual operation resets the
+ * always-trust option. To support older gnupg versions we
+ * ignore the unknown option error. */
+ err = gpgsm_assuan_simple_command (gpgsm,
+ "OPTION always-trust", NULL, NULL);
+ if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION)
+ return err;
+ }
+
+ err = send_input_size_hint (gpgsm, plain);
+ if (err)
+ return err;
+
gpgsm->input_cb.data = plain;
err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
if (err)
@@ -1817,7 +1902,7 @@ gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray,
static gpgme_error_t
gpgsm_keylist (void *engine, const char *pattern, int secret_only,
- gpgme_keylist_mode_t mode, int engine_flags)
+ gpgme_keylist_mode_t mode)
{
engine_gpgsm_t gpgsm = engine;
char *line;
@@ -1873,12 +1958,6 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only,
"OPTION with-secret=1":
"OPTION with-secret=0" ,
NULL, NULL);
- gpgsm_assuan_simple_command (gpgsm,
- (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
- "OPTION offline=1":
- "OPTION offline=0" ,
- NULL, NULL);
-
/* Length is "LISTSECRETKEYS " + p + '\0'. */
line = malloc (15 + strlen (pattern) + 1);
@@ -1908,7 +1987,7 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only,
static gpgme_error_t
gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
- int reserved, gpgme_keylist_mode_t mode, int engine_flags)
+ int reserved, gpgme_keylist_mode_t mode)
{
engine_gpgsm_t gpgsm = engine;
char *line;
@@ -1948,11 +2027,6 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
"OPTION with-secret=1":
"OPTION with-secret=0" ,
NULL, NULL);
- gpgsm_assuan_simple_command (gpgsm,
- (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
- "OPTION offline=1":
- "OPTION offline=0" ,
- NULL, NULL);
if (pattern && *pattern)
{
@@ -2040,7 +2114,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
static gpgme_error_t
gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
- gpgme_sig_mode_t mode, int use_armor, int use_textmode,
+ gpgme_sig_mode_t flags, int use_armor, int use_textmode,
int include_certs, gpgme_ctx_t ctx /* FIXME */)
{
engine_gpgsm_t gpgsm = engine;
@@ -2054,6 +2128,9 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);
+ if (flags & (GPGME_SIG_MODE_CLEAR | GPGME_SIG_MODE_ARCHIVE))
+ return gpg_error (GPG_ERR_INV_VALUE);
+
/* FIXME: This does not work as RESET does not reset it so we can't
revert back to default. */
if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
@@ -2090,6 +2167,10 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
return err;
}
+ err = send_input_size_hint (gpgsm, in);
+ if (err)
+ return err;
+
gpgsm->input_cb.data = in;
err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
if (err)
@@ -2102,15 +2183,16 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
gpgsm_clear_fd (gpgsm, MESSAGE_FD);
gpgsm->inline_data = NULL;
- err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
+ err = start (gpgsm, (flags & GPGME_SIG_MODE_DETACH)
? "SIGN --detached" : "SIGN");
return err;
}
static gpgme_error_t
-gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
- gpgme_data_t plaintext, gpgme_ctx_t ctx)
+gpgsm_verify (void *engine, gpgme_verify_flags_t flags, gpgme_data_t sig,
+ gpgme_data_t signed_text, gpgme_data_t plaintext,
+ gpgme_ctx_t ctx)
{
engine_gpgsm_t gpgsm = engine;
gpgme_error_t err;
@@ -2120,6 +2202,9 @@ gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);
+ if (flags & GPGME_VERIFY_ARCHIVE)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
gpgsm->input_cb.data = sig;
err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
if (err)
@@ -2127,6 +2212,10 @@ gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
if (!signed_text)
{
/* Normal or cleartext signature. */
+ err = send_input_size_hint (gpgsm, sig);
+ if (err)
+ return err;
+
if (plaintext)
{
gpgsm->output_cb.data = plaintext;
@@ -2142,6 +2231,10 @@ gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
else
{
/* Detached signature. */
+ err = send_input_size_hint (gpgsm, signed_text);
+ if (err)
+ return err;
+
gpgsm->message_cb.data = signed_text;
err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
gpgsm_clear_fd (gpgsm, OUTPUT_FD);