libldap/tls.c: change tls_verify_cb to no longer ignore verification errors.

This means a ldaps connection may drop before any LDAP protocol exchange
occurs (due to expired cert, unrecognized CAs, etc.).
  Change ldap_pvt_tls_connect to copy any TLS error string to ld_error upon
connection failure, otherwise client just sees "can't contact LDAP server."

slapd/connection.c: add flush/delay when SSL_accept fails, to allow any
TLS alerts we generated to propagate back to the client. (Which will then
be picked up by ldap_pvt_tls_connect on the client...)
This commit is contained in:
Howard Chu 2000-05-10 17:07:09 +00:00
parent dcad3d9569
commit f0c4f83ea2
3 changed files with 73 additions and 12 deletions

View file

@ -138,15 +138,18 @@ ldap_pvt_str2lower LDAP_P(( char *str ));
/* tls.c */ /* tls.c */
struct ldapoptions; struct ldapoptions;
struct ldap;
LIBLDAP_F (int) ldap_pvt_tls_init LDAP_P(( void )); LIBLDAP_F (int) ldap_pvt_tls_init LDAP_P(( void ));
LIBLDAP_F (int) ldap_pvt_tls_config LDAP_P(( struct ldapoptions *lo, int option, const char *arg )); LIBLDAP_F (int) ldap_pvt_tls_config LDAP_P(( struct ldapoptions *lo, int option, const char *arg ));
LIBLDAP_F (int) ldap_pvt_tls_connect LDAP_P(( Sockbuf *sb, void *ctx_arg )); LIBLDAP_F (int) ldap_pvt_tls_connect LDAP_P(( struct ldap *ld, Sockbuf *sb, void *ctx_arg ));
LIBLDAP_F (int) ldap_pvt_tls_accept LDAP_P(( Sockbuf *sb, void *ctx_arg )); LIBLDAP_F (int) ldap_pvt_tls_accept LDAP_P(( Sockbuf *sb, void *ctx_arg ));
LIBLDAP_F (int) ldap_pvt_tls_get_option LDAP_P(( struct ldapoptions *lo, int option, void *arg )); LIBLDAP_F (int) ldap_pvt_tls_get_option LDAP_P(( struct ldapoptions *lo, int option, void *arg ));
LIBLDAP_F (int) ldap_pvt_tls_set_option LDAP_P(( struct ldapoptions *lo, int option, void *arg )); LIBLDAP_F (int) ldap_pvt_tls_set_option LDAP_P(( struct ldapoptions *lo, int option, void *arg ));
LIBLDAP_F (void *) ldap_pvt_tls_sb_handle LDAP_P(( Sockbuf *sb ));
LIBLDAP_F (void *) ldap_pvt_tls_get_handle LDAP_P(( struct ldap *ld ));
LIBLDAP_F (int) ldap_pvt_tls_inplace LDAP_P(( Sockbuf *sb )); LIBLDAP_F (int) ldap_pvt_tls_inplace LDAP_P(( Sockbuf *sb ));
LIBLDAP_F (int) ldap_pvt_tls_start LDAP_P(( Sockbuf *sb, void *ctx_arg )); LIBLDAP_F (int) ldap_pvt_tls_start LDAP_P(( struct ldap *ld, Sockbuf *sb, void *ctx_arg ));
/* /*
* UTF-8 (in utf-8.c) * UTF-8 (in utf-8.c)

View file

@ -27,6 +27,8 @@
#ifdef HAVE_OPENSSL_SSL_H #ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#elif defined( HAVE_SSL_H ) #elif defined( HAVE_SSL_H )
#include <ssl.h> #include <ssl.h>
#endif #endif
@ -46,7 +48,7 @@ static int tls_remove( Sockbuf *sb );
static ber_slen_t tls_read( Sockbuf *sb, void *buf, ber_len_t len ); static ber_slen_t tls_read( Sockbuf *sb, void *buf, ber_len_t len );
static ber_slen_t tls_write( Sockbuf *sb, void *buf, ber_len_t len ); static ber_slen_t tls_write( Sockbuf *sb, void *buf, ber_len_t len );
static int tls_close( Sockbuf *sb ); static int tls_close( Sockbuf *sb );
static int tls_report_error( void ); static void tls_report_error( void );
static Sockbuf_IO tls_io= static Sockbuf_IO tls_io=
{ {
@ -60,9 +62,12 @@ static Sockbuf_IO tls_io=
static void tls_info_cb( SSL *ssl, int where, int ret ); static void tls_info_cb( SSL *ssl, int where, int ret );
static int tls_verify_cb( int ok, X509_STORE_CTX *ctx ); static int tls_verify_cb( int ok, X509_STORE_CTX *ctx );
static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length );
static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length );
static STACK_OF(X509_NAME) * get_ca_list( char * bundle, char * dir ); static STACK_OF(X509_NAME) * get_ca_list( char * bundle, char * dir );
#if 0 /* Currently this is not used by anyone */
static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length );
#endif
static SSL_CTX *tls_def_ctx = NULL; static SSL_CTX *tls_def_ctx = NULL;
#ifdef LDAP_R_COMPILE #ifdef LDAP_R_COMPILE
@ -302,7 +307,7 @@ update_flags( Sockbuf *sb, SSL * ssl, int rc )
*/ */
int int
ldap_pvt_tls_connect( Sockbuf *sb, void *ctx_arg ) ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, void *ctx_arg )
{ {
int err; int err;
SSL *ssl; SSL *ssl;
@ -319,9 +324,16 @@ ldap_pvt_tls_connect( Sockbuf *sb, void *ctx_arg )
err = SSL_connect( ssl ); err = SSL_connect( ssl );
#ifdef HAVE_WINSOCK
errno = WSAGetLastError();
#endif
if ( err <= 0 ) { if ( err <= 0 ) {
if ( update_flags( sb, ssl, err )) if ( update_flags( sb, ssl, err ))
return 1; return 1;
if ((err = ERR_peek_error())) {
char buf[256];
ld->ld_error = ldap_strdup(ERR_error_string(err, buf));
}
Debug( LDAP_DEBUG_ANY,"TLS: can't connect.\n",0,0,0); Debug( LDAP_DEBUG_ANY,"TLS: can't connect.\n",0,0,0);
ber_pvt_sb_clear_io( sb ); ber_pvt_sb_clear_io( sb );
ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL );
@ -352,6 +364,9 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
err = SSL_accept( ssl ); err = SSL_accept( ssl );
#ifdef HAVE_WINSOCK
errno = WSAGetLastError();
#endif
if ( err <= 0 ) { if ( err <= 0 ) {
if ( update_flags( sb, ssl, err )) if ( update_flags( sb, ssl, err ))
return 1; return 1;
@ -372,14 +387,31 @@ ldap_pvt_tls_inplace ( Sockbuf *sb )
return(0); return(0);
} }
void *
ldap_pvt_tls_sb_handle( Sockbuf *sb )
{
if (HAS_TLS( sb ))
return sb->sb_iodata;
else
return NULL;
}
void *
ldap_pvt_tls_get_handle( LDAP *ld )
{
return ldap_pvt_tls_sb_handle(&ld->ld_sb);
}
const char * const char *
ldap_pvt_tls_get_peer( LDAP *ld ) ldap_pvt_tls_get_peer( LDAP *ld )
{ {
return NULL;
} }
const char * const char *
ldap_pvt_tls_get_peer_issuer( LDAP *ld ) ldap_pvt_tls_get_peer_issuer( LDAP *ld )
{ {
return NULL;
} }
int int
@ -427,9 +459,9 @@ ldap_pvt_tls_get_option( struct ldapoptions *lo, int option, void *arg )
break; break;
case LDAP_OPT_X_TLS_CERT: case LDAP_OPT_X_TLS_CERT:
if ( lo == NULL ) if ( lo == NULL )
arg = (void *) tls_def_ctx; *(void **)arg = (void *) tls_def_ctx;
else else
arg = lo->ldo_tls_ctx; *(void **)arg = lo->ldo_tls_ctx;
break; break;
case LDAP_OPT_X_TLS_CACERTFILE: case LDAP_OPT_X_TLS_CACERTFILE:
*(char **)arg = tls_opt_cacertfile ? *(char **)arg = tls_opt_cacertfile ?
@ -520,12 +552,12 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg )
} }
int int
ldap_pvt_tls_start ( Sockbuf *sb, void *ctx_arg ) ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg )
{ {
/* /*
* Fortunately, the lib uses blocking io... * Fortunately, the lib uses blocking io...
*/ */
if ( ldap_pvt_tls_connect( sb, ctx_arg ) < 0 ) { if ( ldap_pvt_tls_connect( ld, sb, ctx_arg ) < 0 ) {
return LDAP_CONNECT_ERROR; return LDAP_CONNECT_ERROR;
} }
@ -556,6 +588,9 @@ tls_write( Sockbuf *sb, void *buf, ber_len_t sz )
{ {
int ret = SSL_write( (SSL *)sb->sb_iodata, buf, sz ); int ret = SSL_write( (SSL *)sb->sb_iodata, buf, sz );
#ifdef HAVE_WINSOCK
errno = WSAGetLastError();
#endif
update_flags(sb, (SSL *)sb->sb_iodata, ret ); update_flags(sb, (SSL *)sb->sb_iodata, ret );
#ifdef WIN32 #ifdef WIN32
if (sb->sb_trans_needs_write) if (sb->sb_trans_needs_write)
@ -569,6 +604,9 @@ tls_read( Sockbuf *sb, void *buf, ber_len_t sz )
{ {
int ret = SSL_read( (SSL *)sb->sb_iodata, buf, sz ); int ret = SSL_read( (SSL *)sb->sb_iodata, buf, sz );
#ifdef HAVE_WINSOCK
errno = WSAGetLastError();
#endif
update_flags(sb, (SSL *)sb->sb_iodata, ret ); update_flags(sb, (SSL *)sb->sb_iodata, ret );
#ifdef WIN32 #ifdef WIN32
if (sb->sb_trans_needs_read) if (sb->sb_trans_needs_read)
@ -658,11 +696,11 @@ tls_verify_cb( int ok, X509_STORE_CTX *ctx )
if ( iname ) if ( iname )
CRYPTO_free ( iname ); CRYPTO_free ( iname );
return 1; return ok;
} }
/* Inspired by ERR_print_errors in OpenSSL */ /* Inspired by ERR_print_errors in OpenSSL */
static int static void
tls_report_error( void ) tls_report_error( void )
{ {
unsigned long l; unsigned long l;
@ -693,11 +731,13 @@ tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length )
return tmp_rsa; return tmp_rsa;
} }
#if 0
static DH * static DH *
tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ) tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length )
{ {
return NULL; return NULL;
} }
#endif
#else #else
static int dummy; static int dummy;

View file

@ -881,6 +881,9 @@ int connection_read(ber_socket_t s)
if ( c->c_is_tls && c->c_needs_tls_accept ) { if ( c->c_is_tls && c->c_needs_tls_accept ) {
rc = ldap_pvt_tls_accept( c->c_sb, NULL ); rc = ldap_pvt_tls_accept( c->c_sb, NULL );
if ( rc < 0 ) { if ( rc < 0 ) {
struct timeval tv;
fd_set rfd;
Debug( LDAP_DEBUG_TRACE, Debug( LDAP_DEBUG_TRACE,
"connection_read(%d): TLS accept error error=%d id=%ld, closing\n", "connection_read(%d): TLS accept error error=%d id=%ld, closing\n",
s, rc, c->c_connid ); s, rc, c->c_connid );
@ -888,6 +891,21 @@ int connection_read(ber_socket_t s)
c->c_needs_tls_accept = 0; c->c_needs_tls_accept = 0;
/* connections_mutex and c_mutex are locked */ /* connections_mutex and c_mutex are locked */
connection_closing( c ); connection_closing( c );
/* Drain input before close, to allow SSL error codes
* to propagate to client. */
FD_ZERO(&rfd);
FD_SET(s, &rfd);
ber_pvt_sb_set_readahead(c->c_sb, 0);
for (rc=1; rc>0;)
{
char buf[4096];
tv.tv_sec = 1;
tv.tv_usec = 0;
rc = select(s+1, &rfd, NULL, NULL, &tv);
if (rc == 1)
rc = ber_pvt_sb_read(c->c_sb, buf, sizeof(buf));
}
connection_close( c ); connection_close( c );
} else if ( rc == 0 ) { } else if ( rc == 0 ) {
c->c_needs_tls_accept = 0; c->c_needs_tls_accept = 0;
@ -954,7 +972,7 @@ connection_input(
Debug( LDAP_DEBUG_TRACE, Debug( LDAP_DEBUG_TRACE,
"ber_get_next on fd %d failed errno=%d (%s)\n", "ber_get_next on fd %d failed errno=%d (%s)\n",
ber_pvt_sb_get_desc( conn->c_sb ), err, STRERROR(err) ); ber_pvt_sb_get_desc( conn->c_sb ), err, sock_errstr(err) );
Debug( LDAP_DEBUG_TRACE, Debug( LDAP_DEBUG_TRACE,
"\t*** got %ld of %lu so far\n", "\t*** got %ld of %lu so far\n",
(long) ( conn->c_currentber->ber_buf (long) ( conn->c_currentber->ber_buf