Currently HAProxy only supports DNS-style SANs[0]. This can be a problem when 
integrating with external systems. For example, systems that use SPIFFE 
authentication (such as Istio) store SPIFFE IDs[1] in the certificate's SAN, 
but formatted as a URI.

As a quick prototype I was able to piggyback onto the existing `verifyhost` 
keyword, but this has a few drawbacks. In particular:

1. HAProxy currently overrides `verifyhost` with any SNI (Server Name 
Indication) name, if used (not that this behaviour makes sense to me, since 
this special-casing doesn't actually enable anything)
2. Wildcards would behave differently (if supported at all)
3. It is dangerous to allow wildcarding DNS names into URIs (*.haproxy.org 
probably shouldn't match https://evilcorp.com/.haproxy.org)
4. It may be desirable to allow more than one URI (for example, during a 
migration to a new SPIFFE ID)

I attached a prototype patch, but because of the previous drawbacks it 
shouldn't be merged as is. I just wanted a point to jump off of.

Tagged as MAJOR because TLS certificate validation is a security-critical 
feature in a relatively hot code path. I don't expect this to end up as a huge 
patch, but it's an important area to be careful in.

[0]: https://github.com/haproxy/haproxy/blob/
cf1f193624acb9d5a52f40375bb445e5438dd89e/src/ssl_sock.c#L4627-L4636
[1]: https://spiffe.io/docs/latest/spiffe/concepts/#spiffe-id
---
 src/ssl_sock.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index ac6537f38..d3439acfc 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -4541,11 +4541,12 @@ static int ssl_sock_srv_verifycbk(int ok, 
X509_STORE_CTX *ctx)
         */
        servername = SSL_get_servername(ssl_ctx->ssl, 
TLSEXT_NAMETYPE_host_name);
        sni = servername;
-       if (!servername) {
+       /* Disable SNI overriding `verifyhost` */
+       /* if (!servername) { */
                servername = __objt_server(conn->target)->ssl_ctx.verify_host;
                if (!servername)
                        return ok;
-       }
+       /* } */
 
        /* We only need to verify the CN on the actual server cert,
         * not the indirect CAs */
@@ -4575,6 +4576,12 @@ static int ssl_sock_srv_verifycbk(int ok, 
X509_STORE_CTX *ctx)
                                        ok = ssl_sock_srv_hostcheck(str, 
servername);
                                        OPENSSL_free(str);
                                }
+                       } else if (name->type == GEN_URI) {
+                               if (ASN1_STRING_to_UTF8((unsigned char 
**)&str, name->d.uniformResourceIdentifier) >= 0) {
+                                       /* Validate URL prefix */
+                                       ok = strncmp(str, servername, 
strlen(servername)) == 0;
+                                       OPENSSL_free(str);
+                               }
                        }
                }
                sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
-- 
2.25.1

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to