You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tqca/src/tqca.cpp

1492 lines
27 KiB

/*
* tqca.cpp - TQt Cryptographic Architecture
* Copyright (C) 2003 Justin Karneges
* Copyright (C) 2010-2020 TDE Team
*
* 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
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "tqca.h"
#include "tqcaprovider.h"
#include <tqptrlist.h>
#include <tqdir.h>
#include <tqfileinfo.h>
#include <tqstringlist.h>
#include <tqlibrary.h>
#include <tqtimer.h>
#include <tqhostaddress.h>
#include <tqapplication.h>
#include <tqguardedptr.h>
#include <cstdlib>
#if defined(Q_OS_WIN32)
#define PLUGIN_EXT "dll"
#elif defined(Q_OS_MAC)
#define PLUGIN_EXT "dylib"
#else
#define PLUGIN_EXT "so"
#endif
using namespace TQCA;
class ProviderItem
{
public:
TQCAProvider *p;
TQString fname;
static ProviderItem *load(const TQString &fname)
{
TQLibrary *lib = new TQLibrary(fname);
if(!lib->load()) {
delete lib;
return 0;
}
void *s = lib->resolve("createProvider");
if(!s) {
delete lib;
return 0;
}
TQCAProvider *(*createProvider)() = (TQCAProvider *(*)())s;
TQCAProvider *p = createProvider();
if(!p) {
delete lib;
return 0;
}
ProviderItem *i = new ProviderItem(lib, p);
i->fname = fname;
return i;
}
static ProviderItem *fromClass(TQCAProvider *p)
{
ProviderItem *i = new ProviderItem(0, p);
return i;
}
~ProviderItem()
{
delete p;
delete lib;
}
void ensureInit()
{
if(init_done)
return;
init_done = true;
p->init();
}
private:
TQLibrary *lib;
bool init_done;
ProviderItem(TQLibrary *_lib, TQCAProvider *_p)
{
lib = _lib;
p = _p;
init_done = false;
}
};
static TQPtrList<ProviderItem> providerList;
static bool qca_init = false;
static bool plugin_have(const TQString &fname)
{
TQPtrListIterator<ProviderItem> it(providerList);
for(ProviderItem *i; (i = it.current()); ++it) {
if(i->fname == fname)
return true;
}
return false;
}
static void plugin_scan()
{
TQStringList dirs = TQApplication::libraryPaths();
for(TQStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
TQDir libpath(*it);
TQDir dir(libpath.filePath("crypto"));
if(!dir.exists())
continue;
TQStringList list = dir.entryList();
for(TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
TQFileInfo fi(dir.filePath(*it));
if(fi.isDir())
continue;
if(fi.extension() != PLUGIN_EXT)
continue;
TQString fname = fi.filePath();
// don't load the same plugin again!
if(plugin_have(fname))
continue;
//printf("f=[%s]\n", fname.latin1());
ProviderItem *i = ProviderItem::load(fname);
if(!i)
continue;
if(i->p->qcaVersion() != TQCA_PLUGIN_VERSION) {
delete i;
continue;
}
providerList.append(i);
}
}
}
static void plugin_addClass(TQCAProvider *p)
{
ProviderItem *i = ProviderItem::fromClass(p);
providerList.prepend(i);
}
static void plugin_unloadall()
{
providerList.clear();
}
static int plugin_caps()
{
int caps = 0;
TQPtrListIterator<ProviderItem> it(providerList);
for(ProviderItem *i; (i = it.current()); ++it)
caps |= i->p->capabilities();
return caps;
}
TQString TQCA::arrayToHex(const TQByteArray &a)
{
TQString out;
for(int n = 0; n < (int)a.size(); ++n) {
TQString str;
str.sprintf("%02x", (uchar)a[n]);
out.append(str);
}
return out;
}
TQByteArray TQCA::hexToArray(const TQString &str)
{
TQByteArray out(str.length() / 2);
int at = 0;
for(int n = 0; n + 1 < (int)str.length(); n += 2) {
uchar a = str[n];
uchar b = str[n+1];
uchar c = ((a & 0x0f) << 4) + (b & 0x0f);
out[at++] = c;
}
return out;
}
void TQCA::init()
{
if(qca_init)
return;
qca_init = true;
providerList.setAutoDelete(true);
}
bool TQCA::isSupported(int capabilities)
{
init();
int caps = plugin_caps();
if(caps & capabilities)
return true;
// ok, try scanning for new stuff
plugin_scan();
caps = plugin_caps();
if(caps & capabilities)
return true;
return false;
}
void TQCA::insertProvider(TQCAProvider *p)
{
plugin_addClass(p);
}
void TQCA::unloadAllPlugins()
{
plugin_unloadall();
}
static void *getContext(int cap)
{
init();
// this call will also trip a scan for new plugins if needed
if(!TQCA::isSupported(cap))
return 0;
TQPtrListIterator<ProviderItem> it(providerList);
for(ProviderItem *i; (i = it.current()); ++it) {
if(i->p->capabilities() & cap) {
i->ensureInit();
return i->p->context(cap);
}
}
return 0;
}
//----------------------------------------------------------------------------
// Hash
//----------------------------------------------------------------------------
class Hash::Private
{
public:
Private()
{
c = 0;
}
~Private()
{
delete c;
}
void reset()
{
c->reset();
}
TQCA_HashContext *c;
};
Hash::Hash(TQCA_HashContext *c)
{
d = new Private;
d->c = c;
}
Hash::Hash(const Hash &from)
{
d = new Private;
*this = from;
}
Hash & Hash::operator=(const Hash &from)
{
delete d->c;
d->c = from.d->c->clone();
return *this;
}
Hash::~Hash()
{
delete d;
}
void Hash::clear()
{
d->reset();
}
void Hash::update(const TQByteArray &a)
{
d->c->update(a.data(), a.size());
}
TQByteArray Hash::final()
{
TQByteArray buf;
d->c->final(&buf);
return buf;
}
//----------------------------------------------------------------------------
// Cipher
//----------------------------------------------------------------------------
class Cipher::Private
{
public:
Private()
{
c = 0;
}
~Private()
{
delete c;
}
void reset()
{
dir = Encrypt;
key.resize(0);
iv.resize(0);
err = false;
}
TQCA_CipherContext *c;
int dir;
int mode;
TQByteArray key, iv;
bool err;
};
Cipher::Cipher(TQCA_CipherContext *c, int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad)
{
d = new Private;
d->c = c;
reset(dir, mode, key, iv, pad);
}
Cipher::Cipher(const Cipher &from)
{
d = new Private;
*this = from;
}
Cipher & Cipher::operator=(const Cipher &from)
{
delete d->c;
d->c = from.d->c->clone();
d->dir = from.d->dir;
d->mode = from.d->mode;
d->key = from.d->key.copy();
d->iv = from.d->iv.copy();
d->err = from.d->err;
return *this;
}
Cipher::~Cipher()
{
delete d;
}
TQByteArray Cipher::dyn_generateKey(int size) const
{
TQByteArray buf;
if(size != -1)
buf.resize(size);
else
buf.resize(d->c->keySize());
if(!d->c->generateKey(buf.data(), size))
return TQByteArray();
return buf;
}
TQByteArray Cipher::dyn_generateIV() const
{
TQByteArray buf(d->c->blockSize());
if(!d->c->generateIV(buf.data()))
return TQByteArray();
return buf;
}
void Cipher::reset(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad)
{
d->reset();
d->dir = dir;
d->mode = mode;
d->key = key.copy();
d->iv = iv.copy();
if(!d->c->setup(d->dir, d->mode, d->key.isEmpty() ? 0: d->key.data(), d->key.size(), d->iv.isEmpty() ? 0 : d->iv.data(), pad)) {
d->err = true;
return;
}
}
bool Cipher::update(const TQByteArray &a)
{
if(d->err)
return false;
if(!a.isEmpty()) {
if(!d->c->update(a.data(), a.size())) {
d->err = true;
return false;
}
}
return true;
}
TQByteArray Cipher::final(bool *ok)
{
if(ok)
*ok = false;
if(d->err)
return TQByteArray();
TQByteArray out;
if(!d->c->final(&out)) {
d->err = true;
return TQByteArray();
}
if(ok)
*ok = true;
return out;
}
//----------------------------------------------------------------------------
// SHA1
//----------------------------------------------------------------------------
SHA1::SHA1()
:Hash((TQCA_HashContext *)getContext(CAP_SHA1))
{
}
//----------------------------------------------------------------------------
// SHA256
//----------------------------------------------------------------------------
SHA256::SHA256()
:Hash((TQCA_HashContext *)getContext(CAP_SHA256))
{
}
//----------------------------------------------------------------------------
// MD5
//----------------------------------------------------------------------------
MD5::MD5()
:Hash((TQCA_HashContext *)getContext(CAP_MD5))
{
}
//----------------------------------------------------------------------------
// BlowFish
//----------------------------------------------------------------------------
BlowFish::BlowFish(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad)
:Cipher((TQCA_CipherContext *)getContext(CAP_BlowFish), dir, mode, key, iv, pad)
{
}
//----------------------------------------------------------------------------
// TripleDES
//----------------------------------------------------------------------------
TripleDES::TripleDES(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad)
:Cipher((TQCA_CipherContext *)getContext(CAP_TripleDES), dir, mode, key, iv, pad)
{
}
//----------------------------------------------------------------------------
// AES128
//----------------------------------------------------------------------------
AES128::AES128(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad)
:Cipher((TQCA_CipherContext *)getContext(CAP_AES128), dir, mode, key, iv, pad)
{
}
//----------------------------------------------------------------------------
// AES256
//----------------------------------------------------------------------------
AES256::AES256(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad)
:Cipher((TQCA_CipherContext *)getContext(CAP_AES256), dir, mode, key, iv, pad)
{
}
//----------------------------------------------------------------------------
// RSAKey
//----------------------------------------------------------------------------
class RSAKey::Private
{
public:
Private()
{
c = 0;
}
~Private()
{
delete c;
}
TQCA_RSAKeyContext *c;
};
RSAKey::RSAKey()
{
d = new Private;
d->c = (TQCA_RSAKeyContext *)getContext(CAP_RSA);
}
RSAKey::RSAKey(const RSAKey &from)
{
d = new Private;
*this = from;
}
RSAKey & RSAKey::operator=(const RSAKey &from)
{
delete d->c;
d->c = from.d->c->clone();
return *this;
}
RSAKey::~RSAKey()
{
delete d;
}
bool RSAKey::isNull() const
{
return d->c->isNull();
}
bool RSAKey::havePublic() const
{
return d->c->havePublic();
}
bool RSAKey::havePrivate() const
{
return d->c->havePrivate();
}
TQByteArray RSAKey::toDER(bool publicOnly) const
{
TQByteArray out;
if(!d->c->toDER(&out, publicOnly))
return TQByteArray();
return out;
}
bool RSAKey::fromDER(const TQByteArray &a)
{
return d->c->createFromDER(a.data(), a.size());
}
TQString RSAKey::toPEM(bool publicOnly) const
{
TQByteArray out;
if(!d->c->toPEM(&out, publicOnly))
return TQByteArray();
TQCString cs;
cs.resize(out.size()+1);
memcpy(cs.data(), out.data(), out.size());
return TQString::fromLatin1(cs);
}
bool RSAKey::fromPEM(const TQString &str)
{
TQCString cs = str.latin1();
TQByteArray a(cs.length());
memcpy(a.data(), cs.data(), a.size());
return d->c->createFromPEM(a.data(), a.size());
}
bool RSAKey::fromNative(void *p)
{
return d->c->createFromNative(p);
}
bool RSAKey::encrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const
{
TQByteArray out;
if(!d->c->encrypt(a, &out, oaep))
return false;
*b = out;
return true;
}
bool RSAKey::decrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const
{
TQByteArray out;
if(!d->c->decrypt(a, &out, oaep))
return false;
*b = out;
return true;
}
bool RSAKey::generate(unsigned int bits)
{
return d->c->generate(bits);
}
//----------------------------------------------------------------------------
// RSA
//----------------------------------------------------------------------------
RSA::RSA()
{
}
RSA::~RSA()
{
}
RSAKey RSA::key() const
{
return v_key;
}
void RSA::setKey(const RSAKey &k)
{
v_key = k;
}
bool RSA::encrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const
{
if(v_key.isNull())
return false;
return v_key.encrypt(a, b, oaep);
}
bool RSA::decrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const
{
if(v_key.isNull())
return false;
return v_key.decrypt(a, b, oaep);
}
RSAKey RSA::generateKey(unsigned int bits)
{
RSAKey k;
k.generate(bits);
return k;
}
//----------------------------------------------------------------------------
// Cert
//----------------------------------------------------------------------------
class Cert::Private
{
public:
Private()
{
c = 0;
}
~Private()
{
delete c;
}
TQCA_CertContext *c;
};
Cert::Cert()
{
d = new Private;
// crash because this is returning 0
d->c = (TQCA_CertContext *)getContext(CAP_X509);
}
Cert::Cert(const Cert &from)
{
d = new Private;
*this = from;
}
Cert & Cert::operator=(const Cert &from)
{
delete d->c;
if ( from.d->c )
d->c = from.d->c->clone();
else
d->c = 0;
return *this;
}
Cert::~Cert()
{
delete d;
}
void Cert::fromContext(TQCA_CertContext *ctx)
{
delete d->c;
d->c = ctx;
}
bool Cert::isNull() const
{
return d->c->isNull();
}
TQString Cert::commonName() const
{
CertProperties props = subject();
return props["CN"];
}
TQString Cert::serialNumber() const
{
return d->c->serialNumber();
}
TQString Cert::subjectString() const
{
return d->c->subjectString();
}
TQString Cert::issuerString() const
{
return d->c->issuerString();
}
CertProperties Cert::subject() const
{
TQValueList<TQCA_CertProperty> list = d->c->subject();
CertProperties props;
for(TQValueList<TQCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
props[(*it).var] = (*it).val;
return props;
}
CertProperties Cert::issuer() const
{
TQValueList<TQCA_CertProperty> list = d->c->issuer();
CertProperties props;
for(TQValueList<TQCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
props[(*it).var] = (*it).val;
return props;
}
TQDateTime Cert::notBefore() const
{
return d->c->notBefore();
}
TQDateTime Cert::notAfter() const
{
return d->c->notAfter();
}
TQByteArray Cert::toDER() const
{
TQByteArray out;
if(!d->c->toDER(&out))
return TQByteArray();
return out;
}
bool Cert::fromDER(const TQByteArray &a)
{
return d->c->createFromDER(a.data(), a.size());
}
TQString Cert::toPEM() const
{
TQByteArray out;
if(!d->c->toPEM(&out))
return TQByteArray();
TQCString cs;
cs.resize(out.size()+1);
memcpy(cs.data(), out.data(), out.size());
return TQString::fromLatin1(cs);
}
bool Cert::fromPEM(const TQString &str)
{
TQCString cs = str.latin1();
TQByteArray a(cs.length());
memcpy(a.data(), cs.data(), a.size());
return d->c->createFromPEM(a.data(), a.size());
}
//----------------------------------------------------------------------------
// TLS
//----------------------------------------------------------------------------
class TLS::Private
{
public:
Private()
{
c = (TQCA_TLSContext *)getContext(CAP_TLS);
}
~Private()
{
delete c;
}
void reset()
{
handshaken = false;
closing = false;
in.resize(0);
out.resize(0);
from_net.resize(0);
to_net.resize(0);
host = "";
hostMismatch = false;
// this causes the crash, because the Cert ctor is setting a null context
cert = Cert();
bytesEncoded = 0;
tryMore = false;
}
void appendArray(TQByteArray *a, const TQByteArray &b)
{
int oldsize = a->size();
a->resize(oldsize + b.size());
memcpy(a->data() + oldsize, b.data(), b.size());
}
Cert cert;
TQCA_TLSContext *c;
TQByteArray in, out, to_net, from_net;
int bytesEncoded;
bool tryMore;
bool handshaken;
TQString host;
bool hostMismatch;
bool closing;
Cert ourCert;
RSAKey ourKey;
TQPtrList<TQCA_CertContext> store;
};
TLS::TLS(TQObject *parent)
:TQObject(parent)
{
d = new Private;
}
TLS::~TLS()
{
delete d;
}
void TLS::setCertificate(const Cert &cert, const RSAKey &key)
{
d->ourCert = cert;
d->ourKey = key;
}
void TLS::setCertificateStore(const TQPtrList<Cert> &store)
{
// convert the cert list into a context list
d->store.clear();
TQPtrListIterator<Cert> it(store);
for(Cert *cert; (cert = it.current()); ++it)
d->store.append(cert->d->c);
}
void TLS::reset()
{
d->reset();
}
bool TLS::startClient(const TQString &host)
{
d->reset();
d->host = host;
if(!d->c->startClient(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
return false;
TQTimer::singleShot(0, this, TQ_SLOT(update()));
return true;
}
bool TLS::startServer()
{
d->reset();
if(!d->c->startServer(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
return false;
TQTimer::singleShot(0, this, TQ_SLOT(update()));
return true;
}
void TLS::close()
{
if(!d->handshaken || d->closing)
return;
d->closing = true;
TQTimer::singleShot(0, this, TQ_SLOT(update()));
}
bool TLS::isHandshaken() const
{
return d->handshaken;
}
void TLS::write(const TQByteArray &a)
{
d->appendArray(&d->out, a);
update();
}
TQByteArray TLS::read()
{
TQByteArray a = d->in.copy();
d->in.resize(0);
return a;
}
void TLS::writeIncoming(const TQByteArray &a)
{
d->appendArray(&d->from_net, a);
update();
}
TQByteArray TLS::readOutgoing()
{
TQByteArray a = d->to_net.copy();
d->to_net.resize(0);
return a;
}
TQByteArray TLS::readUnprocessed()
{
TQByteArray a = d->from_net.copy();
d->from_net.resize(0);
return a;
}
const Cert & TLS::peerCertificate() const
{
return d->cert;
}
int TLS::certificateValidityResult() const
{
if(d->hostMismatch)
return TQCA::TLS::HostMismatch;
else
return d->c->validityResult();
}
void TLS::update()
{
bool force_read = false;
bool eof = false;
bool done = false;
TQGuardedPtr<TLS> self = this;
if(d->closing) {
TQByteArray a;
int r = d->c->shutdown(d->from_net, &a);
d->from_net.resize(0);
if(r == TQCA_TLSContext::Error) {
reset();
error(ErrHandshake);
return;
}
if(r == TQCA_TLSContext::Success) {
d->from_net = d->c->unprocessed().copy();
done = true;
}
d->appendArray(&d->to_net, a);
}
else {
if(!d->handshaken) {
TQByteArray a;
int r = d->c->handshake(d->from_net, &a);
d->from_net.resize(0);
if(r == TQCA_TLSContext::Error) {
reset();
error(ErrHandshake);
return;
}
d->appendArray(&d->to_net, a);
if(r == TQCA_TLSContext::Success) {
TQCA_CertContext *cc = d->c->peerCertificate();
if(cc && !d->host.isEmpty() && d->c->validityResult() == TQCA::TLS::Valid) {
if(!cc->matchesAddress(d->host))
d->hostMismatch = true;
}
d->cert.fromContext(cc);
d->handshaken = true;
handshaken();
if(!self)
return;
// there is a teeny tiny possibility that incoming data awaits. let us get it.
force_read = true;
}
}
if(d->handshaken) {
if(!d->out.isEmpty() || d->tryMore) {
d->tryMore = false;
TQByteArray a;
int enc;
bool more = false;
bool ok = d->c->encode(d->out, &a, &enc);
eof = d->c->eof();
if(ok && enc < (int)d->out.size())
more = true;
d->out.resize(0);
if(!eof) {
if(!ok) {
reset();
error(ErrCrypt);
return;
}
d->bytesEncoded += enc;
if(more)
d->tryMore = true;
d->appendArray(&d->to_net, a);
}
}
if(!d->from_net.isEmpty() || force_read) {
TQByteArray a, b;
bool ok = d->c->decode(d->from_net, &a, &b);
eof = d->c->eof();
d->from_net.resize(0);
if(!ok) {
reset();
error(ErrCrypt);
return;
}
d->appendArray(&d->in, a);
d->appendArray(&d->to_net, b);
}
if(!d->in.isEmpty()) {
readyRead();
if(!self)
return;
}
}
}
if(!d->to_net.isEmpty()) {
int bytes = d->bytesEncoded;
d->bytesEncoded = 0;
readyReadOutgoing(bytes);
if(!self)
return;
}
if(eof) {
close();
if(!self)
return;
return;
}
if(d->closing && done) {
reset();
closed();
}
}
//----------------------------------------------------------------------------
// SASL
//----------------------------------------------------------------------------
TQString saslappname = "qca";
class SASL::Private
{
public:
Private()
{
c = (TQCA_SASLContext *)getContext(CAP_SASL);
}
~Private()
{
delete c;
}
void setSecurityProps()
{
c->setSecurityProps(noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual, ssfmin, ssfmax, ext_authid, ext_ssf);
}
// security opts
bool noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual;
int ssfmin, ssfmax;
TQString ext_authid;
int ext_ssf;
bool tried;
TQCA_SASLContext *c;
TQHostAddress localAddr, remoteAddr;
int localPort, remotePort;
TQByteArray stepData;
bool allowCSF;
bool first, server;
TQByteArray inbuf, outbuf;
};
SASL::SASL(TQObject *parent)
:TQObject(parent)
{
d = new Private;
reset();
}
SASL::~SASL()
{
delete d;
}
void SASL::setAppName(const TQString &name)
{
saslappname = name;
}
void SASL::reset()
{
d->localPort = -1;
d->remotePort = -1;
d->noPlain = false;
d->noActive = false;
d->noDict = false;
d->noAnon = false;
d->reqForward = false;
d->reqCreds = false;
d->reqMutual = false;
d->ssfmin = 0;
d->ssfmax = 0;
d->ext_authid = "";
d->ext_ssf = 0;
d->inbuf.resize(0);
d->outbuf.resize(0);
d->c->reset();
}
int SASL::errorCondition() const
{
return d->c->errorCond();
}
void SASL::setAllowPlain(bool b)
{
d->noPlain = !b;
}
void SASL::setAllowAnonymous(bool b)
{
d->noAnon = !b;
}
void SASL::setAllowActiveVulnerable(bool b)
{
d->noActive = !b;
}
void SASL::setAllowDictionaryVulnerable(bool b)
{
d->noDict = !b;
}
void SASL::setRequireForwardSecrecy(bool b)
{
d->reqForward = b;
}
void SASL::setRequirePassCredentials(bool b)
{
d->reqCreds = b;
}
void SASL::setRequireMutualAuth(bool b)
{
d->reqMutual = b;
}
void SASL::setMinimumSSF(int x)
{
d->ssfmin = x;
}
void SASL::setMaximumSSF(int x)
{
d->ssfmax = x;
}
void SASL::setExternalAuthID(const TQString &authid)
{
d->ext_authid = authid;
}
void SASL::setExternalSSF(int x)
{
d->ext_ssf = x;
}
void SASL::setLocalAddr(const TQHostAddress &addr, TQ_UINT16 port)
{
d->localAddr = addr;
d->localPort = port;
}
void SASL::setRemoteAddr(const TQHostAddress &addr, TQ_UINT16 port)
{
d->remoteAddr = addr;
d->remotePort = port;
}
bool SASL::startClient(const TQString &service, const TQString &host, const TQStringList &mechlist, bool allowClientSendFirst)
{
TQCA_SASLHostPort la, ra;
if(d->localPort != -1) {
la.addr = d->localAddr;
la.port = d->localPort;
}
if(d->remotePort != -1) {
ra.addr = d->remoteAddr;
ra.port = d->remotePort;
}
d->allowCSF = allowClientSendFirst;
d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
d->setSecurityProps();
if(!d->c->clientStart(mechlist))
return false;
d->first = true;
d->server = false;
d->tried = false;
TQTimer::singleShot(0, this, TQ_SLOT(tryAgain()));
return true;
}
bool SASL::startServer(const TQString &service, const TQString &host, const TQString &realm, TQStringList *mechlist)
{
TQCA_SASLHostPort la, ra;
if(d->localPort != -1) {
la.addr = d->localAddr;
la.port = d->localPort;
}
if(d->remotePort != -1) {
ra.addr = d->remoteAddr;
ra.port = d->remotePort;
}
d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
d->setSecurityProps();
if(!d->c->serverStart(realm, mechlist, saslappname))
return false;
d->first = true;
d->server = true;
d->tried = false;
return true;
}
void SASL::putServerFirstStep(const TQString &mech)
{
int r = d->c->serverFirstStep(mech, 0);
handleServerFirstStep(r);
}
void SASL::putServerFirstStep(const TQString &mech, const TQByteArray &clientInit)
{
int r = d->c->serverFirstStep(mech, &clientInit);
handleServerFirstStep(r);
}
void SASL::handleServerFirstStep(int r)
{
if(r == TQCA_SASLContext::Success)
authenticated();
else if(r == TQCA_SASLContext::Continue)
nextStep(d->c->result());
else if(r == TQCA_SASLContext::AuthCheck)
tryAgain();
else
error(ErrAuth);
}
void SASL::putStep(const TQByteArray &stepData)
{
d->stepData = stepData.copy();
tryAgain();
}
void SASL::setUsername(const TQString &user)
{
d->c->setClientParams(&user, 0, 0, 0);
}
void SASL::setAuthzid(const TQString &authzid)
{
d->c->setClientParams(0, &authzid, 0, 0);
}
void SASL::setPassword(const TQString &pass)
{
d->c->setClientParams(0, 0, &pass, 0);
}
void SASL::setRealm(const TQString &realm)
{
d->c->setClientParams(0, 0, 0, &realm);
}
void SASL::continueAfterParams()
{
tryAgain();
}
void SASL::continueAfterAuthCheck()
{
tryAgain();
}
void SASL::tryAgain()
{
int r;
if(d->server) {
if(!d->tried) {
r = d->c->nextStep(d->stepData);
d->tried = true;
}
else {
r = d->c->tryAgain();
}
if(r == TQCA_SASLContext::Error) {
error(ErrAuth);
return;
}
else if(r == TQCA_SASLContext::Continue) {
d->tried = false;
nextStep(d->c->result());
return;
}
else if(r == TQCA_SASLContext::AuthCheck) {
authCheck(d->c->username(), d->c->authzid());
return;
}
}
else {
if(d->first) {
if(!d->tried) {
r = d->c->clientFirstStep(d->allowCSF);
d->tried = true;
}
else
r = d->c->tryAgain();
if(r == TQCA_SASLContext::Error) {
error(ErrAuth);
return;
}
else if(r == TQCA_SASLContext::NeedParams) {
//d->tried = false;
TQCA_SASLNeedParams np = d->c->clientParamsNeeded();
needParams(np.user, np.authzid, np.pass, np.realm);
return;
}
TQString mech = d->c->mech();
const TQByteArray *clientInit = d->c->clientInit();
d->first = false;
d->tried = false;
clientFirstStep(mech, clientInit);
}
else {
if(!d->tried) {
r = d->c->nextStep(d->stepData);
d->tried = true;
}
else
r = d->c->tryAgain();
if(r == TQCA_SASLContext::Error) {
error(ErrAuth);
return;
}
else if(r == TQCA_SASLContext::NeedParams) {
//d->tried = false;
TQCA_SASLNeedParams np = d->c->clientParamsNeeded();
needParams(np.user, np.authzid, np.pass, np.realm);
return;
}
d->tried = false;
//else if(r == TQCA_SASLContext::Continue) {
nextStep(d->c->result());
// return;
//}
}
}
if(r == TQCA_SASLContext::Success)
authenticated();
else if(r == TQCA_SASLContext::Error)
error(ErrAuth);
}
int SASL::ssf() const
{
return d->c->security();
}
void SASL::write(const TQByteArray &a)
{
TQByteArray b;
if(!d->c->encode(a, &b)) {
error(ErrCrypt);
return;
}
int oldsize = d->outbuf.size();
d->outbuf.resize(oldsize + b.size());
memcpy(d->outbuf.data() + oldsize, b.data(), b.size());
readyReadOutgoing(a.size());
}
TQByteArray SASL::read()
{
TQByteArray a = d->inbuf.copy();
d->inbuf.resize(0);
return a;
}
void SASL::writeIncoming(const TQByteArray &a)
{
TQByteArray b;
if(!d->c->decode(a, &b)) {
error(ErrCrypt);
return;
}
int oldsize = d->inbuf.size();
d->inbuf.resize(oldsize + b.size());
memcpy(d->inbuf.data() + oldsize, b.data(), b.size());
readyRead();
}
TQByteArray SASL::readOutgoing()
{
TQByteArray a = d->outbuf.copy();
d->outbuf.resize(0);
return a;
}
#include "tqca.moc"