From 00c501d296da287bec2fd6a0e3912abfbde90a98 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 13 Sep 2016 18:57:38 +0200 Subject: core: New function gpgme_op_create_key. * src/engine-backend.h (engine_ops): Change prototype of genkey. * src/engine-gpgsm.c (gpgsm_genkey): Change accordingly. * src/engine-gpg.c (gpg_genkey): Change it to a dispatcher. (gpg_createkey_from_param): New for the old functionality. (gpg_createkey_legacy): New. Stub for now. (gpg_createkey): New. (gpg_addkey): New. Stub for now. (gpg_adduid): New. Stub for now. * src/engine.c (_gpgme_engine_op_genkey): Add new args. * src/genkey.c (op_data_t): Add field ERROR_CODE. (parse_error): New. (genkey_status_handler): Parse ERROR status line. (genkey_start): Use NULL/0 for the new args. (createkey_start): New. (gpgme_op_createkey_start, gpgme_op_createkey): New. * src/gpgme.def, src/libgpgme.vers: Add gpgme_op_createkey_start and gpgme_op_createkey. * src/gpgme.h.in (_gpgme_op_genkey_result): Add fields PUBKEY and SECKEY. (GPGME_CREATE_SIGN): New. (GPGME_CREATE_ENCR): New. (GPGME_CREATE_CERT): New. (GPGME_CREATE_AUTH): New. (GPGME_CREATE_NOPASSWD): New. (GPGME_CREATE_SELFSIGNED): New. (GPGME_CREATE_NOSTORE): New. (GPGME_CREATE_WANTPUB): New. (GPGME_CREATE_WANTSEC): New. (GPGME_CREATE_FORCE): New. * tests/run-genkey.c: New. * tests/Makefile.am (noinst_PROGRAMS): Add it. -- This function uses the new --quick-gen-key API of gpg. A limited compatibility mode to use older gpg versions and gpgsm will eventually be provided. Not all flags are currently implemented. ./run-genkey --unprotected --force test@example.com Create a new standard key with the given user id. --force is used to allow creating more than one key with that user id in the keyring. ./run-genkey --unprotected --force \ test@example.com default default 2145826800 Creates a new standard key with an expiration date of 2037-12-31. ./run-genkey --unprotected --force \ test@example.com future-default default 2145826800 Create a standard key using the fugure default algorithms. Signed-off-by: Werner Koch --- src/engine-gpg.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 149 insertions(+), 13 deletions(-) (limited to 'src/engine-gpg.c') diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 3f77ba87..289578b0 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1964,22 +1964,11 @@ gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode, static gpgme_error_t -gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor, - gpgme_data_t pubkey, gpgme_data_t seckey) +gpg_createkey_from_param (engine_gpg_t gpg, + gpgme_data_t help_data, int use_armor) { - engine_gpg_t gpg = engine; gpgme_error_t err; - if (!gpg) - return gpg_error (GPG_ERR_INV_VALUE); - - /* We need a special mechanism to get the fd of a pipe here, so that - we can use this for the %pubring and %secring parameters. We - don't have this yet, so we implement only the adding to the - standard keyrings. */ - if (pubkey || seckey) - return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - err = add_arg (gpg, "--gen-key"); if (!err && use_armor) err = add_arg (gpg, "--armor"); @@ -1987,9 +1976,156 @@ gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor, err = add_arg (gpg, "--"); if (!err) err = add_data (gpg, help_data, -1, 0); + if (!err) + err = start (gpg); + return err; +} + + +/* This is used for gpg versions which do not support the quick-genkey + * command to emulate the gpgme_op_createkey API. */ +static gpgme_error_t +gpg_createkey_legacy (engine_gpg_t gpg, + const char *userid, const char *algo, + unsigned long expires, + unsigned int flags, + int use_armor) +{ + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); +} + + +static gpgme_error_t +gpg_createkey (engine_gpg_t gpg, + const char *userid, const char *algo, + unsigned long expires, + unsigned int flags, + int use_armor) +{ + gpgme_error_t err; + + err = add_arg (gpg, "--quick-gen-key"); + 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 && (flags & GPGME_CREATE_FORCE)) + err = add_arg (gpg, "--yes"); + if (!err) + err = add_arg (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 = start (gpg); + return err; +} + + +static gpgme_error_t +gpg_addkey (engine_gpg_t gpg, + const char *algo, + unsigned long expires, + gpgme_key_t key, + unsigned int flags, + int use_armor) +{ + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); +} + + +static gpgme_error_t +gpg_adduid (engine_gpg_t gpg, + const char *userid, + unsigned int flags, + int use_armor) +{ + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); +} + + +static gpgme_error_t +gpg_genkey (void *engine, + const char *userid, const char *algo, + unsigned long reserved, unsigned long expires, + gpgme_key_t key, unsigned int flags, + gpgme_data_t help_data, int use_armor, + gpgme_data_t pubkey, gpgme_data_t seckey) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + (void)reserved; + + if (!gpg) + return gpg_error (GPG_ERR_INV_VALUE); + + /* If HELP_DATA is given the use of the old interface + * (gpgme_op_genkey) has been requested. The other modes are: + * + * 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). + * + */ + if (help_data) + { + /* We need a special mechanism to get the fd of a pipe here, so + that we can use this for the %pubring and %secring + parameters. We don't have this yet, so we implement only the + adding to the standard keyrings. */ + if (pubkey || seckey) + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + else + err = gpg_createkey_from_param (gpg, help_data, use_armor); + } + else if (userid && !key) + { + if (!have_gpg_version (gpg, "2.1.13")) + err = gpg_createkey_legacy (gpg, userid, algo, expires, flags, + use_armor); + else + err = gpg_createkey (gpg, userid, algo, expires, flags, use_armor); + } + else if (!have_gpg_version (gpg, "2.1.13")) + err = gpg_error (GPG_ERR_NOT_SUPPORTED); + 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); + else + err = gpg_error (GPG_ERR_INV_VALUE); return err; } -- cgit v1.2.3