XMPP connection fails: it's stuck waiting for <proceed> and doesn't skip the <stream:features> line
Description of problem:
When speaking XMPP, it doesn't connect to a server and timeouts while waiting for the text <proceed
. It's just confused because the server sends a first line (<stream:features>
) and then the <proceed
in a 2nd line, but XMPP doesn't understand the first line and just waits some seconds and complains that it didn't see <proceed
.
This made my emacs-jabber not connect to my Jabber account (at jabberes.org), for some years already.
Version of gnutls used:
3.6.6
Distributor of gnutls (e.g., Ubuntu, Fedora, RHEL)
Devuan
How reproducible:
Steps to reproduce: just run the command in the „actual results“ below.
Actual results:
$ gnutls-cli -p 5222 jabberes.org --starttls-proto=xmpp -V
Processed 120 CA certificate(s).
Resolving 'jabberes.org:5222'...
Connecting to '95.211.10.153:5222'...
Negotiating XMPP STARTTLS
starttls: sending: <stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='jabberes.org' version='1.0'>
starttls: waiting for: "<?"
starttls: received: <?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='2255077113' from='jabberes.org' version='1.0' xml:lang='es'>
starttls: sending: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
starttls: waiting for: "<proceed"
starttls: received: <stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism><mechanism>DIGEST-MD5</mechanism><mechanism>SCRAM-SHA-1</mechanism></mechanisms><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='VX1ZxJXED0Sme0Unk3GOZrknLy0='/><register xmlns='http://jabber.org/features/iq-register'/></stream:features>
starttls: received: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
error receiving <proceed: Success
$
Expected results:
It shouldn't fail, it should connect. If I apply the patch posted below, I can correctly connect (also from Emacs after making it use my version with (setq tls-program '("gnutls-cli-with-my-patch --x509cafile %t -p %p %h --starttls-proto=xmpp"))
…)
The output is then:
$ gnutls-cli-with-my-patch -p 5222 jabberes.org --starttls-proto=xmpp -V
Processed 120 CA certificate(s).
Resolving 'jabberes.org:5222'...
Connecting to '95.211.10.153:5222'...
Negotiating XMPP STARTTLS
starttls: sending: <stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='jabberes.org' version='1.0'>
starttls: waiting for: "<?"
starttls: received: <?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='1876947985' from='jabberes.org' version='1.0' xml:lang='es'>
starttls: sending: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
starttls: waiting for: "<stream:"
starttls: received: <stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism><mechanism>DIGEST-MD5</mechanism><mechanism>SCRAM-SHA-1</mechanism></mechanisms><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='VX1ZxJXED0Sme0Unk3GOZrknLy0='/><register xmlns='http://jabber.org/features/iq-register'/></stream:features>
starttls: waiting for: "<proceed"
starttls: received: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
- Certificate type: X.509
- Got a certificate list of 2 certificates.
- Certificate[0] info:
- X.509 Certificate Information:
Version: 3
Serial Number (hex): 03e952752ec04bfcc10054d9701f6b98b2db
Issuer: CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US
Validity:
Not Before: Thu Apr 11 09:56:22 UTC 2019
Not After: Wed Jul 10 09:56:22 UTC 2019
Subject: CN=jabberes.org
[…]
Patch
Attention, this isn't a full patch, it's a workaround. I don't speak the XMPP protocol yet so I don't know when do we expect to see a <stream:features>
and when not, or what does it mean. A better option would be to ignore <stream:features>
if it's there, but not to fail if it isn't.
The patch just expects to see both lines one after the other, which works for jabberes.org
diff --git a/src/socket.c b/src/socket.c
index be60f94..498d93f 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -250,6 +250,7 @@ socket_starttls(socket_st * socket)
send_line(socket, buf);
wait_for_text(socket, "<?", 2);
send_line(socket, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+ wait_for_text(socket, "<stream:", 8);
wait_for_text(socket, "<proceed", 8);
} else if (strcasecmp(socket->app_proto, "ldap") == 0) {
if (socket->verbose)