Commit fe9c29d0a1 for openssl.org

commit fe9c29d0a1f1e5b075660c32568ef4b5da85a70a
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date:   Sun Oct 4 15:40:23 2026 +0200

    Omit key_share from a cookie-only HelloRetryRequest

    When the server requires a HelloRetryRequest cookie and the client is
    resuming with a PSK-only key exchange, no (EC)DHE group is selected, so
    there is no key_share to process and the group id stays at zero. The
    HelloRetryRequest construction still treated a missing peer key share
    as "ask for a different group" and emitted a key_share extension naming
    group 0, which the client rightly rejects with illegal_parameter.

    Only include key_share in the HelloRetryRequest when a different group
    was actually selected, and record the same decision in the cookie so the
    transcript is reconstructed correctly on the second ClientHello.

    A DTLS test for this follows with the SSL_OP_COOKIE_EXCHANGE change that
    exposed it. SSL_stateless() cannot be used for it since it fails the PSK
    binder check on the second ClientHello for an unrelated reason.

    Assisted-by: Claude:claude-fable-5-1
    Reviewed-by: Matt Caswell <matt@openssl.foundation>
    Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Merge-date: Tue Oct  6 14:46:54 2026
    Merged-from: https://github.com/openssl/openssl/pull/33093

diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index 02ff6e8106..e3a25e2bd3 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -2020,6 +2020,12 @@ EXT_RETURN tls_construct_stoc_supported_versions(SSL_CONNECTION *s, WPACKET *pkt
     return EXT_RETURN_SENT;
 }

+/* Does the HelloRetryRequest ask the client for a different key_share? */
+static int hrr_sends_key_share(const SSL_CONNECTION *s)
+{
+    return s->s3.peer_tmp == NULL && s->s3.group_id != 0;
+}
+
 EXT_RETURN tls_construct_stoc_key_share(SSL_CONNECTION *s, WPACKET *pkt,
     unsigned int context, X509 *x,
     size_t chainidx)
@@ -2031,10 +2037,8 @@ EXT_RETURN tls_construct_stoc_key_share(SSL_CONNECTION *s, WPACKET *pkt,
     const TLS_GROUP_INFO *ginf = NULL;

     if (s->hello_retry_request == SSL_HRR_PENDING) {
-        if (ckey != NULL) {
-            /* Original key_share was acceptable so don't ask for another one */
+        if (!hrr_sends_key_share(s))
             return EXT_RETURN_NOT_SENT;
-        }
         if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
             || !WPACKET_start_sub_packet_u16(pkt)
             || !WPACKET_put_bytes_u16(pkt, s->s3.group_id)
@@ -2205,7 +2209,7 @@ EXT_RETURN tls_construct_stoc_cookie(SSL_CONNECTION *s, WPACKET *pkt,
         || !ssl->method->put_cipher_by_char(s->s3.tmp.new_cipher, pkt,
             &ciphlen)
         /* Is there a key_share extension present in this HRR? */
-        || !WPACKET_put_bytes_u8(pkt, s->s3.peer_tmp == NULL)
+        || !WPACKET_put_bytes_u8(pkt, hrr_sends_key_share(s))
         || !WPACKET_put_bytes_u64(pkt, time(NULL))
         || !WPACKET_start_sub_packet_u16(pkt)
         || !WPACKET_reserve_bytes(pkt, EVP_MAX_MD_SIZE, &hashval1)) {