to set and get the number of certifications to include in S/MIME
signed messages.
+ * New interfaces gpgme_op_encrypt_sign and gpgme_op_encrypt_sign_start
+ to encrypt and sign a message in a combined operation.
+
* Interface changes relative to the 0.3.3 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_set_include_certs NEW
gpgme_get_include_certs NEW
+gpgme_op_encrypt_sign NEW
+gpgme_op_encrypt_sign_start NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.3.3 (2002-02-12)
+2002-02-26 Marcus Brinkmann <marcus@g10code.de>
+
+ * gpgme.texi (Encrypting a Plaintext): Document
+ gpgme_op_encrypt_sign and gpgme_op_encrypt_sign_start.
+
2002-02-25 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Creating a Signature): Add a note about
@subsubsection Encrypting a Plaintext
@deftypefun GpgmeError gpgme_op_encrypt (@w{GpgmeCtx @var{ctx}}, @w{GpgmeRecipients @var{rset}}, @w{GpgmeData @var{plain}}, @w{GpgmeData @var{cipher}})
-The function @code{gpgme_op_crypt} encrypts the plaintext in the data
+The function @code{gpgme_op_encrypt} encrypts the plaintext in the data
object @var{plain} for the recipients @var{rset} and stores the
ciphertext in the data object @var{cipher}. The type of the
ciphertext created is determined by the @acronym{ASCII} armor and text
@end deftypefun
+@deftypefun GpgmeError gpgme_op_encrypt_sign (@w{GpgmeCtx @var{ctx}}, @w{GpgmeRecipients @var{rset}}, @w{GpgmeData @var{plain}}, @w{GpgmeData @var{cipher}})
+The function @code{gpgme_op_encrypt_sign} does a combined encrypt and
+sign operation. It is used like @code{gpgme_op_encrypt}, but the
+ciphertext also contains signatures for the signers listed in
+@var{ctx}.
+
+The combined encrypt and sign operation is currently only available
+for the OpenPGP crypto engine.
+@end deftypefun
+
+@deftypefun GpgmeError gpgme_op_encrypt_sign_start (@w{GpgmeCtx @var{ctx}}, @w{GpgmeRecipients @var{rset}}, @w{GpgmeData @var{plain}}, @w{GpgmeData @var{cipher}})
+The function @code{gpgme_op_encrypt_sign_start} initiates a
+@code{gpgme_op_encrypt_sign} operation. It can be completed by
+calling @code{gpgme_wait} on the context. @xref{Waiting For
+Completion}.
+
+The function returns @code{GPGME_No_Error} if the operation could be
+started successfully, @code{GPGME_Invalid_Value} if @var{ctx},
+@var{rset}, @var{plain} or @var{cipher} is not a valid pointer, and
+@code{GPGME_No_Recipient} if @var{rset} does not contain any valid
+recipients.
+@end deftypefun
+
+
@node Detailed Results
@subsection Detailed Results
@cindex cryptographic operation, detailed results
+2002-02-25 Marcus Brinkmann <marcus@g10code.de>
+
+ * engine.c (_gpgme_engine_op_encrypt_sign): New function.
+ * engine.h (_gpgme_engine_op_encrypt_sign): New prototype.
+ * rungpg.c (_gpgme_append_gpg_args_from_signers): New function.
+ (_gpgme_gpg_op_sign): Use that new function.
+ (_gpgme_gpg_op_encrypt_sign): New function.
+ * rungpg.h (_gpgme_gpg_op_encrypt_sign): New prototype.
+ * gpgme.h (gpgme_op_encrypt_sign_start): New prototype.
+ (gpgme_op_encrypt_sign): Likewise.
+ * Makefile.am (libgpgme_la_SOURCES): Add encrypt-sign.c.
+ * ops.h (_gpgme_encrypt_status_handler): Add prototype.
+ (_gpgme_sign_status_handler): Add prototype.
+ * sign.c (sign_status_handler): Rename to ...
+ (_gpgme_sign_status_handler): ... this and make non-static.
+ * encrypt.c (encrypt_status_handler): Rename to ...
+ (_gpgme_encrypt_status_handler): ... this and make non-static.
+ * encrypt.c (gpgme_op_encrypt_start): Use new status handler name.
+ * sign.c (gpgme_op_sign_start): Likewise.
+
2002-02-25 Marcus Brinkmann <marcus@g10code.de>
* verify.c (_gpgme_verify_status_handler): Parse the args line to
data.c recipient.c signers.c \
wait.c wait.h \
encrypt.c \
+ encrypt-sign.c \
decrypt.c \
decrypt-verify.c \
verify.c \
--- /dev/null
+/* encrypt-sign.c - encrypt and verify functions
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ * Copyright (C) 2001, 2002 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+
+
+static void
+encrypt_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
+{
+ char *encrypt_info = 0;
+ int encrypt_info_len;
+
+ _gpgme_encrypt_status_handler (ctx, code, args);
+
+ if (code == STATUS_EOF)
+ {
+ encrypt_info = gpgme_data_release_and_get_mem (ctx->op_info,
+ &encrypt_info_len);
+ ctx->op_info = NULL;
+ }
+ _gpgme_sign_status_handler (ctx, code, args);
+ if (code == STATUS_EOF && encrypt_info)
+ _gpgme_data_append (ctx->op_info, encrypt_info, encrypt_info_len);
+}
+
+
+GpgmeError
+gpgme_op_encrypt_sign_start (GpgmeCtx ctx, GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData cipher)
+{
+ int err = 0;
+
+ fail_on_pending_request (ctx);
+ ctx->pending = 1;
+
+ _gpgme_release_result (ctx);
+
+ /* Do some checks. */
+ if (!gpgme_recipients_count (recp))
+ {
+ /* FIXME: In this case we should do symmetric encryption. */
+ err = mk_error (No_Recipients);
+ goto leave;
+ }
+
+ /* Create an engine object. */
+ _gpgme_engine_release (ctx->engine);
+ ctx->engine = NULL;
+ err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
+ : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+ if (err)
+ goto leave;
+
+ err = _gpgme_passphrase_start (ctx);
+ if (err)
+ goto leave;
+
+ _gpgme_engine_set_status_handler (ctx->engine,
+ encrypt_sign_status_handler, ctx);
+ _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
+
+ /* Check the supplied data */
+ if (gpgme_data_get_type (plain) == GPGME_DATA_TYPE_NONE)
+ {
+ err = mk_error (No_Data);
+ goto leave;
+ }
+ _gpgme_data_set_mode (plain, GPGME_DATA_MODE_OUT);
+ if (!cipher || gpgme_data_get_type (cipher) != GPGME_DATA_TYPE_NONE)
+ {
+ err = mk_error (Invalid_Value);
+ goto leave;
+ }
+ _gpgme_data_set_mode (cipher, GPGME_DATA_MODE_IN);
+
+ err = _gpgme_engine_op_encrypt_sign (ctx->engine, recp, plain, cipher,
+ ctx->use_armor, ctx /* FIXME */);
+
+ if (!err) /* And kick off the process. */
+ err = _gpgme_engine_start (ctx->engine, ctx);
+
+ leave:
+ if (err)
+ {
+ ctx->pending = 0;
+ _gpgme_engine_release (ctx->engine);
+ ctx->engine = NULL;
+ }
+ return err;
+}
+
+
+/**
+ * gpgme_op_encrypt_sign:
+ * @ctx: The context
+ * @recp: The set of recipients
+ * @plain: plaintext input
+ * @cipher: signed ciphertext
+ *
+ * This function encrypts @plain for all recipients in recp, signs it,
+ * and returns the ciphertext in @out. The function does wait for the
+ * result.
+ *
+ * Return value: 0 on success or an errorcode.
+ **/
+GpgmeError
+gpgme_op_encrypt_sign (GpgmeCtx ctx, GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData cipher)
+{
+ GpgmeError err = gpgme_op_encrypt_sign_start (ctx, recp, plain, cipher);
+
+ if (!err)
+ {
+ gpgme_wait (ctx, &err, 1);
+ /* Old gpg versions don't return status info for invalid
+ recipients, so we simply check whether we got any output at
+ all, and if not we assume that we don't have valid
+ recipients. */
+ if (!ctx->error && gpgme_data_get_type (cipher) == GPGME_DATA_TYPE_NONE)
+ ctx->error = mk_error (No_Recipients);
+ err = ctx->error;
+ }
+ return err;
+}
}
-static void
-encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
+void
+_gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
{
if (ctx->error)
return;
if (err)
goto leave;
- _gpgme_engine_set_status_handler (ctx->engine, encrypt_status_handler, ctx);
+ _gpgme_engine_set_status_handler (ctx->engine, _gpgme_encrypt_status_handler,
+ ctx);
_gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
/* Check the supplied data */
return 0;
}
+
GpgmeError
_gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph, int use_armor)
return 0;
}
+
+GpgmeError
+_gpgme_engine_op_encrypt_sign (EngineObject engine, GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData ciph, int use_armor,
+ GpgmeCtx ctx /* FIXME */)
+{
+ if (!engine)
+ return mk_error (Invalid_Value);
+
+ switch (engine->protocol)
+ {
+ case GPGME_PROTOCOL_OpenPGP:
+ return _gpgme_gpg_op_encrypt_sign (engine->engine.gpg, recp, plain, ciph,
+ use_armor, ctx);
+ case GPGME_PROTOCOL_CMS:
+ return mk_error (Not_Implemented);
+ default:
+ break;
+ }
+ return 0;
+}
+
+
GpgmeError
_gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
GpgmeData keydata, int use_armor)
GpgmeError _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph,
int use_armor);
+GpgmeError _gpgme_engine_op_encrypt_sign (EngineObject engine,
+ GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData ciph,
+ int use_armor,
+ GpgmeCtx ctx /* FIXME */);
GpgmeError _gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
GpgmeData keydata, int use_armor);
GpgmeError _gpgme_engine_op_genkey (EngineObject engine, GpgmeData help_data,
GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher);
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ store the resulting ciphertext in CIPHER. Also sign the ciphertext
+ with the signers in CTX. */
+GpgmeError gpgme_op_encrypt_sign_start (GpgmeCtx ctx,
+ GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData cipher);
+GpgmeError gpgme_op_encrypt_sign (GpgmeCtx ctx,
+ GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData cipher);
+
/* Decrypt ciphertext CIPHER within CTX and store the resulting
plaintext in PLAIN. */
GpgmeError gpgme_op_decrypt_start (GpgmeCtx ctx,
/*-- sign.c --*/
void _gpgme_release_sign_result ( SignResult res );
+void _gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code,
+ char *args);
/*-- encrypt.c --*/
void _gpgme_release_encrypt_result ( EncryptResult res );
+void _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code,
+ char *args);
/*-- passphrase.c --*/
void _gpgme_release_passphrase_result (PassphraseResult result);
return err;
}
+
static GpgmeError
_gpgme_append_gpg_args_from_recipients (GpgObject gpg,
const GpgmeRecipients rset)
return err;
}
+
+static GpgmeError
+_gpgme_append_gpg_args_from_signers (GpgObject gpg,
+ GpgmeCtx ctx /* FIXME */)
+{
+ GpgmeError err = 0;
+ int i;
+ GpgmeKey key;
+
+ for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
+ {
+ const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID,
+ NULL, 0);
+ if (s)
+ {
+ if (!err)
+ err = _gpgme_gpg_add_arg (gpg, "-u");
+ if (!err)
+ err = _gpgme_gpg_add_arg (gpg, s);
+ }
+ gpgme_key_unref (key);
+ if (err) break;
+ }
+ return err;
+}
+
+
GpgmeError
_gpgme_gpg_op_encrypt (GpgObject gpg, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph, int use_armor)
return err;
}
+GpgmeError
+_gpgme_gpg_op_encrypt_sign (GpgObject gpg, GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData ciph, int use_armor,
+ GpgmeCtx ctx /* FIXME */)
+{
+ GpgmeError err;
+
+ err = _gpgme_gpg_add_arg (gpg, "--encrypt");
+ if (!err)
+ err = _gpgme_gpg_add_arg (gpg, "--sign");
+ if (!err && use_armor)
+ err = _gpgme_gpg_add_arg (gpg, "--armor");
+
+ /* If we know that all recipients are valid (full or ultimate trust)
+ * we can suppress further checks */
+ if (!err && _gpgme_recipients_all_valid (recp))
+ err = _gpgme_gpg_add_arg (gpg, "--always-trust");
+
+ if (!err)
+ err = _gpgme_append_gpg_args_from_recipients (gpg, recp);
+
+ if (!err)
+ err = _gpgme_append_gpg_args_from_signers (gpg, ctx);
+
+ /* Tell the gpg object about the data. */
+ if (!err)
+ err = _gpgme_gpg_add_arg (gpg, "--output");
+ if (!err)
+ err = _gpgme_gpg_add_arg (gpg, "-");
+ if (!err)
+ err = _gpgme_gpg_add_data (gpg, ciph, 1);
+ if (!err)
+ err = _gpgme_gpg_add_arg (gpg, "--");
+ if (!err)
+ err = _gpgme_gpg_add_data (gpg, plain, 0);
+
+ return err;
+}
+
GpgmeError
_gpgme_gpg_op_export (GpgObject gpg, GpgmeRecipients recp,
GpgmeData keydata, int use_armor)
int use_textmode, GpgmeCtx ctx /* FIXME */)
{
GpgmeError err;
- GpgmeKey key;
- int i;
if (mode == GPGME_SIG_MODE_CLEAR)
err = _gpgme_gpg_add_arg (gpg, "--clearsign");
if (!err && use_textmode)
_gpgme_gpg_add_arg (gpg, "--textmode");
}
- for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
- {
- const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID,
- NULL, 0);
- if (s)
- {
- if (!err)
- err = _gpgme_gpg_add_arg (gpg, "-u");
- if (!err)
- err = _gpgme_gpg_add_arg (gpg, s);
- }
- gpgme_key_unref (key);
- if (err) break;
- }
+
+ if (!err)
+ err = _gpgme_append_gpg_args_from_signers (gpg, ctx);
/* Tell the gpg object about the data. */
if (!err)
GpgmeError _gpgme_gpg_op_encrypt (GpgObject gpg, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph,
int use_armor);
+GpgmeError _gpgme_gpg_op_encrypt_sign (GpgObject gpg, GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData ciph,
+ int use_armor, GpgmeCtx ctx);
GpgmeError _gpgme_gpg_op_export (GpgObject gpg, GpgmeRecipients recp,
GpgmeData keydata, int use_armor);
GpgmeError _gpgme_gpg_op_genkey (GpgObject gpg, GpgmeData help_data,
_gpgme_data_append_string (dh, "</fpr>\n");
}
-static void
-sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
+void
+_gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
{
_gpgme_passphrase_status_handler (ctx, code, args);
if (err)
goto leave;
- _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler, ctx);
+ _gpgme_engine_set_status_handler (ctx->engine, _gpgme_sign_status_handler,
+ ctx);
_gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
_gpgme_engine_op_sign (ctx->engine, in, out, mode, ctx->use_armor,
+2002-02-26 Marcus Brinkmann <marcus@g10code.de>
+
+ * gpg/t-encrypt-sign.c: New file.
+ * gpg/Makefile.am (TESTS): Add t-encrypt-sign.
+
2002-02-13 Werner Koch <wk@gnupg.org>
* gpgsm/Makefile.am (private-keys-v1.d): Don't
TESTS_ENVIRONMENT = GNUPGHOME=.
-TESTS = t-encrypt t-sign t-signers t-decrypt t-verify \
+TESTS = t-encrypt t-encrypt-sign t-sign t-signers t-decrypt t-verify \
t-decrypt-verify t-keylist t-export t-import t-trustlist
CLEANFILES = secring.gpg pubring.gpg trustdb.gpg random_seed
--- /dev/null
+/* t-encrypt-sign.c - regression test
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ * Copyright (C) 2001, 2002 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <gpgme.h>
+
+#define fail_if_err(a) do { if(a) { \
+ fprintf (stderr, "%s:%d: GpgmeError %s\n", \
+ __FILE__, __LINE__, gpgme_strerror(a)); \
+ exit (1); } \
+ } while(0)
+
+static void
+print_op_info (GpgmeCtx c)
+{
+ char *s = gpgme_get_op_info (c, 0);
+
+ if (!s)
+ puts ("<!-- no operation info available -->");
+ else {
+ puts (s);
+ free (s);
+ }
+}
+
+
+static void
+print_data ( GpgmeData dh )
+{
+ char buf[100];
+ size_t nread;
+ GpgmeError err;
+
+ err = gpgme_data_rewind ( dh );
+ fail_if_err (err);
+ while ( !(err = gpgme_data_read ( dh, buf, 100, &nread )) ) {
+ fwrite ( buf, nread, 1, stdout );
+ }
+ if (err != GPGME_EOF)
+ fail_if_err (err);
+}
+
+
+static const char *
+passphrase_cb ( void *opaque, const char *desc, void **r_hd )
+{
+ const char *pass;
+
+ if ( !desc ) {
+ /* cleanup by looking at *r_hd */
+
+
+ return NULL;
+ }
+
+ pass = "abc";
+ fprintf (stderr, "%% requesting passphrase for `%s': ", desc );
+ fprintf (stderr, "sending `%s'\n", pass );
+
+ return pass;
+}
+
+
+int
+main (int argc, char **argv )
+{
+ GpgmeCtx ctx;
+ GpgmeError err;
+ GpgmeData in, out;
+ GpgmeRecipients rset;
+
+ err = gpgme_check_engine ();
+ fail_if_err (err);
+ puts ( gpgme_get_engine_info() );
+
+ do {
+ err = gpgme_new (&ctx);
+ fail_if_err (err);
+ gpgme_set_armor (ctx, 1);
+ if (!getenv("GPG_AGENT_INFO"))
+ gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
+
+ err = gpgme_data_new_from_mem ( &in, "Hallo Leute\n", 12, 0 );
+ fail_if_err (err);
+
+ err = gpgme_data_new ( &out );
+ fail_if_err (err);
+
+ err = gpgme_recipients_new (&rset);
+ fail_if_err (err);
+ err = gpgme_recipients_add_name_with_validity (rset, "Bob",
+ GPGME_VALIDITY_FULL);
+ fail_if_err (err);
+ err = gpgme_recipients_add_name_with_validity (rset, "Alpha",
+ GPGME_VALIDITY_FULL);
+ fail_if_err (err);
+
+
+ err = gpgme_op_encrypt_sign (ctx, rset, in, out);
+ print_op_info (ctx);
+ fail_if_err (err);
+
+ fflush (NULL);
+ fputs ("Begin Result:\n", stdout );
+ print_data (out);
+ fputs ("End Result.\n", stdout );
+
+ gpgme_recipients_release (rset);
+ gpgme_data_release (in);
+ gpgme_data_release (out);
+ gpgme_release (ctx);
+ } while ( argc > 1 && !strcmp( argv[1], "--loop" ) );
+
+ return 0;
+}
+
+