Windows Server 2025: LDAPS, TLS 1.2/1.3 e l’errore 0x51 (LDAPSERVER_DOWN). Come leggere Wireshark e risolvere davvero

Un’app C++ su Windows Server 2025 fallisce l’LDAPS con 0x51 e Wireshark sembra indicare un ClientHello “TLS 1.0”. In realtà il server negozia TLS 1.2/1.3: ecco perché nasce il falso allarme e come risolvere davvero tra certificati, porte, MTU e Schannel.

Indice

Scenario e sintomi

Su Windows Server 2025 Standard (24H2, build 26100) un’applicazione C++ basata sulle API WinLDAP (ldapsslinit + ldapconnect) non riesce a stabilire una connessione LDAPS verso un server LDAP. La chiamata a ldapconnect ritorna 0x51 (LDAPSERVER_DOWN). Con Wireshark, l’autore osserva un ClientHello etichettato come TLS 1.0, nonostante nel Registro i protocolli TLS 1.0/1.1 risultino disattivati e siano attivi TLS 1.2/1.3. La stessa utility, eseguita su Windows 11 contro lo stesso server, completa l’handshake in TLS 1.2 e la sessione LDAPS funziona.

Interpretazioni iniziali e tentativi non risolutivi

PropostaIdea di fondoEsito
Criteri di gruppo → “Disattiva supporto crittografia” (Internet Explorer → Pannello di controllo Internet → Pagina Avanzate) impostato su Abilitata con solo TLS 1.0Forzare/impedire protocolli TLS a livello di WinInet/IENessun cambiamento: Wireshark continua a mostrare ClientHello “TLS 1.0”.
Centro connessioni di rete → Impostazioni avanzateVerificare se TLS 1.0 è spuntato nell’elenco protocolliTLS 1.0 già deselezionato; nessun effetto.
Inviare feedback con strumenti di diagnostica MicrosoftPossibile bug nella pila TLS di Windows Server 2025Suggerito come passo successivo, ma non necessario.

Perché Wireshark “sembra” indicare TLS 1.0 quando in realtà è TLS 1.2/1.3

Il punto chiave è comprendere la differenza tra la versione “legacy” nel record layer e la versione effettivamente negoziata dal protocollo.

  • Nelle implementazioni moderne, il campo Record Layer Version del primo pacchetto può riportare 0x0301 (TLS 1.0) o 0x0303 (TLS 1.2) per compatibilità con middlebox e vecchi dispositivi di rete. Questo valore non determina la versione che sarà negoziata.
  • La versione reale è pubblicizzata nell’estensione Supported Versions del ClientHello. Lì vedrai tipicamente TLS 1.3 (0x0304) e TLS 1.2 (0x0303). Se il server supporta TLS 1.3 o TLS 1.2, la negoziazione avviene a quel livello, indipendentemente da come Wireshark etichetta la riga “Record Layer: TLS 1.0”.
  • Interpretazioni ambigue o release non aggiornate di Wireshark possono enfatizzare la voce “TLS 1.0” nel pannello, generando un false positive.

Morale: Windows Server 2025 non “forza” TLS 1.0 su LDAPS. Se sul sistema TLS 1.0/1.1 sono disattivati (impostazione predefinita in Schannel sulle build recenti), il ClientHello includerà TLS 1.2/1.3 e la negoziazione userà il miglior protocollo comune.

Risoluzione effettiva (TL;DR)

  • Il presunto uso di TLS 1.0 era un falso allarme dovuto alla lettura del campo errato o a un’etichettatura discutibile dello sniffer.
  • Lo 0x51 (LDAPSERVER_DOWN) va ricondotto ad altre cause: porta o hostname errato, catena certificati incompleta o non fidata, firewall/MTU, mismatch SNI, policy di sicurezza, ecc.

Checklist di diagnostica rapida

  1. Conferma versione TLS reale:
    • Abilita i log di Schannel/TLS e verifica gli Event ID 36874/36888.
    • Esegui un test esterno: openssl sclient -connect <host>:636 -servername <FQDN> -tls13 -showcerts e, se necessario, ripeti con -tls1_2. Se l’handshake completa, il server accetta TLS 1.3/1.2.
  2. Porta/servizio corretti:
    • LDAPS: 636/tcp, canale già cifrato.
    • LDAP con STARTTLS: 389/tcp + estensione STARTTLS.
    • Test veloce: Test-NetConnection <host> -Port 636 (PowerShell).
  3. Certificati e trust:
    • Il certificato server deve avere EKU Server Authentication e SAN con l’FQDN usato dal client (SNI/DNS).
    • Importa la catena completa fino a una radice fidata nel Trusted Root Certification Authorities del client.
    • Valida con certutil -verify -urlfetch server_cert.cer.
  4. Firewall/MTU:
    • Un ClientHello ampio può frammentarsi e venire scartato da middlebox: verifica MTU (ping -f -l 1472) e considera il path IPv6.
    • Se necessario, riduci temporaneamente la lista di cipher suite consentite per restringere il ClientHello.
  5. Policy e stack corretti:
    • Le API WinLDAP si appoggiano a Schannel, non a WinInet: le spunte “TLS” nel pannello Internet non governano LDAPS.
    • Controlla i percorsi Registro di Schannel per protocolli abilitati/disabilitati.

Approfondimento: come Windows Server 2025 negozia TLS per LDAPS

In Windows, le API WinLDAP (wldap32.dll) demandano la sicurezza del trasporto al provider Schannel. Da build recenti di Windows Server 2025:

  • TLS 1.0/1.1 sono disattivati per impostazione predefinita a livello di Schannel, salvo override espliciti via Criteri di gruppo o Registro (HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols).
  • TLS 1.2/1.3 sono attivi e usati come predefiniti.

Per verificare/forzare i protocolli consentiti, i percorsi tipici sono:

HKEYLOCALMACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client
  DisabledByDefault = 1 (DWORD)  // disabilitato
  Enabled           = 0 (DWORD)

HKEYLOCALMACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client
DisabledByDefault = 1
Enabled           = 0

HKEYLOCALMACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client
DisabledByDefault = 0
Enabled           = 1

HKEYLOCALMACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client
DisabledByDefault = 0
Enabled           = 1 

Nota: le impostazioni di Internet Explorer/WinInet (Pannello di controllo Internet → Avanzate) non governano le connessioni LDAPS; tali spunte impattano i componenti che usano WinInet o WinHTTP, non wldap32.

Perché il record layer può essere “TLS 1.0”

Il ClientHello moderno incapsula la versione reale nell’estensione Supported Versions. Il record layer può mostrare un valore “legacy” (talvolta 0x0301) per compatibilità. In Wireshark, espandi “Handshake Protocol: Client Hello” e osserva Supported Versions per leggere la realtà.

Cause comuni di LDAPSERVER_DOWN (0x51)

CategoriaCausa tipicaVerifica/Correzione
PorteUso di 389 senza STARTTLS o tentativo su 636 ma servizio non in ascoltoTest-NetConnection host -Port 636. Se usi 389, avvia ldapstarttls_s prima del bind.
DNS/SNIHostname errato o privo di SAN nel certificato; mancato SNIUsa l’FQDN presente nel SAN del certificato; in OpenSSL aggiungi -servername. Con WinLDAP, usa l’FQDN corretto.
TrustCA non fidata o catena incompletaImporta intermedi e radice; verifica con certutil -verify -urlfetch.
Cipher/PolicyServer e client non condividono cipher suite; FIPS mode attivoControlla Get-TlsCipherSuite. Disabilita policy FIPS se non necessaria o allinea le suite.
MTU/MiddleboxFrammentazione del ClientHello e drop da firewall/IPSVerifica MTU e riduci temporaneamente le suite (GPO “TLS Cipher Suite Order”) per restringere il ClientHello.
Cert revocationCRL/OCSP non raggiungibili → fallisce il controllo revocaAbilita accesso verso endpoint CRL/OCSP o disabilita temporaneamente il check a scopo diagnostico.
BindingUso di 389 con bind semplice senza STARTTLS in ambienti che impongono “LDAP signing”Usa LDAPS (636) o negozia STARTTLS prima del bind.

Strumenti utili e comandi

Eventi Schannel/TLS

Attiva i log dettagliati di Schannel per diagnosticare gli handshake:

reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\Schannel" ^
  /v EventLogging /t REG_DWORD /d 7 /f

Controlla il registro eventi: “Applicazioni e servizi → Microsoft → Windows → Schannel/Operational”. In caso di errori, cerca Event ID 36874 (failure di protocollo/cipher) e 36888 (fatal alert).

OpenSSL dal server o da un host di test

# Test TLS 1.3
openssl sclient -connect ldap.example.com:636 -servername ldap.example.com -tls13 -showcerts

Test TLS 1.2

openssl sclient -connect ldap.example.com:636 -servername ldap.example.com -tls12 -showcerts 

PowerShell: cipher suite e porta

# Elenco delle cipher suite abilitate lato client
Get-TlsCipherSuite | Sort-Object Name | Format-Table Name, Protocols, Exchange

Test apertura porta 636

Test-NetConnection ldap.example.com -Port 636 

CertUtil: validare la catena

CertUtil -verify -urlfetch C:\temp\server_cert.cer

Netsh trace per handshaking TCP/TLS

netsh trace start scenario=NetConnection capture=yes report=yes
rem Esegui il test LDAPS
netsh trace stop

Wireshark: leggere correttamente il ClientHello

  • Filtra: tcp.port == 636.
  • Apri il pacchetto con “Handshake Protocol: Client Hello”.
  • Controlla la sezione Supported Versions e non solo la riga del “Record Layer”.
  • Assicurati di usare una versione aggiornata (consigliata ≥ 4.2) per etichette corrette su TLS 1.3.

Guida completa passo‑passo alla correzione

  1. Verifica connessione di base: pinga l’FQDN, esegui Test-NetConnection -Port 636. Se fallisce, priorità a DNS/routing/firewall.
  2. Conferma TLS:
    • OpenSSL: handshake ok con TLS 1.2/1.3? Se sì, la rete e il server LDAPS sono sani.
    • Eventi Schannel: esistono alert di protocollo o cipher incompatibili?
  3. Valida il certificato server:
    • Il SAN deve includere l’FQDN che usi (es. ldap.example.com).
    • EKU: Server Authentication. Catena completa installata e fidata sul client.
  4. Riduci le variabili:
    • Prova con l’utility Ldp.exe (inbox Windows). Se Ldp.exe si connette in LDAPS, il problema è nell’app o nei parametri di bind.
    • Testa sia LDAPS (636) sia LDAP + STARTTLS (389) per isolare differenze di percorso/MTU.
  5. MTU e middlebox:
    • Se il ClientHello è grande (molte cipher suite/estensioni), verifica che non avvenga frammentazione su link con MTU ristretta.
    • Temporaneamente, ordina/riduci le cipher suite via GPO “TLS Cipher Suite Order” per snellire il ClientHello.
  6. Policy di sicurezza:
    • Se è abilitata la policy “Usa algoritmi compatibili FIPS”, alcune suite moderne possono essere escluse.
    • Assicurati che non vi siano override in GPO che riattivano TLS 1.0/1.1 o disabilitano TLS 1.2/1.3.
  7. Riprova dall’app C++ con log dettagliati e controlla l’esito di ldapconnect, ldapget_option per l’ultimo errore e GetLastError() per indizi aggiuntivi.

Esempi di codice C++ (WinLDAP) corretti

LDAPS nativo sulla porta 636

// Compila con: wldap32.lib
#include <windows.h>
#include <winldap.h>
#pragma comment(lib, "wldap32.lib")

int wmain() {
ULONG version = LDAP_VERSION3;
// secure = 1 per LDAPS (canale TLS dal connect)
LDAP* ld = ldap_sslinitW(L"ldap.example.com", 636, 1);
if (!ld) {
wprintf(L"ldap_sslinitW fallita, err=%lu\n", GetLastError());
return 1;
}
```
ULONG rc = ldap_set_optionW(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (rc != LDAP_SUCCESS) {
    wprintf(L"ldap_set_optionW(PROTOCOL_VERSION)=%lu\n", rc);
    ldap_unbind(ld);
    return 1;
}

// Facoltativo: timeout di connessione
timeval tv{10, 0}; // 10 secondi
rc = ldap_connect(ld, &tv);
if (rc != LDAP_SUCCESS) {
    wprintf(L"ldap_connect=%lu (0x%lx)\n", rc, rc);
    ldap_unbind(ld);
    return 1;
}

// A questo punto il canale TLS è stabilito via Schannel.
// Esegui un bind (esempio: simple bind con UPN)
SEC_WINNT_AUTH_IDENTITY_W auth{};
// ...riempi 'auth' se usi SASL/GSSAPI o credenziali esplicite...

// Esempio di simple bind (sconsigliato senza TLS)
rc = ldap_simple_bind_sW(ld, L"user@example.com", L"Password#2025!");
if (rc != LDAP_SUCCESS) {
    wprintf(L"ldap_simple_bind_sW=%lu (0x%lx)\n", rc, rc);
} else {
    wprintf(L"Bind riuscito.\n");
}

ldap_unbind(ld);
return 0;
```
} 

LDAP + STARTTLS sulla porta 389

// Stabilisce una connessione LDAP "in chiaro",
// poi eleva a TLS con STARTTLS prima del bind.
#include <windows.h>
#include <winldap.h>
#pragma comment(lib, "wldap32.lib")

int wmain() {
ULONG version = LDAP_VERSION3;
LDAP* ld = ldap_initW(L"ldap.example.com", 389);
if (!ld) {
wprintf(L"ldap_initW fallita, err=%lu\n", GetLastError());
return 1;
}
```
ULONG rc = ldap_set_optionW(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (rc != LDAP_SUCCESS) {
    wprintf(L"ldap_set_optionW=%lu\n", rc);
    ldap_unbind(ld);
    return 1;
}

// Eleva a TLS prima di ogni bind o query sensibile
rc = ldap_start_tls_sW(ld, nullptr, nullptr, nullptr, nullptr);
if (rc != LDAP_SUCCESS) {
    wprintf(L"ldap_start_tls_sW=%lu (0x%lx)\n", rc, rc);
    ldap_unbind(ld);
    return 1;
}

timeval tv{10, 0};
rc = ldap_connect(ld, &tv);
if (rc != LDAP_SUCCESS) {
    wprintf(L"ldap_connect=%lu (0x%lx)\n", rc, rc);
    ldap_unbind(ld);
    return 1;
}

// Ora il canale è protetto da TLS; puoi eseguire il bind
rc = ldap_simple_bind_sW(ld, L"user@example.com", L"Password#2025!");
if (rc != LDAP_SUCCESS) {
    wprintf(L"ldap_simple_bind_sW=%lu (0x%lx)\n", rc, rc);
} else {
    wprintf(L"Bind riuscito.\n");
}

ldap_unbind(ld);
return 0;
```
} 

Note pratiche per il codice

  • Usa Unicode (ldap_*W) per evitare problemi di encoding.
  • Imposta sempre LDAP_VERSION3: STARTTLS richiede v3, e in generale è best practice.
  • Non esiste un’opzione WinLDAP per “forzare TLS 1.3” per singola connessione: la selezione del protocollo e delle suite è demandata a Schannel (policy di sistema).
  • Per diagnosticare, interroga ldapgetoption con LDAPOPTERRORNUMBER e LDAPOPTERRORSTRING dopo un fallimento.

Confermare “cosa” è stato negoziato davvero

Con Schannel event logging

  • Event ID 36874: traccia di handshake fallito (ad esempio protokoll mismatch o cipher incompatibile). Le descrizioni indicano spesso protocollo e suite attese.
  • Event ID 36888: fatal alert con un codice (es. Handshake Failure), utile per incrociare con il lato server.

Con OpenSSL

L’output di openssl s_client riporta in chiaro protocollo e cipher suite effettiva, ad esempio:

New, TLSv1.3, Cipher is TLSAES256GCMSHA384
Server public key is 2048 bit
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLSAES256GCMSHA384

Ottimizzare il ClientHello (MTU e middlebox ostili)

In alcuni ambienti, la frammentazione dei primi pacchetti TLS viene filtrata. Suggerimenti:

  • Misura l’MTU effettiva end‑to‑end con ping -f -l e allineala sugli hop critici.
  • Riduci temporaneamente le cipher suite abilitate via GPO (TLS Cipher Suite Order) per snellire le estensioni del ClientHello.
  • Preferisci LDAPS su 636 se il path per 389 subisce ispezioni/riscritture più aggressive.

Domande frequenti

Perché su Windows 11 funziona e su Server 2025 no?
Molto spesso il motivo è non il protocollo TLS: sul client Windows 11 la CA potrebbe già essere fidata, la rete meno filtrata o la catena del certificato più accessibile (CRL/OCSP). Allinea trust store, percorsi e policy.

Posso forzare TLS 1.3 per quell’unica app C++?
Con WinLDAP no: il minimo/massimo protocollo è definito a livello di Schannel (sistema). Per test, puoi disattivare temporaneamente TLS 1.2 lato client, ma non è una pratica consigliata in produzione.

Le spunte TLS nel Pannello Internet possono sbloccare LDAPS?
No. Quelle opzioni si applicano ai componenti che usano WinInet/WinHTTP (browser, alcune librerie), non a wldap32.

Serve “LDAP signing” se uso LDAPS?
Con LDAPS (TLS) il canale è già cifrato e autenticato; molte policy che richiedono signing sono soddisfatte. Con LDAP semplice su 389, usa sempre STARTTLS prima del bind.

Best practice per Windows Server 2025 e LDAPS

  • TLS 1.2/1.3 di default: mantieni TLS 1.0/1.1 disattivati; evita override non necessari.
  • Certificati “a prova di futuro”: SAN con FQDN corretti, chiavi ECDSA o RSA ≥ 2048, curve/suite moderne, CRL/OCSP raggiungibili.
  • DNS e SNI allineati: usa sempre l’FQDN che appare nel certificato server.
  • Monitoraggio: abilita e conserva i log Schannel/TLS in fase di migrazione.
  • Toolchain aggiornata: usa Wireshark recente per un parsing accurato di TLS 1.3; aggiorna OpenSSL nei bastioni di test.

Conclusioni

Nel caso esaminato, l’“allarme” su TLS 1.0 era un falso positivo. Windows Server 2025, a parità di policy, negozia TLS 1.2/1.3 su LDAPS come previsto. Quando ldapconnect ritorna 0x51, concentrare la diagnosi su porte, DNS/SNI, catena di certificati, policy/cipher suite e MTU/middlebox porta quasi sempre alla soluzione. Per una verifica oggettiva dei protocolli, affidati a Schannel event logging e a openssl s_client, non alla singola etichetta “TLS 1.0” sul record layer di Wireshark. In breve: non è Windows Server 2025 a forzare TLS 1.0; è l’interpretazione a essere ingannevole.

Appendice: riferimenti operativi concentrati

  • Verifica protocolli reali: Event ID 36874/36888; openssl sclient -tls13/-tls1_2.
  • Stack TLS: WinLDAP usa Schannel; le impostazioni di IE/WinInet non si applicano.
  • Default Server 2025: TLS 1.0/1.1 disattivati, TLS 1.2/1.3 abilitati salvo override (HKLM...\SCHANNEL\Protocols).
  • Diagnosi 0x51: controlla porta, certificati, trust, firewall/MTU, cipher suite, policy FIPS.
  • Strumenti: CertUtil -verify -urlfetch, Get-TlsCipherSuite, Test-NetConnection, Wireshark 4.2+.

In sintesi: l’allarme su TLS 1.0 nasce da una lettura parziale dei pacchetti. Windows Server 2025 aderisce alla policy che privilegia TLS 1.2/1.3 di default. Raddrizza il tiro della diagnostica: certificati, rete, configurazione di Schannel e corretto uso delle API WinLDAP fanno la differenza.

Indice