mirror of
https://github.com/QuasarApp/qca.git
synced 2025-04-27 20:14:32 +00:00
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)
416 lines
11 KiB
C++
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
|