diff --git a/src/Makefile.am b/src/Makefile.am
index 7af66325..ba8a7fb1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,115 +1,116 @@
 # Makefile.am for GPGMEPP.
 # Copyright (C) 2016 Bundesamt für Sicherheit in der Informationstechnik
 # Software engineering by Intevation GmbH
 #
 # This file is part of GPGMEPP.
 #
 # GPGME-CL 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-CL 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 General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 # 02111-1307, USA
 
 EXTRA_DIST = GpgmeppConfig.cmake.in.in GpgmeppConfigVersion.cmake.in \
              gpgmepp_version.h.in GpgmeppConfig-w32.cmake.in.in
 
 lib_LTLIBRARIES = libgpgmepp.la
 
 main_sources = \
     exception.cpp context.cpp key.cpp trustitem.cpp data.cpp callbacks.cpp \
     eventloopinteractor.cpp editinteractor.cpp \
     keylistresult.cpp keygenerationresult.cpp importresult.cpp \
     decryptionresult.cpp verificationresult.cpp \
     signingresult.cpp encryptionresult.cpp \
     engineinfo.cpp gpgsetexpirytimeeditinteractor.cpp \
     gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \
     gpgadduserideditinteractor.cpp gpggencardkeyinteractor.cpp \
     gpgaddexistingsubkeyeditinteractor.cpp \
     defaultassuantransaction.cpp \
     scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \
     statusconsumerassuantransaction.cpp \
-    vfsmountresult.cpp configuration.cpp tofuinfo.cpp swdbresult.cpp
+    vfsmountresult.cpp configuration.cpp tofuinfo.cpp swdbresult.cpp \
+    util.cpp
 
 gpgmepp_headers = \
     configuration.h context.h data.h decryptionresult.h \
     defaultassuantransaction.h editinteractor.h encryptionresult.h \
     engineinfo.h error.h eventloopinteractor.h exception.h global.h \
     gpgadduserideditinteractor.h gpgagentgetinfoassuantransaction.h \
     gpgmefw.h gpgsetexpirytimeeditinteractor.h \
     gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \
     gpggencardkeyinteractor.h \
     gpgaddexistingsubkeyeditinteractor.h \
     importresult.h keygenerationresult.h key.h keylistresult.h \
     notation.h result.h scdgetinfoassuantransaction.h signingresult.h \
     statusconsumerassuantransaction.h \
     trustitem.h verificationresult.h vfsmountresult.h gpgmepp_export.h \
     tofuinfo.h swdbresult.h
 
 private_gpgmepp_headers = \
     result_p.h context_p.h util.h callbacks.h data_p.h
 
 interface_headers= \
     interfaces/assuantransaction.h interfaces/dataprovider.h \
     interfaces/passphraseprovider.h interfaces/progressprovider.h \
     interfaces/statusconsumer.h
 
 gpgmeppincludedir = $(includedir)/gpgme++
 gpgmeppinclude_HEADERS = $(gpgmepp_headers)
 nobase_gpgmeppinclude_HEADERS = $(interface_headers)
 nodist_gpgmeppinclude_HEADERS = gpgmepp_version.h
 
 libgpgmepp_la_SOURCES = $(main_sources) $(gpgmepp_headers) context_vanilla.cpp \
                         $(interface_headers) $(private_gpgmepp_headers)
 
 AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \
               -DBUILDING_GPGMEPP -Wsuggest-override \
               -Wzero-as-null-pointer-constant
 
 libgpgmepp_la_LIBADD = ../../../src/libgpgme.la @LIBASSUAN_LIBS@
 libgpgmepp_la_LDFLAGS = -no-undefined -version-info \
     @LIBGPGMEPP_LT_CURRENT@:@LIBGPGMEPP_LT_REVISION@:@LIBGPGMEPP_LT_AGE@
 
 if HAVE_MACOS_SYSTEM
 libsuffix=.dylib
 else
 libsuffix=.so
 endif
 
 if HAVE_W32_SYSTEM
 GpgmeppConfig.cmake: GpgmeppConfig-w32.cmake.in
 	sed -e 's|[@]resolved_bindir@|$(bindir)|g' < "$<" | \
 	sed -e 's|[@]resolved_libdir@|$(libdir)|g' | \
 	sed -e 's|[@]resolved_includedir@|$(includedir)|g' > $@
 else
 GpgmeppConfig.cmake: GpgmeppConfig.cmake.in
 	sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" | \
 	sed -e 's|[@]libsuffix@|$(libsuffix)|g' | \
 	sed -e 's|[@]resolved_includedir@|$(includedir)|g' > $@
 endif
 install-cmake-files: GpgmeppConfig.cmake GpgmeppConfigVersion.cmake
 	-$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp
 	$(INSTALL) -m 644 GpgmeppConfig.cmake \
         $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake
 	$(INSTALL) -m 644 GpgmeppConfigVersion.cmake \
         $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake
 
 uninstall-cmake-files:
 	-rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake
 	-rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake
 	-rmdir $(DESTDIR)$(libdir)/cmake/Gpgmepp/
 
 install-data-local: install-cmake-files
 
 uninstall-local: uninstall-cmake-files
 
 CLEANFILES = GpgmeppConfig.cmake GpgmeppConfigVersion.cmake \
              gpgmepp_version.h GpgmeppConfig.cmake.in
diff --git a/src/util.cpp b/src/util.cpp
new file mode 100644
index 00000000..9104435f
--- /dev/null
+++ b/src/util.cpp
@@ -0,0 +1,47 @@
+/*
+  util.cpp - some internal helpers
+  Copyright (c) 2022 g10 Code GmbH
+  Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library 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 Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "util.h"
+
+#include <functional>
+
+StringsToCStrings::StringsToCStrings(const std::vector<std::string>& v)
+    : m_strings{v}
+{
+}
+
+const char **StringsToCStrings::c_strs() const
+{
+    if (m_cstrings.empty()) {
+        m_cstrings.reserve(m_strings.size() + 1);
+        std::transform(std::begin(m_strings), std::end(m_strings),
+                       std::back_inserter(m_cstrings),
+                       std::mem_fn(&std::string::c_str));
+        m_cstrings.push_back(nullptr);
+    }
+    return m_cstrings.data();
+}
diff --git a/src/util.h b/src/util.h
index e04115bf..b6f9ca50 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,178 +1,201 @@
 /*
-  util.h - some inline helper functions
+  util.h - some internal helpers
   Copyright (C) 2004 Klarälvdalens Datakonsult AB
   2016 Bundesamt für Sicherheit in der Informationstechnik
   Software engineering by Intevation GmbH
+  Copyright (c) 2022 g10 Code GmbH
+  Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
 
   This file is part of GPGME++.
 
   GPGME++ is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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 Library General Public License for more details.
 
   You should have received a copy of the GNU Library General Public License
   along with GPGME++; see the file COPYING.LIB.  If not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
 */
 
 // -*- c++ -*-
 #ifndef __GPGMEPP_UTIL_H__
 #define __GPGMEPP_UTIL_H__
 
 #include "global.h"
 #include "notation.h"
 
 #include <gpgme.h>
 
 #ifndef NDEBUG
 #include <iostream>
 #endif
 #include <sstream>
 #include <string>
 
 static inline const char *protect(const char *s)
 {
     return s ? s : "<null>" ;
 }
 
 static inline gpgme_error_t make_error(gpgme_err_code_t code)
 {
     return gpgme_err_make((gpgme_err_source_t)22, code);
 }
 
 static inline unsigned long to_pid(const std::string &s)
 {
     std::stringstream ss(s);
     unsigned int result;
     if (ss >> result) {
         return result;
     } else {
         return 0U;
     }
 }
 
 static inline gpgme_keylist_mode_t add_to_gpgme_keylist_mode_t(unsigned int oldmode, unsigned int newmodes)
 {
     if (newmodes & GpgME::Local) {
         oldmode |= GPGME_KEYLIST_MODE_LOCAL;
     }
     if (newmodes & GpgME::Extern) {
         oldmode |= GPGME_KEYLIST_MODE_EXTERN;
     }
     if (newmodes & GpgME::Signatures) {
         oldmode |= GPGME_KEYLIST_MODE_SIGS;
     }
     if (newmodes & GpgME::SignatureNotations) {
         oldmode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
     }
     if (newmodes & GpgME::Validate) {
         oldmode |= GPGME_KEYLIST_MODE_VALIDATE;
     }
     if (newmodes & GpgME::Ephemeral) {
         oldmode |= GPGME_KEYLIST_MODE_EPHEMERAL;
     }
     if (newmodes & GpgME::WithTofu) {
         oldmode |= GPGME_KEYLIST_MODE_WITH_TOFU;
     }
     if (newmodes & GpgME::WithKeygrip) {
         oldmode |= GPGME_KEYLIST_MODE_WITH_KEYGRIP;
     }
     if (newmodes & GpgME::WithSecret) {
         oldmode |= GPGME_KEYLIST_MODE_WITH_SECRET;
     }
 #ifndef NDEBUG
     if (newmodes & ~(GpgME::Local |
                      GpgME::Extern |
                      GpgME::Signatures |
                      GpgME::SignatureNotations |
                      GpgME::Validate |
                      GpgME::Ephemeral |
                      GpgME::WithTofu |
                      GpgME::WithKeygrip |
                      GpgME::WithSecret)) {
         //std::cerr << "GpgME::Context: keylist mode must be one of Local, "
         //"Extern, Signatures, SignatureNotations, Validate, Ephemeral, WithTofu, "
         //"WithKeygrip, WithSecret, or a combination thereof!" << std::endl;
     }
 #endif
     return static_cast<gpgme_keylist_mode_t>(oldmode);
 }
 
 static inline unsigned int convert_from_gpgme_keylist_mode_t(unsigned int mode)
 {
     unsigned int result = 0;
     if (mode & GPGME_KEYLIST_MODE_LOCAL) {
         result |= GpgME::Local;
     }
     if (mode & GPGME_KEYLIST_MODE_EXTERN) {
         result |= GpgME::Extern;
     }
     if (mode & GPGME_KEYLIST_MODE_SIGS) {
         result |= GpgME::Signatures;
     }
     if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) {
         result |= GpgME::SignatureNotations;
     }
     if (mode & GPGME_KEYLIST_MODE_WITH_SECRET) {
         result |= GpgME::WithSecret;
     }
     if (mode & GPGME_KEYLIST_MODE_WITH_TOFU) {
         result |= GpgME::WithTofu;
     }
     if (mode & GPGME_KEYLIST_MODE_WITH_KEYGRIP) {
         result |= GpgME::WithKeygrip;
     }
     if (mode & GPGME_KEYLIST_MODE_EPHEMERAL) {
         result |= GpgME::Ephemeral;
     }
     if (mode & GPGME_KEYLIST_MODE_VALIDATE) {
         result |= GpgME::Validate;
     }
 #ifndef NDEBUG
     if (mode & ~(GPGME_KEYLIST_MODE_LOCAL |
                  GPGME_KEYLIST_MODE_EXTERN |
                  GPGME_KEYLIST_MODE_SIGS |
                  GPGME_KEYLIST_MODE_SIG_NOTATIONS |
                  GPGME_KEYLIST_MODE_WITH_SECRET |
                  GPGME_KEYLIST_MODE_WITH_TOFU |
                  GPGME_KEYLIST_MODE_WITH_KEYGRIP |
                  GPGME_KEYLIST_MODE_EPHEMERAL |
                  GPGME_KEYLIST_MODE_VALIDATE)) {
         //std::cerr << "GpgME: WARNING: gpgme_get_keylist_mode() returned an unknown flag!" << std::endl;
     }
 #endif // NDEBUG
     return result;
 }
 
 static inline GpgME::Notation::Flags convert_from_gpgme_sig_notation_flags_t(unsigned int flags)
 {
     unsigned int result = 0;
     if (flags & GPGME_SIG_NOTATION_HUMAN_READABLE) {
         result |= GpgME::Notation::HumanReadable ;
     }
     if (flags & GPGME_SIG_NOTATION_CRITICAL) {
         result |= GpgME::Notation::Critical ;
     }
     return static_cast<GpgME::Notation::Flags>(result);
 }
 
 static inline gpgme_sig_notation_flags_t  add_to_gpgme_sig_notation_flags_t(unsigned int oldflags, unsigned int newflags)
 {
     unsigned int result = oldflags;
     if (newflags & GpgME::Notation::HumanReadable) {
         result |= GPGME_SIG_NOTATION_HUMAN_READABLE;
     }
     if (newflags & GpgME::Notation::Critical) {
         result |= GPGME_SIG_NOTATION_CRITICAL;
     }
     return static_cast<gpgme_sig_notation_flags_t>(result);
 }
 
+/**
+ * Adapter for passing a vector of strings as NULL-terminated array of
+ * const char* to the C-interface of gpgme.
+ */
+class StringsToCStrings
+{
+public:
+    explicit StringsToCStrings(const std::vector<std::string> &v);
+    ~StringsToCStrings() = default;
+
+    StringsToCStrings(const StringsToCStrings &) = delete;
+    StringsToCStrings &operator=(const StringsToCStrings &) = delete;
+    StringsToCStrings(StringsToCStrings &&) = delete;
+    StringsToCStrings &operator=(StringsToCStrings &&) = delete;
+
+    const char **c_strs() const;
+private:
+    const std::vector<std::string> m_strings;
+    mutable std::vector<const char *> m_cstrings;
+};
+
 #endif // __GPGMEPP_UTIL_H__