diff options
Diffstat (limited to 'lang/cpp')
-rw-r--r-- | lang/cpp/Makefile.in | 4 | ||||
-rw-r--r-- | lang/cpp/src/GpgmeppConfig.cmake.in.in | 4 | ||||
-rw-r--r-- | lang/cpp/src/Makefile.am | 11 | ||||
-rw-r--r-- | lang/cpp/src/Makefile.in | 16 | ||||
-rw-r--r-- | lang/cpp/src/context.cpp | 70 | ||||
-rw-r--r-- | lang/cpp/src/context.h | 28 | ||||
-rw-r--r-- | lang/cpp/src/context_p.h | 1 | ||||
-rw-r--r-- | lang/cpp/src/data.cpp | 24 | ||||
-rw-r--r-- | lang/cpp/src/data.h | 5 | ||||
-rw-r--r-- | lang/cpp/src/editinteractor.cpp | 2 | ||||
-rw-r--r-- | lang/cpp/src/gpggencardkeyinteractor.cpp | 332 | ||||
-rw-r--r-- | lang/cpp/src/gpggencardkeyinteractor.h | 71 | ||||
-rw-r--r-- | lang/cpp/src/key.cpp | 59 | ||||
-rw-r--r-- | lang/cpp/src/key.h | 22 | ||||
-rw-r--r-- | lang/cpp/src/verificationresult.cpp | 3 |
15 files changed, 627 insertions, 25 deletions
diff --git a/lang/cpp/Makefile.in b/lang/cpp/Makefile.in index 30aef31..f49d1d0 100644 --- a/lang/cpp/Makefile.in +++ b/lang/cpp/Makefile.in @@ -110,8 +110,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.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 + $(top_srcdir)/m4/python.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 diff --git a/lang/cpp/src/GpgmeppConfig.cmake.in.in b/lang/cpp/src/GpgmeppConfig.cmake.in.in index 928d19f..7f42f31 100644 --- a/lang/cpp/src/GpgmeppConfig.cmake.in.in +++ b/lang/cpp/src/GpgmeppConfig.cmake.in.in @@ -63,8 +63,8 @@ add_library(Gpgmepp SHARED IMPORTED) set_target_properties(Gpgmepp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "@resolved_includedir@/gpgme++;@resolved_includedir@" - INTERFACE_LINK_LIBRARIES "pthread;@resolved_libdir@/libgpgme@libsuffix@;@LIBASSUAN_LIBS@" - IMPORTED_LOCATION "@resolved_libdir@/libgpgmepp.so" + INTERFACE_LINK_LIBRARIES "pthread;@resolved_libdir@/libgpgme.so;@LIBASSUAN_LIBS@" + IMPORTED_LOCATION "@resolved_libdir@/libgpgmepp@libsuffix@" ) if(CMAKE_VERSION VERSION_LESS 2.8.12) diff --git a/lang/cpp/src/Makefile.am b/lang/cpp/src/Makefile.am index 92ed784..4028b3d 100644 --- a/lang/cpp/src/Makefile.am +++ b/lang/cpp/src/Makefile.am @@ -31,7 +31,8 @@ main_sources = \ signingresult.cpp encryptionresult.cpp \ engineinfo.cpp gpgsetexpirytimeeditinteractor.cpp \ gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \ - gpgadduserideditinteractor.cpp defaultassuantransaction.cpp \ + gpgadduserideditinteractor.cpp gpggencardkeyinteractor.cpp \ + defaultassuantransaction.cpp \ scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \ vfsmountresult.cpp configuration.cpp tofuinfo.cpp swdbresult.cpp @@ -42,6 +43,7 @@ gpgmepp_headers = \ gpgadduserideditinteractor.h gpgagentgetinfoassuantransaction.h \ gpgmefw.h gpgsetexpirytimeeditinteractor.h \ gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \ + gpggencardkeyinteractor.h \ importresult.h keygenerationresult.h key.h keylistresult.h \ notation.h result.h scdgetinfoassuantransaction.h signingresult.h \ trustitem.h verificationresult.h vfsmountresult.h gpgmepp_export.h \ @@ -69,6 +71,12 @@ 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' < "$<" | \ @@ -77,6 +85,7 @@ GpgmeppConfig.cmake: GpgmeppConfig-w32.cmake.in 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 diff --git a/lang/cpp/src/Makefile.in b/lang/cpp/src/Makefile.in index 45f6219..27bf982 100644 --- a/lang/cpp/src/Makefile.in +++ b/lang/cpp/src/Makefile.in @@ -117,8 +117,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.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 + $(top_srcdir)/m4/python.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 @@ -166,8 +166,8 @@ am__objects_1 = exception.lo context.lo key.lo trustitem.lo data.lo \ encryptionresult.lo engineinfo.lo \ gpgsetexpirytimeeditinteractor.lo \ gpgsetownertrusteditinteractor.lo gpgsignkeyeditinteractor.lo \ - gpgadduserideditinteractor.lo defaultassuantransaction.lo \ - scdgetinfoassuantransaction.lo \ + gpgadduserideditinteractor.lo gpggencardkeyinteractor.lo \ + defaultassuantransaction.lo scdgetinfoassuantransaction.lo \ gpgagentgetinfoassuantransaction.lo vfsmountresult.lo \ configuration.lo tofuinfo.lo swdbresult.lo am__objects_2 = @@ -470,7 +470,8 @@ main_sources = \ signingresult.cpp encryptionresult.cpp \ engineinfo.cpp gpgsetexpirytimeeditinteractor.cpp \ gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \ - gpgadduserideditinteractor.cpp defaultassuantransaction.cpp \ + gpgadduserideditinteractor.cpp gpggencardkeyinteractor.cpp \ + defaultassuantransaction.cpp \ scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \ vfsmountresult.cpp configuration.cpp tofuinfo.cpp swdbresult.cpp @@ -481,6 +482,7 @@ gpgmepp_headers = \ gpgadduserideditinteractor.h gpgagentgetinfoassuantransaction.h \ gpgmefw.h gpgsetexpirytimeeditinteractor.h \ gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \ + gpggencardkeyinteractor.h \ importresult.h keygenerationresult.h key.h keylistresult.h \ notation.h result.h scdgetinfoassuantransaction.h signingresult.h \ trustitem.h verificationresult.h vfsmountresult.h gpgmepp_export.h \ @@ -507,6 +509,8 @@ libgpgmepp_la_LIBADD = ../../../src/libgpgme.la @LIBASSUAN_LIBS@ libgpgmepp_la_LDFLAGS = -no-undefined -version-info \ @LIBGPGMEPP_LT_CURRENT@:@LIBGPGMEPP_LT_REVISION@:@LIBGPGMEPP_LT_AGE@ +@HAVE_MACOS_SYSTEM_FALSE@libsuffix = .so +@HAVE_MACOS_SYSTEM_TRUE@libsuffix = .dylib CLEANFILES = GpgmeppConfig.cmake GpgmeppConfigVersion.cmake \ gpgmepp_version.h GpgmeppConfig.cmake.in @@ -611,6 +615,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgadduserideditinteractor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgagentgetinfoassuantransaction.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpggencardkeyinteractor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgsetexpirytimeeditinteractor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgsetownertrusteditinteractor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgsignkeyeditinteractor.Plo@am__quote@ @@ -943,6 +948,7 @@ uninstall-am: uninstall-gpgmeppincludeHEADERS uninstall-libLTLIBRARIES \ @HAVE_W32_SYSTEM_TRUE@ sed -e 's|[@]resolved_includedir@|$(includedir)|g' > $@ @HAVE_W32_SYSTEM_FALSE@GpgmeppConfig.cmake: GpgmeppConfig.cmake.in @HAVE_W32_SYSTEM_FALSE@ sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" | \ +@HAVE_W32_SYSTEM_FALSE@ sed -e 's|[@]libsuffix@|$(libsuffix)|g' | \ @HAVE_W32_SYSTEM_FALSE@ sed -e 's|[@]resolved_includedir@|$(includedir)|g' > $@ install-cmake-files: GpgmeppConfig.cmake GpgmeppConfigVersion.cmake -$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp diff --git a/lang/cpp/src/context.cpp b/lang/cpp/src/context.cpp index ada7bea..77962d8 100644 --- a/lang/cpp/src/context.cpp +++ b/lang/cpp/src/context.cpp @@ -280,6 +280,11 @@ std::unique_ptr<Context> Context::createForEngine(Engine eng, Error *error) return std::unique_ptr<Context>(new Context(ctx)); } +void Context::setDecryptionFlags(DecryptionFlags flags) +{ + d->decryptFlags = flags; +} + // // // Context::Private @@ -294,7 +299,8 @@ Context::Private::Private(gpgme_ctx_t c) lastAssuanInquireData(Data::null), lastAssuanTransaction(), lastEditInteractor(), - lastCardEditInteractor() + lastCardEditInteractor(), + decryptFlags(DecryptNone) { } @@ -904,21 +910,32 @@ std::unique_ptr<AssuanTransaction> Context::takeLastAssuanTransaction() return std::move(d->lastAssuanTransaction); } -DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText) +DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText, const DecryptionFlags flags) { d->lastop = Private::Decrypt; const Data::Private *const cdp = cipherText.impl(); Data::Private *const pdp = plainText.impl(); - d->lasterr = gpgme_op_decrypt(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0); + d->lasterr = gpgme_op_decrypt_ext(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags), cdp ? cdp->data : 0, pdp ? pdp->data : 0); return DecryptionResult(d->ctx, Error(d->lasterr)); } -Error Context::startDecryption(const Data &cipherText, Data &plainText) +DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText) +{ + return decrypt(cipherText, plainText, DecryptNone); +} + +Error Context::startDecryption(const Data &cipherText, Data &plainText, const DecryptionFlags flags) { d->lastop = Private::Decrypt; const Data::Private *const cdp = cipherText.impl(); Data::Private *const pdp = plainText.impl(); - return Error(d->lasterr = gpgme_op_decrypt_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0)); + return Error(d->lasterr = gpgme_op_decrypt_ext_start(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags), + cdp ? cdp->data : 0, pdp ? pdp->data : 0)); +} + +Error Context::startDecryption(const Data &cipherText, Data &plainText) +{ + return startDecryption(cipherText, plainText, DecryptNone); } DecryptionResult Context::decryptionResult() const @@ -973,22 +990,33 @@ VerificationResult Context::verificationResult() const } } -std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText) +std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText, DecryptionFlags flags) { d->lastop = Private::DecryptAndVerify; const Data::Private *const cdp = cipherText.impl(); Data::Private *const pdp = plainText.impl(); - d->lasterr = gpgme_op_decrypt_verify(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0); + d->lasterr = gpgme_op_decrypt_ext(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags | DecryptVerify), + cdp ? cdp->data : 0, pdp ? pdp->data : 0); return std::make_pair(DecryptionResult(d->ctx, Error(d->lasterr)), VerificationResult(d->ctx, Error(d->lasterr))); } -Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText) +std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText) +{ + return decryptAndVerify(cipherText, plainText, DecryptNone); +} + +Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText, DecryptionFlags flags) { d->lastop = Private::DecryptAndVerify; const Data::Private *const cdp = cipherText.impl(); Data::Private *const pdp = plainText.impl(); - return Error(d->lasterr = gpgme_op_decrypt_verify_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0)); + return Error(d->lasterr = gpgme_op_decrypt_ext_start(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags | DecryptVerify), cdp ? cdp->data : 0, pdp ? pdp->data : 0)); +} + +Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText) +{ + return startCombinedDecryptionAndVerification(cipherText, plainText, DecryptNone); } unsigned int to_auditlog_flags(unsigned int flags) @@ -1376,6 +1404,30 @@ Error Context::setTofuPolicyStart(const Key &k, unsigned int policy) k.impl(), to_tofu_policy_t(policy))); } +Error Context::addUid(const Key &k, const char *userid) +{ + return Error(d->lasterr = gpgme_op_adduid(d->ctx, + k.impl(), userid, 0)); +} + +Error Context::startAddUid(const Key &k, const char *userid) +{ + return Error(d->lasterr = gpgme_op_adduid_start(d->ctx, + k.impl(), userid, 0)); +} + +Error Context::revUid(const Key &k, const char *userid) +{ + return Error(d->lasterr = gpgme_op_revuid(d->ctx, + k.impl(), userid, 0)); +} + +Error Context::startRevUid(const Key &k, const char *userid) +{ + return Error(d->lasterr = gpgme_op_revuid_start(d->ctx, + k.impl(), userid, 0)); +} + // Engine Spawn stuff Error Context::spawn(const char *file, const char *argv[], Data &input, Data &output, Data &err, diff --git a/lang/cpp/src/context.h b/lang/cpp/src/context.h index 2c205b0..bec4e39 100644 --- a/lang/cpp/src/context.h +++ b/lang/cpp/src/context.h @@ -214,6 +214,12 @@ public: GpgME::Error edit(const Key &key, std::unique_ptr<EditInteractor> function, Data &out); GpgME::Error startEditing(const Key &key, std::unique_ptr<EditInteractor> function, Data &out); + Error addUid(const Key &key, const char *userid); + Error startAddUid(const Key &key, const char *userid); + + Error revUid(const Key &key, const char *userid); + Error startRevUid(const Key &key, const char *userid); + // using TofuInfo::Policy Error setTofuPolicy(const Key &k, unsigned int policy); Error setTofuPolicyStart(const Key &k, unsigned int policy); @@ -255,14 +261,28 @@ public: // // Crypto Operations // - // + + enum DecryptionFlags { + // Keep in line with core's flags + DecryptNone = 0, + DecryptVerify = 1, + DecryptUnwrap = 128, + DecryptMaxValue = 0x80000000 + }; // // Decryption // + // Alternative way to set decryption flags as they were added only in + // 1.9.0 and so other API can still be used but with 1.9.0 additionally + // flags can be set. + void setDecryptionFlags (const DecryptionFlags flags); + DecryptionResult decrypt(const Data &cipherText, Data &plainText); GpgME::Error startDecryption(const Data &cipherText, Data &plainText); + DecryptionResult decrypt(const Data &cipherText, Data &plainText, const DecryptionFlags flags); + GpgME::Error startDecryption(const Data &cipherText, Data &plainText, const DecryptionFlags flags); DecryptionResult decryptionResult() const; // @@ -280,7 +300,9 @@ public: // std::pair<DecryptionResult, VerificationResult> decryptAndVerify(const Data &cipherText, Data &plainText); + std::pair<DecryptionResult, VerificationResult> decryptAndVerify(const Data &cipherText, Data &plainText, const DecryptionFlags flags); GpgME::Error startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText); + GpgME::Error startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText, const DecryptionFlags flags); // use verificationResult() and decryptionResult() to retrieve the result objects... // @@ -319,7 +341,9 @@ public: Prepare = 4, ExpectSign = 8, NoCompress = 16, - Symmetric = 32 + Symmetric = 32, + ThrowKeyIds = 64, + EncryptWrap = 128 }; EncryptionResult encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags); GpgME::Error encryptSymmetrically(const Data &plainText, Data &cipherText); diff --git a/lang/cpp/src/context_p.h b/lang/cpp/src/context_p.h index be34783..d53da0a 100644 --- a/lang/cpp/src/context_p.h +++ b/lang/cpp/src/context_p.h @@ -77,6 +77,7 @@ public: Data lastAssuanInquireData; std::unique_ptr<AssuanTransaction> lastAssuanTransaction; std::unique_ptr<EditInteractor> lastEditInteractor, lastCardEditInteractor; + DecryptionFlags decryptFlags; }; } // namespace GpgME diff --git a/lang/cpp/src/data.cpp b/lang/cpp/src/data.cpp index 2cb4fa8..32ca561 100644 --- a/lang/cpp/src/data.cpp +++ b/lang/cpp/src/data.cpp @@ -25,6 +25,7 @@ #endif #include "data_p.h" +#include "context_p.h" #include <error.h> #include <interfaces/dataprovider.h> @@ -230,3 +231,26 @@ off_t GpgME::Data::seek(off_t offset, int whence) { return gpgme_data_seek(d->data, offset, whence); } + +std::vector<GpgME::Key> GpgME::Data::toKeys(Protocol proto) const +{ + std::vector<GpgME::Key> ret; + if (isNull()) { + return ret; + } + auto ctx = GpgME::Context::createForProtocol(proto); + if (!ctx) { + return ret; + } + + if (gpgme_op_keylist_from_data_start (ctx->impl()->ctx, d->data, 0)) { + return ret; + } + + gpgme_key_t key; + while (!gpgme_op_keylist_next (ctx->impl()->ctx, &key)) { + ret.push_back(GpgME::Key(key, false)); + } + delete ctx; + return ret; +} diff --git a/lang/cpp/src/data.h b/lang/cpp/src/data.h index 50bdf62..cc7906f 100644 --- a/lang/cpp/src/data.h +++ b/lang/cpp/src/data.h @@ -24,6 +24,7 @@ #define __GPGMEPP_DATA_H__ #include "global.h" +#include "key.h" #include <sys/types.h> // for size_t, off_t #include <cstdio> // FILE @@ -109,6 +110,10 @@ public: ssize_t write(const void *buffer, size_t length); off_t seek(off_t offset, int whence); + /** Try to parse the data to a key object using the + * Protocol proto. Returns an empty list on error.*/ + std::vector<Key> toKeys(const Protocol proto = Protocol::OpenPGP) const; + class Private; Private *impl() { diff --git a/lang/cpp/src/editinteractor.cpp b/lang/cpp/src/editinteractor.cpp index 31591fa..b652bda 100644 --- a/lang/cpp/src/editinteractor.cpp +++ b/lang/cpp/src/editinteractor.cpp @@ -212,6 +212,8 @@ bool EditInteractor::needsNoResponse(unsigned int status) const case GPGME_STATUS_KEY_CREATED: case GPGME_STATUS_NEED_PASSPHRASE_SYM: case GPGME_STATUS_SC_OP_FAILURE: + case GPGME_STATUS_CARDCTRL: + case GPGME_STATUS_BACKUP_KEY_CREATED: return false; default: return true; diff --git a/lang/cpp/src/gpggencardkeyinteractor.cpp b/lang/cpp/src/gpggencardkeyinteractor.cpp new file mode 100644 index 0000000..90329e2 --- /dev/null +++ b/lang/cpp/src/gpggencardkeyinteractor.cpp @@ -0,0 +1,332 @@ +/* + gpggencardkeyinteractor.cpp - Edit Interactor to generate a key on a card + Copyright (C) 2017 Intevation 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 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 "gpggencardkeyinteractor.h" + +#include "error.h" + +#include <gpgme.h> + +using namespace GpgME; + +class GpgGenCardKeyInteractor::Private +{ +public: + Private() : keysize(2048), backup(false) + { + + } + std::string name, email, backupFileName, expiry, serial; + int keysize; + bool backup; +}; + +GpgGenCardKeyInteractor::~GpgGenCardKeyInteractor() {} + +GpgGenCardKeyInteractor::GpgGenCardKeyInteractor(const std::string &serial): + d(new Private) +{ + d->serial = serial; +} + +void GpgGenCardKeyInteractor::setNameUtf8(const std::string &name) +{ + d->name = name; +} + +void GpgGenCardKeyInteractor::setEmailUtf8(const std::string &email) +{ + d->email = email; +} + +void GpgGenCardKeyInteractor::setDoBackup(bool value) +{ + d->backup = value; +} + +void GpgGenCardKeyInteractor::setKeySize(int value) +{ + d->keysize = value; +} + +void GpgGenCardKeyInteractor::setExpiry(const std::string &timeStr) +{ + d->expiry = timeStr; +} + +std::string GpgGenCardKeyInteractor::backupFileName() const +{ + return d->backupFileName; +} + +namespace GpgGenCardKeyInteractor_Private +{ +enum { + START = EditInteractor::StartState, + DO_ADMIN, + EXPIRE, + + GOT_SERIAL, + COMMAND, + NAME, + EMAIL, + COMMENT, + BACKUP, + REPLACE, + SIZE, + SIZE2, + SIZE3, + BACKUP_KEY_CREATED, + KEY_CREATED, + QUIT, + SAVE, + + ERROR = EditInteractor::ErrorState +}; +} + +const char *GpgGenCardKeyInteractor::action(Error &err) const +{ + + using namespace GpgGenCardKeyInteractor_Private; + + switch (state()) { + case DO_ADMIN: + return "admin"; + case COMMAND: + return "generate"; + case NAME: + return d->name.c_str(); + case EMAIL: + return d->email.c_str(); + case EXPIRE: + return d->expiry.c_str(); + case BACKUP: + return d->backup ? "Y" : "N"; + case REPLACE: + return "Y"; + case SIZE: + case SIZE2: + case SIZE3: + return std::to_string(d->keysize).c_str(); + case COMMENT: + return ""; + case SAVE: + return "Y"; + case QUIT: + return "quit"; + case KEY_CREATED: + case START: + case GOT_SERIAL: + case BACKUP_KEY_CREATED: + case ERROR: + return 0; + default: + err = Error::fromCode(GPG_ERR_GENERAL); + return 0; + } +} + +unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char *args, Error &err) const +{ + + static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL); + static const Error INV_NAME_ERROR = Error::fromCode(GPG_ERR_INV_NAME); + static const Error INV_EMAIL_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID); + static const Error INV_COMMENT_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID); + + if (needsNoResponse(status)) { + return state(); + } + + using namespace GpgGenCardKeyInteractor_Private; + + switch (state()) { + case START: + if (status == GPGME_STATUS_CARDCTRL && + !d->serial.empty()) { + const std::string sArgs = args; + if (sArgs.find(d->serial) == std::string::npos) { + // Wrong smartcard + err = Error::fromCode(GPG_ERR_WRONG_CARD); + return ERROR; + } else { + printf("EditInteractor: Confirmed S/N: %s %s\n", + d->serial.c_str(), sArgs.c_str()); + } + return GOT_SERIAL; + } else if (d->serial.empty()) { + return GOT_SERIAL; + } + err = GENERAL_ERROR; + return ERROR; + case GOT_SERIAL: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.prompt") == 0) { + return DO_ADMIN; + } + err = GENERAL_ERROR; + return ERROR; + case DO_ADMIN: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.prompt") == 0) { + return COMMAND; + } + err = GENERAL_ERROR; + return ERROR; + case COMMAND: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.genkeys.backup_enc") == 0) { + return BACKUP; + } + err = GENERAL_ERROR; + return ERROR; + case BACKUP: + if (status == GPGME_STATUS_GET_BOOL && + strcmp(args, "cardedit.genkeys.replace_keys") == 0) { + return REPLACE; + } + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.genkeys.size") == 0) { + return SIZE; + } + err = GENERAL_ERROR; + return ERROR; + case REPLACE: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.genkeys.size") == 0) { + printf("Moving to SIZE\n"); + return SIZE; + } + err = GENERAL_ERROR; + return ERROR; + case SIZE: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.genkeys.size") == 0) { + return SIZE2; + } + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.valid") == 0) { + return EXPIRE; + } + err = GENERAL_ERROR; + return ERROR; + case SIZE2: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.genkeys.size") == 0) { + return SIZE3; + } + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.valid") == 0) { + return EXPIRE; + } + err = GENERAL_ERROR; + return ERROR; + case SIZE3: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.valid") == 0) { + return EXPIRE; + } + err = GENERAL_ERROR; + return ERROR; + case EXPIRE: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.name") == 0) { + return NAME; + } + err = GENERAL_ERROR; + return ERROR; + case NAME: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.email") == 0) { + return EMAIL; + } + err = GENERAL_ERROR; + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.name") == 0) { + err = INV_NAME_ERROR; + } + return ERROR; + case EMAIL: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.comment") == 0) { + return COMMENT; + } + err = GENERAL_ERROR; + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.email") == 0) { + err = INV_EMAIL_ERROR; + } + return ERROR; + case COMMENT: + if (status == GPGME_STATUS_BACKUP_KEY_CREATED) { + std::string sArgs = args; + const auto pos = sArgs.rfind(" "); + if (pos != std::string::npos) { + d->backupFileName = sArgs.substr(pos + 1); + return BACKUP_KEY_CREATED; + } + } + if (status == GPGME_STATUS_KEY_CREATED) { + return KEY_CREATED; + } + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keyedit.prompt") == 0) { + return QUIT; + } + err = GENERAL_ERROR; + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keygen.comment") == 0) { + err = INV_COMMENT_ERROR; + } + return ERROR; + case BACKUP_KEY_CREATED: + if (status == GPGME_STATUS_KEY_CREATED) { + return KEY_CREATED; + } + err = GENERAL_ERROR; + return ERROR; + case KEY_CREATED: + return QUIT; + case QUIT: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "cardedit.prompt") == 0) { + return QUIT; + } + err = GENERAL_ERROR; + return ERROR; + case ERROR: + if (status == GPGME_STATUS_GET_LINE && + strcmp(args, "keyedit.prompt") == 0) { + return QUIT; + } + err = lastError(); + return ERROR; + default: + err = GENERAL_ERROR; + return ERROR; + } +} diff --git a/lang/cpp/src/gpggencardkeyinteractor.h b/lang/cpp/src/gpggencardkeyinteractor.h new file mode 100644 index 0000000..c6b17d1 --- /dev/null +++ b/lang/cpp/src/gpggencardkeyinteractor.h @@ -0,0 +1,71 @@ +/* + gpggencardkeyinteractor.h - Edit Interactor to generate a key on a card + Copyright (C) 2017 Intevation 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 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. +*/ + +#ifndef __GPGMEPP_GPGGENCARDKEYEDITINTERACTOR_H__ +#define __GPGMEPP_GPGGENCARDKEYEDITINTERACTOR_H__ + +#include <editinteractor.h> + +#include <string> +#include <memory> + +namespace GpgME +{ + +class GPGMEPP_EXPORT GpgGenCardKeyInteractor: public EditInteractor +{ +public: + /** Edit interactor to generate a key on a smartcard. + * + * The \a serialnumber argument is intended to safeguard + * against accidentally working on the wrong smartcard. + * + * The edit interactor will fail if the card did not match. + * + * @param serialnumber: Serialnumber of the intended card. + **/ + explicit GpgGenCardKeyInteractor(const std::string &serialnumber); + ~GpgGenCardKeyInteractor(); + + /** Set the key sizes for the subkeys (default 2048) */ + void setKeySize(int size); + + void setNameUtf8(const std::string &name); + void setEmailUtf8(const std::string &email); + + void setDoBackup(bool value); + void setExpiry(const std::string &timeString); + + std::string backupFileName() const; + +private: + /* reimp */ const char *action(Error &err) const; + /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const; + +private: + class Private; + std::shared_ptr<Private> d; +}; + +} // namespace GpgME + +#endif // __GPGMEPP_GPGGENCARDKEYEDITINTERACTOR_H__ diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp index 235a3c8..31e59e1 100644 --- a/lang/cpp/src/key.cpp +++ b/lang/cpp/src/key.cpp @@ -234,6 +234,11 @@ bool Key::isQualified() const return key && key->is_qualified; } +bool Key::isDeVs() const +{ + return key && key->subkeys && key->subkeys->is_de_vs; +} + const char *Key::issuerSerial() const { return key ? key->issuer_serial : 0 ; @@ -341,7 +346,12 @@ void Key::update() KeyListMode::Validate | KeyListMode::WithTofu); Error err; - auto newKey = ctx->key(primaryFingerprint(), err, hasSecret()); + auto newKey = ctx->key(primaryFingerprint(), err, true); + // Not secret so we get the information from the pubring. + if (newKey.isNull()) + { + newKey = ctx->key(primaryFingerprint(), err, false); + } delete ctx; if (err) { return; @@ -464,6 +474,11 @@ bool Subkey::isQualified() const return subkey && subkey->is_qualified; } +bool Subkey::isDeVs() const +{ + return subkey && subkey->is_de_vs; +} + bool Subkey::isCardKey() const { return subkey && subkey->is_cardkey; @@ -471,7 +486,12 @@ bool Subkey::isCardKey() const const char *Subkey::cardSerialNumber() const { - return subkey ? subkey->card_number : 0 ; + return subkey ? subkey->card_number : nullptr; +} + +const char *Subkey::keyGrip() const +{ + return subkey ? subkey->keygrip : nullptr; } bool Subkey::isSecret() const @@ -894,7 +914,39 @@ std::string UserID::addrSpecFromString(const char *userid) std::string UserID::addrSpec() const { - return addrSpecFromString(email()); + if (!uid || !uid->address) { + return std::string(); + } + + return uid->address; +} + +Error UserID::revoke() +{ + if (isNull()) { + return Error::fromCode(GPG_ERR_GENERAL); + } + auto ctx = Context::createForProtocol(parent().protocol()); + if (!ctx) { + return Error::fromCode(GPG_ERR_INV_ENGINE); + } + Error ret = ctx->revUid(key, id()); + delete ctx; + return ret; +} + +Error Key::addUid(const char *uid) +{ + if (isNull()) { + return Error::fromCode(GPG_ERR_GENERAL); + } + auto ctx = Context::createForProtocol(protocol()); + if (!ctx) { + return Error::fromCode(GPG_ERR_INV_ENGINE); + } + Error ret = ctx->addUid(key, uid); + delete ctx; + return ret; } std::ostream &operator<<(std::ostream &os, const UserID &uid) @@ -903,6 +955,7 @@ std::ostream &operator<<(std::ostream &os, const UserID &uid) if (!uid.isNull()) { os << "\n name: " << protect(uid.name()) << "\n email: " << protect(uid.email()) + << "\n mbox: " << uid.addrSpec() << "\n comment: " << protect(uid.comment()) << "\n validity: " << uid.validityAsString() << "\n revoked: " << uid.isRevoked() diff --git a/lang/cpp/src/key.h b/lang/cpp/src/key.h index 3f596a8..829bd26 100644 --- a/lang/cpp/src/key.h +++ b/lang/cpp/src/key.h @@ -112,6 +112,7 @@ public: bool canCertify() const; bool canAuthenticate() const; bool isQualified() const; + bool isDeVs() const; bool hasSecret() const; GPGMEPP_DEPRECATED bool isSecret() const @@ -152,6 +153,17 @@ public: * how long the keylisting takes.*/ void update(); + /** + * @brief Add a user id to this key. + * + * Needs gnupg 2.1.13 and the key needs to be updated + * afterwards to see the new uid. + * + * @param uid should be fully formated and UTF-8 encoded. + * + * @returns a possible error. + **/ + Error addUid(const char *uid); private: gpgme_key_t impl() const { @@ -208,6 +220,7 @@ public: bool canCertify() const; bool canAuthenticate() const; bool isQualified() const; + bool isDeVs() const; bool isCardKey() const; bool isSecret() const; @@ -259,6 +272,8 @@ public: const char *cardSerialNumber() const; + const char *keyGrip() const; + private: shared_gpgme_key_t key; gpgme_sub_key_t subkey; @@ -335,6 +350,13 @@ public: * @returns a normalized mail address for this userid * or an empty string. */ std::string addrSpec() const; + + /*! Revoke the user id. + * + * Key needs update afterwards. + * + * @returns an error on error.*/ + Error revoke(); private: shared_gpgme_key_t key; gpgme_user_id_t uid; diff --git a/lang/cpp/src/verificationresult.cpp b/lang/cpp/src/verificationresult.cpp index 23c458e..42e483c 100644 --- a/lang/cpp/src/verificationresult.cpp +++ b/lang/cpp/src/verificationresult.cpp @@ -413,7 +413,8 @@ GpgME::Key GpgME::Signature::key(bool search, bool update) const } } if (update) { - ret.update(); + d->keys[idx].update(); + ret = d->keys[idx]; } return ret; } |