Forum Discussion

kevin_flynn_180's avatar
kevin_flynn_180
Icon for Nimbostratus rankNimbostratus
Feb 25, 2016

LDAP/LDAPS for port 389

Hey guys, I have a requirement where some new linux flavors are using 389 securely (ldaps).

 

Because of this, I have tried a few different ideas that have denigrated to:

 

when CLIENT_ACCEPTED { if { [PROFILE::exists clientssl] == 1 } { SSL::profile ldap-test.ssl.profile } }

 

I had a different idea previously, but that was a long time ago and can't find that code.

 

Essentially, I am just trying to test if a connection is coming in secure, if so, go secure.

 

Any thoughts would be appreciated.

 

Thanks

 

2 Replies

  • Hi Kevin,

     

    are you talking about traditional LDAP:389 / LDAPS:636 (but mistakenly used on :389) or LDAP:389 by using the STARTTLS extension?

     

    What should be the outcome of the iRule? Why do you need to MitM the encryption layer?

     

    Cheers, Kai

     

  • Hi Steve,

    found some spare time today to code the mentioned LDAP:386-STARTTLS to LDAPS:636 Proxy iRule.

    The currently implemented functionality will respond to LDAP-STARTTLS request on behalf of the LDAP server and then change the pool in the background to become LDAPS. On this way you could point your Linux client to a non-STARTTLS aware LDAP instance and still use LDAP:386-STARTTLS provided by the LDAPS:636 instance. If you don't even have LDAPS:636 running, then add some Client_SSL_Profiles on your Virtual Server to SSL-Offload the LDAP:389-STARTTLS traffic back to plaintext LDAP:389

     

    when RULE_INIT {
        array set static::hex_filler {
            1 "0000000" 2 "000000" 3 "00000" 4 "0000" 5 "000" 6 "00" 7 "0" 8 ""
        }
        set static::ldaps_pool YOUR_LDAPS_POOL
    }
    when CLIENT_ACCEPTED {
         Collecting TCP data
        log local0.debug "Client [IP::client_addr] is Connected to VS [IP::local_addr]:[TCP::local_port]"
        TCP::collect
    }
    when CLIENT_DATA {
         Searching for STARTTLS OID request 
        if { [TCP::payload] contains "1.3.6.1.4.1.1466.20037" } then {
            catch {
                 Parsing 1st BER encoded message envelope (type and length)
                binary scan [TCP::payload] H2c temp(ber_1_type) temp(ber_1_length)
                set temp(scan_offset) 2
                 Checking 1st BER encoded message type = sequence(30)
                if { $temp(ber_1_type) eq "30" } then {
                     Skipping 1st BER encoded length value (aka. just adding bytes to scan_offset)
                    if { [expr { $temp(ber_1_length) & 0xFF }] > 127 } then {
                         Multi-Byte length field detected. Parsing the Multi-Byte length value
                        binary scan [TCP::payload] x$temp(scan_offset)H[expr { ($temp(ber_1_length) & 0x7F) * 2 }] temp(ber_1_mlength)
                        incr temp(scan_offset) [expr { $temp(ber_1_length) & 0x7F }]
                    }
                     Parsing 2nd BER encoded message envelope (type and length)
                    binary scan [TCP::payload] x$temp(scan_offset)H2c temp(ber_2_type) temp(ber_2_length)
                    incr temp(scan_offset) 2
                     Checking 2nd BER encoded message type = integer(02)
                    if { $temp(ber_2_type) eq "02" } then {
                         Inspecting 2nd BER encoded length value
                        if { [expr { $temp(ber_2_length) & 0xFF }] > 127 } then {
                             Multi-Byte length field detected. Parsing the Multi-Byte length value
                            binary scan [TCP::payload] x$temp(scan_offset)H[expr { ($temp(ber_2_length) & 0x7F) * 2 }] temp(ber_2_mlength)
                            incr temp(scan_offset) [expr { $temp(ber_2_length) & 0x7F }]
                            set temp(ber_2_length) [expr "0x$temp(ber_2_mlength)"]
                        }
                         Extracting 2nd BER encoded message value = MessageId (value)
                        binary scan [TCP::payload] x$temp(scan_offset)H[expr { $temp(ber_2_length) * 2 }] temp(ber_2_value)
                         Sending STARTTLS reply with matching LDAP MessageID to client
                        TCP::respond [binary format H* "30840000002B0204$static::hex_filler([string length $temp(ber_2_value)])$temp(ber_2_value)78840000001f0a0100040004008a16312e332e362e312e342e312e313436362e3230303337"]
                         Clearing the collected payload buffer
                        TCP::payload replace 0 [TCP::payload length] ""
                         Selecting LDAPS:683 pool
                        pool $static::ldaps_pool
                    }
                }
            }
            unset -nocomplain temp
        }
         Releasing the connection
        TCP::release
    }
    when SERVER_CONNECTED {
        log local0.debug "Client [IP::client_addr] is forwarded to [LB::server addr]:[LB::server port]"
    }
    

     

    Note: The iRule seems to be stable. But keep in mind that this code is still somewhat hot smoked. Please test the iRule before using in productive environments. I'm planning to polish the iRule here and there in the comming weeks and then publish it on Codeshare. So stay tuned...

    Cheers, Kai