Files
2026-09-06 13:51:11 +00:00

48 lines
1.6 KiB
Python

#!/usr/bin/env python3
"""STARTTLS probe for Prosody/XMPP servers (c2s 5222 default, --s2s uses jabber:server for 5269).
Usage: starttls_probe.py <host> <port> <domain> [--s2s]
Verifies: stream features -> starttls -> <proceed/> -> TLS handshake -> cert subject/issuer/SAN.
Reason to exist: `openssl s_client -starttls xmpp` reports "no peer certificate"/Cipher NONE
on Prosody 0.11 even when TLS works fine (false negative).
Exit 0 with "TLS OK" = c2s/s2s STARTTLS fully working with a trusted cert.
"""
import socket, ssl, sys, time
HOST = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 5222
DOMAIN = sys.argv[3] if len(sys.argv) > 3 else "nixg.ru"
S2S = "--s2s" in sys.argv
NS = "jabber:server" if S2S else "jabber:client"
s = socket.create_connection((HOST, PORT), timeout=10)
s.settimeout(8)
def recv():
data = s.recv(8192)
print(" <<", data.decode(errors="replace")[:300].replace("\n", " "))
return data
s.sendall(
("<stream:stream to='%s' xmlns='%s' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>" % (DOMAIN, NS)).encode()
)
time.sleep(1)
recv()
s.sendall(b"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>")
time.sleep(1)
recv()
ctx = ssl.create_default_context()
tls = ctx.wrap_socket(s, server_hostname=DOMAIN)
print("TLS OK:", tls.cipher()[0], tls.version())
try:
cert = tls.getpeercert()
print("SUBJECT:", cert["subject"])
print("ISSUER:", cert["issuer"])
print("SAN:", cert.get("subjectAltName"))
except Exception as e:
print("cert verification issue:", e)
tls.close()