aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rw-r--r--Makefile.am59
-rw-r--r--NEWS81
-rw-r--r--README2
-rw-r--r--configure.ac21
-rw-r--r--doc/gpgme.texi224
-rw-r--r--lang/cpp/src/key.cpp49
-rw-r--r--lang/cpp/src/key.h31
-rw-r--r--lang/python/README12
-rw-r--r--lang/python/README.org9
-rwxr-xr-xlang/python/setup.py.in19
-rw-r--r--src/Makefile.am2
-rw-r--r--src/context.h3
-rw-r--r--src/conversion.c46
-rw-r--r--src/decrypt.c80
-rw-r--r--src/encrypt-sign.c111
-rw-r--r--src/encrypt.c106
-rw-r--r--src/engine-backend.h2
-rw-r--r--src/engine-gpg.c203
-rw-r--r--src/engine-gpgsm.c58
-rw-r--r--src/engine-uiserver.c59
-rw-r--r--src/engine.c10
-rw-r--r--src/engine.h2
-rw-r--r--src/gpgme-json.c568
-rw-r--r--src/gpgme.c8
-rw-r--r--src/gpgme.def5
-rw-r--r--src/gpgme.h.in384
-rw-r--r--src/libgpgme.vers9
-rw-r--r--src/op-support.c19
-rw-r--r--src/ops.h4
-rw-r--r--src/util.h5
-rw-r--r--src/verify.c32
-rw-r--r--src/versioninfo.rc.in2
-rw-r--r--tests/gpg/t-verify.c146
-rw-r--r--tests/run-decrypt.c42
-rw-r--r--tests/run-encrypt.c79
-rw-r--r--tests/run-verify.c32
37 files changed, 1993 insertions, 535 deletions
diff --git a/AUTHORS b/AUTHORS
index 6d2ce673..c989eff7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,5 +1,5 @@
Package: gpgme
-Homepage: https://gnupg.org/related_software/gpgme/
+Homepage: https://gnupg.org/software/gpgme/
Download: https://gnupg.org/ftp/gcrypt/gpgme/
Repository: git://git.gnupg.org/gpgme.git
Maintainer: Werner Koch <[email protected]>
@@ -19,7 +19,7 @@ List of Copyright holders
Copyright (C) 1991-2013 Free Software Foundation, Inc.
Copyright (C) 2000-2001 Werner Koch
- Copyright (C) 2001-2017 g10 Code GmbH
+ Copyright (C) 2001-2018 g10 Code GmbH
Copyright (C) 2002 Klarälvdalens Datakonsult AB
Copyright (C) 2004-2008 Igor Belyi
Copyright (C) 2002 John Goerzen
diff --git a/Makefile.am b/Makefile.am
index e47ace50..2dc02e7e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,6 +19,16 @@
## Process this file with automake to produce Makefile.in
+# Location of the released tarball archives. Note that this is an
+# internal archive and before uploading this to the public server,
+# manual tests should be run and the git release tat set and pushed.
+# Adjust as needed.
+RELEASE_ARCHIVE_DIR = wk@vigenere:tarballs/gpgme/
+
+# The key used to sign the released sources. Adjust as needed.
+RELEASE_SIGNING_KEY = D8692123C4065DEA5E0F3AB5249B39D24F25E3B6
+
+# Autoconf flags
ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS =
@@ -57,9 +67,9 @@ distcheck-hook:
esac;\
done ) | tee $(distdir).swdb
+.PHONY: gen-ChangeLog release sign-release
gen_start_date = 2011-12-01T00:00:00
-.PHONY: gen-ChangeLog
gen-ChangeLog:
if test -d $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \
@@ -70,3 +80,50 @@ gen-ChangeLog:
rm -f $(distdir)/ChangeLog; \
mv $(distdir)/cl-t $(distdir)/ChangeLog; \
fi
+
+
+# Macro to help the release target.
+RELEASE_NAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)
+
+release:
+ +(set -e;\
+ if [ "$(abs_top_builddir)" = "$(abs_top_srcdir)" ]; then \
+ echo "error: build directory must not be the source directory" >&2;\
+ exit 2;\
+ fi ;\
+ echo "/* Build started at $$(date -uIseconds) */" ;\
+ cd $(top_srcdir); \
+ ./autogen.sh --force; \
+ cd $(abs_top_builddir); \
+ rm -rf dist; mkdir dist ; cd dist ; \
+ $(abs_top_srcdir)/configure --enable-maintainer-mode; \
+ $(MAKE) distcheck TESTFLAGS=--parallel; \
+ echo "/* Build finished at $$(date -uIseconds) */" ;\
+ echo "/*" ;\
+ echo " * Please run the final step interactivly:" ;\
+ echo " * make sign-release" ;\
+ echo " */" ;\
+ ) 2>&1 | tee "$(RELEASE_NAME).buildlog"
+
+sign-release:
+ +(set -e; \
+ cd dist; \
+ files1="$(RELEASE_NAME).tar.bz2" ;\
+ files2="$(RELEASE_NAME).tar.bz2.sig \
+ $(RELEASE_NAME).swdb \
+ $(RELEASE_NAME).buildlog" ;\
+ echo "/* Signing the source tarball ..." ;\
+ gpg -sbu $(RELEASE_SIGNING_KEY) $(RELEASE_NAME).tar.bz2 ;\
+ cat $(RELEASE_NAME).swdb >swdb.snippet;\
+ echo >>swdb.snippet ;\
+ sha1sum $${files1} >>swdb.snippet ;\
+ cat "../$(RELEASE_NAME).buildlog" swdb.snippet \
+ | gzip >$(RELEASE_NAME).buildlog ;\
+ echo "Copying to local archive ..." ;\
+ scp -p $${files1} $${files2} $(RELEASE_ARCHIVE_DIR)/ || true;\
+ echo "Uploading documentation ..." ;\
+ $(MAKE) -C doc online; \
+ echo '/*' ;\
+ echo ' * All done; for checksums see dist/swdb.snippet' ;\
+ echo ' */' ;\
+ )
diff --git a/NEWS b/NEWS
index 7b6fdd9c..80c01190 100644
--- a/NEWS
+++ b/NEWS
@@ -1,13 +1,86 @@
-Noteworthy changes in version 1.10.1 (unreleased)
+Noteworthy changes in version 1.11.2 (unreleased)
-------------------------------------------------
+
+Noteworthy changes in version 1.11.1 (2018-04-20)
+-------------------------------------------------
+
+ * Fixed build problems in the 1.11.0 release.
+
+ * Added C++ interfaces which were planned for 1.11.0.
+
+ * Interface changes relative to the 1.10.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ cpp: Key::origin NEW.
+ cpp: Key::lastUpdate NEW.
+ cpp: UserID::origin NEW.
+ cpp: UserID::lastUpdate NEW.
+
+ [c=C31/A20/R1 cpp=C13/A7/R0 qt=C10/A3/R2]
+
+
+Noteworthy changes in version 1.11.0 (2018-04-18)
+-------------------------------------------------
+
+ * New encryption API to support direct key specification including
+ hidden recipients option and taking keys from a file. This also
+ allows to enforce the use of a subkey.
+
+ * New encryption flag for the new API to enforce the use of plain
+ mail addresses (addr-spec).
+
+ * The import API can now tell whether v3 keys are skipped. These old
+ and basically broken keys are not anymore supported by GnuPG 2.1.
+
+ * The decrypt and verify API will now return the MIME flag as
+ specified by RFC-4880bis.
+
+ * The offline mode now has an effect on gpg by disabling all network
+ access. [#3831]
+
+ * A failed OpenPGP verification how returns the fingerprint of the
+ intended key if a recent gpg version was used for signature
+ creation.
+
+ * New tool gpgme-json as native messaging server for web browsers.
+ As of now public key encryption and decryption is supported.
+ Requires Libgpg-error 1.29.
+
+ * New context flag "request-origin" which has an effect when used
+ with GnuPG 2.2.6 or later.
+
+ * New context flag "no-symkey-cache" which has an effect when used
+ with GnuPG 2.2.7 or later.
+
+ * New convenience constant GPGME_KEYLIST_MODE_LOCATE.
+
+ * Improved the Python documentation.
+
+ * Fixed a potential regression with GnuPG 2.2.6 or later.
+
+ * Fixed a crash in the Python bindings on 32 bit platforms. [#3892]
+
+ * Various minor fixes.
+
* Interface changes relative to the 1.10.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'
- cpp: Key::locate NEW.
- cpp: Data::toString NEW.
+ gpgme_op_encrypt_ext NEW.
+ gpgme_op_encrypt_ext_start NEW.
+ gpgme_op_encrypt_sign_ext NEW.
+ gpgme_op_encrypt_sign_ext_start NEW.
+ GPGME_ENCRYPT_WANT_ADDRESS NEW.
+ GPGME_KEYLIST_MODE_LOCATE NEW.
+ gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'.
+ gpgme_decrypt_result_t EXTENDED: New field 'symkey_algo'.
+ gpgme_decrypt_result_t EXTENDED: New field 'is_mime'.
+ gpgme_verify_result_t EXTENDED: New field 'is_mime'.
+ cpp: Key::locate NEW.
+ cpp: Data::toString NEW.
cpp: ImportResult::numV3KeysSkipped NEW.
+ [c=C31/A20/R0 cpp=C12/A6/R0 qt=C10/A3/R1]
+
+
Noteworthy changes in version 1.10.0 (2017-12-12)
-------------------------------------------------
diff --git a/README b/README
index f7b006f1..8e031ae6 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
GPGME - GnuPG Made Easy
---------------------------
-Copyright 2001-2017 g10 Code GmbH
+Copyright 2001-2018 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
diff --git a/configure.ac b/configure.ac
index c6c6dc86..a1da1e3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,6 @@
# configure.ac for GPGME
# Copyright (C) 2000 Werner Koch (dd9jn)
-# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-# 2009, 2010, 2011, 2012, 2013, 2014, 2015 g10 Code GmbH
+# Copyright (C) 2001-2018 g10 Code GmbH
#
# This file is part of GPGME.
#
@@ -28,8 +27,8 @@ min_automake_version="1.14"
# commit and push so that the git magic is able to work. See below
# for the LT versions.
m4_define(mym4_version_major, [1])
-m4_define(mym4_version_minor, [10])
-m4_define(mym4_version_micro, [1])
+m4_define(mym4_version_minor, [11])
+m4_define(mym4_version_micro, [2])
# Below is m4 magic to extract and compute the revision number, the
# decimalized short revision number, a beta version string, and a flag
@@ -55,20 +54,20 @@ AC_INIT([gpgme],[mym4_full_version],[http://bugs.gnupg.org])
# (Interfaces added: AGE++)
# (Interfaces removed/changed: AGE=0)
#
-LIBGPGME_LT_CURRENT=30
-LIBGPGME_LT_AGE=19
-LIBGPGME_LT_REVISION=0
+LIBGPGME_LT_CURRENT=31
+LIBGPGME_LT_AGE=20
+LIBGPGME_LT_REVISION=1
# If there is an ABI break in gpgmepp or qgpgme also bump the
# version in IMPORTED_LOCATION in the GpgmeppConfig-w32.cmake.in.in
-LIBGPGMEPP_LT_CURRENT=11
-LIBGPGMEPP_LT_AGE=5
+LIBGPGMEPP_LT_CURRENT=13
+LIBGPGMEPP_LT_AGE=7
LIBGPGMEPP_LT_REVISION=0
LIBQGPGME_LT_CURRENT=10
LIBQGPGME_LT_AGE=3
-LIBQGPGME_LT_REVISION=0
+LIBQGPGME_LT_REVISION=2
# If the API is changed in an incompatible way: increment the next counter.
GPGME_CONFIG_API_VERSION=1
@@ -810,7 +809,7 @@ AH_BOTTOM([
#define GPG_ERR_ENABLE_ERRNO_MACROS 1
#define CRIGHTBLURB "Copyright (C) 2000 Werner Koch\n" \
- "Copyright (C) 2001--2017 g10 Code GmbH\n"
+ "Copyright (C) 2001--2018 g10 Code GmbH\n"
])
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index ab554d86..c4a29d54 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -2606,22 +2606,26 @@ valid pointer.
@deftypefun void gpgme_set_offline (@w{gpgme_ctx_t @var{ctx}}, @w{int @var{yes}})
@since{1.6.0}
-The function @code{gpgme_set_offline} specifies if offline mode
-should be used. By default, offline mode is not used.
+The function @code{gpgme_set_offline} specifies if offline mode should
+be used. Offline mode is disabled if @var{yes} is zero, and enabled
+otherwise. By default, offline mode is disabled.
-The offline mode specifies if dirmngr should be used to do additional
-validation that might require connections to external services.
-(e.g. CRL / OCSP checks).
+The details of the offline mode depend on the used protocol and its
+backend engine. It may eventually be extended to be more stricter and
+for example completely disable the use of Dirmngr for any engine.
-Offline mode only affects the keylist mode @code{GPGME_KEYLIST_MODE_VALIDATE}
-and is only relevant to the CMS crypto engine. Offline mode
-is ignored otherwise.
+For the CMS protocol the offline mode specifies whether Dirmngr shall
+be used to do additional validation that might require connecting
+external services (e.g. CRL / OCSP checks). Here the offline mode
+only affects the keylist mode @code{GPGME_KEYLIST_MODE_VALIDATE}.
-This option may be extended in the future to completely disable
-the use of dirmngr for any engine.
+For the OpenPGP protocol offline mode entirely disables the use of the
+Dirmngr and will thus guarantee that no network connections are done
+as part of an operation on this context. It has only an effect with
+GnuPG versions 2.1.23 or later.
+
+For all other protocols the offline mode is currently ignored.
-Offline mode is disabled if @var{yes} is zero, and enabled
-otherwise.
@end deftypefun
@deftypefun int gpgme_get_offline (@w{gpgme_ctx_t @var{ctx}})
@@ -2765,6 +2769,11 @@ type of external source is dependent on the crypto engine used and
whether it is combined with @code{GPGME_KEYLIST_MODE_LOCAL}. For
example, it can be a remote keyserver or LDAP certificate server.
+@item GPGME_KEYLIST_MODE_LOCATE
+This is a shortcut for the combination of
+@code{GPGME_KEYLIST_MODE_LOCAL} and @code{GPGME_KEYLIST_MODE_EXTERN}
+and convenient when the --locate-key feature of OpenPGP is desired.
+
@item GPGME_KEYLIST_MODE_SIGS
The @code{GPGME_KEYLIST_MODE_SIGS} symbol specifies that the key
signatures should be included in the listed keys.
@@ -3069,7 +3078,13 @@ the time when you verified the signature.
The string given in @var{value} is passed to the GnuPG engines to
request restrictions based on the origin of the request. Valid values
are documented in the GnuPG manual and the gpg man page under the
-option ``--request-origin''.
+option ``--request-origin''. Requires at least GnuPG 2.2.6 to have an
+effect.
+
+@item "no-symkey-cache"
+For OpenPGP disable the passphrase cache used for symmetrical en- and
+decryption. This cache is based on the message specific salt value.
+Requires at least GnuPG 2.2.7 to have an effect.
@end table
@@ -5274,7 +5289,7 @@ if @var{cipher} or @var{plain} is not a valid pointer.
@since{1.8.0}
The function @code{gpgme_op_decrypt_ext} is the same as
-@code{gpgme_op_decrypt_ext} but has an additional argument
+@code{gpgme_op_decrypt} but has an additional argument
@var{flags}. If @var{flags} is 0 both function behave identically.
The value in @var{flags} is a bitwise-or combination of one or
@@ -5389,6 +5404,13 @@ You must not try to access this member of the struct unless
or @code{gpgme_get_ctx_flag (ctx, "export-session-key")} returns true
(non-empty string).
+@item char *symkey_algo
+@since{1.11.0}
+
+A string with the symmetric encryption algorithm and mode using the
+format "<algo>.<mode>". Note that old non-MDC encryption mode of
+OpenPGP is given as "PGPCFB".
+
@end table
@end deftp
@@ -6088,7 +6110,7 @@ also expect a sign command.
The @code{GPGME_ENCRYPT_SYMMETRIC} symbol specifies that the
output should be additionally encrypted symmetrically even
-if recipients are provided. This feature is only supported for
+if recipients are provided. This feature is only supported
for the OpenPGP crypto engine.
@item GPGME_ENCRYPT_THROW_KEYIDS
@@ -6107,6 +6129,18 @@ The @code{GPGME_ENCRYPT_WRAP} symbol specifies that the input is an
OpenPGP message and not a plain data. This is the counterpart to
@code{GPGME_DECRYPT_UNWRAP}.
+@item GPGME_ENCRYPT_WANT_ADDRESS
+@since{1.11.0}
+
+The @code{GPGME_ENCRYPT_WANT_ADDRESS} symbol requests that all
+supplied keys or key specifications include a syntactically valid mail
+address. If this is not the case the operation is not even tried and
+the error code @code{GPG_ERR_INV_USER_ID} is returned. Only the
+address part of the key specification is conveyed to the backend. As
+of now the key must be specified using the @var{recpstring} argument
+of the extended encrypt functions. This feature is currently only
+supported for the OpenPGP crypto engine.
+
@end table
If @code{GPG_ERR_UNUSABLE_PUBKEY} is returned, some recipients in
@@ -6148,6 +6182,128 @@ pointer, and @code{GPG_ERR_UNUSABLE_PUBKEY} if @var{rset} does not
contain any valid recipients.
@end deftypefun
+@deftypefun gpgme_error_t gpgme_op_encrypt_ext @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create key objects. Leading and trailing white space is
+remove from each line in @var{recpstring}. The keys are then passed
+verbatim to the backend engine.
+
+For the OpenPGP backend several special keywords are supported to
+modify the operation. These keywords are given instead of a key
+specification. The currently supported keywords are:
+
+@table @code
+@item --hidden
+@itemx --no-hidden
+These keywords toggle between normal and hidden recipients for all
+following key specifications. When a hidden recipient is requested
+the gpg option @option{-R} (or @option{-F} in file mode) is used
+instead of @option{-r} (@option{-f} in file mode).
+
+@item --file
+@itemx --no-file
+These keywords toggle between regular and file mode for all following
+key specification. In file mode the option @option{-f} or @option{-F}
+is passed to gpg. At least GnuPG version 2.1.14 is required to handle
+these options. The @code{GPGME_ENCRYPT_WANT_ADDRESS} flag is ignored
+in file mode.
+
+@item --
+This keyword disables all keyword detection up to the end of the
+string. All keywords are treated as verbatim arguments.
+
+@end table
+
+To create a @var{recpstring} it is often useful to employ a strconcat
+style function. For example this function creates a string to encrypt
+to two keys:
+
+@example
+char *
+xbuild_recpstring (const char *key1, const char *key2)
+@{
+ char *result = gpgrt_strconcat ("--\n", key1, "\n", key2, NULL);
+ if (!result)
+ @{ perror ("strconcat failed"); exit (2); @}
+ return result;
+@}
+@end example
+
+Note the use of the double dash here; unless you want to specify a
+keyword, it is a good idea to avoid any possible trouble with key
+specifications starting with a double dash. The used strconcat
+function is available in Libgpg-error 1.28 and later; Libgpg-error
+(aka Gpgrt) is a dependency of GPGME. The number of arguments to
+@code{gpgrt_strconcat} is limited to 47 but that should always be
+sufficient. In case a larger and non-fixed number of keys are to be
+supplied the following code can be used:
+
+@example
+char *
+xbuild_long_recpstring (void)
+@{
+ gpgrt_stream_t memfp;
+ const char *s;
+ void *result;
+
+ memfp = gpgrt_fopenmem (0, "w+b");
+ if (!memfp)
+ @{ perror ("fopenmem failed"); exit (2); @}
+ gpgrt_fputs ("--", memfp);
+ while ((s = get_next_keyspec ()))
+ @{
+ gpgrt_fputc ('\n', memfp);
+ gpgrt_fputs (s, memfp);
+ @}
+ gpgrt_fputc (0, memfp);
+ if (gpgrt_ferror (memfp))
+ @{ perror ("writing to memstream failed"); exit (2); @}
+ if (gpgrt_fclose_snatch (memfp, &result, NULL))
+ @{ perror ("fclose_snatch failed"); exit (2); @}
+ return result;
+@}
+@end example
+
+In this example @code{get_next_keyspec} is expected to return the next
+key to be added to the string. Please take care: Encrypting to a
+large number of recipients is often questionable due to security
+reasons and also for the technicality that all keys are currently
+passed on the command line to @command{gpg} which has as a platform
+specific length limitation.
+@end deftypefun
+
+
+@deftypefun gpgme_error_t gpgme_op_encrypt_ext_start @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_start} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create key objects. The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
@deftp {Data type} {gpgme_encrypt_result_t}
This is a pointer to a structure used to store the result of a
@code{gpgme_op_encrypt} operation. After successfully encrypting
@@ -6197,6 +6353,44 @@ if @var{ctx}, @var{rset}, @var{plain} or @var{cipher} is not a valid
pointer.
@end deftypefun
+@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_sign} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create the key objects. The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
+@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext_start @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_sign_start} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create the key objects. The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
@node Miscellaneous
@section Miscellaneous operations
diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp
index 0e86a19e..034286f0 100644
--- a/lang/cpp/src/key.cpp
+++ b/lang/cpp/src/key.cpp
@@ -967,6 +967,42 @@ Error UserID::revoke()
return ret;
}
+static Key::Origin gpgme_origin_to_pp_origin (const unsigned int origin)
+{
+ switch (origin) {
+ case GPGME_KEYORG_KS:
+ return Key::OriginKS;
+ case GPGME_KEYORG_DANE:
+ return Key::OriginDane;
+ case GPGME_KEYORG_WKD:
+ return Key::OriginWKD;
+ case GPGME_KEYORG_URL:
+ return Key::OriginURL;
+ case GPGME_KEYORG_FILE:
+ return Key::OriginFile;
+ case GPGME_KEYORG_SELF:
+ return Key::OriginSelf;
+ case GPGME_KEYORG_OTHER:
+ return Key::OriginOther;
+ case GPGME_KEYORG_UNKNOWN:
+ default:
+ return Key::OriginUnknown;
+ }
+}
+
+Key::Origin UserID::origin() const
+{
+ if (isNull()) {
+ return Key::OriginUnknown;
+ }
+ return gpgme_origin_to_pp_origin(uid->origin);
+}
+
+time_t UserID::lastUpdate() const
+{
+ return static_cast<time_t>(uid ? uid->last_update : 0);
+}
+
Error Key::addUid(const char *uid)
{
if (isNull()) {
@@ -981,6 +1017,19 @@ Error Key::addUid(const char *uid)
return ret;
}
+Key::Origin Key::origin() const
+{
+ if (isNull()) {
+ return OriginUnknown;
+ }
+ return gpgme_origin_to_pp_origin(key->origin);
+}
+
+time_t Key::lastUpdate() const
+{
+ return static_cast<time_t>(key ? key->last_update : 0);
+}
+
std::ostream &operator<<(std::ostream &os, const UserID &uid)
{
os << "GpgME::UserID(";
diff --git a/lang/cpp/src/key.h b/lang/cpp/src/key.h
index c3c711c1..76a0d4f4 100644
--- a/lang/cpp/src/key.h
+++ b/lang/cpp/src/key.h
@@ -178,6 +178,27 @@ public:
*/
static Key locate(const char *mbox);
+ /* @enum Origin
+ * @brief The Origin of the key. */
+ enum Origin : unsigned int {
+ OriginUnknown = 0,
+ OriginKS = 1,
+ OriginDane = 3,
+ OriginWKD = 4,
+ OriginURL = 5,
+ OriginFile = 6,
+ OriginSelf = 7,
+ OriginOther = 31,
+ };
+ /*! Get the origin of the key.
+ *
+ * @returns the Origin. */
+ Origin origin() const;
+
+ /*! Get the last update time.
+ *
+ * @returns the last update time. */
+ time_t lastUpdate() const;
private:
gpgme_key_t impl() const
{
@@ -371,6 +392,16 @@ public:
*
* @returns an error on error.*/
Error revoke();
+
+ /*! Get the origin of the key.
+ *
+ * @returns the Origin. */
+ Key::Origin origin() const;
+
+ /*! Get the last update time.
+ *
+ * @returns the last update time. */
+ time_t lastUpdate() const;
private:
shared_gpgme_key_t key;
gpgme_user_id_t uid;
diff --git a/lang/python/README b/lang/python/README
index 49e88205..99da4dd7 100644
--- a/lang/python/README
+++ b/lang/python/README
@@ -1,6 +1,6 @@
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- GPG - GPGME BINDINGS FOR PYTHON
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ GPG - GPGME BINDINGS FOR PYTHON
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Table of Contents
@@ -13,7 +13,7 @@ Table of Contents
The "gpg" module is a python interface to the GPGME library:
-[https://www.gnupg.org/related_software/gpgme/]
+[https://www.gnupg.org/software/gpgme/]
"gpg" offers two interfaces, one is a high-level, curated, and idiomatic
interface that is implemented as a shim on top of the low-level
@@ -36,8 +36,8 @@ functionality of the underlying library.
2 Bugs
══════
- Please report bugs using our bug tracker using the category 'gpgme',
- and topic 'python': [https://bugs.gnupg.org/gnupg/]
+ Please report bugs using our bug tracker [https://bugs.gnupg.org] with
+ tag (aka project) 'gpgme'.
3 Authors
diff --git a/lang/python/README.org b/lang/python/README.org
index 22e7d1f8..cba99669 100644
--- a/lang/python/README.org
+++ b/lang/python/README.org
@@ -1,8 +1,8 @@
#+TITLE: gpg - GPGME bindings for Python
-
+#+OPTIONS: author:nil
The "gpg" module is a python interface to the GPGME library:
-https://www.gnupg.org/related_software/gpgme/
+[[https://www.gnupg.org/software/gpgme/]]
"gpg" offers two interfaces, one is a high-level, curated, and
idiomatic interface that is implemented as a shim on top of the
@@ -21,9 +21,8 @@ https://lists.gnupg.org/mailman/listinfo/gnupg-devel
* Bugs
-Please report bugs using our bug tracker using the category 'gpgme',
-and topic 'python':
-https://bugs.gnupg.org/gnupg/
+Please report bugs using our bug tracker
+[[https://bugs.gnupg.org]] with tag (aka project) 'gpgme'.
* Authors
diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
index f9dda20f..2595073f 100755
--- a/lang/python/setup.py.in
+++ b/lang/python/setup.py.in
@@ -152,25 +152,8 @@ class BuildExtFirstHack(build):
sink.write(content)
def _generate_gpgme_h(self, source_name, sink_name):
- if up_to_date(source_name, sink_name):
- return
-
print("Using gpgme.h from {}".format(source_name))
-
- deprec_func = re.compile(r'^(.*typedef.*|.*\(.*\)|[^#]+\s+.+)'
- + r'\s*_GPGME_DEPRECATED(_OUTSIDE_GPGME)?\(.*\);\s*',
- re.S)
- line_break = re.compile(';|\\$|\\x0c|^\s*#|{')
-
- with open(sink_name, "w") as sink, open(source_name) as source:
- text = ''
- for line in source:
- text += re.sub(' class ', ' _py_obsolete_class ', line)
- if line_break.search(line):
- if not deprec_func.search(text):
- sink.write(text)
- text = ''
- sink.write(text)
+ shutil.copy2(source_name, sink_name)
def _generate_errors_i(self):
diff --git a/src/Makefile.am b/src/Makefile.am
index c2d4a843..0a196e0c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -104,8 +104,6 @@ gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@
gpgme_json_SOURCES = gpgme-json.c cJSON.c cJSON.h
gpgme_json_LDADD = -lm libgpgme.la $(GPG_ERROR_LIBS)
-# We use -no-install temporary during development.
-gpgme_json_LDFLAGS = -no-install
if HAVE_W32_SYSTEM
diff --git a/src/context.h b/src/context.h
index 202cf168..c8e75ba0 100644
--- a/src/context.h
+++ b/src/context.h
@@ -121,6 +121,9 @@ struct gpgme_context
/* True if the option --auto-key-retrieve shall be passed to gpg. */
unsigned int auto_key_retrieve : 1;
+ /* Do not use the symmtric encryption passphrase cache. */
+ unsigned int no_symkey_cache : 1;
+
/* Flags for keylist mode. */
gpgme_keylist_mode_t keylist_mode;
diff --git a/src/conversion.c b/src/conversion.c
index 5b84f672..4bfd3d3e 100644
--- a/src/conversion.c
+++ b/src/conversion.c
@@ -575,3 +575,49 @@ _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol)
return algo;
}
+
+
+/* Return a string with a cipher algorithm. */
+const char *
+_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol)
+{
+ if (protocol == GPGME_PROTOCOL_OPENPGP)
+ {
+ /* The algo is given according to OpenPGP specs. */
+ switch (algo)
+ {
+ case 1: return "IDEA";
+ case 2: return "3DES";
+ case 3: return "CAST5";
+ case 4: return "BLOWFISH";
+ case 7: return "AES";
+ case 8: return "AES192";
+ case 9: return "AES256";
+ case 10: return "TWOFISH";
+ case 11: return "CAMELLIA128";
+ case 12: return "CAMELLIA192";
+ case 13: return "CAMELLIA256";
+ }
+ }
+
+ return "Unknown";
+}
+
+
+/* Return a string with the cipher mode. */
+const char *
+_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol)
+{
+ if (protocol == GPGME_PROTOCOL_OPENPGP)
+ {
+ /* The algo is given according to OpenPGP specs. */
+ switch (algo)
+ {
+ case 0: return "CFB";
+ case 1: return "EAX";
+ case 2: return "OCB";
+ }
+ }
+
+ return "Unknown";
+}
diff --git a/src/decrypt.c b/src/decrypt.c
index 8c2cd4d7..0fc7019c 100644
--- a/src/decrypt.c
+++ b/src/decrypt.c
@@ -69,14 +69,10 @@ release_op_data (void *hook)
op_data_t opd = (op_data_t) hook;
gpgme_recipient_t recipient = opd->result.recipients;
- if (opd->result.unsupported_algorithm)
- free (opd->result.unsupported_algorithm);
-
- if (opd->result.file_name)
- free (opd->result.file_name);
-
- if (opd->result.session_key)
- free (opd->result.session_key);
+ free (opd->result.unsupported_algorithm);
+ free (opd->result.file_name);
+ free (opd->result.session_key);
+ free (opd->result.symkey_algo);
while (recipient)
{
@@ -104,6 +100,17 @@ gpgme_op_decrypt_result (gpgme_ctx_t ctx)
return NULL;
}
+ /* Make sure that SYMKEY_ALGO has a value. */
+ if (!opd->result.symkey_algo)
+ {
+ opd->result.symkey_algo = strdup ("?.?");
+ if (!opd->result.symkey_algo)
+ {
+ TRACE_SUC0 ("result=(null)");
+ return NULL;
+ }
+ }
+
if (_gpgme_debug_trace ())
{
gpgme_recipient_t rcp;
@@ -263,6 +270,49 @@ parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol)
}
+/* Parse the ARGS of a
+ * DECRYPTION_INFO <mdc_method> <sym_algo> [<aead_algo>]
+ * status. Returns 0 on success and updates the OPD.
+ */
+static gpgme_error_t
+parse_decryption_info (char *args, op_data_t opd, gpgme_protocol_t protocol)
+{
+ char *field[3];
+ int nfields;
+ char *args2;
+ int mdc, mode;
+ const char *algostr, *modestr;
+
+ if (!args)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+ args2 = strdup (args); /* Split modifies the input string. */
+ nfields = _gpgme_split_fields (args2, field, DIM (field));
+ if (nfields < 2)
+ {
+ free (args2);
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing. */
+ }
+
+ mdc = atoi (field[0]);
+ algostr = _gpgme_cipher_algo_name (atoi (field[1]), protocol);
+ mode = nfields < 3? 0 : atoi (field[2]);
+ modestr = _gpgme_cipher_mode_name (mode, protocol);
+
+ free (args2);
+
+ free (opd->result.symkey_algo);
+ if (!mode && mdc != 2)
+ opd->result.symkey_algo = _gpgme_strconcat (algostr, ".PGPCFB", NULL);
+ else
+ opd->result.symkey_algo = _gpgme_strconcat (algostr, ".", modestr, NULL);
+ if (!opd->result.symkey_algo)
+ return gpg_error_from_syserror ();
+
+ return 0;
+}
+
+
gpgme_error_t
_gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
char *args)
@@ -303,7 +353,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
break;
case GPGME_STATUS_DECRYPTION_INFO:
- /* Fixme: Provide a way to return the used symmetric algorithm. */
+ err = parse_decryption_info (args, opd, ctx->protocol);
+ if (err)
+ return err;
break;
case GPGME_STATUS_DECRYPTION_OKAY:
@@ -357,9 +409,13 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
break;
case GPGME_STATUS_PLAINTEXT:
- err = _gpgme_parse_plaintext (args, &opd->result.file_name);
- if (err)
- return err;
+ {
+ int mime = 0;
+ err = _gpgme_parse_plaintext (args, &opd->result.file_name, &mime);
+ if (err)
+ return err;
+ opd->result.is_mime = !!mime;
+ }
break;
case GPGME_STATUS_INQUIRE_MAXLEN:
diff --git a/src/encrypt-sign.c b/src/encrypt-sign.c
index af6de63e..4db46e25 100644
--- a/src/encrypt-sign.c
+++ b/src/encrypt-sign.c
@@ -62,6 +62,7 @@ encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
static gpgme_error_t
encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
@@ -72,7 +73,7 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
if (err)
return err;
- symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
+ symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC);
if (!plain)
return gpg_error (GPG_ERR_NO_DATA);
@@ -103,43 +104,75 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
: encrypt_sign_status_handler,
ctx);
- return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, flags, plain,
+ return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, recpstring,
+ flags, plain,
cipher, ctx->use_armor,
ctx /* FIXME */);
}
-/* 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. */
+/* Old version of gpgme_op_encrypt_sign_ext_start w/o RECPSTRING. */
gpgme_error_t
gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
+ return gpgme_op_encrypt_sign_ext_start (ctx, recp, NULL,
+ flags, plain, cipher);
+}
+
+
+/* Old version of gpgme_op_encrypt_sign_ext w/o RECPSTRING. */
+gpgme_error_t
+gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ return gpgme_op_encrypt_sign_ext (ctx, recp, NULL, flags, plain, 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. */
+gpgme_error_t
+gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
-
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
- (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ if (recp)
+ {
+ int i = 0;
+
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_sign_start (ctx, 0, recp, flags, plain, cipher);
- return err;
+ err = encrypt_sign_start (ctx, 1, recp, recpstring, flags, plain, cipher);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
}
@@ -147,33 +180,39 @@ gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
store the resulting ciphertext in CIPHER. Also sign the ciphertext
with the signers in CTX. */
gpgme_error_t
-gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
- gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher)
+gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
-
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
- (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ if (recp)
+ {
+ int i = 0;
+
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher);
- if (!err)
- err = _gpgme_wait_one (ctx);
- return TRACE_ERR (err);
+ err = encrypt_sign_start (ctx, 0, recp, recpstring, flags, plain, cipher);
+ return err;
}
diff --git a/src/encrypt.c b/src/encrypt.c
index 40236544..2318497e 100644
--- a/src/encrypt.c
+++ b/src/encrypt.c
@@ -214,6 +214,7 @@ _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
static gpgme_error_t
encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
@@ -228,13 +229,13 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
if (err)
return err;
- symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
+ symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC);
if (!plain)
return gpg_error (GPG_ERR_NO_DATA);
if (!cipher)
return gpg_error (GPG_ERR_INV_VALUE);
- if (recp && ! *recp)
+ if (recp && !*recp)
return gpg_error (GPG_ERR_INV_VALUE);
if (symmetric && ctx->passphrase_cb)
@@ -252,72 +253,111 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
: encrypt_status_handler,
ctx);
- return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher,
- ctx->use_armor);
+ return _gpgme_engine_op_encrypt (ctx->engine, recp, recpstring,
+ flags, plain, cipher, ctx->use_armor);
}
+/* Old version of gpgme_op_encrypt_ext without RECPSTRING. */
+gpgme_error_t
+gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ return gpgme_op_encrypt_ext (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Old version of gpgme_op_encrypt_ext_start without RECPSTRING. */
gpgme_error_t
gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
+ return gpgme_op_encrypt_ext_start (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ * store the resulting ciphertext in CIPHER. RECPSTRING can be used
+ * instead of the RECP array to directly specify recipients as LF
+ * delimited strings; these may be any kind of recipient specification
+ * patterns as supported by the backend. */
+gpgme_error_t
+gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
+ if (recp)
+ {
+ int i = 0;
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
(recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_start (ctx, 0, recp, flags, plain, cipher);
+ err = encrypt_start (ctx, 1, recp, recpstring, flags, plain, cipher);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
return TRACE_ERR (err);
}
-/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
- store the resulting ciphertext in CIPHER. */
gpgme_error_t
-gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
- gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher)
+gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
-
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
- (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ if (recp)
+ {
+ int i = 0;
+
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_start (ctx, 1, recp, flags, plain, cipher);
- if (!err)
- err = _gpgme_wait_one (ctx);
+ err = encrypt_start (ctx, 0, recp, recpstring, flags, plain, cipher);
return TRACE_ERR (err);
}
diff --git a/src/engine-backend.h b/src/engine-backend.h
index 97cf6a10..f6926662 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -72,10 +72,12 @@ struct engine_ops
gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key,
gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */);
gpgme_error_t (*encrypt) (void *engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor);
gpgme_error_t (*encrypt_sign) (void *engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor, gpgme_ctx_t ctx /* FIXME */);
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index 3b9a6ff5..173e940c 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -43,6 +43,7 @@
#include "sema.h"
#include "debug.h"
#include "data.h"
+#include "mbox-util.h"
#include "engine-backend.h"
@@ -145,6 +146,11 @@ struct engine_gpg
gpgme_pinentry_mode_t pinentry_mode;
char request_origin[10];
+ struct {
+ unsigned int no_symkey_cache : 1;
+ unsigned int offline : 1;
+ } flags;
+
/* NULL or the data object fed to --override_session_key-fd. */
gpgme_data_t override_session_key;
};
@@ -644,6 +650,12 @@ gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
}
else
*gpg->request_origin = 0;
+
+ gpg->flags.no_symkey_cache = (ctx->no_symkey_cache
+ && have_gpg_version (gpg, "2.2.7"));
+
+ gpg->flags.offline = (ctx->offline && have_gpg_version (gpg, "2.1.23"));
+
}
@@ -875,7 +887,8 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
argc++;
if (!gpg->cmd.used)
argc++; /* --batch */
- argc += 2; /* --no-sk-comments, --request-origin */
+ argc += 4; /* --no-sk-comments, --request-origin, --no-symkey-cache */
+ /* --disable-dirmngr */
argv = calloc (argc + 1, sizeof *argv);
if (!argv)
@@ -937,6 +950,32 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
argc++;
}
+ if (gpg->flags.no_symkey_cache)
+ {
+ argv[argc] = strdup ("--no-symkey-cache");
+ if (!argv[argc])
+ {
+ int saved_err = gpg_error_from_syserror ();
+ free (fd_data_map);
+ free_argv (argv);
+ return saved_err;
+ }
+ argc++;
+ }
+
+ if (gpg->flags.offline)
+ {
+ argv[argc] = strdup ("--disable-dirmngr");
+ if (!argv[argc])
+ {
+ int saved_err = gpg_error_from_syserror ();
+ free (fd_data_map);
+ free_argv (argv);
+ return saved_err;
+ }
+ argc++;
+ }
+
if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0"))
{
const char *s = NULL;
@@ -1871,8 +1910,70 @@ gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
}
+/* Add a single argument from a key to an -r option. */
+static gpg_error_t
+add_arg_recipient (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
+ gpgme_key_t key)
+{
+ gpg_error_t err;
+
+ if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
+ {
+ /* We have no way to figure out which mail address was
+ * requested. FIXME: It would be possible to figure this out by
+ * consulting the SENDER property of the context. */
+ err = gpg_error (GPG_ERR_INV_USER_ID);
+ }
+ else
+ err = add_arg (gpg, key->subkeys->fpr);
+
+ return err;
+}
+
+
+/* Add a single argument from a USERID string to an -r option. */
+static gpg_error_t
+add_arg_recipient_string (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
+ const char *userid, int useridlen)
+{
+ gpg_error_t err;
+
+ if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
+ {
+ char *tmpstr, *mbox;
+
+ tmpstr = malloc (useridlen + 1);
+ if (!tmpstr)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ memcpy (tmpstr, userid, useridlen);
+ tmpstr[useridlen] = 0;
+
+ mbox = _gpgme_mailbox_from_userid (tmpstr);
+ if (!mbox)
+ {
+ err = gpg_error_from_syserror ();
+ if (gpg_err_code (err) == GPG_ERR_EINVAL)
+ err = gpg_error (GPG_ERR_INV_USER_ID);
+ }
+ else
+ err = add_arg (gpg, mbox);
+
+ free (mbox);
+ free (tmpstr);
+ }
+ }
+ else
+ err = add_arg_len (gpg, NULL, userid, useridlen);
+
+ return err;
+}
+
+
static gpgme_error_t
-append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
+append_args_from_recipients (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
+ gpgme_key_t recp[])
{
gpgme_error_t err = 0;
int i = 0;
@@ -1884,7 +1985,7 @@ append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
if (!err)
err = add_arg (gpg, "-r");
if (!err)
- err = add_arg (gpg, recp[i]->subkeys->fpr);
+ err = add_arg_recipient (gpg, flags, recp[i]);
if (err)
break;
i++;
@@ -1893,17 +1994,86 @@ append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
}
+/* Take recipients from the LF delimited STRING and add -r args. */
+static gpg_error_t
+append_args_from_recipients_string (engine_gpg_t gpg,
+ gpgme_encrypt_flags_t flags,
+ const char *string)
+{
+ gpg_error_t err = 0;
+ gpgme_encrypt_flags_t orig_flags = flags;
+ int any = 0;
+ int ignore = 0;
+ int hidden = 0;
+ int file = 0;
+ const char *s;
+ int n;
+
+ do
+ {
+ /* Skip leading white space */
+ while (*string == ' ' || *string == '\t')
+ string++;
+ if (!*string)
+ break;
+
+ /* Look for the LF. */
+ s = strchr (string, '\n');
+ if (s)
+ n = s - string;
+ else
+ n = strlen (string);
+ while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+ n--;
+
+ if (!ignore && n == 2 && !memcmp (string, "--", 2))
+ ignore = 1;
+ else if (!ignore && n == 8 && !memcmp (string, "--hidden", 8))
+ hidden = 1;
+ else if (!ignore && n == 11 && !memcmp (string, "--no-hidden", 11))
+ hidden = 0;
+ else if (!ignore && n == 6 && !memcmp (string, "--file", 6))
+ {
+ file = 1;
+ /* Because the key is used as is we need to ignore this flag: */
+ flags &= ~GPGME_ENCRYPT_WANT_ADDRESS;
+ }
+ else if (!ignore && n == 9 && !memcmp (string, "--no-file", 9))
+ {
+ file = 0;
+ flags = orig_flags;
+ }
+ else if (n) /* Not empty - use it. */
+ {
+ err = add_arg (gpg, file? (hidden? "-F":"-f") : (hidden? "-R":"-r"));
+ if (!err)
+ err = add_arg_recipient_string (gpg, flags, string, n);
+ if (!err)
+ any = 1;
+ }
+
+ string += n + !!s;
+ }
+ while (!err);
+
+ if (!err && !any)
+ err = gpg_error (GPG_ERR_MISSING_KEY);
+ return err;
+}
+
+
static gpgme_error_t
-gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+ gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
engine_gpg_t gpg = engine;
gpgme_error_t err = 0;
- if (recp)
+ if (recp || recpstring)
err = add_arg (gpg, "--encrypt");
- if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+ if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
err = add_arg (gpg, "--symmetric");
if (!err && use_armor)
@@ -1930,7 +2100,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
&& have_gpg_version (gpg, "2.1.14"))
err = add_arg (gpg, "--mimemode");
- if (recp)
+ if (recp || recpstring)
{
/* If we know that all recipients are valid (full or ultimate trust)
we can suppress further checks. */
@@ -1940,8 +2110,10 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
err = add_arg (gpg, "--no-encrypt-to");
- if (!err)
- err = append_args_from_recipients (gpg, recp);
+ if (!err && !recp && recpstring)
+ err = append_args_from_recipients_string (gpg, flags, recpstring);
+ else if (!err)
+ err = append_args_from_recipients (gpg, flags, recp);
}
/* Tell the gpg object about the data. */
@@ -1974,6 +2146,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
static gpgme_error_t
gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags, gpgme_data_t plain,
gpgme_data_t ciph, int use_armor,
gpgme_ctx_t ctx /* FIXME */)
@@ -1981,10 +2154,10 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
engine_gpg_t gpg = engine;
gpgme_error_t err = 0;
- if (recp)
+ if (recp || recpstring)
err = add_arg (gpg, "--encrypt");
- if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+ if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
err = add_arg (gpg, "--symmetric");
if (!err)
@@ -2002,7 +2175,7 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
&& have_gpg_version (gpg, "2.1.14"))
err = add_arg (gpg, "--mimemode");
- if (recp)
+ if (recp || recpstring)
{
/* If we know that all recipients are valid (full or ultimate trust)
we can suppress further checks. */
@@ -2012,8 +2185,10 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
err = add_arg (gpg, "--no-encrypt-to");
- if (!err)
- err = append_args_from_recipients (gpg, recp);
+ if (!err && !recp && recpstring)
+ err = append_args_from_recipients_string (gpg, flags, recpstring);
+ else if (!err)
+ err = append_args_from_recipients (gpg, flags, recp);
}
if (!err)
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index b8e44e7c..da7e524f 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -1327,8 +1327,57 @@ set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
}
+/* Take recipients from the LF delimited STRING and send RECIPIENT
+ * commands to gpgsm. */
static gpgme_error_t
-gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+set_recipients_from_string (engine_gpgsm_t gpgsm, const char *string)
+{
+ gpg_error_t err = 0;
+ char *line = NULL;
+ int no_pubkey = 0;
+ const char *s;
+ int n;
+
+ for (;;)
+ {
+ while (*string == ' ' || *string == '\t')
+ string++;
+ if (!*string)
+ break;
+
+ s = strchr (string, '\n');
+ if (s)
+ n = s - string;
+ else
+ n = strlen (string);
+ while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+ n--;
+
+ gpgrt_free (line);
+ if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
+ {
+ err = gpg_error_from_syserror ();
+ break;
+ }
+ string += n + !!s;
+
+ err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
+ gpgsm->status.fnc_value);
+
+ /* Fixme: Improve error reporting. */
+ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+ no_pubkey++;
+ else if (err)
+ break;
+ }
+ gpgrt_free (line);
+ return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0;
+}
+
+
+static gpgme_error_t
+gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+ gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
engine_gpgsm_t gpgsm = engine;
@@ -1339,7 +1388,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
if (!recp)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
+ if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
{
err = gpgsm_assuan_simple_command (gpgsm,
"OPTION no-encrypt-to", NULL, NULL);
@@ -1359,7 +1408,10 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
gpgsm_clear_fd (gpgsm, MESSAGE_FD);
gpgsm->inline_data = NULL;
- err = set_recipients (gpgsm, recp);
+ if (!recp && recpstring)
+ err = set_recipients_from_string (gpgsm, recpstring);
+ else
+ err = set_recipients (gpgsm, recp);
if (!err)
err = start (gpgsm, "ENCRYPT");
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index fd5ac174..d8f4fce3 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -1075,8 +1075,58 @@ set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[])
}
+/* Take recipients from the LF delimited STRING and send RECIPIENT
+ * commands to gpgsm. */
static gpgme_error_t
-uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+set_recipients_from_string (engine_uiserver_t uiserver, const char *string)
+{
+ gpg_error_t err = 0;
+ char *line = NULL;
+ int no_pubkey = 0;
+ const char *s;
+ int n;
+
+ for (;;)
+ {
+ while (*string == ' ' || *string == '\t')
+ string++;
+ if (!*string)
+ break;
+
+ s = strchr (string, '\n');
+ if (s)
+ n = s - string;
+ else
+ n = strlen (string);
+ while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+ n--;
+
+ gpgrt_free (line);
+ if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
+ {
+ err = gpg_error_from_syserror ();
+ break;
+ }
+ string += n + !!s;
+
+ err = uiserver_assuan_simple_command (uiserver, line,
+ uiserver->status.fnc,
+ uiserver->status.fnc_value);
+
+ /* Fixme: Improve error reporting. */
+ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+ no_pubkey++;
+ else if (err)
+ break;
+ }
+ gpgrt_free (line);
+ return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0;
+}
+
+
+static gpgme_error_t
+uiserver_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+ gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
engine_uiserver_t uiserver = engine;
@@ -1140,9 +1190,12 @@ uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
uiserver->inline_data = NULL;
- if (recp)
+ if (recp || recpstring)
{
- err = set_recipients (uiserver, recp);
+ if (recp)
+ err = set_recipients (uiserver, recp);
+ else
+ err = set_recipients_from_string (uiserver, recpstring);
if (err)
{
gpgrt_free (cmd);
diff --git a/src/engine.c b/src/engine.c
index e51384f0..b716ca24 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -721,6 +721,7 @@ _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
gpgme_error_t
_gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
@@ -730,13 +731,14 @@ _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
if (!engine->ops->encrypt)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
- use_armor);
+ return (*engine->ops->encrypt) (engine->engine, recp, recpstring,
+ flags, plain, ciph, use_armor);
}
gpgme_error_t
_gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor, gpgme_ctx_t ctx /* FIXME */)
@@ -747,8 +749,8 @@ _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
if (!engine->ops->encrypt_sign)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
- plain, ciph, use_armor, ctx);
+ return (*engine->ops->encrypt_sign) (engine->engine, recp, recpstring,
+ flags, plain, ciph, use_armor, ctx);
}
diff --git a/src/engine.h b/src/engine.h
index 34bf8e90..8b692f2e 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -98,11 +98,13 @@ gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type,
gpgme_ctx_t ctx /* FIXME */);
gpgme_error_t _gpgme_engine_op_encrypt (engine_t engine,
gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor);
gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine,
gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain,
gpgme_data_t ciph,
diff --git a/src/gpgme-json.c b/src/gpgme-json.c
index b54d9a8a..f1e9f256 100644
--- a/src/gpgme-json.c
+++ b/src/gpgme-json.c
@@ -20,8 +20,7 @@
/* This is tool implements the Native Messaging protocol of web
* browsers and provides the server part of it. A Javascript based
- * client can be found in lang/javascript. The used data format is
- * similar to the API of openpgpjs.
+ * client can be found in lang/javascript.
*/
#include <config.h>
@@ -33,6 +32,7 @@
#include <locale.h>
#endif
#include <stdint.h>
+#include <sys/stat.h>
#define GPGRT_ENABLE_ES_MACROS 1
#define GPGRT_ENABLE_LOG_MACROS 1
@@ -48,6 +48,16 @@ int main (void){fputs ("Build with Libgpg-error >= 1.28!\n", stderr);return 1;}
/* We don't allow a request with more than 64 MiB. */
#define MAX_REQUEST_SIZE (64 * 1024 * 1024)
+/* Minimal, default and maximum chunk size for returned data. The
+ * first chunk is returned directly. If the "more" flag is also
+ * returned, a "getmore" command needs to be used to get the next
+ * chunk. Right now this value covers just the value of the "data"
+ * element; so to cover for the other returned objects this values
+ * needs to be lower than the maximum allowed size of the browser. */
+#define MIN_REPLY_CHUNK_SIZE 512
+#define DEF_REPLY_CHUNK_SIZE (512 * 1024)
+#define MAX_REPLY_CHUNK_SIZE (10 * 1024 * 1024)
+
static void xoutofcore (const char *type) GPGRT_ATTR_NORETURN;
static cjson_t error_object_v (cjson_t json, const char *message,
@@ -63,6 +73,16 @@ static int opt_interactive;
/* True is debug mode is active. */
static int opt_debug;
+/* Pending data to be returned by a getmore command. */
+static struct
+{
+ char *buffer; /* Malloced data or NULL if not used. */
+ size_t length; /* Length of that data. */
+ size_t written; /* # of already written bytes from BUFFER. */
+ const char *type;/* The "type" of the data. */
+ int base64; /* The "base64" flag of the data. */
+} pending_data;
+
/*
* Helper functions and macros
@@ -94,6 +114,19 @@ static int opt_debug;
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
+#ifndef HAVE_STPCPY
+static GPGRT_INLINE char *
+_my_stpcpy (char *a, const char *b)
+{
+ while (*b)
+ *a++ = *b++;
+ *a = 0;
+ return a;
+}
+#define stpcpy(a,b) _my_stpcpy ((a), (b))
+#endif /*!HAVE_STPCPY*/
+
+
static void
xoutofcore (const char *type)
@@ -146,11 +179,12 @@ xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
return ;
}
-/* This is similar to cJSON_AddStringToObject but takes a gpgme DATA
- * object and adds it under NAME as a base 64 encoded string to
- * OBJECT. Ownership of DATA is transferred to this function. */
+/* This is similar to cJSON_AddStringToObject but takes (DATA,
+ * DATALEN) and adds it under NAME as a base 64 encoded string to
+ * OBJECT. */
static gpg_error_t
-add_base64_to_object (cjson_t object, const char *name, gpgme_data_t data)
+add_base64_to_object (cjson_t object, const char *name,
+ const void *data, size_t datalen)
{
#if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
return gpg_error (GPG_ERR_NOT_SUPPORTED);
@@ -160,7 +194,6 @@ add_base64_to_object (cjson_t object, const char *name, gpgme_data_t data)
gpgrt_b64state_t state = NULL;
cjson_t j_str = NULL;
void *buffer = NULL;
- size_t buflen;
fp = es_fopenmem (0, "rwb");
if (!fp)
@@ -175,20 +208,9 @@ add_base64_to_object (cjson_t object, const char *name, gpgme_data_t data)
goto leave;
}
- gpgme_data_write (data, "", 1); /* Make sure we have a string. */
- buffer = gpgme_data_release_and_get_mem (data, &buflen);
- data = NULL;
- if (!buffer)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
-
- err = gpgrt_b64enc_write (state, buffer, buflen);
+ err = gpgrt_b64enc_write (state, data, datalen);
if (err)
goto leave;
- xfree (buffer);
- buffer = NULL;
err = gpgrt_b64enc_finish (state);
state = NULL;
@@ -226,7 +248,6 @@ add_base64_to_object (cjson_t object, const char *name, gpgme_data_t data)
cJSON_Delete (j_str);
gpgrt_b64enc_finish (state);
es_fclose (fp);
- gpgme_data_release (data);
return err;
#endif
}
@@ -354,18 +375,42 @@ get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
}
-/* Extract the keys from the KEYS array in the JSON object. CTX is a
- * GPGME context object. On success an array with the keys is stored
- * at R_KEYS. In failure an error code is returned. */
+/* Get the chunksize from JSON and store it at R_CHUNKSIZE. */
static gpg_error_t
-get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys)
+get_chunksize (cjson_t json, size_t *r_chunksize)
+{
+ cjson_t j_item;
+
+ *r_chunksize = DEF_REPLY_CHUNK_SIZE;
+ j_item = cJSON_GetObjectItem (json, "chunksize");
+ if (!j_item)
+ ;
+ else if (!cjson_is_number (j_item))
+ return gpg_error (GPG_ERR_INV_VALUE);
+ else if ((size_t)j_item->valueint < MIN_REPLY_CHUNK_SIZE)
+ *r_chunksize = MIN_REPLY_CHUNK_SIZE;
+ else if ((size_t)j_item->valueint > MAX_REPLY_CHUNK_SIZE)
+ *r_chunksize = MAX_REPLY_CHUNK_SIZE;
+ else
+ *r_chunksize = (size_t)j_item->valueint;
+
+ return 0;
+}
+
+
+/* Extract the keys from the "keys" array in the JSON object. On
+ * success a string with the keys identifiers is stored at R_KEYS.
+ * The keys in that string are LF delimited. On failure an error code
+ * is returned. */
+static gpg_error_t
+get_keys (cjson_t json, char **r_keystring)
{
- gpg_error_t err;
cjson_t j_keys, j_item;
int i, nkeys;
- gpgme_key_t *keys;
+ char *p;
+ size_t length;
- *r_keys = NULL;
+ *r_keystring = NULL;
j_keys = cJSON_GetObjectItem (json, "keys");
if (!j_keys)
@@ -373,8 +418,15 @@ get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys)
if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
return gpg_error (GPG_ERR_INV_VALUE);
+ /* Fixme: We should better use a membuf like thing. */
+ length = 1; /* For the EOS. */
if (cjson_is_string (j_keys))
- nkeys = 1;
+ {
+ nkeys = 1;
+ length += strlen (j_keys->valuestring);
+ if (strchr (j_keys->valuestring, '\n'))
+ return gpg_error (GPG_ERR_INV_USER_ID);
+ }
else
{
nkeys = cJSON_GetArraySize (j_keys);
@@ -385,43 +437,37 @@ get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys)
j_item = cJSON_GetArrayItem (j_keys, i);
if (!j_item || !cjson_is_string (j_item))
return gpg_error (GPG_ERR_INV_VALUE);
+ if (i)
+ length++; /* Space for delimiter. */
+ length += strlen (j_item->valuestring);
+ if (strchr (j_item->valuestring, '\n'))
+ return gpg_error (GPG_ERR_INV_USER_ID);
}
}
- /* Now allocate an array to store the gpgme key objects. */
- keys = xcalloc (nkeys + 1, sizeof *keys);
+ p = *r_keystring = xtrymalloc (length);
+ if (!p)
+ return gpg_error_from_syserror ();
if (cjson_is_string (j_keys))
{
- err = gpgme_get_key (ctx, j_keys->valuestring, &keys[0], 0);
- if (err)
- goto leave;
+ strcpy (p, j_keys->valuestring);
}
else
{
for (i=0; i < nkeys; i++)
{
j_item = cJSON_GetArrayItem (j_keys, i);
- err = gpgme_get_key (ctx, j_item->valuestring, &keys[i], 0);
- if (err)
- goto leave;
+ if (i)
+ *p++ = '\n'; /* Add delimiter. */
+ p = stpcpy (p, j_item->valuestring);
}
}
- err = 0;
- *r_keys = keys;
- keys = NULL;
-
- leave:
- if (keys)
- {
- for (i=0; keys[i]; i++)
- gpgme_key_unref (keys[i]);
- xfree (keys);
- }
- return err;
+ return 0;
}
+
/*
* GPGME support functions.
@@ -546,10 +592,95 @@ data_from_base64_string (gpgme_data_t *r_data, cjson_t json)
/*
- * Implementaion of the commands.
+ * Implementation of the commands.
*/
+/* Create a "data" object and the "type", "base64" and "more" flags
+ * from DATA and append them to RESULT. Ownership if DATA is
+ * transferred to this function. TYPE must be a fixed string.
+ * CHUNKSIZE is the chunksize requested from the caller. If BASE64 is
+ * -1 the need for base64 encoding is determined by the content of
+ * DATA, all other values are take as rtue or false. Note that
+ * op_getmore has similar code but works on PENDING_DATA which is set
+ * here. */
+static gpg_error_t
+make_data_object (cjson_t result, gpgme_data_t data, size_t chunksize,
+ const char *type, int base64)
+{
+ gpg_error_t err;
+ char *buffer;
+ size_t buflen;
+ int c;
+
+ if (!base64 || base64 == -1) /* Make sure that we really have a string. */
+ gpgme_data_write (data, "", 1);
+
+ buffer = gpgme_data_release_and_get_mem (data, &buflen);
+ data = NULL;
+ if (!buffer)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ if (base64 == -1)
+ {
+ base64 = 0;
+ if (!buflen)
+ log_fatal ("Appended Nul byte got lost\n");
+ if (memchr (buffer, 0, buflen-1))
+ {
+ buflen--; /* Adjust for the extra nul byte. */
+ base64 = 1;
+ }
+ /* Fixme: We might want to do more advanced heuristics than to
+ * only look for a Nul. */
+ }
+
+ /* Adjust the chunksize if we need to do base64 conversion. */
+ if (base64)
+ chunksize = (chunksize / 4) * 3;
+
+ xjson_AddStringToObject (result, "type", type);
+ xjson_AddBoolToObject (result, "base64", base64);
+
+ if (buflen > chunksize)
+ {
+ xjson_AddBoolToObject (result, "more", 1);
+
+ c = buffer[chunksize];
+ buffer[chunksize] = 0;
+ if (base64)
+ err = add_base64_to_object (result, "data", buffer, chunksize);
+ else
+ err = cjson_AddStringToObject (result, "data", buffer);
+ buffer[chunksize] = c;
+ if (err)
+ goto leave;
+
+ pending_data.buffer = buffer;
+ buffer = NULL;
+ pending_data.length = buflen;
+ pending_data.written = chunksize;
+ pending_data.type = type;
+ pending_data.base64 = base64;
+ }
+ else
+ {
+ if (base64)
+ err = add_base64_to_object (result, "data", buffer, buflen);
+ else
+ err = cjson_AddStringToObject (result, "data", buffer);
+ }
+
+ leave:
+ gpgme_free (buffer);
+ return err;
+}
+
+
+
static const char hlp_encrypt[] =
"op: \"encrypt\"\n"
"keys: Array of strings with the fingerprints or user-ids\n"
@@ -559,14 +690,17 @@ static const char hlp_encrypt[] =
"\n"
"Optional parameters:\n"
"protocol: Either \"openpgp\" (default) or \"cms\".\n"
+ "chunksize: Max number of bytes in the resulting \"data\".\n"
"\n"
"Optional boolean flags (default is false):\n"
"base64: Input data is base64 encoded.\n"
+ "mime: Indicate that data is a MIME object.\n"
"armor: Request output in armored format.\n"
"always-trust: Request --always-trust option.\n"
"no-encrypt-to: Do not use a default recipient.\n"
"no-compress: Do not compress the plaintext first.\n"
"throw-keyids: Request the --throw-keyids option.\n"
+ "want-address: Require that the keys include a mail address.\n"
"wrap: Assume the input is an OpenPGP message.\n"
"\n"
"Response on success:\n"
@@ -574,27 +708,34 @@ static const char hlp_encrypt[] =
"data: Unless armor mode is used a Base64 encoded binary\n"
" ciphertext. In armor mode a string with an armored\n"
" OpenPGP or a PEM message.\n"
- "base64: Boolean indicating whether data is base64 encoded.";
+ "base64: Boolean indicating whether data is base64 encoded.\n"
+ "more: Optional boolean indicating that \"getmore\" is required.";
static gpg_error_t
op_encrypt (cjson_t request, cjson_t result)
{
gpg_error_t err;
gpgme_ctx_t ctx = NULL;
gpgme_protocol_t protocol;
+ size_t chunksize;
int opt_base64;
- gpgme_key_t *keys = NULL;
+ int opt_mime;
+ char *keystring = NULL;
cjson_t j_input;
gpgme_data_t input = NULL;
gpgme_data_t output = NULL;
- int abool, i;
+ int abool;
gpgme_encrypt_flags_t encrypt_flags = 0;
if ((err = get_protocol (request, &protocol)))
goto leave;
ctx = get_context (protocol);
+ if ((err = get_chunksize (request, &chunksize)))
+ goto leave;
if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
goto leave;
+ if ((err = get_boolean_flag (request, "mime", 0, &opt_mime)))
+ goto leave;
if ((err = get_boolean_flag (request, "armor", 0, &abool)))
goto leave;
@@ -619,10 +760,14 @@ op_encrypt (cjson_t request, cjson_t result)
goto leave;
if (abool)
encrypt_flags |= GPGME_ENCRYPT_WRAP;
+ if ((err = get_boolean_flag (request, "want-address", 0, &abool)))
+ goto leave;
+ if (abool)
+ encrypt_flags |= GPGME_ENCRYPT_WANT_ADDRESS;
/* Get the keys. */
- err = get_keys (ctx, request, &keys);
+ err = get_keys (request, &keystring);
if (err)
{
/* Provide a custom error response. */
@@ -663,6 +808,9 @@ op_encrypt (cjson_t request, cjson_t result)
goto leave;
}
}
+ if (opt_mime)
+ gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
+
/* Create an output data object. */
err = gpgme_data_new (&output);
@@ -674,7 +822,8 @@ op_encrypt (cjson_t request, cjson_t result)
}
/* Encrypt. */
- err = gpgme_op_encrypt (ctx, keys, encrypt_flags, input, output);
+ err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
+ input, output);
/* encrypt_result = gpgme_op_encrypt_result (ctx); */
if (err)
{
@@ -684,48 +833,216 @@ op_encrypt (cjson_t request, cjson_t result)
gpgme_data_release (input);
input = NULL;
- xjson_AddStringToObject (result, "type", "ciphertext");
- /* If armoring is used we do not need to base64 the output. */
- xjson_AddBoolToObject (result, "base64", !gpgme_get_armor (ctx));
- if (gpgme_get_armor (ctx))
- {
- char *buffer;
+ /* We need to base64 if armoring has not been requested. */
+ err = make_data_object (result, output, chunksize,
+ "ciphertext", !gpgme_get_armor (ctx));
+ output = NULL;
+
+ leave:
+ xfree (keystring);
+ release_context (ctx);
+ gpgme_data_release (input);
+ gpgme_data_release (output);
+ return err;
+}
+
+
+
+static const char hlp_decrypt[] =
+ "op: \"decrypt\"\n"
+ "data: The encrypted data.\n"
+ "\n"
+ "Optional parameters:\n"
+ "protocol: Either \"openpgp\" (default) or \"cms\".\n"
+ "chunksize: Max number of bytes in the resulting \"data\".\n"
+ "\n"
+ "Optional boolean flags (default is false):\n"
+ "base64: Input data is base64 encoded.\n"
+ "\n"
+ "Response on success:\n"
+ "type: \"plaintext\"\n"
+ "data: The decrypted data. This may be base64 encoded.\n"
+ "base64: Boolean indicating whether data is base64 encoded.\n"
+ "mime: A Boolean indicating whether the data is a MIME object.\n"
+ "info: An optional object with extra information.\n"
+ "more: Optional boolean indicating that \"getmore\" is required.";
+static gpg_error_t
+op_decrypt (cjson_t request, cjson_t result)
+{
+ gpg_error_t err;
+ gpgme_ctx_t ctx = NULL;
+ gpgme_protocol_t protocol;
+ size_t chunksize;
+ int opt_base64;
+ cjson_t j_input;
+ gpgme_data_t input = NULL;
+ gpgme_data_t output = NULL;
+ gpgme_decrypt_result_t decrypt_result;
+
+ if ((err = get_protocol (request, &protocol)))
+ goto leave;
+ ctx = get_context (protocol);
+ if ((err = get_chunksize (request, &chunksize)))
+ goto leave;
+
+ if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
+ goto leave;
- /* Make sure that we really have a string. */
- gpgme_data_write (output, "", 1);
- buffer = gpgme_data_release_and_get_mem (output, NULL);
- if (!buffer)
+ /* Get the data. Note that INPUT is a shallow data object with the
+ * storage hold in REQUEST. */
+ j_input = cJSON_GetObjectItem (request, "data");
+ if (!j_input)
+ {
+ err = gpg_error (GPG_ERR_NO_DATA);
+ goto leave;
+ }
+ if (!cjson_is_string (j_input))
+ {
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ goto leave;
+ }
+ if (opt_base64)
+ {
+ err = data_from_base64_string (&input, j_input);
+ if (err)
{
- err = gpg_error_from_syserror ();
+ error_object (result, "Error decoding Base-64 encoded 'data': %s",
+ gpg_strerror (err));
goto leave;
}
- err = cjson_AddStringToObject (result, "data", buffer);
- gpgme_free (buffer);
- if (err)
- goto leave;
}
else
{
- err = add_base64_to_object (result, "data", output);
- output = NULL;
+ err = gpgme_data_new_from_mem (&input, j_input->valuestring,
+ strlen (j_input->valuestring), 0);
if (err)
- goto leave;
+ {
+ error_object (result, "Error getting 'data': %s", gpg_strerror (err));
+ goto leave;
+ }
}
- leave:
- if (keys)
+ /* Create an output data object. */
+ err = gpgme_data_new (&output);
+ if (err)
+ {
+ error_object (result, "Error creating output data object: %s",
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Decrypt. */
+ err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
+ input, output);
+ decrypt_result = gpgme_op_decrypt_result (ctx);
+ if (err)
{
- for (i=0; keys[i]; i++)
- gpgme_key_unref (keys[i]);
- xfree (keys);
+ error_object (result, "Decryption failed: %s", gpg_strerror (err));
+ goto leave;
}
+ gpgme_data_release (input);
+ input = NULL;
+
+ if (decrypt_result->is_mime)
+ xjson_AddBoolToObject (result, "mime", 1);
+
+ err = make_data_object (result, output, chunksize, "plaintext", -1);
+ output = NULL;
+
+ leave:
release_context (ctx);
gpgme_data_release (input);
+ gpgme_data_release (output);
return err;
}
+
+static const char hlp_getmore[] =
+ "op: \"getmore\"\n"
+ "\n"
+ "Optional parameters:\n"
+ "chunksize: Max number of bytes in the \"data\" object.\n"
+ "\n"
+ "Response on success:\n"
+ "type: Type of the pending data\n"
+ "data: The next chunk of data\n"
+ "base64: Boolean indicating whether data is base64 encoded\n"
+ "more: Optional boolean requesting another \"getmore\".";
+static gpg_error_t
+op_getmore (cjson_t request, cjson_t result)
+{
+ gpg_error_t err;
+ int c;
+ size_t n;
+ size_t chunksize;
+
+ if ((err = get_chunksize (request, &chunksize)))
+ goto leave;
+
+ /* Adjust the chunksize if we need to do base64 conversion. */
+ if (pending_data.base64)
+ chunksize = (chunksize / 4) * 3;
+
+ /* Do we have anything pending? */
+ if (!pending_data.buffer)
+ {
+ err = gpg_error (GPG_ERR_NO_DATA);
+ error_object (result, "Operation not possible: %s", gpg_strerror (err));
+ goto leave;
+ }
+
+ xjson_AddStringToObject (result, "type", pending_data.type);
+ xjson_AddBoolToObject (result, "base64", pending_data.base64);
+ if (pending_data.written >= pending_data.length)
+ {
+ /* EOF reached. This should not happen but we return an empty
+ * string once in case of client errors. */
+ gpgme_free (pending_data.buffer);
+ pending_data.buffer = NULL;
+ xjson_AddBoolToObject (result, "more", 0);
+ err = cjson_AddStringToObject (result, "data", "");
+ }
+ else
+ {
+ n = pending_data.length - pending_data.written;
+ if (n > chunksize)
+ {
+ n = chunksize;
+ xjson_AddBoolToObject (result, "more", 1);
+ }
+ else
+ xjson_AddBoolToObject (result, "more", 0);
+
+ c = pending_data.buffer[pending_data.written + n];
+ pending_data.buffer[pending_data.written + n] = 0;
+ if (pending_data.base64)
+ err = add_base64_to_object (result, "data",
+ (pending_data.buffer
+ + pending_data.written), n);
+ else
+ err = cjson_AddStringToObject (result, "data",
+ (pending_data.buffer
+ + pending_data.written));
+ pending_data.buffer[pending_data.written + n] = c;
+ if (!err)
+ {
+ pending_data.written += n;
+ if (pending_data.written >= pending_data.length)
+ {
+ gpgme_free (pending_data.buffer);
+ pending_data.buffer = NULL;
+ }
+ }
+ }
+
+ leave:
+ return err;
+}
+
+
+
static const char hlp_help[] =
"The tool expects a JSON object with the request and responds with\n"
"another JSON object. Even on error a JSON object is returned. The\n"
@@ -735,6 +1052,7 @@ static const char hlp_help[] =
"returned. To list all operations it is allowed to leave out \"op\" in\n"
"help mode. Supported values for \"op\" are:\n\n"
" encrypt Encrypt data.\n"
+ " getmore Retrieve remaining data.\n"
" help Help overview.";
static gpg_error_t
op_help (cjson_t request, cjson_t result)
@@ -757,6 +1075,10 @@ op_help (cjson_t request, cjson_t result)
}
+
+/*
+ * Dispatcher
+ */
/* Process a request and return the response. The response is a newly
* allocated string or NULL in case of an error. */
@@ -769,8 +1091,8 @@ process_request (const char *request)
const char * const helpstr;
} optbl[] = {
{ "encrypt", op_encrypt, hlp_encrypt },
-
-
+ { "decrypt", op_decrypt, hlp_decrypt },
+ { "getmore", op_getmore, hlp_getmore },
{ "help", op_help, hlp_help },
{ NULL }
};
@@ -825,6 +1147,14 @@ process_request (const char *request)
{
gpg_error_t err;
+ /* If this is not the "getmore" command and we have any
+ * pending data release that data. */
+ if (pending_data.buffer && optbl[idx].handler != op_getmore)
+ {
+ gpgme_free (pending_data.buffer);
+ pending_data.buffer = NULL;
+ }
+
err = optbl[idx].handler (json, response);
if (err)
{
@@ -839,7 +1169,6 @@ process_request (const char *request)
xjson_AddStringToObject (response, "op", op);
}
-
}
}
else /* Operation not supported. */
@@ -866,6 +1195,48 @@ process_request (const char *request)
* Driver code
*/
+static char *
+get_file (const char *fname)
+{
+ gpg_error_t err;
+ estream_t fp;
+ struct stat st;
+ char *buf;
+ size_t buflen;
+
+ fp = es_fopen (fname, "r");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
+ return NULL;
+ }
+
+ if (fstat (es_fileno(fp), &st))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
+ es_fclose (fp);
+ return NULL;
+ }
+
+ buflen = st.st_size;
+ buf = xmalloc (buflen+1);
+ if (es_fread (buf, buflen, 1, fp) != 1)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
+ es_fclose (fp);
+ xfree (buf);
+ return NULL;
+ }
+ buf[buflen] = 0;
+ es_fclose (fp);
+
+ return buf;
+}
+
+
/* Return a malloced line or NULL on EOF. Terminate on read
* error. */
static char *
@@ -929,14 +1300,39 @@ process_meta_commands (const char *request)
request++;
if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
- result = process_request ("{ \"op\": \"help\","
- " \"interactive_help\": "
- "\"\\nMeta commands:\\n"
- " ,help This help\\n"
- " ,quit Terminate process\""
- "}");
+ {
+ if (request[4])
+ {
+ char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
+ "\" }", NULL);
+ result = process_request (buf);
+ xfree (buf);
+ }
+ else
+ result = process_request ("{ \"op\": \"help\","
+ " \"interactive_help\": "
+ "\"\\nMeta commands:\\n"
+ " ,read FNAME Process data from FILE\\n"
+ " ,help CMD Print help for a command\\n"
+ " ,quit Terminate process\""
+ "}");
+ }
else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
exit (0);
+ else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
+ {
+ if (!request[4])
+ log_info ("usage: ,read FILENAME\n");
+ else
+ {
+ char *buffer = get_file (request + 5);
+ if (buffer)
+ {
+ result = process_request (buffer);
+ xfree (buffer);
+ }
+ }
+ }
else
log_info ("invalid meta command\n");
diff --git a/src/gpgme.c b/src/gpgme.c
index 9e65c50a..82d67478 100644
--- a/src/gpgme.c
+++ b/src/gpgme.c
@@ -538,6 +538,10 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
if (!ctx->request_origin)
err = gpg_error_from_syserror ();
}
+ else if (!strcmp (name, "no-symkey-cache"))
+ {
+ ctx->no_symkey_cache = abool;
+ }
else
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
@@ -583,6 +587,10 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name)
{
return ctx->request_origin? ctx->request_origin : "";
}
+ else if (!strcmp (name, "no-symkey-cache"))
+ {
+ return ctx->no_symkey_cache? "1":"";
+ }
else
return NULL;
}
diff --git a/src/gpgme.def b/src/gpgme.def
index cad30f6c..a01d89a2 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -267,5 +267,10 @@ EXPORTS
gpgme_op_conf_dir @199
+ gpgme_op_encrypt_ext @200
+ gpgme_op_encrypt_ext_start @201
+ gpgme_op_encrypt_sign_ext @202
+ gpgme_op_encrypt_sign_ext_start @203
+
; END
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index e3198798..49fafb90 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1,6 +1,6 @@
/* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*-
* Copyright (C) 2000 Werner Koch (dd9jn)
- * Copyright (C) 2001-2017 g10 Code GmbH
+ * Copyright (C) 2001-2018 g10 Code GmbH
*
* This file is part of GPGME.
*
@@ -16,6 +16,7 @@
*
* 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/>.
+ * SPDX-License-Identifier: LGPL-2.1+
*
* Generated from gpgme.h.in for @GPGME_CONFIG_HOST@.
*/
@@ -37,14 +38,14 @@ extern "C" {
/* The version of this header should match the one of the library. Do
- not use this symbol in your application, use gpgme_check_version
- instead. The purpose of this macro is to let autoconf (using the
- AM_PATH_GPGME macro) check that this header matches the installed
- library. */
+ * not use this symbol in your application, use gpgme_check_version
+ * instead. The purpose of this macro is to let autoconf (using the
+ * AM_PATH_GPGME macro) check that this header matches the installed
+ * library. */
#define GPGME_VERSION "@PACKAGE_VERSION@"
/* The version number of this header. It may be used to handle minor
- API incompatibilities. */
+ * API incompatibilities. */
#define GPGME_VERSION_NUMBER @VERSION_NUMBER@
@@ -87,7 +88,7 @@ extern "C" {
/* The macro _GPGME_DEPRECATED_OUTSIDE_GPGME suppresses warnings for
- fields we must access in GPGME for ABI compatibility. */
+ * fields we must access in GPGME for ABI compatibility. */
#ifdef _GPGME_IN_GPGME
#define _GPGME_DEPRECATED_OUTSIDE_GPGME(a,b)
#else
@@ -113,7 +114,7 @@ extern "C" {
*/
/* The context holds some global state and configuration options, as
- well as the results of a crypto operation. */
+ * well as the results of a crypto operation. */
struct gpgme_context;
typedef struct gpgme_context *gpgme_ctx_t;
@@ -124,7 +125,8 @@ typedef struct gpgme_data *gpgme_data_t;
/*
- * Wrappers for the libgpg-error library.
+ * Wrappers for the libgpg-error library. They are generally not
+ * needed and the gpg-error versions may be used instead.
*/
typedef gpg_error_t gpgme_error_t;
@@ -140,7 +142,7 @@ gpgme_err_make (gpgme_err_source_t source, gpgme_err_code_t code)
/* The user can define GPGME_ERR_SOURCE_DEFAULT before including this
- file to specify a default source for gpgme_error. */
+ * file to specify a default source for gpgme_error. */
#ifndef GPGME_ERR_SOURCE_DEFAULT
#define GPGME_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_USER_1
#endif
@@ -167,45 +169,46 @@ gpgme_err_source (gpgme_error_t err)
/* Return a pointer to a string containing a description of the error
- code in the error value ERR. This function is not thread safe. */
+ * code in the error value ERR. This function is not thread safe. */
const char *gpgme_strerror (gpgme_error_t err);
/* Return the error string for ERR in the user-supplied buffer BUF of
- size BUFLEN. This function is, in contrast to gpg_strerror,
- thread-safe if a thread-safe strerror_r() function is provided by
- the system. If the function succeeds, 0 is returned and BUF
- contains the string describing the error. If the buffer was not
- large enough, ERANGE is returned and BUF contains as much of the
- beginning of the error string as fits into the buffer. */
+ * size BUFLEN. This function is, in contrast to gpg_strerror,
+ * thread-safe if a thread-safe strerror_r() function is provided by
+ * the system. If the function succeeds, 0 is returned and BUF
+ * contains the string describing the error. If the buffer was not
+ * large enough, ERANGE is returned and BUF contains as much of the
+ * beginning of the error string as fits into the buffer. */
int gpgme_strerror_r (gpg_error_t err, char *buf, size_t buflen);
/* Return a pointer to a string containing a description of the error
- source in the error value ERR. */
+ * source in the error value ERR. */
const char *gpgme_strsource (gpgme_error_t err);
/* Retrieve the error code for the system error ERR. This returns
- GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
- this). */
+ * GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
+ * this). */
gpgme_err_code_t gpgme_err_code_from_errno (int err);
/* Retrieve the system error for the error code CODE. This returns 0
- if CODE is not a system error code. */
+ * if CODE is not a system error code. */
int gpgme_err_code_to_errno (gpgme_err_code_t code);
/* Retrieve the error code directly from the ERRNO variable. This
- returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped
- (report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */
+ * returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped
+ * (report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */
gpgme_err_code_t gpgme_err_code_from_syserror (void);
/* Set the ERRNO variable. This function is the preferred way to set
- ERRNO due to peculiarities on WindowsCE. */
+ * ERRNO due to peculiarities on WindowsCE. */
void gpgme_err_set_errno (int err);
/* Return an error value with the error source SOURCE and the system
- error ERR. FIXME: Should be inline. */
+ * error ERR. FIXME: Should be inline. */
gpgme_error_t gpgme_err_make_from_errno (gpgme_err_source_t source, int err);
-/* Return an error value with the system error ERR. FIXME: Should be inline. */
+/* Return an error value with the system error ERR.
+ * inline. */
gpgme_error_t gpgme_error_from_errno (int err);
@@ -373,6 +376,8 @@ gpgme_protocol_t;
#define GPGME_KEYLIST_MODE_EPHEMERAL 128
#define GPGME_KEYLIST_MODE_VALIDATE 256
+#define GPGME_KEYLIST_MODE_LOCATE (1|2)
+
typedef unsigned int gpgme_keylist_mode_t;
@@ -417,7 +422,7 @@ struct _gpgme_sig_notation
struct _gpgme_sig_notation *next;
/* If NAME is a null pointer, then VALUE contains a policy URL
- rather than a notation. */
+ * rather than a notation. */
char *name;
/* The value of the notation data. */
@@ -632,10 +637,10 @@ struct _gpgme_key_sig
/* Same as in gpgme_signature_t. */
gpgme_error_t status;
+ /* Deprecated; use SIG_CLASS instead. */
#ifdef __cplusplus
unsigned int _obsolete_class _GPGME_DEPRECATED(0,4);
#else
- /* Must be set to SIG_CLASS below. */
unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME(0,4);
#endif
@@ -874,10 +879,10 @@ gpgme_error_t gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t proto);
gpgme_protocol_t gpgme_get_protocol (gpgme_ctx_t ctx);
/* Set the crypto protocol to be used by CTX to PROTO.
- gpgme_set_protocol actually sets the backend engine. This sets the
- crypto protocol used in engines that support more than one crypto
- prococol (for example, an UISERVER can support OpenPGP and CMS).
- This is reset to the default with gpgme_set_protocol. */
+ * gpgme_set_protocol actually sets the backend engine. This sets the
+ * crypto protocol used in engines that support more than one crypto
+ * prococol (for example, an UISERVER can support OpenPGP and CMS).
+ * This is reset to the default with gpgme_set_protocol. */
gpgme_error_t gpgme_set_sub_protocol (gpgme_ctx_t ctx,
gpgme_protocol_t proto);
@@ -929,47 +934,47 @@ gpgme_error_t gpgme_set_pinentry_mode (gpgme_ctx_t ctx,
gpgme_pinentry_mode_t gpgme_get_pinentry_mode (gpgme_ctx_t ctx);
/* Set the passphrase callback function in CTX to CB. HOOK_VALUE is
- passed as first argument to the passphrase callback function. */
+ * passed as first argument to the passphrase callback function. */
void gpgme_set_passphrase_cb (gpgme_ctx_t ctx,
gpgme_passphrase_cb_t cb, void *hook_value);
/* Get the current passphrase callback function in *CB and the current
- hook value in *HOOK_VALUE. */
+ * hook value in *HOOK_VALUE. */
void gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *cb,
void **hook_value);
/* Set the progress callback function in CTX to CB. HOOK_VALUE is
- passed as first argument to the progress callback function. */
+ * passed as first argument to the progress callback function. */
void gpgme_set_progress_cb (gpgme_ctx_t c, gpgme_progress_cb_t cb,
void *hook_value);
/* Get the current progress callback function in *CB and the current
- hook value in *HOOK_VALUE. */
+ * hook value in *HOOK_VALUE. */
void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb,
void **hook_value);
/* Set the status callback function in CTX to CB. HOOK_VALUE is
- passed as first argument to the status callback function. */
+ * passed as first argument to the status callback function. */
void gpgme_set_status_cb (gpgme_ctx_t c, gpgme_status_cb_t cb,
void *hook_value);
/* Get the current status callback function in *CB and the current
- hook value in *HOOK_VALUE. */
+ * hook value in *HOOK_VALUE. */
void gpgme_get_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t *cb,
void **hook_value);
/* This function sets the locale for the context CTX, or the default
- locale if CTX is a null pointer. */
+ * locale if CTX is a null pointer. */
gpgme_error_t gpgme_set_locale (gpgme_ctx_t ctx, int category,
const char *value);
/* Get the information about the configured engines. A pointer to the
- first engine in the statically allocated linked list is returned.
- The returned data is valid until the next gpgme_ctx_set_engine_info. */
+ * first engine in the statically allocated linked list is returned.
+ * The returned data is valid until the next gpgme_ctx_set_engine_info. */
gpgme_engine_info_t gpgme_ctx_get_engine_info (gpgme_ctx_t ctx);
/* Set the engine info for the context CTX, protocol PROTO, to the
- file name FILE_NAME and the home directory HOME_DIR. */
+ * file name FILE_NAME and the home directory HOME_DIR. */
gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx,
gpgme_protocol_t proto,
const char *file_name,
@@ -991,10 +996,10 @@ gpgme_key_t gpgme_signers_enum (const gpgme_ctx_t ctx, int seq);
void gpgme_sig_notation_clear (gpgme_ctx_t ctx);
/* Add the human-readable notation data with name NAME and value VALUE
- to the context CTX, using the flags FLAGS. If NAME is NULL, then
- VALUE should be a policy URL. The flag
- GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
- data, and false for policy URLs. */
+ * to the context CTX, using the flags FLAGS. If NAME is NULL, then
+ * VALUE should be a policy URL. The flag
+ * GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
+ * data, and false for policy URLs. */
gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name,
const char *value,
gpgme_sig_notation_flags_t flags);
@@ -1018,17 +1023,17 @@ const char *gpgme_get_sender (gpgme_ctx_t ctx);
typedef gpgme_error_t (*gpgme_io_cb_t) (void *data, int fd);
/* The type of a function that can register FNC as the I/O callback
- function for the file descriptor FD with direction dir (0: for writing,
- 1: for reading). FNC_DATA should be passed as DATA to FNC. The
- function should return a TAG suitable for the corresponding
- gpgme_remove_io_cb_t, and an error value. */
+ * function for the file descriptor FD with direction dir (0: for writing,
+ * 1: for reading). FNC_DATA should be passed as DATA to FNC. The
+ * function should return a TAG suitable for the corresponding
+ * gpgme_remove_io_cb_t, and an error value. */
typedef gpgme_error_t (*gpgme_register_io_cb_t) (void *data, int fd, int dir,
gpgme_io_cb_t fnc,
void *fnc_data, void **tag);
/* The type of a function that can remove a previously registered I/O
- callback function given TAG as returned by the register
- function. */
+ * callback function given TAG as returned by the register
+ * function. */
typedef void (*gpgme_remove_io_cb_t) (void *tag);
typedef enum
@@ -1043,7 +1048,7 @@ gpgme_event_io_t;
struct gpgme_io_event_done_data
{
/* A fatal IPC error or an operational error in state-less
- protocols. */
+ * protocols. */
gpgme_error_t err;
/* An operational errors in session-based protocols. */
@@ -1052,7 +1057,7 @@ struct gpgme_io_event_done_data
typedef struct gpgme_io_event_done_data *gpgme_io_event_done_data_t;
/* The type of a function that is called when a context finished an
- operation. */
+ * operation. */
typedef void (*gpgme_event_io_cb_t) (void *data, gpgme_event_io_t type,
void *type_data);
@@ -1073,13 +1078,13 @@ void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
void gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
/* Wrappers around the internal I/O functions for use with
- gpgme_passphrase_cb_t and gpgme_interact_cb_t. */
+ * gpgme_passphrase_cb_t and gpgme_interact_cb_t. */
@API__SSIZE_T@ gpgme_io_read (int fd, void *buffer, size_t count);
@API__SSIZE_T@ gpgme_io_write (int fd, const void *buffer, size_t count);
int gpgme_io_writen (int fd, const void *buffer, size_t count);
/* Process the pending operation and, if HANG is non-zero, wait for
- the pending operation to finish. */
+ * the pending operation to finish. */
gpgme_ctx_t gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang);
gpgme_ctx_t gpgme_wait_ext (gpgme_ctx_t ctx, gpgme_error_t *status,
@@ -1098,21 +1103,21 @@ gpgme_error_t gpgme_cancel_async (gpgme_ctx_t ctx);
*/
/* Read up to SIZE bytes into buffer BUFFER from the data object with
- the handle HANDLE. Return the number of characters read, 0 on EOF
- and -1 on error. If an error occurs, errno is set. */
+ * the handle HANDLE. Return the number of characters read, 0 on EOF
+ * and -1 on error. If an error occurs, errno is set. */
typedef @API__SSIZE_T@ (*gpgme_data_read_cb_t) (void *handle, void *buffer,
size_t size);
/* Write up to SIZE bytes from buffer BUFFER to the data object with
- the handle HANDLE. Return the number of characters written, or -1
- on error. If an error occurs, errno is set. */
+ * the handle HANDLE. Return the number of characters written, or -1
+ * on error. If an error occurs, errno is set. */
typedef @API__SSIZE_T@ (*gpgme_data_write_cb_t) (void *handle, const void *buffer,
size_t size);
/* Set the current position from where the next read or write starts
- in the data object with the handle HANDLE to OFFSET, relativ to
- WHENCE. Returns the new offset in bytes from the beginning of the
- data object. */
+ * in the data object with the handle HANDLE to OFFSET, relativ to
+ * WHENCE. Returns the new offset in bytes from the beginning of the
+ * data object. */
typedef @API__OFF_T@ (*gpgme_data_seek_cb_t) (void *handle,
@API__OFF_T@ offset, int whence);
@@ -1129,19 +1134,19 @@ struct gpgme_data_cbs
typedef struct gpgme_data_cbs *gpgme_data_cbs_t;
/* Read up to SIZE bytes into buffer BUFFER from the data object with
- the handle DH. Return the number of characters read, 0 on EOF and
- -1 on error. If an error occurs, errno is set. */
+ * the handle DH. Return the number of characters read, 0 on EOF and
+ * -1 on error. If an error occurs, errno is set. */
@API__SSIZE_T@ gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size);
/* Write up to SIZE bytes from buffer BUFFER to the data object with
- the handle DH. Return the number of characters written, or -1 on
- error. If an error occurs, errno is set. */
+ * the handle DH. Return the number of characters written, or -1 on
+ * error. If an error occurs, errno is set. */
@API__SSIZE_T@ gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size);
/* Set the current position from where the next read or write starts
- in the data object with the handle DH to OFFSET, relativ to WHENCE.
- Returns the new offset in bytes from the beginning of the data
- object. */
+ * in the data object with the handle DH to OFFSET, relativ to WHENCE.
+ * Returns the new offset in bytes from the beginning of the data
+ * object. */
@API__OFF_T@ gpgme_data_seek (gpgme_data_t dh, @API__OFF_T@ offset, int whence);
/* Create a new data buffer and return it in R_DH. */
@@ -1151,19 +1156,19 @@ gpgme_error_t gpgme_data_new (gpgme_data_t *r_dh);
void gpgme_data_release (gpgme_data_t dh);
/* Create a new data buffer filled with SIZE bytes starting from
- BUFFER. If COPY is zero, copying is delayed until necessary, and
- the data is taken from the original location when needed. */
+ * BUFFER. If COPY is zero, copying is delayed until necessary, and
+ * the data is taken from the original location when needed. */
gpgme_error_t gpgme_data_new_from_mem (gpgme_data_t *r_dh,
const char *buffer, size_t size,
int copy);
/* Destroy the data buffer DH and return a pointer to its content.
- The memory has be to released with gpgme_free() by the user. It's
- size is returned in R_LEN. */
+ * The memory has be to released with gpgme_free() by the user. It's
+ * size is returned in R_LEN. */
char *gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len);
/* Release the memory returned by gpgme_data_release_and_get_mem() and
- some other functions. */
+ * some other functions. */
void gpgme_free (void *buffer);
gpgme_error_t gpgme_data_new_from_cbs (gpgme_data_t *dh,
@@ -1182,11 +1187,11 @@ gpgme_error_t gpgme_data_set_encoding (gpgme_data_t dh,
gpgme_data_encoding_t enc);
/* Get the file name associated with the data object with handle DH, or
- NULL if there is none. */
+ * NULL if there is none. */
char *gpgme_data_get_file_name (gpgme_data_t dh);
/* Set the file name associated with the data object with handle DH to
- FILE_NAME. */
+ * FILE_NAME. */
gpgme_error_t gpgme_data_set_file_name (gpgme_data_t dh,
const char *file_name);
@@ -1199,15 +1204,15 @@ gpgme_data_type_t gpgme_data_identify (gpgme_data_t dh, int reserved);
/* Create a new data buffer filled with the content of file FNAME.
- COPY must be non-zero. For delayed read, please use
- gpgme_data_new_from_fd or gpgme_data_new_from_stream instead. */
+ * COPY must be non-zero. For delayed read, please use
+ * gpgme_data_new_from_fd or gpgme_data_new_from_stream instead. */
gpgme_error_t gpgme_data_new_from_file (gpgme_data_t *r_dh,
const char *fname,
int copy);
/* Create a new data buffer filled with LENGTH bytes starting from
- OFFSET within the file FNAME or stream FP (exactly one must be
- non-zero). */
+ * OFFSET within the file FNAME or stream FP (exactly one must be
+ * non-zero). */
gpgme_error_t gpgme_data_new_from_filepart (gpgme_data_t *r_dh,
const char *fname, FILE *fp,
@API__OFF_T@ offset, size_t length);
@@ -1222,7 +1227,7 @@ gpgme_error_t gpgme_data_rewind (gpgme_data_t dh);
*/
/* Get the key with the fingerprint FPR from the crypto backend. If
- SECRET is true, get the secret key. */
+ * SECRET is true, get the secret key. */
gpgme_error_t gpgme_get_key (gpgme_ctx_t ctx, const char *fpr,
gpgme_key_t *r_key, int secret);
@@ -1233,7 +1238,7 @@ gpgme_error_t gpgme_key_from_uid (gpgme_key_t *key, const char *name);
void gpgme_key_ref (gpgme_key_t key);
/* Release a reference to KEY. If this was the last one the key is
- destroyed. */
+ * destroyed. */
void gpgme_key_unref (gpgme_key_t key);
void gpgme_key_release (gpgme_key_t key);
@@ -1266,22 +1271,35 @@ typedef enum
GPGME_ENCRYPT_NO_COMPRESS = 16,
GPGME_ENCRYPT_SYMMETRIC = 32,
GPGME_ENCRYPT_THROW_KEYIDS = 64,
- GPGME_ENCRYPT_WRAP = 128
+ GPGME_ENCRYPT_WRAP = 128,
+ GPGME_ENCRYPT_WANT_ADDRESS = 256
}
gpgme_encrypt_flags_t;
/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
- store the resulting ciphertext in CIPHER. */
+ * store the resulting ciphertext in CIPHER. */
gpgme_error_t gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher);
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
gpgme_error_t gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher);
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t 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. */
+ * store the resulting ciphertext in CIPHER. Also sign the ciphertext
+ * with the signers in CTX. */
gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx,
gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
@@ -1289,7 +1307,19 @@ gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx,
gpgme_data_t cipher);
gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher);
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx,
+ gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
/*
@@ -1317,6 +1347,7 @@ struct _gpgme_recipient
};
typedef struct _gpgme_recipient *gpgme_recipient_t;
+
/* An object to return results from a decryption operation.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1331,24 +1362,33 @@ struct _gpgme_op_decrypt_result
* mode. */
unsigned int is_de_vs : 1;
+ /* The message claims that the content is a MIME object. */
+ unsigned int is_mime : 1;
+
/* Internal to GPGME, do not use. */
- int _unused : 30;
+ int _unused : 29;
gpgme_recipient_t recipients;
/* The original file name of the plaintext message, if
- available. */
+ * available. */
char *file_name;
/* A textual representation of the session key used to decrypt the
* message, if available */
char *session_key;
+
+ /* A string with the symmetric encryption algorithm and mode using
+ * the format "<algo>.<mode>". */
+ char *symkey_algo;
};
typedef struct _gpgme_op_decrypt_result *gpgme_decrypt_result_t;
+
/* Retrieve a pointer to the result of the decrypt operation. */
gpgme_decrypt_result_t gpgme_op_decrypt_result (gpgme_ctx_t ctx);
+
/* The valid decryption flags. */
typedef enum
{
@@ -1357,15 +1397,16 @@ typedef enum
}
gpgme_decrypt_flags_t;
+
/* Decrypt ciphertext CIPHER within CTX and store the resulting
- plaintext in PLAIN. */
+ * plaintext in PLAIN. */
gpgme_error_t gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
gpgme_data_t plain);
gpgme_error_t gpgme_op_decrypt (gpgme_ctx_t ctx,
gpgme_data_t cipher, gpgme_data_t plain);
/* Decrypt ciphertext CIPHER and make a signature verification within
- CTX and store the resulting plaintext in PLAIN. */
+ * CTX and store the resulting plaintext in PLAIN. */
gpgme_error_t gpgme_op_decrypt_verify_start (gpgme_ctx_t ctx,
gpgme_data_t cipher,
gpgme_data_t plain);
@@ -1407,7 +1448,7 @@ struct _gpgme_new_signature
gpgme_hash_algo_t hash_algo;
/* Internal to GPGME, do not use. Must be set to the same value as
- CLASS below. */
+ * CLASS below. */
unsigned long _obsolete_class;
/* Signature creation time. */
@@ -1416,10 +1457,10 @@ struct _gpgme_new_signature
/* The fingerprint of the signature. */
char *fpr;
+ /* Deprecated; use SIG_CLASS instead. */
#ifdef __cplusplus
unsigned int _obsolete_class_2;
#else
- /* Must be set to SIG_CLASS below. */
unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME(0,4);
#endif
@@ -1440,6 +1481,7 @@ struct _gpgme_op_sign_result
};
typedef struct _gpgme_op_sign_result *gpgme_sign_result_t;
+
/* Retrieve a pointer to the result of the signing operation. */
gpgme_sign_result_t gpgme_op_sign_result (gpgme_ctx_t ctx);
@@ -1533,6 +1575,7 @@ struct _gpgme_signature
};
typedef struct _gpgme_signature *gpgme_signature_t;
+
/* An object to return the results of a verify operation.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1543,9 +1586,16 @@ struct _gpgme_op_verify_result
/* The original file name of the plaintext message, if
available. */
char *file_name;
+
+ /* The message claims that the content is a MIME object. */
+ unsigned int is_mime : 1;
+
+ /* Internal to GPGME; do not use. */
+ unsigned int _unused : 31;
};
typedef struct _gpgme_op_verify_result *gpgme_verify_result_t;
+
/* Retrieve a pointer to the result of the verify operation. */
gpgme_verify_result_t gpgme_op_verify_result (gpgme_ctx_t ctx);
@@ -1590,6 +1640,7 @@ struct _gpgme_import_status
};
typedef struct _gpgme_import_status *gpgme_import_status_t;
+
/* Import result object.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1645,6 +1696,7 @@ struct _gpgme_op_import_result
};
typedef struct _gpgme_op_import_result *gpgme_import_result_t;
+
/* Retrieve a pointer to the result of the import operation. */
gpgme_import_result_t gpgme_op_import_result (gpgme_ctx_t ctx);
@@ -1702,6 +1754,7 @@ gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx,
#define GPGME_CREATE_FORCE (1 << 12) /* Force creation. */
#define GPGME_CREATE_NOEXPIRE (1 << 13) /* Create w/o expiration. */
+
/* An object to return result from a key generation.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1732,9 +1785,10 @@ struct _gpgme_op_genkey_result
};
typedef struct _gpgme_op_genkey_result *gpgme_genkey_result_t;
+
/* Generate a new keypair and add it to the keyring. PUBKEY and
- SECKEY should be null for now. PARMS specifies what keys should be
- generated. */
+ * SECKEY should be null for now. PARMS specifies what keys should be
+ * generated. */
gpgme_error_t gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
gpgme_data_t pubkey, gpgme_data_t seckey);
gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms,
@@ -1800,7 +1854,7 @@ gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx);
/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret
- keys are also deleted. */
+ * keys are also deleted. */
gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key,
int allow_secret);
gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key,
@@ -1919,7 +1973,7 @@ gpgme_error_t gpgme_op_keylist_end (gpgme_ctx_t ctx);
*/
/* Change the passphrase for KEY. FLAGS is reserved for future use
- and must be passed as 0. */
+ * and must be passed as 0. */
gpgme_error_t gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key,
unsigned int flags);
gpgme_error_t gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key,
@@ -1984,7 +2038,7 @@ gpgme_error_t gpgme_op_trustlist_end (gpgme_ctx_t ctx);
void gpgme_trust_item_ref (gpgme_trust_item_t item);
/* Release a reference to ITEM. If this was the last one the trust
- item is destroyed. */
+ * item is destroyed. */
void gpgme_trust_item_unref (gpgme_trust_item_t item);
@@ -2014,8 +2068,8 @@ gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output,
/* Run the command FILE with the arguments in ARGV. Connect stdin to
- DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data
- streams is NULL, connect to /dev/null instead. */
+ * DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data
+ * streams is NULL, connect to /dev/null instead. */
gpgme_error_t gpgme_op_spawn_start (gpgme_ctx_t ctx,
const char *file, const char *argv[],
gpgme_data_t datain,
@@ -2031,6 +2085,7 @@ gpgme_error_t gpgme_op_spawn (gpgme_ctx_t ctx,
/*
* Low-level Assuan protocol access.
*/
+
typedef gpgme_error_t (*gpgme_assuan_data_cb_t)
(void *opaque, const void *data, size_t datalen);
@@ -2042,7 +2097,7 @@ typedef gpgme_error_t (*gpgme_assuan_status_cb_t)
(void *opaque, const char *status, const char *args);
/* Send the Assuan COMMAND and return results via the callbacks.
- Asynchronous variant. */
+ * Asynchronous variant. */
gpgme_error_t gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,
const char *command,
gpgme_assuan_data_cb_t data_cb,
@@ -2053,7 +2108,7 @@ gpgme_error_t gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,
void *stat_cb_value);
/* Send the Assuan COMMAND and return results via the callbacks.
- Synchronous variant. */
+ * Synchronous variant. */
gpgme_error_t gpgme_op_assuan_transact_ext (gpgme_ctx_t ctx,
const char *command,
gpgme_assuan_data_cb_t data_cb,
@@ -2081,8 +2136,8 @@ typedef struct _gpgme_op_vfs_mount_result *gpgme_vfs_mount_result_t;
gpgme_vfs_mount_result_t gpgme_op_vfs_mount_result (gpgme_ctx_t ctx);
/* The container is automatically unmounted when the context is reset
- or destroyed. Transmission errors are returned directly,
- operational errors are returned in OP_ERR. */
+ * or destroyed. Transmission errors are returned directly,
+ * operational errors are returned in OP_ERR. */
gpgme_error_t gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file,
const char *mount_dir, unsigned int flags,
gpgme_error_t *op_err);
@@ -2097,8 +2152,8 @@ gpgme_error_t gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
*/
/* The expert level at which a configuration option or group of
- options should be displayed. See the gpgconf(1) documentation for
- more details. */
+ * options should be displayed. See the gpgconf(1) documentation for
+ * more details. */
typedef enum
{
GPGME_CONF_BASIC = 0,
@@ -2111,7 +2166,7 @@ gpgme_conf_level_t;
/* The data type of a configuration option argument. See the gpgconf(1)
- documentation for more details. */
+ * documentation for more details. */
typedef enum
{
/* Basic types. */
@@ -2135,7 +2190,7 @@ gpgme_conf_type_t;
/* This represents a single argument for a configuration option.
- Which of the members of value is used depends on the ALT_TYPE. */
+ * Which of the members of value is used depends on the ALT_TYPE. */
typedef struct gpgme_conf_arg
{
struct gpgme_conf_arg *next;
@@ -2152,7 +2207,7 @@ typedef struct gpgme_conf_arg
/* The flags of a configuration option. See the gpgconf
- documentation for details. */
+ * documentation for details. */
#define GPGME_CONF_GROUP (1 << 0)
#define GPGME_CONF_OPTIONAL (1 << 1)
#define GPGME_CONF_LIST (1 << 2)
@@ -2164,7 +2219,7 @@ typedef struct gpgme_conf_arg
/* The representation of a single configuration option. See the
- gpg-conf documentation for details. */
+ * gpg-conf documentation for details. */
typedef struct gpgme_conf_opt
{
struct gpgme_conf_opt *next;
@@ -2209,7 +2264,7 @@ typedef struct gpgme_conf_opt
/* The representation of a component that can be configured. See the
- gpg-conf documentation for details. */
+ * gpg-conf documentation for details. */
typedef struct gpgme_conf_comp
{
struct gpgme_conf_comp *next;
@@ -2232,9 +2287,9 @@ typedef struct gpgme_conf_comp
/* Allocate a new gpgme_conf_arg_t. If VALUE is NULL, a "no arg
- default" is prepared. If type is a string type, VALUE should point
- to the string. Else, it should point to an unsigned or signed
- integer respectively. */
+ * default" is prepared. If type is a string type, VALUE should point
+ * to the string. Else, it should point to an unsigned or signed
+ * integer respectively. */
gpgme_error_t gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
gpgme_conf_type_t type, const void *value);
@@ -2242,10 +2297,10 @@ gpgme_error_t gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
void gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type);
/* Register a change for the value of OPT to ARG. If RESET is 1 (do
- not use any values but 0 or 1), ARG is ignored and the option is
- not changed (reverting a previous change). Otherwise, if ARG is
- NULL, the option is cleared or reset to its default. The change
- is done with gpgconf's --runtime option to immediately take effect. */
+ * not use any values but 0 or 1), ARG is ignored and the option is
+ * not changed (reverting a previous change). Otherwise, if ARG is
+ * NULL, the option is cleared or reset to its default. The change
+ * is done with gpgconf's --runtime option to immediately take effect. */
gpgme_error_t gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset,
gpgme_conf_arg_t arg);
@@ -2336,16 +2391,17 @@ gpgme_query_swdb_result_t gpgme_op_query_swdb_result (gpgme_ctx_t ctx);
int gpgme_set_global_flag (const char *name, const char *value);
/* Check that the library fulfills the version requirement. Note:
- This is here only for the case where a user takes a pointer from
- the old version of this function. The new version and macro for
- run-time checks are below. */
+ * This is here only for the case where a user takes a pointer from
+ * the old version of this function. The new version and macro for
+ * run-time checks are below. */
const char *gpgme_check_version (const char *req_version);
-/* Check that the library fulfills the version requirement and check
- for struct layout mismatch involving bitfields. */
+/* Do not call this directly; use the macro below. */
const char *gpgme_check_version_internal (const char *req_version,
size_t offset_sig_validity);
+/* Check that the library fulfills the version requirement and check
+ * for struct layout mismatch involving bitfields. */
#define gpgme_check_version(req_version) \
gpgme_check_version_internal (req_version, \
offsetof (struct _gpgme_signature, validity))
@@ -2354,19 +2410,19 @@ const char *gpgme_check_version_internal (const char *req_version,
const char *gpgme_get_dirinfo (const char *what);
/* Get the information about the configured and installed engines. A
- pointer to the first engine in the statically allocated linked list
- is returned in *INFO. If an error occurs, it is returned. The
- returned data is valid until the next gpgme_set_engine_info. */
+ * pointer to the first engine in the statically allocated linked list
+ * is returned in *INFO. If an error occurs, it is returned. The
+ * returned data is valid until the next gpgme_set_engine_info. */
gpgme_error_t gpgme_get_engine_info (gpgme_engine_info_t *engine_info);
/* Set the default engine info for the protocol PROTO to the file name
- FILE_NAME and the home directory HOME_DIR. */
+ * FILE_NAME and the home directory HOME_DIR. */
gpgme_error_t gpgme_set_engine_info (gpgme_protocol_t proto,
const char *file_name,
const char *home_dir);
/* Verify that the engine implementing PROTO is installed and
- available. */
+ * available. */
gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto);
@@ -2375,15 +2431,15 @@ void gpgme_result_ref (void *result);
void gpgme_result_unref (void *result);
/* Return a public key algorithm string (e.g. "rsa2048"). Caller must
- free using gpgme_free. */
+ * free using gpgme_free. */
char *gpgme_pubkey_algo_string (gpgme_subkey_t subkey);
/* Return a statically allocated string with the name of the public
- key algorithm ALGO, or NULL if that name is not known. */
+ * key algorithm ALGO, or NULL if that name is not known. */
const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo);
/* Return a statically allocated string with the name of the hash
- algorithm ALGO, or NULL if that name is not known. */
+ * algorithm ALGO, or NULL if that name is not known. */
const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo);
/* Return the addr-spec from a user id. Caller must free the result
@@ -2535,7 +2591,7 @@ gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
_GPGME_DEPRECATED(1,7);
/* The possible signature stati. Deprecated, use error value in sig
- status. */
+ * status. */
typedef enum
{
GPGME_SIG_STAT_NONE = 0,
@@ -2552,7 +2608,7 @@ _gpgme_sig_stat_t;
typedef _gpgme_sig_stat_t gpgme_sig_stat_t _GPGME_DEPRECATED(0,4);
/* The available key and signature attributes. Deprecated, use the
- individual result structures instead. */
+ * individual result structures instead. */
typedef enum
{
GPGME_ATTR_KEYID = 1,
@@ -2592,18 +2648,18 @@ _gpgme_attr_t;
typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED(0,4);
/* Retrieve the signature status of signature IDX in CTX after a
- successful verify operation in R_STAT (if non-null). The creation
- time stamp of the signature is returned in R_CREATED (if non-null).
- The function returns a string containing the fingerprint.
- Deprecated, use verify result directly. */
+ * successful verify operation in R_STAT (if non-null). The creation
+ * time stamp of the signature is returned in R_CREATED (if non-null).
+ * The function returns a string containing the fingerprint.
+ * Deprecated, use verify result directly. */
const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
_gpgme_sig_stat_t *r_stat,
time_t *r_created) _GPGME_DEPRECATED(0,4);
/* Retrieve certain attributes of a signature. IDX is the index
- number of the signature after a successful verify operation. WHAT
- is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
- one. WHATIDX is to be passed as 0 for most attributes . */
+ * number of the signature after a successful verify operation. WHAT
+ * is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
+ * one. WHATIDX is to be passed as 0 for most attributes . */
unsigned long gpgme_get_sig_ulong_attr (gpgme_ctx_t c, int idx,
_gpgme_attr_t what, int whatidx)
_GPGME_DEPRECATED(0,4);
@@ -2613,13 +2669,13 @@ const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx,
/* Get the key used to create signature IDX in CTX and return it in
- R_KEY. */
+ * R_KEY. */
gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
_GPGME_DEPRECATED(0,4);
/* Create a new data buffer which retrieves the data from the callback
- function READ_CB. Deprecated, please use gpgme_data_new_from_cbs
- instead. */
+ * function READ_CB. Deprecated, please use gpgme_data_new_from_cbs
+ * instead. */
gpgme_error_t gpgme_data_new_with_read_cb (gpgme_data_t *r_dh,
int (*read_cb) (void*,char *,
size_t,size_t*),
@@ -2627,34 +2683,34 @@ gpgme_error_t gpgme_data_new_with_read_cb (gpgme_data_t *r_dh,
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
- representable by a string. IDX specifies the sub key or user ID
- for attributes related to sub keys or user IDs. Deprecated, use
- key structure directly instead. */
+ * representable by a string. IDX specifies the sub key or user ID
+ * for attributes related to sub keys or user IDs. Deprecated, use
+ * key structure directly instead. */
const char *gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
- representable by an unsigned integer. IDX specifies the sub key or
- user ID for attributes related to sub keys or user IDs.
- Deprecated, use key structure directly instead. */
+ * representable by an unsigned integer. IDX specifies the sub key or
+ * user ID for attributes related to sub keys or user IDs.
+ * Deprecated, use key structure directly instead. */
unsigned long gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of a signature on user ID
- UID_IDX in KEY, which has to be representable by a string. IDX
- specifies the signature. Deprecated, use key structure directly
- instead. */
+ * UID_IDX in KEY, which has to be representable by a string. IDX
+ * specifies the signature. Deprecated, use key structure directly
+ * instead. */
const char *gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
_gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of a signature on user ID
- UID_IDX in KEY, which has to be representable by an unsigned
- integer string. IDX specifies the signature. Deprecated, use key
- structure directly instead. */
+ * UID_IDX in KEY, which has to be representable by an unsigned
+ * integer string. IDX specifies the signature. Deprecated, use key
+ * structure directly instead. */
unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx,
_gpgme_attr_t what,
const void *reserved, int idx)
@@ -2665,21 +2721,21 @@ gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata,
int *nr) _GPGME_DEPRECATED(0,4);
/* Release the trust item ITEM. Deprecated, use
- gpgme_trust_item_unref. */
+ * gpgme_trust_item_unref. */
void gpgme_trust_item_release (gpgme_trust_item_t item) _GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of ITEM, which has to be
- representable by a string. Deprecated, use trust item structure
- directly. */
+ * representable by a string. Deprecated, use trust item structure
+ * directly. */
const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item,
_gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
- representable by an integer. IDX specifies a running index if the
- attribute appears more than once in the key. Deprecated, use trust
- item structure directly. */
+ * representable by an integer. IDX specifies a running index if the
+ * attribute appears more than once in the key. Deprecated, use trust
+ * item structure directly. */
int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index a95befba..b49c86d9 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -215,10 +215,15 @@ GPGME_1.0 {
gpgme_op_edit;
gpgme_op_edit_start;
gpgme_op_encrypt;
- gpgme_op_encrypt_result;
+ gpgme_op_encrypt_start;
+ gpgme_op_encrypt_ext;
+ gpgme_op_encrypt_ext_start;
gpgme_op_encrypt_sign;
+ gpgme_op_encrypt_sign_ext;
gpgme_op_encrypt_sign_start;
- gpgme_op_encrypt_start;
+ gpgme_op_encrypt_sign_ext_start;
+ gpgme_op_encrypt_result;
+
gpgme_op_export;
gpgme_op_export_ext;
gpgme_op_export_ext_start;
diff --git a/src/op-support.c b/src/op-support.c
index 43cb1c76..9414e612 100644
--- a/src/op-support.c
+++ b/src/op-support.c
@@ -358,7 +358,7 @@ _gpgme_parse_key_considered (const char *args,
/* Parse the PLAINTEXT status line in ARGS and return the result in
FILENAMEP. */
gpgme_error_t
-_gpgme_parse_plaintext (char *args, char **filenamep)
+_gpgme_parse_plaintext (char *args, char **filenamep, int *r_mime)
{
char *tail;
@@ -367,7 +367,9 @@ _gpgme_parse_plaintext (char *args, char **filenamep)
if (*args == '\0')
return 0;
- /* First argument is file type. */
+ /* First argument is file type (a one byte uppercase hex value). */
+ if (args[0] == '6' && args[1] == 'D')
+ *r_mime = 1;
while (*args != ' ' && *args != '\0')
args++;
while (*args == ' ')
@@ -400,12 +402,21 @@ _gpgme_parse_plaintext (char *args, char **filenamep)
/* Parse a FAILURE status line and return the error code. ARGS is
- modified to contain the location part. */
+ * modified to contain the location part. Note that for now we ignore
+ * failure codes with a location of gpg-exit; they are too trouble
+ * some. Instead we should eventually record that error in the
+ * context and provide a function to return a fuller error
+ * description; this could then also show the location of the error
+ * (e.g. "option- parser") to make it easier for the user to detect
+ * the actual error. */
gpgme_error_t
_gpgme_parse_failure (char *args)
{
char *where, *which;
+ if (!strncmp (args, "gpg-exit", 8))
+ return 0;
+
where = strchr (args, ' ');
if (!where)
return trace_gpg_error (GPG_ERR_INV_ENGINE);
@@ -417,7 +428,5 @@ _gpgme_parse_failure (char *args)
if (where)
*where = '\0';
- where = args;
-
return atoi (which);
}
diff --git a/src/ops.h b/src/ops.h
index cc61dc4f..5955454c 100644
--- a/src/ops.h
+++ b/src/ops.h
@@ -68,8 +68,8 @@ gpgme_error_t _gpgme_parse_inv_recp (char *args, int for_signing,
gpgme_invalid_key_t *key);
/* Parse the PLAINTEXT status line in ARGS and return the result in
- FILENAMEP. */
-gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep);
+ FILENAMEP and R_MIME. */
+gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep,int *r_mime);
/* Parse a FAILURE status line and return the error code. ARGS is
modified to contain the location part. */
diff --git a/src/util.h b/src/util.h
index b4043ed1..da929eb4 100644
--- a/src/util.h
+++ b/src/util.h
@@ -165,10 +165,11 @@ time_t _gpgme_parse_timestamp (const char *timestamp, char **endp);
* on error or missing timestamp. */
unsigned long _gpgme_parse_timestamp_ul (const char *timestamp);
-gpgme_error_t _gpgme_map_gnupg_error (char *err);
-
int _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol);
+const char *_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol);
+const char *_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol);
+
/*-- b64dec.c --*/
diff --git a/src/verify.c b/src/verify.c
index ee730a34..26b205aa 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -284,6 +284,7 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
gpgme_signature_t sig;
char *end = strchr (args, ' ');
char *tail;
+ int got_fpr = 0;
if (end)
{
@@ -370,7 +371,23 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
if (!*end)
goto parse_err_sig_fail;
- sig->status = strtoul (end, NULL, 10);
+ gpg_err_set_errno (0);
+ sig->status = strtoul (end, &tail, 10);
+ if (errno || end == tail || (*tail && *tail != ' '))
+ goto parse_err_sig_fail;
+ if (!*tail)
+ goto parse_err_sig_ok;
+ end = tail;
+ while (*end == ' ')
+ end++;
+
+ /* Parse the new fingerprint (from the ISSUER_FPR subpacket). */
+ if (!*end || (*end == '-' && (end[1] == ' ' || !end[1])))
+ goto parse_err_sig_ok; /* Okay (just trailing spaces). */
+ sig->fpr = strdup (end);
+ if (!sig->fpr)
+ return gpg_error_from_syserror ();
+ got_fpr = 1;
goto parse_err_sig_ok;
parse_err_sig_fail:
@@ -382,7 +399,7 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
return gpg_error (GPG_ERR_GENERAL);
}
- if (*args)
+ if (*args && !got_fpr)
{
sig->fpr = strdup (args);
if (!sig->fpr)
@@ -1074,9 +1091,14 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
case GPGME_STATUS_PLAINTEXT:
if (++opd->plaintext_seen > 1)
return gpg_error (GPG_ERR_BAD_DATA);
- err = _gpgme_parse_plaintext (args, &opd->result.file_name);
- if (err)
- return err;
+ {
+ int mime = 0;
+ err = _gpgme_parse_plaintext (args, &opd->result.file_name, &mime);
+ if (err)
+ return err;
+ opd->result.is_mime = !!mime;
+ }
+ break;
case GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE:
PARSE_COMPLIANCE_FLAGS (args, opd->current_sig);
diff --git a/src/versioninfo.rc.in b/src/versioninfo.rc.in
index 2b1cc811..88b662ea 100644
--- a/src/versioninfo.rc.in
+++ b/src/versioninfo.rc.in
@@ -39,7 +39,7 @@ BEGIN
VALUE "FileDescription", "GPGME - GnuPG Made Easy\0"
VALUE "FileVersion", "@LIBGPGME_LT_CURRENT@.@LIBGPGME_LT_AGE@.@LIBGPGME_LT_REVISION@.@BUILD_REVISION@\0"
VALUE "InternalName", "gpgme\0"
- VALUE "LegalCopyright", "Copyright � 2001-2017 g10 Code GmbH\0"
+ VALUE "LegalCopyright", "Copyright � 2001-2018 g10 Code GmbH\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "gpgme.dll\0"
VALUE "PrivateBuild", "\0"
diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c
index f955cc9d..fa0164ac 100644
--- a/tests/gpg/t-verify.c
+++ b/tests/gpg/t-verify.c
@@ -31,31 +31,14 @@
#include <gpgme.h>
+#define PGM "t-verify"
#include "t-support.h"
+
static const char test_text1[] = "Just GNU it!\n";
static const char test_text1f[]= "Just GNU it?\n";
static const char test_sig1[] =
-#if 0
-"-----BEGIN PGP SIGNATURE-----\n"
-"\n"
-"iEYEABECAAYFAjoKgjIACgkQLXJ8x2hpdzQMSwCeO/xUrhysZ7zJKPf/FyXA//u1\n"
-"ZgIAn0204PBR7yxSdQx6CFxugstNqmRv\n"
-"=yku6\n"
-"-----END PGP SIGNATURE-----\n"
-#elif 0
-"-----BEGIN PGP SIGNATURE-----\n"
-"Version: GnuPG v1.0.4-2 (GNU/Linux)\n"
-"Comment: For info see http://www.gnupg.org\n"
-"\n"
-"iJcEABECAFcFAjoS8/E1FIAAAAAACAAkZm9vYmFyLjF0aGlzIGlzIGEgbm90YXRp\n"
-"b24gZGF0YSB3aXRoIDIgbGluZXMaGmh0dHA6Ly93d3cuZ3Uub3JnL3BvbGljeS8A\n"
-"CgkQLXJ8x2hpdzQLyQCbBW/fgU8ZeWSlWPM1F8umHX17bAAAoIfSNDSp5zM85XcG\n"
-"iwxMrf+u8v4r\n"
-"=88Zo\n"
-"-----END PGP SIGNATURE-----\n"
-#elif 1
"-----BEGIN PGP SIGNATURE-----\n"
"\n"
"iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n"
@@ -64,9 +47,24 @@ static const char test_sig1[] =
"Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n"
"dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA==\n"
"=nts1\n"
-"-----END PGP SIGNATURE-----\n"
-#endif
-;
+"-----END PGP SIGNATURE-----\n";
+
+/* The same as test_sig1 but with a second signature for which we do
+ * not have the public key (deleted after signature creation). */
+static const char test_sig1_plus_unknown_key[] =
+"-----BEGIN PGP SIGNATURE-----\n"
+"\n"
+"iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n"
+"bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv\n"
+"b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw\n"
+"Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n"
+"dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaIh1BAAWCAAdFiEENuwqcMZC\n"
+"brD85btN+RyY8EnUIEwFAlrPR4cACgkQ+RyY8EnUIEyiuAEAm41LJTGUFDzhavRm\n"
+"jNwqUZxGGOySduW+u/X1lEfV+MYA/2lJOo75rHtD1EG+tkFVWt4Ukj0rjhR132vZ\n"
+"IOtrYAcG\n"
+"=yYwZ\n"
+"-----END PGP SIGNATURE-----\n";
+
static const char test_sig2[] =
"-----BEGIN PGP MESSAGE-----\n"
"\n"
@@ -91,37 +89,57 @@ static const char double_plaintext_sig[] =
+/* NO_OF_SIGS is the expected number of signatures. SKIP_SKIPS is
+ * which of these signatures to check (0 based). */
static void
-check_result (gpgme_verify_result_t result, unsigned int summary,
- const char *fpr,
+check_result (gpgme_verify_result_t result, int no_of_sigs, int skip_sigs,
+ unsigned int summary, const char *fpr,
gpgme_error_t status, int notation)
{
gpgme_signature_t sig;
+ int n;
sig = result->signatures;
- if (!sig || sig->next)
+ for (n=0; sig; sig = sig->next)
+ n++;
+ if (n != no_of_sigs)
+ {
+ fprintf (stderr, "%s:%i: Unexpected number of signatures"
+ " (got %d expected %d)\n", PGM, __LINE__, n, no_of_sigs);
+ exit (1);
+ }
+ if (skip_sigs >= n)
{
- fprintf (stderr, "%s:%i: Unexpected number of signatures\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i: oops SKIPP_SIGS to high\n", PGM, __LINE__);
exit (1);
}
+
+ for (n=0, sig = result->signatures; n < skip_sigs; sig = sig->next, n++)
+ ;
+
if (sig->summary != summary)
{
- fprintf (stderr, "%s:%i: Unexpected signature summary: "
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected signature summary: "
"want=0x%x have=0x%x\n",
- __FILE__, __LINE__, summary, sig->summary);
+ PGM, __LINE__, skip_sigs, summary, sig->summary);
exit (1);
}
if (strcmp (sig->fpr, fpr))
{
- fprintf (stderr, "%s:%i: Unexpected fingerprint: %s\n",
- __FILE__, __LINE__, sig->fpr);
- exit (1);
+ if (strlen (sig->fpr) == 16 && strlen (fpr) == 40
+ && !strncmp (sig->fpr, fpr + 24, 16))
+ ; /* okay because gnupg < 2.2.6 only shows the keyid. */
+ else
+ {
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected fingerprint: %s\n",
+ PGM, __LINE__, skip_sigs, sig->fpr);
+ exit (1);
+ }
}
if (gpgme_err_code (sig->status) != status)
{
- fprintf (stderr, "%s:%i: Unexpected signature status: %s\n",
- __FILE__, __LINE__, gpgme_strerror (sig->status));
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected signature status: %s\n",
+ PGM, __LINE__, skip_sigs, gpgme_strerror (sig->status));
exit (1);
}
if (notation)
@@ -166,8 +184,8 @@ check_result (gpgme_verify_result_t result, unsigned int summary,
}
if (!any)
{
- fprintf (stderr, "%s:%i: Unexpected notation data\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected notation data\n",
+ PGM, __LINE__, skip_sigs);
exit (1);
}
}
@@ -175,28 +193,30 @@ check_result (gpgme_verify_result_t result, unsigned int summary,
{
if (expected_notations[i].seen != 1)
{
- fprintf (stderr, "%s:%i: Missing or duplicate notation data\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i:sig-%d: "
+ "Missing or duplicate notation data\n",
+ PGM, __LINE__, skip_sigs);
exit (1);
}
}
}
if (sig->wrong_key_usage)
{
- fprintf (stderr, "%s:%i: Unexpectedly wrong key usage\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i:sig-%d: Unexpectedly wrong key usage\n",
+ PGM, __LINE__, skip_sigs);
exit (1);
}
if (sig->validity != GPGME_VALIDITY_UNKNOWN)
{
- fprintf (stderr, "%s:%i: Unexpected validity: %i\n",
- __FILE__, __LINE__, sig->validity);
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected validity: %i\n",
+ PGM, __LINE__, skip_sigs, sig->validity);
exit (1);
}
if (gpgme_err_code (sig->validity_reason) != GPG_ERR_NO_ERROR)
{
- fprintf (stderr, "%s:%i: Unexpected validity reason: %s\n",
- __FILE__, __LINE__, gpgme_strerror (sig->validity_reason));
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected validity reason: %s\n",
+ PGM, __LINE__, skip_sigs,
+ gpgme_strerror (sig->validity_reason));
exit (1);
}
}
@@ -227,7 +247,7 @@ main (int argc, char *argv[])
err = gpgme_op_verify (ctx, sig, text, NULL);
fail_if_err (err);
result = gpgme_op_verify_result (ctx);
- check_result (result, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ check_result (result, 1, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
GPG_ERR_NO_ERROR, 1);
/* Checking a manipulated message. */
@@ -238,9 +258,29 @@ main (int argc, char *argv[])
err = gpgme_op_verify (ctx, sig, text, NULL);
fail_if_err (err);
result = gpgme_op_verify_result (ctx);
- check_result (result, GPGME_SIGSUM_RED, "2D727CC768697734",
+ check_result (result, 1, 0, GPGME_SIGSUM_RED, "2D727CC768697734",
GPG_ERR_BAD_SIGNATURE, 0);
+ /* Checking a valid message. Bu that one has a second signature
+ * made by an unknown key. */
+ gpgme_data_release (text);
+ gpgme_data_release (sig);
+ err = gpgme_data_new_from_mem (&text, test_text1, strlen (test_text1), 0);
+ fail_if_err (err);
+ err = gpgme_data_new_from_mem (&sig, test_sig1_plus_unknown_key,
+ strlen (test_sig1_plus_unknown_key), 0);
+ fail_if_err (err);
+ err = gpgme_op_verify (ctx, sig, text, NULL);
+ fail_if_err (err);
+ result = gpgme_op_verify_result (ctx);
+ check_result (result, 2, 0, 0,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ GPG_ERR_NO_ERROR, 1);
+ check_result (result, 2, 1, GPGME_SIGSUM_KEY_MISSING,
+ "36EC2A70C6426EB0FCE5BB4DF91C98F049D4204C",
+ GPG_ERR_NO_PUBKEY, 0);
+
+
/* Checking a normal signature. */
gpgme_data_release (sig);
gpgme_data_release (text);
@@ -251,7 +291,7 @@ main (int argc, char *argv[])
err = gpgme_op_verify (ctx, sig, NULL, text);
fail_if_err (err);
result = gpgme_op_verify_result (ctx);
- check_result (result, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ check_result (result, 1, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
GPG_ERR_NO_ERROR, 0);
@@ -267,7 +307,7 @@ main (int argc, char *argv[])
if (gpgme_err_code (err) != GPG_ERR_BAD_DATA)
{
fprintf (stderr, "%s:%i: Double plaintext message not detected\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -278,7 +318,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "[email protected]"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -288,7 +328,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "[email protected]"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -298,7 +338,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "[email protected]"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -306,7 +346,7 @@ main (int argc, char *argv[])
if (gpgme_err_code (err) != GPG_ERR_INV_VALUE)
{
fprintf (stderr, "%s:%i: gpgme_set_sender didn't detect bogus address\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
/* (the former address should still be there.) */
@@ -314,7 +354,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "[email protected]"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c
index f4c47544..69de139c 100644
--- a/tests/run-decrypt.c
+++ b/tests/run-decrypt.c
@@ -53,19 +53,21 @@ print_result (gpgme_decrypt_result_t result)
gpgme_recipient_t recp;
int count = 0;
- printf ("Original file name: %s\n", nonnull(result->file_name));
- printf ("Wrong key usage: %i\n", result->wrong_key_usage);
- printf ("Unsupported algorithm: %s\n",
- nonnull(result->unsupported_algorithm));
- if (result->session_key)
- printf ("Session key: %s\n", result->session_key);
-
- for (recp = result->recipients; recp->next; recp = recp->next)
+ printf ("Original file name .: %s\n", nonnull(result->file_name));
+ printf ("Wrong key usage ....: %s\n", result->wrong_key_usage? "yes":"no");
+ printf ("Compliance de-vs ...: %s\n", result->is_de_vs? "yes":"no");
+ printf ("MIME flag ..........: %s\n", result->is_mime? "yes":"no");
+ printf ("Unsupported algo ...: %s\n", nonnull(result->unsupported_algorithm));
+ printf ("Session key ........: %s\n", nonnull (result->session_key));
+ printf ("Symmetric algorithm : %s\n", result->symkey_algo);
+
+ for (recp = result->recipients; recp && recp->next; recp = recp->next)
{
- printf ("recipient %d\n", count++);
+ printf ("Recipient ...: %d\n", count++);
printf (" status ....: %s\n", gpgme_strerror (recp->status));
- printf (" keyid: %s\n", nonnull (recp->keyid));
- printf (" algo ...: %s\n", gpgme_pubkey_algo_name (recp->pubkey_algo));
+ printf (" keyid .....: %s\n", nonnull (recp->keyid));
+ printf (" algo ......: %s\n",
+ gpgme_pubkey_algo_name (recp->pubkey_algo));
}
}
@@ -82,6 +84,7 @@ show_usage (int ex)
" --export-session-key show the session key\n"
" --override-session-key STRING use STRING as session key\n"
" --request-origin STRING use STRING as request origin\n"
+ " --no-symkey-cache disable the use of that cache\n"
" --unwrap remove only the encryption layer\n"
, stderr);
exit (ex);
@@ -104,6 +107,7 @@ main (int argc, char **argv)
int export_session_key = 0;
const char *override_session_key = NULL;
const char *request_origin = NULL;
+ int no_symkey_cache = 0;
int raw_output = 0;
if (argc)
@@ -160,6 +164,11 @@ main (int argc, char **argv)
request_origin = *argv;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--no-symkey-cache"))
+ {
+ no_symkey_cache = 1;
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--unwrap"))
{
flags |= GPGME_DECRYPT_UNWRAP;
@@ -226,6 +235,17 @@ main (int argc, char **argv)
}
}
+ if (no_symkey_cache)
+ {
+ err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1");
+ if (err)
+ {
+ fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n",
+ gpgme_strerror (err));
+ exit (1);
+ }
+ }
+
err = gpgme_data_new_from_stream (&in, fp_in);
if (err)
{
diff --git a/tests/run-encrypt.c b/tests/run-encrypt.c
index e949d760..94084694 100644
--- a/tests/run-encrypt.c
+++ b/tests/run-encrypt.c
@@ -37,6 +37,19 @@
static int verbose;
+static char *
+xstrdup (const char *string)
+{
+ char *p = strdup (string);
+ if (!p)
+ {
+ fprintf (stderr, "strdup failed\n");
+ exit (2);
+ }
+ return p;
+}
+
+
static gpg_error_t
status_cb (void *opaque, const char *keyword, const char *value)
{
@@ -80,17 +93,19 @@ show_usage (int ex)
{
fputs ("usage: " PGM " [options] FILE\n\n"
"Options:\n"
- " --verbose run in verbose mode\n"
- " --status print status lines from the backend\n"
- " --progress print progress info\n"
- " --openpgp use the OpenPGP protocol (default)\n"
- " --cms use the CMS protocol\n"
- " --uiserver use the UI server\n"
- " --loopback use a loopback pinentry\n"
- " --key NAME encrypt to key NAME\n"
- " --throw-keyids use this option\n"
- " --wrap assume input is valid OpenPGP message\n"
- " --symmetric encrypt symmetric (OpenPGP only)\n"
+ " --verbose run in verbose mode\n"
+ " --status print status lines from the backend\n"
+ " --progress print progress info\n"
+ " --openpgp use the OpenPGP protocol (default)\n"
+ " --cms use the CMS protocol\n"
+ " --uiserver use the UI server\n"
+ " --loopback use a loopback pinentry\n"
+ " --key NAME encrypt to key NAME\n"
+ " --keystring NAMES encrypt to ';' delimited NAMES\n"
+ " --throw-keyids use this option\n"
+ " --no-symkey-cache disable the use of that cache\n"
+ " --wrap assume input is valid OpenPGP message\n"
+ " --symmetric encrypt symmetric (OpenPGP only)\n"
, stderr);
exit (ex);
}
@@ -102,7 +117,6 @@ main (int argc, char **argv)
int last_argc = -1;
gpgme_error_t err;
gpgme_ctx_t ctx;
- const char *key_string = NULL;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
gpgme_data_t in, out;
gpgme_encrypt_result_t result;
@@ -112,9 +126,11 @@ main (int argc, char **argv)
char *keyargs[10];
gpgme_key_t keys[10+1];
int keycount = 0;
+ char *keystring = NULL;
int i;
gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
gpgme_off_t offset;
+ int no_symkey_cache = 0;
if (argc)
{ argc--; argv++; }
@@ -172,6 +188,17 @@ main (int argc, char **argv)
keyargs[keycount++] = *argv;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--keystring"))
+ {
+ argc--; argv++;
+ if (!argc)
+ show_usage (1);
+ keystring = xstrdup (*argv);
+ for (i=0; keystring[i]; i++)
+ if (keystring[i] == ';')
+ keystring[i] = '\n';
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--throw-keyids"))
{
flags |= GPGME_ENCRYPT_THROW_KEYIDS;
@@ -192,6 +219,11 @@ main (int argc, char **argv)
flags |= GPGME_ENCRYPT_SYMMETRIC;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--no-symkey-cache"))
+ {
+ no_symkey_cache = 1;
+ argc--; argv++;
+ }
else if (!strncmp (*argv, "--", 2))
show_usage (1);
@@ -200,15 +232,6 @@ main (int argc, char **argv)
if (argc != 1)
show_usage (1);
- if (key_string && protocol == GPGME_PROTOCOL_UISERVER)
- {
- fprintf (stderr, PGM ": ignoring --key in UI-server mode\n");
- key_string = NULL;
- }
-
- if (!key_string)
- key_string = "test";
-
init_gpgme (protocol);
err = gpgme_new (&ctx);
@@ -227,6 +250,16 @@ main (int argc, char **argv)
gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
}
+ if (no_symkey_cache)
+ {
+ err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1");
+ if (err)
+ {
+ fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n",
+ gpgme_strerror (err));
+ exit (1);
+ }
+ }
for (i=0; i < keycount; i++)
{
@@ -281,7 +314,8 @@ main (int argc, char **argv)
err = gpgme_data_new (&out);
fail_if_err (err);
- err = gpgme_op_encrypt (ctx, keycount ? keys : NULL, flags, in, out);
+ err = gpgme_op_encrypt_ext (ctx, keycount ? keys : NULL, keystring,
+ flags, in, out);
result = gpgme_op_encrypt_result (ctx);
if (result)
print_result (result);
@@ -301,5 +335,6 @@ main (int argc, char **argv)
for (i=0; i < keycount; i++)
gpgme_key_unref (keys[i]);
gpgme_release (ctx);
+ free (keystring);
return 0;
}
diff --git a/tests/run-verify.c b/tests/run-verify.c
index b22e6446..4a6c9601 100644
--- a/tests/run-verify.c
+++ b/tests/run-verify.c
@@ -136,10 +136,11 @@ print_result (gpgme_verify_result_t result)
gpgme_tofu_info_t ti;
int count = 0;
- printf ("Original file name: %s\n", nonnull(result->file_name));
+ printf ("Original file name .: %s\n", nonnull(result->file_name));
+ printf ("MIME flag ..........: %s\n", result->is_mime? "yes":"no");
for (sig = result->signatures; sig; sig = sig->next)
{
- printf ("Signature %d\n", count++);
+ printf ("Signature ...: %d\n", count++);
printf (" status ....: %s\n", gpgme_strerror (sig->status));
printf (" summary ...:"); print_summary (sig->summary); putchar ('\n');
printf (" fingerprint: %s\n", nonnull (sig->fpr));
@@ -163,17 +164,24 @@ print_result (gpgme_verify_result_t result)
);
for (nt = sig->notations; nt; nt = nt->next)
{
- printf (" notation ..: '%s'\n", nt->name);
- if (strlen (nt->name) != nt->name_len)
- printf (" warning : name larger (%d)\n", nt->name_len);
- printf (" flags ...:%s%s (0x%02x)\n",
- nt->critical? " critical":"",
- nt->human_readable? " human":"",
- nt->flags);
- if (nt->value)
- printf (" value ...: '%s'\n", nt->value);
+ if (nt->name)
+ {
+ printf (" notation ..: '%s'\n", nt->name);
+ if (strlen (nt->name) != nt->name_len)
+ printf (" warning .: name larger (%d)\n", nt->name_len);
+ printf (" flags ...:%s%s (0x%02x)\n",
+ nt->critical? " critical":"",
+ nt->human_readable? " human":"",
+ nt->flags);
+ if (nt->value)
+ printf (" value ...: '%s'\n", nt->value);
+ }
+ else
+ {
+ printf (" policy ....: '%s'\n", nt->value);
+ }
if ((nt->value?strlen (nt->value):0) != nt->value_len)
- printf (" warning : value larger (%d)\n", nt->value_len);
+ printf (" warning .: value larger (%d)\n", nt->value_len);
}
if (sig->key)
{