From: Tomas Mraz Date: Tue, 17 Oct 2023 08:00:58 +0000 (+0200) Subject: QUIC: Add handling of SSL_get_shutdown() X-Git-Tag: openssl-3.2.0-beta1~61 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7757f5ef731ad4e8d6c0f59ef752e4f726ba4f90;p=thirdparty%2Fopenssl.git QUIC: Add handling of SSL_get_shutdown() Return SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN with semantics similar to TLS connections. Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22408) --- diff --git a/doc/man3/SSL_CTX_set_quiet_shutdown.pod b/doc/man3/SSL_CTX_set_quiet_shutdown.pod index b7c2a320691..4894e2f5d25 100644 --- a/doc/man3/SSL_CTX_set_quiet_shutdown.pod +++ b/doc/man3/SSL_CTX_set_quiet_shutdown.pod @@ -2,7 +2,8 @@ =head1 NAME -SSL_CTX_set_quiet_shutdown, SSL_CTX_get_quiet_shutdown, SSL_set_quiet_shutdown, SSL_get_quiet_shutdown - manipulate shutdown behaviour +SSL_CTX_set_quiet_shutdown, SSL_CTX_get_quiet_shutdown, SSL_set_quiet_shutdown, +SSL_get_quiet_shutdown - manipulate shutdown behaviour =head1 SYNOPSIS @@ -54,7 +55,7 @@ The default is normal shutdown behaviour as described by the TLS standard. SSL_CTX_set_quiet_shutdown() and SSL_set_quiet_shutdown() do not return diagnostic information. -SSL_CTX_get_quiet_shutdown() and SSL_get_quiet_shutdown return the current +SSL_CTX_get_quiet_shutdown() and SSL_get_quiet_shutdown() return the current setting. =head1 SEE ALSO diff --git a/doc/man3/SSL_set_shutdown.pod b/doc/man3/SSL_set_shutdown.pod index c3b613a247d..9a7eb463a82 100644 --- a/doc/man3/SSL_set_shutdown.pod +++ b/doc/man3/SSL_set_shutdown.pod @@ -57,13 +57,21 @@ If a close_notify was received, SSL_RECEIVED_SHUTDOWN will be set, for setting SSL_SENT_SHUTDOWN the application must however still call L or SSL_set_shutdown() itself. -These functions are not supported for QUIC SSL objects. +SSL_set_shutdown() is not supported for QUIC SSL objects. =head1 RETURN VALUES SSL_set_shutdown() does not return diagnostic information. -SSL_get_shutdown() returns the current setting. +SSL_get_shutdown() returns the current shutdown state as set or based +on the actual connection state. + +SSL_get_shutdown() returns 0 if called on a QUIC stream SSL object. If it +is called on a QUIC connection SSL object, it returns a value with +SSL_SENT_SHUTDOWN set if CONNECTION_CLOSE has been sent to the peer and +it returns a value with SSL_RECEIVED_SHUTDOWN set if CONNECTION_CLOSE +has been received from the peer or the QUIC connection is fully terminated +for other reasons. =head1 SEE ALSO diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index 0841001c23d..f46db0637e9 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -320,6 +320,7 @@ QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch, int ossl_quic_channel_is_term_any(const QUIC_CHANNEL *ch); const QUIC_TERMINATE_CAUSE * ossl_quic_channel_get_terminate_cause(const QUIC_CHANNEL *ch); +int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_terminated(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch); diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h index 66cea1bfe12..52d4527c811 100644 --- a/include/internal/quic_ssl.h +++ b/include/internal/quic_ssl.h @@ -125,6 +125,7 @@ void ossl_quic_conn_force_assist_thread_wake(SSL *s); QUIC_CHANNEL *ossl_quic_conn_get_channel(SSL *s); int ossl_quic_has_pending(const SSL *s); +int ossl_quic_get_shutdown(const SSL *s); # endif diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 3b9993b96ad..8e75eda539f 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -635,7 +635,7 @@ int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch) return ch != NULL && ch->state == QUIC_CHANNEL_STATE_ACTIVE; } -static int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch) +int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch) { return ch->state == QUIC_CHANNEL_STATE_TERMINATING_CLOSING; } diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 29a283dca0b..bdf5d5fea88 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -3571,6 +3571,27 @@ const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u) return NULL; } +/* + * SSL_get_shutdown() + * ------------------ + */ +int ossl_quic_get_shutdown(const SSL *s) +{ + QCTX ctx; + int shut = 0; + + if (!expect_quic_conn_only(s, &ctx)) + return 0; + + if (ossl_quic_channel_is_term_any(ctx.qc->ch)) { + shut |= SSL_SENT_SHUTDOWN; + if (!ossl_quic_channel_is_closing(ctx.qc->ch)) + shut |= SSL_RECEIVED_SHUTDOWN; + } + + return shut; +} + /* * Internal Testing APIs * ===================== diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f15fe126a22..bd9160b7561 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5142,7 +5142,7 @@ void SSL_set_quiet_shutdown(SSL *s, int mode) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s); - /* TODO(QUIC): Currently not supported for QUIC. */ + /* Not supported with QUIC */ if (sc == NULL) return; @@ -5153,7 +5153,7 @@ int SSL_get_quiet_shutdown(const SSL *s) { const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s); - /* TODO(QUIC): Currently not supported for QUIC. */ + /* Not supported with QUIC */ if (sc == NULL) return 0; @@ -5164,7 +5164,7 @@ void SSL_set_shutdown(SSL *s, int mode) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s); - /* TODO(QUIC): Do we want this for QUIC? */ + /* Not supported with QUIC */ if (sc == NULL) return; @@ -5175,7 +5175,12 @@ int SSL_get_shutdown(const SSL *s) { const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s); - /* TODO(QUIC): Do we want this for QUIC? */ +#ifndef OPENSSL_NO_QUIC + /* QUIC: Just indicate whether the connection was shutdown cleanly. */ + if (IS_QUIC(s)) + return ossl_quic_get_shutdown(s); +#endif + if (sc == NULL) return 0; diff --git a/test/quicapitest.c b/test/quicapitest.c index 81c8c215bd4..37d7803005c 100644 --- a/test/quicapitest.c +++ b/test/quicapitest.c @@ -1335,6 +1335,52 @@ static int test_alpn(int idx) return testresult; } +/* + * Test SSL_get_shutdown() behavior. + */ +static int test_get_shutdown(void) +{ + SSL_CTX *cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method()); + SSL *clientquic = NULL; + QUIC_TSERVER *qtserv = NULL; + int testresult = 0; + + if (!TEST_ptr(cctx) + || !TEST_true(qtest_create_quic_objects(libctx, cctx, NULL, cert, + privkey, + QTEST_FLAG_FAKE_TIME, + &qtserv, &clientquic, + NULL, NULL)) + || !TEST_true(qtest_create_quic_connection(qtserv, clientquic))) + goto err; + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), 0)) + goto err; + + if (!TEST_int_eq(SSL_shutdown(clientquic), 0)) + goto err; + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), SSL_SENT_SHUTDOWN)) + goto err; + + do { + ossl_quic_tserver_tick(qtserv); + qtest_add_time(100); + } while (SSL_shutdown(clientquic) == 0); + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), + SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) + goto err; + + testresult = 1; + err: + ossl_quic_tserver_free(qtserv); + SSL_free(clientquic); + SSL_CTX_free(cctx); + + return testresult; +} + #define MAX_LOOPS 2000 /* @@ -1586,6 +1632,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_client_auth, 2); ADD_ALL_TESTS(test_alpn, 2); ADD_ALL_TESTS(test_noisy_dgram, 2); + ADD_TEST(test_get_shutdown); return 1; err: