diff options
Diffstat (limited to 'lang/python/tests')
30 files changed, 3092 insertions, 0 deletions
diff --git a/lang/python/tests/Makefile.am b/lang/python/tests/Makefile.am new file mode 100644 index 0000000..aa88bdc --- /dev/null +++ b/lang/python/tests/Makefile.am @@ -0,0 +1,114 @@ +# Makefile.am for the tests of the Python bindings. +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +GPG = gpg +GPG_AGENT = gpg-agent +export GNUPGHOME := $(abs_builddir) +export GPG_AGENT_INFO := + +test_srcdir = $(top_srcdir)/tests/gpg + +TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) \ + LC_ALL=C GPG_AGENT_INFO= \ + top_srcdir=$(top_srcdir) \ + srcdir=$(srcdir) \ + LD_LIBRARY_PATH="../../../src/.libs:$(LD_LIBRARY_PATH)" + +py_tests = t-wrapper.py \ + t-callbacks.py \ + t-data.py \ + t-encrypt.py \ + t-encrypt-sym.py \ + t-encrypt-sign.py \ + t-sign.py \ + t-signers.py \ + t-decrypt.py \ + t-verify.py \ + t-decrypt-verify.py \ + t-sig-notation.py \ + t-export.py \ + t-import.py \ + t-trustlist.py \ + t-edit.py \ + t-keylist.py \ + t-wait.py \ + t-encrypt-large.py \ + t-file-name.py \ + t-idiomatic.py \ + t-protocol-assuan.py + +XTESTS = initial.py $(py_tests) final.py +EXTRA_DIST = support.py $(XTESTS) encrypt-only.asc sign-only.asc \ + run-tests.py + +# XXX: Currently, one cannot override automake's 'check' target. As a +# workaround, we avoid defining 'TESTS', thus automake will not emit +# the 'check' target. For extra robustness, we merely define a +# dependency on 'xcheck', so this hack should also work even if +# automake would emit the 'check' target, as adding dependencies to +# targets is okay. +check: xcheck + +.PHONY: xcheck + +xcheck: ./pubring-stamp + $(TESTS_ENVIRONMENT) $(PYTHON) $(srcdir)/run-tests.py \ + --interpreters="$(PYTHONS)" --srcdir=$(srcdir) $(TESTFLAGS) \ + $(XTESTS) + +CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \ + gpg-agent.conf pubring.kbx~ gpg.conf pubring.gpg~ \ + random_seed .gpg-v21-migrated \ + pubring-stamp private-keys-v1.d/gpg-sample.stamp + +private_keys = \ + $(test_srcdir)/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \ + $(test_srcdir)/76F7E2B35832976B50A27A282D9B87E44577EB66 \ + $(test_srcdir)/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD \ + $(test_srcdir)/13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F \ + $(test_srcdir)/7A030357C0F253A5BBCD282FFC4E521B37558F5C + +clean-local: + -$(top_srcdir)/tests/start-stop-agent --stop + -rm -fR -- private-keys-v1.d openpgp-revocs.d S.gpg-agent sshcontrol + + +./private-keys-v1.d/gpg-sample.stamp: $(private_keys) + test -d ./private-keys-v1.d || mkdir ./private-keys-v1.d + for k in $(private_keys); do \ + cp $$k private-keys-v1.d/$${k#$(test_srcdir)/}.key; \ + done + echo x > ./private-keys-v1.d/gpg-sample.stamp + +./pubring-stamp: $(test_srcdir)/pubdemo.asc \ + ./gpg.conf ./gpg-agent.conf \ + ./private-keys-v1.d/gpg-sample.stamp + $(GPG) --batch --no-permission-warning \ + --import $(test_srcdir)/pubdemo.asc + -$(GPG) --batch --no-permission-warning \ + --import $(test_srcdir)/secdemo.asc + echo x > ./pubring-stamp + +./gpg.conf: +# This is required for t-sig-notations. + echo no-force-v3-sigs > ./gpg.conf + +./gpg-agent.conf: +# This is required for gpg2, which does not support command fd. + echo pinentry-program $(abs_top_srcdir)/tests/gpg/pinentry >$@ + echo allow-loopback-pinentry >>$@ diff --git a/lang/python/tests/Makefile.in b/lang/python/tests/Makefile.in new file mode 100644 index 0000000..3886bf4 --- /dev/null +++ b/lang/python/tests/Makefile.in @@ -0,0 +1,620 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the tests of the Python bindings. +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lang/python/tests +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/build-aux/mkinstalldirs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4/ax_pkg_swig.m4 \ + $(top_srcdir)/m4/ax_python_devel.m4 \ + $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \ + $(top_srcdir)/m4/gnupg-ttyname.m4 \ + $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ + $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLED_LANGUAGES = @ENABLED_LANGUAGES@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@ +GLIBC21 = @GLIBC21@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@ +GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@ +GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@ +GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@ +GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@ +GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@ +GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@ +GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@ +GPGME_QT_LIBS = @GPGME_QT_LIBS@ +GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GPG_ERROR_LIBS = @GPG_ERROR_LIBS@ +GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@ +GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@ +GRAPHVIZ = @GRAPHVIZ@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAVE_DOT = @HAVE_DOT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@ +LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@ +LIBASSUAN_LIBS = @LIBASSUAN_LIBS@ +LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@ +LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@ +LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@ +LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@ +LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@ +LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@ +LIBOBJS = @LIBOBJS@ +LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@ +LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@ +LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MOC = @MOC@ +MOC2 = @MOC2@ +NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PYTHON = @PYTHON@ +PYTHONS = @PYTHONS@ +PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@ +PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@ +PYTHON_LDFLAGS = @PYTHON_LDFLAGS@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_SITE_PKG = @PYTHON_SITE_PKG@ +PYTHON_VERSION = @PYTHON_VERSION@ +PYTHON_VERSIONS = @PYTHON_VERSIONS@ +QTCHOOSER = @QTCHOOSER@ +RANLIB = @RANLIB@ +RC = @RC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SWIG = @SWIG@ +SWIG_LIB = @SWIG_LIB@ +SYSROOT = @SYSROOT@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +emacs_local_vars_begin = @emacs_local_vars_begin@ +emacs_local_vars_end = @emacs_local_vars_end@ +emacs_local_vars_read_only = @emacs_local_vars_read_only@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +GPG = gpg +GPG_AGENT = gpg-agent +test_srcdir = $(top_srcdir)/tests/gpg +TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) \ + LC_ALL=C GPG_AGENT_INFO= \ + top_srcdir=$(top_srcdir) \ + srcdir=$(srcdir) \ + LD_LIBRARY_PATH="../../../src/.libs:$(LD_LIBRARY_PATH)" + +py_tests = t-wrapper.py \ + t-callbacks.py \ + t-data.py \ + t-encrypt.py \ + t-encrypt-sym.py \ + t-encrypt-sign.py \ + t-sign.py \ + t-signers.py \ + t-decrypt.py \ + t-verify.py \ + t-decrypt-verify.py \ + t-sig-notation.py \ + t-export.py \ + t-import.py \ + t-trustlist.py \ + t-edit.py \ + t-keylist.py \ + t-wait.py \ + t-encrypt-large.py \ + t-file-name.py \ + t-idiomatic.py \ + t-protocol-assuan.py + +XTESTS = initial.py $(py_tests) final.py +EXTRA_DIST = support.py $(XTESTS) encrypt-only.asc sign-only.asc \ + run-tests.py + +CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \ + gpg-agent.conf pubring.kbx~ gpg.conf pubring.gpg~ \ + random_seed .gpg-v21-migrated \ + pubring-stamp private-keys-v1.d/gpg-sample.stamp + +private_keys = \ + $(test_srcdir)/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \ + $(test_srcdir)/76F7E2B35832976B50A27A282D9B87E44577EB66 \ + $(test_srcdir)/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD \ + $(test_srcdir)/13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F \ + $(test_srcdir)/7A030357C0F253A5BBCD282FFC4E521B37558F5C + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/python/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu lang/python/tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +export GNUPGHOME := $(abs_builddir) +export GPG_AGENT_INFO := + +# XXX: Currently, one cannot override automake's 'check' target. As a +# workaround, we avoid defining 'TESTS', thus automake will not emit +# the 'check' target. For extra robustness, we merely define a +# dependency on 'xcheck', so this hack should also work even if +# automake would emit the 'check' target, as adding dependencies to +# targets is okay. +check: xcheck + +.PHONY: xcheck + +xcheck: ./pubring-stamp + $(TESTS_ENVIRONMENT) $(PYTHON) $(srcdir)/run-tests.py \ + --interpreters="$(PYTHONS)" --srcdir=$(srcdir) $(TESTFLAGS) \ + $(XTESTS) + +clean-local: + -$(top_srcdir)/tests/start-stop-agent --stop + -rm -fR -- private-keys-v1.d openpgp-revocs.d S.gpg-agent sshcontrol + +./private-keys-v1.d/gpg-sample.stamp: $(private_keys) + test -d ./private-keys-v1.d || mkdir ./private-keys-v1.d + for k in $(private_keys); do \ + cp $$k private-keys-v1.d/$${k#$(test_srcdir)/}.key; \ + done + echo x > ./private-keys-v1.d/gpg-sample.stamp + +./pubring-stamp: $(test_srcdir)/pubdemo.asc \ + ./gpg.conf ./gpg-agent.conf \ + ./private-keys-v1.d/gpg-sample.stamp + $(GPG) --batch --no-permission-warning \ + --import $(test_srcdir)/pubdemo.asc + -$(GPG) --batch --no-permission-warning \ + --import $(test_srcdir)/secdemo.asc + echo x > ./pubring-stamp + +./gpg.conf: +# This is required for t-sig-notations. + echo no-force-v3-sigs > ./gpg.conf + +./gpg-agent.conf: +# This is required for gpg2, which does not support command fd. + echo pinentry-program $(abs_top_srcdir)/tests/gpg/pinentry >$@ + echo allow-loopback-pinentry >>$@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lang/python/tests/encrypt-only.asc b/lang/python/tests/encrypt-only.asc new file mode 100644 index 0000000..6e068a0 --- /dev/null +++ b/lang/python/tests/encrypt-only.asc @@ -0,0 +1,33 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v2 + +lQPGBFd/jL0BCAD8jfoblIrlHS0shDCbSiO7RFaT6sEa/6tSPkv6XzBba9oXOkuO +FLTkNpIwPb92U8SOS+27j7n9v6U5NW2tyZwIoeLb8lUyKnCBr22IUhTFVXf7fros +zmPugsJaDBi9f7RL0bqiCn4EV3DGKyAukZklk1k1JV4Ec3dEPMAmL9LmnvXreEjU +pQZZN9sJV32ew8CYkZ6AB8foFQwfxn4x0iUoKvj8kW9RsY1KMPucp4YiFhHeMZW1 +5wGAZdEIZYKyWEp4bi/wC9yn/TUR5uNWc0uVJzQvuHwaYjolPW89DinjBkPEJCBr +RwumaOWfbu/hb51wBoUTmUr9diVw93L2ROLPABEBAAH+BwMC1bmUAoPJKI/WBiHm +P6tSNRLdd+7etfjAFvKL7Ob2pNTrc3hbtyOLIQ9tuEaqXEyfnCms/DCg8QdkaFUv +Nkoj0W5+G/MQuR2jIvrq/wyL/4jIw0AFbp9/V1JbSXZh2g1eJLnnykn7uPxCbDFY +FrVeFmkhoxZ3pid6ZQSWlxXsdW+YMvbUfNIIZpbygI/alIBvbDS1YJYEBDCwFZjU +7quE2Ufxo8dm34EHcmbpYpn4r3DUrU5AHQ2fIprLIVqHn4+NUrR8WZS9nCnIeu/z +OaJUZ2lJFRjUC6Gpsbsw6Xwh4Ntwzyt2SsXc+UVZngjozw3yw0VpDifxMBqcd+9x +baSc7dfbOZF2BCZOwnB7/QrFZDaqe5b3n6rTdj1va/CrJMuxbgaNAjvLpdT2EUPZ +fHDAdPAjASofxBREv+HIKwksuPJ9cvavZU6Q4KQA7buo25hd7yjuba4WbLQhp0jH +AT1P7SdakMhk/IFcUKFdB3ZyZZZ1JTTPa2xZn9yDa3Jb1t7IMLYLwY6EFbjvaxH5 +WEGZvOAq2iEa941mxv4miwgf7MQPx6g9u0+dXc7iZApwWs9MNfJo3J25sKhWK5Be +Bu3w7c6nrlg40GtPuDRgaBvYWbVerJcepTA/EPfugEJtRsDJkt7wZq1H9lWHU7Ih +Up6/+XKtBzlCIqYjorzFLnC721pcKFcPhLgvtjjNJvUsLXbr9CwnBub/eTFcfRb2 +ro60H9cOhf0fQSQyvkZWfzq0BN6rG27G1KhyprsJAmpW0fTHHkB4V19788C2sTQv +D93VU3Nd6MWocwAYtPWmtwXPpuOAU9IcwAvVTxBeBJCXxbH3uyx1frwDXA7lf4Pb +a8hMoMMVU+rAG1uepKI5h4seBIKP7qKEKAPloI6/Vtf7/Ump4DKprS1QpfOW+lsX +aR48lgNR6sQXtDdFbmNyeXB0aW9uIE9ubHkgKHRlc3Qga2V5LCBkbyBub3QgdXNl +KSA8ZW9AZXhhbXBsZS5vcmc+iQE3BBMBCAAhBQJXf4y9AhsNBQsJCAcCBhUICQoL +AgQWAgMBAh4BAheAAAoJEJIFcnabn+Gc/KgH/07wzrsBzTqdI5L6cIqQ81Vq8ASj +tsuYoVfFxymB8F/AxpnLMhYRuWQTcoUHQ/olG2yA0C6o4e1JPAmh6LQGwr0eRnc2 +2tr4cbnQAhXpJ8xOR6kH9eE8nGeC7tlEeeV/Wnj3SLZOXOjYjnA9bA3JX9DP3qcz +w1sKQPEHsGkMJuT0ZadnlJ1qw8AnnNKLDlG4kIO9hz3qB8BjxFZf+j5f/nhFNv5I +pnNdMcDwQqHVrwD6WO+Xmmdykab0awL9To0S9DG9ohcXuJiTMa8vtXFSBM0koUDk +BWajEq+QAcDpmdFsQr4/gbzvHkAIVTQb0seJr4gpmXFZu3TMuGVD9j13GaI= +=38ri +-----END PGP PRIVATE KEY BLOCK----- diff --git a/lang/python/tests/final.py b/lang/python/tests/final.py new file mode 100755 index 0000000..8e7ab33 --- /dev/null +++ b/lang/python/tests/final.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import os +import subprocess + +subprocess.check_call([os.path.join(os.getenv('top_srcdir'), + "tests", "start-stop-agent"), "--stop"]) diff --git a/lang/python/tests/initial.py b/lang/python/tests/initial.py new file mode 100755 index 0000000..2d4827a --- /dev/null +++ b/lang/python/tests/initial.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import os +import subprocess +import pyme +import support +support.init_gpgme(pyme.constants.PROTOCOL_OpenPGP) + +subprocess.check_call([os.path.join(os.getenv('top_srcdir'), + "tests", "start-stop-agent"), "--start"]) + +with pyme.Context() as c: + alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) + bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) + + # Mark alpha as trusted. The signature verification tests expect + # this. + support.mark_key_trusted(c, alpha) + + c.op_import(open(support.in_srcdir("encrypt-only.asc"))) + c.op_import(open(support.in_srcdir("sign-only.asc"))) diff --git a/lang/python/tests/run-tests.py b/lang/python/tests/run-tests.py new file mode 100644 index 0000000..55d3f11 --- /dev/null +++ b/lang/python/tests/run-tests.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import argparse +import glob +import os +import subprocess +import sys + +class SplitAndAccumulate(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + current = getattr(namespace, self.dest, list()) + current.extend(values.split()) + setattr(namespace, self.dest, current) + +parser = argparse.ArgumentParser(description='Run tests.') +parser.add_argument('tests', metavar='TEST', type=str, nargs='+', + help='A test to run') +parser.add_argument('-v', '--verbose', action="store_true", default=False, + help='Be verbose.') +parser.add_argument('--interpreters', metavar='PYTHON', type=str, + default=[], action=SplitAndAccumulate, + help='Use these interpreters to run the tests, ' + + 'separated by spaces.') +parser.add_argument('--srcdir', type=str, + default=os.environ.get("srcdir", ""), + help='Location of the tests.') +parser.add_argument('--builddir', type=str, + default=os.environ.get("abs_builddir", ""), + help='Location of the tests.') + +args = parser.parse_args() +if not args.interpreters: + args.interpreters = [sys.executable] + +out = sys.stdout if args.verbose else None +err = sys.stderr if args.verbose else None + +def status_to_str(code): + return {0: "PASS", 77: "SKIP", 99: "ERROR"}.get(code, "FAIL") + +results = list() +for interpreter in args.interpreters: + version = subprocess.check_output( + [interpreter, "-c", "import sys; print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"]).strip().decode() + + builddirs = glob.glob(os.path.join(args.builddir, "..", "build", + "lib*"+version)) + assert len(builddirs) == 1, \ + "Expected one build directory, got {0}".format(builddirs) + env = dict(os.environ) + env["PYTHONPATH"] = builddirs[0] + + print("Running tests using {0} ({1})...".format(interpreter, version)) + for test in args.tests: + status = subprocess.call( + [interpreter, os.path.join(args.srcdir, test)], + env=env, stdout=out, stderr=err) + print("{0}: {1}".format(status_to_str(status), test)) + results.append(status) + +def count(status): + return len(list(filter(lambda x: x == status, results))) +def failed(): + return len(list(filter(lambda x: x not in (0, 77, 99), results))) + +print("{0} tests run, {1} succeeded, {2} failed, {3} skipped.".format( + len(results), count(0), failed(), count(77))) +sys.exit(len(results) - count(0)) diff --git a/lang/python/tests/sign-only.asc b/lang/python/tests/sign-only.asc new file mode 100644 index 0000000..6e2a6f3 --- /dev/null +++ b/lang/python/tests/sign-only.asc @@ -0,0 +1,33 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v2 + +lQPFBFd/jO8BCADiull4EVJiKmJqclPyU6GhTlbJXw7Ch0zbFAauOWYT3ACmgr1U +KfJlZ2sPe2EezZkVSACxgIjTCzcgKQLh/swXdhO8uEgWEIN8f07WcSVDrcRGYwDS +KFSRsK0bfO/OQQDUsSkNQSHjcOdLnCHCinMrQi1mBZOs+Y/DXOkkEV1zbFFV7q6X +4vX9HSWwTRQTdOV9CFZykbwM+X1YIZlVtpOAKqSNJi3P17uQF7P9zko6HWKKKQ5S +96BfXUOIpBRl82R85/yQgeGrWlvZ2BT2ittscNQlBKqLHJ7LIeDr9ctbKlKZjHTn +Da7NYg+PoMHspbizjSONbEzpcR/9ZUq16oJJABEBAAH+BwMC7hQZNJSmlX/W6sfL +0wakX6kTsiCEMy2vMCRcZ769JKT234avHtkL/g7MBJEzqdG9HSEp7+LHGuOWJhfa +20f61WvPT5ujUIy//QXJ9a8z877jCm+fHKCTDXGYLLfCkJLfr3/GfTRy6gaIGTSw +BqZaRelPvHbMp+eiFqDkf8W/E1LO3/83k87+pXggjz4p0OasyMw8RcDmy+IKBMGG +bzet5WIKHIhpblIzuuucQHOjtwA8vCedub3F4lcRuULe2GW6sNuCB9kjSC9g6D1d +bJ+WYi5GiUUQARGSNXiWVoVPLpEo0i6/2bKJ7vBYGRewNp42ebVQU2bFW7uzhaIq +4itzNTjFNTpcxX3Lo0/mzJpe7pVRJwN+HGahNGT0EtPDsT/nNTFDUq8e8nt0U9/8 +0eekg4MRBJEzE3A+wosIHPjzCkQgu98+nh79rPMbCpZVxNfLb136cTkubmHCWptN +T2MbqK2L4hMcOxHGGOmI9SjFltNeKtTsVtkxh3Vj67UESPdN550centfasJYA0bj +guRQfHWHJXYIfFwblIFkl8xtIVLTeWlQMEvc7oI8jcJOc2ri8Zdjj/55xxv/RvjC +ZKzfjPpdkLYcN1zP/hETLD68u7WmiMAYCr8Eq9YQ3oKklUpWxRMCAAtmgjGGpm5P +QQW+36s96Q3cuG8R0Z4Wo8y89FgWzCEzuAhemCdffoUA8kn0HJQaVndnExJb1Ebz +wp+zsX/JqiOFvcKHJAWCaXkk0oXVi1aIV4tQyCPfhyjnd846K7g8UabAz51IJHvF +CXRAmqJvu26NqjYOfWBJJxZQsPH4FjPfYx+e/MFPZa+UTKCfzaOHClrePHUDHw58 +Ez5ItcORYn51IWW33r+c4tlhW5mrjMD7FcjFOuYT4EIivd5BSnwLP0fjBz8TBVAY +yyFO+YAXTQ+0MVNpZ24gT25seSAodGVzdCBrZXksIGRvIG5vdCB1c2UpIDxzb0Bl +eGFtcGxlLm9yZz6JATcEEwEIACEFAld/jO8CGwMFCwkIBwIGFQgJCgsCBBYCAwEC +HgECF4AACgkQ/tFT8S8Y9F3PAwgAvKav6+luvcAhrpBMO4z/Q8kDMtO5AW1KTEcz +neqpj5eTVJVbYUgDuBlEXbFYtcZmYyYtJC5KQkN3bxPmehVUzGk27UYWMWbPIWyU +riGcFL5BWWQaKSqiWUypzhNVnxYoiWVhHeJ36LICVMpLBaubgcpwCSW/j58yZo/7 +XRwf40OblXr4cevIW4Oq5GSxKOQF+DCErF6BeikC2i+NoqSxwNiIO/1NUxs8QfAI +z8UT/bSUXr62BWLfeCIDGgXutMMPth3tKi4DlvLCzI6eYJrd8E3Rt7iUZm9IH8OQ +Djv2DKnL/E/AP8oITItrOmICqfEWcj+Tk2Xep4pCCMNU+Pa0yg== +=gG5b +-----END PGP PRIVATE KEY BLOCK----- diff --git a/lang/python/tests/support.py b/lang/python/tests/support.py new file mode 100644 index 0000000..4d7135e --- /dev/null +++ b/lang/python/tests/support.py @@ -0,0 +1,69 @@ +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import sys +import os +from pyme import core + +# known keys +alpha = "A0FF4590BB6122EDEF6E3C542D727CC768697734" +bob = "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2" +encrypt_only = "F52770D5C4DB41408D918C9F920572769B9FE19C" +sign_only = "7CCA20CCDE5394CEE71C9F0BFED153F12F18F45D" + +def make_filename(name): + return os.path.join(os.environ['top_srcdir'], 'tests', 'gpg', name) + +def in_srcdir(name): + return os.path.join(os.environ['srcdir'], name) + +def init_gpgme(proto): + core.engine_check_version(proto) + +verbose = int(os.environ.get('verbose', 0)) > 1 +def print_data(data): + if verbose: + try: + # See if it is a file-like object. + data.seek(0, os.SEEK_SET) + data = data.read() + except: + # Hope for the best. + pass + sys.stdout.buffer.write(data) + +def mark_key_trusted(ctx, key): + class Editor(object): + def __init__(self): + self.steps = ["trust", "save"] + def edit(self, status, args, out): + if args == "keyedit.prompt": + result = self.steps.pop(0) + elif args == "edit_ownertrust.value": + result = "5" + elif args == "edit_ownertrust.set_ultimate.okay": + result = "Y" + elif args == "keyedit.save.okay": + result = "Y" + else: + result = None + return result + with core.Data() as sink: + ctx.op_edit(key, Editor().edit, sink, sink) diff --git a/lang/python/tests/t-callbacks.py b/lang/python/tests/t-callbacks.py new file mode 100755 index 0000000..b3b4349 --- /dev/null +++ b/lang/python/tests/t-callbacks.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import os +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) + +c = core.Context() +c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK) + +source = core.Data("Hallo Leute\n") +sink = core.Data() + +# Valid passphrases, both as string and bytes. +for passphrase in ('foo', b'foo'): + def passphrase_cb(hint, desc, prev_bad, hook=None): + assert hook == passphrase + return hook + + c.set_passphrase_cb(passphrase_cb, passphrase) + c.op_encrypt([], 0, source, sink) + +# Returning an invalid type. +def passphrase_cb(hint, desc, prev_bad, hook=None): + return 0 + +c.set_passphrase_cb(passphrase_cb, None) +try: + c.op_encrypt([], 0, source, sink) +except Exception as e: + assert type(e) == TypeError + assert str(e) == "expected str or bytes from passphrase callback, got int" +else: + assert False, "Expected an error, got none" + +# Raising an exception inside callback. +myException = Exception() +def passphrase_cb(hint, desc, prev_bad, hook=None): + raise myException + +c.set_passphrase_cb(passphrase_cb, None) +try: + c.op_encrypt([], 0, source, sink) +except Exception as e: + assert e == myException +else: + assert False, "Expected an error, got none" + +# Wrong kind of callback function. +def bad_passphrase_cb(): + pass + +c.set_passphrase_cb(bad_passphrase_cb, None) +try: + c.op_encrypt([], 0, source, sink) +except Exception as e: + assert type(e) == TypeError +else: + assert False, "Expected an error, got none" + + + +# Test the progress callback. +parms = """<GnupgKeyParms format="internal"> +Key-Type: RSA +Key-Length: 1024 +Name-Real: Joe Tester +Name-Comment: with stupid passphrase +Name-Email: joe+pyme@example.org +Passphrase: Crypt0R0cks +Expire-Date: 2020-12-31 +</GnupgKeyParms> +""" + +messages = [] +def progress_cb(what, typ, current, total, hook=None): + assert hook == messages + messages.append( + "PROGRESS UPDATE: what = {}, type = {}, current = {}, total = {}" + .format(what, typ, current, total)) + +c = core.Context() +c.set_progress_cb(progress_cb, messages) +c.op_genkey(parms, None, None) +assert len(messages) > 0 + +# Test exception handling. +def progress_cb(what, typ, current, total, hook=None): + raise myException + +c = core.Context() +c.set_progress_cb(progress_cb, None) +try: + c.op_genkey(parms, None, None) +except Exception as e: + assert e == myException +else: + assert False, "Expected an error, got none" + + +# Test the edit callback. +c = core.Context() +c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK) +c.set_passphrase_cb(lambda *args: "abc") +sink = core.Data() +alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) + +cookie = object() +edit_cb_called = False +def edit_cb(status, args, hook): + global edit_cb_called + edit_cb_called = True + assert hook == cookie + return "quit" if args == "keyedit.prompt" else None +c.op_edit(alpha, edit_cb, cookie, sink) +assert edit_cb_called + +# Test exceptions. +c = core.Context() +c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK) +c.set_passphrase_cb(lambda *args: "abc") +sink = core.Data() + +def edit_cb(status, args): + raise myException +try: + c.op_edit(alpha, edit_cb, None, sink) +except Exception as e: + assert e == myException +else: + assert False, "Expected an error, got none" + + + +# Test the status callback. +source = core.Data("Hallo Leute\n") +sink = core.Data() + +status_cb_called = False +def status_cb(keyword, args, hook=None): + global status_cb_called + status_cb_called = True + assert hook == cookie + +c = core.Context() +c.set_status_cb(status_cb, cookie) +c.set_ctx_flag("full-status", "1") +c.op_encrypt([alpha], constants.ENCRYPT_ALWAYS_TRUST, source, sink) +assert status_cb_called + +# Test exceptions. +source = core.Data("Hallo Leute\n") +sink = core.Data() + +def status_cb(keyword, args): + raise myException + +c = core.Context() +c.set_status_cb(status_cb, None) +c.set_ctx_flag("full-status", "1") +try: + c.op_encrypt([alpha], constants.ENCRYPT_ALWAYS_TRUST, source, sink) +except Exception as e: + assert e == myException +else: + assert False, "Expected an error, got none" + + + +# Test the data callbacks. +def read_cb(amount, hook=None): + assert hook == cookie + return 0 +def release_cb(hook=None): + assert hook == cookie +data = core.Data(cbs=(read_cb, None, None, release_cb, cookie)) +try: + data.read() +except Exception as e: + assert type(e) == TypeError +else: + assert False, "Expected an error, got none" + +def read_cb(amount): + raise myException +data = core.Data(cbs=(read_cb, None, None, lambda: None)) +try: + data.read() +except Exception as e: + assert e == myException +else: + assert False, "Expected an error, got none" + + +def write_cb(what, hook=None): + assert hook == cookie + return "wrong type" +data = core.Data(cbs=(None, write_cb, None, release_cb, cookie)) +try: + data.write(b'stuff') +except Exception as e: + assert type(e) == TypeError +else: + assert False, "Expected an error, got none" + +def write_cb(what): + raise myException +data = core.Data(cbs=(None, write_cb, None, lambda: None)) +try: + data.write(b'stuff') +except Exception as e: + assert e == myException +else: + assert False, "Expected an error, got none" + + +def seek_cb(offset, whence, hook=None): + assert hook == cookie + return "wrong type" +data = core.Data(cbs=(None, None, seek_cb, release_cb, cookie)) +try: + data.seek(0, os.SEEK_SET) +except Exception as e: + assert type(e) == TypeError +else: + assert False, "Expected an error, got none" + +def seek_cb(offset, whence): + raise myException +data = core.Data(cbs=(None, None, seek_cb, lambda: None)) +try: + data.seek(0, os.SEEK_SET) +except Exception as e: + assert e == myException +else: + assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-data.py b/lang/python/tests/t-data.py new file mode 100755 index 0000000..4812a2e --- /dev/null +++ b/lang/python/tests/t-data.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import io +import os +import tempfile +from pyme import core + +data = core.Data('Hello world!') +assert data.read() == b'Hello world!' +assert data.read() == b'' + +data.seek(0, os.SEEK_SET) +assert data.read() == b'Hello world!' +assert data.read() == b'' + +data = core.Data(b'Hello world!') +assert data.read() == b'Hello world!' + +data = core.Data(b'Hello world!', copy=False) +assert data.read() == b'Hello world!' + +data = core.Data() +data.write('Hello world!') +data.seek(0, os.SEEK_SET) +assert data.read() == b'Hello world!' + +data = core.Data() +data.write(b'Hello world!') +data.seek(0, os.SEEK_SET) +assert data.read() == b'Hello world!' + +binjunk = bytes(range(256)) +data = core.Data() +data.write(binjunk) +data.seek(0, os.SEEK_SET) +assert data.read() == binjunk + +data = core.Data() +data.set_file_name("foobar") +assert data.get_file_name() == "foobar" + +# Test reading from an existing file. +with tempfile.NamedTemporaryFile() as tmp: + tmp.write(binjunk) + tmp.flush() + tmp.seek(0) + + # Open using name. + data = core.Data(file=tmp.name) + assert data.read() == binjunk + + # Open using name, without copying. + if False: + # delayed reads are not yet supported + data = core.Data(file=tmp.name, copy=False) + assert data.read() == binjunk + + # Open using stream. + tmp.seek(0) + data = core.Data(file=tmp) + assert data.read() == binjunk + + # Open using stream, offset, and length. + data = core.Data(file=tmp, offset=0, length=42) + assert data.read() == binjunk[:42] + + # Open using name, offset, and length. + data = core.Data(file=tmp.name, offset=23, length=42) + assert data.read() == binjunk[23:23+42] + +# Test callbacks. +class DataObject(object): + def __init__(self): + self.buffer = io.BytesIO() + self.released = False + + def read(self, amount, hook=None): + assert not self.released + return self.buffer.read(amount) + + def write(self, data, hook=None): + assert not self.released + return self.buffer.write(data) + + def seek(self, offset, whence, hook=None): + assert not self.released + return self.buffer.seek(offset, whence) + + def release(self, hook=None): + assert not self.released + self.released = True + +do = DataObject() +cookie = object() +data = core.Data(cbs=(do.read, do.write, do.seek, do.release, cookie)) +data.write('Hello world!') +data.seek(0, os.SEEK_SET) +assert data.read() == b'Hello world!' +del data +assert do.released + +# Again, without the cookie. +do = DataObject() +data = core.Data(cbs=(do.read, do.write, do.seek, do.release)) +data.write('Hello world!') +data.seek(0, os.SEEK_SET) +assert data.read() == b'Hello world!' +del data +assert do.released diff --git a/lang/python/tests/t-decrypt-verify.py b/lang/python/tests/t-decrypt-verify.py new file mode 100755 index 0000000..a38a965 --- /dev/null +++ b/lang/python/tests/t-decrypt-verify.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import pyme +from pyme import core, constants, errors +import support + +def check_verify_result(result, summary, fpr, status): + assert len(result.signatures) == 1, "Unexpected number of signatures" + sig = result.signatures[0] + assert sig.summary == summary, "Unexpected signature summary" + assert sig.fpr == fpr + assert errors.GPGMEError(sig.status).getcode() == status + assert len(sig.notations) == 0 + assert not sig.wrong_key_usage + assert sig.validity == constants.VALIDITY_FULL + assert errors.GPGMEError(sig.validity_reason).getcode() == errors.NO_ERROR + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() + +source = core.Data(file=support.make_filename("cipher-2.asc")) +sink = core.Data() + +c.op_decrypt_verify(source, sink) +result = c.op_decrypt_result() +assert not result.unsupported_algorithm, \ + "Unsupported algorithm: {}".format(result.unsupported_algorithm) + +support.print_data(sink) + +verify_result = c.op_verify_result() +check_verify_result(verify_result, + constants.SIGSUM_VALID | constants.SIGSUM_GREEN, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", + errors.NO_ERROR) + +# Idiomatic interface. +with pyme.Context() as c: + alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) + bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) + plaintext, _, verify_result = \ + c.decrypt(open(support.make_filename("cipher-2.asc")), verify=[alpha]) + assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \ + 'Plaintext not found' + check_verify_result(verify_result, + constants.SIGSUM_VALID | constants.SIGSUM_GREEN, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", + errors.NO_ERROR) + + try: + c.decrypt(open(support.make_filename("cipher-2.asc")), + verify=[alpha, bob]) + except errors.MissingSignatures as e: + assert len(e.missing) == 1 + assert e.missing[0] == bob + else: + assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-decrypt.py b/lang/python/tests/t-decrypt.py new file mode 100755 index 0000000..2d85bc2 --- /dev/null +++ b/lang/python/tests/t-decrypt.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import pyme +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() + +source = core.Data(file=support.make_filename("cipher-1.asc")) +sink = core.Data() + +c.op_decrypt(source, sink) +result = c.op_decrypt_result() +assert not result.unsupported_algorithm, \ + "Unsupported algorithm: {}".format(result.unsupported_algorithm) + +support.print_data(sink) + +# Idiomatic interface. +with pyme.Context() as c: + plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-1.asc"))) + assert len(plaintext) > 0 + assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \ + 'Plaintext not found' diff --git a/lang/python/tests/t-edit.py b/lang/python/tests/t-edit.py new file mode 100755 index 0000000..18bcb94 --- /dev/null +++ b/lang/python/tests/t-edit.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# Copyright (C) 2005 Igor Belyi <belyi@users.sourceforge.net> +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import sys +import os +from pyme import core, constants +import support + +class KeyEditor(object): + def __init__(self): + self.steps = ["fpr", "expire", "1", "primary", "quit"] + self.step = 0 + self.done = False + self.verbose = int(os.environ.get('verbose', 0)) > 1 + + def edit_fnc(self, status, args, out=None): + if args == "keyedit.prompt": + result = self.steps[self.step] + self.step += 1 + elif args == "keyedit.save.okay": + result = "Y" + self.done = self.step == len(self.steps) + elif args == "keygen.valid": + result = "0" + else: + result = None + + if self.verbose: + sys.stderr.write("Code: {}, args: {!r}, Returning: {!r}\n" + .format(status, args, result)) + + return result + +support.init_gpgme(constants.PROTOCOL_OpenPGP) + +c = core.Context() +c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK) +c.set_passphrase_cb(lambda *args: "abc") +c.set_armor(True) + +# The deprecated interface. +editor = KeyEditor() +c.interact(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), + editor.edit_fnc) +assert editor.done + +# The deprecated interface. +sink = core.Data() +editor = KeyEditor() +c.op_edit(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), + editor.edit_fnc, sink, sink) +assert editor.done diff --git a/lang/python/tests/t-encrypt-large.py b/lang/python/tests/t-encrypt-large.py new file mode 100755 index 0000000..b9cc3b5 --- /dev/null +++ b/lang/python/tests/t-encrypt-large.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import sys +import random +from pyme import core, constants +import support + +if len(sys.argv) == 2: + nbytes = int(sys.argv[1]) +else: + nbytes = 100000 + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() + +ntoread = nbytes +def read_cb(amount): + global ntoread + chunk = ntoread if ntoread < amount else amount + ntoread -= chunk + assert ntoread >= 0 + assert chunk >= 0 + return bytes(bytearray(random.randrange(256) for i in range(chunk))) + +nwritten = 0 +def write_cb(data): + global nwritten + nwritten += len(data) + return len(data) + +source = core.Data(cbs=(read_cb, None, None, lambda: None)) +sink = core.Data(cbs=(None, write_cb, None, lambda: None)) + +keys = [] +keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) +keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) + +c.op_encrypt(keys, constants.ENCRYPT_ALWAYS_TRUST, source, sink) +result = c.op_encrypt_result() +assert not result.invalid_recipients, \ + "Invalid recipient encountered: {}".format(result.invalid_recipients.fpr) +assert ntoread == 0 + +if support.verbose: + sys.stderr.write( + "plaintext={} bytes, ciphertext={} bytes\n".format(nbytes, nwritten)) diff --git a/lang/python/tests/t-encrypt-sign.py b/lang/python/tests/t-encrypt-sign.py new file mode 100755 index 0000000..a453f79 --- /dev/null +++ b/lang/python/tests/t-encrypt-sign.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import sys +import pyme +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_armor(True) + +def check_result(r, typ): + if r.invalid_signers: + sys.exit("Invalid signer found: {}".format(r.invalid_signers.fpr)) + + if len(r.signatures) != 1: + sys.exit("Unexpected number of signatures created") + + signature = r.signatures[0] + if signature.type != typ: + sys.exit("Wrong type of signature created") + + if signature.pubkey_algo != constants.PK_DSA: + sys.exit("Wrong pubkey algorithm reported: {}".format( + signature.pubkey_algo)) + + if signature.hash_algo not in (constants.MD_SHA1, constants.MD_RMD160): + sys.exit("Wrong hash algorithm reported: {}".format( + signature.hash_algo)) + + if signature.sig_class != 0: + sys.exit("Wrong signature class reported: {}".format( + signature.sig_class)) + + if signature.fpr != "A0FF4590BB6122EDEF6E3C542D727CC768697734": + sys.exit("Wrong fingerprint reported: {}".format(signature.fpr)) + +keys = [] +keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) +keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) + +for recipients in (keys, []): + source = core.Data("Hallo Leute\n") + sink = core.Data() + + c.op_encrypt_sign(recipients, constants.ENCRYPT_ALWAYS_TRUST, source, sink) + result = c.op_encrypt_result() + assert not result.invalid_recipients, \ + "Invalid recipient encountered: {}".format( + result.invalid_recipients.fpr) + + result = c.op_sign_result() + check_result(result, constants.SIG_MODE_NORMAL) + + support.print_data(sink) + + +# Idiomatic interface. +with pyme.Context(armor=True) as c: + message = "Hallo Leute\n".encode() + ciphertext, _, sig_result = c.encrypt(message, + recipients=keys, + always_trust=True) + assert len(ciphertext) > 0 + assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' + check_result(sig_result, constants.SIG_MODE_NORMAL) + + c.signers = [c.get_key(support.sign_only, True)] + c.encrypt(message, recipients=keys, always_trust=True) + + c.signers = [c.get_key(support.encrypt_only, True)] + try: + c.encrypt(message, recipients=keys, always_trust=True) + except pyme.errors.InvalidSigners as e: + assert len(e.signers) == 1 + assert support.encrypt_only.endswith(e.signers[0].fpr) + else: + assert False, "Expected an InvalidSigners error, got none" diff --git a/lang/python/tests/t-encrypt-sym.py b/lang/python/tests/t-encrypt-sym.py new file mode 100755 index 0000000..d577184 --- /dev/null +++ b/lang/python/tests/t-encrypt-sym.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import os +import pyme +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) + +for passphrase in ("abc", b"abc"): + c = core.Context() + c.set_armor(True) + c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK) + + source = core.Data("Hallo Leute\n") + cipher = core.Data() + + passphrase_cb_called = 0 + def passphrase_cb(hint, desc, prev_bad, hook=None): + global passphrase_cb_called + passphrase_cb_called += 1 + return passphrase + + c.set_passphrase_cb(passphrase_cb, None) + + c.op_encrypt([], 0, source, cipher) + assert passphrase_cb_called == 1, \ + "Callback called {} times".format(passphrase_cb_called) + support.print_data(cipher) + + c = core.Context() + c.set_armor(True) + c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK) + c.set_passphrase_cb(passphrase_cb, None) + plain = core.Data() + cipher.seek(0, os.SEEK_SET) + + c.op_decrypt(cipher, plain) + # Seems like the passphrase is cached. + #assert passphrase_cb_called == 2, \ + # "Callback called {} times".format(passphrase_cb_called) + support.print_data(plain) + + plain.seek(0, os.SEEK_SET) + plaintext = plain.read() + assert plaintext == b"Hallo Leute\n", \ + "Wrong plaintext {!r}".format(plaintext) + +# Idiomatic interface. +for passphrase in ("abc", b"abc"): + with pyme.Context(armor=True) as c: + # Check that the passphrase callback is not altered. + def f(*args): + assert False + c.set_passphrase_cb(f) + + message = "Hallo Leute\n".encode() + ciphertext, _, _ = c.encrypt(message, + passphrase=passphrase, + sign=False) + assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' + + plaintext, _, _ = c.decrypt(ciphertext, passphrase=passphrase) + assert plaintext == message, 'Message body not recovered' + + assert c._passphrase_cb[1] == f, "Passphrase callback not restored" diff --git a/lang/python/tests/t-encrypt.py b/lang/python/tests/t-encrypt.py new file mode 100755 index 0000000..65e7d24 --- /dev/null +++ b/lang/python/tests/t-encrypt.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import pyme +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_armor(True) + +source = core.Data("Hallo Leute\n") +sink = core.Data() + +keys = [] +keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) +keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) + +c.op_encrypt(keys, constants.ENCRYPT_ALWAYS_TRUST, source, sink) +result = c.op_encrypt_result() +assert not result.invalid_recipients, \ + "Invalid recipients: {}".format(", ".join(r.fpr for r in result.recipients)) +support.print_data(sink) + +# Idiomatic interface. +with pyme.Context(armor=True) as c: + ciphertext, _, _ = c.encrypt("Hallo Leute\n".encode(), + recipients=keys, + sign=False, + always_trust=True) + assert len(ciphertext) > 0 + assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' + + c.encrypt("Hallo Leute\n".encode(), + recipients=[c.get_key(support.encrypt_only, False)], + sign=False, always_trust=True) + + try: + c.encrypt("Hallo Leute\n".encode(), + recipients=[c.get_key(support.sign_only, False)], + sign=False, always_trust=True) + except pyme.errors.InvalidRecipients as e: + assert len(e.recipients) == 1 + assert support.sign_only.endswith(e.recipients[0].fpr) + else: + assert False, "Expected an InvalidRecipients error, got none" diff --git a/lang/python/tests/t-export.py b/lang/python/tests/t-export.py new file mode 100755 index 0000000..db36b98 --- /dev/null +++ b/lang/python/tests/t-export.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_armor(True) + +sink = core.Data() +c.op_export_ext(['Alpha', 'Bob'], 0, sink) +support.print_data(sink) + +# Again. Now using a key array. +keys = [] +keys.append(c.get_key("0x68697734", False)) # Alpha +keys.append(c.get_key("0xA9E3B0B2", False)) # Bob +sink = core.Data() +c.op_export_keys(keys, 0, sink) +support.print_data(sink) diff --git a/lang/python/tests/t-file-name.py b/lang/python/tests/t-file-name.py new file mode 100755 index 0000000..e93b120 --- /dev/null +++ b/lang/python/tests/t-file-name.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import os +from pyme import core, constants +import support + +testname = "abcde12345" + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_armor(True) + +source = core.Data("Hallo Leute\n") +source.set_file_name(testname) +cipher = core.Data() +plain = core.Data() + +keys = [] +keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) + +c.op_encrypt(keys, constants.ENCRYPT_ALWAYS_TRUST, source, cipher) +cipher.seek(0, os.SEEK_SET) +c.op_decrypt(cipher, plain) +result = c.op_decrypt_result() +assert result.file_name == testname diff --git a/lang/python/tests/t-idiomatic.py b/lang/python/tests/t-idiomatic.py new file mode 100755 index 0000000..f063206 --- /dev/null +++ b/lang/python/tests/t-idiomatic.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import sys +import io +import os +import tempfile +import pyme +import support + +support.init_gpgme(pyme.constants.PROTOCOL_OpenPGP) + +# Both Context and Data can be used as context manager: +with pyme.Context() as c, pyme.Data() as d: + c.get_engine_info() + d.write(b"Halloechen") + leak_c = c + leak_d = d +assert leak_c.wrapped == None +assert leak_d.wrapped == None + +def sign_and_verify(source, signed, sink): + with pyme.Context() as c: + c.op_sign(source, signed, pyme.constants.SIG_MODE_NORMAL) + signed.seek(0, os.SEEK_SET) + c.op_verify(signed, None, sink) + result = c.op_verify_result() + + assert len(result.signatures) == 1, "Unexpected number of signatures" + sig = result.signatures[0] + assert sig.summary == (pyme.constants.SIGSUM_VALID | + pyme.constants.SIGSUM_GREEN) + assert pyme.errors.GPGMEError(sig.status).getcode() == pyme.errors.NO_ERROR + + sink.seek(0, os.SEEK_SET) + assert sink.read() == b"Hallo Leute\n" + +# Demonstrate automatic wrapping of file-like objects with 'fileno' +# method. +with tempfile.TemporaryFile() as source, \ + tempfile.TemporaryFile() as signed, \ + tempfile.TemporaryFile() as sink: + source.write(b"Hallo Leute\n") + source.seek(0, os.SEEK_SET) + + sign_and_verify(source, signed, sink) + +if sys.version_info[0] == 3: + # Python2's io.BytesIO does not implement the buffer interface, + # hence we cannot use it as sink. + + # XXX: Python's io.BytesIo.truncate does not work as advertised. + # http://bugs.python.org/issue27261 + bio = io.BytesIO() + bio.truncate(1) + if len(bio.getvalue()) != 1: + # This version of Python is affected, preallocate buffer. + preallocate = 128*b'\x00' + else: + preallocate = b'' + + # Demonstrate automatic wrapping of objects implementing the buffer + # interface, and the use of data objects with the 'with' statement. + with io.BytesIO(preallocate) as signed, pyme.Data() as sink: + sign_and_verify(b"Hallo Leute\n", signed, sink) diff --git a/lang/python/tests/t-import.py b/lang/python/tests/t-import.py new file mode 100755 index 0000000..0b50d02 --- /dev/null +++ b/lang/python/tests/t-import.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from pyme import core, constants +import support + +def check_result(result, fpr, secret): + assert result.considered == 1 or (secret and result.considered == 3) + assert result.no_user_id == 0 + assert not ((secret and result.imported != 0) + or (not secret and (result.imported != 0 + and result.imported != 1))) + assert result.imported_rsa == 0 + assert not ((secret and (result.unchanged != 0 and result.unchanged != 1)) + or (not secret and ((result.imported == 0 + and result.unchanged != 1) + or (result.imported == 1 + and result.unchanged != 0)))) + assert result.new_user_ids == 0 + assert result.new_sub_keys == 0 + assert not ((secret + and ((result.secret_imported == 0 + and result.new_signatures != 0) + or (result.secret_imported == 1 + and result.new_signatures > 1))) + or (not secret and result.new_signatures != 0)) + assert result.new_revocations == 0 + assert not ((secret and result.secret_read != 1 and result.secret_read != 3) + or (not secret and result.secret_read != 0)) + assert not ((secret and result.secret_imported != 0 + and result.secret_imported != 1 + and result.secret_imported != 2) + or (not secret and result.secret_imported != 0)) + assert not ((secret + and ((result.secret_imported == 0 + and result.secret_unchanged != 1 + and result.secret_unchanged != 2) + or (result.secret_imported == 1 + and result.secret_unchanged != 0))) + or (not secret and result.secret_unchanged != 0)) + assert result.not_imported == 0 + if secret: + assert not (len(result.imports) in (0, 3)) + else: + assert not (len(result.imports) in (0, 2)) + + assert fpr == result.imports[0].fpr + assert len(result.imports) == 1 or fpr == result.imports[1].fpr + assert result.imports[0].result == 0 + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() + +c.op_import(core.Data(file=support.make_filename("pubkey-1.asc"))) +result = c.op_import_result() +check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", False) + +c.op_import(core.Data(file=support.make_filename("seckey-1.asc"))) +result = c.op_import_result() +check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", True) diff --git a/lang/python/tests/t-keylist.py b/lang/python/tests/t-keylist.py new file mode 100755 index 0000000..5e8b333 --- /dev/null +++ b/lang/python/tests/t-keylist.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() + +# Check expration of keys. This test assumes three subkeys of which +# 2 are expired; it is used with the "Whisky" test key. It has +# already been checked that these 3 subkeys are available. +def check_whisky(name, key): + sub1 = key.subkeys[2] + sub2 = key.subkeys[3] + + assert sub1.expired and sub2.expired, \ + "Subkey of `{}' not flagged as expired".format(name) + assert sub1.expires == 1129636886 and sub2.expires == 1129636939, \ + "Subkey of `{}' has wrong expiration date".format(name) + +keys = [ + [ "A0FF4590BB6122EDEF6E3C542D727CC768697734", "6AE6D7EE46A871F8", + [ [ "Alfa Test", "demo key", "alfa@example.net" ], + [ "Alpha Test", "demo key", "alpha@example.net" ], + [ "Alice", "demo key", "" ] ], 1 ], + [ "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", "5381EA4EE29BA37F", + [ [ "Bob", "demo key", "" ], + [ "Bravo Test", "demo key", "bravo@example.net" ] ], 1 ], + [ "61EE841A2A27EB983B3B3C26413F4AF31AFDAB6C", "E71E72ACBC43DA60", + [ [ "Charlie Test", "demo key", "charlie@example.net" ] ], 1 ], + [ "6560C59C43D031C54D7C588EEBA9F240EB9DC9E6", "06F22880B0C45424", + [ [ "Delta Test", "demo key", "delta@example.net" ] ], 1 ], + [ "3531152DE293E26A07F504BC318C1FAEFAEF6D1B", "B5C79E1A7272144D", + [ [ "Echelon", "demo key", "" ], + [ "Echo Test", "demo key", "echo@example.net" ], + [ "Eve", "demo key", "" ] ], 1 ], + [ "56D33268F7FE693FBB594762D4BF57F37372E243", "0A32EE79EE45198E", + [ [ "Foxtrot Test", "demo key", "foxtrot@example.net" ] ], 1 ], + [ "C9C07DCC6621B9FB8D071B1D168410A48FC282E6", "247491CC9DCAD354", + [ [ "Golf Test", "demo key", "golf@example.net" ] ], 1 ], + [ "9E91CBB11E4D4135583EF90513DB965534C6E3F1", "76E26537D622AD0A", + [ [ "Hotel Test", "demo key", "hotel@example.net" ] ], 1 ], + [ "CD538D6CC9FB3D745ECDA5201FE8FC6F04259677", "C1C8EFDE61F76C73", + [ [ "India Test", "demo key", "india@example.net" ] ], 1 ], + [ "F8F1EDC73995AB739AD54B380C820C71D2699313", "BD0B108735F8F136", + [ [ "Juliet Test", "demo key", "juliet@example.net" ] ], 1 ], + [ "3FD11083779196C2ECDD9594AD1B0FAD43C2D0C7", "86CBB34A9AF64D02", + [ [ "Kilo Test", "demo key", "kilo@example.net" ] ], 1 ], + [ "1DDD28CEF714F5B03B8C246937CAB51FB79103F8", "0363B449FE56350C", + [ [ "Lima Test", "demo key", "lima@example.net" ] ], 1 ], + [ "2686AA191A278013992C72EBBE794852BE5CF886", "5F600A834F31EAE8", + [ [ "Mallory", "demo key", "" ], + [ "Mike Test", "demo key", "mike@example.net" ] ], 1 ], + [ "5AB9D6D7BAA1C95B3BAA3D9425B00FD430CEC684", "4C1D63308B70E472", + [ [ "November Test", "demo key", "november@example.net" ] ], 1 ], + [ "43929E89F8F79381678CAE515F6356BA6D9732AC", "FF0785712681619F", + [ [ "Oscar Test", "demo key", "oscar@example.net" ] ], 1 ], + [ "6FAA9C201E5E26DCBAEC39FD5D15E01D3FF13206", "2764E18263330D9C", + [ [ "Papa test", "demo key", "papa@example.net" ] ], 1 ], + [ "A7969DA1C3297AA96D49843F1C67EC133C661C84", "6CDCFC44A029ACF4", + [ [ "Quebec Test", "demo key", "quebec@example.net" ] ], 1 ], + [ "38FBE1E4BF6A5E1242C8F6A13BDBEDB1777FBED3", "9FAB805A11D102EA", + [ [ "Romeo Test", "demo key", "romeo@example.net" ] ], 1 ], + [ "045B2334ADD69FC221076841A5E67F7FA3AE3EA1", "93B88B0F0F1B50B4", + [ [ "Sierra Test", "demo key", "sierra@example.net" ] ], 1 ], + [ "ECAC774F4EEEB0620767044A58CB9A4C85A81F38", "97B60E01101C0402", + [ [ "Tango Test", "demo key", "tango@example.net" ] ], 1 ], + [ "0DBCAD3F08843B9557C6C4D4A94C0F75653244D6", "93079B915522BDB9", + [ [ "Uniform Test", "demo key", "uniform@example.net" ] ], 1 ], + [ "E8143C489C8D41124DC40D0B47AF4B6961F04784", "04071FB807287134", + [ [ "Victor Test", "demo key", "victor@example.org" ] ], 1 ], + [ "E8D6C90B683B0982BD557A99DEF0F7B8EC67DBDE", "D7FBB421FD6E27F6", + [ [ "Whisky Test", "demo key", "whisky@example.net" ] ], 3, + check_whisky ], + [ "04C1DF62EFA0EBB00519B06A8979A6C5567FB34A", "5CC6F87F41E408BE", + [ [ "XRay Test", "demo key", "xray@example.net" ] ], 1 ], + [ "ED9B316F78644A58D042655A9EEF34CD4B11B25F", "5ADFD255F7B080AD", + [ [ "Yankee Test", "demo key", "yankee@example.net" ] ], 1 ], + [ "23FD347A419429BACCD5E72D6BC4778054ACD246", "EF9DC276A172C881", + [ [ "Zulu Test", "demo key", "zulu@example.net" ] ], 1 ], +] + +def check_global(key, uids, n_subkeys): + assert not key.revoked, "Key unexpectedly revoked" + assert not key.expired, "Key unexpectedly expired" + assert not key.disabled, "Key unexpectedly disabled" + assert not key.invalid, "Key unexpectedly invalid" + assert key.can_sign, "Key unexpectedly unusable for signing" + assert key.can_certify, "Key unexpectedly unusable for certifications" + assert not key.secret, "Key unexpectedly secret" + assert not key.protocol != constants.PROTOCOL_OpenPGP, \ + "Key has unexpected protocol: {}".format(key.protocol) + assert not key.issuer_serial, \ + "Key unexpectedly carries issuer serial: {}".format(key.issuer_serial) + assert not key.issuer_name, \ + "Key unexpectedly carries issuer name: {}".format(key.issuer_name) + assert not key.chain_id, \ + "Key unexpectedly carries chain ID: {}".format(key.chain_id) + + # Only key Alfa is trusted + assert key.uids[0].name == 'Alfa Test' \ + or key.owner_trust == constants.VALIDITY_UNKNOWN, \ + "Key has unexpected owner trust: {}".format(key.owner_trust) + assert key.uids[0].name != 'Alfa Test' \ + or key.owner_trust == constants.VALIDITY_ULTIMATE, \ + "Key has unexpected owner trust: {}".format(key.owner_trust) + + assert len(key.subkeys) - 1 == n_subkeys, \ + "Key `{}' has unexpected number of subkeys".format(uids[0][0]) + + +def check_subkey(fpr, which, subkey): + assert not subkey.revoked, which + " key unexpectedly revoked" + assert not subkey.expired, which + " key unexpectedly expired" + assert not subkey.disabled, which + " key unexpectedly disabled" + assert not subkey.invalid, which + " key unexpectedly invalid" + + if which == "Primary": + assert not subkey.can_encrypt, \ + which + " key unexpectedly usable for encryption" + assert subkey.can_sign, \ + which + " key unexpectedly unusable for signing" + assert subkey.can_certify, \ + which + " key unexpectedly unusable for certifications" + else: + assert subkey.can_encrypt, \ + which + " key unexpectedly unusable for encryption" + assert not subkey.can_sign, \ + which + " key unexpectedly usable for signing" + assert not subkey.can_certify, \ + which + " key unexpectedly usable for certifications" + + assert not subkey.secret, which + " key unexpectedly secret" + assert not subkey.is_cardkey, "Public key marked as card key" + assert not subkey.card_number, "Public key with card number set" + assert not subkey.pubkey_algo != (constants.PK_DSA if which == "Primary" + else constants.PK_ELG_E), \ + which + " key has unexpected public key algo: {}".\ + format(subkey.pubkey_algo) + assert subkey.length == 1024, \ + which + " key has unexpected length: {}".format(subkey.length) + assert fpr.endswith(subkey.keyid), \ + which + " key has unexpected key ID: {}".format(subkey.keyid) + assert which == "Secondary" or subkey.fpr == fpr, \ + which + " key has unexpected fingerprint: {}".format(subkey.fpr) + assert not subkey.expires, \ + which + " key unexpectedly expires: {}".format(subkey.expires) + +def check_uid(which, ref, uid): + assert not uid.revoked, which + " user ID unexpectedly revoked" + assert not uid.invalid, which + " user ID unexpectedly invalid" + assert uid.validity == (constants.VALIDITY_UNKNOWN + if uid.name.split()[0] + not in {'Alfa', 'Alpha', 'Alice'} else + constants.VALIDITY_ULTIMATE), \ + which + " user ID has unexpectedly validity: {}".format(uid.validity) + assert not uid.signatures, which + " user ID unexpectedly signed" + assert uid.name == ref[0], \ + "Unexpected name in {} user ID: {!r}".format(which.lower(), uid.name) + assert uid.comment == ref[1], \ + "Unexpected comment in {} user ID: {!r}".format(which.lower(), + uid.comment) + assert uid.email == ref[2], \ + "Unexpected email in {} user ID: {!r}".format(which.lower(), uid.email) + +i = 0 +c.op_keylist_start(None, False) +key = c.op_keylist_next () +while key: + try: + if len(keys[i]) == 4: + fpr, sec_keyid, uids, n_subkeys = keys[i] + misc_check = None + else: + fpr, sec_keyid, uids, n_subkeys, misc_check = keys[i] + except IndexError: + # There are more keys. We don't check for that. + break + + # Global key flags. + check_global(key, uids, n_subkeys) + check_subkey(fpr, "Primary", key.subkeys[0]) + check_subkey(sec_keyid, "Secondary", key.subkeys[1]) + + assert len(key.uids) == len(uids) + check_uid("First", uids[0], key.uids[0]) + if len(key.uids) > 1: + check_uid("Second", uids[1], key.uids[1]) + if len(key.uids) > 2: + check_uid("Third", uids[2], key.uids[2]) + + if misc_check: + misc_check (uids[0][0], key) + key = c.op_keylist_next () + i += 1 + +c.op_keylist_end() +result = c.op_keylist_result() +assert not result.truncated, "Key listing unexpectedly truncated" + + +for i, key in enumerate(c.keylist()): + try: + if len(keys[i]) == 4: + fpr, sec_keyid, uids, n_subkeys = keys[i] + misc_check = None + else: + fpr, sec_keyid, uids, n_subkeys, misc_check = keys[i] + except IndexError: + # There are more keys. We don't check for that. + break + + # Global key flags. + check_global(key, uids, n_subkeys) + check_subkey(fpr, "Primary", key.subkeys[0]) + check_subkey(sec_keyid, "Secondary", key.subkeys[1]) + + assert len(key.uids) == len(uids) + check_uid("First", uids[0], key.uids[0]) + if len(key.uids) > 1: + check_uid("Second", uids[1], key.uids[1]) + if len(key.uids) > 2: + check_uid("Third", uids[2], key.uids[2]) + + if misc_check: + misc_check (uids[0][0], key) diff --git a/lang/python/tests/t-protocol-assuan.py b/lang/python/tests/t-protocol-assuan.py new file mode 100755 index 0000000..172c7d0 --- /dev/null +++ b/lang/python/tests/t-protocol-assuan.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import pyme + +with pyme.Context(protocol=pyme.constants.PROTOCOL_ASSUAN) as c: + # Do nothing. + c.assuan_transact('nop') + c.assuan_transact('NOP') + c.assuan_transact(['NOP']) + + err = c.assuan_transact('idontexist') + assert err.getsource() == pyme.errors.SOURCE_GPGAGENT + assert err.getcode() == pyme.errors.ASS_UNKNOWN_CMD + + # Invoke the pinentry to get a confirmation. + c.assuan_transact(['GET_CONFIRMATION', 'Hello there']) + + data = [] + def data_cb(line): + data.append(line) + + err = c.assuan_transact(['GETINFO', 'version'], data_cb=data_cb) + assert not err + assert len(data) == 1 + + data = [] + err = c.assuan_transact(['GETINFO', 's2k_count'], data_cb=data_cb) + if not err: + assert len(data) == 1 + assert int(data[0]) > 0 + + # XXX HELP sends status lines if we could use ASSUAN_CONVEY_COMMENTS. + + status = [] + def status_cb(line, args): + status.append((line, args)) + + alphas_grip = '76F7E2B35832976B50A27A282D9B87E44577EB66' + err = c.assuan_transact(['KEYINFO', alphas_grip], status_cb=status_cb) + if not err: + assert len(status) == 1 + line, args = status[0] + assert line.startswith('KEYINFO') + assert args.startswith(alphas_grip) + + # XXX: test these callbacks, e.g. using PRESET_PASSPHRASE + # XXX: once issue2428 is resolved + def inq_cb(name, args): + print("inq_cb", name, args) diff --git a/lang/python/tests/t-sig-notation.py b/lang/python/tests/t-sig-notation.py new file mode 100755 index 0000000..777bc0b --- /dev/null +++ b/lang/python/tests/t-sig-notation.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import os +from pyme import core, constants +import support + +expected_notations = { + "laughing@me": ("Just Squeeze Me", constants.SIG_NOTATION_HUMAN_READABLE), + "preferred-email-encoding@pgp.com": ("pgpmime", + constants.SIG_NOTATION_HUMAN_READABLE + | constants.SIG_NOTATION_CRITICAL), + None: ("http://www.gnu.org/policy/", 0), +} + +# GnuPG prior to 2.1.13 did not report the critical flag correctly. +with core.Context() as c: + version = c.engine_info.version + have_correct_sig_data = not (version.startswith("1.") + or version == "2.1.1" + or (version.startswith("2.1.1") + and version[5] < '3')) + +def check_result(result): + assert len(result.signatures) == 1, "Unexpected number of signatures" + sig = result.signatures[0] + assert len(sig.notations) == len(expected_notations) + + for r in sig.notations: + assert not 'name_len' in dir(r) + assert not 'value_len' in dir(r) + assert r.name in expected_notations + value, flags = expected_notations.pop(r.name) + + assert r.value == value, \ + "Expected {!r}, got {!r}".format(value, r.value) + assert r.human_readable \ + == bool(flags&constants.SIG_NOTATION_HUMAN_READABLE) + assert r.critical \ + == (bool(flags&constants.SIG_NOTATION_CRITICAL) + if have_correct_sig_data else False) + + assert len(expected_notations) == 0 + +support.init_gpgme(constants.PROTOCOL_OpenPGP) + +source = core.Data("Hallo Leute\n") +signed = core.Data() + +c = core.Context() +for name, (value, flags) in expected_notations.items(): + c.sig_notation_add(name, value, flags) + +c.op_sign(source, signed, constants.SIG_MODE_NORMAL) + +signed.seek(0, os.SEEK_SET) +sink = core.Data() +c.op_verify(signed, None, sink) +result = c.op_verify_result() +check_result(result) diff --git a/lang/python/tests/t-sign.py b/lang/python/tests/t-sign.py new file mode 100755 index 0000000..b0e211a --- /dev/null +++ b/lang/python/tests/t-sign.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import os +import pyme +from pyme import core, constants +import support + +def fail(msg): + raise RuntimeError(msg) + +def check_result(r, typ): + if r.invalid_signers: + fail("Invalid signer found: {}".format(r.invalid_signers.fpr)) + + if len(r.signatures) != 1: + fail("Unexpected number of signatures created") + + signature = r.signatures[0] + if signature.type != typ: + fail("Wrong type of signature created") + + if signature.pubkey_algo != constants.PK_DSA: + fail("Wrong pubkey algorithm reported: {}".format( + signature.pubkey_algo)) + + if signature.hash_algo != constants.MD_SHA1: + fail("Wrong hash algorithm reported: {}".format( + signature.hash_algo)) + + if signature.sig_class != 1: + fail("Wrong signature class reported: {}".format( + signature.sig_class)) + + if signature.fpr != "A0FF4590BB6122EDEF6E3C542D727CC768697734": + fail("Wrong fingerprint reported: {}".format(signature.fpr)) + + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_textmode(True) +c.set_armor(True) + +source = core.Data("Hallo Leute\n") +sink = core.Data() + +c.op_sign(source, sink, constants.SIG_MODE_NORMAL) + +result = c.op_sign_result() +check_result(result, constants.SIG_MODE_NORMAL) +support.print_data(sink) + +# Now a detached signature. +source.seek(0, os.SEEK_SET) +sink = core.Data() + +c.op_sign(source, sink, constants.SIG_MODE_DETACH) + +result = c.op_sign_result() +check_result(result, constants.SIG_MODE_DETACH) +support.print_data(sink) + +# And finally a cleartext signature. */ +source.seek(0, os.SEEK_SET) +sink = core.Data() + +c.op_sign(source, sink, constants.SIG_MODE_CLEAR) + +result = c.op_sign_result() +check_result(result, constants.SIG_MODE_CLEAR) +support.print_data(sink) + +# Idiomatic interface. +with pyme.Context(armor=True, textmode=True) as c: + message = "Hallo Leute\n".encode() + signed, _ = c.sign(message) + assert len(signed) > 0 + assert signed.find(b'BEGIN PGP MESSAGE') > 0, 'Message not found' + + signed, _ = c.sign(message, mode=pyme.constants.SIG_MODE_DETACH) + assert len(signed) > 0 + assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' + + signed, _ = c.sign(message, mode=pyme.constants.SIG_MODE_CLEAR) + assert len(signed) > 0 + assert signed.find(b'BEGIN PGP SIGNED MESSAGE') > 0, 'Message not found' + assert signed.find(message) > 0, 'Message content not found' + assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' + +with pyme.Context() as c: + message = "Hallo Leute\n".encode() + + c.signers = [c.get_key(support.sign_only, True)] + c.sign(message) + + c.signers = [c.get_key(support.encrypt_only, True)] + try: + c.sign(message) + except pyme.errors.InvalidSigners as e: + assert len(e.signers) == 1 + assert support.encrypt_only.endswith(e.signers[0].fpr) + else: + assert False, "Expected an InvalidSigners error, got none" diff --git a/lang/python/tests/t-signers.py b/lang/python/tests/t-signers.py new file mode 100755 index 0000000..11403af --- /dev/null +++ b/lang/python/tests/t-signers.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import pyme +from pyme import core, constants +import support + +def fail(msg): + raise RuntimeError(msg) + +def check_result(r, typ): + if r.invalid_signers: + fail("Invalid signer found: {}".format(r.invalid_signers.fpr)) + + if len(r.signatures) != 2: + fail("Unexpected number of signatures created") + + for signature in r.signatures: + if signature.type != typ: + fail("Wrong type of signature created") + + if signature.pubkey_algo != constants.PK_DSA: + fail("Wrong pubkey algorithm reported: {}".format( + signature.pubkey_algo)) + + if signature.hash_algo != constants.MD_SHA1: + fail("Wrong hash algorithm reported: {}".format( + signature.hash_algo)) + + if signature.sig_class != 1: + fail("Wrong signature class reported: got {}, want {}".format( + signature.sig_class, 1)) + + if signature.fpr not in ("A0FF4590BB6122EDEF6E3C542D727CC768697734", + "23FD347A419429BACCD5E72D6BC4778054ACD246"): + fail("Wrong fingerprint reported: {}".format(signature.fpr)) + + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_textmode(True) +c.set_armor(True) + +keys = [] +c.op_keylist_start('', True) +keys.append(c.op_keylist_next()) +keys.append(c.op_keylist_next()) +c.op_keylist_end() + +c.signers_add(keys[0]) +c.signers_add(keys[1]) + +for mode in (constants.SIG_MODE_NORMAL, constants.SIG_MODE_DETACH, + constants.SIG_MODE_CLEAR): + source = core.Data("Hallo Leute\n") + sink = core.Data() + + c.op_sign(source, sink, mode) + + result = c.op_sign_result() + check_result(result, mode) + support.print_data(sink) + +# Idiomatic interface. +with pyme.Context(armor=True, textmode=True, signers=keys) as c: + message = "Hallo Leute\n".encode() + signed, result = c.sign(message) + check_result(result, constants.SIG_MODE_NORMAL) + assert signed.find(b'BEGIN PGP MESSAGE') > 0, 'Message not found' + + signed, result = c.sign(message, mode=constants.SIG_MODE_DETACH) + check_result(result, constants.SIG_MODE_DETACH) + assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' + + signed, result = c.sign(message, mode=constants.SIG_MODE_CLEAR) + check_result(result, constants.SIG_MODE_CLEAR) + assert signed.find(b'BEGIN PGP SIGNED MESSAGE') > 0, 'Message not found' + assert signed.find(message) > 0, 'Message content not found' + assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' diff --git a/lang/python/tests/t-trustlist.py b/lang/python/tests/t-trustlist.py new file mode 100755 index 0000000..4253bd7 --- /dev/null +++ b/lang/python/tests/t-trustlist.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from pyme import core, constants +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() + +def dump_item(item): + print("l={} k={} t={} o={} v={} u={}".format( + item.level, item.keyid, item.type, item.owner_trust, + item.validity, item.name)) + +c.op_trustlist_start("alice", 0) +while True: + item = c.op_trustlist_next() + if not item: + break + dump_item(item) +c.op_trustlist_end() + +for item in c.op_trustlist_all("alice", 0): + dump_item(item) diff --git a/lang/python/tests/t-verify.py b/lang/python/tests/t-verify.py new file mode 100755 index 0000000..39f6176 --- /dev/null +++ b/lang/python/tests/t-verify.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import sys +import os +import pyme +from pyme import core, constants, errors +import support + +test_text1 = b"Just GNU it!\n" +test_text1f= b"Just GNU it?\n" +test_sig1 = b"""-----BEGIN PGP SIGNATURE----- + +iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt +bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv +b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw +Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc +dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA== +=nts1 +-----END PGP SIGNATURE----- +""" + +test_sig2 = b"""-----BEGIN PGP MESSAGE----- + +owGbwMvMwCSoW1RzPCOz3IRxjXQSR0lqcYleSUWJTZOvjVdpcYmCu1+oQmaJIleH +GwuDIBMDGysTSIqBi1MApi+nlGGuwDeHao53HBr+FoVGP3xX+kvuu9fCMJvl6IOf +y1kvP4y+8D5a11ang0udywsA +=Crq6 +-----END PGP MESSAGE----- +""" + +# A message with a prepended but unsigned plaintext packet. +double_plaintext_sig = b"""-----BEGIN PGP MESSAGE----- + +rDRiCmZvb2Jhci50eHRF4pxNVGhpcyBpcyBteSBzbmVha3kgcGxhaW50ZXh0IG1l +c3NhZ2UKowGbwMvMwCSoW1RzPCOz3IRxTWISa6JebnG666MFD1wzSzJSixQ81XMV +UlITUxTyixRyKxXKE0uSMxQyEosVikvyCwpSU/S4FNCArq6Ce1F+aXJGvoJvYlGF +erFCTmJxiUJ5flFKMVeHGwuDIBMDGysTyA4GLk4BmO036xgWzMgzt9V85jCtfDFn +UqVooWlGXHwNw/xg/fVzt9VNbtjtJ/fhUqYo0/LyCGEA +=6+AK +-----END PGP MESSAGE----- +""" + +def check_result(result, summary, validity, fpr, status, notation): + assert len(result.signatures) == 1, "Unexpected number of signatures" + sig = result.signatures[0] + assert sig.summary == summary, \ + "Unexpected signature summary: {}, want: {}".format(sig.summary, + summary) + assert sig.fpr == fpr + assert errors.GPGMEError(sig.status).getcode() == status + + if notation: + expected_notations = { + "bar": (b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f" + + b" das waren Umlaute und jetzt ein prozent%-Zeichen" + if sys.version_info[0] < 3 else + b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f".decode() + + " das waren Umlaute und jetzt ein prozent%-Zeichen"), + "foobar.1": "this is a notation data with 2 lines", + None: "http://www.gu.org/policy/", + } + assert len(sig.notations) == len(expected_notations) + + for r in sig.notations: + assert not 'name_len' in dir(r) + assert not 'value_len' in dir(r) + assert r.name in expected_notations + assert r.value == expected_notations[r.name], \ + "Expected {!r}, got {!r}".format(expected_notations[r.name], + r.value) + expected_notations.pop(r.name) + + assert len(expected_notations) == 0 + + assert not sig.wrong_key_usage + assert sig.validity == validity, \ + "Unexpected signature validity: {}, want: {}".format( + sig.validity, validity) + assert errors.GPGMEError(sig.validity_reason).getcode() == errors.NO_ERROR + + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_armor(True) + +# Checking a valid message. +text = core.Data(test_text1) +sig = core.Data(test_sig1) +c.op_verify(sig, text, None) +result = c.op_verify_result() +check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN, + constants.VALIDITY_FULL, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", + errors.NO_ERROR, True) + + +# Checking a manipulated message. +text = core.Data(test_text1f) +sig.seek(0, os.SEEK_SET) +c.op_verify(sig, text, None) +result = c.op_verify_result() +check_result(result, constants.SIGSUM_RED, constants.VALIDITY_UNKNOWN, + "2D727CC768697734", errors.BAD_SIGNATURE, False) + +# Checking a normal signature. +text = core.Data() +sig = core.Data(test_sig2) +c.op_verify(sig, None, text) +result = c.op_verify_result() +check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN, + constants.VALIDITY_FULL, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", + errors.NO_ERROR, False) + +# Checking an invalid message. +text = core.Data() +sig = core.Data(double_plaintext_sig) +try: + c.op_verify(sig, None, text) +except Exception as e: + assert type(e) == errors.GPGMEError + assert e.getcode() == errors.BAD_DATA +else: + assert False, "Expected an error but got none." + + +# Idiomatic interface. +with pyme.Context(armor=True) as c: + # Checking a valid message. + _, result = c.verify(test_text1, test_sig1) + check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN, + constants.VALIDITY_FULL, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", + errors.NO_ERROR, True) + + # Checking a manipulated message. + try: + c.verify(test_text1f, test_sig1) + except errors.BadSignatures as e: + check_result(e.result, constants.SIGSUM_RED, + constants.VALIDITY_UNKNOWN, + "2D727CC768697734", errors.BAD_SIGNATURE, False) + else: + assert False, "Expected an error but got none." + + # Checking a normal signature. + sig = core.Data(test_sig2) + data, result = c.verify(test_sig2) + check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN, + constants.VALIDITY_FULL, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", + errors.NO_ERROR, False) + assert data == test_text1 + + # Checking an invalid message. + try: + c.verify(double_plaintext_sig) + except errors.GPGMEError as e: + assert e.getcode() == errors.BAD_DATA + else: + assert False, "Expected an error but got none." + + alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) + bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) + + # Checking a valid message. + c.verify(test_text1, test_sig1, verify=[alpha]) + + try: + c.verify(test_text1, test_sig1, verify=[alpha, bob]) + except errors.MissingSignatures as e: + assert len(e.missing) == 1 + assert e.missing[0] == bob + else: + assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-wait.py b/lang/python/tests/t-wait.py new file mode 100755 index 0000000..b7d9a34 --- /dev/null +++ b/lang/python/tests/t-wait.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import time +from pyme import core, constants, errors +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() +c.set_armor(True) + +# Checking a message without a signature. +sig = core.Data("foo\n") +text = core.Data() +c.op_verify_start(sig, None, text) + +try: + while True: + err = c.wait(False) + if err: + break + time.sleep(0.1) +except Exception as e: + assert e.getcode() == errors.NO_DATA +else: + assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-wrapper.py b/lang/python/tests/t-wrapper.py new file mode 100755 index 0000000..d260264 --- /dev/null +++ b/lang/python/tests/t-wrapper.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +from pyme import core + +d0 = core.Data() +d0.seek # trigger on-demand-wrapping +assert d0.seek == d0.seek, "Generated wrapper functions are not cached" +assert hasattr(core.Data, 'seek'), "Generated wrapper functions are not shared" |