qca/plugins/qca-gnupg/mymessagecontext.cpp
Albert Astals Cid f62a8ee8f7 Run clang-format
find . \( -name "*.cpp" -or -name "*.h"  -or -name "*.c"  -or -name "*.cc" \) -exec clang-format -i {} \;

If you reached this file doing a git blame, please see README.clang-format (added 2 commits in the future of this one)
2020-09-07 02:13:47 +02:00

416 lines
11 KiB
C++

/*
* Copyright (C) 2003-2008 Justin Karneges <justin@affinix.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "mymessagecontext.h"
#include "mykeystorelist.h"
#include "mypgpkeycontext.h"
#include "utils.h"
using namespace QCA;
namespace gpgQCAPlugin {
MyMessageContext::MyMessageContext(MyOpenPGPContext *_sms, Provider *p)
: MessageContext(p, QStringLiteral("pgpmsg"))
, sms(_sms)
, op(Sign)
, signMode(SecureMessage::Detached)
, format(SecureMessage::Ascii)
, wrote(0)
, ok(false)
, wasSigned(false)
, op_err(GpgOp::ErrorUnknown)
, gpg(find_bin())
, _finished(false)
{
connect(&gpg, &GpgOp::readyRead, this, &MyMessageContext::gpg_readyRead);
connect(&gpg, &GpgOp::bytesWritten, this, &MyMessageContext::gpg_bytesWritten);
connect(&gpg, &GpgOp::finished, this, &MyMessageContext::gpg_finished);
connect(&gpg, &GpgOp::needPassphrase, this, &MyMessageContext::gpg_needPassphrase);
connect(&gpg, &GpgOp::needCard, this, &MyMessageContext::gpg_needCard);
connect(&gpg, &GpgOp::readyReadDiagnosticText, this, &MyMessageContext::gpg_readyReadDiagnosticText);
connect(&asker, &QCA::PasswordAsker::responseReady, this, &MyMessageContext::asker_responseReady);
connect(&tokenAsker, &QCA::TokenAsker::responseReady, this, &MyMessageContext::tokenAsker_responseReady);
}
Provider::Context *MyMessageContext::clone() const
{
return nullptr;
}
bool MyMessageContext::canSignMultiple() const
{
return false;
}
SecureMessage::Type MyMessageContext::type() const
{
return SecureMessage::OpenPGP;
}
void MyMessageContext::reset()
{
wrote = 0;
ok = false;
wasSigned = false;
}
void MyMessageContext::setupEncrypt(const SecureMessageKeyList &keys)
{
recipIds.clear();
for (int n = 0; n < keys.count(); ++n)
recipIds += keys[n].pgpPublicKey().keyId();
}
void MyMessageContext::setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool, bool)
{
signerId = keys.first().pgpSecretKey().keyId();
signMode = m;
}
void MyMessageContext::setupVerify(const QByteArray &detachedSig)
{
sig = detachedSig;
}
void MyMessageContext::start(SecureMessage::Format f, Operation op)
{
_finished = false;
format = f;
this->op = op;
if (getProperty(QStringLiteral("pgp-always-trust")).toBool())
gpg.setAlwaysTrust(true);
if (format == SecureMessage::Ascii)
gpg.setAsciiFormat(true);
else
gpg.setAsciiFormat(false);
if (op == Encrypt) {
gpg.doEncrypt(recipIds);
} else if (op == Decrypt) {
gpg.doDecrypt();
} else if (op == Sign) {
if (signMode == SecureMessage::Message) {
gpg.doSign(signerId);
} else if (signMode == SecureMessage::Clearsign) {
gpg.doSignClearsign(signerId);
} else // SecureMessage::Detached
{
gpg.doSignDetached(signerId);
}
} else if (op == Verify) {
if (!sig.isEmpty())
gpg.doVerifyDetached(sig);
else
gpg.doDecrypt();
} else if (op == SignAndEncrypt) {
gpg.doSignAndEncrypt(signerId, recipIds);
}
}
void MyMessageContext::update(const QByteArray &in)
{
gpg.write(in);
// this->in.append(in);
}
QByteArray MyMessageContext::read()
{
const QByteArray a = out;
out.clear();
return a;
}
int MyMessageContext::written()
{
int x = wrote;
wrote = 0;
return x;
}
void MyMessageContext::end()
{
gpg.endWrite();
}
void MyMessageContext::seterror()
{
gpg.reset();
_finished = true;
ok = false;
op_err = GpgOp::ErrorUnknown;
}
void MyMessageContext::complete()
{
_finished = true;
dtext = gpg.readDiagnosticText();
ok = gpg.success();
if (ok) {
if (op == Sign && signMode == SecureMessage::Detached)
sig = gpg.read();
else
out = gpg.read();
}
if (ok) {
if (gpg.wasSigned()) {
const QString signerId = gpg.signerId();
const QDateTime ts = gpg.timestamp();
const GpgOp::VerifyResult vr = gpg.verifyResult();
SecureMessageSignature::IdentityResult ir;
Validity v;
if (vr == GpgOp::VerifyGood) {
ir = SecureMessageSignature::Valid;
v = ValidityGood;
} else if (vr == GpgOp::VerifyBad) {
ir = SecureMessageSignature::InvalidSignature;
v = ValidityGood; // good key, bad sig
} else // GpgOp::VerifyNoKey
{
ir = SecureMessageSignature::NoKey;
v = ErrorValidityUnknown;
}
SecureMessageKey key;
PGPKey pub = publicKeyFromId(signerId);
if (pub.isNull()) {
MyPGPKeyContext *kc = new MyPGPKeyContext(provider());
kc->_props.keyId = signerId;
pub.change(kc);
}
key.setPGPPublicKey(pub);
signer = SecureMessageSignature(ir, v, key, ts);
wasSigned = true;
}
} else
op_err = gpg.errorCode();
}
bool MyMessageContext::finished() const
{
return _finished;
}
bool MyMessageContext::waitForFinished(int msecs)
{
// FIXME
Q_UNUSED(msecs);
MyKeyStoreList *keyStoreList = MyKeyStoreList::instance();
while (true) {
// TODO: handle token prompt events
GpgOp::Event e = gpg.waitForEvent(-1);
if (e.type == GpgOp::Event::NeedPassphrase) {
// TODO
QString keyId;
PGPKey sec = secretKeyFromId(e.keyId);
if (!sec.isNull())
keyId = sec.keyId();
else
keyId = e.keyId;
QStringList out;
out += escape_string(QStringLiteral("qca-gnupg-1"));
out += escape_string(keyId);
QString serialized = out.join(QStringLiteral(":"));
KeyStoreEntry kse;
KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized);
if (c)
kse.change(c);
asker.ask(Event::StylePassphrase,
KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)),
kse,
nullptr);
asker.waitForResponse();
if (!asker.accepted()) {
seterror();
return true;
}
gpg.submitPassphrase(asker.password());
} else if (e.type == GpgOp::Event::NeedCard) {
tokenAsker.ask(KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)),
KeyStoreEntry(),
nullptr);
if (!tokenAsker.accepted()) {
seterror();
return true;
}
gpg.cardOkay();
} else if (e.type == GpgOp::Event::Finished)
break;
}
complete();
return true;
}
bool MyMessageContext::success() const
{
return ok;
}
SecureMessage::Error MyMessageContext::errorCode() const
{
SecureMessage::Error e = SecureMessage::ErrorUnknown;
if (op_err == GpgOp::ErrorProcess)
e = SecureMessage::ErrorUnknown;
else if (op_err == GpgOp::ErrorPassphrase)
e = SecureMessage::ErrorPassphrase;
else if (op_err == GpgOp::ErrorFormat)
e = SecureMessage::ErrorFormat;
else if (op_err == GpgOp::ErrorSignerExpired)
e = SecureMessage::ErrorSignerExpired;
else if (op_err == GpgOp::ErrorSignerRevoked)
e = SecureMessage::ErrorSignerRevoked;
else if (op_err == GpgOp::ErrorSignatureExpired)
e = SecureMessage::ErrorSignatureExpired;
else if (op_err == GpgOp::ErrorEncryptExpired)
e = SecureMessage::ErrorEncryptExpired;
else if (op_err == GpgOp::ErrorEncryptRevoked)
e = SecureMessage::ErrorEncryptRevoked;
else if (op_err == GpgOp::ErrorEncryptUntrusted)
e = SecureMessage::ErrorEncryptUntrusted;
else if (op_err == GpgOp::ErrorEncryptInvalid)
e = SecureMessage::ErrorEncryptInvalid;
else if (op_err == GpgOp::ErrorDecryptNoKey)
e = SecureMessage::ErrorUnknown;
else if (op_err == GpgOp::ErrorUnknown)
e = SecureMessage::ErrorUnknown;
return e;
}
QByteArray MyMessageContext::signature() const
{
return sig;
}
QString MyMessageContext::hashName() const
{
// TODO
return QStringLiteral("sha1");
}
SecureMessageSignatureList MyMessageContext::signers() const
{
SecureMessageSignatureList list;
if (ok && wasSigned)
list += signer;
return list;
}
QString MyMessageContext::diagnosticText() const
{
return dtext;
}
void MyMessageContext::gpg_readyRead()
{
emit updated();
}
void MyMessageContext::gpg_bytesWritten(int bytes)
{
wrote += bytes;
}
void MyMessageContext::gpg_finished()
{
complete();
emit updated();
}
void MyMessageContext::gpg_needPassphrase(const QString &in_keyId)
{
// FIXME: copied from above, clean up later
QString keyId;
PGPKey sec = secretKeyFromId(in_keyId);
if (!sec.isNull())
keyId = sec.keyId();
else
keyId = in_keyId;
// emit keyStoreList->storeNeedPassphrase(0, 0, keyId);
QStringList out;
out += escape_string(QStringLiteral("qca-gnupg-1"));
out += escape_string(keyId);
QString serialized = out.join(QStringLiteral(":"));
KeyStoreEntry kse;
MyKeyStoreList * keyStoreList = MyKeyStoreList::instance();
KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized);
if (c)
kse.change(c);
asker.ask(Event::StylePassphrase,
KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)),
kse,
nullptr);
}
void MyMessageContext::gpg_needCard()
{
MyKeyStoreList *keyStoreList = MyKeyStoreList::instance();
tokenAsker.ask(
KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), KeyStoreEntry(), nullptr);
}
void MyMessageContext::gpg_readyReadDiagnosticText()
{
// TODO ?
}
void MyMessageContext::asker_responseReady()
{
if (!asker.accepted()) {
seterror();
emit updated();
return;
}
const SecureArray a = asker.password();
gpg.submitPassphrase(a);
}
void MyMessageContext::tokenAsker_responseReady()
{
if (!tokenAsker.accepted()) {
seterror();
emit updated();
return;
}
gpg.cardOkay();
}
} // end namespace gpgQCAPlugin