[Pkg-sssd-devel] Bug#849756: sssd-ldap fails to connect to ldaps:// due to problem with non-blocking socket

Bernhard R. Link brlink at debian.org
Fri Dec 30 15:39:10 UTC 2016


Package: sssd-ldap
Version: 1.14.2-1
Severity: serious
Tags: security

Feel free to downgrade the severity, but as this sends passwords in cleartext (though in a case that I hope
will never work so not that likely to loose important passwords) and makes me wonder whether this package can
work at all with any ldaps server, I guessed it might be a suitable severity.

This might be the cause of other "[sdap_process_result] (0x0040): ldap_result error: [Can't contact LDAP server]" bug reports, but as this error message is so generic, I'm creating a new bug report.

sssd calls ldap_install_tls on a socket without removing and NON_BLOCKING bits from it.
This seems to be not supported by the current libldap2-4 version, which returns LDAP_SUCCESS but later fails.

Due to the way libldap fails the request is then send unencrypted (within the SSL Stream).
Here it usually happens that sssd sends both the "Client Hello" and an "Application Data" block (containing unencryted ldap_default_bind_dn and ldap_default_authtok)  before the server can even answer with an hello and the server than sends (depending when the Application data arrives) either with an Unexpected Message Fatal Alert or an Unencrypted Data Alert. (The ldap Server log reports TLS handshake errors, while the on the sssd side one gets "[sdap_process_result] (0x0040): ldap_result error: [Can't contact LDAP server]").

Some example data extracted from the output of wireshark:


Transmission Control Protocol, Src Port: 47911 (47911), Dst Port: 636 (636), Seq: 1, Ack: 1, Len: 150
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 145
        Handshake Protocol: Client Hello

Transmission Control Protocol, Src Port: 47911 (47911), Dst Port: 636 (636), Seq: 151, Ack: 1, Len: 140
Secure Sockets Layer
    TLSv1.2 Record Layer: Application Data Protocol: ldap
        Content Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 135
        Encrypted Application Data: 30818402010160600201030439636e3dxxxxxxxxxxxxxxxx...

Transmission Control Protocol, Src Port: 636 (636), Dst Port: 47911 (47911), Seq: 1, Ack: 151, Len: 0

Transmission Control Protocol, Src Port: 636 (636), Dst Port: 47911 (47911), Seq: 1, Ack: 291, Len: 0

Transmission Control Protocol, Src Port: 636 (636), Dst Port: 47911 (47911), Seq: 1, Ack: 291, Len: 1448
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 53
        Handshake Protocol: Server Hello

Transmission Control Protocol, Src Port: 47911 (47911), Dst Port: 636 (636), Seq: 291, Ack: 1449, Len: 0

Transmission Control Protocol, Src Port: 636 (636), Dst Port: 47911 (47911), Seq: 1449, Ack: 291, Len: 2648
[2 Reassembled TCP Segments (3389 bytes): #29(1390), #31(1999)]
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Certificate
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 3384
        Handshake Protocol: Certificate
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 527
        Handshake Protocol: Server Key Exchange

Transmission Control Protocol, Src Port: 47911 (47911), Dst Port: 636 (636), Seq: 291, Ack: 4097, Len: 0

Transmission Control Protocol, Src Port: 636 (636), Dst Port: 47911 (47911), Seq: 4097, Ack: 291, Len: 216
[2 Reassembled TCP Segments (333 bytes): #31(117), #33(216)]
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 328
        Handshake Protocol: Certificate Request
        Handshake Protocol: Server Hello Done

Transmission Control Protocol, Src Port: 47911 (47911), Dst Port: 636 (636), Seq: 291, Ack: 4313, Len: 0

Transmission Control Protocol, Src Port: 636 (636), Dst Port: 47911 (47911), Seq: 4313, Ack: 291, Len: 7
Secure Sockets Layer
    TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Unexpected Message)
        Content Type: Alert (21)
        Version: TLS 1.2 (0x0303)
        Length: 2
        Alert Message



The content of the "Application Data Protocol: ldap" package is plain non-encrypted data (here a bit redacted):
0``9cn=XXXXXXXXXXXXXXXXXXXX,cn=XXXXXXXXXXXXX,cn=XXXX,ou=XXXXX MYPASWORD_______________________01.3.6.1.4.1.42.2.27.8.5.1


As I can see it the cause of this is that in ../openldap-2.4.44+dfsg/libraries/libldap/tls2.c
the code is:

#ifdef LDAP_USE_NON_BLOCKING_TLS
        /*
         * Use non-blocking io during SSL Handshake when a timeout is configured
         */
        if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
                ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, sb );
                ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
                tv = ld->ld_options.ldo_tm_net;
                tv0 = tv;
#ifdef HAVE_GETTIMEOFDAY
                gettimeofday( &start_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
                time( &start_time_tv.tv_sec );
                start_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */
        }

#endif /* LDAP_USE_NON_BLOCKING_TLS */

        ld->ld_errno = LDAP_SUCCESS;
        ret = ldap_int_tls_connect( ld, conn );

#ifdef LDAP_USE_NON_BLOCKING_TLS
        while ( ret > 0 ) { /* this should only happen for non-blocking io */
            [shortened to make it more readable]
        }
#endif /* LDAP_USE_NON_BLOCKING_TLS */

        if ( ret < 0 ) {
                if ( ld->ld_errno == LDAP_SUCCESS )
                        ld->ld_errno = LDAP_CONNECT_ERROR;
                return (ld->ld_errno);
        }

        ssl = ldap_pvt_tls_sb_ctx( sb );
        assert( ssl != NULL );

        /*
         * compare host with name(s) in certificate
         */
        if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER &&
            ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) {
                ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
                if (ld->ld_errno != LDAP_SUCCESS) {
                        return ld->ld_errno;
                }
        }

        return LDAP_SUCCESS;
}


i.e. libldap expect that if it does not set the fd non-blocking, ldap_int_tls_connect will not return > 0 (which it does if gnutls_handshare returns GNUTLS_E_AGAIN).

(and the only place LDAP_USE_NON_BLOCKING_TLS is defined is:
#ifdef LDAP_DEVEL
#define LDAP_USE_NON_BLOCKING_TLS
#endif /* LDAP_DEVEL */
earlier in the same file. Running sssd in an debugger shows that the code is not compiled in (i.e. it is not defined as expected))

The test of sssd with the problem was done with libldap-2.4-2 version 2.4.44+dfsg-2 and libgnutls30 version 3.5.7-3.



More information about the Pkg-sssd-devel mailing list