From 995ff282103d444844a476ae6aba4a05936284fa Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 18 Apr 2023 19:30:55 +0100 Subject: QUIC CHANNEL, APL: Reject policy handling Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20765) --- include/internal/quic_channel.h | 17 ++++++++ ssl/quic/quic_channel.c | 24 +++++++++++- ssl/quic/quic_channel_local.h | 9 +++++ ssl/quic/quic_impl.c | 87 +++++++++++++++++++++++++++-------------- 4 files changed, 107 insertions(+), 30 deletions(-) diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index 74b3473782..32e5a57fd9 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -299,6 +299,23 @@ QUIC_STREAM *ossl_quic_channel_new_stream_local(QUIC_CHANNEL *ch, int is_uni); QUIC_STREAM *ossl_quic_channel_new_stream_remote(QUIC_CHANNEL *ch, uint64_t stream_id); +/* + * Configures incoming stream auto-reject. If enabled, incoming streams have + * both their sending and receiving parts automatically rejected using + * STOP_SENDING and STREAM_RESET frames. aec is the application error + * code to be used for those frames. + */ +void ossl_quic_channel_set_incoming_stream_auto_reject(QUIC_CHANNEL *ch, + int enable, + uint64_t aec); + +/* + * Causes the channel to reject the sending and receiving parts of a stream, + * as though autorejected. Can be used if a stream has already been + * accepted. + */ +void ossl_quic_channel_reject_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs); + # endif #endif diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index f11139132f..3e099e9d93 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2342,10 +2342,32 @@ QUIC_STREAM *ossl_quic_channel_new_stream_remote(QUIC_CHANNEL *ch, if (!ch_init_new_stream(ch, qs, /*can_send=*/!is_uni, /*can_recv=*/1)) goto err; - ossl_quic_stream_map_push_accept_queue(&ch->qsm, qs); + if (ch->incoming_stream_auto_reject) + ossl_quic_channel_reject_stream(ch, qs); + else + ossl_quic_stream_map_push_accept_queue(&ch->qsm, qs); + return qs; err: ossl_quic_stream_map_release(&ch->qsm, qs); return NULL; } + +void ossl_quic_channel_set_incoming_stream_auto_reject(QUIC_CHANNEL *ch, + int enable, + uint64_t aec) +{ + ch->incoming_stream_auto_reject = (enable != 0); + ch->incoming_stream_auto_reject_aec = aec; +} + +void ossl_quic_channel_reject_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs) +{ + ossl_quic_stream_stop_sending(qs, ch->incoming_stream_auto_reject_aec); + ossl_quic_stream_reset(qs, ch->incoming_stream_auto_reject_aec); + + qs->deleted = 1; + + ossl_quic_stream_map_update_state(&ch->qsm, qs); +} diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h index 3645c277dd..a1ce833f56 100644 --- a/ssl/quic/quic_channel_local.h +++ b/ssl/quic/quic_channel_local.h @@ -167,6 +167,12 @@ struct quic_channel_st { uint64_t next_local_stream_ordinal_bidi; uint64_t next_local_stream_ordinal_uni; + /* + * Application error code to be used for STOP_SENDING/RESET_STREAM frames + * used to autoreject incoming streams. + */ + uint64_t incoming_stream_auto_reject_aec; + /* Valid if we are in the TERMINATING or TERMINATED states. */ QUIC_TERMINATE_CAUSE terminate_cause; @@ -290,6 +296,9 @@ struct quic_channel_st { * 10.1). */ unsigned int have_sent_ack_eliciting_since_rx : 1; + + /* Should incoming streams automatically be rejected? */ + unsigned int incoming_stream_auto_reject : 1; }; # endif diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 840dcfed96..2dd5a4f91f 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -25,6 +25,9 @@ static int qc_wait_for_default_xso_for_read(QUIC_CONNECTION *qc); static void quic_lock(QUIC_CONNECTION *qc); static void quic_unlock(QUIC_CONNECTION *qc); static int quic_do_handshake(QUIC_CONNECTION *qc); +static void qc_update_reject_policy(QUIC_CONNECTION *qc); +static void qc_touch_default_xso(QUIC_CONNECTION *qc); +static void qc_set_default_xso(QUIC_CONNECTION *qc, QUIC_XSO *xso, int touch); /* * QUIC Front-End I/O API: Common Utilities @@ -303,6 +306,8 @@ SSL *ossl_quic_new(SSL_CTX *ctx) if (!create_channel(qc)) goto err; + qc_update_reject_policy(qc); + /* * We do not create the default XSO yet. The reason for this is that the * stream ID of the default XSO will depend on whether the stream is client @@ -458,6 +463,21 @@ void ossl_quic_conn_force_assist_thread_wake(SSL *s) ossl_quic_thread_assist_notify_deadline_changed(&ctx.qc->thread_assist); } +QUIC_NEEDS_LOCK +static void qc_touch_default_xso(QUIC_CONNECTION *qc) +{ + qc->default_xso_created = 1; + qc_update_reject_policy(qc); +} + +QUIC_NEEDS_LOCK +static void qc_set_default_xso(QUIC_CONNECTION *qc, QUIC_XSO *xso, int touch) +{ + qc->default_xso = xso; + if (touch) + qc_touch_default_xso(qc); +} + /* * QUIC Front-End I/O API: Network BIO Configuration * ================================================= @@ -1170,11 +1190,12 @@ static int qc_try_create_default_xso_for_write(QUIC_CONNECTION *qc) if (qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_AUTO_UNI) flags |= SSL_STREAM_FLAG_UNI; - qc->default_xso = (QUIC_XSO *)ossl_quic_conn_stream_new(&qc->ssl, flags); + qc_set_default_xso(qc, (QUIC_XSO *)ossl_quic_conn_stream_new(&qc->ssl, flags), + /*touch=*/0); if (qc->default_xso == NULL) return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL); - qc->default_xso_created = 1; + qc_touch_default_xso(qc); return 1; } @@ -1267,11 +1288,11 @@ static int qc_wait_for_default_xso_for_read(QUIC_CONNECTION *qc) * We now have qs != NULL. Make it the default stream, creating the * necessary XSO. */ - qc->default_xso = create_xso_from_stream(qc, qs); + qc_set_default_xso(qc, create_xso_from_stream(qc, qs), /*touch=*/0); if (qc->default_xso == NULL) return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL); - qc->default_xso_created = 1; + qc_touch_default_xso(qc); /* inhibits default XSO */ return 1; } @@ -1326,7 +1347,7 @@ SSL *ossl_quic_conn_stream_new(SSL *s, uint64_t flags) if (xso == NULL) goto err; - ctx.qc->default_xso_created = 1; /* inhibits default XSO */ + qc_touch_default_xso(ctx.qc); /* inhibits default XSO */ quic_unlock(ctx.qc); return &xso->ssl; @@ -2055,11 +2076,9 @@ SSL *ossl_quic_detach_stream(SSL *s) quic_lock(ctx.qc); - xso = ctx.qc->default_xso; - ctx.qc->default_xso = NULL; - /* Calling this function inhibits default XSO autocreation. */ - ctx.qc->default_xso_created = 1; + xso = ctx.qc->default_xso; + qc_set_default_xso(ctx.qc, NULL, /*touch=*/1); quic_unlock(ctx.qc); @@ -2090,10 +2109,8 @@ int ossl_quic_attach_stream(SSL *conn, SSL *stream) "connection already has a default stream"); } - ctx.qc->default_xso = (QUIC_XSO *)stream; - /* Calling this function inhibits default XSO autocreation. */ - ctx.qc->default_xso_created = 1; + qc_set_default_xso(ctx.qc, (QUIC_XSO *)stream, /*touch=*/1); quic_unlock(ctx.qc); return 1; @@ -2103,6 +2120,33 @@ int ossl_quic_attach_stream(SSL *conn, SSL *stream) * SSL_set_incoming_stream_reject_policy * ------------------------------------- */ +QUIC_NEEDS_LOCK +static int qc_get_effective_incoming_stream_reject_policy(QUIC_CONNECTION *qc) +{ + switch (qc->incoming_stream_reject_policy) { + case SSL_INCOMING_STREAM_REJECT_POLICY_AUTO: + if ((qc->default_xso == NULL && !qc->default_xso_created) + || qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_NONE) + return SSL_INCOMING_STREAM_REJECT_POLICY_ACCEPT; + else + return SSL_INCOMING_STREAM_REJECT_POLICY_REJECT; + + default: + return qc->incoming_stream_reject_policy; + } +} + +QUIC_NEEDS_LOCK +static void qc_update_reject_policy(QUIC_CONNECTION *qc) +{ + int policy = qc_get_effective_incoming_stream_reject_policy(qc); + int enable_reject = (policy == SSL_INCOMING_STREAM_REJECT_POLICY_REJECT); + + ossl_quic_channel_set_incoming_stream_auto_reject(qc->ch, + enable_reject, + qc->incoming_stream_reject_aec); +} + QUIC_TAKES_LOCK int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy, uint64_t aec) @@ -2128,6 +2172,7 @@ int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy, break; } + qc_update_reject_policy(ctx.qc); quic_unlock(ctx.qc); return ret; } @@ -2136,22 +2181,6 @@ int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy, * SSL_accept_stream * ----------------- */ -QUIC_NEEDS_LOCK -static int qc_get_effective_incoming_stream_reject_policy(QUIC_CONNECTION *qc) -{ - switch (qc->incoming_stream_reject_policy) { - case SSL_INCOMING_STREAM_REJECT_POLICY_AUTO: - if ((qc->default_xso == NULL && qc->default_xso_created) - || qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_NONE) - return SSL_INCOMING_STREAM_REJECT_POLICY_ACCEPT; - else - return SSL_INCOMING_STREAM_REJECT_POLICY_REJECT; - - default: - return qc->incoming_stream_reject_policy; - } -} - struct wait_for_incoming_stream_args { QUIC_CONNECTION *qc; QUIC_STREAM *qs; @@ -2228,7 +2257,7 @@ SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags) new_s = &xso->ssl; /* Calling this function inhibits default XSO autocreation. */ - ctx.qc->default_xso_created = 1; + qc_touch_default_xso(ctx.qc); /* inhibits default XSO */ out: quic_unlock(ctx.qc); -- cgit v1.2.1