How to Retrieve SSL Certificate Chain from XMPP/Jabber Server for Client Validation


2 views

When connecting to an XMPP server with a self-signed certificate using Pidgin, you might encounter the "unable to validate certificate" error. The standard approach would be to retrieve the certificate chain using OpenSSL:

openssl s_client -connect my.jabber.server.net:5222 </dev/null

But surprisingly, this returns:

CONNECTED(00000003)
140472458057376:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
--- no peer certificate available
--- No client certificate CA names sent
--- SSL handshake has read 0 bytes and written 213 bytes

XMPP servers typically use STARTTLS rather than immediate SSL/TLS negotiation on port 5222. This explains why the direct OpenSSL connection fails - it's attempting standard SSL when the server expects XMPP protocol first.

To properly retrieve certificates from an XMPP server, we need to:

  1. Establish a plaintext connection
  2. Initiate STARTTLS
  3. Then perform the certificate retrieval

Here's a working method using OpenSSL:

openssl s_client -starttls xmpp -connect my.jabber.server.net:5222 </dev/null

The -starttls xmpp flag tells OpenSSL to use XMPP's specific STARTTLS implementation.

If the above doesn't work, try these approaches:

Method 1: Using gnutls-cli

gnutls-cli --starttls --port 5222 my.jabber.server.net

Method 2: Python script

import socket
import ssl
from OpenSSL import SSL

context = SSL.Context(SSL.SSLv23_METHOD)
conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
conn.connect(('my.jabber.server.net', 5222))
conn.do_handshake()
cert = conn.get_peer_cert_chain()
for c in cert:
    print(SSL.dump_certificate(SSL.FILETYPE_PEM, c))

Once you have the certificates, ensure they're in the correct chain order. The server certificate should come first, followed by intermediate CAs (if any), and finally the root CA.

For Pidgin specifically, you'll need to convert the certificates to the appropriate format and place them in Pidgin's certificate store, typically located at:

~/.purple/certificates/x509/tls_peers/

The file should be named using the SHA-1 fingerprint of the certificate. You can obtain this using:

openssl x509 -noout -fingerprint -sha1 -inform pem -in certificate.pem

When connecting to XMPP servers with self-signed certificates, Pidgin and other clients often throw "unable to validate certificate" errors. While some clients allow disabling validation, proper security practice requires importing the complete certificate chain.

The initial approach using:

openssl s_client -connect my.jabber.server.net:5222 </dev/null

fails because XMPP requires STARTTLS negotiation. Unlike HTTPS which immediately establishes TLS, XMPP begins with plaintext and upgrades to TLS.

To properly extract certificates from an XMPP server:

openssl s_client -connect my.jabber.server.net:5222 -starttls xmpp \
-showcerts </dev/null

Key parameters:

  • -starttls xmpp: Performs XMPP protocol negotiation
  • -showcerts: Displays full certificate chain
  • -servername: Important for SNI-enabled servers

For server xmpp.example.com:

openssl s_client -connect xmpp.example.com:5222 \
-starttls xmpp -showcerts -servername xmpp.example.com </dev/null \
| awk '/BEGIN CERT/,/END CERT/ {print $0}' > xmpp_chain.pem

If you encounter:

SSL handshake failure

Try forcing TLS 1.2:

openssl s_client -connect xmpp.example.com:5222 \
-starttls xmpp -tls1_2 -showcerts

After obtaining the chain, verify it with:

openssl verify -CAfile xmpp_chain.pem xmpp_chain.pem

1. Copy the certificate chain to ~/.purple/certificates/x509/tls_peers/
2. Rename the file to match the server's domain (e.g., xmpp_example_com.pem)
3. Restart Pidgin