mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-21 05:06:56 +00:00
MINOR: Add sample fetch to detect Supported Elliptic Curves Extension
Clients that support ECC cipher suites SHOULD send the specified extension within the SSL ClientHello message according to RFC4492, section 5.1. We can use this extension to chain-proxy requests so that, on the same IP address, a ECC compatible clients gets an EC certificate and a non-ECC compatible client gets a regular RSA certificate. The main advantage of this approach compared to the one presented by Dave Zhu on the mailing list is that we can make it work with OpenSSL versions before 1.0.2. Example: frontend ssl-relay mode tcp bind 0.0.0.0:443 use_backend ssl-ecc if { req.ssl_ec_ext 1 } default_backend ssl-rsa backend ssl-ecc mode tcp server ecc unix@/var/run/haproxy_ssl_ecc.sock send-proxy-v2 check backend ssl-rsa mode tcp server rsa unix@/var/run/haproxy_ssl_rsa.sock send-proxy-v2 check listen all-ssl bind unix@/var/run/haproxy_ssl_ecc.sock accept-proxy ssl crt /usr/local/haproxy/ecc.foo.com.pem user nobody bind unix@/var/run/haproxy_ssl_rsa.sock accept-proxy ssl crt /usr/local/haproxy/www.foo.com.pem user nobody Signed-off-by: Nenad Merdanovic <nmerdan@anine.io>
This commit is contained in:
parent
fc017fec48
commit
5fc7d7e8ce
@ -12631,6 +12631,15 @@ rdp_cookie_cnt([name]) : integer (deprecated)
|
||||
ACL derivatives :
|
||||
req_rdp_cookie_cnt([<name>]) : integer match
|
||||
|
||||
req.ssl_ec_ext : boolean
|
||||
Returns a boolean identifying if client sent the Supported Elliptic Curves
|
||||
Extension as defined in RFC4492, section 5.1. within the SSL ClientHello
|
||||
message. This can be used to present ECC compatible clients with EC certificate
|
||||
and to use RSA for all others, on the same IP address. 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.
|
||||
|
||||
req.ssl_hello_type : integer
|
||||
req_ssl_hello_type : integer (deprecated)
|
||||
Returns an integer value containing the type of the SSL hello message found
|
||||
|
122
src/payload.c
122
src/payload.c
@ -56,6 +56,127 @@ smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *
|
||||
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)
|
||||
@ -648,6 +769,7 @@ static struct sample_fetch_kw_list smp_kws = {ILH, {
|
||||
{ "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 },
|
||||
|
Loading…
Reference in New Issue
Block a user