Merge branch 'master' into javascript-binding

This commit is contained in:
Maximilian Krambach 2018-04-20 15:23:57 +02:00
commit 94f21d9f6b
37 changed files with 2017 additions and 559 deletions

View File

@ -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 <wk@gnupg.org>
@ -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

View File

@ -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 ' */' ;\
)

81
NEWS
View File

@ -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:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'
cpp: Key::locate NEW.
cpp: Data::toString NEW.
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_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)
-------------------------------------------------

2
README
View File

@ -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

View File

@ -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"
])

View File

@ -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

View File

@ -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(";

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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;

View File

@ -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";
}

View File

@ -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:

View File

@ -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,53 +104,42 @@ 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)
{
gpgme_error_t err;
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)
{
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++;
}
}
err = encrypt_sign_start (ctx, 0, recp, flags, plain, cipher);
return err;
return gpgme_op_encrypt_sign_ext_start (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. */
/* 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;
@ -159,21 +149,70 @@ gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
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],
(recp[i]->subkeys && recp[i]->subkeys->fpr) ?
recp[i]->subkeys->fpr : "invalid");
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++;
}
}
else
{
TRACE_LOG1 ("recipients = '%s'", recpstring);
}
}
err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher);
err = encrypt_sign_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. Also sign the ciphertext
with the signers in CTX. */
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 err;
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 || recpstring))
{
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, recpstring, flags, plain, cipher);
return err;
}

View File

@ -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,48 +253,41 @@ 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)
{
gpgme_error_t err;
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)
{
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++;
}
}
err = encrypt_start (ctx, 0, recp, flags, plain, cipher);
return TRACE_ERR (err);
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. */
* 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 (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 (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;
@ -303,21 +297,67 @@ gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
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, 1, 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);
}
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 err;
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 || recpstring))
{
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, 0, recp, recpstring, flags, plain, cipher);
return TRACE_ERR (err);
}

View File

@ -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 */);

View File

@ -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)

View File

@ -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");

View File

@ -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);

View File

@ -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);
}

View File

@ -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,

View File

@ -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. */
@ -630,6 +775,119 @@ op_encrypt (cjson_t request, cjson_t result)
goto leave;
}
/* 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)
{
error_object (result, "Error decoding Base-64 encoded 'data': %s",
gpg_strerror (err));
goto leave;
}
}
else
{
err = gpgme_data_new_from_mem (&input, j_input->valuestring,
strlen (j_input->valuestring), 0);
if (err)
{
error_object (result, "Error getting 'data': %s", gpg_strerror (err));
goto leave;
}
}
if (opt_mime)
gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
/* 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;
}
/* Encrypt. */
err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
input, output);
/* encrypt_result = gpgme_op_encrypt_result (ctx); */
if (err)
{
error_object (result, "Encryption failed: %s", gpg_strerror (err));
goto leave;
}
gpgme_data_release (input);
input = NULL;
/* 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;
/* Get the data. Note that INPUT is a shallow data object with the
* storage hold in REQUEST. */
j_input = cJSON_GetObjectItem (request, "data");
@ -673,59 +931,118 @@ op_encrypt (cjson_t request, cjson_t result)
goto leave;
}
/* Encrypt. */
err = gpgme_op_encrypt (ctx, keys, encrypt_flags, input, output);
/* encrypt_result = gpgme_op_encrypt_result (ctx); */
/* Decrypt. */
err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
input, output);
decrypt_result = gpgme_op_decrypt_result (ctx);
if (err)
{
error_object (result, "Encryption failed: %s", gpg_strerror (err));
error_object (result, "Decryption failed: %s", gpg_strerror (err));
goto leave;
}
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;
if (decrypt_result->is_mime)
xjson_AddBoolToObject (result, "mime", 1);
/* Make sure that we really have a string. */
gpgme_data_write (output, "", 1);
buffer = gpgme_data_release_and_get_mem (output, NULL);
if (!buffer)
{
err = gpg_error_from_syserror ();
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;
if (err)
goto leave;
}
err = make_data_object (result, output, chunksize, "plaintext", -1);
output = NULL;
leave:
if (keys)
{
for (i=0; keys[i]; i++)
gpgme_key_unref (keys[i]);
xfree (keys);
}
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");

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -215,10 +215,15 @@ GPGME_1.0 {
gpgme_op_edit;
gpgme_op_edit_start;
gpgme_op_encrypt;
gpgme_op_encrypt_result;
gpgme_op_encrypt_sign;
gpgme_op_encrypt_sign_start;
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_sign_ext_start;
gpgme_op_encrypt_result;
gpgme_op_export;
gpgme_op_export_ext;
gpgme_op_export_ext_start;

View File

@ -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);
}

View File

@ -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. */

View File

@ -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 --*/

View File

@ -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);

View File

@ -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"

View File

@ -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\n",
__FILE__, __LINE__);
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: 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, "foo@example.org"))
{
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, "bar@example.org"))
{
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, "foo@example.org"))
{
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, "foo@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
__FILE__, __LINE__);
PGM, __LINE__);
exit (1);
}

View File

@ -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);
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->next; recp = recp->next)
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)
{

View File

@ -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;
}

View File

@ -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)
{