aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--NEWS2
-rw-r--r--doc/gpgme.texi2
-rw-r--r--src/engine-gpg.c95
-rw-r--r--src/genkey.c85
-rw-r--r--src/gpgme.def2
-rw-r--r--src/libgpgme.vers2
-rw-r--r--tests/run-genkey.c41
7 files changed, 196 insertions, 33 deletions
diff --git a/NEWS b/NEWS
index d3639c89..9445f7f9 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,8 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
gpgme_data_set_flag NEW.
gpgme_op_createkey NEW.
gpgme_op_createkey_start NEW.
+ gpgme_op_createsubkey NEW.
+ gpgme_op_createsubkey_start 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/doc/gpgme.texi b/doc/gpgme.texi
index dfc9548b..ef39d81b 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -3792,7 +3792,7 @@ The function @code{gpgme_op_genkey} generates a new key pair in the
context @var{ctx}. The meaning of @var{public} and @var{secret}
depends on the crypto backend.
-GnuPG does not support @var{public} and @var{secret}, they should be
+GPG does not support @var{public} and @var{secret}, they should be
@code{NULL}. GnuPG will generate a key pair and add it to the
standard key ring. The fingerprint of the generated key is available
with @code{gpgme_op_genkey_result}.
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index f22d8b44..5a16f805 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -1969,6 +1969,47 @@ gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
}
+
+/* Helper to add algo, usage, and expire to the list of args. */
+static gpgme_error_t
+gpg_add_algo_usage_expire (engine_gpg_t gpg,
+ const char *algo,
+ unsigned long expires,
+ unsigned int flags)
+{
+ gpg_error_t err;
+
+ /* This condition is only required to allow the use of gpg < 2.1.16 */
+ if (algo
+ || (flags & (GPGME_CREATE_SIGN | GPGME_CREATE_ENCR
+ | GPGME_CREATE_CERT | GPGME_CREATE_AUTH))
+ || expires)
+ {
+ err = add_arg (gpg, algo? algo : "default");
+ if (!err)
+ {
+ char tmpbuf[5*4+1];
+ snprintf (tmpbuf, sizeof tmpbuf, "%s%s%s%s",
+ (flags & GPGME_CREATE_SIGN)? " sign":"",
+ (flags & GPGME_CREATE_ENCR)? " encr":"",
+ (flags & GPGME_CREATE_CERT)? " cert":"",
+ (flags & GPGME_CREATE_AUTH)? " auth":"");
+ err = add_arg (gpg, *tmpbuf? tmpbuf : "default");
+ }
+ if (!err && expires)
+ {
+ char tmpbuf[8+20];
+ snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
+ err = add_arg (gpg, tmpbuf);
+ }
+ }
+ else
+ err = 0;
+
+ return err;
+}
+
+
static gpgme_error_t
gpg_createkey_from_param (engine_gpg_t gpg,
gpgme_data_t help_data, int use_armor)
@@ -2026,32 +2067,8 @@ gpg_createkey (engine_gpg_t gpg,
if (!err)
err = add_arg (gpg, userid);
- /* This condition is only required to allow the use of gpg < 2.1.16 */
- if (algo
- || (flags & (GPGME_CREATE_SIGN | GPGME_CREATE_ENCR
- | GPGME_CREATE_CERT | GPGME_CREATE_AUTH))
- || expires)
- {
-
- if (!err)
- err = add_arg (gpg, algo? algo : "default");
- if (!err)
- {
- char tmpbuf[5*4+1];
- snprintf (tmpbuf, sizeof tmpbuf, "%s%s%s%s",
- (flags & GPGME_CREATE_SIGN)? " sign":"",
- (flags & GPGME_CREATE_ENCR)? " encr":"",
- (flags & GPGME_CREATE_CERT)? " cert":"",
- (flags & GPGME_CREATE_AUTH)? " auth":"");
- err = add_arg (gpg, *tmpbuf? tmpbuf : "default");
- }
- if (!err && expires)
- {
- char tmpbuf[8+20];
- snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
- err = add_arg (gpg, tmpbuf);
- }
- }
+ if (!err)
+ err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
if (!err)
err = start (gpg);
@@ -2067,7 +2084,31 @@ gpg_addkey (engine_gpg_t gpg,
unsigned int flags,
int use_armor)
{
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ gpgme_error_t err;
+
+ if (!key || !key->fpr)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = add_arg (gpg, "--quick-addkey");
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+ if (!err && (flags & GPGME_CREATE_NOPASSWD))
+ {
+ err = add_arg (gpg, "--passphrase");
+ if (!err)
+ err = add_arg (gpg, "");
+ }
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_arg (gpg, key->fpr);
+
+ if (!err)
+ err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
+
+ if (!err)
+ err = start (gpg);
+ return err;
}
diff --git a/src/genkey.c b/src/genkey.c
index 0b795f43..26bcca6e 100644
--- a/src/genkey.c
+++ b/src/genkey.c
@@ -387,3 +387,88 @@ gpgme_op_createkey (gpgme_ctx_t ctx, const char *userid, const char *algo,
err = _gpgme_wait_one (ctx);
return TRACE_ERR (err);
}
+
+
+
+static gpgme_error_t
+createsubkey_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_key_t key,
+ const char *algo,
+ unsigned long reserved, unsigned long expires,
+ 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);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ if (reserved || !key)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ _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,
+ NULL, algo, reserved, expires,
+ key, flags,
+ NULL, ctx->use_armor, NULL, NULL);
+
+}
+
+
+/* Add a subkey to an existing KEY. */
+gpgme_error_t
+gpgme_op_createsubkey_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createsubkey_start", ctx,
+ "key=%p, algo='%s' flags=0x%x", key, algo, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+ err = createsubkey_start (ctx, 0, key, algo, reserved, expires, flags);
+ return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_createsubkey (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createsubkey", ctx,
+ "key=%p, algo='%s' flags=0x%x", key, algo, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+ err = createsubkey_start (ctx, 1, key, algo, reserved, expires, flags);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
diff --git a/src/gpgme.def b/src/gpgme.def
index a56b9efa..7b7b1f20 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -231,6 +231,8 @@ EXPORTS
gpgme_op_createkey_start @172
gpgme_op_createkey @173
+ gpgme_op_createsubkey_start @174
+ gpgme_op_createsubkey @175
; END
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index b06c9c65..2a3e9fc3 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -105,6 +105,8 @@ GPGME_1.1 {
gpgme_op_createkey_start;
gpgme_op_createkey;
+ gpgme_op_createsubkey_start;
+ gpgme_op_createsubkey;
};
diff --git a/tests/run-genkey.c b/tests/run-genkey.c
index 74d4038e..3b645025 100644
--- a/tests/run-genkey.c
+++ b/tests/run-genkey.c
@@ -201,6 +201,7 @@ show_usage (int ex)
{
fputs ("usage: " PGM " [options] USERID [ALGO [USAGE [EXPIRESECONDS]]]\n\n"
"Options:\n"
+ " --addkey add a subkey to the key with USERID\n"
" --verbose run in verbose mode\n"
" --status print status lines from the backend\n"
" --progress print progress info\n"
@@ -224,6 +225,7 @@ main (int argc, char **argv)
int print_status = 0;
int print_progress = 0;
int use_loopback = 0;
+ int addkey = 0;
const char *userid;
const char *algo = NULL;
unsigned int flags = 0;
@@ -243,6 +245,11 @@ main (int argc, char **argv)
}
else if (!strcmp (*argv, "--help"))
show_usage (0);
+ else if (!strcmp (*argv, "--addkey"))
+ {
+ addkey = 1;
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--verbose"))
{
verbose = 1;
@@ -316,12 +323,36 @@ main (int argc, char **argv)
gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
}
- err = gpgme_op_createkey (ctx, userid, algo, 0, expire, NULL, flags);
- if (err)
+ if (addkey)
{
- fprintf (stderr, PGM ": gpgme_op_createkey failed: %s\n",
- gpg_strerror (err));
- exit (1);
+ gpgme_key_t akey;
+
+ err = gpgme_get_key (ctx, userid, &akey, 1);
+ if (err)
+ {
+ fprintf (stderr, PGM ": error getting secret key for '%s': %s\n",
+ userid, 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);
+ }
+ gpgme_key_unref (akey);
+ }
+ else
+ {
+ err = gpgme_op_createkey (ctx, userid, algo, 0, expire, NULL, flags);
+ if (err)
+ {
+ fprintf (stderr, PGM ": gpgme_op_createkey failed: %s\n",
+ gpg_strerror (err));
+ exit (1);
+ }
}
result = gpgme_op_genkey_result (ctx);