Logo Search packages:      
Sourcecode: qca version File versions  Download package

qca.cpp

/*
 * qca.cpp - Qt 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include"qca.h"

#include<qptrlist.h>
#include<qdir.h>
#include<qfileinfo.h>
#include<qstringlist.h>
#include<qlibrary.h>
#include<qtimer.h>
#include<qhostaddress.h>
#include<qapplication.h>
#include<qguardedptr.h>
#include<stdlib.h>
#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;

00045 class ProviderItem
{
public:
      QCAProvider *p;
      QString fname;

      static ProviderItem *load(const QString &fname)
      {
            QLibrary *lib = new QLibrary(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:
      QLibrary *lib;
      bool init_done;

      ProviderItem(QLibrary *_lib, QCAProvider *_p)
      {
            lib = _lib;
            p = _p;
            init_done = false;
      }
};

static QPtrList<ProviderItem> providerList;
static bool qca_init = false;

static bool plugin_have(const QString &fname)
{
      QPtrListIterator<ProviderItem> it(providerList);
      for(ProviderItem *i; (i = it.current()); ++it) {
            if(i->fname == fname)
                  return true;
      }
      return false;
}

static void plugin_scan()
{
      QStringList dirs = QApplication::libraryPaths();
      for(QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
            QDir libpath(*it);
            QDir dir(libpath.filePath("crypto"));
            if(!dir.exists())
                  continue;

            QStringList list = dir.entryList();
            for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
                  QFileInfo fi(dir.filePath(*it));
                  if(fi.isDir())
                        continue;
                  if(fi.extension() != PLUGIN_EXT)
                        continue;
                  QString 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;
      QPtrListIterator<ProviderItem> it(providerList);
      for(ProviderItem *i; (i = it.current()); ++it)
            caps |= i->p->capabilities();
      return caps;
}

QString QCA::arrayToHex(const QByteArray &a)
{
      QString out;
      for(int n = 0; n < (int)a.size(); ++n) {
            QString str;
            str.sprintf("%02x", (uchar)a[n]);
            out.append(str);
      }
      return out;
}

QByteArray QCA::hexToArray(const QString &str)
{
      QByteArray 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;

      QPtrListIterator<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
//----------------------------------------------------------------------------
00256 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 QByteArray &a)
{
      d->c->update(a.data(), a.size());
}

QByteArray Hash::final()
{
      QByteArray buf;
      d->c->final(&buf);
      return buf;
}


//----------------------------------------------------------------------------
// Cipher
//----------------------------------------------------------------------------
00322 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;
      QByteArray key, iv;
      bool err;
};

Cipher::Cipher(QCA_CipherContext *c, int dir, int mode, const QByteArray &key, const QByteArray &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;
}

QByteArray Cipher::dyn_generateKey(int size) const
{
      QByteArray buf;
      if(size != -1)
            buf.resize(size);
      else
            buf.resize(d->c->keySize());
      if(!d->c->generateKey(buf.data(), size))
            return QByteArray();
      return buf;
}

QByteArray Cipher::dyn_generateIV() const
{
      QByteArray buf(d->c->blockSize());
      if(!d->c->generateIV(buf.data()))
            return QByteArray();
      return buf;
}

void Cipher::reset(int dir, int mode, const QByteArray &key, const QByteArray &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 QByteArray &a)
{
      if(d->err)
            return false;

      if(!a.isEmpty()) {
            if(!d->c->update(a.data(), a.size())) {
                  d->err = true;
                  return false;
            }
      }
      return true;
}

QByteArray Cipher::final(bool *ok)
{
      if(ok)
            *ok = false;
      if(d->err)
            return QByteArray();

      QByteArray out;
      if(!d->c->final(&out)) {
            d->err = true;
            return QByteArray();
      }
      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 QByteArray &key, const QByteArray &iv, bool pad)
:Cipher((QCA_CipherContext *)getContext(CAP_BlowFish), dir, mode, key, iv, pad)
{
}


//----------------------------------------------------------------------------
// TripleDES
//----------------------------------------------------------------------------
TripleDES::TripleDES(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
:Cipher((QCA_CipherContext *)getContext(CAP_TripleDES), dir, mode, key, iv, pad)
{
}


//----------------------------------------------------------------------------
// AES128
//----------------------------------------------------------------------------
AES128::AES128(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
:Cipher((QCA_CipherContext *)getContext(CAP_AES128), dir, mode, key, iv, pad)
{
}


//----------------------------------------------------------------------------
// AES256
//----------------------------------------------------------------------------
AES256::AES256(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
:Cipher((QCA_CipherContext *)getContext(CAP_AES256), dir, mode, key, iv, pad)
{
}


//----------------------------------------------------------------------------
// RSAKey
//----------------------------------------------------------------------------
00512 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();
}

QByteArray RSAKey::toDER(bool publicOnly) const
{
      QByteArray out;
      if(!d->c->toDER(&out, publicOnly))
            return QByteArray();
      return out;
}

bool RSAKey::fromDER(const QByteArray &a)
{
      return d->c->createFromDER(a.data(), a.size());
}

QString RSAKey::toPEM(bool publicOnly) const
{
      QByteArray out;
      if(!d->c->toPEM(&out, publicOnly))
            return QByteArray();

      QCString cs;
      cs.resize(out.size()+1);
      memcpy(cs.data(), out.data(), out.size());
      return QString::fromLatin1(cs);
}

bool RSAKey::fromPEM(const QString &str)
{
      QCString cs = str.latin1();
      QByteArray 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 QByteArray &a, QByteArray *b, bool oaep) const
{
      QByteArray out;
      if(!d->c->encrypt(a, &out, oaep))
            return false;
      *b = out;
      return true;
}

bool RSAKey::decrypt(const QByteArray &a, QByteArray *b, bool oaep) const
{
      QByteArray 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 QByteArray &a, QByteArray *b, bool oaep) const
{
      if(v_key.isNull())
            return false;
      return v_key.encrypt(a, b, oaep);
}

bool RSA::decrypt(const QByteArray &a, QByteArray *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
//----------------------------------------------------------------------------
00675 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();
}

QString Cert::commonName() const
{
      CertProperties props = subject();
      return props["CN"];
}

QString Cert::serialNumber() const
{
      return d->c->serialNumber();
}

QString Cert::subjectString() const
{
      return d->c->subjectString();
}

QString Cert::issuerString() const
{
      return d->c->issuerString();
}

CertProperties Cert::subject() const
{
      QValueList<QCA_CertProperty> list = d->c->subject();
      CertProperties props;
      for(QValueList<QCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
            props[(*it).var] = (*it).val;
      return props;
}

CertProperties Cert::issuer() const
{
      QValueList<QCA_CertProperty> list = d->c->issuer();
      CertProperties props;
      for(QValueList<QCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
            props[(*it).var] = (*it).val;
      return props;
}

QDateTime Cert::notBefore() const
{
      return d->c->notBefore();
}

QDateTime Cert::notAfter() const
{
      return d->c->notAfter();
}

QByteArray Cert::toDER() const
{
      QByteArray out;
      if(!d->c->toDER(&out))
            return QByteArray();
      return out;
}

bool Cert::fromDER(const QByteArray &a)
{
      return d->c->createFromDER(a.data(), a.size());
}

QString Cert::toPEM() const
{
      QByteArray out;
      if(!d->c->toPEM(&out))
            return QByteArray();

      QCString cs;
      cs.resize(out.size()+1);
      memcpy(cs.data(), out.data(), out.size());
      return QString::fromLatin1(cs);
}

bool Cert::fromPEM(const QString &str)
{
      QCString cs = str.latin1();
      QByteArray a(cs.length());
      memcpy(a.data(), cs.data(), a.size());
      return d->c->createFromPEM(a.data(), a.size());
}


//----------------------------------------------------------------------------
// TLS
//----------------------------------------------------------------------------
00812 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(QByteArray *a, const QByteArray &b)
      {
            int oldsize = a->size();
            a->resize(oldsize + b.size());
            memcpy(a->data() + oldsize, b.data(), b.size());
      }

      Cert cert;
      QCA_TLSContext *c;
      QByteArray in, out, to_net, from_net;
      int bytesEncoded;
      bool tryMore;
      bool handshaken;
      QString host;
      bool hostMismatch;
      bool closing;

      Cert ourCert;
      RSAKey ourKey;
      QPtrList<QCA_CertContext> store;
};

TLS::TLS(QObject *parent)
:QObject(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 QPtrList<Cert> &store)
{
      // convert the cert list into a context list
      d->store.clear();
      QPtrListIterator<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 QString &host)
{
      d->reset();
      d->host = host;

      if(!d->c->startClient(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
            return false;
      QTimer::singleShot(0, this, 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;
      QTimer::singleShot(0, this, SLOT(update()));
      return true;
}

void TLS::close()
{
      if(!d->handshaken || d->closing)
            return;

      d->closing = true;
      QTimer::singleShot(0, this, SLOT(update()));
}

bool TLS::isHandshaken() const
{
      return d->handshaken;
}

void TLS::write(const QByteArray &a)
{
      d->appendArray(&d->out, a);
      update();
}

QByteArray TLS::read()
{
      QByteArray a = d->in.copy();
      d->in.resize(0);
      return a;
}

void TLS::writeIncoming(const QByteArray &a)
{
      d->appendArray(&d->from_net, a);
      update();
}

QByteArray TLS::readOutgoing()
{
      QByteArray a = d->to_net.copy();
      d->to_net.resize(0);
      return a;
}

QByteArray TLS::readUnprocessed()
{
      QByteArray 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;
      QGuardedPtr<TLS> self = this;

      if(d->closing) {
            QByteArray 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) {
                  QByteArray 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;
                        QByteArray 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) {
                        QByteArray 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
//----------------------------------------------------------------------------
QString saslappname = "qca";
01095 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;
      QString ext_authid;
      int ext_ssf;

      bool tried;
      QCA_SASLContext *c;
      QHostAddress localAddr, remoteAddr;
      int localPort, remotePort;
      QByteArray stepData;
      bool allowCSF;
      bool first, server;

      QByteArray inbuf, outbuf;
};

SASL::SASL(QObject *parent)
:QObject(parent)
{
      d = new Private;
      reset();
}

SASL::~SASL()
{
      delete d;
}

void SASL::setAppName(const QString &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 QString &authid)
{
      d->ext_authid = authid;
}

void SASL::setExternalSSF(int x)
{
      d->ext_ssf = x;
}

void SASL::setLocalAddr(const QHostAddress &addr, Q_UINT16 port)
{
      d->localAddr = addr;
      d->localPort = port;
}

void SASL::setRemoteAddr(const QHostAddress &addr, Q_UINT16 port)
{
      d->remoteAddr = addr;
      d->remotePort = port;
}

bool SASL::startClient(const QString &service, const QString &host, const QStringList &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;
      QTimer::singleShot(0, this, SLOT(tryAgain()));
      return true;
}

bool SASL::startServer(const QString &service, const QString &host, const QString &realm, QStringList *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 QString &mech)
{
      int r = d->c->serverFirstStep(mech, 0);
      handleServerFirstStep(r);
}

void SASL::putServerFirstStep(const QString &mech, const QByteArray &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 QByteArray &stepData)
{
      d->stepData = stepData.copy();
      tryAgain();
}

void SASL::setUsername(const QString &user)
{
      d->c->setClientParams(&user, 0, 0, 0);
}

void SASL::setAuthzid(const QString &authzid)
{
      d->c->setClientParams(0, &authzid, 0, 0);
}

void SASL::setPassword(const QString &pass)
{
      d->c->setClientParams(0, 0, &pass, 0);
}

void SASL::setRealm(const QString &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;
                  }

                  QString mech = d->c->mech();
                  const QByteArray *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 QByteArray &a)
{
      QByteArray 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());
}

QByteArray SASL::read()
{
      QByteArray a = d->inbuf.copy();
      d->inbuf.resize(0);
      return a;
}

void SASL::writeIncoming(const QByteArray &a)
{
      QByteArray 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();
}

QByteArray SASL::readOutgoing()
{
      QByteArray a = d->outbuf.copy();
      d->outbuf.resize(0);
      return a;
}

Generated by  Doxygen 1.6.0   Back to index