Skip to content

Commit

Permalink
Support SSL_OP_CLEANSE_PLAINTEXT on QUIC streams
Browse files Browse the repository at this point in the history
  • Loading branch information
t8m committed Jun 12, 2023
1 parent 247f307 commit 6b317c4
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 10 deletions.
37 changes: 37 additions & 0 deletions doc/man3/SSL_CTX_set_options.pod
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,43 @@ renegotiation between OpenSSL clients and unpatched servers B<only>, while
B<SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION> allows initial connections
and renegotiation between OpenSSL and unpatched clients or servers.

=head2 Applicability of options to QUIC connections and streams

These options apply to SSL objects referencing a QUIC connection:

=over 4

=item SSL_OP_ALLOW_NO_DHE_KEX

=item SSL_OP_NO_TX_CERTIFICATE_COMPRESSION

=item SSL_OP_NO_RX_CERTIFICATE_COMPRESSION

=item SSL_OP_NO_TICKET

=item SSL_OP_PRIORITIZE_CHACHA

=back

Other options do not have an effect and will be ignored.

These options apply to SSL objects referencing a QUIC stream:

=over 4

=item SSL_OP_CLEANSE_PLAINTEXT

=back

Other options do not have an effect and will be ignored.

If an SSL object is a QUIC connection object with a default stream attached,
only the stream-relevant options are applied. If it is a QUIC connection
without a default stream, the stream-relevant options are ignored.

Connection and stream relevant options are initialized from the options
set on SSL_CTX before the connection or stream objects are created.

=head1 RETURN VALUES

SSL_CTX_set_options() and SSL_set_options() return the new options bit-mask
Expand Down
2 changes: 2 additions & 0 deletions include/internal/quic_sf_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ typedef struct sframe_list_st {
uint64_t offset;
/* Is head locked ? */
int head_locked;
/* Cleanse data on release? */
int cleanse;
} SFRAME_LIST;

/*
Expand Down
1 change: 1 addition & 0 deletions include/internal/quic_ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ __owur long ossl_quic_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void)
__owur size_t ossl_quic_pending(const SSL *s);
__owur int ossl_quic_num_ciphers(void);
__owur const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u);
__owur int ossl_quic_set_ssl_op(SSL *ssl, uint64_t op);
int ossl_quic_renegotiate_check(SSL *ssl, int initok);

typedef struct quic_conn_st QUIC_CONNECTION;
Expand Down
5 changes: 5 additions & 0 deletions include/internal/quic_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,11 @@ int ossl_quic_rstream_move_to_rbuf(QUIC_RSTREAM *qrs);
* than currently occupied.
*/
int ossl_quic_rstream_resize_rbuf(QUIC_RSTREAM *qrs, size_t rbuf_size);

/*
* Sets flag to cleanse the buffered data when user reads it.
*/
void ossl_quic_rstream_set_cleanse(QUIC_RSTREAM *qrs, int cleanse);
# endif

#endif
20 changes: 19 additions & 1 deletion include/internal/ring_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,31 @@ static ossl_inline int ring_buf_get_buf_at(const struct ring_buf *r,
}

static ossl_inline void ring_buf_cpop_range(struct ring_buf *r,
uint64_t start, uint64_t end)
uint64_t start, uint64_t end,
int cleanse)
{
assert(end >= start);

if (start > r->ctail_offset)
return;

if (cleanse && r->alloc > 0 && end > r->ctail_offset) {
size_t idx = r->ctail_offset % r->alloc;
uint64_t cleanse_end = end + 1;
size_t l;

if (cleanse_end > r->head_offset)
cleanse_end = r->head_offset;
l = cleanse_end - r->ctail_offset;
if (l > r->alloc - idx) {
OPENSSL_cleanse((unsigned char *)r->start + idx, r->alloc - idx);
l -= r->alloc - idx;
idx = 0;
}
if (l > 0)
OPENSSL_cleanse((unsigned char *)r->start + idx, l);
}

r->ctail_offset = end + 1;
/* Allow culling unpushed data */
if (r->head_offset < r->ctail_offset)
Expand Down
9 changes: 7 additions & 2 deletions ssl/quic/quic_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -2379,8 +2379,13 @@ static int ch_init_new_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs,
if (can_send && (qs->sstream = ossl_quic_sstream_new(INIT_APP_BUF_LEN)) == NULL)
goto err;

if (can_recv && (qs->rstream = ossl_quic_rstream_new(NULL, NULL, 0)) == NULL)
goto err;
if (can_recv) {
if ((qs->rstream = ossl_quic_rstream_new(NULL, NULL, 0)) == NULL)
goto err;
ossl_quic_rstream_set_cleanse(qs->rstream,
(ch->tls->ctx->options
& SSL_OP_CLEANSE_PLAINTEXT) != 0);
}

/* TXFC */
if (!ossl_quic_txfc_init(&qs->txfc, &ch->conn_txfc))
Expand Down
18 changes: 18 additions & 0 deletions ssl/quic/quic_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2726,3 +2726,21 @@ const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u)
{
return NULL;
}

int ossl_quic_set_ssl_op(SSL *ssl, uint64_t op)
{
QCTX ctx;

if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/-1, &ctx))
return 0;

if (ctx.xso->stream == NULL || ctx.xso->stream->rstream == NULL)
goto out;

ossl_quic_rstream_set_cleanse(ctx.xso->stream->rstream,
(op & SSL_OP_CLEANSE_PLAINTEXT) != 0);

out:
quic_unlock(ctx.qc);
return 1;
}
9 changes: 7 additions & 2 deletions ssl/quic/quic_rstream.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ static int read_internal(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,

if (drop && offset != 0) {
ret = ossl_sframe_list_drop_frames(&qrs->fl, offset);
ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1);
ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse);
}

if (ret) {
Expand Down Expand Up @@ -245,7 +245,7 @@ int ossl_quic_rstream_release_record(QUIC_RSTREAM *qrs, size_t read_len)
return 0;

if (offset > 0)
ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1);
ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse);

if (qrs->rxfc != NULL) {
OSSL_TIME rtt = get_rtt(qrs);
Expand Down Expand Up @@ -286,3 +286,8 @@ int ossl_quic_rstream_resize_rbuf(QUIC_RSTREAM *qrs, size_t rbuf_size)

return 1;
}

void ossl_quic_rstream_set_cleanse(QUIC_RSTREAM *qrs, int cleanse)
{
qrs->fl.cleanse = cleanse;
}
7 changes: 7 additions & 0 deletions ssl/quic/quic_sf_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ struct stream_frame_st {

static void stream_frame_free(SFRAME_LIST *fl, STREAM_FRAME *sf)
{
if (fl->cleanse && sf->data != NULL)
OPENSSL_cleanse((unsigned char *)sf->data,
sf->range.end - sf->range.start);
ossl_qrx_pkt_release(sf->pkt);
OPENSSL_free(sf);
}
Expand Down Expand Up @@ -295,6 +298,10 @@ int ossl_sframe_list_move_data(SFRAME_LIST *fl,
/* data did not fit */
return 0;

if (fl->cleanse)
OPENSSL_cleanse((unsigned char *)data,
sf->range.end - sf->range.start);

/* release the packet */
sf->data = NULL;
ossl_qrx_pkt_release(sf->pkt);
Expand Down
2 changes: 1 addition & 1 deletion ssl/quic/quic_sstream.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ static void qss_cull(QUIC_SSTREAM *qss)
* can only cull contiguous areas at the start of the ring buffer anyway.
*/
if (h != NULL)
ring_buf_cpop_range(&qss->ring_buf, h->range.start, h->range.end);
ring_buf_cpop_range(&qss->ring_buf, h->range.start, h->range.end, 0);
}

int ossl_quic_sstream_set_buffer_size(QUIC_SSTREAM *qss, size_t num_bytes)
Expand Down
11 changes: 9 additions & 2 deletions ssl/ssl_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -5870,10 +5870,17 @@ uint64_t SSL_CTX_set_options(SSL_CTX *ctx, uint64_t op)

uint64_t SSL_set_options(SSL *s, uint64_t op)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
SSL_CONNECTION *sc;
OSSL_PARAM options[2], *opts = options;

if (sc == NULL)
#ifndef OPENSSL_NO_QUIC
if (IS_QUIC(s) && ossl_quic_set_ssl_op(s, op))
/* Handled by QUIC, return as set */
return op;
#endif

sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
return 0;

sc->options |= op;
Expand Down
13 changes: 11 additions & 2 deletions test/quic_stream_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,9 @@ static int test_rstream_random(int idx)
|| !TEST_ptr(rstream = ossl_quic_rstream_new(NULL, NULL, 0)))
goto err;

if (idx % 3 == 0)
ossl_quic_rstream_set_cleanse(rstream, 1);

for (i = 0; i < data_size; ++i)
bulk_data[i] = (unsigned char)(test_random() & 0xFF);

Expand Down Expand Up @@ -522,8 +525,9 @@ static int test_rstream_random(int idx)
}
if (!TEST_size_t_ge(readbytes, queued_min - read_off)
|| !TEST_size_t_le(readbytes + read_off, data_size)
|| !TEST_mem_eq(read_buf, readbytes, bulk_data + read_off,
readbytes))
|| (idx % 3 != 0
&& !TEST_mem_eq(read_buf, readbytes, bulk_data + read_off,
readbytes)))
goto err;
read_off += readbytes;
queued_min = read_off;
Expand All @@ -543,6 +547,11 @@ static int test_rstream_random(int idx)

TEST_info("Total read bytes: %zu Fin rcvd: %d", read_off, fin);

if (idx % 3 == 0)
for (i = 0; i < read_off; i++)
if (!TEST_uchar_eq(bulk_data[i], 0))
goto err;

if (read_off == data_size && fin_set && !fin) {
/* We might still receive the final empty frame */
if (idx % 2 == 0) {
Expand Down

0 comments on commit 6b317c4

Please sign in to comment.