diff --git a/NEWS b/NEWS index 9445f7f9..621ce3ff 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,8 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_] gpgme_op_createkey_start NEW. gpgme_op_createsubkey NEW. gpgme_op_createsubkey_start NEW. + gpgme_op_adduid_start NEW. + gpgme_op_adduid NEW. gpgme_genkey_result_t EXTENDED: New fields pubkey and seckey. gpgme_signature_t EXTENDED: New field key. gpgme_key_t EXTENDED: New field fpr. diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 5a16f805..d2b6dd34 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2114,11 +2114,25 @@ gpg_addkey (engine_gpg_t gpg, static gpgme_error_t gpg_adduid (engine_gpg_t gpg, - const char *userid, - unsigned int flags, - int use_armor) + gpgme_key_t key, + const char *userid) { - return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + gpgme_error_t err; + + if (!key || !key->fpr || !userid) + return gpg_error (GPG_ERR_INV_ARG); + + err = add_arg (gpg, "--quick-adduid"); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_arg (gpg, key->fpr); + if (!err) + err = add_arg (gpg, userid); + + if (!err) + err = start (gpg); + return err; } @@ -2170,7 +2184,7 @@ gpg_genkey (void *engine, else if (!userid && key) err = gpg_addkey (gpg, algo, expires, key, flags, use_armor); else if (userid && key && !algo) - err = gpg_adduid (gpg, userid, flags, use_armor); + err = gpg_adduid (gpg, key, userid); else err = gpg_error (GPG_ERR_INV_VALUE); diff --git a/src/genkey.c b/src/genkey.c index 26bcca6e..b93abb80 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -42,6 +42,9 @@ typedef struct /* The error code from certain ERROR status lines or 0. */ gpg_error_t error_code; + /* Flag to indicate that a UID is to be added. */ + gpg_error_t uidmode; + /* The key parameters passed to the crypto engine. */ gpgme_data_t key_parameter; } *op_data_t; @@ -142,7 +145,10 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) if (args && *args) { if (*args == 'B' || *args == 'P') - opd->result.primary = 1; + { + opd->result.primary = 1; + opd->result.uid = 1; + } if (*args == 'B' || *args == 'S') opd->result.sub = 1; if (args[1] == ' ') @@ -171,10 +177,12 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) case GPGME_STATUS_EOF: if (opd->error_code) return opd->error_code; - else if (!opd->result.primary && !opd->result.sub) + else if (!opd->uidmode && !opd->result.primary && !opd->result.sub) return gpg_error (GPG_ERR_GENERAL); else if (opd->failure_code) return opd->failure_code; + else if (opd->uidmode) + opd->result.uid = 1; /* We have no status line, thus this hack. */ break; case GPGME_STATUS_INQUIRE_MAXLEN: @@ -277,7 +285,7 @@ gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms, TRACE_LOGBUF (parms, strlen (parms)); if (!ctx) - return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); err = genkey_start (ctx, 0, parms, pubkey, seckey); return TRACE_ERR (err); @@ -298,7 +306,7 @@ gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, gpgme_data_t pubkey, TRACE_LOGBUF (parms, strlen (parms)); if (!ctx) - return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); err = genkey_start (ctx, 1, parms, pubkey, seckey); if (!err) @@ -323,7 +331,7 @@ createkey_start (gpgme_ctx_t ctx, int synchronous, return err; if (reserved || anchorkey || !userid) - return gpg_error (GPG_ERR_INV_VALUE); + return gpg_error (GPG_ERR_INV_ARG); err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, sizeof (*opd), release_op_data); @@ -360,7 +368,7 @@ gpgme_op_createkey_start (gpgme_ctx_t ctx, const char *userid, const char *algo, "userid='%s', algo='%s' flags=0x%x", userid, algo, flags); if (!ctx) - return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); err = createkey_start (ctx, 0, userid, algo, reserved, expires, anchorkey, flags); @@ -379,7 +387,7 @@ gpgme_op_createkey (gpgme_ctx_t ctx, const char *userid, const char *algo, "userid='%s', algo='%s' flags=0x%x", userid, algo, flags); if (!ctx) - return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); err = createkey_start (ctx, 1, userid, algo, reserved, expires, anchorkey, flags); @@ -409,7 +417,7 @@ createsubkey_start (gpgme_ctx_t ctx, int synchronous, return err; if (reserved || !key) - return gpg_error (GPG_ERR_INV_VALUE); + return gpg_error (GPG_ERR_INV_ARG); err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, sizeof (*opd), release_op_data); @@ -447,7 +455,7 @@ gpgme_op_createsubkey_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo, "key=%p, algo='%s' flags=0x%x", key, algo, flags); if (!ctx) - return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); err = createsubkey_start (ctx, 0, key, algo, reserved, expires, flags); return TRACE_ERR (err); @@ -465,10 +473,92 @@ gpgme_op_createsubkey (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo, "key=%p, algo='%s' flags=0x%x", key, algo, flags); if (!ctx) - return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); err = createsubkey_start (ctx, 1, key, algo, reserved, expires, flags); if (!err) err = _gpgme_wait_one (ctx); return TRACE_ERR (err); } + + + +static gpgme_error_t +adduid_start (gpgme_ctx_t ctx, int synchronous, + gpgme_key_t key, const char *userid, unsigned int flags) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + if (ctx->protocol != GPGME_PROTOCOL_OPENPGP) + return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL); + + if (!key || !userid) + return gpg_error (GPG_ERR_INV_ARG); + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + + opd->uidmode = 1; + + _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx); + + if (ctx->passphrase_cb) + { + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + + return _gpgme_engine_op_genkey (ctx->engine, + userid, NULL, 0, 0, + key, flags, + NULL, ctx->use_armor, NULL, NULL); + +} + + +/* Add USERID to an existing KEY. */ +gpgme_error_t +gpgme_op_adduid_start (gpgme_ctx_t ctx, + gpgme_key_t key, const char *userid, unsigned int flags) +{ + gpgme_error_t err; + + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_adduid_start", ctx, + "uid='%s' flags=0x%x", userid, flags); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); + + err = adduid_start (ctx, 0, key, userid, flags); + return TRACE_ERR (err); +} + + +gpgme_error_t +gpgme_op_adduid (gpgme_ctx_t ctx, + gpgme_key_t key, const char *userid, unsigned int flags) +{ + gpgme_error_t err; + + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_adduid", ctx, + "uid='%s' flags=0x%x", userid, flags); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); + + err = adduid_start (ctx, 1, key, userid, flags); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} diff --git a/src/gpgme.def b/src/gpgme.def index 7b7b1f20..54b04e04 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -233,6 +233,8 @@ EXPORTS gpgme_op_createkey @173 gpgme_op_createsubkey_start @174 gpgme_op_createsubkey @175 + gpgme_op_adduid_start @176 + gpgme_op_adduid @177 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 0fdc9276..ec436c80 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1835,8 +1835,11 @@ struct _gpgme_op_genkey_result /* A sub key was generated. */ unsigned int sub : 1; + /* A user id was generated. */ + unsigned int uid : 1; + /* Internal to GPGME, do not use. */ - unsigned int _unused : 30; + unsigned int _unused : 29; /* The fingerprint of the generated key. */ char *fpr; @@ -1888,6 +1891,14 @@ gpgme_error_t gpgme_op_createsubkey (gpgme_ctx_t ctx, unsigned long expires, unsigned int flags); +/* Add USERID to an existing KEY. */ +gpgme_error_t gpgme_op_adduid_start (gpgme_ctx_t ctx, + gpgme_key_t key, const char *userid, + unsigned int flags); +gpgme_error_t gpgme_op_adduid (gpgme_ctx_t ctx, + gpgme_key_t key, const char *userid, + unsigned int flags); + /* Retrieve a pointer to the result of a genkey, createkey, or diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 2a3e9fc3..0cef9e0b 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -107,6 +107,8 @@ GPGME_1.1 { gpgme_op_createkey; gpgme_op_createsubkey_start; gpgme_op_createsubkey; + gpgme_op_adduid_start; + gpgme_op_adduid; }; diff --git a/tests/run-genkey.c b/tests/run-genkey.c index 3b645025..959e2ea1 100644 --- a/tests/run-genkey.c +++ b/tests/run-genkey.c @@ -199,9 +199,13 @@ parse_usage_string (const char *string) static int show_usage (int ex) { - fputs ("usage: " PGM " [options] USERID [ALGO [USAGE [EXPIRESECONDS]]]\n\n" + fputs ("usage: " PGM " [options] ARGS\n" + " args: USERID [ALGO [USAGE [EXPIRESECONDS]]]\n" + " for addkey: FPR [ALGO [USAGE [EXPIRESECONDS]]]\n" + " for adduid: FPR USERID\n" "Options:\n" - " --addkey add a subkey to the key with USERID\n" + " --addkey add a subkey to the key with FPR\n" + " --adduid add a user id to the key with FPR\n" " --verbose run in verbose mode\n" " --status print status lines from the backend\n" " --progress print progress info\n" @@ -226,8 +230,10 @@ main (int argc, char **argv) int print_progress = 0; int use_loopback = 0; int addkey = 0; + int adduid = 0; const char *userid; const char *algo = NULL; + const char *newuserid = NULL; unsigned int flags = 0; unsigned long expire = 0; gpgme_genkey_result_t result; @@ -248,6 +254,13 @@ main (int argc, char **argv) else if (!strcmp (*argv, "--addkey")) { addkey = 1; + adduid = 0; + argc--; argv++; + } + else if (!strcmp (*argv, "--adduid")) + { + addkey = 0; + adduid = 1; argc--; argv++; } else if (!strcmp (*argv, "--verbose")) @@ -294,15 +307,25 @@ main (int argc, char **argv) show_usage (1); } - if (!argc || argc > 4) - show_usage (1); - userid = argv[0]; - if (argc > 1) - algo = argv[1]; - if (argc > 2) - flags |= parse_usage_string (argv[2]); - if (argc > 3) - expire = parse_expire_string (argv[3]); + if (adduid) + { + if (argc != 2) + show_usage (1); + userid = argv[0]; + newuserid = argv[1]; + } + else + { + if (!argc || argc > 4) + show_usage (1); + userid = argv[0]; + if (argc > 1) + algo = argv[1]; + if (argc > 2) + flags |= parse_usage_string (argv[2]); + if (argc > 3) + expire = parse_expire_string (argv[3]); + } init_gpgme (protocol); @@ -323,7 +346,7 @@ main (int argc, char **argv) gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL); } - if (addkey) + if (addkey || adduid) { gpgme_key_t akey; @@ -335,12 +358,25 @@ main (int argc, char **argv) exit (1); } - err = gpgme_op_createsubkey (ctx, akey, algo, 0, expire, flags); - if (err) + if (addkey) { - fprintf (stderr, PGM ": gpgme_op_createsubkey failed: %s\n", - gpg_strerror (err)); - exit (1); + err = gpgme_op_createsubkey (ctx, akey, algo, 0, expire, flags); + if (err) + { + fprintf (stderr, PGM ": gpgme_op_createsubkey failed: %s\n", + gpg_strerror (err)); + exit (1); + } + } + else if (adduid) + { + err = gpgme_op_adduid (ctx, akey, newuserid, flags); + if (err) + { + fprintf (stderr, PGM ": gpgme_op_adduid failed: %s\n", + gpg_strerror (err)); + exit (1); + } } gpgme_key_unref (akey); } @@ -373,6 +409,8 @@ main (int argc, char **argv) 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;