/* * qca.cpp - TQt Cryptographic Architecture * Copyright (C) 2003 Justin Karneges * * 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.h" #include #include #include #include #include #include #include #include #include #include #include"qcaprovider.h" #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 QCA; class ProviderItem { public: QCAProvider *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; } QCAProvider *(*createProvider)() = (QCAProvider *(*)())s; QCAProvider *p = createProvider(); if(!p) { delete lib; return 0; } ProviderItem *i = new ProviderItem(lib, p); i->fname = fname; return i; } static ProviderItem *fromClass(QCAProvider *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, QCAProvider *_p) { lib = _lib; p = _p; init_done = false; } }; static TQPtrList providerList; static bool qca_init = false; static bool plugin_have(const TQString &fname) { TQPtrListIterator 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() != QCA_PLUGIN_VERSION) { delete i; continue; } providerList.append(i); } } } static void plugin_addClass(QCAProvider *p) { ProviderItem *i = ProviderItem::fromClass(p); providerList.prepend(i); } static void plugin_unloadall() { providerList.clear(); } static int plugin_caps() { int caps = 0; TQPtrListIterator it(providerList); for(ProviderItem *i; (i = it.current()); ++it) caps |= i->p->capabilities(); return caps; } TQString QCA::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 QCA::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 QCA::init() { if(qca_init) return; qca_init = true; providerList.setAutoDelete(true); } bool QCA::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 QCA::insertProvider(QCAProvider *p) { plugin_addClass(p); } void QCA::unloadAllPlugins() { plugin_unloadall(); } static void *getContext(int cap) { init(); // this call will also trip a scan for new plugins if needed if(!QCA::isSupported(cap)) return 0; TQPtrListIterator 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(); } QCA_HashContext *c; }; Hash::Hash(QCA_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; } QCA_CipherContext *c; int dir; int mode; TQByteArray key, iv; bool err; }; Cipher::Cipher(QCA_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((QCA_HashContext *)getContext(CAP_SHA1)) { } //---------------------------------------------------------------------------- // SHA256 //---------------------------------------------------------------------------- SHA256::SHA256() :Hash((QCA_HashContext *)getContext(CAP_SHA256)) { } //---------------------------------------------------------------------------- // MD5 //---------------------------------------------------------------------------- MD5::MD5() :Hash((QCA_HashContext *)getContext(CAP_MD5)) { } //---------------------------------------------------------------------------- // BlowFish //---------------------------------------------------------------------------- BlowFish::BlowFish(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad) :Cipher((QCA_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((QCA_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((QCA_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((QCA_CipherContext *)getContext(CAP_AES256), dir, mode, key, iv, pad) { } //---------------------------------------------------------------------------- // RSAKey //---------------------------------------------------------------------------- class RSAKey::Private { public: Private() { c = 0; } ~Private() { delete c; } QCA_RSAKeyContext *c; }; RSAKey::RSAKey() { d = new Private; d->c = (QCA_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::tqfromLatin1(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; } QCA_CertContext *c; }; Cert::Cert() { d = new Private; d->c = (QCA_CertContext *)getContext(CAP_X509); } Cert::Cert(const Cert &from) { d = new Private; *this = from; } Cert & Cert::operator=(const Cert &from) { delete d->c; d->c = from.d->c->clone(); return *this; } Cert::~Cert() { delete d; } void Cert::fromContext(QCA_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 list = d->c->subject(); CertProperties props; for(TQValueList::ConstIterator it = list.begin(); it != list.end(); ++it) props[(*it).var] = (*it).val; return props; } CertProperties Cert::issuer() const { TQValueList list = d->c->issuer(); CertProperties props; for(TQValueList::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::tqfromLatin1(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 = (QCA_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; 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; QCA_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 store; }; TLS::TLS(TQObject *tqparent) :TQObject(tqparent) { 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 &store) { // convert the cert list into a context list d->store.clear(); TQPtrListIterator 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, TQT_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, TQT_SLOT(update())); return true; } void TLS::close() { if(!d->handshaken || d->closing) return; d->closing = true; TQTimer::singleShot(0, this, TQT_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 QCA::TLS::HostMismatch; else return d->c->validityResult(); } void TLS::update() { bool force_read = false; bool eof = false; bool done = false; TQGuardedPtr self = this; if(d->closing) { TQByteArray a; int r = d->c->shutdown(d->from_net, &a); d->from_net.resize(0); if(r == QCA_TLSContext::Error) { reset(); error(ErrHandshake); return; } if(r == QCA_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 == QCA_TLSContext::Error) { reset(); error(ErrHandshake); return; } d->appendArray(&d->to_net, a); if(r == QCA_TLSContext::Success) { QCA_CertContext *cc = d->c->peerCertificate(); if(cc && !d->host.isEmpty() && d->c->validityResult() == QCA::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 = (QCA_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; QCA_SASLContext *c; TQHostAddress localAddr, remoteAddr; int localPort, remotePort; TQByteArray stepData; bool allowCSF; bool first, server; TQByteArray inbuf, outbuf; }; SASL::SASL(TQObject *tqparent) :TQObject(tqparent) { 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) { QCA_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, TQT_SLOT(tryAgain())); return true; } bool SASL::startServer(const TQString &service, const TQString &host, const TQString &realm, TQStringList *mechlist) { QCA_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 == QCA_SASLContext::Success) authenticated(); else if(r == QCA_SASLContext::Continue) nextStep(d->c->result()); else if(r == QCA_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 == QCA_SASLContext::Error) { error(ErrAuth); return; } else if(r == QCA_SASLContext::Continue) { d->tried = false; nextStep(d->c->result()); return; } else if(r == QCA_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 == QCA_SASLContext::Error) { error(ErrAuth); return; } else if(r == QCA_SASLContext::NeedParams) { //d->tried = false; QCA_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 == QCA_SASLContext::Error) { error(ErrAuth); return; } else if(r == QCA_SASLContext::NeedParams) { //d->tried = false; QCA_SASLNeedParams np = d->c->clientParamsNeeded(); needParams(np.user, np.authzid, np.pass, np.realm); return; } d->tried = false; //else if(r == QCA_SASLContext::Continue) { nextStep(d->c->result()); // return; //} } } if(r == QCA_SASLContext::Success) authenticated(); else if(r == QCA_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 "qca.moc"