diff --git a/NEWS b/NEWS index 16e1550c..367b718f 100644 --- a/NEWS +++ b/NEWS @@ -10,10 +10,12 @@ Noteworthy changes in version 1.8.1 (unreleased) gpgme_op_createkey CHANGED: Meaning of 'expire' parameter. gpgme_op_createsubkey CHANGED: Meaning of 'expire' parameter. GPGME_CREATE_NOEXPIRE NEW. - gpgme_subkey_t EXTENDED: New field is_de_vs. + gpgme_subkey_t EXTENDED: New field 'is_de_vs'. gpgme_op_keylist_from_data_start NEW. + gpgme_op_set_uid_flag_start NEW. + gpgme_op_set_uid_flag NEW. GPGME_ENCRYPT_THROW_KEYIDS NEW. - gpgme_data_rewind UN-DEPRECATE + gpgme_data_rewind UN-DEPRECATE. cpp: Context::revUid(const Key&, const char*) NEW. cpp: Context::startRevUid(const Key&, const char*) NEW. cpp: Context::addUid(const Key&, const char*) NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 98462990..fd1f9bc7 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3896,6 +3896,61 @@ be completed by calling @code{gpgme_wait} on the context. @end deftypefun +@c +@c gpgme_op_set_uid_flag +@c +@deftypefun gpgme_error_t gpgme_op_set_ui_flag @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_key_t @var{key}}, @ + @w{const char *@var{userid}}, @ + @w{cons char * @var{name}}, @ + @w{cons char * @var{value}}); + +The function @code{gpgme_op_set_uid_flag} is used to set flags on a +user ID from the OpenPGP key given by @var{KEY}. Setting flags on +user IDs after key creation is a feature of the OpenPGP protocol and +thus the protocol for the context @var{ctx} must be set to OpenPGP. + +@var{key} specifies the key to operate on. This parameters is required. + +@var{userid} is the user ID of the key to be manipulated. This 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. This is a required parameter. + +@var{name} names the flag which is to be changed. The only currently +supported flag is: + +@table @code +@item primary +This sets the primary key flag on the given user ID. All other +primary key flag on other user IDs are removed. @var{value} must be +given as NULL. For technical reasons this functions bumps the +creation timestamp of all affected self-signatures up by one second. +At least GnuPG version 2.1.20 is required. + +@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_set_uid_flag_start @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_key_t @var{key}}, @ + @w{const char *@var{userid}}, @ + @w{cons char * @var{name}}, @ + @w{cons char * @var{value}}); + +The function @code{gpgme_op_set_uid_flag_start} initiates a +@code{gpgme_op_set_uid_flag} 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 gpgme_op_genkey @c diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 6024529b..6e4b8339 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2222,7 +2222,14 @@ gpg_adduid (engine_gpg_t gpg, if (!key || !key->fpr || !userid) return gpg_error (GPG_ERR_INV_ARG); - if ((extraflags & GENKEY_EXTRAFLAG_REVOKE)) + if ((extraflags & GENKEY_EXTRAFLAG_SETPRIMARY)) + { + if (!have_gpg_version (gpg, "2.1.20")) + err = gpg_error (GPG_ERR_NOT_SUPPORTED); + else + err = add_arg (gpg, "--quick-set-primary-uid"); + } + else if ((extraflags & GENKEY_EXTRAFLAG_REVOKE)) err = add_arg (gpg, "--quick-revuid"); else err = add_arg (gpg, "--quick-adduid"); @@ -2262,7 +2269,7 @@ gpg_genkey (void *engine, * USERID && !KEY - Create a new keyblock. * !USERID && KEY - Add a new subkey to KEY (gpg >= 2.1.14) * USERID && KEY && !ALGO - Add a new user id to KEY (gpg >= 2.1.14). - * + * or set a flag on a user id. */ if (help_data) { diff --git a/src/engine.h b/src/engine.h index f456812e..1064f5ed 100644 --- a/src/engine.h +++ b/src/engine.h @@ -25,8 +25,9 @@ #include "gpgme.h" /* Flags used by the EXTRAFLAGS arg of _gpgme_engine_op_genkey. */ -#define GENKEY_EXTRAFLAG_ARMOR 1 -#define GENKEY_EXTRAFLAG_REVOKE 2 +#define GENKEY_EXTRAFLAG_ARMOR 1 +#define GENKEY_EXTRAFLAG_REVOKE 2 +#define GENKEY_EXTRAFLAG_SETPRIMARY 4 struct engine; diff --git a/src/genkey.c b/src/genkey.c index ea3f1ea4..710b58ff 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -489,7 +489,7 @@ gpgme_op_createsubkey (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo, static gpgme_error_t -addrevuid_start (gpgme_ctx_t ctx, int synchronous, int revoke, +addrevuid_start (gpgme_ctx_t ctx, int synchronous, int extraflags, gpgme_key_t key, const char *userid, unsigned int flags) { gpgme_error_t err; @@ -512,7 +512,7 @@ addrevuid_start (gpgme_ctx_t ctx, int synchronous, int revoke, if (err) return err; - opd->uidmode = revoke? 2 : 1; + opd->uidmode = extraflags? 2 : 1; _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx); @@ -528,7 +528,7 @@ addrevuid_start (gpgme_ctx_t ctx, int synchronous, int revoke, userid, NULL, 0, 0, key, flags, NULL, - revoke? GENKEY_EXTRAFLAG_REVOKE : 0, + extraflags, NULL, NULL); } @@ -584,7 +584,7 @@ gpgme_op_revuid_start (gpgme_ctx_t ctx, if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); - err = addrevuid_start (ctx, 0, 1, key, userid, flags); + err = addrevuid_start (ctx, 0, GENKEY_EXTRAFLAG_REVOKE, key, userid, flags); return TRACE_ERR (err); } @@ -601,8 +601,60 @@ gpgme_op_revuid (gpgme_ctx_t ctx, if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); - err = addrevuid_start (ctx, 1, 1, key, userid, flags); + err = addrevuid_start (ctx, 1, GENKEY_EXTRAFLAG_REVOKE, key, userid, flags); if (!err) err = _gpgme_wait_one (ctx); return TRACE_ERR (err); } + + +/* Set a flag on the USERID of KEY. The only supported flag right now + * is "primary" to mark the primary key. */ +static gpg_error_t +set_uid_flag (gpgme_ctx_t ctx, int synchronous, + gpgme_key_t key, const char *userid, + const char *name, const char *value) +{ + gpgme_error_t err; + + TRACE_BEG4 (DEBUG_CTX, "gpgme_op_set_uid_flag", ctx, + "%d uid='%s' '%s'='%s'", synchronous, userid, name, value); + + if (!ctx || !name || !key || !userid) + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); + + if (!strcmp (name, "primary")) + { + if (value) + err = gpg_error (GPG_ERR_INV_ARG); + else + err = addrevuid_start (ctx, synchronous, + GENKEY_EXTRAFLAG_SETPRIMARY, key, userid, 0); + } + else + return err = gpg_error (GPG_ERR_UNKNOWN_NAME); + + if (synchronous && !err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} + + +/* See set_uid_flag. */ +gpgme_error_t +gpgme_op_set_uid_flag_start (gpgme_ctx_t ctx, + gpgme_key_t key, const char *userid, + const char *name, const char *value) +{ + return set_uid_flag (ctx, 0, key, userid, name, value); +} + + +/* See set_uid_flag. Thsi is the synchronous variant. */ +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) +{ + return set_uid_flag (ctx, 1, key, userid, name, value); +} diff --git a/src/gpgme.def b/src/gpgme.def index ddd57d35..9faffb85 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -256,5 +256,8 @@ EXPORTS gpgme_op_keylist_from_data_start @192 + gpgme_op_set_uid_flag_start @193 + gpgme_op_set_uid_flag @194 + ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 16191ebc..e9ee6e2f 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1726,6 +1726,13 @@ gpgme_error_t gpgme_op_revuid (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid, unsigned int reserved); +/* Set a flag on the USERID of KEY. See the manual for supported flags. */ +gpgme_error_t gpgme_op_set_uid_flag_start (gpgme_ctx_t ctx, + gpgme_key_t key, const char *userid, + const char *name, const char *value); +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); /* Retrieve a pointer to the result of a genkey, createkey, or diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 9344a752..037a6ae2 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -126,6 +126,9 @@ GPGME_1.1 { gpgme_op_query_swdb; gpgme_op_query_swdb_result; + + gpgme_op_set_uid_flag_start; + gpgme_op_set_uid_flag; }; diff --git a/tests/run-genkey.c b/tests/run-genkey.c index c5abc423..91edb222 100644 --- a/tests/run-genkey.c +++ b/tests/run-genkey.c @@ -204,10 +204,12 @@ show_usage (int ex) " for addkey: FPR [ALGO [USAGE [EXPIRESECONDS]]]\n" " for adduid: FPR USERID\n" " for revuid: FPR USERID\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" + " --revuid revoke a user id from the key with FPR\n" + " --set-primary set the primary key flag on USERID\n" " --verbose run in verbose mode\n" " --status print status lines from the backend\n" " --progress print progress info\n" @@ -234,6 +236,7 @@ main (int argc, char **argv) int addkey = 0; int adduid = 0; int revuid = 0; + int setpri = 0; const char *userid; const char *algo = NULL; const char *newuserid = NULL; @@ -259,6 +262,7 @@ main (int argc, char **argv) addkey = 1; adduid = 0; revuid = 0; + setpri = 0; argc--; argv++; } else if (!strcmp (*argv, "--adduid")) @@ -266,6 +270,7 @@ main (int argc, char **argv) addkey = 0; adduid = 1; revuid = 0; + setpri = 0; argc--; argv++; } else if (!strcmp (*argv, "--revuid")) @@ -273,6 +278,15 @@ main (int argc, char **argv) addkey = 0; adduid = 0; revuid = 1; + setpri = 0; + argc--; argv++; + } + else if (!strcmp (*argv, "--set-primary")) + { + addkey = 0; + adduid = 0; + revuid = 0; + setpri = 1; argc--; argv++; } else if (!strcmp (*argv, "--verbose")) @@ -319,7 +333,7 @@ main (int argc, char **argv) show_usage (1); } - if (adduid || revuid) + if (adduid || revuid || setpri) { if (argc != 2) show_usage (1); @@ -358,7 +372,7 @@ main (int argc, char **argv) gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL); } - if (addkey || adduid || revuid) + if (addkey || adduid || revuid || setpri) { gpgme_key_t akey; @@ -400,6 +414,16 @@ main (int argc, char **argv) exit (1); } } + else if (setpri) + { + err = gpgme_op_set_uid_flag (ctx, akey, newuserid, "primary", NULL); + if (err) + { + fprintf (stderr, PGM ": gpgme_op_set_uid_flag failed: %s\n", + gpg_strerror (err)); + exit (1); + } + } gpgme_key_unref (akey); } else @@ -413,27 +437,30 @@ main (int argc, char **argv) } } - result = gpgme_op_genkey_result (ctx); - if (!result) + if (!setpri) { - fprintf (stderr, PGM": gpgme_op_genkey_result returned NULL\n"); - exit (1); + result = gpgme_op_genkey_result (ctx); + if (!result) + { + fprintf (stderr, PGM": gpgme_op_genkey_result returned NULL\n"); + exit (1); + } + + printf ("Generated key: %s (%s)\n", + result->fpr ? result->fpr : "none", + result->primary ? (result->sub ? "primary, sub" : "primary") + /**/ : (result->sub ? "sub" : "none")); + + if (result->fpr && strlen (result->fpr) < 40) + fprintf (stderr, PGM": generated key has unexpected fingerprint\n"); + if (!result->primary) + fprintf (stderr, PGM": primary key was not generated\n"); + if (!result->sub) + fprintf (stderr, PGM": sub key was not generated\n"); + if (!result->uid) + fprintf (stderr, PGM": uid was not generated\n"); } - printf ("Generated key: %s (%s)\n", - result->fpr ? result->fpr : "none", - result->primary ? (result->sub ? "primary, sub" : "primary") - /**/ : (result->sub ? "sub" : "none")); - - if (result->fpr && strlen (result->fpr) < 40) - fprintf (stderr, PGM": generated key has unexpected fingerprint\n"); - if (!result->primary) - fprintf (stderr, PGM": primary key was not generated\n"); - if (!result->sub) - fprintf (stderr, PGM": sub key was not generated\n"); - if (!result->uid) - fprintf (stderr, PGM": uid was not generated\n"); - gpgme_release (ctx); return 0; }