[git] GPGME - branch, master, updated. gpgme-1.6.0-340-g00c501d

by Werner Koch cvs at cvs.gnupg.org
Tue Sep 13 19:02:51 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, master has been updated
       via  00c501d296da287bec2fd6a0e3912abfbde90a98 (commit)
      from  70a3be27a509a1b5ea7372bee93d83c5019427ff (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 00c501d296da287bec2fd6a0e3912abfbde90a98
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Sep 13 18:57:38 2016 +0200

    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 at 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 at example.com default default 2145826800
    
    Creates a new standard key with an expiration date of 2037-12-31.
    
     ./run-genkey --unprotected --force \
          test at example.com future-default default 2145826800
    
    Create a standard key using the fugure default algorithms.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index da331b4..d3639c8 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,9 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  GPGME_PK_EDDSA                 NEW.
  gpgme_set_ctx_flag             NEW.
  gpgme_data_set_flag            NEW.
+ gpgme_op_createkey             NEW.
+ gpgme_op_createkey_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.
  gpgme_subkey_t                 EXTENDED: New field keygrip.
@@ -31,6 +34,16 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  GPGME_DATA_TYPE_PGP_SIGNATURE  NEW.
  GPGME_DATA_ENCODING_MIME       NEW.
  GPGME_ENCRYPT_SYMMETRIC        NEW.
+ 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.
 
 
 Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0]
diff --git a/src/engine-backend.h b/src/engine-backend.h
index a15194e..842292d 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -82,7 +82,11 @@ struct engine_ops
   gpgme_error_t (*export_ext) (void *engine, const char *pattern[],
 			       gpgme_export_mode_t mode, gpgme_data_t keydata,
 			       int use_armor);
-  gpgme_error_t (*genkey) (void *engine, gpgme_data_t help_data, int use_armor,
+  gpgme_error_t (*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);
   gpgme_error_t (*import) (void *engine, gpgme_data_t keydata,
                            gpgme_key_t *keyarray);
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index 3f77ba8..289578b 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;
 }
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index d4a1cf7..3f3230b 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -1433,29 +1433,49 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
 
 
 static gpgme_error_t
-gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
+gpgsm_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_gpgsm_t gpgsm = engine;
   gpgme_error_t err;
 
-  if (!gpgsm || !pubkey || seckey)
+  (void)reserved;
+
+  if (!gpgsm)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  gpgsm->input_cb.data = help_data;
-  err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
-  if (err)
-    return err;
-  gpgsm->output_cb.data = pubkey;
-  err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
-		      : map_data_enc (gpgsm->output_cb.data));
-  if (err)
-    return err;
-  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
-  gpgsm->inline_data = NULL;
+  if (help_data)
+    {
+      if (!pubkey || seckey)
+        return gpg_error (GPG_ERR_INV_VALUE);
 
-  err = start (gpgsm, "GENKEY");
-  return err;
+      gpgsm->input_cb.data = help_data;
+      err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
+      if (err)
+        return err;
+      gpgsm->output_cb.data = pubkey;
+      err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
+                          : map_data_enc (gpgsm->output_cb.data));
+      if (err)
+        return err;
+      gpgsm_clear_fd (gpgsm, MESSAGE_FD);
+      gpgsm->inline_data = NULL;
+
+      err = start (gpgsm, "GENKEY");
+      return err;
+    }
+
+  (void)userid;
+  (void)expires;
+  (void)key;
+  (void)flags;
+
+  /* The new interface has not yet been implemented,  */
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 }
 
 
diff --git a/src/engine.c b/src/engine.c
index f428034..1ff8698 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -773,7 +773,11 @@ _gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
 
 
 gpgme_error_t
-_gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
+_gpgme_engine_op_genkey (engine_t 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)
 {
@@ -783,7 +787,9 @@ _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
   if (!engine->ops->genkey)
     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
-  return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
+  return (*engine->ops->genkey) (engine->engine,
+                                 userid, algo, reserved, expires, key, flags,
+                                 help_data, use_armor,
 				 pubkey, seckey);
 }
 
diff --git a/src/engine.h b/src/engine.h
index b713d96..857dff4 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -108,6 +108,10 @@ gpgme_error_t _gpgme_engine_op_export_ext (engine_t engine,
 					   gpgme_data_t keydata,
 					   int use_armor);
 gpgme_error_t _gpgme_engine_op_genkey (engine_t 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);
diff --git a/src/export.c b/src/export.c
index a29fbde..41a9eba 100644
--- a/src/export.c
+++ b/src/export.c
@@ -34,7 +34,7 @@
 /* Local operation data.  */
 typedef struct
 {
-  gpg_error_t err;  /* Error encountred during the export.  */
+  gpg_error_t err;  /* Error encountered during the export.  */
 } *op_data_t;
 
 
diff --git a/src/genkey.c b/src/genkey.c
index 34cc5af..0b795f4 100644
--- a/src/genkey.c
+++ b/src/genkey.c
@@ -1,23 +1,22 @@
 /* genkey.c - Key generation.
-   Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
-
-   This file is part of GPGME.
-
-   GPGME is free software; you can redistribute it and/or modify it
-   under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   GPGME is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ * Copyright (C) 2001, 2002, 2003, 2004, 2016 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #if HAVE_CONFIG_H
 #include <config.h>
@@ -40,6 +39,9 @@ typedef struct
   /* The error code from a FAILURE status line or 0.  */
   gpg_error_t failure_code;
 
+  /* The error code from certain ERROR status lines or 0.  */
+  gpg_error_t error_code;
+
   /* The key parameters passed to the crypto engine.  */
   gpgme_data_t key_parameter;
 } *op_data_t;
@@ -82,7 +84,39 @@ gpgme_op_genkey_result (gpgme_ctx_t ctx)
   return &opd->result;
 }
 
+
 

+/* Parse an error status line.  Return the error location and the
+   error code.  The function may modify ARGS. */
+static char *
+parse_error (char *args, gpg_error_t *r_err)
+{
+  char *where = strchr (args, ' ');
+  char *which;
+
+  if (where)
+    {
+      *where = '\0';
+      which = where + 1;
+
+      where = strchr (which, ' ');
+      if (where)
+	*where = '\0';
+
+      where = args;
+    }
+  else
+    {
+      *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
+      return NULL;
+    }
+
+  *r_err = atoi (which);
+
+  return where;
+}
+
+
 static gpgme_error_t
 genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
 {
@@ -90,6 +124,7 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
   gpgme_error_t err;
   void *hook;
   op_data_t opd;
+  char *loc;
 
   /* Pipe the status code through the progress status handler.  */
   err = _gpgme_progress_status_handler (ctx, code, args);
@@ -121,13 +156,22 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
 	}
       break;
 
+    case GPGME_STATUS_ERROR:
+      loc = parse_error (args, &err);
+      if (!loc)
+        return err;
+      if (!opd->error_code)
+        opd->error_code = err;
+      break;
+
     case GPGME_STATUS_FAILURE:
       opd->failure_code = _gpgme_parse_failure (args);
       break;
 
     case GPGME_STATUS_EOF:
-      /* FIXME: Should return some more useful error value.  */
-      if (!opd->result.primary && !opd->result.sub)
+      if (opd->error_code)
+        return opd->error_code;
+      else if (!opd->result.primary && !opd->result.sub)
 	return gpg_error (GPG_ERR_GENERAL);
       else if (opd->failure_code)
         return opd->failure_code;
@@ -212,7 +256,9 @@ genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms,
         return err;
     }
 
-  return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter,
+  return _gpgme_engine_op_genkey (ctx->engine,
+                                  NULL, NULL, 0, 0, NULL, 0,
+                                  opd->key_parameter,
 				  ctx->use_armor, pubkey, seckey);
 }
 
@@ -259,3 +305,85 @@ gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, gpgme_data_t pubkey,
     err = _gpgme_wait_one (ctx);
   return TRACE_ERR (err);
 }
+
+
+

+static gpgme_error_t
+createkey_start (gpgme_ctx_t ctx, int synchronous,
+                 const char *userid, const char *algo,
+                 unsigned long reserved, unsigned long expires,
+                 gpgme_key_t anchorkey, unsigned int flags)
+{
+  gpgme_error_t err;
+  void *hook;
+  op_data_t opd;
+
+  err = _gpgme_op_reset (ctx, synchronous);
+  if (err)
+    return err;
+
+  if (reserved || anchorkey || !userid)
+    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,
+                                  userid, algo, reserved, expires,
+                                  anchorkey, flags,
+                                  NULL, ctx->use_armor, NULL, NULL);
+
+}
+
+
+gpgme_error_t
+gpgme_op_createkey_start (gpgme_ctx_t ctx, const char *userid, const char *algo,
+                          unsigned long reserved, unsigned long expires,
+                          gpgme_key_t anchorkey, unsigned int flags)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createkey_start", ctx,
+	      "userid='%s', algo='%s' flags=0x%x", userid, algo, flags);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = createkey_start (ctx, 0,
+                         userid, algo, reserved, expires, anchorkey, flags);
+  return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_createkey (gpgme_ctx_t ctx, const char *userid, const char *algo,
+                    unsigned long reserved, unsigned long expires,
+                    gpgme_key_t anchorkey, unsigned int flags)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createkey", ctx,
+	      "userid='%s', algo='%s' flags=0x%x", userid, algo, flags);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = createkey_start (ctx, 1,
+                         userid, algo, reserved, expires, anchorkey, flags);
+  if (!err)
+    err = _gpgme_wait_one (ctx);
+  return TRACE_ERR (err);
+}
diff --git a/src/gpgme.def b/src/gpgme.def
index a15c35b..a56b9ef 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -229,5 +229,8 @@ EXPORTS
 
     gpgme_data_set_flag                   @171
 
+    gpgme_op_createkey_start              @172
+    gpgme_op_createkey                    @173
+
 ; END
 
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 00a4bed..0fdc927 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1815,6 +1815,18 @@ gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx,
  * Key generation.
  */
 
+/* Flags for the key creation functions.  */
+#define GPGME_CREATE_SIGN       (1 << 0)  /* Allow usage: signing.     */
+#define GPGME_CREATE_ENCR       (1 << 1)  /* Allow usage: encryption.  */
+#define GPGME_CREATE_CERT       (1 << 2)  /* Allow usage: certification.  */
+#define GPGME_CREATE_AUTH       (1 << 3)  /* Allow usage: authentication.  */
+#define GPGME_CREATE_NOPASSWD   (1 << 7)  /* Create w/o passphrase.    */
+#define GPGME_CREATE_SELFSIGNED (1 << 8)  /* Create self-signed cert.  */
+#define GPGME_CREATE_NOSTORE    (1 << 9)  /* Do not store the key.     */
+#define GPGME_CREATE_WANTPUB    (1 << 10) /* Return the public key.    */
+#define GPGME_CREATE_WANTSEC    (1 << 11) /* Return the secret key.    */
+#define GPGME_CREATE_FORCE      (1 << 12) /* Force creation.           */
+
 struct _gpgme_op_genkey_result
 {
   /* A primary key was generated.  */
@@ -1828,6 +1840,14 @@ struct _gpgme_op_genkey_result
 
   /* The fingerprint of the generated key.  */
   char *fpr;
+
+  /* A memory data object with the created public key.  Only set when
+   * GPGME_CREATE_WANTPUB has been used. */
+  gpgme_data_t pubkey;
+
+  /* A memory data object with the created secret key.  Only set when
+   * GPGME_CREATE_WANTSEC has been used. */
+  gpgme_data_t seckey;
 };
 typedef struct _gpgme_op_genkey_result *gpgme_genkey_result_t;
 
@@ -1839,7 +1859,39 @@ gpgme_error_t gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
 gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms,
 			       gpgme_data_t pubkey, gpgme_data_t seckey);
 
-/* Retrieve a pointer to the result of the genkey operation.  */
+/* Generate a key pair using the modern interface.  */
+gpgme_error_t gpgme_op_createkey_start (gpgme_ctx_t ctx,
+                                        const char *userid,
+                                        const char *algo,
+                                        unsigned long reserved,
+                                        unsigned long expires,
+                                        gpgme_key_t certkey,
+                                        unsigned int flags);
+gpgme_error_t gpgme_op_createkey       (gpgme_ctx_t ctx,
+                                        const char *userid,
+                                        const char *algo,
+                                        unsigned long reserved,
+                                        unsigned long expires,
+                                        gpgme_key_t certkey,
+                                        unsigned int flags);
+/* Add a new subkey to 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 gpgme_op_createsubkey       (gpgme_ctx_t ctx,
+                                           gpgme_key_t key,
+                                           const char *algo,
+                                           unsigned long reserved,
+                                           unsigned long expires,
+                                           unsigned int flags);
+
+
+
+/* Retrieve a pointer to the result of a genkey, createkey, or
+ * createsubkey operation.  */
 gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx);
 
 
@@ -2177,7 +2229,7 @@ typedef struct gpgme_conf_arg
 } *gpgme_conf_arg_t;
 
 
-/* The flags of a configuration option.  See the gpg-conf
+/* The flags of a configuration option.  See the gpgconf
    documentation for details.  */
 #define GPGME_CONF_GROUP	(1 << 0)
 #define GPGME_CONF_OPTIONAL	(1 << 1)
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index d29bc14..b06c9c6 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -101,6 +101,10 @@ GPGME_1.1 {
 
     gpgme_pubkey_algo_string;
     gpgme_set_ctx_flag;
+    gpgme_data_set_flag;
+
+    gpgme_op_createkey_start;
+    gpgme_op_createkey;
 };
 
 
@@ -230,8 +234,6 @@ GPGME_1.0 {
     gpgme_err_code_from_syserror;
     gpgme_err_set_errno;
 
-    gpgme_data_set_flag;
-
   local:
     *;
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a450f2a..f3a1604 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -32,7 +32,7 @@ LDADD = ../src/libgpgme.la @GPG_ERROR_LIBS@
 noinst_HEADERS = run-support.h
 
 noinst_PROGRAMS = $(TESTS) run-keylist run-export run-import run-sign \
-		  run-verify run-encrypt run-identify run-decrypt
+		  run-verify run-encrypt run-identify run-decrypt run-genkey
 
 
 if RUN_GPG_TESTS
diff --git a/tests/run-genkey.c b/tests/run-genkey.c
new file mode 100644
index 0000000..74d4038
--- /dev/null
+++ b/tests/run-genkey.c
@@ -0,0 +1,348 @@
+/* run-genkey.c  - Test tool to perform key generation
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* We need to include config.h so that we know whether we are building
+   with large file system (LFS) support. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <gpgme.h>
+
+#define PGM "run-genkey"
+
+#include "run-support.h"
+
+
+static int verbose;
+
+
+/* Tokenize STRING using the set of delimiters in DELIM.  Leading
+ * spaces and tabs are removed from all tokens.  The caller must free
+ * the result.
+ *
+ * Returns: A malloced and NULL delimited array with the tokens.  On
+ *          memory error NULL is returned and ERRNO is set.
+ */
+static char **
+strtokenize (const char *string, const char *delim)
+{
+  const char *s;
+  size_t fields;
+  size_t bytes, n;
+  char *buffer;
+  char *p, *px, *pend;
+  char **result;
+
+  /* Count the number of fields.  */
+  for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim))
+    fields++;
+  fields++; /* Add one for the terminating NULL.  */
+
+  /* Allocate an array for all fields, a terminating NULL, and space
+     for a copy of the string.  */
+  bytes = fields * sizeof *result;
+  if (bytes / sizeof *result != fields)
+    {
+      gpg_err_set_errno (ENOMEM);
+      return NULL;
+    }
+  n = strlen (string) + 1;
+  bytes += n;
+  if (bytes < n)
+    {
+      gpg_err_set_errno (ENOMEM);
+      return NULL;
+    }
+  result = malloc (bytes);
+  if (!result)
+    return NULL;
+  buffer = (char*)(result + fields);
+
+  /* Copy and parse the string.  */
+  strcpy (buffer, string);
+  for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1)
+    {
+      *pend = 0;
+      while (*p == ' ' || *p == '\t')
+        p++;
+      for (px = pend - 1; px >= p && (*px == ' ' || *px == '\t'); px--)
+        *px = 0;
+      result[n++] = p;
+    }
+  while (*p == ' ' || *p == '\t')
+    p++;
+  for (px = p + strlen (p) - 1; px >= p && (*px == ' ' || *px == '\t'); px--)
+    *px = 0;
+  result[n++] = p;
+  result[n] = NULL;
+
+  assert ((char*)(result + n + 1) == buffer);
+
+  return result;
+}
+
+
+static gpg_error_t
+status_cb (void *opaque, const char *keyword, const char *value)
+{
+  (void)opaque;
+  fprintf (stderr, "status_cb: %s %s\n", nonnull(keyword), nonnull(value));
+  return 0;
+}
+
+
+static void
+progress_cb (void *opaque, const char *what, int type, int current, int total)
+{
+  (void)opaque;
+  (void)type;
+
+  if (total)
+    fprintf (stderr, "progress for '%s' %u%% (%d of %d)\n",
+             nonnull (what),
+             (unsigned)(((double)current / total) * 100), current, total);
+  else
+    fprintf (stderr, "progress for '%s' %d\n", nonnull(what), current);
+  fflush (stderr);
+}
+
+
+static unsigned long
+parse_expire_string (const char *string)
+{
+  unsigned long seconds;
+
+  if (!string || !*string || !strcmp (string, "none")
+      || !strcmp (string, "never") || !strcmp (string, "-"))
+    seconds = 0;
+  else if (strspn (string, "01234567890") == strlen (string))
+    seconds = strtoul (string, NULL, 10);
+  else
+    {
+      fprintf (stderr, PGM ": invalid value '%s'\n", string);
+      exit (1);
+    }
+
+  return seconds;
+}
+
+
+/* Parse a usage string and return flags for gpgme_op_createkey.  */
+static unsigned int
+parse_usage_string (const char *string)
+{
+  gpg_error_t err;
+  char **tokens = NULL;
+  const char *s;
+  int i;
+  unsigned int flags = 0;
+
+  tokens = strtokenize (string, " \t,");
+  if (!tokens)
+    {
+      err = gpg_error_from_syserror ();
+      fprintf (stderr, PGM": strtokenize failed: %s\n", gpg_strerror (err));
+      exit (1);
+    }
+
+  for (i=0; (s = tokens[i]); i++)
+    {
+      if (!*s)
+        ;
+      else if (!strcmp (s, "default"))
+        ;
+      else if (!strcmp (s, "sign"))
+        flags |= GPGME_CREATE_SIGN;
+      else if (!strcmp (s, "encr"))
+        flags |= GPGME_CREATE_ENCR;
+      else if (!strcmp (s, "cert"))
+        flags |= GPGME_CREATE_CERT;
+      else if (!strcmp (s, "auth"))
+        flags |= GPGME_CREATE_AUTH;
+      else
+        {
+          free (tokens);
+          fprintf (stderr, PGM": invalid value '%s': %s\n",
+                   string, "bad usage");
+          exit (1);
+        }
+    }
+
+  free (tokens);
+  return flags;
+}
+
+
+
+static int
+show_usage (int ex)
+{
+  fputs ("usage: " PGM " [options] USERID [ALGO [USAGE [EXPIRESECONDS]]]\n\n"
+         "Options:\n"
+         "  --verbose        run in verbose mode\n"
+         "  --status         print status lines from the backend\n"
+         "  --progress       print progress info\n"
+         "  --openpgp        use the OpenPGP protocol (default)\n"
+         "  --cms            use the CMS protocol\n"
+         "  --loopback       use a loopback pinentry\n"
+         "  --unprotected    do not use a passphrase\n"
+         "  --force          do not check for a duplicated user id\n"
+         , stderr);
+  exit (ex);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  gpgme_error_t err;
+  gpgme_ctx_t ctx;
+  gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
+  int print_status = 0;
+  int print_progress = 0;
+  int use_loopback = 0;
+  const char *userid;
+  const char *algo = NULL;
+  unsigned int flags = 0;
+  unsigned long expire = 0;
+  gpgme_genkey_result_t result;
+
+  if (argc)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        show_usage (0);
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--status"))
+        {
+          print_status = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--progress"))
+        {
+          print_progress = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--openpgp"))
+        {
+          protocol = GPGME_PROTOCOL_OpenPGP;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--cms"))
+        {
+          protocol = GPGME_PROTOCOL_CMS;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--loopback"))
+        {
+          use_loopback = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--unprotected"))
+        {
+          flags |= GPGME_CREATE_NOPASSWD;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--force"))
+        {
+          flags |= GPGME_CREATE_FORCE;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        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]);
+
+  init_gpgme (protocol);
+
+  err = gpgme_new (&ctx);
+  fail_if_err (err);
+  gpgme_set_protocol (ctx, protocol);
+  gpgme_set_armor (ctx, 1);
+  if (print_status)
+    {
+      gpgme_set_status_cb (ctx, status_cb, NULL);
+      gpgme_set_ctx_flag (ctx, "full-status", "1");
+    }
+  if (print_progress)
+    gpgme_set_progress_cb (ctx, progress_cb, NULL);
+  if (use_loopback)
+    {
+      gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
+      gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
+    }
+
+  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);
+  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");
+
+  gpgme_release (ctx);
+  return 0;
+}

-----------------------------------------------------------------------

Summary of changes:
 NEWS                 |  13 ++
 src/engine-backend.h |   6 +-
 src/engine-gpg.c     | 162 ++++++++++++++++++++++--
 src/engine-gpgsm.c   |  50 +++++---
 src/engine.c         |  10 +-
 src/engine.h         |   4 +
 src/export.c         |   2 +-
 src/genkey.c         | 172 +++++++++++++++++++++----
 src/gpgme.def        |   3 +
 src/gpgme.h.in       |  56 ++++++++-
 src/libgpgme.vers    |   6 +-
 tests/Makefile.am    |   2 +-
 tests/run-genkey.c   | 348 +++++++++++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 775 insertions(+), 59 deletions(-)
 create mode 100644 tests/run-genkey.c


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list