mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-19 13:35:47 +00:00
MINOR: ssl: Handle sending early data to server.
This adds a new keyword on the "server" line, "allow-0rtt", if set, we'll try to send early data to the server, as long as the client sent early data, as in case the server rejects the early data, we no longer have them, and can't resend them, so the only option we have is to send back a 425, and we need to be sure the client knows how to interpret it correctly.
This commit is contained in:
parent
cfdef2e312
commit
522eea7110
@ -226,6 +226,7 @@ enum {
|
||||
CO_ER_SSL_HANDSHAKE_HB, /* SSL error during handshake with heartbeat present */
|
||||
CO_ER_SSL_KILLED_HB, /* Stopped a TLSv1 heartbeat attack (CVE-2014-0160) */
|
||||
CO_ER_SSL_NO_TARGET, /* unknown target (not client nor server) */
|
||||
CO_ER_SSL_EARLY_FAILED, /* Server refused early data */
|
||||
};
|
||||
|
||||
/* source address settings for outgoing connections */
|
||||
|
@ -167,6 +167,7 @@ enum srv_initaddr {
|
||||
#define SRV_SSL_O_NONE 0x0000
|
||||
#define SRV_SSL_O_NO_TLS_TICKETS 0x0100 /* disable session resumption tickets */
|
||||
#define SRV_SSL_O_NO_REUSE 0x200 /* disable session reuse */
|
||||
#define SRV_SSL_O_EARLY_DATA 0x400 /* Allow using early data */
|
||||
#endif
|
||||
|
||||
struct pid_list {
|
||||
|
@ -1038,7 +1038,7 @@ static void assign_tproxy_address(struct stream *s)
|
||||
*/
|
||||
int connect_server(struct stream *s)
|
||||
{
|
||||
struct connection *cli_conn;
|
||||
struct connection *cli_conn = NULL;
|
||||
struct connection *srv_conn;
|
||||
struct conn_stream *srv_cs;
|
||||
struct conn_stream *old_cs;
|
||||
@ -1180,10 +1180,11 @@ int connect_server(struct stream *s)
|
||||
|
||||
/* process the case where the server requires the PROXY protocol to be sent */
|
||||
srv_conn->send_proxy_ofs = 0;
|
||||
cli_conn = objt_conn(strm_orig(s));
|
||||
|
||||
if (srv && srv->pp_opts) {
|
||||
srv_conn->flags |= CO_FL_PRIVATE;
|
||||
srv_conn->send_proxy_ofs = 1; /* must compute size */
|
||||
cli_conn = objt_conn(strm_orig(s));
|
||||
if (cli_conn)
|
||||
conn_get_to_addr(cli_conn);
|
||||
}
|
||||
@ -1208,6 +1209,15 @@ int connect_server(struct stream *s)
|
||||
|
||||
err = si_connect(&s->si[1]);
|
||||
|
||||
if (!reuse && cli_conn && srv &&
|
||||
(srv->ssl_ctx.options & SRV_SSL_O_EARLY_DATA) &&
|
||||
(cli_conn->flags & CO_FL_EARLY_DATA) &&
|
||||
!channel_is_empty(si_oc(&s->si[1])) &&
|
||||
srv_conn->flags & CO_FL_SSL_WAIT_HS) {
|
||||
srv_conn->flags &= ~(CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN);
|
||||
srv_conn->flags |= CO_FL_EARLY_SSL_HS;
|
||||
}
|
||||
|
||||
if (err != SF_ERR_NONE)
|
||||
return err;
|
||||
|
||||
|
@ -5147,6 +5147,17 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
|
||||
channel_auto_close(rep);
|
||||
rep->analysers &= AN_RES_FLT_END;
|
||||
txn->status = 502;
|
||||
|
||||
/* Check to see if the server refused the early data.
|
||||
* If so, just send a 425
|
||||
*/
|
||||
if (objt_cs(s->si[1].end)) {
|
||||
struct connection *conn = objt_cs(s->si[1].end)->conn;
|
||||
|
||||
if (conn->err_code == CO_ER_SSL_EARLY_FAILED)
|
||||
txn->status = 425;
|
||||
}
|
||||
|
||||
s->si[1].flags |= SI_FL_NOLINGER;
|
||||
channel_truncate(rep);
|
||||
http_reply_and_close(s, txn->status, http_error_message(s));
|
||||
|
@ -5210,6 +5210,22 @@ check_error:
|
||||
goto out_error;
|
||||
}
|
||||
}
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||
else {
|
||||
/*
|
||||
* If the server refused the early data, we have to send a
|
||||
* 425 to the client, as we no longer have the data to sent
|
||||
* them again.
|
||||
*/
|
||||
if ((conn->flags & CO_FL_EARLY_DATA) && (objt_server(conn->target))) {
|
||||
if (SSL_get_early_data_status(conn->xprt_ctx) == SSL_EARLY_DATA_REJECTED) {
|
||||
conn->err_code = CO_ER_SSL_EARLY_FAILED;
|
||||
goto out_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
reneg_ok:
|
||||
|
||||
@ -5328,7 +5344,8 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun
|
||||
|
||||
ret = SSL_read_early_data(conn->xprt_ctx,
|
||||
bi_end(buf), try, &read_length);
|
||||
if (read_length > 0)
|
||||
if (ret == SSL_READ_EARLY_DATA_SUCCESS &&
|
||||
read_length > 0)
|
||||
conn->flags |= CO_FL_EARLY_DATA;
|
||||
if (ret == SSL_READ_EARLY_DATA_SUCCESS ||
|
||||
ret == SSL_READ_EARLY_DATA_FINISH) {
|
||||
@ -5465,16 +5482,34 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
|
||||
if (conn->tmp_early_data == -1)
|
||||
conn->tmp_early_data = 0;
|
||||
|
||||
max_early = SSL_get_max_early_data(conn->xprt_ctx);
|
||||
if (objt_listener(conn->target))
|
||||
max_early = SSL_get_max_early_data(conn->xprt_ctx);
|
||||
else {
|
||||
if (SSL_get0_session(conn->xprt_ctx))
|
||||
max_early = SSL_SESSION_get_max_early_data(SSL_get0_session(conn->xprt_ctx));
|
||||
else
|
||||
max_early = 0;
|
||||
}
|
||||
|
||||
if (try + conn->tmp_early_data > max_early) {
|
||||
try -= (try + conn->tmp_early_data) - max_early;
|
||||
if (try <= 0)
|
||||
if (try <= 0) {
|
||||
if (objt_server(conn->target)) {
|
||||
conn->flags &= ~CO_FL_EARLY_SSL_HS;
|
||||
conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = SSL_write_early_data(conn->xprt_ctx, bo_ptr(buf), try, &written_data);
|
||||
if (ret == 1) {
|
||||
ret = written_data;
|
||||
conn->tmp_early_data += ret;
|
||||
if (objt_server(conn->target)) {
|
||||
conn->flags &= ~CO_FL_EARLY_SSL_HS;
|
||||
conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN | CO_FL_EARLY_DATA;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
@ -5600,6 +5635,13 @@ static void ssl_sock_close(struct connection *conn) {
|
||||
*/
|
||||
static void ssl_sock_shutw(struct connection *conn, int clean)
|
||||
{
|
||||
/* If we're done with the connection before we did the handshake
|
||||
* force the handshake anyway, so that the session is in a consistent
|
||||
* state
|
||||
*/
|
||||
if (conn->flags & CO_FL_EARLY_SSL_HS)
|
||||
SSL_do_handshake(conn->xprt_ctx);
|
||||
|
||||
if (conn->flags & CO_FL_HANDSHAKE)
|
||||
return;
|
||||
if (!clean)
|
||||
@ -7705,6 +7747,13 @@ static int srv_parse_no_ssl(char **args, int *cur_arg, struct proxy *px, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the "allow-0rtt" server keyword */
|
||||
static int srv_parse_allow_0rtt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
||||
{
|
||||
newsrv->ssl_ctx.options |= SRV_SSL_O_EARLY_DATA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the "no-ssl-reuse" server keyword */
|
||||
static int srv_parse_no_ssl_reuse(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
||||
{
|
||||
@ -8558,6 +8607,7 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
|
||||
* not enabled.
|
||||
*/
|
||||
static struct srv_kw_list srv_kws = { "SSL", { }, {
|
||||
{ "allow-0rtt", srv_parse_allow_0rtt, 0, 1 }, /* Allow using early data on this server */
|
||||
{ "ca-file", srv_parse_ca_file, 1, 1 }, /* set CAfile to process verify server cert */
|
||||
{ "check-sni", srv_parse_check_sni, 1, 1 }, /* set SNI */
|
||||
{ "check-ssl", srv_parse_check_ssl, 0, 1 }, /* enable SSL for health checks */
|
||||
|
Loading…
Reference in New Issue
Block a user