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
signature.asc
Description: This is a digitally signed message part.

