Commit 33eaaad65b for openssl.org
commit 33eaaad65ba7623345a6dcf7a20612dc0339107e
Author: Alberto Maschietto <albertomaschietto9@gmail.com>
Date: Wed Aug 19 21:42:03 2026 +0400
Fix NULL dereference in SSL_get0_group_name() before a handshake
SSL_get0_group_name() falls back to sc->session->kex_group whenever the
connection is not a TLSv1.3 one that has already done a key exchange.
On a connection that has not started (or completed) a handshake yet,
sc->session is still NULL, so the fallback crashes instead of returning
NULL as the manual page promises.
This is the same problem that was fixed for SSL_get_negotiated_group() in
commit 4ca80d3941, and the fix here mirrors it: only consult the session
when there is one, and report "no group" otherwise. It affects TLS, DTLS
and QUIC connections, and every branch since the accessor was added in
3.2.
The RETURN VALUES section said a NULL return meant an error occurred.
That is not accurate: NULL simply means no group is available, which is
the normal answer before a handshake or after one that used no key
agreement group. Reword it accordingly.
Add a regression test that calls both group accessors on a fresh SSL
object. Without the fix it segfaults; with it, SSL_get0_group_name()
returns NULL and SSL_get_negotiated_group() returns NID_undef.
Fixes #32379
Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Frederik Wedel-Heinen <fwh.openssl@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Merge-date: Tue Sep 29 17:04:02 2026
Merged-from: https://github.com/openssl/openssl/pull/32437
diff --git a/doc/man3/SSL_get0_group_name.pod b/doc/man3/SSL_get0_group_name.pod
index 37bea2fc7b..574a6be14c 100644
--- a/doc/man3/SSL_get0_group_name.pod
+++ b/doc/man3/SSL_get0_group_name.pod
@@ -20,8 +20,9 @@ the key agreement of the current TLS session establishment.
If non-NULL, SSL_get0_group_name() returns the name of the group that was used for
the key agreement of the current TLS session establishment.
-If SSL_get0_group_name() returns NULL, an error occurred; possibly no TLS session
-has been established. See also L<SSL_get_negotiated_group(3)>.
+SSL_get0_group_name() returns NULL if no group is available, for example
+because no TLS session has been established yet, or because the handshake did
+not use a key agreement group. See also L<SSL_get_negotiated_group(3)>.
Note that the return value is valid only during the lifetime of the
SSL object I<ssl>.
@@ -37,7 +38,7 @@ This function was added in OpenSSL 3.2.
=head1 COPYRIGHT
-Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index af320478bf..05ac3e493d 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -5671,8 +5671,10 @@ const char *SSL_get0_group_name(SSL *s)
if (SSL_CONNECTION_IS_VERSION13(sc) && sc->s3.did_kex)
id = sc->s3.group_id;
- else
+ else if (sc->session != NULL)
id = sc->session->kex_group;
+ else
+ return NULL;
return tls1_group_id2name(s->ctx, id);
}
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 697c3d5b83..fc43d6af0a 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -8433,6 +8433,37 @@ end:
#endif /* OSSL_NO_USABLE_TLS1_3 */
#endif /* !defined(OSSL_NO_USABLE_TLS1_3) || !defined(OSSL_NO_USABLE_DTLS1_3) */
+/*
+ * Test that the group accessors report "no group" rather than crashing when
+ * they are called on a connection that has not performed a handshake yet.
+ */
+#if !defined(OPENSSL_NO_TLS1_2) || !defined(OSSL_NO_USABLE_TLS1_3)
+static int test_group_before_handshake(void)
+{
+ SSL_CTX *cctx = NULL;
+ SSL *clientssl = NULL;
+ int testresult = 0;
+
+ if (!TEST_ptr(cctx = SSL_CTX_new_ex(libctx, NULL, TLS_client_method())))
+ goto end;
+
+ if (!TEST_ptr(clientssl = SSL_new(cctx)))
+ goto end;
+
+ if (!TEST_ptr_null(SSL_get0_group_name(clientssl)))
+ goto end;
+
+ if (!TEST_int_eq(SSL_get_negotiated_group(clientssl), NID_undef))
+ goto end;
+
+ testresult = 1;
+end:
+ SSL_free(clientssl);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+#endif
+
static int clntaddoldcb = 0;
static int clntparseoldcb = 0;
static int srvaddoldcb = 0;
@@ -18030,6 +18061,9 @@ int setup_tests(void)
#ifndef OSSL_NO_USABLE_TLS1_3
ADD_TEST(test_ktls_moving_write_buffer);
#endif
+#endif
+#if !defined(OPENSSL_NO_TLS1_2) || !defined(OSSL_NO_USABLE_TLS1_3)
+ ADD_TEST(test_group_before_handshake);
#endif
ADD_TEST(test_large_message_tls);
ADD_TEST(test_large_message_tls_read_ahead);