4
0
mirror of https://github.com/QuasarApp/qca.git synced 2025-05-07 08:19:33 +00:00
qca/src/qca_securemessage.cpp
Albert Astals Cid 7df8f7e215 Move to the new connect syntax
QProcess::errorOccurred is since 5.6 so increase min version
2020-01-29 08:34:13 +00:00

689 lines
14 KiB
C++

/*
* Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
* Copyright (C) 2004,2005 Brad Hards <bradh@frogmouth.net>
*
* 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 Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "qca_securemessage.h"
#include "qcaprovider.h"
#include "qca_safeobj.h"
#include "qca_safetimer.h"
namespace QCA {
Provider::Context *getContext(const QString &type, const QString &provider);
//----------------------------------------------------------------------------
// SecureMessageKey
//----------------------------------------------------------------------------
class SecureMessageKey::Private : public QSharedData
{
public:
SecureMessageKey::Type type;
PGPKey pgp_pub, pgp_sec;
CertificateChain cert_pub;
PrivateKey cert_sec;
Private()
{
type = SecureMessageKey::None;
}
// set the proper type, and reset the opposite data structures if needed
void ensureType(SecureMessageKey::Type t)
{
// if we were non-null and changed, we may need to reset some things
if(type != SecureMessageKey::None && t != type)
{
if(type == SecureMessageKey::X509)
{
cert_pub = CertificateChain();
cert_sec = PrivateKey();
}
else if(type == SecureMessageKey::PGP)
{
pgp_pub = PGPKey();
pgp_sec = PGPKey();
}
}
type = t;
}
};
SecureMessageKey::SecureMessageKey()
:d(new Private)
{
}
SecureMessageKey::SecureMessageKey(const SecureMessageKey &from)
:d(from.d)
{
}
SecureMessageKey::~SecureMessageKey()
{
}
SecureMessageKey & SecureMessageKey::operator=(const SecureMessageKey &from)
{
d = from.d;
return *this;
}
bool SecureMessageKey::isNull() const
{
return (d->type == None);
}
SecureMessageKey::Type SecureMessageKey::type() const
{
return d->type;
}
PGPKey SecureMessageKey::pgpPublicKey() const
{
return d->pgp_pub;
}
PGPKey SecureMessageKey::pgpSecretKey() const
{
return d->pgp_sec;
}
void SecureMessageKey::setPGPPublicKey(const PGPKey &pub)
{
d->ensureType(SecureMessageKey::PGP);
d->pgp_pub = pub;
}
void SecureMessageKey::setPGPSecretKey(const PGPKey &sec)
{
d->ensureType(SecureMessageKey::PGP);
Q_ASSERT(sec.isSecret());
d->pgp_sec = sec;
}
CertificateChain SecureMessageKey::x509CertificateChain() const
{
return d->cert_pub;
}
PrivateKey SecureMessageKey::x509PrivateKey() const
{
return d->cert_sec;
}
void SecureMessageKey::setX509CertificateChain(const CertificateChain &c)
{
d->ensureType(SecureMessageKey::X509);
d->cert_pub = c;
}
void SecureMessageKey::setX509PrivateKey(const PrivateKey &k)
{
d->ensureType(SecureMessageKey::X509);
d->cert_sec = k;
}
void SecureMessageKey::setX509KeyBundle(const KeyBundle &kb)
{
setX509CertificateChain(kb.certificateChain());
setX509PrivateKey(kb.privateKey());
}
bool SecureMessageKey::havePrivate() const
{
if(d->type == SecureMessageKey::PGP && !d->pgp_sec.isNull())
return true;
else if(d->type == SecureMessageKey::X509 && !d->cert_sec.isNull())
return true;
return false;
}
QString SecureMessageKey::name() const
{
if(d->type == SecureMessageKey::PGP && !d->pgp_pub.isNull())
return d->pgp_pub.primaryUserId();
else if(d->type == SecureMessageKey::X509 && !d->cert_pub.isEmpty())
return d->cert_pub.primary().commonName();
else
return QString();
}
//----------------------------------------------------------------------------
// SecureMessageSignature
//----------------------------------------------------------------------------
class SecureMessageSignature::Private : public QSharedData
{
public:
SecureMessageSignature::IdentityResult r;
Validity v;
SecureMessageKey key;
QDateTime ts;
Private()
{
r = SecureMessageSignature::NoKey;
v = ErrorValidityUnknown;
}
};
SecureMessageSignature::SecureMessageSignature()
:d(new Private)
{
}
SecureMessageSignature::SecureMessageSignature(IdentityResult r, Validity v, const SecureMessageKey &key, const QDateTime &ts)
:d(new Private)
{
d->r = r;
d->v = v;
d->key = key;
d->ts = ts;
}
SecureMessageSignature::SecureMessageSignature(const SecureMessageSignature &from)
:d(from.d)
{
}
SecureMessageSignature::~SecureMessageSignature()
{
}
SecureMessageSignature & SecureMessageSignature::operator=(const SecureMessageSignature &from)
{
d = from.d;
return *this;
}
SecureMessageSignature::IdentityResult SecureMessageSignature::identityResult() const
{
return d->r;
}
Validity SecureMessageSignature::keyValidity() const
{
return d->v;
}
SecureMessageKey SecureMessageSignature::key() const
{
return d->key;
}
QDateTime SecureMessageSignature::timestamp() const
{
return d->ts;
}
//----------------------------------------------------------------------------
// SecureMessage
//----------------------------------------------------------------------------
enum ResetMode
{
ResetSession = 0,
ResetSessionAndData = 1,
ResetAll = 2
};
class SecureMessage::Private : public QObject
{
Q_OBJECT
public:
SecureMessage *q;
MessageContext *c;
SecureMessageSystem *system;
bool bundleSigner, smime;
SecureMessage::Format format;
SecureMessageKeyList to;
SecureMessageKeyList from;
QByteArray in;
bool success;
SecureMessage::Error errorCode;
QByteArray detachedSig;
QString hashName;
SecureMessageSignatureList signers;
QString dtext;
QList<int> bytesWrittenArgs;
SafeTimer readyReadTrigger, bytesWrittenTrigger, finishedTrigger;
Private(SecureMessage *_q) : readyReadTrigger(this), bytesWrittenTrigger(this), finishedTrigger(this)
{
q = _q;
c = 0;
system = 0;
readyReadTrigger.setSingleShot(true);
bytesWrittenTrigger.setSingleShot(true);
finishedTrigger.setSingleShot(true);
connect(&readyReadTrigger, &SafeTimer::timeout, this, &Private::t_readyRead);
connect(&bytesWrittenTrigger, &SafeTimer::timeout, this, &Private::t_bytesWritten);
connect(&finishedTrigger, &SafeTimer::timeout, this, &Private::t_finished);
reset(ResetAll);
}
void init()
{
connect(c, &MessageContext::updated, this, &Private::updated);
}
void reset(ResetMode mode)
{
if(c)
c->reset();
bytesWrittenArgs.clear();
readyReadTrigger.stop();
bytesWrittenTrigger.stop();
finishedTrigger.stop();
if(mode >= ResetSessionAndData)
{
in.clear();
success = false;
errorCode = SecureMessage::ErrorUnknown;
detachedSig.clear();
hashName = QString();
signers.clear();
}
if(mode >= ResetAll)
{
bundleSigner = true;
format = SecureMessage::Binary;
to.clear();
from.clear();
}
}
public Q_SLOTS:
void updated()
{
bool sig_read = false;
bool sig_written = false;
bool sig_done = false;
int written = 0;
{
QByteArray a = c->read();
if(!a.isEmpty())
{
sig_read = true;
in.append(a);
}
int x = c->written();
if(x > 0)
{
sig_written = true;
written = x;
}
}
if(c->finished())
{
sig_done = true;
success = c->success();
errorCode = c->errorCode();
dtext = c->diagnosticText();
if(success)
{
detachedSig = c->signature();
hashName = c->hashName();
signers = c->signers();
}
reset(ResetSession);
}
if(sig_read)
readyReadTrigger.start();
if(sig_written)
{
bytesWrittenArgs += written;
bytesWrittenTrigger.start();
}
if(sig_done)
finishedTrigger.start();
}
void t_readyRead()
{
emit q->readyRead();
}
void t_bytesWritten()
{
emit q->bytesWritten(bytesWrittenArgs.takeFirst());
}
void t_finished()
{
emit q->finished();
}
};
SecureMessage::SecureMessage(SecureMessageSystem *system)
{
d = new Private(this);
d->system = system;
d->c = static_cast<SMSContext *>(d->system->context())->createMessage();
change(d->c);
d->init();
}
SecureMessage::~SecureMessage()
{
delete d;
}
SecureMessage::Type SecureMessage::type() const
{
return d->c->type();
}
bool SecureMessage::canSignMultiple() const
{
return d->c->canSignMultiple();
}
bool SecureMessage::canClearsign() const
{
return (type() == OpenPGP);
}
bool SecureMessage::canSignAndEncrypt() const
{
return (type() == OpenPGP);
}
void SecureMessage::reset()
{
d->reset(ResetAll);
}
bool SecureMessage::bundleSignerEnabled() const
{
return d->bundleSigner;
}
bool SecureMessage::smimeAttributesEnabled() const
{
return d->smime;
}
SecureMessage::Format SecureMessage::format() const
{
return d->format;
}
SecureMessageKeyList SecureMessage::recipientKeys() const
{
return d->to;
}
SecureMessageKeyList SecureMessage::signerKeys() const
{
return d->from;
}
void SecureMessage::setBundleSignerEnabled(bool b)
{
d->bundleSigner = b;
}
void SecureMessage::setSMIMEAttributesEnabled(bool b)
{
d->smime = b;
}
void SecureMessage::setFormat(Format f)
{
d->format = f;
}
void SecureMessage::setRecipient(const SecureMessageKey &key)
{
d->to = SecureMessageKeyList() << key;
}
void SecureMessage::setRecipients(const SecureMessageKeyList &keys)
{
d->to = keys;
}
void SecureMessage::setSigner(const SecureMessageKey &key)
{
d->from = SecureMessageKeyList() << key;
}
void SecureMessage::setSigners(const SecureMessageKeyList &keys)
{
d->from = keys;
}
void SecureMessage::startEncrypt()
{
d->reset(ResetSessionAndData);
d->c->setupEncrypt(d->to);
d->c->start(d->format, MessageContext::Encrypt);
}
void SecureMessage::startDecrypt()
{
d->reset(ResetSessionAndData);
d->c->start(d->format, MessageContext::Decrypt);
}
void SecureMessage::startSign(SignMode m)
{
d->reset(ResetSessionAndData);
d->c->setupSign(d->from, m, d->bundleSigner, d->smime);
d->c->start(d->format, MessageContext::Sign);
}
void SecureMessage::startVerify(const QByteArray &sig)
{
d->reset(ResetSessionAndData);
if(!sig.isEmpty())
d->c->setupVerify(sig);
d->c->start(d->format, MessageContext::Verify);
}
void SecureMessage::startSignAndEncrypt()
{
d->reset(ResetSessionAndData);
d->c->setupEncrypt(d->to);
d->c->setupSign(d->from, Message, d->bundleSigner, d->smime);
d->c->start(d->format, MessageContext::SignAndEncrypt);
}
void SecureMessage::update(const QByteArray &in)
{
d->c->update(in);
}
QByteArray SecureMessage::read()
{
QByteArray a = d->in;
d->in.clear();
return a;
}
int SecureMessage::bytesAvailable() const
{
return d->in.size();
}
void SecureMessage::end()
{
d->c->end();
}
bool SecureMessage::waitForFinished(int msecs)
{
d->c->waitForFinished(msecs);
d->updated();
return d->success;
}
bool SecureMessage::success() const
{
return d->success;
}
SecureMessage::Error SecureMessage::errorCode() const
{
return d->errorCode;
}
QByteArray SecureMessage::signature() const
{
return d->detachedSig;
}
QString SecureMessage::hashName() const
{
return d->hashName;
}
bool SecureMessage::wasSigned() const
{
return !d->signers.isEmpty();
}
bool SecureMessage::verifySuccess() const
{
// if we're not done or there were no signers, then return false
if(!d->success || d->signers.isEmpty())
return false;
// make sure all signers have a valid signature
for(int n = 0; n < d->signers.count(); ++n)
{
if(d->signers[n].identityResult() != SecureMessageSignature::Valid)
return false;
}
return true;
}
SecureMessageSignature SecureMessage::signer() const
{
if(d->signers.isEmpty())
return SecureMessageSignature();
return d->signers.first();
}
SecureMessageSignatureList SecureMessage::signers() const
{
return d->signers;
}
QString SecureMessage::diagnosticText() const
{
return d->dtext;
}
//----------------------------------------------------------------------------
// SecureMessageSystem
//----------------------------------------------------------------------------
SecureMessageSystem::SecureMessageSystem(QObject *parent, const QString &type, const QString &provider)
:QObject(parent), Algorithm(type, provider)
{
}
SecureMessageSystem::~SecureMessageSystem()
{
}
//----------------------------------------------------------------------------
// OpenPGP
//----------------------------------------------------------------------------
OpenPGP::OpenPGP(QObject *parent, const QString &provider)
:SecureMessageSystem(parent, "openpgp", provider)
{
}
OpenPGP::~OpenPGP()
{
}
//----------------------------------------------------------------------------
// CMS
//----------------------------------------------------------------------------
class CMS::Private
{
public:
CertificateCollection trusted, untrusted;
SecureMessageKeyList privateKeys;
};
CMS::CMS(QObject *parent, const QString &provider)
:SecureMessageSystem(parent, "cms", provider)
{
d = new Private;
}
CMS::~CMS()
{
delete d;
}
CertificateCollection CMS::trustedCertificates() const
{
return d->trusted;
}
CertificateCollection CMS::untrustedCertificates() const
{
return d->untrusted;
}
SecureMessageKeyList CMS::privateKeys() const
{
return d->privateKeys;
}
void CMS::setTrustedCertificates(const CertificateCollection &trusted)
{
d->trusted = trusted;
static_cast<SMSContext *>(context())->setTrustedCertificates(trusted);
}
void CMS::setUntrustedCertificates(const CertificateCollection &untrusted)
{
d->untrusted = untrusted;
static_cast<SMSContext *>(context())->setUntrustedCertificates(untrusted);
}
void CMS::setPrivateKeys(const SecureMessageKeyList &keys)
{
d->privateKeys = keys;
static_cast<SMSContext *>(context())->setPrivateKeys(keys);
}
}
#include "qca_securemessage.moc"