[git] GPGME - branch, master, updated. gpgme-1.6.0-362-gd79dcb7

by Werner Koch cvs at cvs.gnupg.org
Wed Sep 14 19:05:50 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  d79dcb78d867aaf55b85aea117c4ae6035a1531a (commit)
       via  bfd2bd0ccc9fed8284ef932ac788d4ca0dba0336 (commit)
      from  594c3b8b052e60b6be77ed532fe46549133a9726 (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 d79dcb78d867aaf55b85aea117c4ae6035a1531a
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Sep 14 19:02:40 2016 +0200

    core: Defer implementation of gpgme_op_createkey with gpg < 2.1
    
    * src/engine-gpg.c (gpg_createkey_legacy): Mark unused variables.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index dc0906d..ac85c4d 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -2056,6 +2056,12 @@ gpg_createkey_legacy (engine_gpg_t gpg,
                unsigned int flags,
                unsigned int extraflags)
 {
+  (void)gpg;
+  (void)userid;
+  (void)algo;
+  (void)expires;
+  (void)flags;
+  (void)extraflags;
   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 }
 

commit bfd2bd0ccc9fed8284ef932ac788d4ca0dba0336
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Sep 14 18:44:33 2016 +0200

    core: New function gpgme_op_keysign.
    
    * src/gpgme.h.in (gpgme_op_keysign_start, gpgme_op_keysign): New.
    (GPGME_KEYSIGN_LOCAL): New.
    (GPGME_KEYSIGN_LFSEP): New.
    (GPGME_KEYSIGN_NOEXPIRE): New.
    * src/context.h (ctx_op_data_id_t): Add OPDATA_KEYSIGN.
    * src/keysign.c: New.
    * src/Makefile.am (main_sources): Add keysig.
    * src/libgpgme.vers, src/gpgme.def: Add gpgme_op_keysign_start.
    * src/engine.c (_gpgme_engine_op_keysign): New.
    * src/engine-backend.h (engine_ops): Add 'keysign' and adjust all
    engine initializers.
    * src/engine-gpg.c (_add_arg): Add args PREFIX and ARGLEN and change
    callers to set them.
    (add_arg_pfx): New.
    (add_arg_len): New.
    (gpg_keysign): New.
    (_gpgme_engine_ops_gpg): Set keysign to gpg_keysign.
    * tests/run-keysign.c: New.
    * tests/Makefile.am (noinst_PROGRAMS): Add run-keysign.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 10296ff..fd9b20c 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,8 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  gpgme_op_adduid                NEW.
  gpgme_op_revuid_start          NEW.
  gpgme_op_revuid                NEW.
+ gpgme_op_keysign_start         NEW.
+ gpgme_op_keysign               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.
@@ -50,6 +52,8 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  GPGME_CREATE_WANTPUB           NEW.
  GPGME_CREATE_WANTSEC           NEW.
  GPGME_CREATE_FORCE             NEW.
+ GPGME_KEYSIGN_LOCAL            NEW.
+ GPGME_KEYSIGN_LFSEP            NEW.
 
 
 Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0]
diff --git a/src/Makefile.am b/src/Makefile.am
index d541f87..39752b3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -84,7 +84,7 @@ main_sources =								\
 	op-support.c							\
 	encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c	\
 	sign.c passphrase.c progress.c					\
-	key.c keylist.c trust-item.c trustlist.c			\
+	key.c keylist.c keysign.c trust-item.c trustlist.c		\
 	import.c export.c genkey.c delete.c edit.c getauditlog.c        \
 	opassuan.c passwd.c spawn.c assuan-support.c                    \
 	engine.h engine-backend.h engine.c engine-gpg.c status-table.c	\
diff --git a/src/context.h b/src/context.h
index de69a7a..c099d66 100644
--- a/src/context.h
+++ b/src/context.h
@@ -38,7 +38,7 @@ typedef enum
     OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,
     OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
     OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
-    OPDATA_PASSWD, OPDATA_EXPORT
+    OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN
   } ctx_op_data_id_t;
 
 
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index 5f0ea06..6f11cc0 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -775,6 +775,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
     NULL,               /* import */
     NULL,               /* keylist */
     NULL,               /* keylist_ext */
+    NULL,               /* keysign */
     NULL,               /* sign */
     NULL,		/* trustlist */
     NULL,               /* verify */
diff --git a/src/engine-backend.h b/src/engine-backend.h
index ec1a58c..ed3e303 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -98,6 +98,10 @@ struct engine_ops
 				int secret_only, int reserved,
 				gpgme_keylist_mode_t mode,
 				int engine_flags);
+  gpgme_error_t (*keysign) (void *engine,
+                            gpgme_key_t key, const char *userid,
+                            unsigned long expires, unsigned int flags,
+                            gpgme_ctx_t ctx);
   gpgme_error_t (*sign) (void *engine, gpgme_data_t in, gpgme_data_t out,
 			 gpgme_sig_mode_t mode, int use_armor,
 			 int use_textmode, int include_certs,
diff --git a/src/engine-g13.c b/src/engine-g13.c
index 7f225eb..0da00f7 100644
--- a/src/engine-g13.c
+++ b/src/engine-g13.c
@@ -792,6 +792,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
     NULL,               /* import */
     NULL,               /* keylist */
     NULL,               /* keylist_ext */
+    NULL,               /* keysign */
     NULL,               /* sign */
     NULL,		/* trustlist */
     NULL,               /* verify */
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index 534d5d1..dc0906d 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -206,14 +206,16 @@ close_notify_handler (int fd, void *opaque)
 /* If FRONT is true, push at the front of the list.  Use this for
    options added late in the process.  */
 static gpgme_error_t
-_add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
+_add_arg (engine_gpg_t gpg, const char *prefix, const char *arg, size_t arglen,
+          int front, int *arg_locp)
 {
   struct arg_and_data_s *a;
+  size_t prefixlen = prefix? strlen (prefix) : 0;
 
   assert (gpg);
   assert (arg);
 
-  a = malloc (sizeof *a + strlen (arg));
+  a = malloc (sizeof *a + prefixlen + arglen);
   if (!a)
     return gpg_error_from_syserror ();
 
@@ -221,7 +223,10 @@ _add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
   a->dup_to = -1;
   a->arg_locp = arg_locp;
 
-  strcpy (a->arg, arg);
+  if (prefixlen)
+    memcpy (a->arg, prefix, prefixlen);
+  memcpy (a->arg + prefixlen, arg, arglen);
+  a->arg[prefixlen + arglen] = 0;
   if (front)
     {
       a->next = gpg->arglist;
@@ -243,24 +248,36 @@ _add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
   return 0;
 }
 
+
 static gpgme_error_t
 add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
 {
-  return _add_arg (gpg, arg, front, NULL);
+  return _add_arg (gpg, NULL, arg, strlen (arg), front, NULL);
 }
 
-
 static gpgme_error_t
 add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
 {
-  return _add_arg (gpg, arg, 0, locp);
+  return _add_arg (gpg, NULL, arg, strlen (arg), 0, locp);
 }
 
-
 static gpgme_error_t
 add_arg (engine_gpg_t gpg, const char *arg)
 {
-  return add_arg_ext (gpg, arg, 0);
+  return _add_arg (gpg, NULL, arg, strlen (arg), 0, NULL);
+}
+
+static gpgme_error_t
+add_arg_pfx (engine_gpg_t gpg, const char *prefix, const char *arg)
+{
+  return _add_arg (gpg, prefix, arg, strlen (arg), 0, NULL);
+}
+
+static gpgme_error_t
+add_arg_len (engine_gpg_t gpg, const char *prefix,
+             const char *arg, size_t arglen)
+{
+  return _add_arg (gpg, prefix, arg, arglen, 0, NULL);
 }
 
 
@@ -1606,7 +1623,8 @@ append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
 	    err = add_arg (gpg, s);
 	}
       gpgme_key_unref (key);
-      if (err) break;
+      if (err)
+        break;
     }
   return err;
 }
@@ -2644,6 +2662,71 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
 
 
 static gpgme_error_t
+gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
+             unsigned long expire, unsigned int flags,
+             gpgme_ctx_t ctx)
+{
+  engine_gpg_t gpg = engine;
+  gpgme_error_t err;
+  const char *s;
+
+  if (!key || !key->fpr)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (!have_gpg_version (gpg, "2.1.12"))
+    return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+  if ((flags & GPGME_KEYSIGN_LOCAL))
+    err = add_arg (gpg, "--quick-lsign-key");
+  else
+    err = add_arg (gpg, "--quick-sign-key");
+
+  if (!err)
+    err = append_args_from_signers (gpg, ctx);
+
+  /* If an expiration time has been given use that.  If none has been
+   * given the default from gpg.conf is used.  To make sure not to set
+   * an expiration time at all the flag GPGME_KEYSIGN_NOEXPIRE can be
+   * used.  */
+  if (!err && (expire || (flags & GPGME_KEYSIGN_NOEXPIRE)))
+    {
+      char tmpbuf[8+20];
+
+      if ((flags & GPGME_KEYSIGN_NOEXPIRE))
+        expire = 0;
+      snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expire);
+      err = add_arg (gpg, "--default-cert-expire");
+      if (!err)
+        err = add_arg (gpg, tmpbuf);
+    }
+
+  if (!err)
+    err = add_arg (gpg, "--");
+
+  if (!err)
+    err = add_arg (gpg, key->fpr);
+  if (!err && userid)
+    {
+      if ((flags & GPGME_KEYSIGN_LFSEP))
+        {
+          for (; !err && (s = strchr (userid, '\n')); userid = s + 1)
+            if ((s - userid))
+              err = add_arg_len (gpg, "=", userid, s - userid);
+          if (!err && *userid)
+            err = add_arg_pfx (gpg, "=", userid);
+        }
+      else
+        err = add_arg_pfx (gpg, "=", userid);
+    }
+
+  if (!err)
+    err = start (gpg);
+
+  return err;
+}
+
+
+static gpgme_error_t
 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
 	  gpgme_sig_mode_t mode, int use_armor, int use_textmode,
 	  int include_certs, gpgme_ctx_t ctx /* FIXME */)
@@ -2816,6 +2899,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
     gpg_import,
     gpg_keylist,
     gpg_keylist_ext,
+    gpg_keysign,
     gpg_sign,
     gpg_trustlist,
     gpg_verify,
diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
index 015ef00..8be76cb 100644
--- a/src/engine-gpgconf.c
+++ b/src/engine-gpgconf.c
@@ -957,6 +957,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
     NULL,		/* import */
     NULL,		/* keylist */
     NULL,		/* keylist_ext */
+    NULL,               /* keysign */
     NULL,		/* sign */
     NULL,		/* trustlist */
     NULL,		/* verify */
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index 071626a..aae9d28 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -2074,6 +2074,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
     gpgsm_import,
     gpgsm_keylist,
     gpgsm_keylist_ext,
+    NULL,               /* keysign */
     gpgsm_sign,
     NULL,		/* trustlist */
     gpgsm_verify,
diff --git a/src/engine-spawn.c b/src/engine-spawn.c
index e2ee8ba..82dbc0b 100644
--- a/src/engine-spawn.c
+++ b/src/engine-spawn.c
@@ -460,6 +460,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
     NULL,		/* import */
     NULL,		/* keylist */
     NULL,		/* keylist_ext */
+    NULL,               /* keysign */
     NULL,		/* sign */
     NULL,		/* trustlist */
     NULL,		/* verify */
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index 2817527..827c347 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -1364,6 +1364,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
     NULL,		/* import */
     NULL,		/* keylist */
     NULL,		/* keylist_ext */
+    NULL,               /* keysign */
     uiserver_sign,
     NULL,		/* trustlist */
     uiserver_verify,
diff --git a/src/engine.c b/src/engine.c
index b3bbcab..47bb23c 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -795,6 +795,22 @@ _gpgme_engine_op_genkey (engine_t engine,
 
 
 gpgme_error_t
+_gpgme_engine_op_keysign (engine_t engine, gpgme_key_t key, const char *userid,
+                          unsigned long expires, unsigned int flags,
+                          gpgme_ctx_t ctx)
+{
+  if (!engine)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (!engine->ops->keysign)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+  return (*engine->ops->keysign) (engine->engine,
+                                  key, userid, expires, flags, ctx);
+}
+
+
+gpgme_error_t
 _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
                          gpgme_key_t *keyarray)
 {
diff --git a/src/engine.h b/src/engine.h
index eb37da8..6f33835 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -121,6 +121,11 @@ gpgme_error_t _gpgme_engine_op_genkey (engine_t engine,
 				       unsigned int extraflags,
                                        gpgme_data_t pubkey,
 				       gpgme_data_t seckey);
+gpgme_error_t _gpgme_engine_op_keysign (engine_t engine,
+                                        gpgme_key_t key, const char *userid,
+                                        unsigned long expires,
+                                        unsigned int flags,
+                                        gpgme_ctx_t ctx);
 gpgme_error_t _gpgme_engine_op_import (engine_t engine,
 				       gpgme_data_t keydata,
                                        gpgme_key_t *keyarray);
diff --git a/src/gpgme.def b/src/gpgme.def
index 4c7ff41..f987b38 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -237,6 +237,8 @@ EXPORTS
     gpgme_op_adduid                       @177
     gpgme_op_revuid_start                 @178
     gpgme_op_revuid                       @179
+    gpgme_op_keysign_start                @180
+    gpgme_op_keysign                      @181
 
 ; END
 
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index a26b432..121e2ce 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1921,10 +1921,32 @@ gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key,
 gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key,
 			       int allow_secret);
 
+

+/*
+ * Key signing interface
+ */
+
+/* Flags for the key signing functions.  */
+#define GPGME_KEYSIGN_LOCAL     (1 << 7)  /* Create a local signature.  */
+#define GPGME_KEYSIGN_LFSEP     (1 << 8)  /* Indicate LF separated user ids. */
+#define GPGME_KEYSIGN_NOEXPIRE  (1 << 9)  /* Force no expiration.  */
+
+
+/* Sign the USERID of KEY using the current set of signers.  */
+gpgme_error_t gpgme_op_keysign_start (gpgme_ctx_t ctx,
+                                      gpgme_key_t key, const char *userid,
+                                      unsigned long expires,
+                                      unsigned int flags);
+gpgme_error_t gpgme_op_keysign       (gpgme_ctx_t ctx,
+                                      gpgme_key_t key, const char *userid,
+                                      unsigned long expires,
+                                      unsigned int flags);
+
+
 
 

 /*
- * Key Edit interface
+ * Key edit interface
  */
 
 /* Edit the key KEY.  Send status and command requests to FNC and
diff --git a/src/keysign.c b/src/keysign.c
new file mode 100644
index 0000000..7d08c11
--- /dev/null
+++ b/src/keysign.c
@@ -0,0 +1,218 @@
+/* keysign.c - OpenPGP key signing
+ * 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/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "debug.h"
+#include "context.h"
+#include "ops.h"
+#include "util.h"
+
+

+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;
+
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+  op_data_t opd = (op_data_t) hook;
+
+  (void)opd;
+}
+
+
+/* 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
+keysign_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+  gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+  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);
+  if (err)
+    return err;
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook, -1, NULL);
+  opd = hook;
+  if (err)
+    return err;
+
+  switch (code)
+    {
+    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:
+      if (opd->error_code)
+        return opd->error_code;
+      else if (opd->failure_code)
+        return opd->failure_code;
+      break;
+
+    case GPGME_STATUS_INQUIRE_MAXLEN:
+      if (ctx->status_cb && !ctx->full_status)
+        {
+          err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
+          if (err)
+            return err;
+        }
+      break;
+
+    default:
+      break;
+    }
+  return 0;
+}
+
+
+/* Sign the USERID of KEY using the current set of signers.  If USERID
+ * is NULL, sign all user ids.  To put several user ids into USERID,
+ * separate them by LF and set the flag GPGME_KEYSIGN_LFSEP.  */
+static gpgme_error_t
+keysign_start (gpgme_ctx_t ctx, int synchronous,
+               gpgme_key_t key, const char *userid,
+               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 (!key)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook,
+			       sizeof (*opd), release_op_data);
+  opd = hook;
+  if (err)
+    return err;
+
+  _gpgme_engine_set_status_handler (ctx->engine, keysign_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_keysign (ctx->engine,
+                                   key, userid, expires, flags, ctx);
+}
+
+
+/* Sign the USERID of KEY using the current set of signers.  */
+gpgme_error_t
+gpgme_op_keysign_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
+                        unsigned long expires, unsigned int flags)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign_start", ctx,
+	      "key=%p, uid='%s' flags=0x%x", key, userid, flags);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+  err = keysign_start (ctx, 0, key, userid, expires, flags);
+  return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_keysign (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
+                  unsigned long expires, unsigned int flags)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign", ctx,
+	      "key=%p, uid='%s' flags=0x%x", key, userid, flags);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+  err = keysign_start (ctx, 1, key, userid, expires, flags);
+  if (!err)
+    err = _gpgme_wait_one (ctx);
+  return TRACE_ERR (err);
+}
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index 8193ee4..d86eee8 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -111,6 +111,8 @@ GPGME_1.1 {
     gpgme_op_adduid;
     gpgme_op_revuid_start;
     gpgme_op_revuid;
+    gpgme_op_keysign_start;
+    gpgme_op_keysign;
 };
 
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f3a1604..1370efd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -32,7 +32,8 @@ 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-genkey
+		  run-verify run-encrypt run-identify run-decrypt run-genkey \
+		  run-keysign
 
 
 if RUN_GPG_TESTS
diff --git a/tests/run-keysign.c b/tests/run-keysign.c
new file mode 100644
index 0000000..f5a13e4
--- /dev/null
+++ b/tests/run-keysign.c
@@ -0,0 +1,261 @@
+/* run-keysign.c  - Test tool to sign a key
+ * 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-keysign"
+
+#include "run-support.h"
+
+
+static int verbose;
+
+
+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 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;
+}
+
+
+
+static int
+show_usage (int ex)
+{
+  fputs ("usage: " PGM " [options] FPR USERIDS\n\n"
+         "Options:\n"
+         "  --verbose        run in verbose mode\n"
+         "  --status         print status lines from the backend\n"
+         "  --loopback       use a loopback pinentry\n"
+         "  --signer NAME    use key NAME for signing\n"
+         "  --local          create a local signature\n"
+         "  --noexpire       force no expiration\n"
+         "  --expire EPOCH   expire the signature at EPOCH\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;
+  const char *signer_string = NULL;
+  int print_status = 0;
+  int use_loopback = 0;
+  const char *userid;
+  unsigned int flags = 0;
+  unsigned long expire = 0;
+  gpgme_key_t thekey;
+  int i;
+  size_t n;
+  char *userid_buffer = NULL;
+
+  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, "--signer"))
+        {
+          argc--; argv++;
+          if (!argc)
+            show_usage (1);
+          signer_string = *argv;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--loopback"))
+        {
+          use_loopback = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--local"))
+        {
+          flags |= GPGME_KEYSIGN_LOCAL;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--noexpire"))
+        {
+          flags |= GPGME_KEYSIGN_NOEXPIRE;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--expire"))
+        {
+          argc--; argv++;
+          if (!argc)
+            show_usage (1);
+          expire = parse_expire_string (*argv);
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        show_usage (1);
+    }
+
+  if (!argc)
+    show_usage (1);
+  userid = argv[0];
+  argc--; argv++;
+
+  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 (use_loopback)
+    {
+      gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
+      gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
+    }
+
+  if (signer_string)
+    {
+      gpgme_key_t akey;
+
+      err = gpgme_get_key (ctx, signer_string, &akey, 1);
+      if (err)
+        {
+          fprintf (stderr, PGM ": error getting signer key '%s': %s\n",
+                   signer_string, gpg_strerror (err));
+          exit (1);
+        }
+      err = gpgme_signers_add (ctx, akey);
+      if (err)
+        {
+          fprintf (stderr, PGM ": error adding signer key: %s\n",
+                   gpg_strerror (err));
+          exit (1);
+        }
+      gpgme_key_unref (akey);
+    }
+
+
+  err = gpgme_get_key (ctx, userid, &thekey, 0);
+  if (err)
+    {
+      fprintf (stderr, PGM ": error getting key for '%s': %s\n",
+               userid, gpg_strerror (err));
+      exit (1);
+    }
+
+  if (argc > 1)
+    {
+      /* Several user ids given  */
+      for (i=0, n = 0; i < argc; i++)
+        n += strlen (argv[1]) + 1;
+      n++;
+      userid_buffer = malloc (n);
+      if (!userid_buffer)
+        {
+          fprintf (stderr, PGM ": malloc failed: %s\n",
+                   gpg_strerror (gpg_error_from_syserror ()));
+          exit (1);
+        }
+      *userid_buffer = 0;
+      for (i=0; i < argc; i++)
+        {
+          strcat (userid_buffer, argv[i]);
+          strcat (userid_buffer, "\n");
+        }
+      userid = userid_buffer;
+      flags |= GPGME_KEYSIGN_LFSEP;
+    }
+  else if (argc)
+    {
+      /* One user id given  */
+      userid = *argv;
+    }
+  else
+    {
+      /* No user id given.  */
+      userid = NULL;
+    }
+
+  err = gpgme_op_keysign (ctx, thekey, userid, expire, flags);
+  if (err)
+    {
+      fprintf (stderr, PGM ": gpgme_op_adduid failed: %s\n",
+               gpg_strerror (err));
+      exit (1);
+    }
+
+  free (userid_buffer);
+  gpgme_key_unref (thekey);
+  gpgme_release (ctx);
+  return 0;
+}

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

Summary of changes:
 NEWS                  |   4 +
 src/Makefile.am       |   2 +-
 src/context.h         |   2 +-
 src/engine-assuan.c   |   1 +
 src/engine-backend.h  |   4 +
 src/engine-g13.c      |   1 +
 src/engine-gpg.c      | 108 +++++++++++++++++++--
 src/engine-gpgconf.c  |   1 +
 src/engine-gpgsm.c    |   1 +
 src/engine-spawn.c    |   1 +
 src/engine-uiserver.c |   1 +
 src/engine.c          |  16 ++++
 src/engine.h          |   5 +
 src/gpgme.def         |   2 +
 src/gpgme.h.in        |  24 ++++-
 src/keysign.c         | 218 +++++++++++++++++++++++++++++++++++++++++
 src/libgpgme.vers     |   2 +
 tests/Makefile.am     |   3 +-
 tests/run-keysign.c   | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++
 19 files changed, 644 insertions(+), 13 deletions(-)
 create mode 100644 src/keysign.c
 create mode 100644 tests/run-keysign.c


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




More information about the Gnupg-commits mailing list