X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Ftls.c;h=53c4e3b0804090d6387be7feaa05873f3a9bc527;hb=9e0958d5bc342e2f35f6ee8aaa6cf179b2d55085;hp=d92784e000d1f572177f6c56f11a2d7c9d92a2dc;hpb=7a64fcf7b3cb63de1fb0d0ab16ac0700db53d36d;p=openldap diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index d92784e000..53c4e3b080 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -1,3 +1,4 @@ +/* $OpenLDAP$ */ /* * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file @@ -10,8 +11,8 @@ #ifdef HAVE_TLS #include -#include +#include #include #include #include @@ -30,6 +31,7 @@ #include #endif +static int tls_opt_trace = 1; static char *tls_opt_certfile = NULL; static char *tls_opt_keyfile = NULL; static char *tls_opt_cacertfile = NULL; @@ -55,7 +57,11 @@ static Sockbuf_IO tls_io= tls_close }; +static void tls_info_cb( SSL *ssl, int where, int ret ); 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 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 SSL_CTX *tls_def_ctx = NULL; @@ -109,6 +115,8 @@ ldap_pvt_tls_init( void ) #endif SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); + /* FIXME: mod_ssl does this */ + X509V3_add_standard_extensions(); return 0; } @@ -118,6 +126,8 @@ ldap_pvt_tls_init( void ) int ldap_pvt_tls_init_def_ctx( void ) { + STACK_OF(X509_NAME) *calist; + #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex ); #endif @@ -147,6 +157,15 @@ ldap_pvt_tls_init_def_ctx( void ) tls_report_error(); goto error_exit; } + calist = get_ca_list( tls_opt_cacertfile, tls_opt_cacertdir ); + if ( !calist ) { + Debug( LDAP_DEBUG_ANY, + "TLS: could not load client CA list (file:`%s',dir:`%s').\n", + tls_opt_cacertfile,tls_opt_cacertdir,0); + tls_report_error(); + goto error_exit; + } + SSL_CTX_set_client_CA_list( tls_def_ctx, calist ); if ( tls_opt_keyfile && !SSL_CTX_use_PrivateKey_file( tls_def_ctx, tls_opt_keyfile, @@ -175,9 +194,14 @@ ldap_pvt_tls_init_def_ctx( void ) tls_report_error(); goto error_exit; } + if ( tls_opt_trace ) { + SSL_CTX_set_info_callback( tls_def_ctx, tls_info_cb ); + } SSL_CTX_set_verify( tls_def_ctx, (tls_opt_require_cert) ? (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT) : SSL_VERIFY_PEER, tls_verify_cb ); + SSL_CTX_set_tmp_rsa_callback( tls_def_ctx, tls_tmp_rsa_cb ); + /* SSL_CTX_set_tmp_dh_callback( tls_def_ctx, tls_tmp_dh_cb ); */ } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex ); @@ -190,6 +214,21 @@ error_exit: return -1; } +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 ); + } + /* + * FIXME: We have now to go over all files in dir, load them + * and add every certificate there to ca_list. + */ + return ca_list; +} + static SSL * alloc_handle( Sockbuf *sb, void *ctx_arg ) { @@ -202,7 +241,7 @@ alloc_handle( Sockbuf *sb, void *ctx_arg ) } else { if ( ldap_pvt_tls_init_def_ctx() < 0 ) return NULL; - ctx=tls_def_ctx; + ctx = tls_def_ctx; } ssl = SSL_new( ctx ); @@ -211,6 +250,10 @@ alloc_handle( Sockbuf *sb, void *ctx_arg ) return NULL; } + if ( tls_opt_trace ) { + SSL_set_info_callback( ssl, tls_info_cb ); + } + sb->sb_iodata = ssl; SSL_set_fd( ssl, ber_pvt_sb_get_desc( sb ) ); return ssl; } @@ -296,14 +339,7 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) err = SSL_accept( ssl ); if ( err <= 0 ) { - if ( -#ifdef EWOULDBLOCK - (errno==EWOULDBLOCK) || -#endif -#ifdef EAGAIN - (errno==EAGAIN) || -#endif - (0)) { + if ( !SSL_want_nothing( ssl ) ) { update_flags( sb, ssl ); return 1; } @@ -343,21 +379,19 @@ ldap_pvt_tls_config( struct ldapoptions *lo, int option, const char *arg ) ( strcasecmp( arg, "true" ) == 0 ) ); return ldap_pvt_tls_set_option( NULL, option, (void *) &i ); case LDAP_OPT_X_TLS: + i = -1; if ( strcasecmp( arg, "never" ) == 0 ) - return ldap_pvt_tls_set_option( lo, option, - LDAP_OPT_X_TLS_NEVER ); + i = LDAP_OPT_X_TLS_NEVER ; if ( strcasecmp( arg, "demand" ) == 0 ) - return ldap_pvt_tls_set_option( lo, option, - LDAP_OPT_X_TLS_DEMAND ); + i = LDAP_OPT_X_TLS_DEMAND ; if ( strcasecmp( arg, "allow" ) == 0 ) - return ldap_pvt_tls_set_option( lo, option, - LDAP_OPT_X_TLS_ALLOW ); + i = LDAP_OPT_X_TLS_ALLOW ; if ( strcasecmp( arg, "try" ) == 0 ) - return ldap_pvt_tls_set_option( lo, option, - LDAP_OPT_X_TLS_TRY ); + i = LDAP_OPT_X_TLS_TRY ; if ( strcasecmp( arg, "hard" ) == 0 ) - return ldap_pvt_tls_set_option( lo, option, - LDAP_OPT_X_TLS_HARD ); + i = LDAP_OPT_X_TLS_HARD ; + if (i >= 0) + return ldap_pvt_tls_set_option( lo, option, &i ); return -1; default: return -1; @@ -379,19 +413,19 @@ ldap_pvt_tls_get_option( struct ldapoptions *lo, int option, void *arg ) break; case LDAP_OPT_X_TLS_CACERTFILE: *(char **)arg = tls_opt_cacertfile ? - strdup( tls_opt_cacertfile ) : NULL; + LDAP_STRDUP( tls_opt_cacertfile ) : NULL; break; case LDAP_OPT_X_TLS_CACERTDIR: *(char **)arg = tls_opt_cacertdir ? - strdup( tls_opt_cacertdir ) : NULL; + LDAP_STRDUP( tls_opt_cacertdir ) : NULL; break; case LDAP_OPT_X_TLS_CERTFILE: *(char **)arg = tls_opt_certfile ? - strdup( tls_opt_certfile ) : NULL; + LDAP_STRDUP( tls_opt_certfile ) : NULL; break; case LDAP_OPT_X_TLS_KEYFILE: *(char **)arg = tls_opt_keyfile ? - strdup( tls_opt_keyfile ) : NULL; + LDAP_STRDUP( tls_opt_keyfile ) : NULL; break; case LDAP_OPT_X_TLS_REQUIRE_CERT: *(int *)arg = tls_opt_require_cert; @@ -431,26 +465,26 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg ) switch( option ) { case LDAP_OPT_X_TLS_CACERTFILE: if ( tls_opt_cacertfile ) free( tls_opt_cacertfile ); - tls_opt_cacertfile = arg ? strdup( (char *) arg ) : NULL; + tls_opt_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_CACERTDIR: if ( tls_opt_cacertdir ) free( tls_opt_cacertdir ); - tls_opt_cacertdir = arg ? strdup( (char *) arg ) : NULL; + tls_opt_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_CERTFILE: if ( tls_opt_certfile ) free( tls_opt_certfile ); - tls_opt_certfile = arg ? strdup( (char *) arg ) : NULL; + tls_opt_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_KEYFILE: if ( tls_opt_keyfile ) free( tls_opt_keyfile ); - tls_opt_keyfile = arg ? strdup( (char *) arg ) : NULL; + tls_opt_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_REQUIRE_CERT: tls_opt_require_cert = * (int *) arg; break; case LDAP_OPT_X_TLS_CIPHER_SUITE: if ( tls_opt_ciphersuite ) free( tls_opt_ciphersuite ); - tls_opt_ciphersuite = arg ? strdup( (char *) arg ) : NULL; + tls_opt_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; default: return -1; @@ -497,9 +531,80 @@ tls_close( Sockbuf *sb ) return 0; } +/* Derived from openssl/apps/s_cb.c */ +static void +tls_info_cb( SSL *ssl, int where, int ret ) +{ + int w; + char *op; + + w = where & ~SSL_ST_MASK; + if ( w & SSL_ST_CONNECT ) { + op = "SSL_connect"; + } else if ( w & SSL_ST_ACCEPT ) { + op = "SSL_accept"; + } else { + op = "undefined"; + } + + if ( where & SSL_CB_LOOP ) { + Debug( LDAP_DEBUG_TRACE, + "TLS trace: %s:%s\n", + op, SSL_state_string_long( ssl ), 0 ); + } else if ( where & SSL_CB_ALERT ) { + op = ( where & SSL_CB_READ ) ? "read" : "write"; + Debug( LDAP_DEBUG_TRACE, + "TLS trace: SSL3 alert %s:%s:%s\n", + op, + SSL_alert_type_string_long( ret ), + SSL_alert_desc_string_long( ret) ); + } else if ( where & SSL_CB_EXIT ) { + if ( ret == 0 ) { + Debug( LDAP_DEBUG_TRACE, + "TLS trace: %s:failed in %s\n", + op, SSL_state_string_long( ssl ), 0 ); + } else if ( ret < 0 ) { + Debug( LDAP_DEBUG_TRACE, + "TLS trace: %s:error in %s\n", + op, SSL_state_string_long( ssl ), 0 ); + } + } +} + static int tls_verify_cb( int ok, X509_STORE_CTX *ctx ) { + X509 *cert; + int errnum; + int errdepth; + X509_NAME *subject; + X509_NAME *issuer; + char *sname; + char *iname; + + cert = X509_STORE_CTX_get_current_cert( ctx ); + errnum = X509_STORE_CTX_get_error( ctx ); + errdepth = X509_STORE_CTX_get_error_depth( ctx ); + + /* + * X509_get_*_name return pointers to the internal copies of + * those things requested. So do not free them. + */ + subject = X509_get_subject_name( cert ); + issuer = X509_get_issuer_name( cert ); + /* X509_NAME_oneline, if passed a NULL buf, allocate memomry */ + sname = X509_NAME_oneline( subject, NULL, 0 ); + iname = X509_NAME_oneline( issuer, NULL, 0 ); + Debug( LDAP_DEBUG_TRACE, + "TLS certificate verification: depth: %d, subject: %s, issuer: %s\n", + errdepth, + sname ? sname : "-unknown-", + iname ? iname : "-unknown-" ); + if ( sname ) + free ( sname ); + if ( iname ) + free ( iname ); + return 1; } @@ -518,6 +623,29 @@ tls_report_error( void ) } } +static RSA * +tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ) +{ + RSA *tmp_rsa; + + /* FIXME: Pregenerate the key on startup */ + /* FIXME: Who frees the key? */ + tmp_rsa = RSA_generate_key( key_length, RSA_F4, NULL, NULL ); + + if ( !tmp_rsa ) { + Debug( LDAP_DEBUG_ANY, "TLS: Failed to generate temporary %d-bit %s RSA key\n", + key_length, is_export ? "export" : "domestic", 0 ); + return NULL; + } + return tmp_rsa; +} + +static DH * +tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ) +{ + return NULL; +} + #else static int dummy; #endif