Allow to export private keys.

Using a workaround that validates passphrase for a secret key.

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.

See https://dev.gnupg.org/T5151

Application may validate a passphrase before invoking engine. Until it is
hopefully fixed in upstream and available in mainstream.
This commit is contained in:
SET
2020-11-24 22:15:46 +01:00
parent b761c366f7
commit b68bee813d
4 changed files with 62 additions and 6 deletions

View File

@@ -11,6 +11,7 @@
#include <gpgme++/keylistresult.h>
#include <gpgme++/importresult.h>
#include <gpgme++/keygenerationresult.h>
#include <gpgme++/signingresult.h>
#include <locale>
#include <iostream>
#include <gpgme++/data.h>
@@ -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)
{

View File

@@ -87,9 +87,9 @@ public:
* @return
*/
const Error RevokeKeyCertifications(const char * fprSigningKey,
const char * fprKeyToSign,
vector<GpgME::UserID>& userIDsToRevoke,
const string& passphrase);
const char * fprKeyToSign,
vector<GpgME::UserID>& 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

View File

@@ -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<ExportKeyStreamResource> shResource =
make_shared<ExportKeyStreamResource>
(fpr, true, "appliation/pgp-keys", m_tmwMessage);

View File

@@ -13,6 +13,8 @@
<gdb_interceptlist>
<gdbinterceptoptions gdb_all="false" gdb_unhandled="true" gdb_unexpected="true"/>
</gdb_interceptlist>
<gdb_signals>
</gdb_signals>
<gdb_options>
<DebugOptions>
</DebugOptions>