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_adduid NEW.
|
||||||
gpgme_op_revuid_start NEW.
|
gpgme_op_revuid_start NEW.
|
||||||
gpgme_op_revuid 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_genkey_result_t EXTENDED: New fields pubkey and seckey.
|
||||||
gpgme_signature_t EXTENDED: New field key.
|
gpgme_signature_t EXTENDED: New field key.
|
||||||
gpgme_key_t EXTENDED: New field fpr.
|
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_WANTPUB NEW.
|
||||||
GPGME_CREATE_WANTSEC NEW.
|
GPGME_CREATE_WANTSEC NEW.
|
||||||
GPGME_CREATE_FORCE 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]
|
Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0]
|
||||||
|
@ -84,7 +84,7 @@ main_sources = \
|
|||||||
op-support.c \
|
op-support.c \
|
||||||
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
|
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
|
||||||
sign.c passphrase.c progress.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 \
|
import.c export.c genkey.c delete.c edit.c getauditlog.c \
|
||||||
opassuan.c passwd.c spawn.c assuan-support.c \
|
opassuan.c passwd.c spawn.c assuan-support.c \
|
||||||
engine.h engine-backend.h engine.c engine-gpg.c status-table.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_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,
|
||||||
OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
|
OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
|
||||||
OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
|
OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
|
||||||
OPDATA_PASSWD, OPDATA_EXPORT
|
OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN
|
||||||
} ctx_op_data_id_t;
|
} ctx_op_data_id_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -775,6 +775,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
|
|||||||
NULL, /* import */
|
NULL, /* import */
|
||||||
NULL, /* keylist */
|
NULL, /* keylist */
|
||||||
NULL, /* keylist_ext */
|
NULL, /* keylist_ext */
|
||||||
|
NULL, /* keysign */
|
||||||
NULL, /* sign */
|
NULL, /* sign */
|
||||||
NULL, /* trustlist */
|
NULL, /* trustlist */
|
||||||
NULL, /* verify */
|
NULL, /* verify */
|
||||||
|
@ -98,6 +98,10 @@ struct engine_ops
|
|||||||
int secret_only, int reserved,
|
int secret_only, int reserved,
|
||||||
gpgme_keylist_mode_t mode,
|
gpgme_keylist_mode_t mode,
|
||||||
int engine_flags);
|
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_error_t (*sign) (void *engine, gpgme_data_t in, gpgme_data_t out,
|
||||||
gpgme_sig_mode_t mode, int use_armor,
|
gpgme_sig_mode_t mode, int use_armor,
|
||||||
int use_textmode, int include_certs,
|
int use_textmode, int include_certs,
|
||||||
|
@ -792,6 +792,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
|
|||||||
NULL, /* import */
|
NULL, /* import */
|
||||||
NULL, /* keylist */
|
NULL, /* keylist */
|
||||||
NULL, /* keylist_ext */
|
NULL, /* keylist_ext */
|
||||||
|
NULL, /* keysign */
|
||||||
NULL, /* sign */
|
NULL, /* sign */
|
||||||
NULL, /* trustlist */
|
NULL, /* trustlist */
|
||||||
NULL, /* verify */
|
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
|
/* If FRONT is true, push at the front of the list. Use this for
|
||||||
options added late in the process. */
|
options added late in the process. */
|
||||||
static gpgme_error_t
|
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;
|
struct arg_and_data_s *a;
|
||||||
|
size_t prefixlen = prefix? strlen (prefix) : 0;
|
||||||
|
|
||||||
assert (gpg);
|
assert (gpg);
|
||||||
assert (arg);
|
assert (arg);
|
||||||
|
|
||||||
a = malloc (sizeof *a + strlen (arg));
|
a = malloc (sizeof *a + prefixlen + arglen);
|
||||||
if (!a)
|
if (!a)
|
||||||
return gpg_error_from_syserror ();
|
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->dup_to = -1;
|
||||||
a->arg_locp = arg_locp;
|
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)
|
if (front)
|
||||||
{
|
{
|
||||||
a->next = gpg->arglist;
|
a->next = gpg->arglist;
|
||||||
@ -243,24 +248,36 @@ _add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gpgme_error_t
|
static gpgme_error_t
|
||||||
add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
|
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
|
static gpgme_error_t
|
||||||
add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
|
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
|
static gpgme_error_t
|
||||||
add_arg (engine_gpg_t gpg, const char *arg)
|
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);
|
err = add_arg (gpg, s);
|
||||||
}
|
}
|
||||||
gpgme_key_unref (key);
|
gpgme_key_unref (key);
|
||||||
if (err) break;
|
if (err)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return err;
|
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
|
static gpgme_error_t
|
||||||
gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
|
gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
|
||||||
gpgme_sig_mode_t mode, int use_armor, int use_textmode,
|
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_import,
|
||||||
gpg_keylist,
|
gpg_keylist,
|
||||||
gpg_keylist_ext,
|
gpg_keylist_ext,
|
||||||
|
gpg_keysign,
|
||||||
gpg_sign,
|
gpg_sign,
|
||||||
gpg_trustlist,
|
gpg_trustlist,
|
||||||
gpg_verify,
|
gpg_verify,
|
||||||
|
@ -957,6 +957,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
|
|||||||
NULL, /* import */
|
NULL, /* import */
|
||||||
NULL, /* keylist */
|
NULL, /* keylist */
|
||||||
NULL, /* keylist_ext */
|
NULL, /* keylist_ext */
|
||||||
|
NULL, /* keysign */
|
||||||
NULL, /* sign */
|
NULL, /* sign */
|
||||||
NULL, /* trustlist */
|
NULL, /* trustlist */
|
||||||
NULL, /* verify */
|
NULL, /* verify */
|
||||||
|
@ -2074,6 +2074,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
|
|||||||
gpgsm_import,
|
gpgsm_import,
|
||||||
gpgsm_keylist,
|
gpgsm_keylist,
|
||||||
gpgsm_keylist_ext,
|
gpgsm_keylist_ext,
|
||||||
|
NULL, /* keysign */
|
||||||
gpgsm_sign,
|
gpgsm_sign,
|
||||||
NULL, /* trustlist */
|
NULL, /* trustlist */
|
||||||
gpgsm_verify,
|
gpgsm_verify,
|
||||||
|
@ -460,6 +460,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
|
|||||||
NULL, /* import */
|
NULL, /* import */
|
||||||
NULL, /* keylist */
|
NULL, /* keylist */
|
||||||
NULL, /* keylist_ext */
|
NULL, /* keylist_ext */
|
||||||
|
NULL, /* keysign */
|
||||||
NULL, /* sign */
|
NULL, /* sign */
|
||||||
NULL, /* trustlist */
|
NULL, /* trustlist */
|
||||||
NULL, /* verify */
|
NULL, /* verify */
|
||||||
|
@ -1364,6 +1364,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
|
|||||||
NULL, /* import */
|
NULL, /* import */
|
||||||
NULL, /* keylist */
|
NULL, /* keylist */
|
||||||
NULL, /* keylist_ext */
|
NULL, /* keylist_ext */
|
||||||
|
NULL, /* keysign */
|
||||||
uiserver_sign,
|
uiserver_sign,
|
||||||
NULL, /* trustlist */
|
NULL, /* trustlist */
|
||||||
uiserver_verify,
|
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_error_t
|
||||||
_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
|
_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
|
||||||
gpgme_key_t *keyarray)
|
gpgme_key_t *keyarray)
|
||||||
|
@ -121,6 +121,11 @@ gpgme_error_t _gpgme_engine_op_genkey (engine_t engine,
|
|||||||
unsigned int extraflags,
|
unsigned int extraflags,
|
||||||
gpgme_data_t pubkey,
|
gpgme_data_t pubkey,
|
||||||
gpgme_data_t seckey);
|
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_error_t _gpgme_engine_op_import (engine_t engine,
|
||||||
gpgme_data_t keydata,
|
gpgme_data_t keydata,
|
||||||
gpgme_key_t *keyarray);
|
gpgme_key_t *keyarray);
|
||||||
|
@ -237,6 +237,8 @@ EXPORTS
|
|||||||
gpgme_op_adduid @177
|
gpgme_op_adduid @177
|
||||||
gpgme_op_revuid_start @178
|
gpgme_op_revuid_start @178
|
||||||
gpgme_op_revuid @179
|
gpgme_op_revuid @179
|
||||||
|
gpgme_op_keysign_start @180
|
||||||
|
gpgme_op_keysign @181
|
||||||
|
|
||||||
; END
|
; 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,
|
gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key,
|
||||||
int allow_secret);
|
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
|
/* 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_adduid;
|
||||||
gpgme_op_revuid_start;
|
gpgme_op_revuid_start;
|
||||||
gpgme_op_revuid;
|
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_HEADERS = run-support.h
|
||||||
|
|
||||||
noinst_PROGRAMS = $(TESTS) run-keylist run-export run-import run-sign \
|
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
|
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