[PATCH] ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6

Maxim Dounin mdounin at mdounin.ru
Wed Dec 20 22:40:21 UTC 2023


Hello!

On Tue, Dec 19, 2023 at 10:44:00PM +0400, Sergey Kandaurov wrote:

> 
> > On 19 Dec 2023, at 12:58, Maxim Dounin <mdounin at mdounin.ru> wrote:
> > 
> > Hello!
> > 
> > On Tue, Dec 19, 2023 at 02:09:10AM +0400, Sergey Kandaurov wrote:
> > 
> >>> On 24 Nov 2023, at 00:29, Ilya Shipitsin <chipitsine at gmail.com> wrote:
> >>> 
> >>> # HG changeset patch
> >>> # User Ilya Shipitsin <chipitsine at gmail.com>
> >>> # Date 1700769135 -3600
> >>> #      Thu Nov 23 20:52:15 2023 +0100
> >>> # Node ID 2001e73ce136d5bfc9bde27d338865b14b8ad436
> >>> # Parent  7ec761f0365f418511e30b82e9adf80bc56681df
> >>> ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6
> >> 
> >> style: SSL prefix should be uppercase.
> >> 
> >>> 
> >>> diff -r 7ec761f0365f -r 2001e73ce136 src/event/ngx_event_openssl_stapling.c
> >>> --- a/src/event/ngx_event_openssl_stapling.c	Thu Oct 26 23:35:09 2023 +0300
> >>> +++ b/src/event/ngx_event_openssl_stapling.c	Thu Nov 23 20:52:15 2023 +0100
> >>> @@ -893,7 +893,8 @@
> >>>    ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> >>>    ocsp->conf = ocf;
> >>> 
> >>> -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER)
> >>> +/* minimum OpenSSL 1.1.1 & LibreSSL 3.3.6 */
> >>> +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER) || (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3030600L))
> >>> 
> >>>    ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> >>> 
> >> 
> >> Testing "defined(LIBRESSL_VERSION_NUMBER)" is superfluous.
> >> The macro test suffers from a very long line.
> >> 
> >> The correct version test seems to be against LibreSSL 3.5.0, see
> >> https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt
> >> 
> >> So, the resulting change would be as follows:
> >> 
> >> diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
> >> --- a/src/event/ngx_event_openssl_stapling.c
> >> +++ b/src/event/ngx_event_openssl_stapling.c
> >> @@ -893,7 +893,9 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
> >>     ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> >>     ocsp->conf = ocf;
> >> 
> >> -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER)
> >> +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L \
> >> +     && !defined LIBRESSL_VERSION_NUMBER) \
> >> +    || LIBRESSL_VERSION_NUMBER >= 0x3050000fL
> > 
> > Rather, 
> > 
> > +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L                                    \
> > +     && (!defined LIBRESSL_VERSION_NUMBER                                     \
> > +         || LIBRESSL_VERSION_NUMBER >= 0x3050000fL))
> > 
> 
> Agree.  For the sake of completeness:
> 
> # HG changeset patch
> # User Sergey Kandaurov <pluknet at nginx.com>
> # Date 1703004490 -14400
> #      Tue Dec 19 20:48:10 2023 +0400
> # Node ID 267cee796462f4f6bacf825c8fd24d13845d36f4
> # Parent  7a6d52990f2e2d88460a3dc6cc84aac89b7329ea
> SSL: using SSL_get0_verified_chain() with LibreSSL 3.5.0+.
> 
> Prodded by Ilya Shipitsin.
> 
> diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
> --- a/src/event/ngx_event_openssl_stapling.c
> +++ b/src/event/ngx_event_openssl_stapling.c
> @@ -893,7 +893,9 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
>      ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
>      ocsp->conf = ocf;
>  
> -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER)
> +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L                                    \
> +     && (!defined LIBRESSL_VERSION_NUMBER                                     \
> +         || LIBRESSL_VERSION_NUMBER >= 0x3050000fL))
>  
>      ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
>  
> 
> >> 
> >>     ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> >> 
> >> 
> >> On the other hand, I don't like the resulting style mudness.
> >> It may have sense just to drop old LibreSSL versions support:
> >> maintaining one or two most recent stable branches should be enough.
> > 
> > +1 on this.
> > 
> > We certainly don't want to maintain support for ancient LibreSSL 
> > versions.  IMO, just two branches is more than enough (and this is 
> > what I use in my testing, which usually means latest development 
> > release and latest stable release).
> > 
> > At most, this probably can be three branches - which seems to 
> > match LibreSSL support policy, 
> > https://www.libressl.org/releases.html:
> > 
> > : LibreSSL transitions to a new stable release branch every 6 months 
> > : in coordination with the OpenBSD development schedule. LibreSSL 
> > : stable branches are updated for 1 year after their corresponding 
> > : OpenBSD branch is tagged for release. See below for the current 
> > : stable release branches.
> > 
> > In either case, LibreSSL versions below 3.5.0 are already not 
> > supported.  If I understand correctly, right now the oldest 
> > supported branch is 3.7.x.
> 
> Agree.  Also, Repology shows that modern popular distributions,
> such as Alpine Linux and FreeBSD, have at least LibreSSL 3.5.x:
> https://repology.org/project/libressl/versions
> 
> > 
> >> But anyway, I don't see an obvious win over the existing code:
> >> the certificate chain is reconstructed if SSL_get0_verified_chain()
> >> is (detected to be) not present, which should be fine in most cases.
> >> 
> >> That said, it doesn't seem to deserve introducing 3-line macro test,
> >> or (see OTOH note) breaking old LibreSSL support for no apparent reason.
> > 
> > Reconstruction of the chain implies verification of signatures 
> > along the chain and can be costly.  As such, it certainly would be 
> > better to use SSL_get0_verified_chain() as long as it is 
> > available.
> 
> Agree.
> My point is that not using SSL_get0_verified_chain() should not result
> in a broken functionality, as in the OCSP cert validation.
> So, intention to start using it in LibreSSL may look an insufficient
> argument per se to drop old LibreSSL versions.
> Though, dropping them may be orthogonal to SSL_get0_verified_chain().
> 
> > 
> > Also, removing the "!defined LIBRESSL_VERSION_NUMBER" check might 
> > be seen as positive even without any additional benefits.
> > 
> > Along with that, however, we might want to adjust the 
> > LIBRESSL_VERSION_NUMBER check in the ngx_event_openssl.h file, so 
> > OPENSSL_VERSION_NUMBER is set to a better value for old LibreSSL 
> > versions - for example, to only set OPENSSL_VERSION_NUMBER to 
> > 0x1010000fL for LibreSSL 3.5.0 or above.
> 
> Sounds like a plan if we are fine to drop older LibreSSL versions.
> 
> >  This might allow to 
> > preserve limited compatibility with ancient LibreSSL versions 
> > without additional efforts (not tested though).
> > 
> 
> This won't build with any LibreSSL version in the [2.8.0, 3.5.0) range.
> Particularly, SSL_CTX_sess_set_get_cb() has got a const argument in
> LibreSSL 2.8.0, which is not backward compatible, see 7337:cab37803ebb3.
> Another reason is SSL was made opaque by default in 3.4.x.

The const argument can be easily ignored by using 
-Wno-error=incompatible-function-pointer-types (or just 
-Wno-error), which seems to be reasonable when trying to build 
things with ancient libraries.  This makes it possible to build 
with LibreSSL 2.8.0-3.3.6 with minimal efforts.

For LibreSSL 3.4.x, the dependency on the SSL internals can be 
easily eliminated by testing SSL_OP_NO_CLIENT_RENEGOTIATION, which 
anyway seems to be a reasonable change.

> 
> (Others seem not to affect building on older versions if pick up 3.5.0:
> - X509_up_ref appeared in LibreSSL 2.6.0, X509 made opaque in 3.5.0;
> - X509_get0_notAfter appeared in 2.7.0, X509_get_notAfter still there.)
> 
> Personally I'm fine to drop ancient LibreSSL versions, because it has
> to happen someday and we don't want to maintain them eternally.
> Alternative patch for your consideration:
> 
> # HG changeset patch
> # User Sergey Kandaurov <pluknet at nginx.com>
> # Date 1703011348 -14400
> #      Tue Dec 19 22:42:28 2023 +0400
> # Node ID 94d4ef4a2316da66fea084952913ff2b0f84827d
> # Parent  7a6d52990f2e2d88460a3dc6cc84aac89b7329ea
> SSL: removed compatibility with LibreSSL < 3.5.0.
> 
> OPENSSL_VERSION_NUMBER is now redefined to 0x1010000fL for LibreSSL 3.5.0+.
> As older versions starting from LibreSSL 2.8.0 won't build with a lesser
> OPENSSL_VERSION_NUMBER value (see 7337:cab37803ebb3 for details), they are
> now explicitly unsupported.
> 
> Besides that, this allows to start using SSL_get0_verified_chain()
> with LibreSSL without additional macro tests.
> 
> diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
> --- a/src/event/ngx_event_openssl.h
> +++ b/src/event/ngx_event_openssl.h
> @@ -45,10 +45,10 @@
>  
>  #if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
>  #undef OPENSSL_VERSION_NUMBER
> -#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL)
> +#if (LIBRESSL_VERSION_NUMBER >= 0x3050000fL)
>  #define OPENSSL_VERSION_NUMBER  0x1010000fL
>  #else
> -#define OPENSSL_VERSION_NUMBER  0x1000107fL
> +#error LibreSSL too old, need at least 3.5.0
>  #endif
>  #endif

I'm certainly against the idea of explicitly rejecting old 
versions.  As demonstrated above, even versions affected by 
various changes can be used with minimal efforts, such as 
disabling -Werror.

For the record, here is a patch I tested with:

diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1105,7 +1105,8 @@ ngx_ssl_info_callback(const ngx_ssl_conn
     BIO               *rbio, *wbio;
     ngx_connection_t  *c;
 
-#ifndef SSL_OP_NO_RENEGOTIATION
+#if (!defined SSL_OP_NO_RENEGOTIATION                                         \
+     && !defined SSL_OP_NO_CLIENT_RENEGOTIATION)
 
     if ((where & SSL_CB_HANDSHAKE_START)
         && SSL_is_server((ngx_ssl_conn_t *) ssl_conn))
@@ -1838,9 +1839,10 @@ ngx_ssl_handshake(ngx_connection_t *c)
         c->read->ready = 1;
         c->write->ready = 1;
 
-#ifndef SSL_OP_NO_RENEGOTIATION
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-#ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS
+#if (!defined SSL_OP_NO_RENEGOTIATION                                         \
+     && !defined SSL_OP_NO_CLIENT_RENEGOTIATION                               \
+     && defined SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS                             \
+     && OPENSSL_VERSION_NUMBER < 0x10100000L)
 
         /* initial handshake done, disable renegotiation (CVE-2009-3555) */
         if (c->ssl->connection->s3 && SSL_is_server(c->ssl->connection)) {
@@ -1848,8 +1850,6 @@ ngx_ssl_handshake(ngx_connection_t *c)
         }
 
 #endif
-#endif
-#endif
 
 #if (defined BIO_get_ktls_send && !NGX_WIN32)
 
@@ -2483,7 +2483,8 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
     int        sslerr;
     ngx_err_t  err;
 
-#ifndef SSL_OP_NO_RENEGOTIATION
+#if (!defined SSL_OP_NO_RENEGOTIATION                                         \
+     && !defined SSL_OP_NO_CLIENT_RENEGOTIATION)
 
     if (c->ssl->renegotiation) {
         /*
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -45,7 +45,7 @@
 
 #if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
 #undef OPENSSL_VERSION_NUMBER
-#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL)
+#if (LIBRESSL_VERSION_NUMBER >= 0x3050000fL)
 #define OPENSSL_VERSION_NUMBER  0x1010000fL
 #else
 #define OPENSSL_VERSION_NUMBER  0x1000107fL
diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
--- a/src/event/ngx_event_openssl_stapling.c
+++ b/src/event/ngx_event_openssl_stapling.c
@@ -893,7 +893,7 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
     ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
     ocsp->conf = ocf;
 
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER)
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
 
     ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
 

-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list