diff --git a/NEWS b/NEWS
index 98cbc40a..d7a96af5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,11 @@
Noteworthy changes in version 1.14.1 (unreleased)
-------------------------------------------------
-* New function gpgme_op_setexpire to make changing the expiration
- easier (requires GnuPG 2.1.22). [#4999]
+ * New function gpgme_op_setexpire to make changing the expiration
+ easier (requires GnuPG 2.1.22). [#4999]
+
+ * New function gpgme_op_revsig to revoke key signatures (requires
+ GnuPG 2.2.24). [#5094]
* cpp: Support for set expire operations in the C++ bindings. [#5003]
@@ -15,6 +18,9 @@ Noteworthy changes in version 1.14.1 (unreleased)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_op_setexpire_start NEW.
gpgme_op_setexpire NEW.
+ gpgme_op_revsig_start NEW.
+ gpgme_op_revsig NEW.
+ GPGME_REVSIG_LFSEP NEW.
cpp: Context::setExpire NEW.
cpp: Context::startSetExpire NEW.
cpp: EngineInfo::Version::operator<= NEW.
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index d3c64ee7..99a228b3 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -4725,6 +4725,71 @@ be completed by calling @code{gpgme_wait} on the context.
@end deftypefun
+@c
+@c gpgme_op_revsig
+@c
+@deftypefun gpgme_error_t gpgme_op_revsig @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{key}}, @
+ @w{gpgme_key_t @var{signing_key}}, @
+ @w{const char *@var{userid}}, @
+ @w{unsigned int @var{flags}});
+
+@since{1.14.1}
+
+The function @code{gpgme_op_revsig} revokes key signatures of the
+public key @var{key} made with the key @var{signing_key}. This
+function requires at least version 2.2.24 of GnuPG.
+
+@var{key} specifies the key to operate on.
+
+@var{signing_key} specifies the key whose signatures shall be revoked.
+
+@var{userid} selects the user ID or user IDs whose signatures shall
+be revoked. If @var{userid} is set to @code{NULL} the signatures
+on all user IDs are revoked. The user ID must be given verbatim
+because the engine does an exact and case sensitive match. Thus the
+@code{uid} field from the user ID object (@code{gpgme_user_id_t}) is to
+be used. To select more than one user ID put them all into one string
+separated by linefeeds characters (@code{\n}) and set the flag
+@code{GPGME_REVSIG_LFSEP}.
+
+@var{flags} can be set to the bit-wise OR of the following flags:
+
+@table @code
+@item GPGME_REVSIG_LFSEP
+@since{1.14.1}
+
+Although linefeeds are uncommon in user IDs this flag is required to
+explicitly declare that @var{userid} may contain several linefeed
+separated user IDs.
+
+@end table
+
+The function returns zero on success, @code{GPG_ERR_NOT_SUPPORTED} if
+the engine does not support the command, or a bunch of other error
+codes.
+
+@end deftypefun
+
+
+@deftypefun gpgme_error_t gpgme_op_revsig_start @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{key}}, @
+ @w{gpgme_key_t @var{signing_key}}, @
+ @w{const char *@var{userid}}, @
+ @w{unsigned int @var{flags}});
+
+@since{1.14.1}
+
+The function @code{gpgme_op_revsig_start} initiates a
+@code{gpgme_op_revsig} operation; see there for details. It must
+be completed by calling @code{gpgme_wait} on the context.
+@xref{Waiting For Completion}.
+
+@end deftypefun
+
+
@c
@c EXPORTING KEYS
@c
diff --git a/src/Makefile.am b/src/Makefile.am
index 1061995c..35add9c8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -79,6 +79,7 @@ main_sources = \
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
sign.c passphrase.c progress.c \
key.c keylist.c keysign.c trust-item.c trustlist.c tofupolicy.c \
+ revsig.c \
import.c export.c genkey.c delete.c edit.c getauditlog.c \
setexpire.c \
opassuan.c passwd.c spawn.c assuan-support.c \
diff --git a/src/context.h b/src/context.h
index 7f745a52..3ed38188 100644
--- a/src/context.h
+++ b/src/context.h
@@ -39,7 +39,7 @@ typedef enum
OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN, OPDATA_TOFU_POLICY,
- OPDATA_QUERY_SWDB, OPDATA_SETEXPIRE
+ OPDATA_QUERY_SWDB, OPDATA_SETEXPIRE, OPDATA_REVSIG
} ctx_op_data_id_t;
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index eb6d2a8e..ab9d05a9 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -833,6 +833,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
NULL, /* keylist_ext */
NULL, /* keylist_data */
NULL, /* keysign */
+ NULL, /* revsig */
NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* verify */
diff --git a/src/engine-backend.h b/src/engine-backend.h
index 791dd3f9..8f90b6c7 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -108,6 +108,9 @@ struct engine_ops
gpgme_key_t key, const char *userid,
unsigned long expires, unsigned int flags,
gpgme_ctx_t ctx);
+ gpgme_error_t (*revsig) (void *engine,
+ gpgme_key_t key, gpgme_key_t signing_key,
+ const char *userid, unsigned int flags);
gpgme_error_t (*tofu_policy) (void *engine,
gpgme_key_t key,
gpgme_tofu_policy_t policy);
diff --git a/src/engine-g13.c b/src/engine-g13.c
index 82f26305..3c111496 100644
--- a/src/engine-g13.c
+++ b/src/engine-g13.c
@@ -804,6 +804,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
NULL, /* keylist_ext */
NULL, /* keylist_data */
NULL, /* keysign */
+ NULL, /* revsig */
NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* verify */
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index 8832572a..02a10ecb 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -3210,6 +3210,52 @@ gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
}
+static gpgme_error_t
+gpg_revsig (void *engine, gpgme_key_t key, gpgme_key_t signing_key,
+ const char *userid, unsigned int flags)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+ const char *s;
+
+ if (!key || !key->fpr)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (!have_gpg_version (gpg, "2.2.24"))
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ err = add_arg (gpg, "--quick-revoke-sig");
+
+ if (!err)
+ err = add_arg (gpg, "--");
+
+ if (!err)
+ err = add_arg (gpg, key->fpr);
+
+ if (!err)
+ err = add_arg (gpg, signing_key->fpr);
+
+ if (!err && userid)
+ {
+ if ((flags & GPGME_REVSIG_LFSEP))
+ {
+ for (; !err && (s = strchr (userid, '\n')); userid = s + 1)
+ if ((s - userid))
+ err = add_arg_len (gpg, "=", userid, s - userid);
+ if (!err && *userid)
+ err = add_arg_pfx (gpg, "=", userid);
+ }
+ else
+ err = add_arg_pfx (gpg, "=", userid);
+ }
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
static gpgme_error_t
gpg_tofu_policy (void *engine, gpgme_key_t key, gpgme_tofu_policy_t policy)
{
@@ -3513,6 +3559,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_keylist_ext,
gpg_keylist_data,
gpg_keysign,
+ gpg_revsig,
gpg_tofu_policy, /* tofu_policy */
gpg_sign,
gpg_verify,
diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
index fba8f23b..28f91158 100644
--- a/src/engine-gpgconf.c
+++ b/src/engine-gpgconf.c
@@ -1302,6 +1302,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
NULL, /* keylist_ext */
NULL, /* keylist_data */
NULL, /* keysign */
+ NULL, /* revsig */
NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* verify */
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index 37022421..d5f0d7a9 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -2322,6 +2322,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
gpgsm_keylist_ext,
NULL, /* keylist_data */
NULL, /* keysign */
+ NULL, /* revsig */
NULL, /* tofu_policy */
gpgsm_sign,
gpgsm_verify,
diff --git a/src/engine-spawn.c b/src/engine-spawn.c
index 4025b83a..368280f3 100644
--- a/src/engine-spawn.c
+++ b/src/engine-spawn.c
@@ -464,6 +464,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
NULL, /* keylist_ext */
NULL, /* keylist_data */
NULL, /* keysign */
+ NULL, /* revsig */
NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* verify */
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index 3693dc3b..9fce1de4 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -1435,6 +1435,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
NULL, /* keylist_ext */
NULL, /* keylist_data */
NULL, /* keysign */
+ NULL, /* revsig */
NULL, /* tofu_policy */
uiserver_sign,
uiserver_verify,
diff --git a/src/engine.c b/src/engine.c
index aeb30c67..8280c520 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -824,6 +824,20 @@ _gpgme_engine_op_keysign (engine_t engine, gpgme_key_t key, const char *userid,
}
+gpgme_error_t
+_gpgme_engine_op_revsig (engine_t engine, gpgme_key_t key, gpgme_key_t signing_key,
+ const char *userid, unsigned int flags)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->revsig)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->revsig) (engine->engine, key, signing_key, userid, flags);
+}
+
+
gpgme_error_t
_gpgme_engine_op_tofu_policy (engine_t engine,
gpgme_key_t key, gpgme_tofu_policy_t policy)
diff --git a/src/engine.h b/src/engine.h
index 74082851..d7ff542c 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -131,6 +131,11 @@ gpgme_error_t _gpgme_engine_op_keysign (engine_t engine,
unsigned long expires,
unsigned int flags,
gpgme_ctx_t ctx);
+gpgme_error_t _gpgme_engine_op_revsig (engine_t engine,
+ gpgme_key_t key,
+ gpgme_key_t signing_key,
+ const char *userid,
+ unsigned int flags);
gpgme_error_t _gpgme_engine_op_tofu_policy (engine_t engine,
gpgme_key_t key,
gpgme_tofu_policy_t policy);
diff --git a/src/gpgme.def b/src/gpgme.def
index 6666a1c7..6644caef 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -277,5 +277,8 @@ EXPORTS
gpgme_op_setexpire @205
gpgme_op_setexpire_start @206
+ gpgme_op_revsig @207
+ gpgme_op_revsig_start @208
+
; END
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index d1bc30de..ec2b3b0d 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1919,6 +1919,20 @@ gpgme_error_t gpgme_op_keysign (gpgme_ctx_t ctx,
unsigned int flags);
+/* Flags for the signature revoking functions. */
+#define GPGME_REVSIG_LFSEP (1 << 8) /* Indicate LF separated user ids. */
+
+/* Revoke the signatures made with SIGNING_KEY on the USERID(s) of KEY. */
+gpgme_error_t gpgme_op_revsig_start (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ gpgme_key_t signing_key,
+ const char *userid,
+ unsigned int flags);
+gpgme_error_t gpgme_op_revsig (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ gpgme_key_t signing_key,
+ const char *userid,
+ unsigned int flags);
/*
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index a740b72d..8e86e4e4 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -276,6 +276,9 @@ GPGME_1.0 {
gpgme_op_setexpire;
gpgme_op_setexpire_start;
+ gpgme_op_revsig;
+ gpgme_op_revsig_start;
+
local:
*;
diff --git a/src/revsig.c b/src/revsig.c
new file mode 100644
index 00000000..8c61f730
--- /dev/null
+++ b/src/revsig.c
@@ -0,0 +1,203 @@
+/* revsig.c - Revoke signature helpers.
+ * Copyright (C) 2020 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see .
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#if HAVE_CONFIG_H
+#include
+#endif
+#include
+
+#include "gpgme.h"
+#include "debug.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ /* The error code from a FAILURE status line or 0. */
+ gpg_error_t failure_code;
+
+ /* The error code from certain ERROR status lines or 0. */
+ gpg_error_t error_code;
+
+} *op_data_t;
+
+
+/* Parse an error status line. Return the error location and the
+ error code. The function may modify ARGS. */
+static char *
+parse_error (char *args, gpg_error_t *r_err)
+{
+ char *where = strchr (args, ' ');
+ char *which;
+
+ if (where)
+ {
+ *where = '\0';
+ which = where + 1;
+
+ where = strchr (which, ' ');
+ if (where)
+ *where = '\0';
+
+ where = args;
+ }
+ else
+ {
+ *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
+ return NULL;
+ }
+
+ *r_err = atoi (which);
+
+ return where;
+}
+
+
+static gpgme_error_t
+revsig_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ char *loc;
+
+ /* Pipe the status code through the progress status handler. */
+ err = _gpgme_progress_status_handler (ctx, code, args);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_REVSIG, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_ERROR:
+ loc = parse_error (args, &err);
+ if (!loc)
+ return err;
+ if (!opd->error_code)
+ opd->error_code = err;
+ break;
+
+ case GPGME_STATUS_FAILURE:
+ opd->failure_code = _gpgme_parse_failure (args);
+ break;
+
+ case GPGME_STATUS_EOF:
+ if (opd->error_code)
+ return opd->error_code;
+ else if (opd->failure_code)
+ return opd->failure_code;
+ break;
+
+ case GPGME_STATUS_INQUIRE_MAXLEN:
+ if (ctx->status_cb && !ctx->full_status)
+ {
+ err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
+ if (err)
+ return err;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* Revoke the signature(s) on USERID of KEY made with SIGNING_KEY.
+ * If USERID is NULL, revoke signatures on all user ids. To put several
+ * user ids into USERID, separate them by LF and set the flag
+ * GPGME_REVSIG_LFSEP. */
+static gpgme_error_t
+revsig_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_key_t key, gpgme_key_t signing_key,
+ const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ if (!ctx)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
+ return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+ if (!key)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_REVSIG, &hook, sizeof (*opd),
+ NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, revsig_status_handler, ctx);
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx);
+ if (err)
+ return err;
+ }
+
+ return _gpgme_engine_op_revsig (ctx->engine, key, signing_key, userid, flags);
+}
+
+
+gpgme_error_t
+gpgme_op_revsig_start (gpgme_ctx_t ctx, gpgme_key_t key, gpgme_key_t signing_key,
+ const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG (DEBUG_CTX, "gpgme_op_revsig_start", ctx,
+ "key=%p, uid='%s' flags=0x%x", key, userid, flags);
+
+ err = revsig_start (ctx, 0, key, signing_key, userid, flags);
+ return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_revsig (gpgme_ctx_t ctx, gpgme_key_t key, gpgme_key_t signing_key,
+ const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG (DEBUG_CTX, "gpgme_op_revsig", ctx,
+ "key=%p, uid='%s' flags=0x%x", key, userid, flags);
+
+ err = revsig_start (ctx, 1, key, signing_key, userid, flags);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
diff --git a/tests/run-keysign.c b/tests/run-keysign.c
index 83130dd0..57488a47 100644
--- a/tests/run-keysign.c
+++ b/tests/run-keysign.c
@@ -1,4 +1,4 @@
-/* run-keysign.c - Test tool to sign a key
+/* run-keysign.c - Test tool to sign a key and to revoke a key signature
* Copyright (C) 2016 g10 Code GmbH
*
* This file is part of GPGME.
@@ -77,10 +77,11 @@ show_usage (int ex)
" --verbose run in verbose mode\n"
" --status print status lines from the backend\n"
" --loopback use a loopback pinentry\n"
- " --signer NAME use key NAME for signing\n"
+ " --signer NAME use key NAME for signing/revoking\n"
" --local create a local signature\n"
" --noexpire force no expiration\n"
" --expire EPOCH expire the signature at EPOCH\n"
+ " --revoke revoke the signature(s)\n"
, stderr);
exit (ex);
}
@@ -97,9 +98,12 @@ main (int argc, char **argv)
int print_status = 0;
int use_loopback = 0;
const char *userid;
- unsigned int flags = 0;
+ unsigned int keysign_flags = 0;
unsigned long expire = 0;
+ int revoke = 0;
+ unsigned int revoke_flags = 0;
gpgme_key_t thekey;
+ gpgme_key_t signing_key = NULL;
int i;
size_t n;
char *userid_buffer = NULL;
@@ -142,12 +146,12 @@ main (int argc, char **argv)
}
else if (!strcmp (*argv, "--local"))
{
- flags |= GPGME_KEYSIGN_LOCAL;
+ keysign_flags |= GPGME_KEYSIGN_LOCAL;
argc--; argv++;
}
else if (!strcmp (*argv, "--noexpire"))
{
- flags |= GPGME_KEYSIGN_NOEXPIRE;
+ keysign_flags |= GPGME_KEYSIGN_NOEXPIRE;
argc--; argv++;
}
else if (!strcmp (*argv, "--expire"))
@@ -158,10 +162,21 @@ main (int argc, char **argv)
expire = parse_expire_string (*argv);
argc--; argv++;
}
+ else if (!strcmp (*argv, "--revoke"))
+ {
+ revoke = 1;
+ argc--; argv++;
+ }
else if (!strncmp (*argv, "--", 2))
show_usage (1);
}
+ if (revoke && !signer_string)
+ {
+ fprintf (stderr, PGM ": please specify the signer key\n");
+ exit (1);
+ }
+
if (!argc)
show_usage (1);
userid = argv[0];
@@ -186,23 +201,20 @@ main (int argc, char **argv)
if (signer_string)
{
- gpgme_key_t akey;
-
- err = gpgme_get_key (ctx, signer_string, &akey, 1);
+ err = gpgme_get_key (ctx, signer_string, &signing_key, 1);
if (err)
{
fprintf (stderr, PGM ": error getting signer key '%s': %s\n",
signer_string, gpg_strerror (err));
exit (1);
}
- err = gpgme_signers_add (ctx, akey);
+ err = gpgme_signers_add (ctx, signing_key);
if (err)
{
fprintf (stderr, PGM ": error adding signer key: %s\n",
gpg_strerror (err));
exit (1);
}
- gpgme_key_unref (akey);
}
@@ -234,7 +246,8 @@ main (int argc, char **argv)
strcat (userid_buffer, "\n");
}
userid = userid_buffer;
- flags |= GPGME_KEYSIGN_LFSEP;
+ keysign_flags |= GPGME_KEYSIGN_LFSEP;
+ revoke_flags |= GPGME_REVSIG_LFSEP;
}
else if (argc)
{
@@ -247,15 +260,29 @@ main (int argc, char **argv)
userid = NULL;
}
- err = gpgme_op_keysign (ctx, thekey, userid, expire, flags);
- if (err)
+ if (revoke)
{
- fprintf (stderr, PGM ": gpgme_op_adduid failed: %s\n",
- gpg_strerror (err));
- exit (1);
+ err = gpgme_op_revsig (ctx, thekey, signing_key, userid, revoke_flags);
+ if (err)
+ {
+ fprintf (stderr, PGM ": gpgme_op_revsig failed: %s\n",
+ gpg_strerror (err));
+ exit (1);
+ }
+ }
+ else
+ {
+ err = gpgme_op_keysign (ctx, thekey, userid, expire, keysign_flags);
+ if (err)
+ {
+ fprintf (stderr, PGM ": gpgme_op_keysign failed: %s\n",
+ gpg_strerror (err));
+ exit (1);
+ }
}
free (userid_buffer);
+ gpgme_key_unref (signing_key);
gpgme_key_unref (thekey);
gpgme_release (ctx);
return 0;