Fix cipher property NIDs for SSL_get_current_cipher and add PSK kx mapping

The cipher property helpers (SSL_CIPHER_get_kx_nid / get_auth_nid /
get_cipher_nid / get_digest_nid / is_aead) parse the cipher name looked
up via cipher->offset in GetCipherSegment(). That offset is only
populated when the cipher is obtained through wolfSSL_get_ciphers_compat()
(SSL_get_ciphers()). When the cipher comes from SSL_get_current_cipher(),
offset is left at 0, so these helpers parsed cipher_names[0] (a TLS 1.3
suite) instead of the negotiated cipher - e.g. returning NID_kx_any for a
plain PSK suite while SSL_CIPHER_get_name() (which uses the suite bytes)
reported the correct name.

Resolve the cipher_names entry from the always-populated suite bytes in
GetCipherSegment(), falling back to cipher->offset when no match is found.

Also add the missing plain "PSK" -> NID_kx_psk entry to the kx lookup
table so PSK suites report NID_kx_psk instead of NID_undef.

Add a regression test that drives the SSL_get_current_cipher() path for
TLS_PSK_WITH_AES_128_GCM_SHA256 and checks all five property helpers.
This commit is contained in:
Juliusz Sosinowicz
2026-06-08 18:12:05 +00:00
parent 8fca95ce65
commit 94bed7e7c2
3 changed files with 71 additions and 0 deletions
+23
View File
@@ -28749,6 +28749,29 @@ const char* GetCipherSegment(const WOLFSSL_CIPHER* cipher, char n[][MAX_SEGMENT_
offset = cipher->offset;
/* The offset field is only populated when the cipher is obtained through
* wolfSSL_get_ciphers_compat() (e.g. SSL_get_ciphers()). When the cipher
* comes from wolfSSL_get_current_cipher() the offset is left at its default
* value of 0, which would make the parsing below operate on
* cipher_names[0] (a TLS 1.3 suite) rather than on the actual cipher. The
* suite bytes are always populated, so resolve the offset from them. */
{
int idx;
int namesSz = GetCipherNamesSize();
for (idx = 0; idx < namesSz; idx++) {
if (cipher_names[idx].cipherSuite0 == cipher->cipherSuite0 &&
cipher_names[idx].cipherSuite == cipher->cipherSuite
#ifndef NO_CIPHER_SUITE_ALIASES
&& (!(cipher_names[idx].flags &
WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS))
#endif
) {
offset = (unsigned long)idx;
break;
}
}
}
if (offset >= (unsigned long)GetCipherNamesSize())
return NULL;
+1
View File
@@ -11321,6 +11321,7 @@ int wolfSSL_CIPHER_get_kx_nid(const WOLFSSL_CIPHER* cipher)
{"RSAPSK", WC_NID_kx_rsa_psk},
{"SRP", WC_NID_kx_srp},
{"EDH", WC_NID_kx_dhe},
{"PSK", WC_NID_kx_psk},
{"RSA", WC_NID_kx_rsa},
{NULL, WC_NID_undef}
};
+47
View File
@@ -28172,6 +28172,52 @@ static int test_SSL_CIPHER_get_xxx(void)
return EXPECT_RESULT();
}
/* Regression test: the cipher property helpers (kx/auth/cipher/digest/aead)
* must report the actual negotiated cipher when it is obtained through
* SSL_get_current_cipher(). That path does not populate cipher->offset, so a
* previous bug caused these helpers to parse cipher_names[0] (a TLS 1.3 suite)
* instead, e.g. returning NID_kx_any for a plain PSK suite. */
static int test_SSL_CIPHER_get_current_kx(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_TLS) && \
defined(BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256)
SSL_CTX* ctx = NULL;
SSL* ssl = NULL;
const SSL_CIPHER* cipher = NULL;
#ifndef NO_WOLFSSL_CLIENT
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#else
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#endif
ExpectNotNull(ssl = SSL_new(ctx));
/* Simulate a negotiated plain-PSK cipher suite without doing a full
* handshake. SSL_get_current_cipher() reports the suite from these
* fields, and leaves cipher->offset at its default value of 0. */
if (ssl != NULL) {
ssl->options.cipherSuite0 = CIPHER_BYTE; /* 0x00 */
ssl->options.cipherSuite = TLS_PSK_WITH_AES_128_GCM_SHA256;
}
ExpectNotNull(cipher = SSL_get_current_cipher(ssl));
/* Name is resolved from the suite bytes and was already correct. */
ExpectStrEQ(SSL_CIPHER_get_name(cipher), "TLS_PSK_WITH_AES_128_GCM_SHA256");
/* These were wrong before the fix (read cipher_names[0]). */
ExpectIntEQ(wolfSSL_CIPHER_get_kx_nid(cipher), NID_kx_psk);
ExpectIntEQ(wolfSSL_CIPHER_get_auth_nid(cipher), NID_auth_psk);
ExpectIntEQ(wolfSSL_CIPHER_get_cipher_nid(cipher), NID_aes_128_gcm);
ExpectIntEQ(wolfSSL_CIPHER_get_digest_nid(cipher), NID_sha256);
ExpectIntEQ(wolfSSL_CIPHER_is_aead(cipher), 1);
SSL_free(ssl);
SSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
(!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \
!defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA))
@@ -34955,6 +35001,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_get_peer_finished_overrun),
#endif
TEST_DECL(test_SSL_CIPHER_get_xxx),
TEST_DECL(test_SSL_CIPHER_get_current_kx),
TEST_DECL(test_wolfSSL_ERR_strings),
TEST_DECL(test_wolfSSL_CTX_set_cipher_list_bytes),
TEST_DECL(test_wolfSSL_set_cipher_list_tls12_keeps_tls13),