diff options
| author | Ingo Klöcker <[email protected]> | 2020-08-04 12:32:31 +0000 | 
|---|---|---|
| committer | Ingo Klöcker <[email protected]> | 2020-08-04 14:51:56 +0000 | 
| commit | db82e99a8a40c57a237dad030928d0fcf6b03ad7 (patch) | |
| tree | dfda54ea9e78429d8e2d89238a371395b8142ad7 | |
| parent | Post release updates (diff) | |
| download | gpgme-db82e99a8a40c57a237dad030928d0fcf6b03ad7.tar.gz gpgme-db82e99a8a40c57a237dad030928d0fcf6b03ad7.zip  | |
core: New function gpgme_op_setexpire.
* src/gpgme.h.in (gpgme_op_setexpire_start, gpgme_op_setexpire): New.
* src/libgpgme.vers, src/gpgme.def: Add new functions.
* src/genkey.c (setexpire): New.
(gpgme_op_setexpire_start, gpgme_op_setexpire): New.
* src/engine.h, src/engine.c: (_gpgme_engine_op_setexpire): New.
* src/engine-backend.h (engine_ops): Add 'setexpire' and adjust all
engine initializers.
* src/engine-gpg.c (gpg_setexpire): New.
(_gpgme_engine_ops_gpg): Set setexpire to gpg_setexpire.
* doc/gpgme.texi: Document new functions.
* tests/run-genkey.c: Add option --setexpire.
--
This extends GPGME to support the --quick-set-expire command
added by GnuPG 2.1.22. This allows changing subkeys expiry
date without going through the editinteractor interface.
Co-authored-by: Andre Heinecke <[email protected]>
GnuPG-bug-id: 4999
| -rw-r--r-- | NEWS | 9 | ||||
| -rw-r--r-- | doc/gpgme.texi | 75 | ||||
| -rw-r--r-- | src/engine-assuan.c | 1 | ||||
| -rw-r--r-- | src/engine-backend.h | 3 | ||||
| -rw-r--r-- | src/engine-g13.c | 1 | ||||
| -rw-r--r-- | src/engine-gpg.c | 54 | ||||
| -rw-r--r-- | src/engine-gpgconf.c | 1 | ||||
| -rw-r--r-- | src/engine-gpgsm.c | 1 | ||||
| -rw-r--r-- | src/engine-spawn.c | 1 | ||||
| -rw-r--r-- | src/engine-uiserver.c | 1 | ||||
| -rw-r--r-- | src/engine.c | 14 | ||||
| -rw-r--r-- | src/engine.h | 5 | ||||
| -rw-r--r-- | src/genkey.c | 52 | ||||
| -rw-r--r-- | src/gpgme.def | 3 | ||||
| -rw-r--r-- | src/gpgme.h.in | 7 | ||||
| -rw-r--r-- | src/libgpgme.vers | 3 | ||||
| -rw-r--r-- | tests/run-genkey.c | 79 | 
17 files changed, 308 insertions, 2 deletions
@@ -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)  | 
