return 1;
}
+/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
+ * Mainly used to detect if client supports ECC cipher suites.
+ */
+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;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ if (!chn->buf)
+ goto not_ssl_hello;
+
+ bleft = chn->buf->i;
+ data = (unsigned char *)chn->buf->p;
+
+ /* 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 <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, ext_len;
+
+ ext_type = (data[0] << 8) + data[1];
+ ext_len = (data[2] << 8) + data[3];
+
+ if (ext_len > hs_len - 4) /* Extension too long */
+ goto not_ssl_hello;
+
+ /* Elliptic curves extension */
+ if (ext_type == 10) {
+ smp->type = SMP_T_BOOL;
+ smp->data.uint = 1;
+ return 1;
+ }
+
+ hs_len -= 4 + ext_len;
+ data += 4 + ext_len;
+ }
+ /* server name not found */
+ goto not_ssl_hello;
+
+ too_short:
+ 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)
{ "req.payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN, SMP_USE_L6REQ },
{ "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
{ "req.rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_L6REQ },
+ { "req.ssl_ec_ext", smp_fetch_req_ssl_ec_ext, 0, NULL, SMP_T_BOOL, SMP_USE_L6REQ },
{ "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
{ "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
{ "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },