Предыстория: я возился с сервером XMPP, который не работает.
Таким образом, документация по этому конкретному токену ответа под названием rspauth
нигде не очень хорошо документирована. Некоторые, кажется, просто пропускают его и используют статическую строку, выглядящую так:
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZA==
Что b64 декодирует в:
rspauth=ea40f60335c427b5527b84dbabcdfffd
Однако на последних этапах аутентификации MD5-DIGEST
я якобы должен отправить следующее:
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZA==
</challenge>
Опять же, я не уверен, почему все и везде в каждом отчете об ошибке используют эту статическую строку. Но любой клиент XMPP ответит:
jabber: Error is -10 : SASL(-10): server failed mutual authentication step: DIGEST-MD5: This server wants us to believe that he knows shared secret
Я стараюсь максимально точно следовать RFC, и это то, что говорится в RFC о rspauth=
:
Сервер получает и проверяет «дайджест-ответ». Сервер
проверяет, что счетчик одноразовых номеров равен "00000001". Если он поддерживает последующую
аутентификацию (см. раздел 2.2), он сохраняет значение одноразового номера и счетчика одноразовых номеров. Он отправляет сообщение в следующем формате:response-auth = "rspauth" "=" response-value
где ответное значение вычисляется, как указано выше, с использованием значений, отправленных на втором шаге, за исключением того, что если qop равно "auth", то A2 равно
A2 = { ":", digest-uri-value }
Исходя из этого, вот как я строю свой rspauth
:
rspauth=b64enc(ByteConv('rspauth=:'+md5_this("xmpp/example.com")))
Что сводится к:
# md5_this == 6dae15e9021a0103e8e09ce86956a659 (obv not with example.com)
respauth = 'cnNwYXV0aD02ZGFlMTVlOTAyMWEwMTAzZThlMDljZTg2OTU2YTY1OQ=='
cli.respond('<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cnNwYXV0aD02ZGFlMTVlOTAyMWEwMTAzZThlMDljZTg2OTU2YTY1OQ==</challenge>')
Согласно этой теме по этому вопросу, последнее, что я отправляю неправильно, я должен отправить:
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cnNwYXV0aD02ZGFlMTVlOTAyMWEwMTAzZThlMDljZTg2OTU2YTY1OQ==</success>
Это также не удается, а затем клиент отправляет </stream:stream>
, и соединение разрывается.
С <challenge>...
Вот тут-то я и запутался, предполагаю, что создаю токен rspauth=...
неправильно, но я не знаю, что это должно быть.
Вот полная трассировка связи между Pidgin
и сервером XMPP:
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>
Я следовал этим руководствам RFC:
- 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
И взглянул на эти исходные коды:
- https://github.com/jaxl/JAXL/blob/master/xmpp/xmpp.auth.php#L86 (также проверил)
- https://github.com/thobbs/pure-sasl/blob/1f7428b8ed37e5ab6d5500b53a637c4698a298ad/puresasl/mechanisms.py
И, по сути, осталось перепроектировать успешное соединение и еще больше разбить ответы, но хеши md5 сложно своевременно реверсировать, поэтому на этот раз я прошу помощи.
Нашел что-то
Проверил некоторые старые исходные коды и нашел следующее:
respauth = step_4 + ':' + nonce + ':' + cresp['nc'] + ':' + cnonce + ':' + cresp['qop'] + ':' + step_5
rspauth = 'rspauth=' + md5_this(rspauth)
Теперь он по-прежнему генерирует ту же ошибку, но это нечто иное, чем статические строки, поэтому я пока с этим работаю.