diff --git a/src/client/messenger.h b/src/client/messenger.h index 15f3d1f8..8dbe0846 100644 --- a/src/client/messenger.h +++ b/src/client/messenger.h @@ -62,10 +62,12 @@ struct op_aes_xts_decrypt_t; void destroy_aes_xts_encrypt(op_aes_xts_encrypt_t *encrypt_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 { - uint8_t encrypted; - uint32_t size; + uint8_t content_type; + uint16_t version; + uint16_t size; }; struct osd_client_t @@ -99,7 +101,7 @@ struct osd_client_t size_t ssl_out_buf_size = 0, ssl_out_buf_cap = 0; bool ssl_handshake_done = false; msgr_tls_record_hdr_t ssl_read_record; - size_t ssl_read_record_size = 0; + size_t ssl_read_header_size = 0; #endif // Read state diff --git a/src/client/msgr_receive.cpp b/src/client/msgr_receive.cpp index 6cd0c5f9..e6577d24 100644 --- a/src/client/msgr_receive.cpp +++ b/src/client/msgr_receive.cpp @@ -107,37 +107,49 @@ public: 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; - if (n > sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_record_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); + size_t h = bufsize-done; + if (bufsize-done <= sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_header_size) + { + // 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; - cl->ssl_read_record_size += n; - if (done >= bufsize) - return true; - } - 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; + cl->ssl_read_record.size -= (n - h); + if (!cl->ssl_read_record.size) + cl->ssl_read_header_size = 0; + return; } + // Continued TLS data - buffer it to BIO size_t n = cl->ssl_read_record.size; if (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); assert(r == n); done += n; cl->ssl_read_record.size -= n; if (!cl->ssl_read_record.size) - cl->ssl_read_record_size = 0; - return true; + cl->ssl_read_header_size = 0; } bool read(uint8_t *dst, size_t dst_len, int flags) override @@ -148,6 +160,8 @@ public: from -= dst_len; return true; } + if (done >= bufsize) + return false; size_t n = dst_len-from; if (!(flags & RDR_TLS) || !cl->ssl_cli) { @@ -170,13 +184,19 @@ public: memcpy(dst+from, curbuf+done, n); done += n; } + cl->read_op_pos += n; + from += n; + if (from < dst_len) + { + return false; + } } else { // Here, dst == NULL is not allowed assert(dst != NULL); - if (!buffer_encrypted()) - return false; +buffer_again: + buffer_encrypted(); if (!cl->ssl_handshake_done) { if (!msgr->ssl_do_handshake(cl)) @@ -198,12 +218,17 @@ public: if (!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); 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)); cl->io_error = true; @@ -214,12 +239,14 @@ public: { XXH3_64bits_update(cl->read_csum_state, dst+from, n); } - } - cl->read_op_pos += n; - from += n; - if (from < dst_len) - { - return false; + cl->read_op_pos += n; + from += n; + if (from < dst_len) + { + if (done < bufsize) + goto buffer_again; + return false; + } } from = 0; return true; diff --git a/src/client/msgr_send.cpp b/src/client/msgr_send.cpp index 7d4768a6..cbf5d23d 100644 --- a/src/client/msgr_send.cpp +++ b/src/client/msgr_send.cpp @@ -102,21 +102,6 @@ public: 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() { if (!cl->ssl_handshake_done) @@ -124,7 +109,9 @@ public: if (!msgr->ssl_do_handshake(cl)) 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) @@ -195,7 +182,9 @@ public: if (!write_to_ssl(cl, src, src_len, flags, from)) 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) return false; @@ -242,8 +231,9 @@ class get_op_writer_t: public msgr_op_writer_t do { ssl_extend_buf(); - cl->ssl_out_buf_size += ssl_op_writer_t::ssl_copy_from_bio(cl->read_from_ssl, - cl->ssl_out_buf+cl->ssl_out_buf_size, cl->ssl_out_buf_cap-cl->ssl_out_buf_size); + 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); + if (r > 0) + cl->ssl_out_buf_size += r; } while (cl->ssl_out_buf_size >= cl->ssl_out_buf_cap); if (cl->ssl_out_buf_size > prev_size) {