Fix handling of max_fragment_length extension for PSK

A psk session was assumed to be a resumption which failed a check
when parsing the max_fragment_length extension hello from the client.

Relevant code from PR#18130 which was a suggested fix to the issue
was cherry-picked.

Fixes #18121

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24513)
This commit is contained in:
Frederik Wedel-Heinen 2024-05-28 13:59:44 +02:00 committed by Tomas Mraz
parent 6a3579e190
commit fa49560451
5 changed files with 25 additions and 21 deletions

View File

@ -231,6 +231,8 @@ extern "C" {
# define TLSEXT_max_fragment_length_1024 2
# define TLSEXT_max_fragment_length_2048 3
# define TLSEXT_max_fragment_length_4096 4
/* OpenSSL value for unset maximum fragment length extension */
# define TLSEXT_max_fragment_length_UNSPECIFIED 255
/*
* TLS Certificate Type (for RFC7250)

View File

@ -109,6 +109,7 @@ SSL_SESSION *SSL_SESSION_new(void)
if (ss == NULL)
return NULL;
ss->ext.max_fragment_len_mode = TLSEXT_max_fragment_length_UNSPECIFIED;
ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */
/* 5 minute timeout by default */
ss->timeout = ossl_seconds2time(60 * 5 + 4);

View File

@ -1741,15 +1741,9 @@ static int final_early_data(SSL_CONNECTION *s, unsigned int context, int sent)
static int final_maxfragmentlen(SSL_CONNECTION *s, unsigned int context,
int sent)
{
/*
* Session resumption on server-side with MFL extension active
* BUT MFL extension packet was not resent (i.e. sent == 0)
*/
if (s->server && s->hit && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)
&& !sent ) {
SSLfatal(s, SSL_AD_MISSING_EXTENSION, SSL_R_BAD_EXTENSION);
return 0;
}
/* MaxFragmentLength defaults to disabled */
if (s->session->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_UNSPECIFIED)
s->session->ext.max_fragment_len_mode = TLSEXT_max_fragment_length_DISABLED;
if (s->session && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)) {
s->rlayer.rrlmethod->set_max_frag_len(s->rlayer.rrl,

View File

@ -192,21 +192,26 @@ int tls_parse_ctos_maxfragmentlen(SSL_CONNECTION *s, PACKET *pkt,
}
/*
* When doing a full handshake or a renegotiation max_fragment_len_mode will
* be TLSEXT_max_fragment_length_UNSPECIFIED
*
* In case of a resumption max_fragment_len_mode will be one of
* TLSEXT_max_fragment_length_DISABLED, TLSEXT_max_fragment_length_512,
* TLSEXT_max_fragment_length_1024, TLSEXT_max_fragment_length_2048.
* TLSEXT_max_fragment_length_4096
*
* RFC 6066: The negotiated length applies for the duration of the session
* including session resumptions.
* We should receive the same code as in resumed session !
*
* So we only set the value in case it is unspecified.
*/
if (s->hit && s->session->ext.max_fragment_len_mode != value) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH);
return 0;
}
if (s->session->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_UNSPECIFIED)
/*
* Store it in session, so it'll become binding for us
* and we'll include it in a next Server Hello.
*/
s->session->ext.max_fragment_len_mode = value;
return 1;
}

View File

@ -3930,6 +3930,8 @@ int SSL_set_tlsext_max_fragment_length(SSL *ssl, uint8_t mode)
uint8_t SSL_SESSION_get_max_fragment_length(const SSL_SESSION *session)
{
if (session->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_UNSPECIFIED)
return TLSEXT_max_fragment_length_DISABLED;
return session->ext.max_fragment_len_mode;
}