diff --git a/GpgMEWorker.cpp b/GpgMEWorker.cpp index fe3ff0f..fc5dccb 100644 --- a/GpgMEWorker.cpp +++ b/GpgMEWorker.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -346,6 +347,32 @@ const Error GpgMEWorker::CreateSubKey(GpgME::Key& k, return e; } +const Error GpgMEWorker::CheckPassphrase(const char* fpr, + const string& passphrase) +{ + Error e; + Context * ctx = Context::createForProtocol(Protocol::OpenPGP); + LoopbackPassphraseProvider * ppp = new LoopbackPassphraseProvider(passphrase); + ctx->setPinentryMode(Context::PinentryMode::PinentryLoopback); + ctx->setPassphraseProvider(ppp); + + Key k = FindKey(fpr, e, true); + if (e.code() != 0) + return e; + e = ctx->addSigningKey(k); + if (e.code() != 0) + return e; + Data plain("dummy"); + Data signature; + SigningResult result = ctx->sign(plain, signature, SignatureMode::Detached); + e = result.error(); + + delete ppp; + delete ctx; + + return e; +} + const Error GpgMEWorker::ExportPrivateKey(const char * pattern, string& buffer, const string& passphrase) { diff --git a/GpgMEWorker.h b/GpgMEWorker.h index bb9042f..f114ea8 100644 --- a/GpgMEWorker.h +++ b/GpgMEWorker.h @@ -87,9 +87,9 @@ public: * @return */ const Error RevokeKeyCertifications(const char * fprSigningKey, - const char * fprKeyToSign, - vector& userIDsToRevoke, - const string& passphrase); + const char * fprKeyToSign, + vector& userIDsToRevoke, + const string& passphrase); /** * Sets the expiry time of a single (sub)key. Requires GPGME >= 1.15.0. * \n If no subkey is found (wrong fpr) or not provided, the expiry time of @@ -101,9 +101,9 @@ public: * @return */ const Error SetKeyExpiryTime(const char * keyFpr, - const char * subkeyFpr, - const string& passphrase, - ulong expires = 63072000); + const char * subkeyFpr, + const string& passphrase, + ulong expires = 63072000); /** * Adds a user identity to a key. * \n The email parameter must have a valid email address format here, else @@ -181,6 +181,21 @@ public: const char * algo, const string& passphrase, ulong expires = 63072000); + /** + * Checks that passphrase can unlock secret key with fingerprint fpr. + * \n This is a workaround when exporting secret keys. + * \n To date, with GnuPG 2.2.23 and GpgME 1.1.15, a secret key can be + * exported when the right passphrase is provided. With a bad passphrase, + * application crashes. + * \n See https://dev.gnupg.org/T5151 + * \n Application may validate a passphrase before invoking engine. + * \n Until it is hopefully fixed in upstream and available in mainstream. + * @param fpr + * @param passphrase + * @return + */ + const Error CheckPassphrase(const char * fpr, + const string& passphrase); /** * Export a secret key. * @param pattern : a key fingerprint diff --git a/KeyringIO.cpp b/KeyringIO.cpp index 294e358..4d05b82 100644 --- a/KeyringIO.cpp +++ b/KeyringIO.cpp @@ -297,6 +297,18 @@ void KeyringIO::OnPreExportSecretKey(const WString& fpr) { // On preExport button of popup WLink link; + GpgMEWorker gpgw; + Error e = gpgw.CheckPassphrase(fpr.toUTF8().c_str(), + m_popupExportSecretKey->GetPassphrase()); + if (e.code() != 0) + { + m_tmwMessage->SetText(e.asString()); + m_popupExportSecretKey->GetApplyButton()->setLink(link); + m_popupExportSecretKey->GetApplyButton()->disable(); + LGE(e); + return; + } + shared_ptr shResource = make_shared (fpr, true, "appliation/pgp-keys", m_tmwMessage); diff --git a/nbproject/private/configurations.xml b/nbproject/private/configurations.xml index 2c9b830..1f82c50 100644 --- a/nbproject/private/configurations.xml +++ b/nbproject/private/configurations.xml @@ -13,6 +13,8 @@ + +