core: New API functions gpgme_set_sender, gpgme_get_sender.

* src/context.h (struct gpgme_context): Add field 'sender'.
* src/gpgme.c: Include mbox-util.h.
(gpgme_release): Free SENDER.
(gpgme_set_sender): New.
(gpgme_get_sender): New.
* src/gpgme.def, src/libgpgme.vers: Add new functions.

* src/engine-gpg.c (append_args_from_sender): New.
(gpg_encrypt_sign, gpg_sign): Call append_args_from_sender.
(gpg_verify): Add arg CTX.  Call append_args_from_sender/
* src/engine-gpgsm.c (gpgsm_verify): Add dummy arg CTX.
* src/engine-uiserver.c (uiserver_verify): Ditto.
* src/engine.c (_gpgme_engine_op_verify): Add arg CTX.
* src/verify.c (verify_start): Pass CTX to engine function.

* tests/gpg/t-verify.c (main): Add some checks for new functions.
* tests/run-sign.c (main): Add option --sender.
* tests/run-verify.c (main): Ditto.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2016-10-25 17:27:49 +02:00
parent 26cbba3c9c
commit b8159eadb5
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
17 changed files with 234 additions and 20 deletions

6
NEWS
View File

@ -2,6 +2,12 @@ Noteworthy changes in version 1.7.2 (unreleased)
------------------------------------------------
* Interface changes relative to the 1.7.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_set_sender NEW.
gpgme_get_sender NEW.
Noteworthy changes in version 1.7.1 (2016-10-18)
------------------------------------------------

View File

@ -186,6 +186,7 @@ Context Attributes
* Protocol Selection:: Selecting the protocol used by a context.
* Crypto Engine:: Configuring the crypto engine.
* Setting the Sender:: How to tell the engine the sender.
* ASCII Armor:: Requesting @acronym{ASCII} armored output.
* Text Mode:: Choosing canonical text mode.
* Offline Mode:: Choosing offline mode.
@ -2366,6 +2367,7 @@ started. In fact, these references are accessed through the
@menu
* Protocol Selection:: Selecting the protocol used by a context.
* Crypto Engine:: Configuring the crypto engine.
* Setting the Sender:: How to tell the engine the sender.
* ASCII Armor:: Requesting @acronym{ASCII} armored output.
* Text Mode:: Choosing canonical text mode.
* Offline Mode:: Choosing offline mode.
@ -2448,6 +2450,47 @@ successful, or an eror code on failure.
@end deftypefun
@node Setting the Sender
@subsection How to tell the engine the sender.
@cindex context, sender
@cindex sender
@cindex From:
Some engines can make use of the senders address, for example to
figure out the best user id in certain trust models. For verification
and signing of mails, it is thus suggested to let the engine know the
sender ("From:") address. @acronym{GPGME} provides two functions to
accomplish that. Note that the esoteric use of multiple "From:"
addresses is not supported.
@deftypefun gpgme_error_t gpgme_set_sender @
(@w{gpgme_ctx_t @var{ctx}}, @
@w{int @var{address}})
The function @code{gpgme_set_sender} specifies the sender address for
use in sign and verify operations. @var{address} is expected to be
the ``addr-spec'' part of an address but my also be a complete mailbox
address, in which case this function extracts the ``addr-spec'' from
it. Using @code{NULL} for @var{address} clears the sender address.
The function returns 0 on success or an error code on failure. The
most likely failure is that no valid ``addr-spec'' was found in
@var{address}.
@end deftypefun
@deftypefun @w{const char *} gpgme_get_sender @
(@w{gpgme_ctx_t @var{ctx}})
The function @code{gpgme_get_sender} returns the current sender
address from the context, or NULL if none was set. The returned
value is valid as long as the @var{ctx} is valid and
@code{gpgme_set_sender} has not been called again.
@end deftypefun
@c FIXME: Unfortunately, using @acronym here breaks texi2dvi.
@node ASCII Armor
@subsection @acronym{ASCII} Armor

View File

@ -119,16 +119,18 @@ struct gpgme_context
/* Number of certs to be included. */
unsigned int include_certs;
/* The number of keys in signers. */
/* The actual number of keys in SIGNERS, the allocated size of the
* array, and the array with the signing keys. */
unsigned int signers_len;
/* Size of the following array. */
unsigned int signers_size;
gpgme_key_t *signers;
/* The signature notations for this context. */
gpgme_sig_notation_t sig_notations;
/* The sender's addr-spec or NULL. */
char *sender;
/* The locale for the pinentry. */
char *lc_ctype;
char *lc_messages;

View File

@ -111,7 +111,8 @@ struct engine_ops
gpgme_ctx_t ctx /* FIXME */);
gpgme_error_t (*trustlist) (void *engine, const char *pattern);
gpgme_error_t (*verify) (void *engine, gpgme_data_t sig,
gpgme_data_t signed_text, gpgme_data_t plaintext);
gpgme_data_t signed_text, gpgme_data_t plaintext,
gpgme_ctx_t ctx);
gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output,
unsigned int flags);
gpgme_error_t (*opassuan_transact) (void *engine,

View File

@ -1645,6 +1645,23 @@ append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
}
static gpgme_error_t
append_args_from_sender (engine_gpg_t gpg, gpgme_ctx_t ctx)
{
gpgme_error_t err;
if (ctx->sender && have_gpg_version (gpg, "2.1.15"))
{
err = add_arg (gpg, "--sender");
if (!err)
err = add_arg (gpg, ctx->sender);
}
else
err = 0;
return err;
}
static gpgme_error_t
append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
{
@ -1892,6 +1909,9 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
if (!err)
err = append_args_from_signers (gpg, ctx);
if (!err)
err = append_args_from_sender (gpg, ctx);
if (!err)
err = append_args_from_sig_notations (gpg, ctx);
@ -2793,6 +2813,8 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
if (!err)
err = append_args_from_signers (gpg, ctx);
if (!err)
err = append_args_from_sender (gpg, ctx);
if (!err)
err = append_args_from_sig_notations (gpg, ctx);
@ -2845,12 +2867,15 @@ gpg_trustlist (void *engine, const char *pattern)
static gpgme_error_t
gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
gpgme_data_t plaintext)
gpgme_data_t plaintext, gpgme_ctx_t ctx)
{
engine_gpg_t gpg = engine;
gpgme_error_t err = 0;
gpgme_error_t err;
if (plaintext)
err = append_args_from_sender (gpg, ctx);
if (err)
;
else if (plaintext)
{
/* Normal or cleartext signature. */
err = add_arg (gpg, "--output");

View File

@ -1901,11 +1901,13 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
static gpgme_error_t
gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
gpgme_data_t plaintext)
gpgme_data_t plaintext, gpgme_ctx_t ctx)
{
engine_gpgsm_t gpgsm = engine;
gpgme_error_t err;
(void)ctx;
if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);

View File

@ -1243,13 +1243,16 @@ uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
/* FIXME: Missing a way to specify --silent. */
static gpgme_error_t
uiserver_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
gpgme_data_t plaintext)
gpgme_data_t plaintext, gpgme_ctx_t ctx)
{
engine_uiserver_t uiserver = engine;
gpgme_error_t err;
const char *protocol;
char *cmd;
(void)ctx; /* FIXME: We should to add a --sender option to the
* UISever protocol. */
if (!uiserver)
return gpg_error (GPG_ERR_INV_VALUE);
if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
@ -1395,6 +1398,6 @@ struct engine_ops _gpgme_engine_ops_uiserver =
uiserver_cancel,
NULL, /* cancel_op */
NULL, /* passwd */
NULL, /* set_pinentry_mode */
NULL, /* set_pinentry_mode */
NULL /* opspawn */
};

View File

@ -902,7 +902,8 @@ _gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
gpgme_error_t
_gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
gpgme_data_t signed_text, gpgme_data_t plaintext)
gpgme_data_t signed_text, gpgme_data_t plaintext,
gpgme_ctx_t ctx)
{
if (!engine)
return gpg_error (GPG_ERR_INV_VALUE);
@ -910,7 +911,8 @@ _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
if (!engine->ops->verify)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext,
ctx);
}

View File

@ -152,7 +152,8 @@ gpgme_error_t _gpgme_engine_op_trustlist (engine_t engine,
const char *pattern);
gpgme_error_t _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
gpgme_data_t signed_text,
gpgme_data_t plaintext);
gpgme_data_t plaintext,
gpgme_ctx_t ctx);
gpgme_error_t _gpgme_engine_op_getauditlog (engine_t engine,
gpgme_data_t output,

View File

@ -38,6 +38,7 @@
#include "debug.h"
#include "priv-io.h"
#include "sys-util.h"
#include "mbox-util.h"
/* The default locale. */
@ -275,12 +276,10 @@ gpgme_release (gpgme_ctx_t ctx)
_gpgme_release_result (ctx);
_gpgme_signers_clear (ctx);
_gpgme_sig_notation_clear (ctx);
if (ctx->signers)
free (ctx->signers);
if (ctx->lc_ctype)
free (ctx->lc_ctype);
if (ctx->lc_messages)
free (ctx->lc_messages);
free (ctx->sender);
free (ctx->signers);
free (ctx->lc_ctype);
free (ctx->lc_messages);
_gpgme_engine_info_release (ctx->engine_info);
ctx->engine_info = NULL;
DESTROY_LOCK (ctx->lock);
@ -459,6 +458,42 @@ gpgme_get_protocol_name (gpgme_protocol_t protocol)
}
}
/* Store the sender's address in the context. ADDRESS is addr-spec of
* mailbox but my also be a complete mailbox, in which case this
* function extracts the addr-spec from it. Returns 0 on success or
* an error code if no valid addr-spec could be extracted from
* ADDRESS. */
gpgme_error_t
gpgme_set_sender (gpgme_ctx_t ctx, const char *address)
{
char *p = NULL;
TRACE_BEG1 (DEBUG_CTX, "gpgme_set_sender", ctx, "sender='%s'",
address?address:"(null)");
if (!ctx || (address && !(p = _gpgme_mailbox_from_userid (address))))
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
free (ctx->sender);
ctx->sender = p;
return TRACE_ERR (0);
}
/* Return the sender's address (addr-spec part) from the context or
* NULL if none was set. The returned value is valid as long as the
* CTX is valid and gpgme_set_sender has not been used. */
const char *
gpgme_get_sender (gpgme_ctx_t ctx)
{
TRACE1 (DEBUG_CTX, "gpgme_get_sender", ctx, "sender='%s'",
ctx?ctx->sender:"");
return ctx->sender;
}
/* Enable or disable the use of an ascii armor for all output. */
void
gpgme_set_armor (gpgme_ctx_t ctx, int use_armor)

View File

@ -246,5 +246,8 @@ EXPORTS
gpgme_addrspec_from_uid @186
gpgme_set_sender @187
gpgme_get_sender @188
; END

View File

@ -1161,6 +1161,12 @@ gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name,
/* Get the sig notations for this context. */
gpgme_sig_notation_t gpgme_sig_notation_get (gpgme_ctx_t ctx);
/* Store a sender address in the context. */
gpgme_error_t gpgme_set_sender (gpgme_ctx_t ctx, const char *address);
/* Get the sender address from the context. */
const char *gpgme_get_sender (gpgme_ctx_t ctx);
/*

View File

@ -119,6 +119,9 @@ GPGME_1.1 {
gpgme_op_interact;
gpgme_addrspec_from_uid;
gpgme_set_sender;
gpgme_get_sender;
};

View File

@ -1104,7 +1104,8 @@ verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
if (!sig)
return gpg_error (GPG_ERR_NO_DATA);
return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext,
ctx);
}

View File

@ -209,6 +209,7 @@ main (int argc, char *argv[])
gpgme_error_t err;
gpgme_data_t sig, text;
gpgme_verify_result_t result;
const char *s;
(void)argc;
(void)argv;
@ -270,6 +271,54 @@ main (int argc, char *argv[])
exit (1);
}
/* Checking that set/get_sernder works. */
err = gpgme_set_sender (ctx, "foo@example.org");
fail_if_err (err);
s = gpgme_get_sender (ctx);
if (!s || strcmp (s, "foo@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
__FILE__, __LINE__);
exit (1);
}
err = gpgme_set_sender (ctx, "<bar@example.org>");
fail_if_err (err);
s = gpgme_get_sender (ctx);
if (!s || strcmp (s, "bar@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
__FILE__, __LINE__);
exit (1);
}
err = gpgme_set_sender (ctx, "Foo bar (comment) <foo@example.org>");
fail_if_err (err);
s = gpgme_get_sender (ctx);
if (!s || strcmp (s, "foo@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
__FILE__, __LINE__);
exit (1);
}
err = gpgme_set_sender (ctx, "foo");
if (gpgme_err_code (err) != GPG_ERR_INV_VALUE)
{
fprintf (stderr, "%s:%i: gpgme_set_sender didn't detect bogus address\n",
__FILE__, __LINE__);
exit (1);
}
/* (the former address should still be there.) */
s = gpgme_get_sender (ctx);
if (!s || strcmp (s, "foo@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
__FILE__, __LINE__);
exit (1);
}
gpgme_data_release (sig);
gpgme_data_release (text);
gpgme_release (ctx);

View File

@ -83,6 +83,7 @@ show_usage (int ex)
" --uiserver use the UI server\n"
" --loopback use a loopback pinentry\n"
" --key NAME use key NAME for signing\n"
" --sender MBOX use MBOX as sender address\n"
, stderr);
exit (ex);
}
@ -101,6 +102,7 @@ main (int argc, char **argv)
gpgme_sign_result_t result;
int print_status = 0;
int use_loopback = 0;
const char *sender = NULL;
if (argc)
{ argc--; argv++; }
@ -148,6 +150,14 @@ main (int argc, char **argv)
key_string = *argv;
argc--; argv++;
}
else if (!strcmp (*argv, "--sender"))
{
argc--; argv++;
if (!argc)
show_usage (1);
sender = *argv;
argc--; argv++;
}
else if (!strcmp (*argv, "--loopback"))
{
use_loopback = 1;
@ -192,6 +202,12 @@ main (int argc, char **argv)
gpgme_key_unref (akey);
}
if (sender)
{
err = gpgme_set_sender (ctx, sender);
fail_if_err (err);
}
err = gpgme_data_new_from_file (&in, *argv, 1);
if (err)
{

View File

@ -221,6 +221,7 @@ show_usage (int ex)
" --status print status lines from the backend\n"
" --openpgp use the OpenPGP protocol (default)\n"
" --cms use the CMS protocol\n"
" --sender MBOX use MBOX as sender address\n"
, stderr);
exit (ex);
}
@ -239,6 +240,7 @@ main (int argc, char **argv)
gpgme_data_t msg = NULL;
gpgme_verify_result_t result;
int print_status = 0;
const char *sender = NULL;
if (argc)
{ argc--; argv++; }
@ -273,6 +275,14 @@ main (int argc, char **argv)
protocol = GPGME_PROTOCOL_CMS;
argc--; argv++;
}
else if (!strcmp (*argv, "--sender"))
{
argc--; argv++;
if (!argc)
show_usage (1);
sender = *argv;
argc--; argv++;
}
else if (!strncmp (*argv, "--", 2))
show_usage (1);
@ -313,6 +323,12 @@ main (int argc, char **argv)
}
/* gpgme_set_ctx_flag (ctx, "raw-description", "1"); */
if (sender)
{
err = gpgme_set_sender (ctx, sender);
fail_if_err (err);
}
err = gpgme_data_new_from_stream (&sig, fp_sig);
if (err)
{