LDAP server-side STARTTLS support (RFC 2830)#1
Open
steffen-heil-secforge wants to merge 3 commits into
Open
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
stunnel's
protocol = ldapoption 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: setsconnect_before_ssl=1so the backend TCP connection is established before the TLS handshake with the clientldap_server_middle: reads and validates the incoming StartTLS ExtendedRequest (APPLICATION 23 / OID1.3.6.1.4.1.1466.20037), then sends a well-formed StartTLS ExtendedResponse (APPLICATION 24, resultCode=success) with the matching messageIDldapname in the PROTOCOL dispatch table —protocol = ldapnow works symmetrically for client and server servicesTests
p28_ldap_starttls.py): Python test harness performs the RFC 2830 exchange directly against a stunnel server, then upgrades to TLS viaasyncio.loop.start_tls(), exercisingldap_server_middlein isolationprotocol = ldap, exercisingldap_client_middleandldap_server_middletogether end-to-endldap_starttls_live_test.sh): optional Docker-based test against a real OpenLDAP server (requires Docker, ldapsearch, openssl — not part ofmake check)Deployment topology enabled