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@gnupg.org>
This commit is contained in:
parent
594c3b8b05
commit
bfd2bd0ccc
4
NEWS
4
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]
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
102
src/engine-gpg.c
102
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;
|
||||
}
|
||||
@ -2643,6 +2661,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,
|
||||
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
16
src/engine.c
16
src/engine.c
@ -794,6 +794,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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
218
src/keysign.c
Normal file
218
src/keysign.c
Normal file
@ -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);
|
||||
}
|
@ -111,6 +111,8 @@ GPGME_1.1 {
|
||||
gpgme_op_adduid;
|
||||
gpgme_op_revuid_start;
|
||||
gpgme_op_revuid;
|
||||
gpgme_op_keysign_start;
|
||||
gpgme_op_keysign;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
261
tests/run-keysign.c
Normal file
261
tests/run-keysign.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user