diff options
author | Hugo Landau <hlandau@openssl.org> | 2023-04-18 19:30:56 +0100 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2023-05-12 14:47:13 +0100 |
commit | c3a04ea2fdd073e55b57e70e4f17f3ccbaa8c8a6 (patch) | |
tree | 2f9714368d7195d214ac85f5e860629ad9f5af80 /ssl | |
parent | b6fc2294a1a5bd6053647afea02180147018112b (diff) |
QUIC DISPATCH/APL: Add SSL_stream_reset and status query APIs
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20765)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/quic/quic_impl.c | 185 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 75 |
2 files changed, 260 insertions, 0 deletions
diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index e3402e5c65..fbcc85e52a 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -2306,6 +2306,191 @@ size_t ossl_quic_get_accept_stream_queue_len(SSL *s) } /* + * SSL_stream_reset + * ---------------- + */ +int ossl_quic_stream_reset(SSL *ssl, + const SSL_STREAM_RESET_ARGS *args, + size_t args_len) +{ + QCTX ctx; + QUIC_STREAM_MAP *qsm; + QUIC_STREAM *qs; + uint64_t error_code; + + if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/0, &ctx)) + return 0; + + qsm = ossl_quic_channel_get_qsm(ctx.qc->ch); + qs = ctx.xso->stream; + error_code = (args != NULL ? args->quic_error_code : 0); + + ossl_quic_stream_map_reset_stream_send_part(qsm, qs, error_code); + + quic_unlock(ctx.qc); + return 1; +} + +/* + * SSL_get_stream_read_state + * ------------------------- + */ +static void quic_classify_stream(QUIC_CONNECTION *qc, + QUIC_STREAM *qs, + int is_write, + int *state, + uint64_t *app_error_code) +{ + int local_init; + uint64_t final_size; + + local_init = (ossl_quic_stream_is_server_init(qs) == qc->as_server); + + if (app_error_code != NULL) + *app_error_code = UINT64_MAX; + else + app_error_code = &final_size; /* throw away value */ + + if (!ossl_quic_stream_is_bidi(qs) && local_init != is_write) { + /* + * Unidirectional stream and this direction of transmission doesn't + * exist. + */ + *state = SSL_STREAM_STATE_WRONG_DIR; + } else if (ossl_quic_channel_is_term_any(qc->ch)) { + /* Connection already closed. */ + *state = SSL_STREAM_STATE_CONN_CLOSED; + } else if (!is_write && qs->recv_fin_retired) { + /* Application has read a FIN. */ + *state = SSL_STREAM_STATE_FINISHED; + } else if ((!is_write && qs->stop_sending) + || (is_write && qs->reset_stream)) { + /* + * Stream has been reset locally. FIN takes precedence over this for the + * read case as the application need not care if the stream is reset + * after a FIN has been successfully processed. + */ + *state = SSL_STREAM_STATE_RESET_LOCAL; + *app_error_code = !is_write + ? qs->stop_sending_aec + : qs->reset_stream_aec; + } else if ((!is_write && qs->peer_reset_stream) + || (is_write && qs->peer_stop_sending)) { + /* + * Stream has been reset remotely. */ + *state = SSL_STREAM_STATE_RESET_REMOTE; + *app_error_code = !is_write + ? qs->peer_reset_stream_aec + : qs->peer_stop_sending_aec; + } else if (is_write && ossl_quic_sstream_get_final_size(qs->sstream, + &final_size)) { + /* + * Stream has been finished. Stream reset takes precedence over this for + * the write case as peer may not have received all data. + */ + *state = SSL_STREAM_STATE_FINISHED; + } else { + /* Stream still healthy. */ + *state = SSL_STREAM_STATE_OK; + } +} + +static int quic_get_stream_state(SSL *ssl, int is_write) +{ + QCTX ctx; + int state; + + if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/-1, &ctx)) + return SSL_STREAM_STATE_NONE; + + quic_classify_stream(ctx.qc, ctx.xso->stream, is_write, &state, NULL); + quic_unlock(ctx.qc); + return state; +} + +int ossl_quic_get_stream_read_state(SSL *ssl) +{ + return quic_get_stream_state(ssl, /*is_write=*/0); +} + +/* + * SSL_get_stream_write_state + * -------------------------- + */ +int ossl_quic_get_stream_write_state(SSL *ssl) +{ + return quic_get_stream_state(ssl, /*is_write=*/1); +} + +/* + * SSL_get_stream_read_error_code + * ------------------------------ + */ +static int quic_get_stream_error_code(SSL *ssl, int is_write, + uint64_t *app_error_code) +{ + QCTX ctx; + int state; + + if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/-1, &ctx)) + return -1; + + quic_classify_stream(ctx.qc, ctx.xso->stream, /*is_write=*/0, + &state, app_error_code); + + quic_unlock(ctx.qc); + switch (state) { + case SSL_STREAM_STATE_FINISHED: + return 0; + case SSL_STREAM_STATE_RESET_LOCAL: + case SSL_STREAM_STATE_RESET_REMOTE: + return 1; + default: + return -1; + } +} + +int ossl_quic_get_stream_read_error_code(SSL *ssl, uint64_t *app_error_code) +{ + return quic_get_stream_error_code(ssl, /*is_write=*/0, app_error_code); +} + +/* + * SSL_get_stream_write_error_code + * ------------------------------- + */ +int ossl_quic_get_stream_write_error_code(SSL *ssl, uint64_t *app_error_code) +{ + return quic_get_stream_error_code(ssl, /*is_write=*/1, app_error_code); +} + +/* + * SSL_get_conn_close_info + * ----------------------- + */ +int ossl_quic_get_conn_close_info(SSL *ssl, + SSL_CONN_CLOSE_INFO *info, + size_t info_len) +{ + QCTX ctx; + const QUIC_TERMINATE_CAUSE *tc; + + if (!expect_quic_conn_only(ssl, &ctx)) + return -1; + + tc = ossl_quic_channel_get_terminate_cause(ctx.qc->ch); + if (tc == NULL) + return 0; + + info->error_code = tc->error_code; + info->reason = NULL; /* TODO(QUIC): Wire reason */ + info->reason_len = 0; + info->is_local = !tc->remote; + info->is_transport = !tc->app; + return 1; +} + +/* * QUIC Front-End I/O API: SSL_CTX Management * ========================================== */ diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1d84ac39dc..3fb80824de 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -7424,6 +7424,81 @@ size_t SSL_get_accept_stream_queue_len(SSL *s) #endif } +int SSL_stream_reset(SSL *s, + const SSL_STREAM_RESET_ARGS *args, + size_t args_len) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return 0; + + return ossl_quic_stream_reset(s, args, args_len); +#else + return 0; +#endif +} + +int SSL_get_stream_read_state(SSL *s) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return SSL_STREAM_STATE_NONE; + + return ossl_quic_get_stream_read_state(s); +#else + return SSL_STREAM_STATE_NONE; +#endif +} + +int SSL_get_stream_write_state(SSL *s) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return SSL_STREAM_STATE_NONE; + + return ossl_quic_get_stream_write_state(s); +#else + return SSL_STREAM_STATE_NONE; +#endif +} + +int SSL_get_stream_read_error_code(SSL *s, uint64_t *app_error_code) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return -1; + + return ossl_quic_get_stream_read_error_code(s, app_error_code); +#else + return -1; +#endif +} + +int SSL_get_stream_write_error_code(SSL *s, uint64_t *app_error_code) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return -1; + + return ossl_quic_get_stream_write_error_code(s, app_error_code); +#else + return -1; +#endif +} + +int SSL_get_conn_close_info(SSL *s, SSL_CONN_CLOSE_INFO *info, + size_t info_len) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return -1; + + return ossl_quic_get_conn_close_info(s, info, info_len); +#else + return -1; +#endif +} + int SSL_add_expected_rpk(SSL *s, EVP_PKEY *rpk) { unsigned char *data = NULL; |