This commit is contained in:
Matthew John Cheetham 2026-04-14 14:15:54 +00:00 committed by GitHub
commit 8917c9566b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 373 additions and 26 deletions

View file

@ -95,8 +95,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
CredHandle credentials;
CtxtHandle context;
PSecPkgInfo SecurityPackage;
SEC_WINNT_AUTH_IDENTITY identity;
SEC_WINNT_AUTH_IDENTITY *p_identity;
SEC_WINNT_AUTH_IDENTITY_EX identity;
SEC_WINNT_AUTH_IDENTITY_EX *p_identity;
SecBuffer chlg_buf;
SecBuffer resp_buf;
SecBufferDesc chlg_desc;
@ -240,7 +240,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
* Returns CURLE_OK on success.
*/
CURLcode Curl_override_sspi_http_realm(const char *chlg,
SEC_WINNT_AUTH_IDENTITY *identity)
SEC_WINNT_AUTH_IDENTITY_EX *identity)
{
xcharp_u domain, dup_domain;
@ -466,8 +466,8 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
if(!digest->http_context) {
CredHandle credentials;
SEC_WINNT_AUTH_IDENTITY identity;
SEC_WINNT_AUTH_IDENTITY *p_identity;
SEC_WINNT_AUTH_IDENTITY_EX identity;
SEC_WINNT_AUTH_IDENTITY_EX *p_identity;
SecBuffer resp_buf;
SecBufferDesc resp_desc;
unsigned long attrs;

View file

@ -138,7 +138,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
&input_token,
&output_token,
mutual_auth,
NULL);
NULL,
GSS_C_NO_CREDENTIAL);
if(GSS_ERROR(major_status)) {
if(output_token.value)

View file

@ -37,6 +37,7 @@
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
/*
* Curl_auth_is_spnego_supported()
*
@ -158,6 +159,54 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
}
#endif
#ifdef HAVE_GSS_SET_NEG_MECHS
#ifdef CURL_DISABLE_NEGOTIATE_NTLM
/* Acquire explicit credentials and restrict SPNEGO sub-mechanisms to
* exclude NTLM. We enumerate all available mechanisms and filter out
* the NTLMSSP OID, matching SSPI's "!ntlm". */
if(nego->cred == GSS_C_NO_CREDENTIAL) {
/* OID 1.3.6.1.4.1.311.2.2.10 (NTLMSSP) */
static const gss_OID_desc ntlmssp_oid = {
10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")
};
gss_OID_set available_mechs = GSS_C_NO_OID_SET;
gss_OID_set filtered_mechs = GSS_C_NO_OID_SET;
/* Acquire default credentials for SPNEGO */
major_status = gss_acquire_cred(&minor_status, GSS_C_NO_NAME,
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
GSS_C_INITIATE, &nego->cred, NULL, NULL);
if(GSS_ERROR(major_status)) {
Curl_gss_log_error(data, "gss_acquire_cred() failed: ",
major_status, minor_status);
Curl_safefree(input_token.value);
return CURLE_AUTH_ERROR;
}
/* Get all available mechanisms */
major_status = gss_indicate_mechs(&minor_status, &available_mechs);
if(!GSS_ERROR(major_status)) {
/* Build a set excluding NTLMSSP */
major_status = gss_create_empty_oid_set(&minor_status, &filtered_mechs);
if(!GSS_ERROR(major_status)) {
size_t i;
for(i = 0; i < available_mechs->count; i++) {
gss_OID oid = &available_mechs->elements[i];
if(oid->length != ntlmssp_oid.length ||
memcmp(oid->elements, ntlmssp_oid.elements, oid->length)) {
gss_add_oid_set_member(&minor_status, oid, &filtered_mechs);
}
}
/* Restrict SPNEGO to only use non-NTLM mechanisms */
gss_set_neg_mechs(&minor_status, nego->cred, filtered_mechs);
gss_release_oid_set(&minor_status, &filtered_mechs);
}
gss_release_oid_set(&minor_status, &available_mechs);
}
}
#endif /* CURL_DISABLE_NEGOTIATE_NTLM */
#endif /* HAVE_GSS_SET_NEG_MECHS */
/* Generate our challenge-response message */
major_status = Curl_gss_init_sec_context(data,
&minor_status,
@ -168,7 +217,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
&input_token,
&output_token,
TRUE,
NULL);
NULL,
nego->cred);
/* Free the decoded challenge as it is not required anymore */
curlx_safefree(input_token.value);
@ -191,6 +241,31 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
return CURLE_AUTH_ERROR;
}
/* Check if NTLM was selected and is disallowed */
#ifdef CURL_DISABLE_NEGOTIATE_NTLM
if(nego->context != GSS_C_NO_CONTEXT) {
/* OID 1.3.6.1.4.1.311.2.2.10 (NTLMSSP) */
static const gss_OID_desc ntlmssp_oid = {
10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")
};
OM_uint32 inquire_major, inquire_minor;
gss_OID mech_type = GSS_C_NO_OID;
inquire_major = Curl_gss_inquire_context(&inquire_minor,
nego->context,
&mech_type);
if(!GSS_ERROR(inquire_major) && mech_type &&
mech_type->length == ntlmssp_oid.length &&
!memcmp(mech_type->elements, ntlmssp_oid.elements,
ntlmssp_oid.length)) {
infof(data, "SPNEGO chose NTLM, but NTLM is not allowed");
gss_release_buffer(&unused_status, &output_token);
Curl_auth_cleanup_spnego(nego);
return CURLE_AUTH_ERROR;
}
}
#endif /* CURL_DISABLE_NEGOTIATE_NTLM */
/* Free previous token */
if(nego->output_token.length && nego->output_token.value)
gss_release_buffer(&unused_status, &nego->output_token);
@ -280,6 +355,12 @@ void Curl_auth_cleanup_spnego(struct negotiatedata *nego)
nego->spn = GSS_C_NO_NAME;
}
/* Free our credentials */
if(nego->cred != GSS_C_NO_CREDENTIAL) {
gss_release_cred(&minor_status, &nego->cred);
nego->cred = GSS_C_NO_CREDENTIAL;
}
/* Reset any variables */
nego->status = 0;
nego->noauthpersist = FALSE;

View file

@ -146,6 +146,29 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
/* Use the current Windows user */
nego->p_identity = NULL;
#ifdef CURL_DISABLE_NEGOTIATE_NTLM
/* Exclude NTLM from SPNEGO negotiation via the PackageList field */
if(!nego->p_identity) {
memset(&nego->identity, 0, sizeof(nego->identity));
nego->identity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
nego->identity.Length = sizeof(nego->identity);
nego->identity.Flags =
#ifdef UNICODE
SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif
nego->p_identity = &nego->identity;
}
/* Use the special name "!ntlm" to prevent NTLM from being used:
* https://learn.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-sec_winnt_auth_identity_exa
*/
nego->identity.PackageList =
(unsigned TCHAR *)CURL_UNCONST(TEXT("!ntlm"));
nego->identity.PackageListLength = 5;
#endif /* CURL_DISABLE_NEGOTIATE_NTLM */
/* Allocate our credentials handle */
nego->credentials = curlx_calloc(1, sizeof(CredHandle));
if(!nego->credentials)

View file

@ -170,8 +170,8 @@ struct ntlmdata {
#endif
CredHandle *credentials;
CtxtHandle *context;
SEC_WINNT_AUTH_IDENTITY identity;
SEC_WINNT_AUTH_IDENTITY *p_identity;
SEC_WINNT_AUTH_IDENTITY_EX identity;
SEC_WINNT_AUTH_IDENTITY_EX *p_identity;
size_t token_max;
BYTE *output_token;
BYTE *input_token;
@ -241,8 +241,8 @@ struct kerberos5data {
CredHandle *credentials;
CtxtHandle *context;
TCHAR *spn;
SEC_WINNT_AUTH_IDENTITY identity;
SEC_WINNT_AUTH_IDENTITY *p_identity;
SEC_WINNT_AUTH_IDENTITY_EX identity;
SEC_WINNT_AUTH_IDENTITY_EX *p_identity;
size_t token_max;
BYTE *output_token;
#else
@ -297,6 +297,7 @@ struct negotiatedata {
OM_uint32 status;
gss_ctx_id_t context;
gss_name_t spn;
gss_cred_id_t cred;
gss_buffer_desc output_token;
#ifdef GSS_C_CHANNEL_BOUND_FLAG
struct dynbuf channel_binding_data;
@ -309,8 +310,8 @@ struct negotiatedata {
SECURITY_STATUS status;
CredHandle *credentials;
CtxtHandle *context;
SEC_WINNT_AUTH_IDENTITY identity;
SEC_WINNT_AUTH_IDENTITY *p_identity;
SEC_WINNT_AUTH_IDENTITY_EX identity;
SEC_WINNT_AUTH_IDENTITY_EX *p_identity;
TCHAR *spn;
size_t token_max;
BYTE *output_token;