I am facing a problem while configuring a HAProxy instance (v1.8.13) with compiled OpenSSL support to only accept client certificates which have been signed by a non-CA certificate. In particular, I want to use an intermediate certificate (non self-signed) certificate as the trust anchor when verifying client certificates.

This is the config I'm using:

frontend myfrontend
     bind *:${PORT} ssl crt /certs/haproxy-server-cert-bundle.pem ca-file /certs/intermediate_cert2.pem verify required

Clients connect via certificates that fulfil the following certificate chain:

client certificate -> intermediate cert1 -> intermediate cert2 (this should become the new trust anchor) -> root CA certificate

When using this configuration connecting to the HAProxy via the client certificate results in the following error: Feb 13 09:17:26 my-forwarder haproxy[108]: <ip>:<port> [13/Feb/2019:09:17:26.619] my-forwarder/1: SSL client CA chain cannot be verified

If I specify the root CA certificate as trust anchor (ca-file config parameter in the HAProxy config) the TLS handshake can be established successfully. However, I only want to accept certificates which were signed by the certificate branch intermediate cert 2 -> root CA certificate, not by i.e. some other intermediate cert -> root CA certificate.

I tried to reproduce this behaviour using plain OpenSSL verify and via some OpenSSL s_server/s_client setup. It seems that the same problem exists using those tools.

Some evidence:

$ openssl verify -CAfile test-certificate-chain.pem test-cert.pem test-cert.pem: C = ..., O = ..., OU = ..., ST = ..., CN = intermediate-cert2 error 2 at 2 depth lookup:unable to get issuer certificate

Appending the root CA certificate to -CAfile results in: $ openssl verify -CAfile <(cat test-certificate-chain.pem root-ca.pem) test-cert.pem test-cert.pem: OK

The only two options I was able to come up with in order to solve this problem are the following:

  • Create a self-signed CA certificate which signs the intermediate cert2 certificate's public key. The self-signed CA certificate must then be installed in the HAProxy configuration's ca-file config key.
  • Configure the HAProxy to ignore the OpenSSL error number 2 (unable to get issuer certificate) via the HAProxy configuration key ca-file /certs/intermediate_cert2.pem verify required ca-ignore-err 2

I am not yet satisfied in terms of security level when using either one of the options above. Hence, I would be curios to know whether there is a "cleaner" solution to this problem.

Has anyone else faced a similar issue?



Update: I solved the problem a bit differently as I was unable to find a way to trust an intermediate (non-CA) certificate without trusting the parent (CA) certificate via the verification of the certificate chain via OpenSSL.

The alternative was to utilize HAProxy's powerful ACL feature. In particular:

frontend my-frontend
    acl my_tls_ca_issuer_acl ssl_c_i_dn(cn) -m reg ^<some-regex-matching-the-client-cert's-issuer-cn>$
    tcp-request content reject unless my_tls_ca_issuer_acl

I'm configuring HAProxy to only accept client certificates issued by an entity which matches a given Common Name regex. This is what the matcher ssl_c_i_dn(cn) is doing (see the documentation for details).

By implementing this I could unfortunately only match to the distinguished name (DN) of the issuer/parent of the client certificate (intermediate cert 1), not its grandparent (intermediate cert 2).

Still I hope this helps someone..

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.