Hi Willy

> Le 5 juil. 2017 à 18:38, Willy Tarreau <w...@1wt.eu> a écrit :
> 
> Hi guys,
> 
> back to this old discussion.
> 
> On Fri, May 12, 2017 at 04:10:20PM +0200, Willy Tarreau wrote:
>> On Tue, May 09, 2017 at 12:12:42AM +0200, Lukas Tribus wrote:
>>> Haproxy can verify the certificate of backend TLS servers since day 1.
>>> 
>>> The only thing missing is client SNI based backend certificate
>>> verification, which yes - since we can pass client SNI to the TLS server
>>> - we need to consider for the certificate verification process as well.
>> 
>> In fact the cert name is checked, it's just that it can only check against
>> a constant in the configuration. I agree that it's a problem when using SNI.
>> Furthermore it forces one to completely disable verifyhost in case SNI is
>> used.
>> 
>> I tend to think that the best approach would be to always enable it when
>> SNI is involved in fact, because if SNI is used to the server, it really
>> means we want to check what cert is provided. This could then possibly be
>> explicitly turned off by the "verify none" directive.
>> 
>> I have absolutely no idea how to do that however, I don't know if we can
>> retrieve the previously configured SNI using openssl's API after the
>> connection is established.
> 
> So after digging I found a way to implement this. The configured SNI value
> is indeed stored in the SSL session and can be extracted, more or less
> easily depending on the version. I came up with the attached patch that
> works for me on all cases below. I'm willing to merge it into 1.8-dev and
> later backport to older versions once we're sure it does the right thing
> and doesn't break compatibility with openssl forks.
> 
> Please give it a try, and if some can test it on libressl/boringssl, it
> would be nice.
> 
> ---------------
> tested with the following server configurations (cert on port 8443 is valid
> for "localhost" only) :
> 
>        # passes checks and traffic (no hostname check)
>        server ssl 127.0.0.1:8443 ssl verify required check inter 100 ca-file 
> rsa2048.pem
> 
>        # passes checks and traffic (localhost is what the server presents)
>        server ssl 127.0.0.1:8443 ssl verify required check inter 100 ca-file 
> rsa2048.pem verifyhost localhost
> 
>        # fails checks and traffic (foo not matched on the server)
>        server ssl 127.0.0.1:8443 ssl verify required check inter 100 ca-file 
> rsa2048.pem verifyhost foo
> 
>        # passes checks and traffic (verify none ignores the host)
>        server ssl 127.0.0.1:8443 ssl verify none check inter 100 ca-file 
> rsa2048.pem verifyhost foo
> 
>        # passes checks and traffic (localhost is fine)
>        server ssl 127.0.0.1:8443 ssl verify required check inter 100 ca-file 
> rsa2048.pem sni str(localhost) verifyhost localhost
> 
>        # passes checks and traffic (verifyhost overrides sni)
>        server ssl 127.0.0.1:8443 ssl verify required check inter 100 ca-file 
> rsa2048.pem sni str(foo) verifyhost localhost
> 
>        # passes checks and traffic (localhost always valid)
>        server ssl 127.0.0.1:8443 ssl verify required check inter 100 ca-file 
> rsa2048.pem sni str(localhost)
> 
>        # passes checks, and traffic without host or with "host: localhost" 
> and fails other hosts.
>        server ssl 127.0.0.1:8443 ssl verify required check inter 100 ca-file 
> rsa2048.pem sni req.hdr(host)
> ---------------
> 
> Cheers,
> Willy
> <0001-MINOR-ssl-compare-server-certificate-names-to-the-SN.patch>

SSL_SESSION_get0_hostname take a ssl_session not a ssl structure.
in openssl-compat.h a section is used for others functions like 
SSL_SESSION_get0_X introduce in openssl 1.1.0

With this diff, it build with boringssl and openssl 1.0.2k. It should also be 
ok with libressl

diff --git a/include/proto/openssl-compat.h b/include/proto/openssl-compat.h
index 7261a7b..88ea01e 100644
--- a/include/proto/openssl-compat.h
+++ b/include/proto/openssl-compat.h
@@ -94,6 +94,11 @@ static inline int SSL_SESSION_set1_id_context(SSL_SESSION 
*s, const unsigned cha
  * Functions introduced in OpenSSL 1.1.0 and not yet present in LibreSSL
  */
 
+static inline const char *SSL_SESSION_get0_hostname(const SSL_SESSION *sess)
+{
+       return sess->tlsext_hostname;
+}
+
 static inline const unsigned char *SSL_SESSION_get0_id_context(const 
SSL_SESSION *sess, unsigned int *sid_ctx_length)
 {
        *sid_ctx_length = sess->sid_ctx_length;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 6448a89..d90d64b 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -127,13 +127,6 @@
 #define HASH_FUNCT EVP_sha256
 #endif /* OPENSSL_NO_SHA256 */
 
-/* Needed to retrieve the configured SNI for an outgoing connection, but only
- * appeared in openssl 1.1.0. I don't know how it's done with forked versions.
- */
-#if OPENSSL_VERSION_NUMBER < 0x1010000fL
-#define SSL_SESSION_get0_hostname(s) s->tlsext_hostname
-#endif
-
 /* ssl_methods flags for ssl options */
 #define MC_SSL_O_ALL            0x0000
 #define MC_SSL_O_NO_SSLV3       0x0001 /* disable SSLv3 */
@@ -3938,7 +3931,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX 
*ctx)
 {
        SSL *ssl;
        struct connection *conn;
-       char *servername;
+       const char *servername;
 
        int depth;
        X509 *cert;
@@ -3963,7 +3956,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX 
*ctx)
                if (!ssl_sess)
                        return ok;
 
-               servername = SSL_SESSION_get0_hostname(ssl);
+               servername = SSL_SESSION_get0_hostname(ssl_sess);
                if (!servername)
                        return ok;
        }


++
Manu

Reply via email to