aboutsummaryrefslogtreecommitdiff
path: root/source/QXmppStream.cpp
diff options
context:
space:
mode:
authorManjeet Dahiya <manjeetdahiya@gmail.com>2009-10-23 19:37:01 +0000
committerManjeet Dahiya <manjeetdahiya@gmail.com>2009-10-23 19:37:01 +0000
commita02e9470dea63957d703931ede50934cdac15882 (patch)
treed48f3aec31a9bc3a5fb83e864f327f3f7ba94115 /source/QXmppStream.cpp
parent2fe5cfecf1d3cf7877fcb609b603add501db8732 (diff)
downloadqxmpp-a02e9470dea63957d703931ede50934cdac15882.tar.gz
Fix for Issue 21: Implement SASL DIGEST-MD5 Authentication mechanism
Also setting SASLDigestMD5 as a default SASLAuth mechanism.
Diffstat (limited to 'source/QXmppStream.cpp')
-rw-r--r--source/QXmppStream.cpp127
1 files changed, 126 insertions, 1 deletions
diff --git a/source/QXmppStream.cpp b/source/QXmppStream.cpp
index 895072d9..9c4bd5bd 100644
--- a/source/QXmppStream.cpp
+++ b/source/QXmppStream.cpp
@@ -286,7 +286,35 @@ void QXmppStream::parser(const QByteArray& data)
}
subElement = subElement.nextSiblingElement();
}
- sendAuthPlain();
+
+ switch(getConfiguration().getSASLAuthMechanism())
+ {
+ case QXmppConfiguration::SASLPlain:
+ if(mechanisms.contains("PLAIN"))
+ {
+ sendAuthPlain();
+ break;
+ }
+ case QXmppConfiguration::SASLDigestMD5:
+ if(mechanisms.contains("DIGEST-MD5"))
+ {
+ sendAuthDigestMD5();
+ break;
+ }
+ default:
+ log(QString("Desired SASL Auth mechanism not available trying the available ones"));
+ if(mechanisms.contains("DIGEST-MD5"))
+ sendAuthDigestMD5();
+ else if(mechanisms.contains("PLAIN"))
+ sendAuthPlain();
+ else
+ {
+ log(QString("SASL Auth mechanism not available"));
+ disconnect();
+ return;
+ }
+ break;
+ }
}
if(nodeRecv.firstChildElement("bind").
@@ -317,6 +345,10 @@ void QXmppStream::parser(const QByteArray& data)
log(QString("Authenticated"));
sendStartStream();
}
+ else if(nodeRecv.tagName() == "challenge")
+ {
+ sendAuthDigestMD5Response(nodeRecv.text());
+ }
}
else if(ns == ns_client)
{
@@ -603,6 +635,99 @@ void QXmppStream::sendAuthPlain()
sendToServer(data);
}
+void QXmppStream::sendAuthDigestMD5()
+{
+ QByteArray packet = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>";
+ sendToServer(packet);
+}
+
+// challenge is BASE64 encoded string
+void QXmppStream::sendAuthDigestMD5Response(const QString& challenge)
+{
+ QByteArray ba = QByteArray::fromBase64(challenge.toUtf8());
+
+ //log(ba);
+
+ ba.replace('"', QString(""));
+ QList<QByteArray> list = ba.split(',');
+
+ QMap<QByteArray, QByteArray> map;
+
+ QList<QByteArray> list2;
+ for(int i = 0; i < list.count(); ++i)
+ {
+ list2 = list.at(i).split('=');
+ if(list2.count() == 2)
+ map[list2.at(0).trimmed()] = list2.at(1).trimmed();
+ else
+ log(QString("Invalid challenge send"));
+ }
+
+ QByteArray user = getConfiguration().getUser().toUtf8();
+ QByteArray passwd = getConfiguration().getPasswd().toUtf8();
+ QByteArray domain = getConfiguration().getDomain().toUtf8();
+ QByteArray realm;
+ if(map.contains("realm"))
+ realm = map["realm"];
+
+ QByteArray response;
+
+ // First challenge
+ if(map.contains("nonce"))
+ {
+ QByteArray cnonce(32, 'm');
+ for(int n = 0; n < cnonce.size(); ++n)
+ cnonce[n] = (char)(256.0*qrand()/(RAND_MAX+1.0));
+
+ QByteArray nc = "00000001";
+ QByteArray digest_uri = "xmpp/" + domain;
+
+ QByteArray a1 = user + ':' + realm + ':' + passwd;
+ QByteArray ha1 = QCryptographicHash::hash(a1, QCryptographicHash::Md5);
+ ha1 += ':' + map["nonce"] + ':' + cnonce;
+
+ if(map.contains("authzid"))
+ ha1 += ':' + map["authzid"];
+
+ QByteArray A1(ha1);
+ QByteArray A2 = "AUTHENTICATE:" + digest_uri;
+ QByteArray HA1 = QCryptographicHash::hash(A1, QCryptographicHash::Md5).toHex();
+ QByteArray HA2 = QCryptographicHash::hash(A2, QCryptographicHash::Md5).toHex();
+ QByteArray KD = HA1 + ':' + map["nonce"] + ':' + nc + ':' + cnonce + ':'
+ + "auth" + ':' + HA2;
+ QByteArray Z = QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex();
+
+ response += "username=\"" + user + "\",";
+
+ if(!realm.isEmpty())
+ response += "realm=\"" + realm + "\",";
+
+ response += "nonce=\"" + map["nonce"] + "\",";
+ response += "cnonce=\"" + cnonce + "\",";
+ response += "nc=" + nc + ",";
+ response += "qop=auth,";
+ response += "digest-uri=\"" + digest_uri + "\",";
+ response += "response=" + Z + ",";
+ if(map.contains("authzid"))
+ response += "authzid=\"" + map["authzid"] + "\",";
+ response += "charset=utf-8";
+
+ log(response);
+ QByteArray packet = "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+ + response.toBase64() + "</response>";
+ sendToServer(packet);
+ }
+ else if(map.contains("rspauth"))
+ {
+ sendToServer("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
+ }
+ else
+ {
+ disconnect();
+ log(QString("sendAuthDigestMD5Response: Invalid input"));
+ }
+}
+
void QXmppStream::sendBindIQ()
{
QXmppBind bind(QXmppIq::Set);