python - XMPP rspauth token should contain what in a DIGEST-MD5 auth? -
background: i'm fiddling xmpp server doesn't work.
so documentation on particular response token called rspauth
not documented anywhere really. appear skip , go static string looking this:
cnnwyxv0ad1lytqwzjywmzm1yzqyn2i1nti3yjg0zgjhymnkzmzmza==
which b64decodes to:
rspauth=ea40f60335c427b5527b84dbabcdfffd
however @ last stages of md5-digest
authentication, supposedly should sending following:
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> cnnwyxv0ad1lytqwzjywmzm1yzqyn2i1nti3yjg0zgjhymnkzmzmza== </challenge>
again, i'm not sure why everywhere in every bug report uses static string. xmpp client respond with:
jabber: error -10 : sasl(-10): server failed mutual authentication step: digest-md5: server wants believe knows shared secret
i try follow rfc's close can, , this rfc says rspauth=
:
the server receives , validates "digest-response". server
checks nonce-count "00000001". if supports subsequent
authentication (see section 2.2), saves value of nonce , nonce-count. sends message formatted follows:response-auth = "rspauth" "=" response-value
where response-value calculated above, using values sent in step two, except if qop "auth", a2 is
a2 = { ":", digest-uri-value }
based on this, how build rspauth
:
rspauth=b64enc(byteconv('rspauth=:'+md5_this("xmpp/example.com")))
which boils down to:
# md5_this == 6dae15e9021a0103e8e09ce86956a659 (obv not example.com) respauth = 'cnnwyxv0ad02zgflmtvlotaymwewmtazzthlmdljztg2otu2yty1oq==' cli.respond('<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cnnwyxv0ad02zgflmtvlotaymwewmtazzthlmdljztg2otu2yty1oq==</challenge>')
according this thread on matter, last thing send wrong, should sending:
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cnnwyxv0ad02zgflmtvlotaymwewmtazzthlmdljztg2otu2yty1oq==</success>
this fails , client sends </stream:stream>
, connection breaks.
<challenge>...
i'm lost, i'm assuming i'm building rspauth=...
token wrong, don't know it's supposed be.
here's full communication trace between pidgin
, xmpp server:
client connected << <?xml version='1.0' ?> << <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> >> sending: <?xml version='1.0'?> <stream:stream xmlns:stream='http://etherx.jabber.org/streams' version='1.0' from='example.com' id='d86961dc-bfb5-4578-aa45-116d5f14ef54' xml:lang='en' xmlns='jabber:client'> <stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><required/></starttls> <register xmlns='http://jabber.org/features/iq-register'/></stream:features> << <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> >> sending: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> - secure connection established [tls] << <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> >> sending: <?xml version='1.0'?> <stream:stream xmlns:stream='http://etherx.jabber.org/streams' version='1.0' from='example.com' id='516f7395-4112-4892-87f1-2e9f7f3a96e1' xml:lang='en' xmlns='jabber:client'> <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>digest-md5</mechanism> </mechanisms> <auth xmlns='http://jabber.org/features/iq-auth'/> </stream:features> << <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='digest-md5' xmlns:ga='http://www.google.com/talk/protocol/auth' ga:client-uses-full-bind-result='true'/> >> sending: <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cmvhbg09imv4yw1wbguuy29tiixub25jzt0imte2iixxb3a9imf1dggilgnoyxjzzxq9dxrmltgsywxnb3jpdghtpw1kns1zzxnz</challenge> << <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dxnlcm5hbwu9inrvcnhlzciscmvhbg09imv4yw1wbguuy29tiixub25jzt0imte2iixjbm9uy2u9ijzgudf5rutbrk1tn2lhsnrbnlnime5oq1jbcmhgu0t3ohrma2xjvejpzgs9iixuyz0wmdawmdawmsxxb3a9yxv0acxkawdlc3qtdxjppsj4bxbwl2v4yw1wbguuy29tiixyzxnwb25zzt1jodhmntrimjjlmmfizgi4zthlmtljowvjzdliyjaxocxjagfyc2v0pxv0zi04</response> >> sending: <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cnnwyxv0ad1lytqwzjywmzm1yzqyn2i1nti3yjg0zgjhymnkzmzmza==</challenge> debug: rspauth=ea40f60335c427b5527b84dbabcdfffd << </stream:stream>
i've followed these rfc guides:
- http://www.xmpp.org/internet-drafts/draft-saintandre-rfc3920bis-01.html
- https://www.ietf.org/rfc/rfc2831.txt
- http://wiki.xmpp.org/web/saslanddigest-md5
and had @ these source codes:
- https://github.com/jaxl/jaxl/blob/master/xmpp/xmpp.auth.php#l86 (also checked out)
- https://github.com/thobbs/pure-sasl/blob/1f7428b8ed37e5ab6d5500b53a637c4698a298ad/puresasl/mechanisms.py
and what's left reverse engineer successful connection , break down responses further, md5 hashes tricky reverse in timely manner, i'm asking time.
found something
checked around in old source codes , found following:
respauth = step_4 + ':' + nonce + ':' + cresp['nc'] + ':' + cnonce + ':' + cresp['qop'] + ':' + step_5 rspauth = 'rspauth=' + md5_this(rspauth)
now still generates same error, it's other static strings got work now.
i know 4 months old, had exact same problem, , seem have solved it.
the rfc sasl digest (https://tools.ietf.org/html/rfc2831#section-2.1.3)
i made code in c#, should easy adept, used function names use in rfc.
i know code not feature complete or bug free, works me in pidgin, gajim , psi (psi not check returning hash server, sure concerning). hope code helps you, or others needed up.
!attention! md5-digest seen unsafe, , new standart scram sasl (https://tools.ietf.org/html/rfc5802)
the methode check client hash
public string generateclienthash(string user, string realm, string password, string nonce, string cnonce, string authzid, string digesturi, string qop, string nc) { byte[] a2 = (qop.equals("auth") ? encoder.getbytes($"authenticate:{digesturi}"): encoder.getbytes($"authenticate:{digesturi}:00000000000000000000000000000000")); byte[] h1 = h(encoder.getbytes($"{user}:{realm}:{password}")); byte[] h2 = encoder.getbytes($":{nonce}:{cnonce}"); byte[] a1 = merge(h1,h2); byte[] response_value = hex(kd(hex(h(a1)), merge(encoder.getbytes($"{nonce}:{nc}:{cnonce}:{qop}:"), hex(h(a2))) )); byte[] h3 = merge(h1, h2); return encoder.getstring(response_value); }
generate server hash (the 1 had problems with)
public string generateserverhash(string user, string realm, string password, string nonce, string cnonce, string authzid, string digesturi, string qop, string nc) { byte[] a2 = (qop.equals("auth") ? encoder.getbytes($":{digesturi}") : encoder.getbytes($":{digesturi}:00000000000000000000000000000000")); byte[] h1 = h(encoder.getbytes($"{user}:{realm}:{password}")); byte[] h2 = encoder.getbytes($":{nonce}:{cnonce}"); byte[] a1 = merge(h1, h2); byte[] response_value = hex(kd(hex(h(a1)), merge(encoder.getbytes($"{nonce}:{nc}:{cnonce}:{qop}:"), hex(h(a2))) )); byte[] h3 = merge(h1, h2); return encoder.getstring(response_value); }
the functions rfc mentioned.
/// <summary> /// let h(s) 16 octet md5 hash [rfc 1321] of octet string s. /// </summary> /// <param name="s">byte array af streng @ sikre encodning</param> /// <returns>s -> base16(s) = s16 -> md5hash(s16)</returns> public byte[] h(byte[] s) { md5cryptoserviceprovider md5 = new md5cryptoserviceprovider(); return md5.computehash(s); } /// <summary> /// let kd(k, s) h({k, ":", s}), i.e., 16 octet hash of string k, colon , string s. /// </summary> /// <param name="k">byte array af streng @ sikre encodning</param> /// <param name="s">byte array af streng @ sikre encodning</param> /// <returns>k + ":" + s = ks -> h(ks)</returns> public byte[] kd(byte[] k, byte[] s) { byte[] colon = encoder.getbytes(":"); byte[] ks = merge(k, colon, s); return h(ks); } /// <summary> /// let hex(n) representation of 16 octet md5 hash n string of 32 hex digits(with alphabetic characters in lower case, since md5 case sensitive). /// </summary> /// <param name="n">byte array af streng @ sikre encodning</param> /// <returns>lowercase of n</returns> public byte[] hex(byte[] n) { byte[] b = encoder.getbytes(tobase16(n).tolower()); return b; }
Comments
Post a Comment