From 59b0cf185ea13e9f79c0978ebe4d6f67567467f6 Mon Sep 17 00:00:00 2001 From: Frank Mertens Date: Thu, 8 Jan 2026 23:07:38 +0100 Subject: [PATCH] Fix: support empty PSK key hint in Client Key Exchange message According to RFC 4279 the psk_identity_hint can be of length 0. This patch enables the TLS 1.2 server to accept such empty hints during TLS 1.2 handshake. The restriction on >0 identity length is also removed on the client side. Signed-off-by: Frank Mertens --- ChangeLog.d/fix-psk-identity-hint-empty.txt | 6 ++++ include/mbedtls/ssl.h | 35 ++++++++++++--------- library/ssl_tls.c | 9 +++--- library/ssl_tls12_server.c | 2 +- tests/ssl-opt.sh | 8 +++++ 5 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 ChangeLog.d/fix-psk-identity-hint-empty.txt diff --git a/ChangeLog.d/fix-psk-identity-hint-empty.txt b/ChangeLog.d/fix-psk-identity-hint-empty.txt new file mode 100644 index 0000000000..42db4190af --- /dev/null +++ b/ChangeLog.d/fix-psk-identity-hint-empty.txt @@ -0,0 +1,6 @@ +Bugfix + * Make the TLS 1.2 server to not reject a Client Key Exchange message which + has a zero-length PSK identity hint (as allowed by RFC 4279). TLS clients + usually pass an empty PSK identity hint when the server accepts only a + single pre-shared key. This fix only affects TLS 1.2 servers using PSK + based ciphersuites. diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 3cdddf7d72..4e80898269 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -3830,11 +3830,21 @@ int mbedtls_ssl_set_hs_psk_opaque(mbedtls_ssl_context *ssl, /** * \brief Set the PSK callback (server-side only). * - * If set, the PSK callback is called for each - * handshake where a PSK-based ciphersuite was negotiated. - * The caller provides the identity received and wants to - * receive the actual PSK data and length. + * If set, the PSK callback is called for each + * handshake where a PSK-based ciphersuite was negotiated. + * The caller provides the identity received and wants to + * receive the actual PSK data and length. * + * If a valid PSK identity is found, the callback should use + * \c mbedtls_ssl_set_hs_psk() or + * \c mbedtls_ssl_set_hs_psk_opaque() + * on the SSL context to set the correct PSK and return \c 0. + * Any other return value will result in a denied PSK identity. + * + * \param conf The SSL configuration to register the callback with. + * + * \param f_psk The callback for selecting and setting the PSK based + * in the PSK identity chosen by the client. * The callback has the following parameters: * - \c void*: The opaque pointer \p p_psk. * - \c mbedtls_ssl_context*: The SSL context to which @@ -3844,11 +3854,8 @@ int mbedtls_ssl_set_hs_psk_opaque(mbedtls_ssl_context *ssl, * - \c size_t: The length of the PSK identity * selected by the client. * - * If a valid PSK identity is found, the callback should use - * \c mbedtls_ssl_set_hs_psk() or - * \c mbedtls_ssl_set_hs_psk_opaque() - * on the SSL context to set the correct PSK and return \c 0. - * Any other return value will result in a denied PSK identity. + * \param p_psk A pointer to an opaque structure to be passed to + * the callback, for example a PSK store. * * \note A dynamic PSK (i.e. set by the PSK callback) takes * precedence over a static PSK (i.e. set by @@ -3859,11 +3866,11 @@ int mbedtls_ssl_set_hs_psk_opaque(mbedtls_ssl_context *ssl, * \c mbedtls_ssl_conf_psk() or * \c mbedtls_ssl_conf_psk_opaque()). * - * \param conf The SSL configuration to register the callback with. - * \param f_psk The callback for selecting and setting the PSK based - * in the PSK identity chosen by the client. - * \param p_psk A pointer to an opaque structure to be passed to - * the callback, for example a PSK store. + * \warning If an empty PSK key identity is provided by the client the + * \p f_psk callback is invoked with the length parameter set + * to zero. It is up to the server to set the default PSK or to + * reject the request in this case. + * */ void mbedtls_ssl_conf_psk_cb(mbedtls_ssl_config *conf, int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 30cde27923..3ba1230a0e 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2161,14 +2161,16 @@ static int ssl_conf_set_psk_identity(mbedtls_ssl_config *conf, size_t psk_identity_len) { /* Identity len will be encoded on two bytes */ - if (psk_identity == NULL || - psk_identity_len == 0 || + if (psk_identity == NULL || (psk_identity_len >> 16) != 0 || psk_identity_len > MBEDTLS_SSL_OUT_CONTENT_LEN) { return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; } conf->psk_identity = mbedtls_calloc(1, psk_identity_len); + if (conf->psk_identity == NULL && psk_identity_len == 0) { + conf->psk_identity = mbedtls_calloc(1, 1); + } if (conf->psk_identity == NULL) { return MBEDTLS_ERR_SSL_ALLOC_FAILED; } @@ -2194,9 +2196,6 @@ int mbedtls_ssl_conf_psk(mbedtls_ssl_config *conf, if (psk == NULL) { return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; } - if (psk_len == 0) { - return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; - } if (psk_len > MBEDTLS_PSK_MAX_LEN) { return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; } diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index acf4bfb07b..267bed13c1 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -3607,7 +3607,7 @@ static int ssl_parse_client_psk_identity(mbedtls_ssl_context *ssl, unsigned char n = MBEDTLS_GET_UINT16_BE(*p, 0); *p += 2; - if (n == 0 || n > end - *p) { + if (n > end - *p) { MBEDTLS_SSL_DEBUG_MSG(1, ("bad client key exchange message")); return MBEDTLS_ERR_SSL_DECODE_ERROR; } diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index ad87605d4e..e28a8dfc9a 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -9635,6 +9635,14 @@ run_test "PSK callback: wrong key" \ -S "SSL - Unknown identity received" \ -s "SSL - Verification of the message MAC failed" +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 +run_test "PSK callback: empty identity hint" \ + "$P_SRV psk=73776f726466697368 psk_identity=''" \ + "$P_CLI psk=73776f726466697368 force_version=tls12 psk_identity=''" \ + 0 \ + -s "Successful connection" \ + -c "Successful connection" + # Tests for EC J-PAKE requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED