Hello Mariam,

On Wed, Jan 29, 2025 at 05:59:37AM -0600, Mariam John wrote:
> Hello William,
> 
>   Thank you for your feedback on this PR and apologies for the delay. I 
> addressed all the comments from
> your last review.:
> - included the SSL bind equivalent for each fetch and fixed a typo in the 
> name of a fetch. 
> - Undid the changes to buf-t.h 
> - Updated test to support AWS-LC
> - Added a new function to do generic clienthello parsing that you can be used 
> in every fetch in payload.c
> 
> Thanks,
> Mariam.
 
Thanks Mariam, I made comments inline, in addition to the following comments.

Note that there are a lot of spaces/tabs problems in your patch, you should try 
enable a way to differenciate them in
your editor. We are using tabs for indentation, and spaces for alignment, you 
could look for examples here
https://www.haproxy.org/coding-style.html

Try to do a `git log -p` of your patches before submitting, it should show you 
the trailing spaces and tabs in red.
If not, you must enable 'color.ui = auto' in your git configuration.

I didn't mention all spaces/tabs problems in my review, but I could fix the 
remaining in your next iteration if that's
fine with you.

The patch is becoming quite big because of the changes with your new parsing 
function, You should split this in multiple
parts to be more readable, it's quite difficult to understand the changes 
currently, because the chunks are mixed up in
the patch.

You could proceed in this order:

1. a patch with your new fetches like you've done previously, without the 
smp_client_hello_parse()
2. a patch with your new reg-test
3. a patch which introduces the new smp_client_hello_parse() function and uses 
it in every fetches

On Wed, Jan 29, 2025 at 05:59:38AM -0600, Mariam John wrote:
> Subject: [PATCH 1/1] MINOR: sample: Add sample fetches for enhanced 
> observability for TLS ClientHello
> Add new sample fetches to get the ciphers, supported groups, key shares and 
> signature algorithms
> that the client supports during a TLS handshake as part of the contents of a 
> TLS ClientHello.
> Currently we can get the following contents of the ClientHello message: 
> SNI(req_ssl_sni) and
> TLS protocol version(req_ssl_ver). The following new sample fetches will be 
> added to get the
> following contents of the ClientHello message exchanged during the TLS 
> handshake (supported by
> the client):
> - req.ssl_cipherlist: Returns the binary form of the list of symmetric cipher 
> options
> - req.ssl_sigalgs: Returns the binary form of the list of signature algorithms
> - req.ssl_keyshare_groups: Return the binary format of the list of key share 
> group
> - req.ssl_supported_groups: Returns the binary form of the list of supported 
> groups used in key exchange
> 
> This added functionality would allow routing with fine granularity pending 
> the capabilities the client
> indicates in the ClientHello. For example, this would allow the ability to 
> enable TLS passthrough or
> TLS termination based on the supported groups detected in the ClientHello 
> message. Another usage is to
> take client key shares into consideration when deciding which of the client 
> supported groups should be
> used for groups considered to have 'equal security level' as well as enabling 
> fine grain selection of
> certificate types(beyond the RSA vs ECC distinction). All of that is relevant 
> in the context of rapidly
> upcoming PQC operation modes.
> 
> Fixes: #2532
> ---
>  doc/configuration.txt                       |  66 ++
>  reg-tests/checks/tcp-check-client-hello.vtc |  82 +++
>  src/payload.c                               | 697 ++++++++++----------
>  3 files changed, 479 insertions(+), 366 deletions(-)
>  create mode 100644 reg-tests/checks/tcp-check-client-hello.vtc
> 
> diff --git a/doc/configuration.txt b/doc/configuration.txt
> index da9d8b540..ab39da283 100644
> --- a/doc/configuration.txt
> +++ b/doc/configuration.txt
>  [...]
> +
> +req.ssl_supported_groups binary
> +  Returns the binary form of the list of supported groups supported by the 
> client
> +  as reported in the TLS ClientHello and used for key exchange which can 
> include
> +  both elliptic curve and non-EC key exchange. Note that this only applies 
> to raw
> +  contents found in the request buffer and not to contents deciphered via an 
> SSL
> +  data layer, so this will not  work with "bind" lines having the "ssl" 
> option.
> +  Refer to "ssl_fc_eclist_bin" hich is the SSL bind equivalent that can be 
> used

                                  ^ small typo there "which"

> +  when the "ssl" option is specified.
> +
> +  Examples :
> +     # Wait for a client hello for at most 5 seconds
> +     tcp-request inspect-delay 5s
> +     tcp-request content accept if { req.ssl_hello_type 1 }
> +     use-server fe3 if { req.ssl_supported_groups, be2hex(:,2),lower -m sub 
> 0017 }
> +     server fe3  ${htst_fe3_addr}:${htst_fe3_port}
> +
>  req.ssl_st_ext : integer
>    Returns 0 if the client didn't send a SessionTicket TLS Extension (RFC5077)
>    Returns 1 if the client sent SessionTicket TLS Extension
> diff --git a/reg-tests/checks/tcp-check-client-hello.vtc 
> b/reg-tests/checks/tcp-check-client-hello.vtc
> new file mode 100644
> index 000000000..137361c65
> --- /dev/null
> +++ b/reg-tests/checks/tcp-check-client-hello.vtc
> @@ -0,0 +1,82 @@
> +#REQUIRE_OPTION=OPENSSL

^ this part is not necessary since you are already doing 'feature(OPENSSL)', 
that was the old way to check this.

> +#REGTEST_TYPE=slow

"slow" types are not executed by the CI, and your test is fairly fast, you 
should change its type to "devel" to see its
result on the CI.

> +#EXCLUDE_TARGETS=osx,generic
> +
> +varnishtest "Health checks: test enhanced observability of TLS ClientHello"
> +feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && 
> !ssllib_name_startswith(wolfSSL) && !ssllib_name_startswith(LibreSSL) && 
> openssl_version_atleast(1.1.1)'"
> +feature ignore_unknown_macro
> +
> +syslog S_ok -level notice {
> +    recv
> +    expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv 
> succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, 
> status: 1/1 UP."
> +    recv
> +    expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv 
> succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, 
> status: 1/1 UP."
> +    recv
> +    expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv 
> succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, 
> status: 1/1 UP."
> +} -start
> +
> +haproxy htst -conf {
> +    global
> +        ssl-default-bind-options ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.3
> +
> +    defaults
> +        log global
> +        option tcplog
> +        timeout  client "${HAPROXY_TEST_TIMEOUT-5s}"
> +        timeout  server "${HAPROXY_TEST_TIMEOUT-5s}"
> +        timeout  connect "${HAPROXY_TEST_TIMEOUT-5s}"
> +
> +    listen li1
> +       mode tcp
> +       bind "fd@${li1}"
> +       tcp-request inspect-delay 100ms
> +       
> +       acl check_sig_algs req.ssl_sigalgs,be2hex(:,2),lower -m found
> +       acl check_key_shares req.ssl_keyshare_groups,be2hex(:,2),lower -m 
> found
> +       tcp-request content accept if check_sig_algs
> +       tcp-request content accept if check_key_shares
> +       
> +       # Refer to 
> https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.8 && 
> https://tls13.xargs.org/#client-hello/annotated to get the binary values
> +       use-server fe3 if { req.ssl_cipherlist,be2hex(:,2),lower -m sub 
> 1302:1303:1301:009f } || { req.ssl_supported_groups, be2hex(:,2),lower -m sub 
> 001d }

That's an interesting way to use the fetches, I wonder if we could find a way 
to simplify this kind of configuration at
some point, by having the list of encoded hex values associated to a string 
name for example, we don't really have a way
to do this right now, but I'll keep that in mind for future evolution of the 
configuration.

> +       server fe3  ${htst_fe3_addr}:${htst_fe3_port}
> +
> +       use-server fe1 if { req.ssl_supported_groups, be2hex(:,2),lower -m 
> sub 0017 }
> +       server fe1 ${htst_fe1_addr}:${htst_fe1_port}
> +
> +    frontend fe1
> +        bind "fd@${fe1}" ssl crt ${testdir}/common.pem curves P-256:P-384
> +
> +    frontend fe3
> +        bind "fd@${fe3}" ssl crt ${testdir}/common.pem
> +} -start
> +
> +haproxy h1 -conf {
> +    defaults
> +        mode tcp
> +        timeout  client "${HAPROXY_TEST_TIMEOUT-5s}"
> +        timeout  server "${HAPROXY_TEST_TIMEOUT-5s}"
> +        timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
> +
> +    backend be1
> +        mode tcp
> +        log ${S_ok_addr}:${S_ok_port} daemon
> +        option log-health-checks
> +        option tcp-check
> +        server srv ${htst_li1_addr}:${htst_li1_port}  check inter 1s rise 1 
> fall 1 check-ssl verify none curves X25519
> +
> +    backend be2
> +        mode tcp
> +        log ${S_ok_addr}:${S_ok_port} daemon
> +        option log-health-checks
> +        option tcp-check
> +        server srv ${htst_li1_addr}:${htst_li1_port}  check inter 1s rise 1 
> fall 1 check-ssl verify none curves P-256:P-384
> +
> +    backend be3
> +        mode tcp
> +        log ${S_ok_addr}:${S_ok_port} daemon
> +        option log-health-checks
> +        option tcp-check
> +        server srv ${htst_li1_addr}:${htst_li1_port}  check inter 1s rise 1 
> fall 1 check-ssl verify none ciphers DHE-RSA-AES256-GCM-SHA384

I'm sure this one won't work with AWS-LC, the "DHE-RSA-AES256-GCM-SHA384" is 
not implemented
(https://github.com/aws/aws-lc/blob/main/docs/porting/functionality-differences.md),
 however
"ECDHE-RSA-AES256-GCM-SHA384" is, you could use it instead.

> +} -start
> +
> +syslog S_ok -wait
> diff --git a/src/payload.c b/src/payload.c
> index 6a536d719..bb1970c8b 100644
> --- a/src/payload.c
> +++ b/src/payload.c
> @@ -31,6 +31,19 @@
>  /*       All supported sample fetch functions must be declared here     */
>  /************************************************************************/
>  
> +int NOT_SSL_HELLO = 1;
> +int TOO_SHORT = 2;
> 

Using shared variables will be a problem there, the fetch could be used on 
multiple connections and threads at the same
time, but according to the code below you don't use these variables and just 
need a enum, maybe something like this
could do:

enum {
        CLIENTHELLO_ERR_OK = 0,
        CLIENTHELLO_ERR_UNAVAIL = 1,
        CLIENTHELLO_ERR_TOO_SHORT = 2,
};


> +/**
> + * struct to hold variables used during generic client hello parsing
> + */
> +struct clnt_hello_proc {
> +               int hs_len;
> +               int ext_len;
> +               int status;
        ^ tabs followed by spaces, you should only have one tab there

> +          unsigned char *data;

        ^ you should have a tab instead of spaces there.

> +};
> +

I don't know if we need the ext_len in this clnt_hello_proc structure, I think 
we only need hs_len since we need to jump to the list of
extensions.

If we look at the existing functions there are:

- smp_fetch_req_ssl_st_ext
- smp_fetch_req_ssl_ec_ext
- smp_fetch_ssl_hello_sni
- smp_fetch_ssl_hello_alpn

Which are all parsing TLS extensions, so we could just have a function which 
jumps to the offset at the start of the
extensions, and returns the number of bytes remaining in the buffer (hs_len), 
then these functions could still do the
parsing of each extensions in their loop:

        while (hs_len >= 4) {
                int ext_type, ext_len;

                ext_type = (data[0] << 8) + data[1];
                ext_len  = (data[2] << 8) + data[3];

                [...]
        }

Your new functions:

- smp_fetch_ssl_supported_groups
- smp_fetch_ssl_sigalgs
- smp_fetch_ssl_keyshare_groups

Are also parsing extensions so we can use the same method.

However smp_fetch_ssl_cipherlist() is different, it's not about parsing a TLS 
extension, but it parses the CipherSuite
field, so you could probably keep a separated function for this, or use an 
argument in your function. That's probably why you added
processCompressionMethods in the smp_client_hello_parse() but I find the name 
confusing.

We could have something which returns the offset corresponding to what we want, 
and use a union like this:

union {
        CLIENTHELLO_OF_EXTENSIONS,
        CLIENTHELLO_OF_CIPHERSUITE,
};

smp_client_hello_parse([...], CLIENTHELLO_OF_CIPHERSUITE)

>  /* wait for more data as long as possible, then return TRUE. This should be
>   * used with content inspection.
>   */
> @@ -75,18 +88,44 @@ smp_fetch_len(const struct arg *args, struct sample *smp, 
> const char *kw, void *
>       return 1;
>  }
>  
> -/* Returns 0 if the client didn't send a SessionTicket Extension
> - * Returns 1 if the client sent SessionTicket Extension
> - * Returns 2 if the client also sent non-zero length SessionTicket
> - * Returns SMP_T_SINT data type
> +/* Extract information presented in a TLS client hello handshake message.
> + * The format of the message is the following (cf RFC5246 + RFC6066) :
> + * TLS frame :
> + *   - uint8  type                            = 0x16   (Handshake)
> + *   - uint16 version                        >= 0x0301 (TLSv1)
> + *   - uint16 length                                   (frame length)
> + *   - TLS handshake :
> + *     - uint8  msg_type                      = 0x01   (ClientHello)
> + *     - uint24 length                                 (handshake message 
> length)
> + *     - ClientHello :
> + *       - uint16 client_version             >= 0x0301 (TLSv1)
> + *       - uint8 Random[32]                  (4 first ones are timestamp)
> + *       - SessionID :
> + *         - uint8 session_id_len (0..32)              (SessionID len in 
> bytes)
> + *         - uint8 session_id[session_id_len]
> + *       - CipherSuite :
> + *         - uint16 cipher_len               >= 2      (Cipher length in 
> bytes)
> + *         - uint16 ciphers[cipher_len/2]
> + *       - CompressionMethod :
> + *         - uint8 compression_len           >= 1      (# of supported 
> methods)
> + *         - uint8 compression_methods[compression_len]
> + *       - optional client_extension_len               (in bytes)
> + *       - optional sequence of ClientHelloExtensions  (as many bytes as 
> above):
> + *         - uint16 extension_type            = 0 for server_name
> + *         - uint16 extension_len
> + *         - opaque extension_data[extension_len]
> + *           - uint16 server_name_list_len             (# of bytes here)
> + *           - opaque server_names[server_name_list_len bytes]
> + *             - uint8 name_type              = 0 for host_name
> + *             - uint16 name_len
> + *             - opaque hostname[name_len bytes]
>   */
> -static int
> -smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
> -{
> -     int hs_len, ext_len, bleft;
> +struct clnt_hello_proc smp_client_hello_parse( struct sample *smp, int 
> processCompressionMethods ) {
> +    int hs_len, ext_len, bleft, status=0;
>       struct channel *chn;
> +     struct clnt_hello_proc cp;
>       unsigned char *data;

Lots of space/tab changes that musn't be there:

> -
> + 

^ unwanted space
>       if (!smp->strm)
>               goto not_ssl_hello;
>  
> @@ -94,8 +133,7 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct 
> sample *smp, const char
>       if (IS_HTX_STRM(smp->strm))
>               goto not_ssl_hello;
>  
> -     chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : 
> &smp->strm->req;
> -
> +    chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : 
> &smp->strm->req;
>  

^ tab was changed to spaces

>       bleft = ci_data(chn);
>       data = (unsigned char *)ci_head(chn);
> @@ -103,7 +141,7 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct 
> sample *smp, const char
>       /* Check for SSL/TLS Handshake */
>       if (!bleft)
>               goto too_short;
> -     if (*data != 0x16)
> +     if(*data != 0x16)

          ^ space removed

>               goto not_ssl_hello;
>  
>       /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
> @@ -114,10 +152,11 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct 
> sample *smp, const char
>  
>       if (bleft < 5)
>               goto too_short;
> +
>       hs_len = (data[3] << 8) + data[4];
>       if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
>               goto not_ssl_hello; /* too short to have an extension */
> -
> +             

         ^ unwanted tabs

>       data += 5; /* enter TLS handshake */
>       bleft -= 5;
>  
> @@ -130,6 +169,7 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct 
> sample *smp, const char
>       /* Check the Hello's length */
>       if (bleft < 4)
>               goto too_short;
> +
>       hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
>       if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
>               goto not_ssl_hello; /* too short to have an extension */



> @@ -156,32 +196,64 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct 
> sample *smp, const char
>           ext_len > hs_len)
>               goto not_ssl_hello;
>  
> -     /* Jump to the compression methods */
> -     hs_len -= 2 + ext_len;
> -     data   += 2 + ext_len;
> +     /* Jump to the compression methods. For fetching cipher list this 
> processing is not required. */
> +     if (processCompressionMethods == 1) {

There you could just do something like:

if (type == CLIENTHELLO_CIPHERSUITE)
        goto end;


> +             hs_len -= 2 + ext_len;
> +             data   += 2 + ext_len;
>  
> -     if (hs_len < 2 ||                       /* minimum one compression 
> method */
> +             if (hs_len < 2 ||                       /* minimum one 
> compression method */
>           data[0] < 1 || data[0] > hs_len)    /* minimum 1 bytes for a method 
> */
> -             goto not_ssl_hello;
> +                     goto not_ssl_hello;
>  
> -     /* Jump to the extensions */
> -     hs_len -= 1 + data[0];
> -     data   += 1 + data[0];
> +             /* Jump to the extensions */
> +             hs_len -= 1 + data[0];
> +             data   += 1 + data[0];
>  
> -     if (hs_len < 2 ||                       /* minimum one extension list 
> length */
> +             if (hs_len < 2 ||                       /* minimum one 
> extension list length */
>           (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long 
> */
> -             goto not_ssl_hello;
> +                     goto not_ssl_hello;
>  
> -     hs_len = ext_len; /* limit ourselves to the extension length */
> -     data += 2;
> +             hs_len = ext_len; /* limit ourselves to the extension length */
> +             data += 2;
> +    }

add a 'end:' label there.

> +     cp.hs_len = hs_len;
> +     cp.ext_len = ext_len;
> +     cp.data = data;
> +     cp.status = status;
> +     return cp;
> +    

^ unwanted spaces
> +     not_ssl_hello:
> +             cp.status = NOT_SSL_HELLO;
> +     

^ unwanted tab

> +     too_short:
> +             cp.status = TOO_SHORT;
> +
> +     return cp;
> +}
>  



> -     while (hs_len >= 4) {
> +/* Returns 0 if the client didn't send a SessionTicket Extension
> + * Returns 1 if the client sent SessionTicket Extension
> + * Returns 2 if the client also sent non-zero length SessionTicket
> + * Returns SMP_T_SINT data type
> + */
> +static int
> +smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
> +{
> +     struct clnt_hello_proc cp;
> +
> +    cp = smp_client_hello_parse(smp, 1);

    ^ tab instead of spaces there

> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
> +             goto too_short;
> +
> +     while (cp.hs_len >= 4) {
>               int ext_type, ext_len;
>  
> -             ext_type = (data[0] << 8) + data[1];
> -             ext_len  = (data[2] << 8) + data[3];
> +             ext_type = (cp.data[0] << 8) + cp.data[1];
> +             ext_len  = (cp.data[2] << 8) + cp.data[3];
>  
> -             if (ext_len > hs_len - 4) /* Extension too long */
> +             if (ext_len > cp.hs_len - 4) /* Extension too long */
>                       goto not_ssl_hello;
>  
>               /* SesstionTicket extension */
> @@ -197,8 +269,8 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct 
> sample *smp, const char
>                       return 1;
>               }
>  
> -             hs_len -= 4 + ext_len;
> -             data   += 4 + ext_len;
> +             cp.hs_len -= 4 + ext_len;
> +             cp.data   += 4 + ext_len;
>       }
>       /* SessionTicket Extension not found */
>       smp->data.type = SMP_T_SINT;
> @@ -219,103 +291,21 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, 
> struct sample *smp, const char
>  static int
>  smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
>  {
> -     int hs_len, ext_len, bleft;
> -     struct channel *chn;
> -     unsigned char *data;
> +     struct clnt_hello_proc cp;
>  
> -     if (!smp->strm)
> -             goto not_ssl_hello;
> -
> -     /* meaningless for HTX buffers */
> -     if (IS_HTX_STRM(smp->strm))
> -             goto not_ssl_hello;
> -
> -     chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : 
> &smp->strm->req;
> -     bleft = ci_data(chn);
> -     data = (unsigned char *)ci_head(chn);
> -
> -     /* Check for SSL/TLS Handshake */
> -     if (!bleft)
> -             goto too_short;
> -     if (*data != 0x16)
> -             goto not_ssl_hello;
> -
> -     /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
> -     if (bleft < 3)
> +    cp = smp_client_hello_parse(smp, 1);
> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
>               goto too_short;
> -     if (data[1] < 0x03)
> -             goto not_ssl_hello;
>  
> -     if (bleft < 5)
> -             goto too_short;
> -     hs_len = (data[3] << 8) + data[4];
> -     if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
> -             goto not_ssl_hello; /* too short to have an extension */
> -
> -     data += 5; /* enter TLS handshake */
> -     bleft -= 5;
> -
> -     /* Check for a complete client hello starting at <data> */
> -     if (bleft < 1)
> -             goto too_short;
> -     if (data[0] != 0x01) /* msg_type = Client Hello */
> -             goto not_ssl_hello;
> -
> -     /* Check the Hello's length */
> -     if (bleft < 4)
> -             goto too_short;
> -     hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
> -     if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
> -             goto not_ssl_hello; /* too short to have an extension */
> -
> -     /* We want the full handshake here */
> -     if (bleft < hs_len)
> -             goto too_short;
> -
> -     data += 4;
> -     /* Start of the ClientHello message */
> -     if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
> -             goto not_ssl_hello;
> -
> -     ext_len = data[34]; /* session_id_len */
> -     if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct 
> session_id len */
> -             goto not_ssl_hello;
> -
> -     /* Jump to cipher suite */
> -     hs_len -= 35 + ext_len;
> -     data   += 35 + ext_len;
> -
> -     if (hs_len < 4 ||                               /* minimum one cipher */
> -         (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for 
> a cipher */
> -         ext_len > hs_len)
> -             goto not_ssl_hello;
> -
> -     /* Jump to the compression methods */
> -     hs_len -= 2 + ext_len;
> -     data   += 2 + ext_len;
> -
> -     if (hs_len < 2 ||                       /* minimum one compression 
> method */
> -         data[0] < 1 || data[0] > hs_len)    /* minimum 1 bytes for a method 
> */
> -             goto not_ssl_hello;
> -
> -     /* Jump to the extensions */
> -     hs_len -= 1 + data[0];
> -     data   += 1 + data[0];
> -
> -     if (hs_len < 2 ||                       /* minimum one extension list 
> length */
> -         (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long 
> */
> -             goto not_ssl_hello;
> -
> -     hs_len = ext_len; /* limit ourselves to the extension length */
> -     data += 2;
> -
> -     while (hs_len >= 4) {
> +     while (cp.hs_len >= 4) {
>               int ext_type, ext_len;
>  
> -             ext_type = (data[0] << 8) + data[1];
> -             ext_len  = (data[2] << 8) + data[3];
> +             ext_type = (cp.data[0] << 8) + cp.data[1];
> +             ext_len  = (cp.data[2] << 8) + cp.data[3];
>  
> -             if (ext_len > hs_len - 4) /* Extension too long */
> +             if (ext_len > cp.hs_len - 4) /* Extension too long */
>                       goto not_ssl_hello;
>  
>               /* Elliptic curves extension */
> @@ -326,8 +316,8 @@ smp_fetch_req_ssl_ec_ext(const struct arg *args, struct 
> sample *smp, const char
>                       return 1;
>               }
>  
> -             hs_len -= 4 + ext_len;
> -             data   += 4 + ext_len;
> +             cp.hs_len -= 4 + ext_len;
> +             cp.data   += 4 + ext_len;
>       }
>       /* server name not found */
>       goto not_ssl_hello;
> @@ -336,9 +326,9 @@ smp_fetch_req_ssl_ec_ext(const struct arg *args, struct 
> sample *smp, const char
>       smp->flags = SMP_F_MAY_CHANGE;
>  
>   not_ssl_hello:
> -
>       return 0;
>  }
> +
>  /* returns the type of SSL hello message (mainly used to detect an SSL 
> hello) */
>  static int
>  smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
> @@ -522,163 +512,246 @@ smp_fetch_req_ssl_ver(const struct arg *args, struct 
> sample *smp, const char *kw
>       return 0;
>  }
>  
> -/* Try to extract the Server Name Indication that may be presented in a TLS
> - * client hello handshake message. The format of the message is the following
> - * (cf RFC5246 + RFC6066) :
> - * TLS frame :
> - *   - uint8  type                            = 0x16   (Handshake)
> - *   - uint16 version                        >= 0x0301 (TLSv1)
> - *   - uint16 length                                   (frame length)
> - *   - TLS handshake :
> - *     - uint8  msg_type                      = 0x01   (ClientHello)
> - *     - uint24 length                                 (handshake message 
> length)
> - *     - ClientHello :
> - *       - uint16 client_version             >= 0x0301 (TLSv1)
> - *       - uint8 Random[32]                  (4 first ones are timestamp)
> - *       - SessionID :
> - *         - uint8 session_id_len (0..32)              (SessionID len in 
> bytes)
> - *         - uint8 session_id[session_id_len]
> - *       - CipherSuite :
> - *         - uint16 cipher_len               >= 2      (Cipher length in 
> bytes)
> - *         - uint16 ciphers[cipher_len/2]
> - *       - CompressionMethod :
> - *         - uint8 compression_len           >= 1      (# of supported 
> methods)
> - *         - uint8 compression_methods[compression_len]
> - *       - optional client_extension_len               (in bytes)
> - *       - optional sequence of ClientHelloExtensions  (as many bytes as 
> above):
> - *         - uint16 extension_type            = 0 for server_name
> - *         - uint16 extension_len
> - *         - opaque extension_data[extension_len]
> - *           - uint16 server_name_list_len             (# of bytes here)
> - *           - opaque server_names[server_name_list_len bytes]
> - *             - uint8 name_type              = 0 for host_name
> - *             - uint16 name_len
> - *             - opaque hostname[name_len bytes]
> +/*
> + * Extract the ciphers that may be presented in a TLS client hello handshake 
> message.
>   */
>  static int
> -smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
> +smp_fetch_ssl_cipherlist(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
>  {
> -     int hs_len, ext_len, bleft;
> -     struct channel *chn;
> -     unsigned char *data;
> +    struct clnt_hello_proc cp;
>  
> -     if (!smp->strm)
> -             goto not_ssl_hello;
> +    cp = smp_client_hello_parse(smp, 0);
> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
> +             goto too_short;
>  
> -     /* meaningless for HTX buffers */
> -     if (IS_HTX_STRM(smp->strm))
> -             goto not_ssl_hello;
> +     smp->data.type = SMP_T_BIN;
> +     smp->data.u.str.area = (char *)cp.data + 2;
> +     smp->data.u.str.data = cp.ext_len;
> +     smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
>  
> -     chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : 
> &smp->strm->req;
> -     bleft = ci_data(chn);
> -     data = (unsigned char *)ci_head(chn);
> +     return 1;
>  
> -     /* Check for SSL/TLS Handshake */
> -     if (!bleft)
> -             goto too_short;
> -     if (*data != 0x16)
> -             goto not_ssl_hello;
> +     too_short:
> +       smp->flags = SMP_F_MAY_CHANGE;
>  
> -     /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
> -     if (bleft < 3)
> -             goto too_short;
> -     if (data[1] < 0x03)
> -             goto not_ssl_hello;
> +     not_ssl_hello:
> +       return 0;
> +}
>  
> -     if (bleft < 5)
> +/* 
> + * Extract the supported group that may be presented in a TLS client hello 
> handshake
> + */
> +static int
> +smp_fetch_ssl_supported_groups(const struct arg *args, struct sample *smp, 
> const char *kw, void *private)
> +{
> +     struct clnt_hello_proc cp;
> +    cp = smp_client_hello_parse(smp, 1);
> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
>               goto too_short;
> -     hs_len = (data[3] << 8) + data[4];
> -     if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
> -             goto not_ssl_hello; /* too short to have an extension */
>  
> -     data += 5; /* enter TLS handshake */
> -     bleft -= 5;
> +    while (cp.hs_len >= 4) {
> +             int ext_type, ext_len, grp_len;
>  
> -     /* Check for a complete client hello starting at <data> */
> -     if (bleft < 1)
> -             goto too_short;
> -     if (data[0] != 0x01) /* msg_type = Client Hello */
> -             goto not_ssl_hello;
> +        ext_type = (cp.data[0] << 8) + cp.data[1]; /* Extension type */
> +        ext_len  = (cp.data[2] << 8) + cp.data[3]; /* Extension length */
>  
> -     /* Check the Hello's length */
> -     if (bleft < 4)
> -             goto too_short;
> -     hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
> -     if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
> -             goto not_ssl_hello; /* too short to have an extension */
> +        if (ext_len > cp.hs_len - 4) /* Extension too long */
> +            goto not_ssl_hello;
>  
> -     /* We want the full handshake here */
> -     if (bleft < hs_len)
> +        if (ext_type == 10) { /* Supported groups extension type ID is 10dec 
> */
> +            if (ext_len < 2) /* need at least one entry of 2 bytes in the 
> list length */
> +                goto not_ssl_hello;
> +
> +            grp_len = (cp.data[4] << 8) + cp.data[5]; /* Supported group 
> list length */
> +            if (grp_len < 2 || grp_len > cp.hs_len - 6)
> +                goto not_ssl_hello; /* at least 2 bytes per supported group 
> */
> +
> +            smp->data.type = SMP_T_BIN;
> +            smp->data.u.str.area = (char *)cp.data + 6;
> +            smp->data.u.str.data = grp_len;
> +            smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
> +
> +            return 1;
> +        }
> +        cp.hs_len -= 4 + ext_len;
> +        cp.data   += 4 + ext_len;
> +    }
> +    /* supported groups not found */
> +    goto not_ssl_hello;
> +
> +    too_short:
> +     smp->flags = SMP_F_MAY_CHANGE;
> +
> +     not_ssl_hello:
> +     return 0;
> +}
> +
> +/*
> + * Extract the signature algorithms that may be presented in a TLS client 
> hello
> + * handshake message.
> + */
> +static int
> +smp_fetch_ssl_sigalgs(const struct arg *args, struct sample *smp, const char 
> *kw, void *private)
> +{
> +    struct clnt_hello_proc cp;
> +    cp = smp_client_hello_parse(smp, 1);
> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
>               goto too_short;
>  
> -     data += 4;
> -     /* Start of the ClientHello message */
> -     if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
> -             goto not_ssl_hello;
> +    while (cp.hs_len >= 4) {
> +         int ext_type, ext_len, sigalg_len;
>  
> -     ext_len = data[34]; /* session_id_len */
> -     if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct 
> session_id len */
> -             goto not_ssl_hello;
> +         ext_type = (cp.data[0] << 8) + cp.data[1]; /* Extension type */
> +         ext_len  = (cp.data[2] << 8) + cp.data[3]; /* Extension length */
>  
> -     /* Jump to cipher suite */
> -     hs_len -= 35 + ext_len;
> -     data   += 35 + ext_len;
> +         if (ext_len > cp.hs_len - 4) /* Extension too long */
> +                 goto not_ssl_hello;
>  
> -     if (hs_len < 4 ||                               /* minimum one cipher */
> -         (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for 
> a cipher */
> -         ext_len > hs_len)
> -             goto not_ssl_hello;
> +         if (ext_type == 13) { /* Sigalgs extension type ID is 13dec */
> +                 if (ext_len < 2) /* need at least one entry of 2 bytes in 
> the list length */
> +                         goto not_ssl_hello;
>  
> -     /* Jump to the compression methods */
> -     hs_len -= 2 + ext_len;
> -     data   += 2 + ext_len;
> +                 sigalg_len = (cp.data[4] << 8) + cp.data[5]; /* Sigalgs 
> list length */
> +                 if (sigalg_len < 2 || sigalg_len > cp.hs_len - 6)
> +                         goto not_ssl_hello; /* at least 2 bytes per sigalg 
> */
>  
> -     if (hs_len < 2 ||                       /* minimum one compression 
> method */
> -         data[0] < 1 || data[0] > hs_len)    /* minimum 1 bytes for a method 
> */
> -             goto not_ssl_hello;
> +                 smp->data.type = SMP_T_BIN;
> +                 smp->data.u.str.area = (char *)cp.data + 6;
> +                 smp->data.u.str.data = sigalg_len;
> +                 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
>  
> -     /* Jump to the extensions */
> -     hs_len -= 1 + data[0];
> -     data   += 1 + data[0];
> +                 return 1;
>  
> -     if (hs_len < 2 ||                       /* minimum one extension list 
> length */
> -         (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long 
> */
> -             goto not_ssl_hello;
> +        }
> +        cp.hs_len -= 4 + ext_len;
> +        cp.data   += 4 + ext_len;
> +    }
> +    /* sigalgs not found */
> +    goto not_ssl_hello;
>  
> -     hs_len = ext_len; /* limit ourselves to the extension length */
> -     data += 2;
> +    too_short:
> +       smp->flags = SMP_F_MAY_CHANGE;
>  
> -     while (hs_len >= 4) {
> -             int ext_type, name_type, srv_len, name_len;
> +    not_ssl_hello:
> +       return 0;
> +}
>  
> -             ext_type = (data[0] << 8) + data[1];
> -             ext_len  = (data[2] << 8) + data[3];
> +/*
> + * Extract the key shares that may be presented in a TLS client hello 
> handshake message.
> + */
> +static int
> +smp_fetch_ssl_keyshare_groups(const struct arg *args, struct sample *smp, 
> const char *kw, void *private)
> +{
> +    int readPosition, numberOfKeyshares;
> +    struct buffer *smp_trash = NULL;
> +    unsigned char *dataPointer;
> +     struct clnt_hello_proc cp;
> +
> +    cp = smp_client_hello_parse(smp, 1);
> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
> +             goto too_short;
>  
> -             if (ext_len > hs_len - 4) /* Extension too long */
> +    while (cp.hs_len >= 4) {
> +         int ext_type, ext_len, keyshare_len;
> +
> +         ext_type = (cp.data[0] << 8) + cp.data[1]; /* Extension type */
> +         ext_len  = (cp.data[2] << 8) + cp.data[3]; /* Extension length */
> +
> +         if (ext_len > cp.hs_len - 4) /* Extension too long */
> +                 goto not_ssl_hello;
> +
> +         if (ext_type == 51) { /* Keyshare extension type ID is 51dec */
> +                 if (ext_len < 2) /* need at least one entry of 2 bytes in 
> the list length */
> +                    goto not_ssl_hello;
> +
> +          keyshare_len = (cp.data[4] << 8) + cp.data[5]; /* Client keyshare 
> length */
> +          if (keyshare_len < 2 || keyshare_len > cp.hs_len - 6)
> +                goto not_ssl_hello; /* at least 2 bytes per keyshare */
> +
> +           dataPointer = cp.data + 6; /* start of keyshare entries */
> +           readPosition = 0;
> +           numberOfKeyshares = 0;
> +           smp_trash = get_trash_chunk();
> +           while (readPosition < keyshare_len) {
> +                /* Get the binary value of the keyshare group and move the 
> offset to the end of the related keyshare */
> +                memmove(b_orig(smp_trash) + (2*numberOfKeyshares), 
> &dataPointer[readPosition], 2);
> +                numberOfKeyshares++;
> +                readPosition += ((int)dataPointer[readPosition+2] << 8) + 
> (int)dataPointer[readPosition+3] + 4;
> +           }
> +           smp->data.type = SMP_T_BIN;
> +           /*smp->data.u.str.area = (char *)&smp->data.u.str.bin;*/
> +           smp->data.u.str.area = smp_trash->area;
> +           smp->data.u.str.data = 2*numberOfKeyshares;
> +           smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
> +
> +           return 1;
> +         }
> +        cp.hs_len -= 4 + ext_len;
> +        cp.data   += 4 + ext_len;
> +    }
> +    /* keyshare groups not found */
> +    goto not_ssl_hello;
> +
> +     too_short:
> +       smp->flags = SMP_F_MAY_CHANGE;
> +     not_ssl_hello:
> +       return 0;
> +}
> +
> +/*
> + * Try to extract the Server Name Indication that may be presented in a TLS
> + * client hello handshake message.
> + */
> +static int
> +smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
> +{
> +     struct clnt_hello_proc cp;
> +
> +    cp = smp_client_hello_parse(smp, 1);
> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
> +             goto too_short;
> +
> +     while (cp.hs_len >= 4) {
> +             int ext_len, ext_type, name_type, srv_len, name_len;
> +
> +             ext_type = (cp.data[0] << 8) + cp.data[1];
> +             ext_len  = (cp.data[2] << 8) + cp.data[3];
> +
> +             if (ext_len > cp.hs_len - 4) /* Extension too long */
>                       goto not_ssl_hello;
>  
>               if (ext_type == 0) { /* Server name */
>                       if (ext_len < 2) /* need one list length */
>                               goto not_ssl_hello;
>  
> -                     srv_len = (data[4] << 8) + data[5];
> -                     if (srv_len < 4 || srv_len > hs_len - 6)
> +                     srv_len = (cp.data[4] << 8) + cp.data[5];
> +                     if (srv_len < 4 || srv_len > cp.hs_len - 6)
>                               goto not_ssl_hello; /* at least 4 bytes per 
> server name */
>  
> -                     name_type = data[6];
> -                     name_len = (data[7] << 8) + data[8];
> +                     name_type = cp.data[6];
> +                     name_len = (cp.data[7] << 8) + cp.data[8];
>  
>                       if (name_type == 0) { /* hostname */
>                               smp->data.type = SMP_T_STR;
> -                             smp->data.u.str.area = (char *)data + 9;
> +                             smp->data.u.str.area = (char *)cp.data + 9;
>                               smp->data.u.str.data = name_len;
>                               smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
>                               return 1;
>                       }
>               }
>  
> -             hs_len -= 4 + ext_len;
> -             data   += 4 + ext_len;
> +             cp.hs_len -= 4 + ext_len;
> +             cp.data   += 4 + ext_len;
>       }
>       /* server name not found */
>       goto not_ssl_hello;
> @@ -687,144 +760,32 @@ smp_fetch_ssl_hello_sni(const struct arg *args, struct 
> sample *smp, const char *
>       smp->flags = SMP_F_MAY_CHANGE;
>  
>   not_ssl_hello:
> -
>       return 0;
>  }
>  
>  /* Try to extract the Application-Layer Protocol Negotiation (ALPN) protocol
>   * names that may be presented in a TLS client hello handshake message. As 
> the
>   * message presents a list of protocol names in descending order of 
> preference,
> - * it may return iteratively. The format of the message is the following
> - * (cf RFC5246 + RFC7301) :
> - * TLS frame :
> - *   - uint8  type                            = 0x16   (Handshake)
> - *   - uint16 version                        >= 0x0301 (TLSv1)
> - *   - uint16 length                                   (frame length)
> - *   - TLS handshake :
> - *     - uint8  msg_type                      = 0x01   (ClientHello)
> - *     - uint24 length                                 (handshake message 
> length)
> - *     - ClientHello :
> - *       - uint16 client_version             >= 0x0301 (TLSv1)
> - *       - uint8 Random[32]                  (4 first ones are timestamp)
> - *       - SessionID :
> - *         - uint8 session_id_len (0..32)              (SessionID len in 
> bytes)
> - *         - uint8 session_id[session_id_len]
> - *       - CipherSuite :
> - *         - uint16 cipher_len               >= 2      (Cipher length in 
> bytes)
> - *         - uint16 ciphers[cipher_len/2]
> - *       - CompressionMethod :
> - *         - uint8 compression_len           >= 1      (# of supported 
> methods)
> - *         - uint8 compression_methods[compression_len]
> - *       - optional client_extension_len               (in bytes)
> - *       - optional sequence of ClientHelloExtensions  (as many bytes as 
> above):
> - *         - uint16 extension_type            = 16 for 
> application_layer_protocol_negotiation
> - *         - uint16 extension_len
> - *         - opaque extension_data[extension_len]
> - *           - uint16 protocol_names_len               (# of bytes here)
> - *           - opaque protocol_names[protocol_names_len bytes]
> - *             - uint8 name_len
> - *             - opaque protocol_name[name_len bytes]
> + * it may return iteratively.
>   */
>  static int
>  smp_fetch_ssl_hello_alpn(const struct arg *args, struct sample *smp, const 
> char *kw, void *private)
>  {
> -     int hs_len, ext_len, bleft;
> -     struct channel *chn;
> -     unsigned char *data;
> -
> -     if (!smp->strm)
> -             goto not_ssl_hello;
> -
> -     /* meaningless for HTX buffers */
> -     if (IS_HTX_STRM(smp->strm))
> -             goto not_ssl_hello;
> +     struct clnt_hello_proc cp;
>  
> -     chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : 
> &smp->strm->req;
> -     bleft = ci_data(chn);
> -     data = (unsigned char *)ci_head(chn);
> -
> -     /* Check for SSL/TLS Handshake */
> -     if (!bleft)
> -             goto too_short;
> -     if (*data != 0x16)
> -             goto not_ssl_hello;
> -
> -     /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
> -     if (bleft < 3)
> +    cp = smp_client_hello_parse(smp, 1);
> +     if (cp.status == NOT_SSL_HELLO)
> +             goto not_ssl_hello;
> +     else if (cp.status == TOO_SHORT)
>               goto too_short;
> -     if (data[1] < 0x03)
> -             goto not_ssl_hello;
> -
> -     if (bleft < 5)
> -             goto too_short;
> -     hs_len = (data[3] << 8) + data[4];
> -     if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
> -             goto not_ssl_hello; /* too short to have an extension */
> -
> -     data += 5; /* enter TLS handshake */
> -     bleft -= 5;
> -
> -     /* Check for a complete client hello starting at <data> */
> -     if (bleft < 1)
> -             goto too_short;
> -     if (data[0] != 0x01) /* msg_type = Client Hello */
> -             goto not_ssl_hello;
> -
> -     /* Check the Hello's length */
> -     if (bleft < 4)
> -             goto too_short;
> -     hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
> -     if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
> -             goto not_ssl_hello; /* too short to have an extension */
> -
> -     /* We want the full handshake here */
> -     if (bleft < hs_len)
> -             goto too_short;
> -
> -     data += 4;
> -     /* Start of the ClientHello message */
> -     if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
> -             goto not_ssl_hello;
> -
> -     ext_len = data[34]; /* session_id_len */
> -     if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct 
> session_id len */
> -             goto not_ssl_hello;
> -
> -     /* Jump to cipher suite */
> -     hs_len -= 35 + ext_len;
> -     data   += 35 + ext_len;
> -
> -     if (hs_len < 4 ||                               /* minimum one cipher */
> -         (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for 
> a cipher */
> -         ext_len > hs_len)
> -             goto not_ssl_hello;
> -
> -     /* Jump to the compression methods */
> -     hs_len -= 2 + ext_len;
> -     data   += 2 + ext_len;
> -
> -     if (hs_len < 2 ||                       /* minimum one compression 
> method */
> -         data[0] < 1 || data[0] > hs_len)    /* minimum 1 bytes for a method 
> */
> -             goto not_ssl_hello;
> -
> -     /* Jump to the extensions */
> -     hs_len -= 1 + data[0];
> -     data   += 1 + data[0];
> -
> -     if (hs_len < 2 ||                       /* minimum one extension list 
> length */
> -         (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long 
> */
> -             goto not_ssl_hello;
> -
> -     hs_len = ext_len; /* limit ourselves to the extension length */
> -     data += 2;
>  
> -     while (hs_len >= 4) {
> -             int ext_type, name_len, name_offset;
> +     while (cp.hs_len >= 4) {
> +             int ext_len, ext_type, name_len, name_offset;
>  
> -             ext_type = (data[0] << 8) + data[1];
> -             ext_len  = (data[2] << 8) + data[3];
> +             ext_type = (cp.data[0] << 8) + cp.data[1];
> +             ext_len  = (cp.data[2] << 8) + cp.data[3];
>  
> -             if (ext_len > hs_len - 4) /* Extension too long */
> +             if (ext_len > cp.hs_len - 4) /* Extension too long */
>                       goto not_ssl_hello;
>  

>               if (ext_type == 16) { /* ALPN */
> @@ -833,13 +794,13 @@ smp_fetch_ssl_hello_alpn(const struct arg *args, struct 
> sample *smp, const char
>  
>                       /* Name cursor in ctx, must begin after 
> protocol_names_len */
>                       name_offset = smp->ctx.i < 6 ? 6 : smp->ctx.i;
> -                     name_len = data[name_offset];
> +                     name_len = cp.data[name_offset];
>  
>                       if (name_len + name_offset - 3 > ext_len)
>                               goto not_ssl_hello;
>  
>                       smp->data.type = SMP_T_STR;
> -                     smp->data.u.str.area = (char *)data + name_offset + 1; 
> /* +1 to skip name_len */
> +                     smp->data.u.str.area = (char *)cp.data + name_offset + 
> 1; /* +1 to skip name_len */
>                       smp->data.u.str.data = name_len;
>                       smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
>  
> @@ -852,8 +813,8 @@ smp_fetch_ssl_hello_alpn(const struct arg *args, struct 
> sample *smp, const char
>                       return 1;
>               }
>  
> -             hs_len -= 4 + ext_len;
> -             data   += 4 + ext_len;
> +             cp.hs_len -= 4 + ext_len;
> +             cp.data   += 4 + ext_len;
>       }


>       /* alpn not found */
>       goto not_ssl_hello;
> @@ -1412,7 +1373,11 @@ static struct sample_fetch_kw_list smp_kws = {ILH, {
>       { "req.ssl_st_ext",      smp_fetch_req_ssl_st_ext, 0,                   
>    NULL,           SMP_T_SINT, SMP_USE_L6REQ },
>       { "req.ssl_hello_type",  smp_fetch_ssl_hello_type, 0,                   
>    NULL,           SMP_T_SINT, SMP_USE_L6REQ },
>       { "req.ssl_sni",         smp_fetch_ssl_hello_sni,  0,                   
>    NULL,           SMP_T_STR,  SMP_USE_L6REQ },
> -     { "req.ssl_alpn",        smp_fetch_ssl_hello_alpn, 0,                   
>    NULL,           SMP_T_STR,  SMP_USE_L6REQ },
> +     { "req.ssl_cipherlist",        smp_fetch_ssl_cipherlist,       0,       
>    NULL,           SMP_T_BIN,  
> SMP_USE_L6REQ|SMP_USE_L4CLI|SMP_USE_L5CLI|SMP_USE_FTEND },
> +    { "req.ssl_supported_groups",  smp_fetch_ssl_supported_groups, 0,        
>   NULL,           SMP_T_BIN,  
> SMP_USE_L6REQ|SMP_USE_L4CLI|SMP_USE_L5CLI|SMP_USE_FTEND },
> +    { "req.ssl_sigalgs",           smp_fetch_ssl_sigalgs,          0,        
>   NULL,           SMP_T_BIN,  
> SMP_USE_L6REQ|SMP_USE_L4CLI|SMP_USE_L5CLI|SMP_USE_FTEND },
> +    { "req.ssl_keyshare_groups",   smp_fetch_ssl_keyshare_groups,  0,        
>   NULL,           SMP_T_BIN,  
> SMP_USE_L6REQ|SMP_USE_L4CLI|SMP_USE_L5CLI|SMP_USE_FTEND },
> +    { "req.ssl_alpn",        smp_fetch_ssl_hello_alpn, 0,                    
>   NULL,           SMP_T_STR,  SMP_USE_L6REQ },

Be careful with tabs and spaces at the beginning of the lines there.


>       { "req.ssl_ver",         smp_fetch_req_ssl_ver,    0,                   
>    NULL,           SMP_T_SINT, SMP_USE_L6REQ },
>       { "res.len",             smp_fetch_len,            0,                   
>    NULL,           SMP_T_SINT, SMP_USE_L6RES },
>       { "res.payload",         smp_fetch_payload,        ARG2(2,SINT,SINT),   
>    NULL,           SMP_T_BIN,  SMP_USE_L6RES },

Regards,

-- 
William Lallemand



Reply via email to