From bd076f8619568b1a2f0193ac3e82e7999bce7e06 Mon Sep 17 00:00:00 2001 From: Mariam John Date: Wed, 30 Apr 2025 12:11:14 -0500 Subject: [PATCH] MINOR: ssl: Introduce new smp_client_hello_parse() function In this patch we introduce a new helped function called `smp_client_hello_parse()` to extract information presented in a TLS client hello handshake message. 7 sample fetches have also been modified to use this helped function to do the common client hello parsing and use the result to do further processing of extensions/cipher. Fixes: #2532 --- src/payload.c | 629 +++++++++++++------------------------------------- 1 file changed, 166 insertions(+), 463 deletions(-) diff --git a/src/payload.c b/src/payload.c index 04cc3d50e..62071aca6 100644 --- a/src/payload.c +++ b/src/payload.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -31,57 +32,51 @@ /* All supported sample fetch functions must be declared here */ /************************************************************************/ -/* wait for more data as long as possible, then return TRUE. This should be - * used with content inspection. - */ -static int -smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!(smp->opt & SMP_OPT_FINAL)) { - smp->flags |= SMP_F_MAY_CHANGE; - return 0; - } - smp->data.type = SMP_T_BOOL; - smp->data.u.sint = 1; - return 1; -} - -/* return the number of bytes in the request buffer */ -static int -smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (smp->strm) { - struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; - - /* Not accurate but kept for backward compatibility purpose */ - if (IS_HTX_STRM(smp->strm)) { - struct htx *htx = htxbuf(&chn->buf); - smp->data.u.sint = htx->data - co_data(chn); - } - else - smp->data.u.sint = ci_data(chn); - } - else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { - struct check *check = __objt_check(smp->sess->origin); +enum client_hello_status { + CLIENTHELLO_ERR_OK = 0, + CLIENTHELLO_ERR_UNAVAIL = 1, + CLIENTHELLO_ERR_TOO_SHORT = 2, +}; - /* Not accurate but kept for backward compatibility purpose */ - smp->data.u.sint = ((check->sc && IS_HTX_SC(check->sc)) ? (htxbuf(&check->bi))->data: b_data(&check->bi)); - } - else - return 0; - - smp->data.type = SMP_T_SINT; - smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE; - return 1; -} +enum client_hello_type { + CLIENTHELLO_EXTENSIONS, + CLIENTHELLO_CIPHERSUITE, +}; -/* 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) +smp_client_hello_parse( struct sample *smp, enum client_hello_type type, unsigned char **ch_data, int *len) { int hs_len, ext_len, bleft; struct channel *chn; @@ -156,7 +151,13 @@ 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 */ + /* Jump to the compression methods. For fetching cipher list this processing is not required. */ + if (type == CLIENTHELLO_EXTENSIONS) + goto parse_extn; + else + goto parse_cipher; + +parse_extn: hs_len -= 2 + ext_len; data += 2 + ext_len; @@ -168,13 +169,92 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char 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; hs_len = ext_len; /* limit ourselves to the extension length */ data += 2; + *len = hs_len; + *ch_data = data; + return CLIENTHELLO_ERR_OK; + +parse_cipher: + *len = ext_len; + *ch_data = data; + return CLIENTHELLO_ERR_OK; + +not_ssl_hello: + return CLIENTHELLO_ERR_UNAVAIL; + +too_short: + return CLIENTHELLO_ERR_TOO_SHORT; +} + +/* wait for more data as long as possible, then return TRUE. This should be + * used with content inspection. + */ +static int +smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!(smp->opt & SMP_OPT_FINAL)) { + smp->flags |= SMP_F_MAY_CHANGE; + return 0; + } + smp->data.type = SMP_T_BOOL; + smp->data.u.sint = 1; + return 1; +} + +/* return the number of bytes in the request buffer */ +static int +smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (smp->strm) { + struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; + + /* Not accurate but kept for backward compatibility purpose */ + if (IS_HTX_STRM(smp->strm)) { + struct htx *htx = htxbuf(&chn->buf); + smp->data.u.sint = htx->data - co_data(chn); + } + else + smp->data.u.sint = ci_data(chn); + } + else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { + struct check *check = __objt_check(smp->sess->origin); + + /* Not accurate but kept for backward compatibility purpose */ + smp->data.u.sint = ((check->sc && IS_HTX_SC(check->sc)) ? (htxbuf(&check->bi))->data: b_data(&check->bi)); + } + else + return 0; + + smp->data.type = SMP_T_SINT; + smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE; + 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 + */ +static int +smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + enum client_hello_status status; + int hs_len; + unsigned char *data; + + status = smp_client_hello_parse(smp, CLIENTHELLO_EXTENSIONS, &data, &hs_len); + if (status == CLIENTHELLO_ERR_UNAVAIL) + goto not_ssl_hello; + else if (status == CLIENTHELLO_ERR_TOO_SHORT) + goto too_short; + + while (hs_len >= 4) { int ext_type, ext_len; @@ -219,96 +299,16 @@ 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; + enum client_hello_status status; + int hs_len; unsigned char *data; - 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) - 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 */ - if (bleft < 1) - goto too_short; - if (data[0] != 0x01) /* msg_type = Client Hello */ + status = smp_client_hello_parse(smp, CLIENTHELLO_EXTENSIONS, &data, &hs_len); + if (status == CLIENTHELLO_ERR_UNAVAIL) 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) + else if (status == CLIENTHELLO_ERR_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; - - 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, ext_len; @@ -528,86 +528,25 @@ smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw static int 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; + enum client_hello_status status; + int hs_len; unsigned char *data; - if (!smp->strm) + status = smp_client_hello_parse(smp, CLIENTHELLO_CIPHERSUITE, &data, &hs_len); + if (status == CLIENTHELLO_ERR_UNAVAIL) goto not_ssl_hello; + else if (status == CLIENTHELLO_ERR_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 *)data + 2; + smp->data.u.str.data = hs_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; - - /* 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; - - 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 */ - 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; - - smp->data.type = SMP_T_BIN; - smp->data.u.str.area = (char *)data + 2; - smp->data.u.str.data = ext_len; - smp->flags = SMP_F_VOLATILE | SMP_F_CONST; - - return 1; - -too_short: - smp->flags = SMP_F_MAY_CHANGE; +too_short: + smp->flags = SMP_F_MAY_CHANGE; not_ssl_hello: @@ -620,97 +559,18 @@ not_ssl_hello: static int smp_fetch_ssl_supported_groups(const struct arg *args, struct sample *smp, const char *kw, void *private) { - int hs_len, ext_len, bleft; - struct channel *chn; + enum client_hello_status status; + int hs_len; unsigned char *data; - 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) - goto too_short; - if (data[1] < 0x03) + status = smp_client_hello_parse(smp, CLIENTHELLO_EXTENSIONS, &data, &hs_len); + if (status == CLIENTHELLO_ERR_UNAVAIL) 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 */ - 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) + else if (status == CLIENTHELLO_ERR_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; - - 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; /* Now 'data' points to the first content byte of an extension */ - while (hs_len >= 4) { - int ext_type, grp_len; + int ext_type, ext_len, grp_len; ext_type = (data[0] << 8) + data[1]; /* Extension type */ ext_len = (data[2] << 8) + data[3]; /* Extension length */ @@ -754,97 +614,18 @@ not_ssl_hello: static int smp_fetch_ssl_sigalgs(const struct arg *args, struct sample *smp, const char *kw, void *private) { - int hs_len, ext_len, bleft; - struct channel *chn; + enum client_hello_status status; + int hs_len; unsigned char *data; - 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) - 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 */ - if (bleft < 1) - goto too_short; - if (data[0] != 0x01) /* msg_type = Client Hello */ + status = smp_client_hello_parse(smp, CLIENTHELLO_EXTENSIONS, &data, &hs_len); + if (status == CLIENTHELLO_ERR_UNAVAIL) goto not_ssl_hello; - - /* Check the Hello's length */ - if (bleft < 4) + else if (status == CLIENTHELLO_ERR_TOO_SHORT) 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; /* Now 'data' points to the first content byte of an extension */ while (hs_len >= 4) { - int ext_type, sigalg_len; + int ext_type, ext_len, sigalg_len; ext_type = (data[0] << 8) + data[1]; /* Extension type */ ext_len = (data[2] << 8) + data[3]; /* Extension length */ @@ -888,100 +669,22 @@ not_ssl_hello: static int smp_fetch_ssl_keyshare_groups(const struct arg *args, struct sample *smp, const char *kw, void *private) { - int hs_len, ext_len, bleft, readPosition, numberOfKeyshares; - struct channel *chn; + int readPosition, numberOfKeyshares; struct buffer *smp_trash = NULL; unsigned char *data; unsigned char *dataPointer; + enum client_hello_status status; + int hs_len; - 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) - 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 */ - if (bleft < 1) - goto too_short; - if (data[0] != 0x01) /* msg_type = Client Hello */ + status = smp_client_hello_parse(smp, CLIENTHELLO_EXTENSIONS, &data, &hs_len); + if (status == CLIENTHELLO_ERR_UNAVAIL) goto not_ssl_hello; - - /* Check the Hello's length */ - if (bleft < 4) + else if (status == CLIENTHELLO_ERR_TOO_SHORT) 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; /* Now 'data' points to the first content byte of an extension */ while (hs_len >= 4) { - int ext_type, keyshare_len; + int ext_type, ext_len, keyshare_len; ext_type = (data[0] << 8) + data[1]; /* Extension type */ ext_len = (data[2] << 8) + data[3]; /* Extension length */ -- 2.47.3