Hi, 

initial report at:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=185080 

Imho it's more a OpenSSL than a OpenLDAP client problem. 

Regards,
 Peter 

Description of problem: 

During tracking down, why a LDAP enabled postfix cannot lookup via TLS 
enabled
LDAP client I found that openssl function SSL_add_dir_cert_subjects_to_stack 
is
very optimistic relating to the files found in a specified directory. 

Version-Release number of selected component (if applicable):
openssl-0.9.7a-43.4
also openssl-0.9.7.i (latest 0.9.7 release)
also openssl-0.9.8.a (latest 0.9.8 release) 

in conjunction with
openldap-2.2.13-4
also openldap-2.2.30 (latest 2.2 release)
also openldap-2.3.20 (latest 2.3 release) 


How reproducible: 

Always 

Steps to Reproduce:
1. Create a directory for local PKI storage, e.g.
/etc/pki 

2. Store local CA, local server certificates and local keys into this 
directory 

3. Set proper permissions to keys, e.g.
chmod o-rwx *.key.pem
#  ll /etc/pki/
total 120
lrwxrwxrwx  1 root root   23 Sep 14 15:42 592fcc04.0 -> ca.crt
 -r--r--r--  1 root root 1834 Sep 14 15:39 ca.crt
 -r--r--r--  1 root root 2529 Sep 14 15:39 AE-CA-Class4-2005-A.crt
 -r--------  1 root root 5875 Sep 14 15:45 ca+cert+key.pem
 -r--r--r--  1 root root 4196 Sep 14 16:07 ca+cert.pem
 -r--r--r--  1 root root 2362 Sep 14 15:37 cert.crt
 -r--r-----  1 root root 4041 Sep 14 15:50 cert+key.pem
 -r--r-----  1 root ldap 1679 Sep 14 15:37 key.pem (note: group=ldap for LDAP
server, which reads key file for server TLS after changing the user to 
"ldap") 

4. Configure /etc/openldap/slapd.conf for TLS like
TLSCACertificateFile    /etc/pki/ca.crt
TLSCACertificatePath    /etc/pki
TLSCertificateFile      /etc/pki/crt.crt
TLSCertificateKeyFile   /etc/pki/key.pem 


5. Configure /etc/openldap/ldap.conf related
URI     ldaps://ldapserver/
#URI    ldap://ldapserver/
BASE dc=example,dc=com
TLS_CACERTDIR   /etc/pki    # <- important! 


6. Try ldapsearch usig TLS as root:
ldapsearch -x -H ldaps://ldapserver/
Result: working 

7. Try ldapsearch using TLS as normal user:
$ ldapsearch -x -v -H ldaps://ldapserver
Result: not working, message:
ldap_initialize( ldaps://ldapserver )
ldap_bind: Can't contact LDAP server (-1) 

Using strace shows me: 

open("/etc/pki/key.pem", O_RDONLY) = -1 EACCES (Permission denied)
close(4)                                = 0
write(2, "ldap_bind: Can\'t contact LDAP server (-1)\n", 42ldap_bind: Can't
contact LDAP server (-1)
) = 42
exit_group(1)                           = ?
Process 15652 detached 

Ooops, why will ldapsearch open this key file??? Ok, thanks to opensource we 
are
now now digging through the code: 

A) openldap: openldap-2.2.13/libraries/libldap/tls.c
(same code in newer/latest versions) 

static STACK_OF(X509_NAME) *
get_ca_list( char * bundle, char * dir )
{
        STACK_OF(X509_NAME) *ca_list = NULL; 

        if ( bundle ) {
                ca_list = SSL_load_client_CA_file( bundle );
        }
#if defined(HAVE_DIRENT_H) || defined(dirent)
        if ( dir ) {
                int freeit = 0; 

                if ( !ca_list ) {
                        ca_list = sk_X509_NAME_new_null();
                        freeit = 1;
                }
                if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) &&
                        freeit ) {
                        sk_X509_NAME_free( ca_list );
                        ca_list = NULL;
                }
        }
#endif
        return ca_list;
} 

Ok, openldap calls an openssl functions to read all certificates in "dir" 
and
add to "ca_list". 

Note that here is also an opportunity for improvements to be more graceful, 
if
SSL_load_client_CA_file works but SSL_add_dir_cert_subjects_to_stack fails.
Currently, the whole ca_list ist dropped. 


B) openssl: openssl-0.9.7a/ssl/ssl_cert.c
(same code in newer/latest versions) 

/*!
 * Add a directory of certs to a stack.
 * \param stack the stack to append to.
 * \param dir the directory to append from. All files in this directory will 
be
 * examined as potential certs. Any that are acceptable to
 * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack 
will be
 * included.
 * \return 1 for success, 0 for failure. Note that in the case of failure 
some
 * certs may have been added to \c stack.
 */ 

#ifndef OPENSSL_SYS_WIN32
#ifndef OPENSSL_SYS_VMS         /* XXXX This may be fixed in the future */
#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! */ 

int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
                                       const char *dir)
        {
        DIR *d;
        struct dirent *dstruct;
        int ret = 0; 

        CRYPTO_w_lock(CRYPTO_LOCK_READDIR);
        d = opendir(dir); 

        /* Note that a side effect is that the CAs will be sorted by name */
        if(!d)
                {
                SYSerr(SYS_F_OPENDIR, get_last_sys_error());
                ERR_add_error_data(3, "opendir('", dir, "')");
                SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, 
ERR_R_SYS_LIB);
                goto err;
                } 

        while((dstruct=readdir(d)))
                {
                char buf[1024];
                int r; 

                if(strlen(dir)+strlen(dstruct->d_name)+2 > sizeof buf)
                        {

SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG);
                        goto err;
                        } 

                r = BIO_snprintf(buf,sizeof 
buf,"%s/%s",dir,dstruct->d_name);
                if (r <= 0 || r >= sizeof buf)
                        goto err;
                if(!SSL_add_file_cert_subjects_to_stack(stack,buf))
                        goto err;
                }
        ret = 1; 

err:
        if (d) closedir(d);
        CRYPTO_w_unlock(CRYPTO_LOCK_READDIR);
        return ret;
        } 

#endif
#endif 

Oooppppssss!!!! Looks like developers were very optimistic that after 
reading
the directory into "d", all files are readable by the user which executes 
the
program. Only a test whether path is too long was made.
Afterwards, file is given to BIO_snprintf for reading, which fails on
non-readable files. 

There is an additional check missing! 

 

Additional info: 

It looks like that a simple 

# touch /path/to/my/pki/certs/dummy
# chmod go-rwx /path/to/my/pki/certs/dummy 

would stop the use of TLS enabled clients executed by non-root users (e.g. 
here:
postfix) at all - that's bad! 


BTW: If I temporary change permissions to 444 to all files in this 
directory,
ldapsearch works for non-root users TLS enabled. 

-- 
Dr. Peter Bieringer                     http://www.bieringer.de/pb/
GPG/PGP Key 0x958F422D               mailto: pb at bieringer dot de
Deep Space 6 Co-Founder and Core Member  http://www.deepspace6.net/

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to