]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: Handle reading early data after writing better.
authorOlivier Houchard <ohouchard@haproxy.com>
Thu, 23 Nov 2017 17:21:29 +0000 (18:21 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 23 Nov 2017 18:35:28 +0000 (19:35 +0100)
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.

include/proto/connection.h
include/types/connection.h
src/ssl_sock.c

index 05a63fe6adf1b1aa62bf85717a91af7af458d946..c68ae20ba79f0cc8f09af7ed76f1178514b693f8 100644 (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;
index 88573b8a75e0984d11a8cc452ba368a9ea427739..a9d04474db3c3ed6809be7f981f4c06e7ab85216 100644 (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, ...) */
index 0fca243d2a38591674ff18ad2a1200340c2930b2..e98cc61f0ec7ca6a9bd25d4a2439d19361fe626a 100644 (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;