[Pkg-javascript-commits] [ltx] 28/469: sasl: DIGEST-MD5 support

Jonas Smedegaard dr at jones.dk
Wed Aug 31 13:00:54 UTC 2016


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository ltx.

commit 33abba0a22e2c949bd25074d35fea7e7acea3abb
Author: Astro <astro at spaceboyz.net>
Date:   Mon May 31 00:47:57 2010 +0200

    sasl: DIGEST-MD5 support
---
 lib/xmpp/client.js |  28 ++++++++----
 lib/xmpp/sasl.js   | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 140 insertions(+), 12 deletions(-)

diff --git a/lib/xmpp/client.js b/lib/xmpp/client.js
index 1e3e95f..a686b74 100644
--- a/lib/xmpp/client.js
+++ b/lib/xmpp/client.js
@@ -83,7 +83,16 @@ Client.prototype.onRawStanza = function(stanza) {
 	this.streamFeatures = stanza;
 	this.useFeatures();
     } else if (this.state == STATE_AUTH) {
-	if (stanza.is('success', NS_XMPP_SASL)) {
+	if (stanza.is('challenge', NS_XMPP_SASL)) {
+	    var challengeMsg = b64.decode(stanza.getText());
+	    sys.puts("challengeMsg: " + challengeMsg);
+	    var responseMsg = b64.encode(
+				  this.mech.challenge(challengeMsg));
+	    this.send(new xml.Element('response',
+				      { xmlns: NS_XMPP_SASL
+				      }).t(responseMsg));
+	} else if (stanza.is('success', NS_XMPP_SASL)) {
+	    this.mech = null;
 	    this.state = STATE_AUTHED;
 	    this.startStream();
 	} else {
@@ -136,19 +145,22 @@ Client.prototype.useFeatures = function() {
     if (this.state == STATE_PREAUTH &&
 	this.streamFeatures.getChild('mechanisms', NS_XMPP_SASL)) {
 	this.state = STATE_AUTH;
-	var mech = sasl.selectMechanism(
+	this.mech = sasl.selectMechanism(
 		       this.streamFeatures.
 		       getChild('mechanisms', NS_XMPP_SASL).
 		       getChildren('mechanism', NS_XMPP_SASL).
 		       map(function(el) { return el.getText(); }));
-	if (mech) {
-	    mech.authzid = this.jid.bare().toString();
-	    mech.authcid = this.jid.user;
-	    mech.password = this.password;
+	if (this.mech) {
+	    this.mech.authzid = this.jid.bare().toString();
+	    this.mech.authcid = this.jid.user;
+	    this.mech.password = this.password;
+	    this.mech.realm = this.jid.domain;  // anything?
+	    this.mech.digest_uri = "xmpp/" + this.jid.domain;
+	    var authMsg = b64.encode(this.mech.auth());
 	    this.send(new xml.Element('auth',
 				      { xmlns: NS_XMPP_SASL,
-					mechanism: mech.name
-				      }).t(b64.encode(mech.auth())));
+					mechanism: this.mech.name
+				      }).t(authMsg));
 	} else {
 	    this.emit('error', 'No usable SASL mechanism');
 	    this.end();
diff --git a/lib/xmpp/sasl.js b/lib/xmpp/sasl.js
index 17bb1b4..290b541 100644
--- a/lib/xmpp/sasl.js
+++ b/lib/xmpp/sasl.js
@@ -1,12 +1,14 @@
+var crypto = require('crypto');
+
 function selectMechanism(mechs) {
     if (mechs.indexOf("ANONYMOUS") >= 0)
 	return new Anonymous();
-    /*if (mechs.indexOf("DIGEST-MD5") >= 0)
-       return "DIGEST-MD5";*/
+    else if (mechs.indexOf("DIGEST-MD5") >= 0)
+	return new DigestMD5();
     else if (mechs.indexOf("PLAIN") >= 0)
-       return new Plain();
+	return new Plain();
     else
-       return null;
+	return null;
 }
 exports.selectMechanism = selectMechanism;
 
@@ -25,3 +27,117 @@ function Anonymous() {
 	return this.authzid;
     };
 }
+
+function DigestMD5() {
+    this.name = "DIGEST-MD5";
+    this.auth = function() {
+	return "";
+    };
+
+    this.nonce_count = 0;
+    this.getNC = function() {
+	return rjust(this.nonce_count.toString(), 8, '0');
+    };
+    this.cnonce = generateNonce();
+    this.challenge = function(s) {
+	dict = parseDict(s);
+	if (dict.realm)
+	    this.realm = dict.realm;
+	//require('sys').puts("dict: "+JSON.stringify(dict));
+
+	var response;
+	if (dict.nonce && dict.qop) {
+	    this.nonce_count++;
+	    var a1 = md5(this.authcid + ':' +
+			 this.realm + ':' +
+			 this.password) + ':' +
+			     dict.nonce + ':' +
+			     this.cnonce + ':' +
+			     this.authzid;
+	    var a2 = "AUTHENTICATE:" + this.digest_uri;
+	    if (dict.qop == 'auth-int' || dict.qop == 'auth-conf')
+		a2 += ":00000000000000000000000000000000";
+	    var responseValue = md5_hex(md5_hex(a1) + ':' +
+					dict.nonce + ':' +
+					this.getNC() + ':' +
+					this.cnonce + ':' +
+					dict.qop + ':' +
+					md5_hex(a2)
+				       );
+	    response = {
+		username: this.authcid,
+		realm: this.realm,
+		nonce: dict.nonce,
+		cnonce: this.cnonce,
+		nc: this.getNC(),
+		qop: dict.qop,
+		'digest-uri': this.digest_uri,
+		response: responseValue,
+		authzid: this.authzid,
+		charset: 'utf-8'
+	    };
+	} else if (dict.rspauth) {
+	    return "";
+	}
+	//require('sys').puts('response: '+JSON.stringify(response));
+	return encodeDict(response);
+    };
+}
+
+function parseDict(s) {
+    var result = {};
+    while (s) {
+	var m;
+
+	if ((m = /^(.+?)="(.*?[^\\])",(.*)/.exec(s))) {
+	    result[m[1]] = m[2];
+	    s = m[3];
+	} else if ((m = /^(.+?)="(.*?[^\\])"$/.exec(s))) {
+	    result[m[1]] = m[2];
+	    s = m[3];
+	} else if ((m = /^(.+?)=(.+?),(.*)/.exec(s))) {
+	    result[m[1]] = m[2];
+	    s = m[3];
+	} else if ((m = /^(.+?)=(.+?)$/.exec(s))) {
+	    result[m[1]] = m[2];
+	    s = m[3];
+	} else {
+	    s = null;
+	}
+    }
+    return result;
+}
+
+function encodeDict(dict) {
+    var s = "";
+    for(k in dict) {
+	var v = dict[k];
+	if (v)
+	    s += ',' + k + '="' + v + '"';
+    }
+    return s.substr(1);  // without first ','
+}
+
+function rjust(s, targetLen, padding) {
+    while(s.length < targetLen)
+	s = padding + s;
+    return s;
+}
+
+function md5(s, encoding) {
+    var hash = crypto.createHash('md5');
+    hash.update(s);
+    return hash.digest(encoding || 'binary');
+}
+
+function md5_hex(s) {
+    return md5(s, 'hex');
+}
+
+function generateNonce() {
+    var result = "";
+    for(var i = 0; i < 8; i++)
+	result += String.fromCharCode(48 +
+				      Math.round(Math.random() * 10));
+    return result;
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/ltx.git



More information about the Pkg-javascript-commits mailing list