Skip to content

GnuTLS+Nettle4 NTLM has build-only backend mismatch #21562

@bagder

Description

@bagder

I did this

(the following report comes from Codex Security, copied mostly as-is. Trimmed a little since it is just so much.)

References this commit: 01f08dc by @vszakats which was a follow-up to #21169

Summary

Introduced build-only bug: GnuTLS DES availability was narrowed to HAVE_GNUTLS_DES, but subsequent conditional compilation still keys off USE_GNUTLS. This can break NTLM builds for certain MultiSSL configurations using GnuTLS with Nettle 4+ and another DES-capable backend.
The patch changes the GnuTLS DES include/selection path to require HAVE_GNUTLS_DES, which is only defined for Nettle versions below 4. However, the later NTLM DES implementation branches still test USE_GNUTLS directly. In a build that enables GnuTLS with Nettle 4+ together with another DES-capable fallback backend such as mbedTLS, the initial backend-selection block can choose USE_MBEDTLS_DES, but the implementation blocks will still select the USE_GNUTLS branches and reference struct des_ctx, des_set_key, and des_encrypt even though nettle/des.h was not included. This is a compile-time backend-selection mismatch, not a runtime memory-safety or authentication vulnerability.

Validation

Report

Validated the finding as a deterministic build-only bug. Code review of /workspace/curl/lib/curl_ntlm_core.c shows the commit added HAVE_GNUTLS_DES only when USE_GNUTLS and NETTLE_VERSION_MAJOR < 4 at lines 52-57, and the top DES backend selection falls through to mbedTLS at lines 73-82 when Nettle 4+ is used. However, later implementation branches still use #elif defined(USE_GNUTLS) at lines 185, 324, and 377, causing the GnuTLS/Nettle DES code to compile even though nettle/des.h was not included and mbedTLS DES was selected. I created /workspace/ntlm_des_poc with curl_ntlm_core.c copied byte-for-byte from the repository (matching sha256 ac675eb2833007eea832220487f977dfde9f131845cd53df1f9edd8c28b0fd44) and fake headers modeling USE_GNUTLS + NETTLE_VERSION_MAJOR 4 + USE_MBEDTLS + HAVE_MBEDTLS_DES_CRYPT_ECB. Preprocessing showed: #define USE_GNUTLS 1, #define USE_MBEDTLS 1, #define USE_MBEDTLS_DES, #define NETTLE_VERSION_MAJOR 4, and no HAVE_GNUTLS_DES. Compiling the original source with ./build_original.sh fails with undefined/incomplete GnuTLS DES symbols: struct des_ctx, curl_des_set_odd_parity, des_set_key, and des_encrypt. As a control, curl_ntlm_core_fixed.c changes only the later USE_GNUTLS implementation guards to HAVE_GNUTLS_DES; ./build_fixed.sh exits 0 under the same fake MultiSSL/Nettle4/mbedTLS configuration. Runtime crash, valgrind, and debugger validation were attempted but are not applicable because the original source does not compile into an executable; valgrind is unavailable in the container and lldb cannot trace a compile-time failure. This confirms the suspected backend-selection mismatch and confirms it is not a runtime security vulnerability.

Evidence

lib/curl_ntlm_core.c (L185 to 198)
Note: The setup_des_key implementation still selects the GnuTLS DES path based on USE_GNUTLS rather than HAVE_GNUTLS_DES, causing references to Nettle DES types/functions even when GnuTLS DES was disabled.

#elif defined(USE_GNUTLS)
static void setup_des_key(const unsigned char *key_56, struct des_ctx *des)
{
  char key[8];

  /* Expand the 56-bit key to 64 bits */
  extend_key_56_to_64(key_56, key);

  /* Set the key parity to odd */
  curl_des_set_odd_parity((unsigned char *)key, sizeof(key));

  /* Set the key */
  des_set_key(des, (const uint8_t *)key);
}

lib/curl_ntlm_core.c (L324 to 331)
Note: The NTLM LM response path still selects GnuTLS DES using USE_GNUTLS, which is inconsistent with the new HAVE_GNUTLS_DES availability check.

#elif defined(USE_GNUTLS)
  struct des_ctx des;
  setup_des_key(keys, &des);
  des_encrypt(&des, 8, results, plaintext);
  setup_des_key(keys + 7, &des);
  des_encrypt(&des, 8, results + 8, plaintext);
  setup_des_key(keys + 14, &des);
  des_encrypt(&des, 8, results + 16, plaintext);

lib/curl_ntlm_core.c (L377 to 382)
Note: The LAN Manager hash path similarly uses USE_GNUTLS instead of HAVE_GNUTLS_DES, completing the same backend mismatch.

#elif defined(USE_GNUTLS)
    struct des_ctx des;
    setup_des_key(pw, &des);
    des_encrypt(&des, 8, lmbuffer, magic);
    setup_des_key(pw + 7, &des);
    des_encrypt(&des, 8, lmbuffer + 8, magic);

lib/curl_ntlm_core.c (L52 to 90)
Note: The patch defines HAVE_GNUTLS_DES only for Nettle versions below 4 and uses it to decide whether nettle/des.h is included. With Nettle 4+, this block may fall through to another DES backend such as mbedTLS.

#ifdef USE_GNUTLS
#include <nettle/version.h>
#if NETTLE_VERSION_MAJOR < 4
#define HAVE_GNUTLS_DES
#endif
#endif

#if defined(USE_OPENSSL) && defined(HAVE_DES_ECB_ENCRYPT)

#  include <openssl/des.h>
#  ifdef OPENSSL_IS_AWSLC  /* for versions 1.2.0 to 1.30.1 */
#    define DES_set_key_unchecked (void)DES_set_key
#  endif
#  define USE_OPENSSL_DES

#elif defined(USE_WOLFSSL) && defined(HAVE_WC_DES_ECBENCRYPT)

#  include <wolfssl/options.h>
#  include <wolfssl/wolfcrypt/des3.h>
#  define USE_WOLFSSL_DES

#elif defined(HAVE_GNUTLS_DES)
#  include <nettle/des.h>
#  define USE_CURL_DES_SET_ODD_PARITY
#elif defined(USE_MBEDTLS) && defined(HAVE_MBEDTLS_DES_CRYPT_ECB)
#  include <mbedtls/version.h>
#  if MBEDTLS_VERSION_NUMBER < 0x03020000
#  error "mbedTLS 3.2.0 or later required"
#  endif
#  include <mbedtls/des.h>
#  define USE_MBEDTLS_DES
#elif defined(USE_OS400CRYPTO)
#  include "cipher.mih"  /* mih/cipher */
#  define USE_CURL_DES_SET_ODD_PARITY
#elif defined(USE_WIN32_CRYPTO)
#  include <wincrypt.h>
#  define USE_CURL_DES_SET_ODD_PARITY
#else
#  error "cannot compile NTLM support without a crypto library with DES."

I expected the following

No response

curl/libcurl version

git master

operating system

any

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions