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 <hlandau@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22408)
This commit is contained in:
Tomas Mraz 2023-10-17 10:00:58 +02:00 committed by Matt Caswell
parent 8e520d2714
commit 7757f5ef73
8 changed files with 93 additions and 9 deletions

View File

@ -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

View File

@ -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<SSL_shutdown(3)> 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

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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
* =====================

View File

@ -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;

View File

@ -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: