mirror of https://github.com/openssl/openssl.git
				
				
				
			Support SSL_OP_CLEANSE_PLAINTEXT on QUIC streams
Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21182)
This commit is contained in:
		
							parent
							
								
									ff88545e02
								
							
						
					
					
						commit
						a02571a024
					
				| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 * =====================
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue