MINOR: ssl: Handle reading early data after writing better.

It can happen that we want to read early data, write some, and then continue
reading them.
To do so, we can't reuse tmp_early_data to store the amount of data sent,
so introduce a new member.
If we read early data, then ssl_sock_to_buf() is now the only responsible
for getting back to the handshake, to make sure we don't miss any early data.
This commit is contained in:
Olivier Houchard 2017-11-23 18:21:29 +01:00 committed by Willy Tarreau
parent 51753458c4
commit 90084a133d
3 changed files with 8 additions and 17 deletions

View File

@ -607,6 +607,7 @@ static inline void conn_init(struct connection *conn)
conn->obj_type = OBJ_TYPE_CONN;
conn->flags = CO_FL_NONE;
conn->tmp_early_data = -1;
conn->sent_early_data = 0;
conn->mux = NULL;
conn->mux_ctx = NULL;
conn->owner = NULL;

View File

@ -373,6 +373,7 @@ struct connection {
void *owner; /* pointer to the owner session for incoming connections, or NULL */
int xprt_st; /* transport layer state, initialized to zero */
int tmp_early_data; /* 1st byte of early data, if any */
int sent_early_data; /* Amount of early data we sent so far */
union conn_handle handle; /* connection handle at the socket layer */
enum obj_type *target; /* the target to connect to (server, proxy, applet, ...) */
struct list list; /* attach point to various connection lists (idle, ...) */

View File

@ -1377,7 +1377,7 @@ void ssl_sock_infocbk(const SSL *ssl, int where, int ret)
if (where & SSL_CB_HANDSHAKE_START) {
/* Disable renegotiation (CVE-2009-3555) */
if ((conn->flags & (CO_FL_CONNECTED | CO_FL_EARLY_SSL_HS)) == CO_FL_CONNECTED) {
if ((conn->flags & (CO_FL_CONNECTED | CO_FL_EARLY_SSL_HS | CO_FL_EARLY_DATA)) == CO_FL_CONNECTED) {
conn->flags |= CO_FL_ERROR;
conn->err_code = CO_ER_SSL_RENEG;
}
@ -5318,15 +5318,6 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun
/* let's realign the buffer to optimize I/O */
if (buffer_empty(buf)) {
buf->p = buf->data;
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
/*
* If we're done reading the early data, and we're using
* a new buffer, then we know for sure we're not tainted
* with early data anymore
*/
if ((conn->flags & (CO_FL_EARLY_SSL_HS |CO_FL_EARLY_DATA)) == CO_FL_EARLY_DATA)
conn->flags &= ~CO_FL_EARLY_DATA;
#endif
}
/* read the largest possible block. For this, we perform only one call
@ -5499,9 +5490,6 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
if (!SSL_is_init_finished(conn->xprt_ctx)) {
unsigned int max_early;
if (conn->tmp_early_data == -1)
conn->tmp_early_data = 0;
if (objt_listener(conn->target))
max_early = SSL_get_max_early_data(conn->xprt_ctx);
else {
@ -5511,17 +5499,18 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
max_early = 0;
}
if (try + conn->tmp_early_data > max_early) {
try -= (try + conn->tmp_early_data) - max_early;
if (try + conn->sent_early_data > max_early) {
try -= (try + conn->sent_early_data) - max_early;
if (try <= 0) {
conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
if (!(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;
conn->sent_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;