]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: payload: add support for tls session ticket ext
authorPradeep Jindal <praddyjindal@gmail.com>
Tue, 29 Sep 2015 04:42:57 +0000 (10:12 +0530)
committerWilly Tarreau <w@1wt.eu>
Tue, 29 Sep 2015 12:07:32 +0000 (14:07 +0200)
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
  Returns 2 if the client also sent non-zero length TLS SessionTicket

doc/configuration.txt
src/payload.c

index a4cfd4462a3c1eb7660082a0a86ec393f9bc379f..72307380597957ce88765560d330c12046d54ddf 100644 (file)
@@ -13210,6 +13210,17 @@ rep_ssl_hello_type : integer (deprecated)
   option. This is mostly used in ACL to detect presence of an SSL hello message
   that is supposed to contain an SSL session ID usable for stickiness.
 
+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
+  Returns 2 if the client also sent non-zero length TLS SessionTicket
+  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. This can for example be used to detect
+  whether the client sent a SessionTicket or not and stick it accordingly, if
+  no SessionTicket then stick on SessionID or don't stick as there's no server
+  side state is there when SessionTickets are in use.
+
 req.ssl_ver : integer
 req_ssl_ver : integer (deprecated)
   Returns an integer value containing the version of the SSL/TLS protocol of a
index 71d3ec00f74e3c6f8f9e2f096d1f35da5e62bb88..ce9280c3137a8895fd147ee147c627085132ffcf 100644 (file)
@@ -56,6 +56,141 @@ 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
+ */
+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 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;
+
+               /* SesstionTicket extension */
+               if (ext_type == 35) {
+                       smp->data.type = SMP_T_SINT;
+                       /* SessionTicket also present */
+                       if (ext_len > 0)
+                               smp->data.u.sint = 2;
+                       /* SessionTicket absent */
+                       else
+                               smp->data.u.sint = 1;
+                       smp->flags = SMP_F_VOLATILE;
+                       return 1;
+               }
+
+               hs_len -= 4 + ext_len;
+               data   += 4 + ext_len;
+       }
+       /* SessionTicket Extension not found */
+       smp->data.type = SMP_T_SINT;
+       smp->data.u.sint = 0;
+       smp->flags = SMP_F_VOLATILE;
+       return 1;
+
+       /* server name not found */
+       goto not_ssl_hello;
+
+ too_short:
+       smp->flags = SMP_F_MAY_CHANGE;
+
+ not_ssl_hello:
+       return 0;
+}
+
 /* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
  * Mainly used to detect if client supports ECC cipher suites.
  */
@@ -799,6 +934,7 @@ static struct sample_fetch_kw_list smp_kws = {ILH, {
        { "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_SINT, SMP_USE_L6REQ },
        { "req.ssl_ec_ext",      smp_fetch_req_ssl_ec_ext, 0,                      NULL,           SMP_T_BOOL, SMP_USE_L6REQ },
+       { "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_ver",         smp_fetch_req_ssl_ver,    0,                      NULL,           SMP_T_SINT, SMP_USE_L6REQ },