Skip to content

LDAP server-side STARTTLS support (RFC 2830)#1

Open
steffen-heil-secforge wants to merge 3 commits into
masterfrom
ldap-server-starttls
Open

LDAP server-side STARTTLS support (RFC 2830)#1
steffen-heil-secforge wants to merge 3 commits into
masterfrom
ldap-server-starttls

Conversation

@steffen-heil-secforge
Copy link
Copy Markdown
Member

Summary

stunnel's protocol = ldap option previously only handled the client side — connecting to an LDAP backend and sending a StartTLS ExtendedRequest. This PR adds the missing server-side counterpart, enabling stunnel to act as a TLS termination proxy for legacy LDAP clients that negotiate TLS via STARTTLS rather than connecting directly on the LDAPS port.

  • ldap_server_init: sets connect_before_ssl=1 so the backend TCP connection is established before the TLS handshake with the client
  • ldap_server_middle: reads and validates the incoming StartTLS ExtendedRequest (APPLICATION 23 / OID 1.3.6.1.4.1.1466.20037), then sends a well-formed StartTLS ExtendedResponse (APPLICATION 24, resultCode=success) with the matching messageID
  • WinLDAP-style four-byte length encoding is handled, matching the existing client-side behaviour
  • Both functions are registered under the existing ldap name in the PROTOCOL dispatch table — protocol = ldap now works symmetrically for client and server services

Tests

  • Test 281 (p28_ldap_starttls.py): Python test harness performs the RFC 2830 exchange directly against a stunnel server, then upgrades to TLS via asyncio.loop.start_tls(), exercising ldap_server_middle in isolation
  • Test 282: full client→server proxy chain with both stunnel instances using protocol = ldap, exercising ldap_client_middle and ldap_server_middle together end-to-end
  • Live integration test (ldap_starttls_live_test.sh): optional Docker-based test against a real OpenLDAP server (requires Docker, ldapsearch, openssl — not part of make check)

Deployment topology enabled

LDAP client (STARTTLS)  →  stunnel server (protocol=ldap)  →  plain LDAP backend

steffen-heil-secforge and others added 3 commits May 13, 2026 16:33
stunnel's ldap protocol helper only handled the client side (sending a
StartTLS ExtendedRequest to the backend). This adds server-side support
so stunnel can accept plain LDAP connections from legacy clients that
send a StartTLS request, perform the TLS upgrade with the client, and
forward to a backend that also speaks STARTTLS.

New functions:
- ldap_server_init: sets connect_before_ssl=1 so the backend TCP
  connection is established before the TLS handshake with the client
- ldap_server_middle: reads and validates the incoming STARTTLS
  ExtendedRequest (APPLICATION 23 / OID 1.3.6.1.4.1.1466.20037),
  then sends a success ExtendedResponse with the matching messageID

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add p28_ldap_starttls.py to the standard test suite (make check):

- Test 281: the Python test harness performs the RFC 2830 StartTLS
  exchange directly (sends ExtendedRequest, validates ExtendedResponse,
  upgrades to TLS via asyncio loop.start_tls()) against a stunnel server
  configured with protocol=ldap, exercising ldap_server_middle in
  isolation.

- Test 282: a full client→server proxy chain where both stunnel
  instances run with protocol=ldap, exercising ldap_client_middle and
  ldap_server_middle together.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ldap_starttls_live_test.sh runs against a real OpenLDAP server
(osixia/openldap) in Docker. It tests:

  Test A: ldapsearch (STARTTLS) -> stunnel server (protocol=ldap) -> slapd
    A.1: anonymous STARTTLS rootDSE query
    A.2: authenticated STARTTLS search (-ZZ)
    A.3: plain LDAP rejected (stunnel requires STARTTLS)

  Test B: full client+server proxy chain
    B.1: plain ldapsearch through client->server proxy chain
    B.2: ldapadd + ldapsearch through proxy chain

Requires Docker, ldapsearch/ldapadd, and openssl. Not part of make check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant