Skip to content

Fix for DTLS1.3 HRR group handling#9848

Open
Frauschi wants to merge 2 commits intowolfSSL:masterfrom
Frauschi:dtls_hrr_group
Open

Fix for DTLS1.3 HRR group handling#9848
Frauschi wants to merge 2 commits intowolfSSL:masterfrom
Frauschi:dtls_hrr_group

Conversation

@Frauschi
Copy link
Contributor

@Frauschi Frauschi commented Mar 2, 2026

When a server uses an HRR to negotiate the key exchange group to use, the selected group is advertised in the HRR key share extension. Furthermore, this group is also stored in the Cookie that is sent to the client. When the server receives the second CH, the group used in the key share extension MUST be the one of the HRR.

For stateless DTLS servers, the handling of this check had a bug. The key share group of the HRR is stored in the ssl->hrr_keyshare_group variable and is checked against the received key share of the second CH. However, in the stateless server case, another CH message may be received inbetween the two CH messages of the desired client, potentially overwriting the ssl->hrr_keyshare_group variable. This then causes handshake failures when the ssl->hrr_keyshare_group variable contains another group than the second CH message of the desired client.

To fix this, two changes are conducted:

  1. Disable the ssl->hrr_keyshare_group check for stateless DTLS 1.3 servers. As long as the server is stateless, CHs from multiple clients may be received that individually cause HRRs with different groups. For each of these clients, the HRR group is properly stored in the cookie.
  2. When a valid cookie is received from the client, the server becomes stateful. In this case, we now parse the cookie for a stored HRR group. If present, we reset the ssl->hrr_keyshare_group variable to this group to ensure the error checks succeed.

A new test is added to check for this behavior.

Identified while working on #9732.

When a server uses a HRR to negotiate the key exchange group to use, the
selected group is advertised in the HRR key share extension.
Furthermore, this group is also stored in the Cookie that is sent to the
client. When the server receives the second CH, the group used in the
key share extension MUST be the one of the HRR.

For stateless DTLS servers, the handling of this check had a bug. The
key share group of the HRR is stored in the ssl->hrr_keyshare_group
variable and is checked against the received key share of the second CH.
However, in the stateless server case, another CH message may be
received inbetween the two CH message of the desired client, potentially
overwriting the ssl->hrr_keyshare_group variable. This then causes
handshake failures when the ssl->hrr_keyshare_group variable contains
another group than the second CH message of the desired client.

To fix this, two changes are conducted:
1. Disable the ssl->hrr_keyshare_group check for stateless DTLS 1.3
   servers. As long as the server is stateless, CHs from multiple
   clients may be received that individually cause HRRs with different
   groups. For each of these clients, the HRR group is properly stored
   in the cookie.
2. When a valid cookie is received from the client, the server becomes
   stateful. In this case, we now parse the cookie for a stored HRR
   group. If present, we reset the ssl->hrr_keyshare_group variable to
   this group to ensure the error checks succeed.

A new test is added to check for this behavior.
src/dtls.c Outdated
Comment on lines +301 to +311
int ret = 0;
word16 len;
const byte* cookie = NULL;

if (ch->cookieExt.size < OPAQUE16_LEN + 1)
return BUFFER_E;
ato16(ch->cookieExt.elements, &len);
if (ch->cookieExt.size - OPAQUE16_LEN != len)
return BUFFER_E;
cookie = ch->cookieExt.elements + OPAQUE16_LEN;
ret = TlsCheckCookie(ssl, cookie, len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, the cookie is already parsed and validated, don't re-parse it.
I suggest to refactor the function in something like get_keyshare_from_cookie(cookie, cookie_sz)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by simplifying the logic in the new TLSX_Cookie_RestoreHrrGroup()

src/dtls.c Outdated
e = Dtls13GetEpoch(ssl, ssl->keys.curEpoch64);
if (e != NULL)
XMEMSET(e->window, 0xFF, sizeof(e->window));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here we already know that the ticket is good and we already parsed it in ch.
It's probably better to just extract the keyshare instead of re-parsing the cookie

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, see above.

Copy link
Member

@julek-wolfssl julek-wolfssl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this PR, we don't need the ssl->hrr_keyshare_group variable anymore.

* Move new test to the test_wolfSSL_dtls_stateless_xxx group
* Move cookie parsing to stateful DTLS processing
* Remove unnecessary redundant cookie parsing logic
@Frauschi
Copy link
Contributor Author

Frauschi commented Mar 3, 2026

@julek-wolfssl @rizlik I addressed all your comments.

@Frauschi Frauschi requested review from julek-wolfssl and rizlik March 3, 2026 15:49
Comment on lines +10278 to +10289
#ifdef WOLFSSL_DTLS
/* In case of stateless DTLSv1.3, the ssl->hrr_keyshare_group variable
* may have already been set without further proceeding the handshake,
* so we never received the second ClientHello with the selected group.
* Hence, when we receive another ClientHello message, we do not
* consider that as an error here.
*/
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version) &&
!ssl->options.dtlsStateful) {
return 0;
}
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to error out when ssl->options.dtls because ssl->hrr_keyshare_group should not be set before anyway right? Am I missing an edge case?

* ssl The SSL/TLS object.
* returns 0 on success and other values indicate failure.
*/
static int TLSX_Cookie_RestoreHrrGroup(WOLFSSL* ssl)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be restored in RestartHandshakeHashWithCookie? That will combine the cookie parsing logic in one place.

@julek-wolfssl julek-wolfssl assigned Frauschi and unassigned wolfSSL-Bot Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants