Parse standard TLS record headers
This commit is contained in:
@@ -60,10 +60,12 @@ struct op_aes_xts_decrypt_t;
|
|||||||
void destroy_aes_xts_encrypt(op_aes_xts_encrypt_t *encrypt_ctx);
|
void destroy_aes_xts_encrypt(op_aes_xts_encrypt_t *encrypt_ctx);
|
||||||
void destroy_aes_xts_decrypt(op_aes_xts_decrypt_t *decrypt_ctx);
|
void destroy_aes_xts_decrypt(op_aes_xts_decrypt_t *decrypt_ctx);
|
||||||
|
|
||||||
|
// Standard TLS record header. We are only interested in the record size
|
||||||
struct __attribute__((__packed__)) msgr_tls_record_hdr_t
|
struct __attribute__((__packed__)) msgr_tls_record_hdr_t
|
||||||
{
|
{
|
||||||
uint8_t encrypted;
|
uint8_t content_type;
|
||||||
uint32_t size;
|
uint16_t version;
|
||||||
|
uint16_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osd_client_t
|
struct osd_client_t
|
||||||
@@ -97,7 +99,7 @@ struct osd_client_t
|
|||||||
size_t ssl_out_buf_size = 0, ssl_out_buf_cap = 0;
|
size_t ssl_out_buf_size = 0, ssl_out_buf_cap = 0;
|
||||||
bool ssl_handshake_done = false;
|
bool ssl_handshake_done = false;
|
||||||
msgr_tls_record_hdr_t ssl_read_record;
|
msgr_tls_record_hdr_t ssl_read_record;
|
||||||
size_t ssl_read_record_size = 0;
|
size_t ssl_read_header_size = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Read state
|
// Read state
|
||||||
|
|||||||
+56
-29
@@ -106,37 +106,49 @@ public:
|
|||||||
from = cl->read_op_pos;
|
from = cl->read_op_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool buffer_encrypted()
|
void buffer_encrypted()
|
||||||
{
|
{
|
||||||
if (cl->ssl_read_record_size < sizeof(msgr_tls_record_hdr_t))
|
if (cl->ssl_read_header_size < sizeof(msgr_tls_record_hdr_t))
|
||||||
{
|
{
|
||||||
size_t n = bufsize-done;
|
size_t h = bufsize-done;
|
||||||
if (n > sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_record_size)
|
if (bufsize-done <= sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_header_size)
|
||||||
n = sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_record_size;
|
{
|
||||||
memcpy(((uint8_t*)&cl->ssl_read_record) + cl->ssl_read_record_size, curbuf+done, n);
|
// Less than record header or just record header
|
||||||
|
memcpy(((uint8_t*)&cl->ssl_read_record) + cl->ssl_read_header_size, curbuf+done, h);
|
||||||
|
cl->ssl_read_header_size += h;
|
||||||
|
if (cl->ssl_read_header_size == sizeof(msgr_tls_record_hdr_t))
|
||||||
|
cl->ssl_read_record.size = ntohs(cl->ssl_read_record.size);
|
||||||
|
int r = BIO_write(cl->write_to_ssl, curbuf+done, h);
|
||||||
|
assert(r == h);
|
||||||
|
done += h;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Record header and at least some data - copy both to BIO in a one BIO_write() call
|
||||||
|
h = sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_header_size;
|
||||||
|
memcpy(((uint8_t*)&cl->ssl_read_record) + cl->ssl_read_header_size, curbuf+done, h);
|
||||||
|
cl->ssl_read_header_size = sizeof(msgr_tls_record_hdr_t);
|
||||||
|
cl->ssl_read_record.size = ntohs(cl->ssl_read_record.size);
|
||||||
|
size_t n = h + cl->ssl_read_record.size;
|
||||||
|
if (n > bufsize-done)
|
||||||
|
n = bufsize-done;
|
||||||
|
int r = BIO_write(cl->write_to_ssl, curbuf+done, n);
|
||||||
|
assert(r == n);
|
||||||
done += n;
|
done += n;
|
||||||
cl->ssl_read_record_size += n;
|
cl->ssl_read_record.size -= (n - h);
|
||||||
if (done >= bufsize)
|
if (!cl->ssl_read_record.size)
|
||||||
return true;
|
cl->ssl_read_header_size = 0;
|
||||||
}
|
return;
|
||||||
if (cl->ssl_read_record.encrypted != 1)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Client %ju got record with unknown type %u\n", cl->ssl_read_record.encrypted);
|
|
||||||
cl->io_error = true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
// Continued TLS data - buffer it to BIO
|
||||||
size_t n = cl->ssl_read_record.size;
|
size_t n = cl->ssl_read_record.size;
|
||||||
if (n > bufsize-done)
|
if (n > bufsize-done)
|
||||||
n = bufsize-done;
|
n = bufsize-done;
|
||||||
// Buffer all encrypted data
|
|
||||||
// FIXME Limit the amount of buffered data
|
|
||||||
int r = BIO_write(cl->write_to_ssl, curbuf+done, n);
|
int r = BIO_write(cl->write_to_ssl, curbuf+done, n);
|
||||||
assert(r == n);
|
assert(r == n);
|
||||||
done += n;
|
done += n;
|
||||||
cl->ssl_read_record.size -= n;
|
cl->ssl_read_record.size -= n;
|
||||||
if (!cl->ssl_read_record.size)
|
if (!cl->ssl_read_record.size)
|
||||||
cl->ssl_read_record_size = 0;
|
cl->ssl_read_header_size = 0;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read(uint8_t *dst, size_t dst_len, int flags) override
|
bool read(uint8_t *dst, size_t dst_len, int flags) override
|
||||||
@@ -147,6 +159,8 @@ public:
|
|||||||
from -= dst_len;
|
from -= dst_len;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (done >= bufsize)
|
||||||
|
return false;
|
||||||
size_t n = dst_len-from;
|
size_t n = dst_len-from;
|
||||||
if (!(flags & RDR_TLS) || !cl->ssl_cli)
|
if (!(flags & RDR_TLS) || !cl->ssl_cli)
|
||||||
{
|
{
|
||||||
@@ -169,13 +183,19 @@ public:
|
|||||||
memcpy(dst+from, curbuf+done, n);
|
memcpy(dst+from, curbuf+done, n);
|
||||||
done += n;
|
done += n;
|
||||||
}
|
}
|
||||||
|
cl->read_op_pos += n;
|
||||||
|
from += n;
|
||||||
|
if (from < dst_len)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Here, dst == NULL is not allowed
|
// Here, dst == NULL is not allowed
|
||||||
assert(dst != NULL);
|
assert(dst != NULL);
|
||||||
if (!buffer_encrypted())
|
buffer_again:
|
||||||
return false;
|
buffer_encrypted();
|
||||||
if (!cl->ssl_handshake_done)
|
if (!cl->ssl_handshake_done)
|
||||||
{
|
{
|
||||||
if (!msgr->ssl_do_handshake(cl))
|
if (!msgr->ssl_do_handshake(cl))
|
||||||
@@ -197,12 +217,17 @@ public:
|
|||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
ok = SSL_get_error(cl->ssl_cli, ok);
|
ok = SSL_get_error(cl->ssl_cli, ok);
|
||||||
if (ok == SSL_ERROR_ZERO_RETURN)
|
if (ok == SSL_ERROR_WANT_READ)
|
||||||
|
{
|
||||||
|
if (done < bufsize)
|
||||||
|
goto buffer_again;
|
||||||
|
}
|
||||||
|
else if (ok == SSL_ERROR_ZERO_RETURN)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Client %ju TLS disconnected\n", cl->client_id);
|
fprintf(stderr, "Client %ju TLS disconnected\n", cl->client_id);
|
||||||
cl->io_error = true;
|
cl->io_error = true;
|
||||||
}
|
}
|
||||||
else if (ok != 0 && ok != SSL_ERROR_WANT_READ && ok != SSL_ERROR_WANT_WRITE)
|
else if (ok != 0 && ok != SSL_ERROR_WANT_WRITE)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Client %ju TLS read error: %s. Disconnecting client\n", cl->client_id, ERR_error_string(ERR_get_error(), NULL));
|
fprintf(stderr, "Client %ju TLS read error: %s. Disconnecting client\n", cl->client_id, ERR_error_string(ERR_get_error(), NULL));
|
||||||
cl->io_error = true;
|
cl->io_error = true;
|
||||||
@@ -213,12 +238,14 @@ public:
|
|||||||
{
|
{
|
||||||
XXH3_64bits_update(cl->read_csum_state, dst+from, n);
|
XXH3_64bits_update(cl->read_csum_state, dst+from, n);
|
||||||
}
|
}
|
||||||
}
|
cl->read_op_pos += n;
|
||||||
cl->read_op_pos += n;
|
from += n;
|
||||||
from += n;
|
if (from < dst_len)
|
||||||
if (from < dst_len)
|
{
|
||||||
{
|
if (done < bufsize)
|
||||||
return false;
|
goto buffer_again;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
from = 0;
|
from = 0;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -101,21 +101,6 @@ public:
|
|||||||
from = cl->write_op_pos;
|
from = cl->write_op_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t ssl_copy_from_bio(BIO *bio, uint8_t *buf, size_t size)
|
|
||||||
{
|
|
||||||
if (size < sizeof(msgr_tls_record_hdr_t))
|
|
||||||
return 0;
|
|
||||||
int r = BIO_read(bio, buf+sizeof(msgr_tls_record_hdr_t), size-sizeof(msgr_tls_record_hdr_t));
|
|
||||||
if (r > 0)
|
|
||||||
{
|
|
||||||
msgr_tls_record_hdr_t *hdr = (msgr_tls_record_hdr_t*)buf;
|
|
||||||
hdr->encrypted = 1;
|
|
||||||
hdr->size = r;
|
|
||||||
return r+sizeof(msgr_tls_record_hdr_t);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush_ssl()
|
void flush_ssl()
|
||||||
{
|
{
|
||||||
if (!cl->ssl_handshake_done)
|
if (!cl->ssl_handshake_done)
|
||||||
@@ -123,7 +108,9 @@ public:
|
|||||||
if (!msgr->ssl_do_handshake(cl))
|
if (!msgr->ssl_do_handshake(cl))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
done += ssl_copy_from_bio(cl->read_from_ssl, curbuf+done, bufsize-done);
|
int r = BIO_read(cl->read_from_ssl, curbuf+done, bufsize-done);
|
||||||
|
if (r > 0)
|
||||||
|
done += r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool write_to_ssl(osd_client_t *cl, uint8_t *src, size_t src_len, int flags, size_t & from)
|
static inline bool write_to_ssl(osd_client_t *cl, uint8_t *src, size_t src_len, int flags, size_t & from)
|
||||||
@@ -194,7 +181,9 @@ public:
|
|||||||
if (!write_to_ssl(cl, src, src_len, flags, from))
|
if (!write_to_ssl(cl, src, src_len, flags, from))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
done += ssl_copy_from_bio(cl->read_from_ssl, curbuf+done, bufsize-done);
|
int r = BIO_read(cl->read_from_ssl, curbuf+done, bufsize-done);
|
||||||
|
if (r > 0)
|
||||||
|
done += r;
|
||||||
}
|
}
|
||||||
if (from < src_len)
|
if (from < src_len)
|
||||||
return false;
|
return false;
|
||||||
@@ -241,8 +230,9 @@ class get_op_writer_t: public msgr_op_writer_t
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
ssl_extend_buf();
|
ssl_extend_buf();
|
||||||
cl->ssl_out_buf_size += ssl_op_writer_t::ssl_copy_from_bio(cl->read_from_ssl,
|
int r = BIO_read(cl->read_from_ssl, cl->ssl_out_buf+cl->ssl_out_buf_size, cl->ssl_out_buf_cap-cl->ssl_out_buf_size);
|
||||||
cl->ssl_out_buf+cl->ssl_out_buf_size, cl->ssl_out_buf_cap-cl->ssl_out_buf_size);
|
if (r > 0)
|
||||||
|
cl->ssl_out_buf_size += r;
|
||||||
} while (cl->ssl_out_buf_size >= cl->ssl_out_buf_cap);
|
} while (cl->ssl_out_buf_size >= cl->ssl_out_buf_cap);
|
||||||
if (cl->ssl_out_buf_size > prev_size)
|
if (cl->ssl_out_buf_size > prev_size)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user