diff options
author | Hugo Landau <hlandau@openssl.org> | 2023-07-26 18:10:16 +0100 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2023-08-10 18:19:45 +0100 |
commit | 40c8c756c86fc17751b989426aa66fb33319c4ca (patch) | |
tree | 77eae277108a725e7ea4d2b7c52cd4fb05f49d05 | |
parent | d56b81ac9f02dd55ecf3281d16fdb156897b4d8d (diff) |
QUIC APL/CHANNEL: Wire up connection closure reason
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21565)
-rw-r--r-- | include/internal/quic_channel.h | 18 | ||||
-rw-r--r-- | include/openssl/ssl.h.in | 8 | ||||
-rw-r--r-- | ssl/quic/quic_channel.c | 47 | ||||
-rw-r--r-- | ssl/quic/quic_impl.c | 7 | ||||
-rw-r--r-- | ssl/quic/quic_tserver.c | 2 |
5 files changed, 69 insertions, 13 deletions
diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index e36acb4eeb..2524a65fe7 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -149,6 +149,21 @@ typedef struct quic_terminate_cause_st { */ uint64_t frame_type; + /* + * Optional reason string. When calling ossl_quic_channel_local_close, if a + * reason string pointer is passed, it is copied and stored inside + * QUIC_CHANNEL for the remainder of the lifetime of the channel object. + * Thus the string pointed to by this value, if non-NULL, is valid for the + * lifetime of the QUIC_CHANNEL object. + */ + const char *reason; + + /* + * Length of reason in bytes. The reason is supposed to contain a UTF-8 + * string but may be arbitrary data if the reason came from the network. + */ + size_t reason_len; + /* Is this error code in the transport (0) or application (1) space? */ unsigned int app : 1; @@ -196,7 +211,8 @@ int ossl_quic_channel_set_mutator(QUIC_CHANNEL *ch, int ossl_quic_channel_start(QUIC_CHANNEL *ch); /* Start a locally initiated connection shutdown. */ -void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code); +void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code, + const char *app_reason); /* * Called when the handshake is confirmed. diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index beedd8956d..66ebaa4784 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2339,10 +2339,10 @@ __owur int SSL_get_stream_read_error_code(SSL *ssl, uint64_t *app_error_code); __owur int SSL_get_stream_write_error_code(SSL *ssl, uint64_t *app_error_code); typedef struct ssl_conn_close_info_st { - uint64_t error_code; - char *reason; - size_t reason_len; - int is_local, is_transport; + uint64_t error_code; + const char *reason; + size_t reason_len; + int is_local, is_transport; } SSL_CONN_CLOSE_INFO; __owur int SSL_get_conn_close_info(SSL *ssl, diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 6931f79d01..a4f451d6b9 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -371,6 +371,7 @@ static void ch_cleanup(QUIC_CHANNEL *ch) ossl_qrx_free(ch->qrx); ossl_quic_demux_free(ch->demux); OPENSSL_free(ch->local_transport_params); + OPENSSL_free((char *)ch->terminate_cause.reason); OSSL_ERR_STATE_free(ch->err_state); } @@ -2438,7 +2439,8 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch) } /* Start a locally initiated connection shutdown. */ -void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code) +void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code, + const char *app_reason) { QUIC_TERMINATE_CAUSE tcause = {0}; @@ -2447,6 +2449,8 @@ void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code) tcause.app = 1; tcause.error_code = app_error_code; + tcause.reason = app_reason; + tcause.reason_len = app_reason != NULL ? strlen(app_reason) : 0; ch_start_terminating(ch, &tcause, 0); } @@ -2622,6 +2626,37 @@ int ossl_quic_channel_on_handshake_confirmed(QUIC_CHANNEL *ch) * closing state and send a packet containing a CONNECTION_CLOSE * frame in response to any UDP datagram that is received. */ +static void copy_tcause(QUIC_TERMINATE_CAUSE *dst, + const QUIC_TERMINATE_CAUSE *src) +{ + dst->error_code = src->error_code; + dst->frame_type = src->frame_type; + dst->app = src->app; + dst->remote = src->remote; + + dst->reason = NULL; + dst->reason_len = 0; + + if (src->reason != NULL && src->reason_len > 0) { + size_t l = src->reason_len; + char *r; + + if (l >= SIZE_MAX) + --l; + + /* + * If this fails, dst->reason becomes NULL and we simply do not use a + * reason. This ensures termination is infallible. + */ + dst->reason = r = OPENSSL_memdup(src->reason, l + 1); + if (r == NULL) + return; + + r[l] = '\0'; + dst->reason_len = l; + } +} + static void ch_start_terminating(QUIC_CHANNEL *ch, const QUIC_TERMINATE_CAUSE *tcause, int force_immediate) @@ -2629,12 +2664,12 @@ static void ch_start_terminating(QUIC_CHANNEL *ch, switch (ch->state) { default: case QUIC_CHANNEL_STATE_IDLE: - ch->terminate_cause = *tcause; + copy_tcause(&ch->terminate_cause, tcause); ch_on_terminating_timeout(ch); break; case QUIC_CHANNEL_STATE_ACTIVE: - ch->terminate_cause = *tcause; + copy_tcause(&ch->terminate_cause, tcause); if (!force_immediate) { ch->state = tcause->remote ? QUIC_CHANNEL_STATE_TERMINATING_DRAINING @@ -2656,6 +2691,8 @@ static void ch_start_terminating(QUIC_CHANNEL *ch, f.error_code = ch->terminate_cause.error_code; f.frame_type = ch->terminate_cause.frame_type; f.is_app = ch->terminate_cause.app; + f.reason = (char *)ch->terminate_cause.reason; + f.reason_len = ch->terminate_cause.reason_len; ossl_quic_tx_packetiser_schedule_conn_close(ch->txp, &f); /* * RFC 9000 s. 10.2.2 Draining Connection State: @@ -2714,7 +2751,8 @@ void ossl_quic_channel_on_remote_conn_close(QUIC_CHANNEL *ch, tcause.app = f->is_app; tcause.error_code = f->error_code; tcause.frame_type = f->frame_type; - + tcause.reason = f->reason; + tcause.reason_len = f->reason_len; ch_start_terminating(ch, &tcause, 0); } @@ -2967,6 +3005,7 @@ void ossl_quic_channel_raise_protocol_error_loc(QUIC_CHANNEL *ch, tcause.error_code = error_code; tcause.frame_type = frame_type; + tcause.reason = reason; ch_start_terminating(ch, &tcause, 0); } diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index ca00fcd476..ba5b27eeb4 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -1200,7 +1200,8 @@ int ossl_quic_conn_shutdown(SSL *s, uint64_t flags, /* Phase 2: Connection Closure */ ossl_quic_channel_local_close(ctx.qc->ch, - args != NULL ? args->quic_error_code : 0); + args != NULL ? args->quic_error_code : 0, + args != NULL ? args->quic_reason : NULL); SSL_set_shutdown(ctx.qc->tls, SSL_SENT_SHUTDOWN); @@ -3043,8 +3044,8 @@ int ossl_quic_get_conn_close_info(SSL *ssl, return 0; info->error_code = tc->error_code; - info->reason = NULL; /* TODO(QUIC): Wire reason */ - info->reason_len = 0; + info->reason = tc->reason; + info->reason_len = tc->reason_len; info->is_local = !tc->remote; info->is_transport = !tc->app; return 1; diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index 15444ecc5b..b92b1de8da 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -488,7 +488,7 @@ OSSL_TIME ossl_quic_tserver_get_deadline(QUIC_TSERVER *srv) int ossl_quic_tserver_shutdown(QUIC_TSERVER *srv) { - ossl_quic_channel_local_close(srv->ch, 0); + ossl_quic_channel_local_close(srv->ch, 0, NULL); /* TODO(QUIC): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */ |