diff options
-rw-r--r-- | doc/man3/SSL_CTX_set_options.pod | 37 | ||||
-rw-r--r-- | include/internal/quic_sf_list.h | 2 | ||||
-rw-r--r-- | include/internal/quic_ssl.h | 1 | ||||
-rw-r--r-- | include/internal/quic_stream.h | 5 | ||||
-rw-r--r-- | include/internal/ring_buf.h | 20 | ||||
-rw-r--r-- | ssl/quic/quic_channel.c | 9 | ||||
-rw-r--r-- | ssl/quic/quic_impl.c | 18 | ||||
-rw-r--r-- | ssl/quic/quic_rstream.c | 9 | ||||
-rw-r--r-- | ssl/quic/quic_sf_list.c | 7 | ||||
-rw-r--r-- | ssl/quic/quic_sstream.c | 2 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 11 | ||||
-rw-r--r-- | test/quic_stream_test.c | 15 |
12 files changed, 125 insertions, 11 deletions
diff --git a/doc/man3/SSL_CTX_set_options.pod b/doc/man3/SSL_CTX_set_options.pod index c7170b160a..44d2fd1342 100644 --- a/doc/man3/SSL_CTX_set_options.pod +++ b/doc/man3/SSL_CTX_set_options.pod @@ -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 diff --git a/include/internal/quic_sf_list.h b/include/internal/quic_sf_list.h index f0efcea2bf..2583ae2811 100644 --- a/include/internal/quic_sf_list.h +++ b/include/internal/quic_sf_list.h @@ -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; /* diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h index 28047f985c..cfcd3a6b92 100644 --- a/include/internal/quic_ssl.h +++ b/include/internal/quic_ssl.h @@ -38,6 +38,7 @@ __owur int ossl_quic_key_update(SSL *s, int update_type); __owur int ossl_quic_get_key_update_type(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; diff --git a/include/internal/quic_stream.h b/include/internal/quic_stream.h index a1e88a4ab6..4bd88d5b11 100644 --- a/include/internal/quic_stream.h +++ b/include/internal/quic_stream.h @@ -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 diff --git a/include/internal/ring_buf.h b/include/internal/ring_buf.h index e7da3b32a0..69b8df2aa8 100644 --- a/include/internal/ring_buf.h +++ b/include/internal/ring_buf.h @@ -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 = (size_t)(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) diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 586441f138..53d86eac98 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2696,8 +2696,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)) diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 4f379e32ed..d2a79feb61 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -2798,6 +2798,24 @@ 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; +} + /* * Internal Testing APIs * ===================== diff --git a/ssl/quic/quic_rstream.c b/ssl/quic/quic_rstream.c index b35bd983af..80970b084f 100644 --- a/ssl/quic/quic_rstream.c +++ b/ssl/quic/quic_rstream.c @@ -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) { @@ -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); @@ -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; +} diff --git a/ssl/quic/quic_sf_list.c b/ssl/quic/quic_sf_list.c index b53cbc1739..7f3fc9b842 100644 --- a/ssl/quic/quic_sf_list.c +++ b/ssl/quic/quic_sf_list.c @@ -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, + (size_t)(sf->range.end - sf->range.start)); ossl_qrx_pkt_release(sf->pkt); OPENSSL_free(sf); } @@ -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 *)sf->data, + (size_t)(sf->range.end - sf->range.start)); + /* release the packet */ sf->data = NULL; ossl_qrx_pkt_release(sf->pkt); diff --git a/ssl/quic/quic_sstream.c b/ssl/quic/quic_sstream.c index 0e15dde51d..5ead14038a 100644 --- a/ssl/quic/quic_sstream.c +++ b/ssl/quic/quic_sstream.c @@ -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) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1894be7d59..51a78fa383 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5880,10 +5880,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; diff --git a/test/quic_stream_test.c b/test/quic_stream_test.c index e7690ff20f..04882b21f0 100644 --- a/test/quic_stream_test.c +++ b/test/quic_stream_test.c @@ -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); @@ -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; @@ -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) { @@ -561,9 +570,9 @@ static int test_rstream_random(int idx) ret = 1; err: + ossl_quic_rstream_free(rstream); OPENSSL_free(bulk_data); OPENSSL_free(read_buf); - ossl_quic_rstream_free(rstream); return ret; } |