summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--doc/gpgme.texi75
-rw-r--r--src/engine-assuan.c1
-rw-r--r--src/engine-backend.h3
-rw-r--r--src/engine-g13.c1
-rw-r--r--src/engine-gpg.c54
-rw-r--r--src/engine-gpgconf.c1
-rw-r--r--src/engine-gpgsm.c1
-rw-r--r--src/engine-spawn.c1
-rw-r--r--src/engine-uiserver.c1
-rw-r--r--src/engine.c14
-rw-r--r--src/engine.h5
-rw-r--r--src/genkey.c52
-rw-r--r--src/gpgme.def3
-rw-r--r--src/gpgme.h.in7
-rw-r--r--src/libgpgme.vers3
-rw-r--r--tests/run-genkey.c79
17 files changed, 308 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index ce5d50d9..a1626202 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,15 @@
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]
+
+ * Interface changes relative to the 1.14.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ gpgme_op_setexpire_start NEW.
+ gpgme_op_setexpire NEW.
+
+
Noteworthy changes in version 1.14.0 (2020-07-16)
-------------------------------------------------
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index 6c1d0622..d3c64ee7 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -4016,6 +4016,81 @@ The function @code{gpgme_key_unref} releases a reference for the key
and all resources associated to it will be released.
@end deftypefun
+@c
+@c gpgme_op_setexpire
+@c
+@deftypefun gpgme_error_t gpgme_op_setexpire @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{key}}, @
+ @w{unsigned long @var{expires}}, @
+ @w{const char *@var{subfprs}}, @
+ @w{unsigned int @var{reserved}});
+
+@since{1.14.1}
+
+The function @code{gpgme_op_setexpire} sets the expiration time of
+the key @var{key} or of the specified subkeys.
+This function requires at least version 2.1.22 of GnuPG.
+
+@var{key} specifies the key to operate on.
+
+@var{expires} specifies the expiration time in seconds from now.
+To be similar to other usages where expiration times are provided
+in unsigned long this is similar to the key creation date
+and so it is in seconds from NOW.
+
+The common case is to use 0 to not set an expiration time.
+Note that this parameter takes an unsigned long value and not
+a @code{time_t} to avoid problems on systems which use a signed
+32 bit @code{time_t}. Note further that the OpenPGP protocol
+uses 32 bit values for timestamps and thus can
+only encode dates up to the year 2106.
+
+@var{subfprs} selects the subkey(s) for which the expiration time
+should be set. If @var{subfprs} is set to @code{NULL}, then the
+expiration time of the primary key is set. If @var{subfprs} is
+an asterisk (@code{*}), then the expiration times of all non-revoked
+and not yet expired subkeys are set. To select more than one subkey
+put all subkey fingerprints into one string separated by linefeeds
+characters (@code{\n}).
+
+@var{reserved} is reserved for later use and must be @code{0}.
+
+@end deftypefun
+
+
+@deftypefun gpgme_error_t gpgme_op_setexpire_start @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{key}}, @
+ @w{unsigned long @var{expires}}, @
+ @w{const char *@var{subfprs}}, @
+ @w{unsigned int @var{flags}});
+
+@since{1.14.1}
+
+The function @code{gpgme_op_setexpire_start} initiates a
+@code{gpgme_op_setexpire} operation; see there for details. It must
+be completed by calling @code{gpgme_wait} on the context.
+@xref{Waiting For Completion}.
+
+@end deftypefun
+
+
+@deftypefun gpgme_error_t gpgme_op_revuid_start @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{key}}, @
+ @w{const char *@var{userid}}, @
+ @w{unsigned int @var{flags}});
+
+@since{1.14.1}
+
+The function @code{gpgme_op_setexpire_start} initiates a
+@code{gpgme_op_setexpire} operation; see there for details. It must
+be completed by calling @code{gpgme_wait} on the context.
+@xref{Waiting For Completion}.
+
+@end deftypefun
+
@node Generating Keys
@subsection Generating Keys
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index a40328f7..b51c17e3 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -828,6 +828,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
NULL, /* sign */
NULL, /* verify */
NULL, /* getauditlog */
+ NULL, /* setexpire */
llass_transact, /* opassuan_transact */
NULL, /* conf_load */
NULL, /* conf_save */
diff --git a/src/engine-backend.h b/src/engine-backend.h
index c8bfad96..791dd3f9 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -120,6 +120,9 @@ struct engine_ops
gpgme_ctx_t ctx);
gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output,
unsigned int flags);
+ gpgme_error_t (*setexpire) (void *engine, gpgme_key_t key,
+ unsigned long expires, const char *subfprs,
+ unsigned int reserved);
gpgme_error_t (*opassuan_transact) (void *engine,
const char *command,
gpgme_assuan_data_cb_t data_cb,
diff --git a/src/engine-g13.c b/src/engine-g13.c
index 45f6c94b..82f26305 100644
--- a/src/engine-g13.c
+++ b/src/engine-g13.c
@@ -808,6 +808,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
NULL, /* sign */
NULL, /* verify */
NULL, /* getauditlog */
+ NULL, /* setexpire */
g13_transact,
NULL, /* conf_load */
NULL, /* conf_save */
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index af2533d8..8832572a 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -3426,6 +3426,59 @@ gpg_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
#undef MYBUFLEN
}
+static gpgme_error_t
+gpg_setexpire (void *engine, gpgme_key_t key, unsigned long expires,
+ const char *subfprs, unsigned int reserved)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+ const char *s;
+
+ if (reserved)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!key || !key->fpr)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (!have_gpg_version (gpg, "2.1.22"))
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ err = add_arg (gpg, "--quick-set-expire");
+
+ if (!err)
+ err = add_arg (gpg, "--");
+
+ if (!err)
+ err = add_arg (gpg, key->fpr);
+
+ if (!err)
+ {
+ char tmpbuf[8+20];
+ snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
+ err = add_arg (gpg, tmpbuf);
+ }
+
+ if (!err && subfprs)
+ {
+ for (; !err && (s = strchr (subfprs, '\n')); subfprs = s + 1)
+ {
+ if ((s - subfprs))
+ {
+ err = add_arg_len (gpg, NULL, subfprs, s - subfprs);
+ }
+ }
+ if (!err && *subfprs)
+ {
+ err = add_arg (gpg, subfprs);
+ }
+ }
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
struct engine_ops _gpgme_engine_ops_gpg =
@@ -3464,6 +3517,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_sign,
gpg_verify,
gpg_getauditlog,
+ gpg_setexpire,
NULL, /* opassuan_transact */
NULL, /* conf_load */
NULL, /* conf_save */
diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
index d4465e97..fba8f23b 100644
--- a/src/engine-gpgconf.c
+++ b/src/engine-gpgconf.c
@@ -1306,6 +1306,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
NULL, /* sign */
NULL, /* verify */
NULL, /* getauditlog */
+ NULL, /* setexpire */
NULL, /* opassuan_transact */
gpgconf_conf_load,
gpgconf_conf_save,
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index 671b3857..c92320e1 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -2326,6 +2326,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
gpgsm_sign,
gpgsm_verify,
gpgsm_getauditlog,
+ NULL, /* setexpire */
NULL, /* opassuan_transact */
NULL, /* conf_load */
NULL, /* conf_save */
diff --git a/src/engine-spawn.c b/src/engine-spawn.c
index 0eeaeb1f..4025b83a 100644
--- a/src/engine-spawn.c
+++ b/src/engine-spawn.c
@@ -468,6 +468,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
NULL, /* sign */
NULL, /* verify */
NULL, /* getauditlog */
+ NULL, /* setexpire */
NULL, /* opassuan_transact */
NULL, /* conf_load */
NULL, /* conf_save */
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index c908ad7f..3693dc3b 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -1439,6 +1439,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
uiserver_sign,
uiserver_verify,
NULL, /* getauditlog */
+ NULL, /* setexpire */
NULL, /* opassuan_transact */
NULL, /* conf_load */
NULL, /* conf_save */
diff --git a/src/engine.c b/src/engine.c
index ded2f4d1..aeb30c67 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -1128,3 +1128,17 @@ _gpgme_engine_op_spawn (engine_t engine,
return (*engine->ops->opspawn) (engine->engine, file, argv,
datain, dataout, dataerr, flags);
}
+
+gpgme_error_t
+_gpgme_engine_op_setexpire (engine_t engine, gpgme_key_t key,
+ unsigned long expires, const char *subfprs,
+ unsigned int reserved)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->setexpire)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->setexpire) (engine->engine, key, expires, subfprs, reserved);
+}
diff --git a/src/engine.h b/src/engine.h
index c512a252..74082851 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -210,6 +210,11 @@ gpgme_error_t _gpgme_engine_op_spawn (engine_t engine,
gpgme_data_t dataout,
gpgme_data_t dataerr,
unsigned int flags);
+gpgme_error_t _gpgme_engine_op_setexpire (engine_t engine,
+ gpgme_key_t key,
+ unsigned long expires,
+ const char *subfprs,
+ unsigned int reserved);
/* The available engine option flags. */
#define GPGME_ENGINE_FLAG_OFFLINE 1
diff --git a/src/genkey.c b/src/genkey.c
index 77576b18..981a0093 100644
--- a/src/genkey.c
+++ b/src/genkey.c
@@ -663,3 +663,55 @@ gpgme_op_set_uid_flag (gpgme_ctx_t ctx,
{
return set_uid_flag (ctx, 1, key, userid, name, value);
}
+
+/* Set the expiration time of a key or its subkeys. See
+ --quick-set-expire in the gnupg documentation. */
+static gpg_error_t
+setexpire (gpgme_ctx_t ctx, int synchronous,
+ gpgme_key_t key,
+ unsigned long expires,
+ const char *subfprs,
+ unsigned int reserved)
+{
+ gpgme_error_t err = 0;
+
+ TRACE_BEG (DEBUG_CTX, "gpgme_op_setexpire", ctx,
+ "%d key=%p expiry: %lu subkeys: '%s' reserved=0x%x",
+ synchronous, key, expires, subfprs, reserved);
+
+ if (!ctx || !key)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_engine_op_setexpire (ctx->engine, key, expires, subfprs, reserved);
+
+ if (synchronous && !err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
+
+/* See setexpire. */
+gpgme_error_t
+gpgme_op_setexpire_start (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ unsigned long expires,
+ const char *subfprs,
+ unsigned int reserved)
+{
+ return setexpire (ctx, 0, key, expires, subfprs, reserved);
+}
+
+
+/* See setexpire. This is the synchronous variant. */
+gpgme_error_t
+gpgme_op_setexpire (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ unsigned long expires,
+ const char *subfprs,
+ unsigned int reserved)
+{
+ return setexpire (ctx, 1, key, expires, subfprs, reserved);
+}
diff --git a/src/gpgme.def b/src/gpgme.def
index c6902208..6666a1c7 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -274,5 +274,8 @@ EXPORTS
gpgme_data_new_from_estream @204
+ gpgme_op_setexpire @205
+ gpgme_op_setexpire_start @206
+
; END
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index b4f817b4..d1bc30de 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1868,6 +1868,13 @@ gpgme_error_t gpgme_op_set_uid_flag (gpgme_ctx_t ctx,
gpgme_key_t key, const char *userid,
const char *name, const char *value);
+/* Change the expiry of a key. */
+gpgme_error_t gpgme_op_setexpire_start (gpgme_ctx_t ctx,
+ gpgme_key_t key, unsigned long expires,
+ const char *subfprs, unsigned int reserved);
+gpgme_error_t gpgme_op_setexpire (gpgme_ctx_t ctx,
+ gpgme_key_t key, unsigned long expires,
+ const char *subfprs, unsigned int reserved);
/* Retrieve a pointer to the result of a genkey, createkey, or
* createsubkey operation. */
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index 79cbeef2..a740b72d 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -273,6 +273,9 @@ GPGME_1.0 {
gpgme_err_code_from_syserror;
gpgme_err_set_errno;
+ gpgme_op_setexpire;
+ gpgme_op_setexpire_start;
+
local:
*;
diff --git a/tests/run-genkey.c b/tests/run-genkey.c
index fd9b42a7..f0f6e302 100644
--- a/tests/run-genkey.c
+++ b/tests/run-genkey.c
@@ -205,12 +205,15 @@ show_usage (int ex)
" for addkey: FPR [ALGO [USAGE [EXPIRESECONDS]]]\n"
" for adduid: FPR USERID\n"
" for revuid: FPR USERID\n"
+ " for setexpire: FPR EXPIRE [SUBFPRS]\n"
" for set-primary: FPR USERID\n"
"Options:\n"
" --addkey add a subkey to the key with FPR\n"
" --adduid add a user id to the key with FPR\n"
" --revuid revoke a user id from the key with FPR\n"
" --set-primary set the primary key flag on USERID\n"
+ " --setexpire set the expiration time of the key FPR\n"
+ " or of its subkeys SUBFPRS\n"
" --verbose run in verbose mode\n"
" --status print status lines from the backend\n"
" --progress print progress info\n"
@@ -238,12 +241,17 @@ main (int argc, char **argv)
int adduid = 0;
int revuid = 0;
int setpri = 0;
+ int setexpire = 0;
const char *userid;
const char *algo = NULL;
const char *newuserid = NULL;
+ const char *subfprs = NULL;
unsigned int flags = 0;
unsigned long expire = 0;
gpgme_genkey_result_t result;
+ int i;
+ size_t n;
+ char *subfprs_buffer = NULL;
if (argc)
{ argc--; argv++; }
@@ -264,6 +272,7 @@ main (int argc, char **argv)
adduid = 0;
revuid = 0;
setpri = 0;
+ setexpire = 0;
argc--; argv++;
}
else if (!strcmp (*argv, "--adduid"))
@@ -272,6 +281,7 @@ main (int argc, char **argv)
adduid = 1;
revuid = 0;
setpri = 0;
+ setexpire = 0;
argc--; argv++;
}
else if (!strcmp (*argv, "--revuid"))
@@ -280,6 +290,7 @@ main (int argc, char **argv)
adduid = 0;
revuid = 1;
setpri = 0;
+ setexpire = 0;
argc--; argv++;
}
else if (!strcmp (*argv, "--set-primary"))
@@ -288,6 +299,16 @@ main (int argc, char **argv)
adduid = 0;
revuid = 0;
setpri = 1;
+ setexpire = 0;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--setexpire"))
+ {
+ addkey = 0;
+ adduid = 0;
+ revuid = 0;
+ setpri = 0;
+ setexpire = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--verbose"))
@@ -341,6 +362,48 @@ main (int argc, char **argv)
userid = argv[0];
newuserid = argv[1];
}
+ else if (setexpire)
+ {
+ if (argc < 2)
+ {
+ show_usage (1);
+ }
+ userid = argv[0];
+ argc--; argv++;
+ expire = parse_expire_string (argv[0]);
+ argc--; argv++;
+ if (argc > 1)
+ {
+ /* Several subkey fprs given */
+ for (i=0, n = 0; i < argc; i++)
+ n += strlen (argv[1]) + 1;
+ n++;
+ subfprs_buffer = malloc (n);
+ if (!subfprs_buffer)
+ {
+ fprintf (stderr, PGM ": malloc failed: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ exit (1);
+ }
+ *subfprs_buffer = 0;
+ for (i=0; i < argc; i++)
+ {
+ strcat (subfprs_buffer, argv[i]);
+ strcat (subfprs_buffer, "\n");
+ }
+ subfprs = subfprs_buffer;
+ }
+ else if (argc)
+ {
+ /* One subkey fpr (or '*') given */
+ subfprs = *argv;
+ }
+ else
+ {
+ /* No subkey fpr given. */
+ subfprs = NULL;
+ }
+ }
else
{
if (!argc || argc > 4)
@@ -373,7 +436,8 @@ main (int argc, char **argv)
gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
}
- if (addkey || adduid || revuid || setpri)
+
+ if (addkey || adduid || revuid || setpri || setexpire)
{
gpgme_key_t akey;
@@ -425,6 +489,17 @@ main (int argc, char **argv)
exit (1);
}
}
+ else if (setexpire)
+ {
+ err = gpgme_op_setexpire (ctx, akey, expire, subfprs, 0);
+ if (err)
+ {
+ fprintf (stderr, PGM ": gpgme_op_setexpire failed: %s\n",
+ gpg_strerror (err));
+ exit (1);
+ }
+ }
+
gpgme_key_unref (akey);
}
else
@@ -438,7 +513,7 @@ main (int argc, char **argv)
}
}
- if (!setpri)
+ if (!setpri && !setexpire)
{
result = gpgme_op_genkey_result (ctx);
if (!result)