Hello list,

   I saw William Lallemand's announcement regarding the possibility of
loading dynamic ssl certificates right here
https://www.mail-archive.com/haproxy@formilux.org/msg36927.html and
the idea of having so much control over the haproxy instance was
intriguing.

   I've set up a test instance of the latest 2.2-dev9 to test out this
feature and I seem to have hit a bump in the road. I am an usure if I
misunderstood what was supposed to happen, or if I've stumbled across
a bug. In my configuration file, I'm instructing haproxy to load all
existing certificates from a folder and I'm trying to load a new
certificate using the new "new ssl cert/add ssl cert/commit ssl cert"
commands through the haproxy socket. The domain with the certificate
loaded manually seems to have SNI problems until haproxy is restarted
and the certificate is read from the crt folder.

   I'm using foo.com and bar.com as example domains. The one that
haproxy loads from the folder is generated and self-signed (foo.com),
while the one I'm trying to load is valid and issued by let's encrypt
(bar.com).

   I've used a slight variation of the config file found in
reg-tests/ssl/set_ssl_cert.vtc as follows:
------------------------------------------------------[Start]------------------------------------------------------
global
        maxconn 4096
        user root
        group root
        daemon
        log 127.0.0.1 local0 debug
        stats socket "/tmp/stats" level admin

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        tune.ssl.default-dh-param 2048

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option  redispatch
        option  http-server-close
        option  forwardfor
        timeout connect 5000
        timeout client  50000
        timeout server  50000


listen https-in
        bind :443 transparent ssl strict-sni crt /etc/haproxy/ssl alpn
h2,http/1.1
        default_backend something

backend something
        mode http
        server web 192.168.1.144:80 check
------------------------------------------------------[End]------------------------------------------------------

Haproxy starts succesfully and the pre-existing certificate in the
/etc/haproxy/ssl is present and loaded:

------------------------------------------------------[Start]------------------------------------------------------
]# haproxy -d -f /etc/haproxy/haproxy.cfg
Available polling systems :
      epoll : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result FAILED
Total: 3 (2 usable), will use epoll.

Available filters :
        [SPOE] spoe
        [COMP] compression
        [TRACE] trace
        [CACHE] cache
        [FCGI] fcgi-app
Using epoll() as the polling mechanism.
------------------------------------------------------[Middle]------------------------------------------------------
]# echo -e "show ssl cert" | socat /tmp/stats stdio
# filename
/etc/haproxy/ssl/foo.com.pem

]# echo -e "show ssl cert /etc/haproxy/ssl/foo.com.pem" | socat /tmp/stats stdio
Filename: /etc/haproxy/ssl/foo.com.pem
*Status: Used*
Serial: DA0AD0EC8F6C0C30
notBefore: Nov  8 15:31:08 2019 GMT
notAfter: Dec  8 15:31:08 2019 GMT
Subject Alternative Name:
Algorithm: RSA2048
SHA1 FingerPrint: 81D4AF40722F5F7C704E3327C5695F78DA6DC1E0
Subject: 
/C=RO/ST=SomeState/L=Locality/O=OrganizationalOrg/OU=OrzanizatoricUnit/CN=foo.pem
Issuer: 
/C=RO/ST=SomeState/L=Locality/O=OrganizationalOrg/OU=OrzanizatoricUnit/CN=foo.pem
------------------------------------------------------[End]------------------------------------------------------
Certificate status is "Used", browser loads "foo.com" with the proper
certificate"

Next I've tried inserting "bar.com" into a running haproxy:
------------------------------------------------------[Start]------------------------------------------------------
]# cat /root/certificates/bar.com/fullchain.pem
/root/certificates/bar.com/privkey.pem | sed '/^$/d' >
/etc/haproxy/ssl/bar.com.pem
]# echo -e "new ssl cert /etc/haproxy/ssl/bar.com.pem" | socat /tmp/stats stdio
New empty certificate store '/etc/haproxy/ssl/bar.com.pem'!

# echo -e "set ssl cert /etc/haproxy/ssl/bar.com.pem <<\n$(cat
/etc/haproxy/ssl/bar.com.pem)\n" | socat /tmp/stats stdio
Transaction created for certificate /etc/haproxy/ssl/bar.com.pem!

]# echo -e "commit ssl cert /etc/haproxy/ssl/bar.com.pem" | socat
/tmp/stats stdio
Committing /etc/haproxy/ssl/bar.com.pem
Success!
------------------------------------------------------[End]------------------------------------------------------

Everything seems to have worked successfully, although the certificate
shows up as "Unused":
------------------------------------------------------[Start]------------------------------------------------------
]# echo -e "show ssl cert /etc/haproxy/ssl/bar.com.pem" | socat /tmp/stats stdio
Filename: /etc/haproxy/ssl/bar.com.pem
*Status: Unused*
Serial: 0315D3DD8EAB437293870474AB2B7055699B
notBefore: Jun 16 20:30:03 2020 GMT
notAfter: Sep 14 20:30:03 2020 GMT
Subject Alternative Name: DNS:*.bar.com, DNS:bar.com
Algorithm: RSA2048
SHA1 FingerPrint: 5AEECEA0218C07B8D9E4D1B248FB1614C32B79DE
Subject: /CN=bar.com
Issuer: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
Chain Subject: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
Chain Issuer: /O=Digital Signature Trust Co./CN=DST Root CA X3
------------------------------------------------------[End]------------------------------------------------------

When accessing bar.com in a firefox browser window, the following happens:
------------------------------------------------------[Start]------------------------------------------------------
Secure Connection Failed

An error occurred during a connection to bar.com. SSL peer has no
certificate for the requested DNS name.

Error code: SSL_ERROR_UNRECOGNIZED_NAME_ALERT
------------------------------------------------------[End]------------------------------------------------------

The haproxy instance displays the following:
------------------------------------------------------[Start]------------------------------------------------------
fd[0013] OpenSSL error[0x1412e0e2] ssl_parse_clienthello_tlsext:
clienthello tlsext
fd[0013] OpenSSL error[0x1408a0e3] ssl3_get_client_hello: parse tlsext
fd[0012] OpenSSL error[0x1412e0e2] ssl_parse_clienthello_tlsext:
clienthello tlsext
fd[0012] OpenSSL error[0x1408a0e3] ssl3_get_client_hello: parse tlsext
fd[0012] OpenSSL error[0x1412e0e2] ssl_parse_clienthello_tlsext:
clienthello tlsext
fd[0012] OpenSSL error[0x1408a0e3] ssl3_get_client_hello: parse tlsext
------------------------------------------------------[End]------------------------------------------------------
probably because of the "strict-sni" present in the haproxy
configuration file. If I remove "strict-sni" then bar.com will load
with the certificate for foo.com and browsers will complain about the
mismatching domain name.

What throws me off, is that in the documentation, "commit ssl cert"
*is* supposed to generate all context and SNI's it needs:
------------------------------------------------------[Start]------------------------------------------------------
commit ssl cert <filename>

Commit and apply a temporary SSL certificate update transaction.
Generate every SSL contextes and SNIs it needs, insert them, and remove
the previous ones. Replace in memory the previous SSL certificates
everywhere the <filename> was used in the configuration.
Upon failure it doesn't remove or insert anything. Once the temporary
transaction is committed, it is destroyed.
------------------------------------------------------[End]------------------------------------------------------

Does anyone have any thoughts on this ?

Regards.
-tbn

Reply via email to