Commit cb5bb8916f for openssl.org
commit cb5bb8916fa0e044e6658c8b3db6d7c672cb25fe
Author: Matt Caswell <matt@openssl.org>
Date: Fri Apr 11 14:19:46 2025 +0100
Fix errors on SSL_accept() and SSL_get_error()
Calling SSL_accept() was raising two errors on the stack if you passed
the wrong object type. Similarly SSL_get_error() was adding an error to
the stack if the wrong object type was passed and returning the wrong
result.
We also ensure SSL_set_accept_state() and SSL_set_connect_state() don't
raise spurious errors since these are void functions.
Fixes #27347
Fixes #27348
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/27351)
diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h
index acfeb0d515..e7fd260ab6 100644
--- a/include/internal/quic_ssl.h
+++ b/include/internal/quic_ssl.h
@@ -72,8 +72,8 @@ __owur const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u);
int ossl_quic_renegotiate_check(SSL *ssl, int initok);
int ossl_quic_do_handshake(SSL *s);
-void ossl_quic_set_connect_state(SSL *s);
-void ossl_quic_set_accept_state(SSL *s);
+int ossl_quic_set_connect_state(SSL *s, int raiseerrs);
+int ossl_quic_set_accept_state(SSL *s, int raiseerrs);
__owur int ossl_quic_has_pending(const SSL *s);
__owur int ossl_quic_handle_events(SSL *s);
diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c
index 847639b89e..64da2be4af 100644
--- a/ssl/quic/quic_impl.c
+++ b/ssl/quic/quic_impl.c
@@ -186,6 +186,10 @@ static int quic_raise_non_normal_error(QCTX *ctx,
* This determines whether SSL_get_error() is updated; the value it returns
* is modified only by an I/O call.
*
+ * QCTX_NO_ERROR
+ * Don't raise an error if the object type is wrong. Should not be used in
+ * conjunction with any flags that may raise errors not related to a wrong
+ * object type.
*/
#define QCTX_C (1U << 0)
#define QCTX_S (1U << 1)
@@ -195,6 +199,7 @@ static int quic_raise_non_normal_error(QCTX *ctx,
#define QCTX_LOCK (1U << 5)
#define QCTX_IO (1U << 6)
#define QCTX_D (1U << 7)
+#define QCTX_NO_ERROR (1U << 8)
/*
* Called when expect_quic failed. Used to diagnose why such a call failed and
@@ -205,7 +210,9 @@ static int wrong_type(const SSL *s, uint32_t flags)
const uint32_t mask = QCTX_C | QCTX_S | QCTX_L | QCTX_D;
int code = ERR_R_UNSUPPORTED;
- if ((flags & mask) == QCTX_D)
+ if ((flags & QCTX_NO_ERROR) != 0)
+ return 1;
+ else if ((flags & mask) == QCTX_D)
code = SSL_R_DOMAIN_USE_ONLY;
else if ((flags & mask) == QCTX_L)
code = SSL_R_LISTENER_USE_ONLY;
@@ -225,7 +232,8 @@ static int wrong_type(const SSL *s, uint32_t flags)
*
* After this returns 1, all fields of the passed QCTX are initialised.
* Returns 0 on failure. This function is intended to be used to provide API
- * semantics and as such, it invokes QUIC_RAISE_NON_NORMAL_ERROR() on failure.
+ * semantics and as such, it invokes QUIC_RAISE_NON_NORMAL_ERROR() on failure
+ * unless the QCTX_NO_ERROR flag is set.
*
* The flags argument controls the preconditions and postconditions of this
* function. See above for the different flags.
@@ -378,6 +386,25 @@ err:
return ok;
}
+static int is_quic_c(const SSL *s, QCTX *ctx, int raiseerrs)
+{
+ uint32_t flags = QCTX_C;
+
+ if (!raiseerrs)
+ flags |= QCTX_NO_ERROR;
+ return expect_quic_as(s, ctx, flags);
+}
+
+/* Same as expect_quic_cs except that errors are not raised if raiseerrs == 0 */
+static int is_quic_cs(const SSL *s, QCTX *ctx, int raiseerrs)
+{
+ uint32_t flags = QCTX_C | QCTX_S;
+
+ if (!raiseerrs)
+ flags |= QCTX_NO_ERROR;
+ return expect_quic_as(s, ctx, flags);
+}
+
static int expect_quic_cs(const SSL *s, QCTX *ctx)
{
return expect_quic_as(s, ctx, QCTX_C | QCTX_S);
@@ -1672,33 +1699,47 @@ long ossl_quic_ctrl(SSL *s, int cmd, long larg, void *parg)
}
/* SSL_set_connect_state */
-void ossl_quic_set_connect_state(SSL *s)
+int ossl_quic_set_connect_state(SSL *s, int raiseerrs)
{
QCTX ctx;
- if (!expect_quic_cs(s, &ctx))
- return;
+ if (!is_quic_c(s, &ctx, raiseerrs))
+ return 0;
+
+ if (ctx.qc->as_server_state == 0)
+ return 1;
/* Cannot be changed after handshake started */
- if (ctx.qc->started || ctx.is_stream)
- return;
+ if (ctx.qc->started) {
+ if (raiseerrs)
+ QUIC_RAISE_NON_NORMAL_ERROR(NULL, SSL_R_INVALID_COMMAND, NULL);
+ return 0;
+ }
ctx.qc->as_server_state = 0;
+ return 1;
}
/* SSL_set_accept_state */
-void ossl_quic_set_accept_state(SSL *s)
+int ossl_quic_set_accept_state(SSL *s, int raiseerrs)
{
QCTX ctx;
- if (!expect_quic_cs(s, &ctx))
- return;
+ if (!is_quic_c(s, &ctx, raiseerrs))
+ return 0;
+
+ if (ctx.qc->as_server_state == 1)
+ return 1;
/* Cannot be changed after handshake started */
- if (ctx.qc->started || ctx.is_stream)
- return;
+ if (ctx.qc->started) {
+ if (raiseerrs)
+ QUIC_RAISE_NON_NORMAL_ERROR(NULL, SSL_R_INVALID_COMMAND, NULL);
+ return 0;
+ }
ctx.qc->as_server_state = 1;
+ return 1;
}
/* SSL_do_handshake */
@@ -1983,7 +2024,8 @@ int ossl_quic_do_handshake(SSL *s)
int ossl_quic_connect(SSL *s)
{
/* Ensure we are in connect state (no-op if non-idle). */
- ossl_quic_set_connect_state(s);
+ if (!ossl_quic_set_connect_state(s, 1))
+ return -1;
/* Begin or continue the handshake */
return ossl_quic_do_handshake(s);
@@ -1993,7 +2035,8 @@ int ossl_quic_connect(SSL *s)
int ossl_quic_accept(SSL *s)
{
/* Ensure we are in accept state (no-op if non-idle). */
- ossl_quic_set_accept_state(s);
+ if (!ossl_quic_set_accept_state(s, 1))
+ return -1;
/* Begin or continue the handshake */
return ossl_quic_do_handshake(s);
@@ -2325,8 +2368,9 @@ int ossl_quic_get_error(const SSL *s, int i)
QCTX ctx;
int net_error, last_error;
- if (!expect_quic_cs(s, &ctx))
- return 0;
+ /* SSL_get_errors() should not raise new errors */
+ if (!is_quic_cs(s, &ctx, 0 /* suppress errors */))
+ return SSL_ERROR_SSL;
qctx_lock(&ctx);
net_error = ossl_quic_channel_net_error(ctx.qc->ch);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a81b16c109..efc6d66fb9 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -4980,7 +4980,8 @@ void SSL_set_accept_state(SSL *s)
#ifndef OPENSSL_NO_QUIC
if (IS_QUIC(s)) {
- ossl_quic_set_accept_state(s);
+ /* We suppress errors because this is a void function */
+ (void)ossl_quic_set_accept_state(s, 0 /* suppress errors */);
return;
}
#endif
@@ -4999,7 +5000,8 @@ void SSL_set_connect_state(SSL *s)
#ifndef OPENSSL_NO_QUIC
if (IS_QUIC(s)) {
- ossl_quic_set_connect_state(s);
+ /* We suppress errors because this is a void function */
+ (void)ossl_quic_set_connect_state(s, 0 /* suppress errors */);
return;
}
#endif