How haproxy knows which TLS/cert to use? was: Tls_post_process_client_hello: no shared cipher


We are trying to connect an old application through haproxy. Although we have found a workaround, I would like to better understand what’s going on.
Debugging, client requests results in:

tls_post_process_client_hello: no shared cipher

Server is running HAProxy version 2.8.9 on IP and bind’s crt-list is as follows:

/etc/haproxy/certs/web.domain.tld.pem.rsa [ ciphers AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA ] web.domain.tld

IIUC, when a request reaches the server, as the name matches “web.domain.tld” it applies “web.domain.tld.pem.rsa” cert, is that right?

That would make sense, as nmap (to host) dumps:

nmap -sV -p 443 --script ssl-enum-ciphers web.domain.tld
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers:
| TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
| TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A

while nmap (to IP) dumps:

nmap -sV -p 443 --script ssl-enum-ciphers
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers:
| TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (ecdh_x25519) - A
| TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (ecdh_x25519) - A
| TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
| TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (ecdh_x25519) - A
| TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (ecdh_x25519) - A
| TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
| TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A

This would mean the server is receiving the name (web.domain.tld) and appliying crt-list or IP and applying global server configuration. Did I understand properly?

Would I be able to see web.domain.tld using tcpdump? I’m unable and starting to wonder how haproxy knows which cert use to negotiate.
My gut is telling me client is asking for IP…

Thanks in advance


The old application is using TLS1.2 without SNI extension providing server_name. (This can be seen in TLS Client Hello using tcpdump).

As stated by documentation haproxy would pick the first loaded certificate as default.

The easiest workaround, apart from upgrading the old application, would be to use a specific port binding with single crt entry.