diff --git a/TODO b/TODO index 0a035e4e..001f001b 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,6 @@ * cipher: option to specify size for genkey * cert: properly check hostnames with wildcards +* ssl: error signal * sasl client * sasl server diff --git a/plugins/qcaopenssl.cpp b/plugins/qcaopenssl.cpp index 5543a2fa..c750c871 100644 --- a/plugins/qcaopenssl.cpp +++ b/plugins/qcaopenssl.cpp @@ -20,6 +20,7 @@ #endif // FIXME: use openssl for entropy instead of stdlib +// FIXME: handle return value of BIO_new #include static bool seeded = false; class QRandom diff --git a/src/qca.cpp b/src/qca.cpp index 0cf1e972..fd2b0480 100644 --- a/src/qca.cpp +++ b/src/qca.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include"qcaprovider.h" #include #include @@ -813,6 +815,24 @@ void SSL::ctx_readyReadOutgoing() class SASL::Private { public: + Private() + { + c = (QCA_SASLContext *)getContext(CAP_SASL); + localPort = -1; + remotePort = -1; + } + + ~Private() + { + delete c; + } + + QCA_SASLContext *c; + bool allowPlain; + QHostAddress localAddr, remoteAddr; + int localPort, remotePort; + QByteArray stepData; + bool first; }; SASL::SASL(QObject *parent) @@ -829,53 +849,126 @@ SASL::~SASL() // options bool SASL::allowPlainText() const { + return d->allowPlain; } -void SASL::setAllowPlainText(bool) +void SASL::setAllowPlainText(bool b) { + d->allowPlain = b; } 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 &methods) { + if(!d->c->startClient(service.latin1(), host, methods, d->localAddr, d->localPort, d->remoteAddr, d->remotePort, d->allowPlain)) + return false; + d->first = true; + QTimer::singleShot(0, this, SLOT(tryAgain())); + return true; } -bool SASL::startServer(const QString &service, const QString &host, const QString &realm, const QString &method) +/*bool SASL::startServer(const QString &service, const QString &host, const QString &realm, const QString &method) { + return false; } bool SASL::startServer(const QString &service, const QString &host, const QString &realm, const QString &method, const QByteArray &clientInit) { -} + return false; +}*/ void SASL::putIncomingStep(const QByteArray &stepData) { + d->stepData = stepData; + tryAgain(); } void SASL::putAuthname(const QString &auth) { + d->c->setAuthname(auth); + QTimer::singleShot(0, this, SLOT(tryAgain())); } void SASL::putUsername(const QString &user) { + d->c->setUsername(user); + QTimer::singleShot(0, this, SLOT(tryAgain())); } void SASL::putPassword(const QString &pass) { + d->c->setPassword(pass); + QTimer::singleShot(0, this, SLOT(tryAgain())); } void SASL::putRealm(const QString &realm) { + d->c->setRealm(realm); + QTimer::singleShot(0, this, SLOT(tryAgain())); } -void SASL::write(const QByteArray &a) +void SASL::tryAgain() +{ + int r; + if(d->first) { + char *out, *meth; + unsigned int outlen; + QCA_SASLNeedParams np; + r = d->c->firstStep(&meth, &out, &outlen, &np); + if(r == QCA_SASLContext::NeedParams) { + needParams(np.auth, np.user, np.pass, np.realm); + return; + } + QString method = meth; + free(meth); + + QByteArray buf; + bool useClientInit = false; + if(out) { + buf.resize(outlen); + memcpy(buf.data(), out, buf.size()); + free(out); + useClientInit = true; + } + clientFirstStep(method, useClientInit, buf); + d->first = false; + } + else { + char *out; + unsigned int outlen; + QCA_SASLNeedParams np; + r = d->c->nextStep(d->stepData.data(), d->stepData.size(), &out, &outlen, &np); + if(r == QCA_SASLContext::NeedParams) { + needParams(np.auth, np.user, np.pass, np.realm); + return; + } + else if(r == QCA_SASLContext::Continue) { + QByteArray buf(outlen); + memcpy(buf.data(), out, buf.size()); + free(out); + nextStep(buf); + return; + } + } + + if(r == QCA_SASLContext::Success) + authenticated(true); + else if(r == QCA_SASLContext::Error) + authenticated(false); +} + +/*void SASL::write(const QByteArray &a) { } @@ -889,4 +982,4 @@ void SASL::writeIncoming(const QByteArray &a) QByteArray SASL::readOutgoing() { -} +}*/ diff --git a/src/qca.h b/src/qca.h index 2ddb5c94..4ede1a94 100644 --- a/src/qca.h +++ b/src/qca.h @@ -332,8 +332,8 @@ namespace QCA // initialize bool startClient(const QString &service, const QString &host, const QStringList &methods); - bool startServer(const QString &service, const QString &host, const QString &realm, const QString &method); - bool startServer(const QString &service, const QString &host, const QString &realm, const QString &method, const QByteArray &clientInit); + //bool startServer(const QString &service, const QString &host, const QString &realm, const QString &method); + //bool startServer(const QString &service, const QString &host, const QString &realm, const QString &method, const QByteArray &clientInit); // authentication void putIncomingStep(const QByteArray &stepData); @@ -343,27 +343,27 @@ namespace QCA void putRealm(const QString &realm); // plain (application side) - void write(const QByteArray &a); + /*void write(const QByteArray &a); QByteArray read(); // encoded (socket side) void writeIncoming(const QByteArray &a); - QByteArray readOutgoing(); + QByteArray readOutgoing();*/ signals: // for authentication void clientFirstStep(const QString &method, bool useClientInit, const QByteArray &clientInit); void nextStep(const QByteArray &stepData); - void needAuthname(); - void needUsername(); - void needPassword(); - void needRealm(); - void authenticated(); + void needParams(bool auth, bool user, bool pass, bool realm); + void authenticated(bool); // for security layer void readyRead(); void readyReadOutgoing(); + private slots: + void tryAgain(); + private: class Private; Private *d; diff --git a/src/qcaprovider.h b/src/qcaprovider.h index db61dd4f..97667805 100644 --- a/src/qcaprovider.h +++ b/src/qcaprovider.h @@ -119,4 +119,24 @@ signals: void readyReadOutgoing(); }; +struct QCA_SASLNeedParams +{ + bool auth, user, pass, realm; +}; + +class QCA_SASLContext +{ +public: + enum { Success, Error, NeedParams, Continue }; + virtual ~QCA_SASLContext() {} + + virtual bool startClient(const char *service, const QString &host, const QStringList &methods, const QHostAddress &localAddr, int localPort, const QHostAddress &remoteAddr, int remotePort, bool allowPlain); + virtual int firstStep(char **meth, char **out, unsigned int *outlen, QCA_SASLNeedParams *np)=0; + virtual int nextStep(const char *in, unsigned int len, char **out, unsigned int *outlen, QCA_SASLNeedParams *np)=0; + virtual void setAuthname(const QString &)=0; + virtual void setUsername(const QString &)=0; + virtual void setPassword(const QString &)=0; + virtual void setRealm(const QString &)=0; +}; + #endif