aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Fabio Bas2010-02-15 19:57:33 +0000
committerGravatar Fabio Bas2010-02-15 19:57:33 +0000
commitc592bab456c2acf4aea91d1a3716d78d4775f312 (patch)
tree1a7c191046f4993bfe181c19143d15a043ac90fe /src
parentAliaseditor code cleaning (diff)
downloadKVIrc-c592bab456c2acf4aea91d1a3716d78d4775f312.tar.gz
KVIrc-c592bab456c2acf4aea91d1a3716d78d4775f312.tar.bz2
KVIrc-c592bab456c2acf4aea91d1a3716d78d4775f312.zip
reworked sasl stuff, added dh-blowfish auth method
git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@3970 17fca916-40b9-46aa-a4ea-0a15b648b75c
Diffstat (limited to 'src')
-rw-r--r--src/kvilib/CMakeLists.txt1
-rw-r--r--src/kvilib/net/kvi_sasl.cpp198
-rw-r--r--src/kvilib/net/kvi_sasl.h61
-rw-r--r--src/kvirc/kernel/kvi_ircconnection.cpp64
-rw-r--r--src/kvirc/kernel/kvi_ircconnection.h7
-rw-r--r--src/kvirc/sparser/kvi_numeric.h4
-rw-r--r--src/kvirc/sparser/kvi_sp_literal.cpp8
7 files changed, 325 insertions, 18 deletions
diff --git a/src/kvilib/CMakeLists.txt b/src/kvilib/CMakeLists.txt
index 6e89f40d5..20c5baac9 100644
--- a/src/kvilib/CMakeLists.txt
+++ b/src/kvilib/CMakeLists.txt
@@ -105,6 +105,7 @@ SET(kvilib_SRCS
net/kvi_dns.cpp
net/kvi_http.cpp
net/kvi_netutils.cpp
+ net/kvi_sasl.cpp
net/kvi_socket.cpp
net/kvi_ssl.cpp
net/kvi_url.cpp
diff --git a/src/kvilib/net/kvi_sasl.cpp b/src/kvilib/net/kvi_sasl.cpp
new file mode 100644
index 000000000..66e719e22
--- /dev/null
+++ b/src/kvilib/net/kvi_sasl.cpp
@@ -0,0 +1,198 @@
+//=============================================================================
+//
+// File : kvi_sasl.cpp
+// Creation date : Mon Feb 14 2010 19:36:12 CEST by Fabio Bas
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2010 Fabio Bas (ctrlaltca at gmail dot com)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+
+
+#include "kvi_sasl.h"
+
+#include "kvi_malloc.h"
+
+#ifdef COMPILE_SSL_SUPPORT
+
+#include <openssl/blowfish.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <arpa/inet.h>
+
+#endif
+
+
+namespace KviSASL
+{
+
+ bool plainMethod(KviStr & szIn, KviStr & szOut, QByteArray & baNick, QByteArray & baPass)
+ {
+ if(szIn=="+")
+ {
+ int answerLen = 3 + (2 * baNick.size()) + baPass.size();
+ char * answer = (char *) kvi_malloc(answerLen);
+ char * answer2 = answer;
+
+ memcpy(answer, baNick.data(), baNick.size());
+ answer+=baNick.size();
+ memset(answer, 0, 1);
+ answer++;
+
+ memcpy(answer, baNick.data(), baNick.size());
+ answer+=baNick.size();
+ memset(answer, 0, 1);
+ answer++;
+
+ memcpy(answer, baPass.data(), baPass.size());
+ answer+=baPass.size();
+ memset(answer, 0, 1);
+ answer++;
+
+ szOut.bufferToBase64(answer2,answerLen);
+ kvi_free(answer2);
+
+ return true;
+ }
+ return false;
+ }
+
+#ifdef COMPILE_SSL_SUPPORT
+ bool dh_blowfishMethod(KviStr & szIn, KviStr & szOut, QByteArray & baNick, QByteArray & baPass)
+ {
+ /*
+ * The format of the auth token is quite complex; the server sends us 3 strings:
+ * p - a prime number
+ * g - a generator number, tipically 2 or 5 are used.
+ * y - the server-generated public key
+ * These 3 strings are null-terminated and codified as pascal strings (they are prefixed
+ * with a 16-bit lenght identifiedr in "network" big-endian order)
+ * Then, the 3 strings are concatenated and base-64 encoded.
+ */
+
+ BF_KEY key;
+ quint16 size, pKlen;
+ int secretLen;
+ unsigned char *secret = NULL, *pubKey = NULL;
+ char * tmpBuf;
+ DH * dh = DH_new();
+ int len = szIn.base64ToBuffer(&tmpBuf,false);
+
+ if(len < 7) return false;
+
+ // extract p
+ size = ntohs(*(unsigned int*)tmpBuf);
+ tmpBuf+=2;
+ len-=2;
+ if(size > len) return false;
+
+ if(!(dh->p = BN_bin2bn((unsigned char*) tmpBuf, size, NULL)))
+ return false;
+
+ tmpBuf+=size;
+ len-=size;
+
+ // extract g
+ size = ntohs(*(unsigned int*)tmpBuf);
+ tmpBuf+=2;
+ len-=2;
+ if(size > len) return false;
+
+ if(!(dh->g = BN_bin2bn((unsigned char*) tmpBuf, size, NULL)))
+ return false;
+
+ tmpBuf+=size;
+ len-=size;
+
+ // extract y
+ size = ntohs(*(unsigned int*)tmpBuf);
+ tmpBuf+=2;
+ len-=2;
+ if(size > len) return false;
+
+ // create our keys and extract shared secret
+ // note: any memory checking tool (as valgrind) will complain on this call. blame openssl
+ if(!DH_generate_key(dh))
+ return false;
+
+ secret=(unsigned char *) kvi_malloc(DH_size(dh));
+ // note: any memory checking tool (as valgrind) will complain on this call. blame openssl
+ if(-1 == (secretLen = DH_compute_key(secret, BN_bin2bn((unsigned char*) tmpBuf, size, NULL), dh)))
+ return false;
+
+ pKlen=BN_num_bytes(dh->pub_key);
+ pubKey = (unsigned char *) kvi_malloc(pKlen);
+ BN_bn2bin(dh->pub_key, pubKey);
+
+ //create crypto buffers
+ int passLen = baPass.size() + ((8 -( baPass.size() % 8)) % 8);
+ int passC = 0;
+ unsigned char *passIn = (unsigned char *) kvi_malloc(passLen);
+ unsigned char *passOut = (unsigned char *) kvi_malloc(passLen);
+
+ memset(passIn, 0, passLen);
+ memset(passOut, 0, passLen);
+ memcpy(passIn, baPass.data(), baPass.size());
+
+ // crypt our password
+ BF_set_key(&key, secretLen, secret);
+
+ for (passC=0; passC < passLen; passC += 8)
+ BF_ecb_encrypt(passIn + passC, passOut + passC, &key, BF_ENCRYPT);
+
+ /*
+ * Build up the answer
+ * The format of the auth answer is quite complex, and formed by the byte concatenation of:
+ * 1) a 16 bit integer containing the byte length of our public key
+ * 2) our public key
+ * 3) our username (nickname), null-terminated
+ * 4) our password, crypted using blowfish in ecb mode and the dh secret as the blowfish key
+ * Then, the answer is to be base64 encoded.
+ */
+
+ int answerLen = 2 + pKlen + baNick.size() + 1 + passLen;
+ char * answer = (char *) malloc(answerLen);
+ char * answer2 = answer;
+ *((unsigned int *)answer) = htons(pKlen);
+ answer+=2;
+ memcpy(answer, pubKey, pKlen);
+ answer+=pKlen;
+ memcpy(answer, baNick.data(), baNick.size());
+ answer+=baNick.size();
+ memset(answer, 0, 1);
+ answer++;
+ memcpy(answer, passOut, passLen);
+ szOut.bufferToBase64(answer2,answerLen);
+
+ //clean up
+ kvi_free(secret);
+ kvi_free(pubKey);
+ kvi_free(passIn);
+ kvi_free(passOut);
+
+ return true;
+ }
+#else
+ bool dh_blowfishMethod(KviStr & szIn, KviStr & szOut, QByteArray & baNick, QByteArray & baPass)
+ {
+ return false;
+ }
+#endif
+
+};
diff --git a/src/kvilib/net/kvi_sasl.h b/src/kvilib/net/kvi_sasl.h
new file mode 100644
index 000000000..9dd660e88
--- /dev/null
+++ b/src/kvilib/net/kvi_sasl.h
@@ -0,0 +1,61 @@
+#ifndef _KVI_SASL_H_
+#define _KVI_SASL_H_
+//=============================================================================
+//
+// File : kvi_sasl.h
+// Creation date : Mon Feb 14 2010 19:36:12 CEST by Fabio Bas
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2010 Fabio Bas (ctrlaltca at gmail dot com)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "kvi_settings.h"
+#include "kvi_string.h"
+
+/**
+* \namespace KviSASL
+* \brief This namespace implement some SASL authentication methods.
+*
+* Currently implementhed methods are PLAIN and DH-BLOWFISH
+*/
+
+namespace KviSASL
+{
+ /**
+ * \brief Create the auth message for PLAIN authentication
+ * \param szIn The server-provided token
+ * \param szOut A KviStr that will be filled with the authentication message
+ * \param baNick The username
+ * \param baPass The password
+ * \return bool
+ */
+ extern KVILIB_API bool plainMethod(KviStr & szIn, KviStr & szOut, QByteArray & baNick, QByteArray & baPass);
+
+ /**
+ * \brief Create the auth message for DH-BLOWFISH authentication
+ * \param szIn The server-provided token
+ * \param szOut A KviStr that will be filled with the authentication message
+ * \param baNick The username
+ * \param baPass The password
+ * \return bool
+ */
+ extern KVILIB_API bool dh_blowfishMethod(KviStr & szIn, KviStr & szOut, QByteArray & baNick, QByteArray & baPass);
+
+};
+
+#endif //_KVI_SASL_H_
diff --git a/src/kvirc/kernel/kvi_ircconnection.cpp b/src/kvirc/kernel/kvi_ircconnection.cpp
index a614e2eeb..260dd5a25 100644
--- a/src/kvirc/kernel/kvi_ircconnection.cpp
+++ b/src/kvirc/kernel/kvi_ircconnection.cpp
@@ -66,6 +66,7 @@
#include "kvi_mirccntrl.h"
#include "kvi_useridentity.h"
#include "kvi_identityprofile.h"
+#include "kvi_sasl.h"
#include <QTimer>
#include <QTextCodec>
@@ -348,7 +349,6 @@ void KviIrcConnection::linkEstabilished()
void KviIrcConnection::handleCapLs()
{
- qDebug("handleCapLs");
m_pStateData->setInsideCapLs(false);
// STARTTLS support: this has to be checked first because it could imply
@@ -385,7 +385,7 @@ void KviIrcConnection::handleCapLs()
void KviIrcConnection::handleCapAck()
{
- qDebug("handleCapAck");
+ bool bUsed=false;
//SASL
if(KVI_OPTION_BOOL(KviOption_boolUseSaslIfAvailable) &&
@@ -393,14 +393,57 @@ void KviIrcConnection::handleCapAck()
serverInfo()->enabledCaps().contains("sasl",Qt::CaseInsensitive)
)
{
+ bUsed=true;
+
+#ifdef COMPILE_SSL_SUPPORT
+ sendFmtData("AUTHENTICATE DH-BLOWFISH");
+#else
sendFmtData("AUTHENTICATE PLAIN");
- //server will send us a "AUTHENTICATE +" answer; we won't wait for this extra step
- QByteArray szAuth = encodeText(target()->server()->saslNick());
- szAuth.append('\0');
- szAuth.append(encodeText(target()->server()->saslNick()));
- szAuth.append('\0');
- szAuth.append(encodeText(target()->server()->saslPass()));
- sendFmtData("AUTHENTICATE %s",szAuth.toBase64().data());
+#endif
+ }
+
+
+ if(!bUsed) endCapLs();
+}
+
+void KviIrcConnection::handleAuthenticate(KviStr & szAuth)
+{
+ //SASL
+ if(KVI_OPTION_BOOL(KviOption_boolUseSaslIfAvailable) &&
+ target()->server()->enabledSASL() &&
+ serverInfo()->enabledCaps().contains("sasl",Qt::CaseInsensitive)
+ )
+ {
+ QByteArray szNick = encodeText(target()->server()->saslNick());
+ QByteArray szPass = encodeText(target()->server()->saslPass());
+ if(szAuth=="+")
+ {
+ //PLAIN
+ KviStr szOut;
+ if(KviSASL::plainMethod(szAuth,
+ szOut,
+ szNick,
+ szPass
+ ))
+ {
+ sendFmtData("AUTHENTICATE %s",szOut.ptr());
+ } else {
+ sendFmtData("AUTHENTICATE *");
+ }
+ } else {
+ //DH-BLOWFISH sasl auth
+ KviStr szOut;
+ if(KviSASL::dh_blowfishMethod(szAuth,
+ szOut,
+ szNick,
+ szPass
+ ))
+ {
+ sendFmtData("AUTHENTICATE %s",szOut.ptr());
+ } else {
+ sendFmtData("AUTHENTICATE *");
+ }
+ }
}
endCapLs();
@@ -408,19 +451,16 @@ void KviIrcConnection::handleCapAck()
void KviIrcConnection::handleCapNak()
{
- qDebug("handleCapNak");
endCapLs();
}
void KviIrcConnection::endCapLs()
{
- sendFmtData("CAP END");
loginToIrcServer();
}
void KviIrcConnection::handleFailedCapLs()
{
- qDebug("handleFailedCapLs");
m_pStateData->setInsideCapLs(false);
loginToIrcServer();
}
diff --git a/src/kvirc/kernel/kvi_ircconnection.h b/src/kvirc/kernel/kvi_ircconnection.h
index 0928244e3..ee8b4efc0 100644
--- a/src/kvirc/kernel/kvi_ircconnection.h
+++ b/src/kvirc/kernel/kvi_ircconnection.h
@@ -68,6 +68,7 @@ class KviNotifyListManager;
class KviDns;
class KviUserIdentity;
class KviIdentityProfileSet;
+class KviStr;
/**
@@ -723,6 +724,12 @@ protected:
void serverInfoReceived(const QString & szServerName, const QString & szUserModes, const QString & szChanModes);
/**
+ * \brief Called when AUTHENTICATE answer is received
+ * \return void
+ */
+ void handleAuthenticate(KviStr & szResponse);
+
+ /**
* \brief Called when CAP LS answer is received
* \return void
*/
diff --git a/src/kvirc/sparser/kvi_numeric.h b/src/kvirc/sparser/kvi_numeric.h
index 4692d87be..a09ecd5e2 100644
--- a/src/kvirc/sparser/kvi_numeric.h
+++ b/src/kvirc/sparser/kvi_numeric.h
@@ -376,9 +376,9 @@
#define RPL_SASLLOGIN 900 /* :jaguar.test 900 jilles jilles!jilles@localhost.stack.nl jilles :You are now logged in as jilles. */
#define RPL_SASLSUCCESS 903 /* :jaguar.test 903 jilles :SASL authentication successful */
#define RPL_SASLFAILED 904 /* :lindbohm.freenode.net 904 * :SASL authentication failed */
-#define RPL_SASLERROR 905 // alternative error message
+#define RPL_SASLERROR 905 // sasl message too long
#define RPL_SASLABORT 906 // sasl authentication aborted
-#define RPL_SASLALREADYAUTH 907 // can't authenticate: already authenticated
+#define RPL_SASLALREADYAUTH 907 // You have already completed SASL authentication
///* 303 */ RPL_ISON, ":",
///* 304 */ RPL_TEXT, (char *)NULL,
diff --git a/src/kvirc/sparser/kvi_sp_literal.cpp b/src/kvirc/sparser/kvi_sp_literal.cpp
index 24ff39e8e..ed6b0e282 100644
--- a/src/kvirc/sparser/kvi_sp_literal.cpp
+++ b/src/kvirc/sparser/kvi_sp_literal.cpp
@@ -1994,7 +1994,6 @@ void KviServerParser::parseLiteralCap(KviIrcMessage *msg)
// Client2server subcommands:
// LIST, LS, REQ, CLEAR, END
- debug("Parsing literal CAP...");
QString szPrefix = msg->connection()->decodeText(msg->safePrefix());
QString szCmd = msg->connection()->decodeText(msg->safeParam(1));
QString szProtocols = msg->connection()->decodeText(msg->safeParam(2));
@@ -2038,8 +2037,9 @@ void KviServerParser::parseLiteralCap(KviIrcMessage *msg)
}
}
-void KviServerParser::parseLiteralAuthenticate(KviIrcMessage *)
+void KviServerParser::parseLiteralAuthenticate(KviIrcMessage *msg)
{
- // :prefix AUTHENTICATE +
- // we don't wait for this when authenticating, so no real handling is needed here
+ // :AUTHENTICATE +
+ KviStr szAuth(msg->safeParam(0));
+ msg->connection()->handleAuthenticate(szAuth);
} \ No newline at end of file