On Fri, Jan 26, 2024 at 02:11:52PM -0800, Tim wrote:
> I'm trying to troubleshoot an issue where Chrome/Chromium browsers
> randomly fail to correctly use SSL against my web server.

This version of a diff from jsing for libssl (it applies with slight
offsets to 7.4-stable) should fix this issue.

Could you please try this with an unpached apache-httpd?

Index: s3_lib.c
===================================================================
RCS file: /cvs/src/lib/libssl/s3_lib.c,v
diff -u -p -r1.248 s3_lib.c
--- s3_lib.c    29 Nov 2023 13:39:34 -0000      1.248
+++ s3_lib.c    30 Jan 2024 11:34:10 -0000
@@ -1594,6 +1594,7 @@ ssl3_free(SSL *s)
        tls1_transcript_hash_free(s);
 
        free(s->s3->alpn_selected);
+       free(s->s3->alpn_wire_data);
 
        freezero(s->s3->peer_quic_transport_params,
            s->s3->peer_quic_transport_params_len);
@@ -1659,6 +1660,9 @@ ssl3_clear(SSL *s)
        free(s->s3->alpn_selected);
        s->s3->alpn_selected = NULL;
        s->s3->alpn_selected_len = 0;
+       free(s->s3->alpn_wire_data);
+       s->s3->alpn_wire_data = NULL;
+       s->s3->alpn_wire_data_len = 0;
 
        freezero(s->s3->peer_quic_transport_params,
            s->s3->peer_quic_transport_params_len);
Index: ssl_local.h
===================================================================
RCS file: /cvs/src/lib/libssl/ssl_local.h,v
diff -u -p -r1.12 ssl_local.h
--- ssl_local.h 29 Dec 2023 12:24:33 -0000      1.12
+++ ssl_local.h 30 Jan 2024 11:34:10 -0000
@@ -1209,6 +1209,8 @@ typedef struct ssl3_state_st {
         */
        uint8_t *alpn_selected;
        size_t alpn_selected_len;
+       uint8_t *alpn_wire_data;
+       size_t alpn_wire_data_len;
 
        /* Contains the QUIC transport params received from our peer. */
        uint8_t *peer_quic_transport_params;
Index: ssl_tlsext.c
===================================================================
RCS file: /cvs/src/lib/libssl/ssl_tlsext.c,v
diff -u -p -r1.137 ssl_tlsext.c
--- ssl_tlsext.c        28 Apr 2023 18:14:59 -0000      1.137
+++ ssl_tlsext.c        30 Jan 2024 11:34:10 -0000
@@ -86,33 +86,48 @@ tlsext_alpn_check_format(CBS *cbs)
 }
 
 static int
-tlsext_alpn_server_parse(SSL *s, uint16_t msg_types, CBS *cbs, int *alert)
+tlsext_alpn_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
 {
-       CBS alpn, selected_cbs;
-       const unsigned char *selected;
-       unsigned char selected_len;
-       int r;
+       CBS alpn;
 
        if (!CBS_get_u16_length_prefixed(cbs, &alpn))
                return 0;
-
        if (!tlsext_alpn_check_format(&alpn))
                return 0;
+       if (!CBS_stow(&alpn, &s->s3->alpn_wire_data, 
&s->s3->alpn_wire_data_len))
+               return 0;
+
+       return 1;
+}
+
+static int
+tlsext_alpn_server_process(SSL *s, uint16_t msg_type, int *alert)
+{
+       const unsigned char *selected;
+       unsigned char selected_len;
+       CBS alpn, selected_cbs;
+       int cb_ret;
 
        if (s->ctx->alpn_select_cb == NULL)
                return 1;
 
+       if (s->s3->alpn_wire_data == NULL) {
+               *alert = SSL_AD_INTERNAL_ERROR;
+               return 0;
+       }
+       CBS_init(&alpn, s->s3->alpn_wire_data, s->s3->alpn_wire_data_len);
+
        /*
         * XXX - A few things should be considered here:
         * 1. Ensure that the same protocol is selected on session resumption.
         * 2. Should the callback be called even if no ALPN extension was sent?
         * 3. TLSv1.2 and earlier: ensure that SNI has already been processed.
         */
-       r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
+       cb_ret = s->ctx->alpn_select_cb(s, &selected, &selected_len,
            CBS_data(&alpn), CBS_len(&alpn),
            s->ctx->alpn_select_cb_arg);
 
-       if (r == SSL_TLSEXT_ERR_OK) {
+       if (cb_ret == SSL_TLSEXT_ERR_OK) {
                CBS_init(&selected_cbs, selected, selected_len);
 
                if (!CBS_stow(&selected_cbs, &s->s3->alpn_selected,
@@ -125,7 +140,7 @@ tlsext_alpn_server_parse(SSL *s, uint16_
        }
 
        /* On SSL_TLSEXT_ERR_NOACK behave as if no callback was present. */
-       if (r == SSL_TLSEXT_ERR_NOACK)
+       if (cb_ret == SSL_TLSEXT_ERR_NOACK)
                return 1;
 
        *alert = SSL_AD_NO_APPLICATION_PROTOCOL;
@@ -1972,6 +1987,7 @@ struct tls_extension_funcs {
        int (*needs)(SSL *s, uint16_t msg_type);
        int (*build)(SSL *s, uint16_t msg_type, CBB *cbb);
        int (*parse)(SSL *s, uint16_t msg_type, CBS *cbs, int *alert);
+       int (*process)(SSL *s, uint16_t msg_type, int *alert);
 };
 
 struct tls_extension {
@@ -2123,6 +2139,7 @@ static const struct tls_extension tls_ex
                        .needs = tlsext_alpn_server_needs,
                        .build = tlsext_alpn_server_build,
                        .parse = tlsext_alpn_server_parse,
+                       .process = tlsext_alpn_server_process,
                },
        },
        {
@@ -2391,6 +2408,14 @@ tlsext_clienthello_hash_extension(SSL *s
        return 1;
 }
 
+static void
+tlsext_cleanup(SSL *s)
+{
+       free(s->s3->alpn_wire_data);
+       s->s3->alpn_wire_data = NULL;
+       s->s3->alpn_wire_data_len = 0;
+}
+
 static int
 tlsext_parse(SSL *s, int is_server, uint16_t msg_type, CBS *cbs, int *alert)
 {
@@ -2466,6 +2491,36 @@ tlsext_parse(SSL *s, int is_server, uint
        return 0;
 }
 
+static int
+tlsext_process(SSL *s, int is_server, uint16_t msg_type, int *alert)
+{
+       const struct tls_extension_funcs *ext;
+       const struct tls_extension *tlsext;
+       int alert_desc;
+       size_t idx;
+
+       alert_desc = SSL_AD_DECODE_ERROR;
+
+       /* Run processing for present TLS extensions, in a defined order. */
+       for (idx = 0; idx < N_TLS_EXTENSIONS; idx++) {
+               tlsext = &tls_extensions[idx];
+               if ((s->s3->hs.extensions_seen & (1 << idx)) == 0)
+                       continue;
+               ext = tlsext_funcs(tlsext, is_server);
+               if (ext->process == NULL)
+                       continue;
+               if (!ext->process(s, msg_type, &alert_desc))
+                       goto err;
+       }
+
+       return 1;
+
+ err:
+       *alert = alert_desc;
+
+       return 0;
+}
+
 static void
 tlsext_server_reset_state(SSL *s)
 {
@@ -2486,11 +2541,23 @@ tlsext_server_build(SSL *s, uint16_t msg
 int
 tlsext_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
 {
+       int ret = 0;
+
        /* XXX - this should be done by the caller... */
        if (msg_type == SSL_TLSEXT_MSG_CH)
                tlsext_server_reset_state(s);
 
-       return tlsext_parse(s, 1, msg_type, cbs, alert);
+       if (!tlsext_parse(s, 1, msg_type, cbs, alert))
+               goto err;
+       if (!tlsext_process(s, 1, msg_type, alert))
+               goto err;
+
+       ret = 1;
+
+ err:
+       tlsext_cleanup(s);
+
+       return ret;
 }
 
 static void

Reply via email to