mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 23:56:57 +02:00
MINOR: ssl/proto_http: Add keywords to take care of early data.
Add a new sample fetch, "ssl_fc_has_early", a boolean that will be true if early data were sent, and a new action, "wait-for-handshake", if used, the request won't be forwarded until the SSL handshake is done.
This commit is contained in:
parent
eff9a9ef95
commit
ccaa7de72e
@ -4163,6 +4163,10 @@ http-request { allow | auth [realm <realm>] | redirect <rule> |
|
|||||||
pass the first router, though it's still delivered to local networks. Do
|
pass the first router, though it's still delivered to local networks. Do
|
||||||
not use it unless you fully understand how it works.
|
not use it unless you fully understand how it works.
|
||||||
|
|
||||||
|
- "wait-for-handshake" : this will delay the processing of the request
|
||||||
|
until the SSL handshake happened. This is mostly useful to delay
|
||||||
|
processing early data until we're sure they are valid.
|
||||||
|
|
||||||
There is no limit to the number of http-request statements per instance.
|
There is no limit to the number of http-request statements per instance.
|
||||||
|
|
||||||
It is important to know that http-request rules are processed very early in
|
It is important to know that http-request rules are processed very early in
|
||||||
@ -14252,6 +14256,11 @@ ssl_fc_has_crt : boolean
|
|||||||
from the cache or the ticket. So prefer "ssl_c_used" if you want to check if
|
from the cache or the ticket. So prefer "ssl_c_used" if you want to check if
|
||||||
current SSL session uses a client certificate.
|
current SSL session uses a client certificate.
|
||||||
|
|
||||||
|
ssl_fc_has_early : boolean
|
||||||
|
Returns true if early data were sent, and the handshake didn't happen yet. As
|
||||||
|
it has security implications, it is useful to be able to refuse those, or
|
||||||
|
wait until the handshake happened.
|
||||||
|
|
||||||
ssl_fc_has_sni : boolean
|
ssl_fc_has_sni : boolean
|
||||||
This checks for the presence of a Server Name Indication TLS extension (SNI)
|
This checks for the presence of a Server Name Indication TLS extension (SNI)
|
||||||
in an incoming connection was made over an SSL/TLS transport layer. Returns
|
in an incoming connection was made over an SSL/TLS transport layer. Returns
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
#include <proto/openssl-compat.h>
|
#include <proto/openssl-compat.h>
|
||||||
#include <proto/pattern.h>
|
#include <proto/pattern.h>
|
||||||
#include <proto/proto_tcp.h>
|
#include <proto/proto_tcp.h>
|
||||||
|
#include <proto/proto_http.h>
|
||||||
#include <proto/server.h>
|
#include <proto/server.h>
|
||||||
#include <proto/stream_interface.h>
|
#include <proto/stream_interface.h>
|
||||||
#include <proto/log.h>
|
#include <proto/log.h>
|
||||||
@ -4892,13 +4893,6 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
|
|||||||
*/
|
*/
|
||||||
if (global_ssl.async)
|
if (global_ssl.async)
|
||||||
SSL_clear_mode(conn->xprt_ctx, SSL_MODE_ASYNC);
|
SSL_clear_mode(conn->xprt_ctx, SSL_MODE_ASYNC);
|
||||||
#endif
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
|
||||||
/* Once the handshake succeeded, we can consider the early data
|
|
||||||
* as valid.
|
|
||||||
*/
|
|
||||||
if (conn->flags & CO_FL_EARLY_DATA)
|
|
||||||
conn->flags &= ~CO_FL_EARLY_DATA;
|
|
||||||
#endif
|
#endif
|
||||||
/* Handshake succeeded */
|
/* Handshake succeeded */
|
||||||
if (!SSL_session_reused(conn->xprt_ctx)) {
|
if (!SSL_session_reused(conn->xprt_ctx)) {
|
||||||
@ -5648,6 +5642,22 @@ static int ssl_sock_get_alpn(const struct connection *conn, const char **str, in
|
|||||||
|
|
||||||
/***** Below are some sample fetching functions for ACL/patterns *****/
|
/***** Below are some sample fetching functions for ACL/patterns *****/
|
||||||
|
|
||||||
|
static int
|
||||||
|
smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||||
|
{
|
||||||
|
struct connection *conn;
|
||||||
|
|
||||||
|
conn = objt_conn(smp->sess->origin);
|
||||||
|
if (!conn || conn->xprt != &ssl_sock)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
smp->flags = 0;
|
||||||
|
smp->data.type = SMP_T_BOOL;
|
||||||
|
smp->data.u.sint = (conn->flags & CO_FL_EARLY_DATA) ? 1 : 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* boolean, returns true if client cert was present */
|
/* boolean, returns true if client cert was present */
|
||||||
static int
|
static int
|
||||||
smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||||
@ -8139,6 +8149,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
|
|||||||
{ "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
{ "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
||||||
{ "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
{ "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
{ "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
{ "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
||||||
|
{ "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
||||||
{ "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
{ "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
||||||
{ "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
{ "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
||||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
@ -8317,6 +8328,34 @@ static struct xprt_ops ssl_sock = {
|
|||||||
.name = "SSL",
|
.name = "SSL",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum act_return ssl_action_wait_for_hs(struct act_rule *rule, struct proxy *px,
|
||||||
|
struct session *sess, struct stream *s, int flags)
|
||||||
|
{
|
||||||
|
struct connection *conn;
|
||||||
|
|
||||||
|
conn = objt_conn(sess->origin);
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
if (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS)) {
|
||||||
|
s->req.flags |= CF_READ_NULL;
|
||||||
|
return ACT_RET_YIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (ACT_RET_CONT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum act_parse_ret ssl_parse_wait_for_hs(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err)
|
||||||
|
{
|
||||||
|
rule->action_ptr = ssl_action_wait_for_hs;
|
||||||
|
|
||||||
|
return ACT_RET_PRS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct action_kw_list http_req_actions = {ILH, {
|
||||||
|
{ "wait-for-handshake", ssl_parse_wait_for_hs },
|
||||||
|
{ /* END */ }
|
||||||
|
}};
|
||||||
|
|
||||||
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
|
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
|
||||||
|
|
||||||
static void ssl_sock_sctl_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
|
static void ssl_sock_sctl_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
|
||||||
@ -8419,6 +8458,8 @@ static void __ssl_sock_init(void)
|
|||||||
#endif
|
#endif
|
||||||
/* Load SSL string for the verbose & debug mode. */
|
/* Load SSL string for the verbose & debug mode. */
|
||||||
ERR_load_SSL_strings();
|
ERR_load_SSL_strings();
|
||||||
|
|
||||||
|
http_req_keywords_register(&http_req_actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
@ -572,6 +572,16 @@ static int si_conn_wake_cb(struct connection *conn)
|
|||||||
if (conn->flags & CO_FL_ERROR)
|
if (conn->flags & CO_FL_ERROR)
|
||||||
si->flags |= SI_FL_ERR;
|
si->flags |= SI_FL_ERR;
|
||||||
|
|
||||||
|
/* If we had early data, and the handshake ended, then
|
||||||
|
* we can remove the flag, and attempt to wake the task up,
|
||||||
|
* in the event there's an analyser waiting for the end of
|
||||||
|
* the handshake.
|
||||||
|
*/
|
||||||
|
if ((conn->flags & (CO_FL_EARLY_DATA | CO_FL_EARLY_SSL_HS)) == CO_FL_EARLY_DATA) {
|
||||||
|
conn->flags &= ~CO_FL_EARLY_DATA;
|
||||||
|
task_wakeup(si_task(si), TASK_WOKEN_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
if ((si->state < SI_ST_EST) &&
|
if ((si->state < SI_ST_EST) &&
|
||||||
(conn->flags & (CO_FL_CONNECTED | CO_FL_HANDSHAKE)) == CO_FL_CONNECTED) {
|
(conn->flags & (CO_FL_CONNECTED | CO_FL_HANDSHAKE)) == CO_FL_CONNECTED) {
|
||||||
si->exp = TICK_ETERNITY;
|
si->exp = TICK_ETERNITY;
|
||||||
|
Loading…
Reference in New Issue
Block a user