X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Ftls.c;h=504263ed14d3df89323f441daa95596dc9ba1d8a;hb=623a7a9fe2619abf658fec3d5f690a5ba240e4f3;hp=4f7a08b9e6b580464314138595b14fa2c3acf778;hpb=ad62d9da1b50b55f616f54b45f11a6e7165d1f77;p=openldap diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index 4f7a08b9e6..504263ed14 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2005 The OpenLDAP Foundation. + * Copyright 1998-2006 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,15 +48,6 @@ #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; -static char *tls_opt_cacertdir = NULL; -static int tls_opt_require_cert = LDAP_OPT_X_TLS_DEMAND; -#ifdef HAVE_OPENSSL_CRL -static int tls_opt_crlcheck = LDAP_OPT_X_TLS_CRL_NONE; -#endif -static char *tls_opt_ciphersuite = NULL; static char *tls_opt_randfile = NULL; #define HAS_TLS( sb ) ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \ @@ -70,11 +61,15 @@ static int tls_verify_ok( int ok, X509_STORE_CTX *ctx ); static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); 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; +typedef struct dhplist { + struct dhplist *next; + int keylength; + DH *param; +} dhplist; + +static dhplist *dhparams; static int tls_seed_PRNG( const char *randfile ); @@ -113,39 +108,54 @@ static void tls_init_threads( void ) } #endif /* LDAP_R_COMPILE */ +void +ldap_int_tls_destroy( struct ldapoptions *lo ) +{ + if ( lo->ldo_tls_ctx ) { + SSL_CTX_free( lo->ldo_tls_ctx ); + lo->ldo_tls_ctx = NULL; + } + + if ( lo->ldo_tls_certfile ) { + LDAP_FREE( lo->ldo_tls_certfile ); + lo->ldo_tls_certfile = NULL; + } + if ( lo->ldo_tls_keyfile ) { + LDAP_FREE( lo->ldo_tls_keyfile ); + lo->ldo_tls_keyfile = NULL; + } + if ( lo->ldo_tls_dhfile ) { + LDAP_FREE( lo->ldo_tls_dhfile ); + lo->ldo_tls_dhfile = NULL; + } + if ( lo->ldo_tls_cacertfile ) { + LDAP_FREE( lo->ldo_tls_cacertfile ); + lo->ldo_tls_cacertfile = NULL; + } + if ( lo->ldo_tls_cacertdir ) { + LDAP_FREE( lo->ldo_tls_cacertdir ); + lo->ldo_tls_cacertdir = NULL; + } + if ( lo->ldo_tls_ciphersuite ) { + LDAP_FREE( lo->ldo_tls_ciphersuite ); + lo->ldo_tls_ciphersuite = NULL; + } +} + /* * Tear down the TLS subsystem. Should only be called once. */ void ldap_pvt_tls_destroy( void ) { - SSL_CTX_free(tls_def_ctx); - tls_def_ctx = NULL; + struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); + + ldap_int_tls_destroy( lo ); EVP_cleanup(); ERR_remove_state(0); ERR_free_strings(); - if ( tls_opt_certfile ) { - LDAP_FREE( tls_opt_certfile ); - tls_opt_certfile = NULL; - } - if ( tls_opt_keyfile ) { - LDAP_FREE( tls_opt_keyfile ); - tls_opt_keyfile = NULL; - } - if ( tls_opt_cacertfile ) { - LDAP_FREE( tls_opt_cacertfile ); - tls_opt_cacertfile = NULL; - } - if ( tls_opt_cacertdir ) { - LDAP_FREE( tls_opt_cacertdir ); - tls_opt_cacertdir = NULL; - } - if ( tls_opt_ciphersuite ) { - LDAP_FREE( tls_opt_ciphersuite ); - tls_opt_ciphersuite = NULL; - } if ( tls_opt_randfile ) { LDAP_FREE( tls_opt_randfile ); tls_opt_randfile = NULL; @@ -186,18 +196,27 @@ ldap_pvt_tls_init( void ) } /* - * initialize the default context + * initialize a new TLS context */ -int -ldap_pvt_tls_init_def_ctx( void ) +static int +ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) { STACK_OF(X509_NAME) *calist; - int rc = 0; - char *ciphersuite = tls_opt_ciphersuite; - char *cacertfile = tls_opt_cacertfile; - char *cacertdir = tls_opt_cacertdir; - char *certfile = tls_opt_certfile; - char *keyfile = tls_opt_keyfile; + int i, rc = 0; + char *ciphersuite = lo->ldo_tls_ciphersuite; + char *cacertfile = lo->ldo_tls_cacertfile; + char *cacertdir = lo->ldo_tls_cacertdir; + char *certfile = lo->ldo_tls_certfile; + char *keyfile = lo->ldo_tls_keyfile; + char *dhfile = lo->ldo_tls_dhfile; + + if ( lo->ldo_tls_ctx ) + return 0; + + if ( is_server && !certfile && !keyfile && !cacertfile && !cacertdir ) { + /* minimum configuration not provided */ + return LDAP_NOT_SUPPORTED; + } #ifdef HAVE_EBCDIC /* This ASCII/EBCDIC handling is a real pain! */ @@ -221,135 +240,155 @@ ldap_pvt_tls_init_def_ctx( void ) keyfile = LDAP_STRDUP( keyfile ); __atoe( keyfile ); } + if ( dhfile ) { + dhfile = LDAP_STRDUP( dhfile ); + __atoe( dhfile ); + } #endif + lo->ldo_tls_ctx = SSL_CTX_new( SSLv23_method() ); + if ( lo->ldo_tls_ctx == NULL ) { + Debug( LDAP_DEBUG_ANY, + "TLS: could not allocate default ctx (%lu).\n", + ERR_peek_error(),0,0); + rc = -1; + goto error_exit; + } -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex ); -#endif - if ( tls_def_ctx == NULL ) { - int i; - tls_def_ctx = SSL_CTX_new( SSLv23_method() ); - if ( tls_def_ctx == NULL ) { - Debug( LDAP_DEBUG_ANY, - "TLS: could not allocate default ctx (%lu).\n", - ERR_peek_error(),0,0); - rc = -1; - goto error_exit; - } - - SSL_CTX_set_session_id_context( tls_def_ctx, + if ( is_server ) { + SSL_CTX_set_session_id_context( lo->ldo_tls_ctx, (const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 ); + } + + if ( lo->ldo_tls_ciphersuite && + !SSL_CTX_set_cipher_list( lo->ldo_tls_ctx, ciphersuite ) ) + { + Debug( LDAP_DEBUG_ANY, + "TLS: could not set cipher list %s.\n", + lo->ldo_tls_ciphersuite, 0, 0 ); + tls_report_error(); + rc = -1; + goto error_exit; + } - if ( tls_opt_ciphersuite && - !SSL_CTX_set_cipher_list( tls_def_ctx, ciphersuite ) ) + if (lo->ldo_tls_cacertfile != NULL || lo->ldo_tls_cacertdir != NULL) { + if ( !SSL_CTX_load_verify_locations( lo->ldo_tls_ctx, + cacertfile, cacertdir ) || + !SSL_CTX_set_default_verify_paths( lo->ldo_tls_ctx ) ) { - Debug( LDAP_DEBUG_ANY, - "TLS: could not set cipher list %s.\n", - tls_opt_ciphersuite, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "TLS: " + "could not load verify locations (file:`%s',dir:`%s').\n", + lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", + lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "", + 0 ); tls_report_error(); rc = -1; goto error_exit; } - if (tls_opt_cacertfile != NULL || tls_opt_cacertdir != NULL) { - if ( !SSL_CTX_load_verify_locations( tls_def_ctx, - cacertfile, cacertdir ) || - !SSL_CTX_set_default_verify_paths( tls_def_ctx ) ) - { - Debug( LDAP_DEBUG_ANY, "TLS: " - "could not load verify locations (file:`%s',dir:`%s').\n", - tls_opt_cacertfile ? tls_opt_cacertfile : "", - tls_opt_cacertdir ? tls_opt_cacertdir : "", - 0 ); - tls_report_error(); - rc = -1; - goto error_exit; - } - + if ( is_server ) { + /* List of CA names to send to a client */ calist = get_ca_list( cacertfile, cacertdir ); if ( !calist ) { Debug( LDAP_DEBUG_ANY, "TLS: " "could not load client CA list (file:`%s',dir:`%s').\n", - tls_opt_cacertfile ? tls_opt_cacertfile : "", - tls_opt_cacertdir ? tls_opt_cacertdir : "", + lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", + lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "", 0 ); tls_report_error(); rc = -1; goto error_exit; } - SSL_CTX_set_client_CA_list( tls_def_ctx, calist ); + SSL_CTX_set_client_CA_list( lo->ldo_tls_ctx, calist ); } + } - if ( tls_opt_keyfile && - !SSL_CTX_use_PrivateKey_file( tls_def_ctx, - keyfile, SSL_FILETYPE_PEM ) ) - { - Debug( LDAP_DEBUG_ANY, - "TLS: could not use key file `%s'.\n", - tls_opt_keyfile,0,0); - tls_report_error(); - rc = -1; - goto error_exit; - } + if ( lo->ldo_tls_certfile && + !SSL_CTX_use_certificate_file( lo->ldo_tls_ctx, + certfile, SSL_FILETYPE_PEM ) ) + { + Debug( LDAP_DEBUG_ANY, + "TLS: could not use certificate `%s'.\n", + lo->ldo_tls_certfile,0,0); + tls_report_error(); + rc = -1; + goto error_exit; + } - if ( tls_opt_certfile && - !SSL_CTX_use_certificate_file( tls_def_ctx, - certfile, SSL_FILETYPE_PEM ) ) - { - Debug( LDAP_DEBUG_ANY, - "TLS: could not use certificate `%s'.\n", - tls_opt_certfile,0,0); - tls_report_error(); - rc = -1; - goto error_exit; - } + /* Key validity is checked automatically if cert has already been set */ + if ( lo->ldo_tls_keyfile && + !SSL_CTX_use_PrivateKey_file( lo->ldo_tls_ctx, + keyfile, SSL_FILETYPE_PEM ) ) + { + Debug( LDAP_DEBUG_ANY, + "TLS: could not use key file `%s'.\n", + lo->ldo_tls_keyfile,0,0); + tls_report_error(); + rc = -1; + goto error_exit; + } - if ( ( tls_opt_certfile || tls_opt_keyfile ) && - !SSL_CTX_check_private_key( tls_def_ctx ) ) - { + if ( lo->ldo_tls_dhfile ) { + DH *dh = NULL; + BIO *bio; + dhplist *p; + + if (( bio=BIO_new_file( dhfile,"r" )) == NULL ) { Debug( LDAP_DEBUG_ANY, - "TLS: private key mismatch.\n", - 0,0,0); + "TLS: could not use DH parameters file `%s'.\n", + lo->ldo_tls_dhfile,0,0); tls_report_error(); rc = -1; goto error_exit; } - - if ( tls_opt_trace ) { - SSL_CTX_set_info_callback( tls_def_ctx, tls_info_cb ); + while (( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) { + p = LDAP_MALLOC( sizeof(dhplist) ); + if ( p != NULL ) { + p->keylength = DH_size( dh ) * 8; + p->param = dh; + p->next = dhparams; + dhparams = p; + } } + BIO_free( bio ); + } - i = SSL_VERIFY_NONE; - if ( tls_opt_require_cert ) { - i = SSL_VERIFY_PEER; - if ( tls_opt_require_cert == LDAP_OPT_X_TLS_DEMAND || - tls_opt_require_cert == LDAP_OPT_X_TLS_HARD ) { - i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; - } + if ( tls_opt_trace ) { + SSL_CTX_set_info_callback( (SSL_CTX *)lo->ldo_tls_ctx, tls_info_cb ); + } + + i = SSL_VERIFY_NONE; + if ( lo->ldo_tls_require_cert ) { + i = SSL_VERIFY_PEER; + if ( lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND || + lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) { + i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } + } - SSL_CTX_set_verify( tls_def_ctx, i, - tls_opt_require_cert == LDAP_OPT_X_TLS_ALLOW ? - tls_verify_ok : 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 ); */ + SSL_CTX_set_verify( lo->ldo_tls_ctx, i, + lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ? + tls_verify_ok : tls_verify_cb ); + SSL_CTX_set_tmp_rsa_callback( lo->ldo_tls_ctx, tls_tmp_rsa_cb ); + if ( lo->ldo_tls_dhfile ) { + SSL_CTX_set_tmp_dh_callback( lo->ldo_tls_ctx, tls_tmp_dh_cb ); + } #ifdef HAVE_OPENSSL_CRL - if ( tls_opt_crlcheck ) { - X509_STORE *x509_s = SSL_CTX_get_cert_store( tls_def_ctx ); - if ( tls_opt_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) { - X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK ); - } else if ( tls_opt_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) { - X509_STORE_set_flags( x509_s, - X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); - } + if ( lo->ldo_tls_crlcheck ) { + X509_STORE *x509_s = SSL_CTX_get_cert_store( lo->ldo_tls_ctx ); + if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) { + X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK ); + } else if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) { + X509_STORE_set_flags( x509_s, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); } -#endif } +#endif + error_exit: - if ( rc == -1 && tls_def_ctx != NULL ) { - SSL_CTX_free( tls_def_ctx ); - tls_def_ctx = NULL; + if ( rc == -1 && lo->ldo_tls_ctx != NULL ) { + SSL_CTX_free( lo->ldo_tls_ctx ); + lo->ldo_tls_ctx = NULL; } #ifdef HAVE_EBCDIC LDAP_FREE( ciphersuite ); @@ -357,11 +396,26 @@ error_exit: LDAP_FREE( cacertdir ); LDAP_FREE( certfile ); LDAP_FREE( keyfile ); + LDAP_FREE( dhfile ); #endif + return rc; +} + +/* + * initialize the default context + */ +int +ldap_pvt_tls_init_def_ctx( int is_server ) +{ + struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); + int rc; +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex ); +#endif + rc = ldap_int_tls_init_ctx( lo, is_server ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex ); #endif - return rc; } static STACK_OF(X509_NAME) * @@ -391,7 +445,7 @@ get_ca_list( char * bundle, char * dir ) } static SSL * -alloc_handle( void *ctx_arg ) +alloc_handle( void *ctx_arg, int is_server ) { SSL_CTX *ctx; SSL *ssl; @@ -399,8 +453,9 @@ alloc_handle( void *ctx_arg ) if ( ctx_arg ) { ctx = (SSL_CTX *) ctx_arg; } else { - if ( ldap_pvt_tls_init_def_ctx() < 0 ) return NULL; - ctx = tls_def_ctx; + struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); + if ( ldap_pvt_tls_init_def_ctx( is_server ) < 0 ) return NULL; + ctx = lo->ldo_tls_ctx; } ssl = SSL_new( ctx ); @@ -714,10 +769,11 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) } else { struct ldapoptions *lo; - void *ctx = ld->ld_defconn - ? ld->ld_defconn->lconn_tls_ctx : NULL; + SSL_CTX *ctx; + + ctx = ld->ld_options.ldo_tls_ctx; - ssl = alloc_handle( ctx ); + ssl = alloc_handle( ctx, 0 ); if ( ssl == NULL ) return -1; @@ -728,15 +784,17 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) ber_sockbuf_add_io( sb, &sb_tls_sbio, LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); + lo = LDAP_INT_GLOBAL_OPT(); if( ctx == NULL ) { - ctx = tls_def_ctx; - conn->lconn_tls_ctx = tls_def_ctx; + ctx = lo->ldo_tls_ctx; + ld->ld_options.ldo_tls_ctx = ctx; + CRYPTO_add( &ctx->references, 1, CRYPTO_LOCK_SSL_CTX ); } - lo = &ld->ld_options; - if ( lo->ldo_tls_connect_cb ) - lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg ); - lo = LDAP_INT_GLOBAL_OPT(); - if ( lo && lo->ldo_tls_connect_cb ) + if ( ld->ld_options.ldo_tls_connect_cb ) + ld->ld_options.ldo_tls_connect_cb( ld, ssl, ctx, + ld->ld_options.ldo_tls_connect_arg ); + if ( lo && lo->ldo_tls_connect_cb && lo->ldo_tls_connect_cb != + ld->ld_options.ldo_tls_connect_cb ) lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg ); } @@ -753,6 +811,10 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) if ((err = ERR_peek_error())) { char buf[256]; + + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } ld->ld_error = LDAP_STRDUP(ERR_error_string(err, buf)); #ifdef HAVE_EBCDIC if ( ld->ld_error ) __etoa(ld->ld_error); @@ -787,7 +849,7 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); } else { - ssl = alloc_handle( ctx_arg ); + ssl = alloc_handle( ctx_arg, 1 ); if ( ssl == NULL ) return -1; #ifdef LDAP_DEBUG @@ -831,10 +893,14 @@ int ldap_tls_inplace( LDAP *ld ) { Sockbuf *sb = NULL; - int rc; - rc = ldap_get_option( ld, LDAP_OPT_SOCKBUF, (void *)&sb ); - if ( rc != LDAP_SUCCESS || sb == NULL ) { + if ( ld->ld_defconn && ld->ld_defconn->lconn_sb ) { + sb = ld->ld_defconn->lconn_sb; + + } else if ( ld->ld_sb ) { + sb = ld->ld_sb; + + } else { return 0; } @@ -1032,7 +1098,10 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) Debug( LDAP_DEBUG_ANY, "TLS: unable to get common name from peer certificate.\n", 0, 0, 0 ); - ret = LDAP_CONNECT_ERROR; + ret = LDAP_CONNECT_ERROR; + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get CN from peer certificate")); @@ -1057,12 +1126,15 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) } if( ret == LDAP_LOCAL_ERROR ) { - Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " - "common name in certificate (%s).\n", - name, buf, 0 ); - ret = LDAP_CONNECT_ERROR; - ld->ld_error = LDAP_STRDUP( - _("TLS: hostname does not match CN in peer certificate")); + Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " + "common name in certificate (%s).\n", + name, buf, 0 ); + ret = LDAP_CONNECT_ERROR; + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } + ld->ld_error = LDAP_STRDUP( + _("TLS: hostname does not match CN in peer certificate")); } } X509_free(x); @@ -1102,6 +1174,7 @@ ldap_int_tls_config( LDAP *ld, int option, const char *arg ) case LDAP_OPT_X_TLS_KEYFILE: case LDAP_OPT_X_TLS_RANDOM_FILE: case LDAP_OPT_X_TLS_CIPHER_SUITE: + case LDAP_OPT_X_TLS_DHFILE: return ldap_pvt_tls_set_option( ld, option, (void *) arg ); case LDAP_OPT_X_TLS_REQUIRE_CERT: @@ -1177,34 +1250,38 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) *(int *)arg = lo->ldo_tls_mode; break; case LDAP_OPT_X_TLS_CTX: - if ( ld == NULL ) { - *(void **)arg = (void *) tls_def_ctx; - } else { - *(void **)arg = ld->ld_defconn->lconn_tls_ctx; + *(void **)arg = lo->ldo_tls_ctx; + if ( lo->ldo_tls_ctx ) { + SSL_CTX *ctx = lo->ldo_tls_ctx; + CRYPTO_add( &ctx->references, 1, CRYPTO_LOCK_SSL_CTX ); } break; case LDAP_OPT_X_TLS_CACERTFILE: - *(char **)arg = tls_opt_cacertfile ? - LDAP_STRDUP( tls_opt_cacertfile ) : NULL; + *(char **)arg = lo->ldo_tls_cacertfile ? + LDAP_STRDUP( lo->ldo_tls_cacertfile ) : NULL; break; case LDAP_OPT_X_TLS_CACERTDIR: - *(char **)arg = tls_opt_cacertdir ? - LDAP_STRDUP( tls_opt_cacertdir ) : NULL; + *(char **)arg = lo->ldo_tls_cacertdir ? + LDAP_STRDUP( lo->ldo_tls_cacertdir ) : NULL; break; case LDAP_OPT_X_TLS_CERTFILE: - *(char **)arg = tls_opt_certfile ? - LDAP_STRDUP( tls_opt_certfile ) : NULL; + *(char **)arg = lo->ldo_tls_certfile ? + LDAP_STRDUP( lo->ldo_tls_certfile ) : NULL; break; case LDAP_OPT_X_TLS_KEYFILE: - *(char **)arg = tls_opt_keyfile ? - LDAP_STRDUP( tls_opt_keyfile ) : NULL; + *(char **)arg = lo->ldo_tls_keyfile ? + LDAP_STRDUP( lo->ldo_tls_keyfile ) : NULL; + break; + case LDAP_OPT_X_TLS_DHFILE: + *(char **)arg = lo->ldo_tls_dhfile ? + LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL; break; case LDAP_OPT_X_TLS_REQUIRE_CERT: - *(int *)arg = tls_opt_require_cert; + *(int *)arg = lo->ldo_tls_require_cert; break; #ifdef HAVE_OPENSSL_CRL case LDAP_OPT_X_TLS_CRLCHECK: - *(int *)arg = tls_opt_crlcheck; + *(int *)arg = lo->ldo_tls_crlcheck; break; #endif case LDAP_OPT_X_TLS_RANDOM_FILE: @@ -1259,6 +1336,8 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) switch( option ) { case LDAP_OPT_X_TLS: + if ( !arg ) return -1; + switch( *(int *) arg ) { case LDAP_OPT_X_TLS_NEVER: case LDAP_OPT_X_TLS_DEMAND: @@ -1274,12 +1353,9 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) return -1; case LDAP_OPT_X_TLS_CTX: - if ( ld == NULL ) { - tls_def_ctx = (SSL_CTX *) arg; - - } else { - ld->ld_defconn->lconn_tls_ctx = arg; - } + if ( lo->ldo_tls_ctx ) + SSL_CTX_free( lo->ldo_tls_ctx ); + lo->ldo_tls_ctx = arg; return 0; case LDAP_OPT_X_TLS_CONNECT_CB: lo->ldo_tls_connect_cb = (LDAP_TLS_CONNECT_CB *)arg; @@ -1287,59 +1363,68 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) case LDAP_OPT_X_TLS_CONNECT_ARG: lo->ldo_tls_connect_arg = arg; return 0; - } - - if ( ld != NULL ) { - return -1; - } - - switch( option ) { case LDAP_OPT_X_TLS_CACERTFILE: - if ( tls_opt_cacertfile ) LDAP_FREE( tls_opt_cacertfile ); - tls_opt_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; - break; + if ( lo->ldo_tls_cacertfile ) LDAP_FREE( lo->ldo_tls_cacertfile ); + lo->ldo_tls_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; case LDAP_OPT_X_TLS_CACERTDIR: - if ( tls_opt_cacertdir ) LDAP_FREE( tls_opt_cacertdir ); - tls_opt_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL; - break; + if ( lo->ldo_tls_cacertdir ) LDAP_FREE( lo->ldo_tls_cacertdir ); + lo->ldo_tls_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; case LDAP_OPT_X_TLS_CERTFILE: - if ( tls_opt_certfile ) LDAP_FREE( tls_opt_certfile ); - tls_opt_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; - break; + if ( lo->ldo_tls_certfile ) LDAP_FREE( lo->ldo_tls_certfile ); + lo->ldo_tls_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; case LDAP_OPT_X_TLS_KEYFILE: - if ( tls_opt_keyfile ) LDAP_FREE( tls_opt_keyfile ); - tls_opt_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; - break; + if ( lo->ldo_tls_keyfile ) LDAP_FREE( lo->ldo_tls_keyfile ); + lo->ldo_tls_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; + case LDAP_OPT_X_TLS_DHFILE: + if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile ); + lo->ldo_tls_dhfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; case LDAP_OPT_X_TLS_REQUIRE_CERT: + if ( !arg ) return -1; switch( *(int *) arg ) { case LDAP_OPT_X_TLS_NEVER: case LDAP_OPT_X_TLS_DEMAND: case LDAP_OPT_X_TLS_ALLOW: case LDAP_OPT_X_TLS_TRY: case LDAP_OPT_X_TLS_HARD: - tls_opt_require_cert = * (int *) arg; + lo->ldo_tls_require_cert = * (int *) arg; return 0; } return -1; #ifdef HAVE_OPENSSL_CRL case LDAP_OPT_X_TLS_CRLCHECK: + if ( !arg ) return -1; switch( *(int *) arg ) { case LDAP_OPT_X_TLS_CRL_NONE: case LDAP_OPT_X_TLS_CRL_PEER: case LDAP_OPT_X_TLS_CRL_ALL: - tls_opt_crlcheck = * (int *) arg; + lo->ldo_tls_crlcheck = * (int *) arg; return 0; } return -1; #endif case LDAP_OPT_X_TLS_CIPHER_SUITE: - if ( tls_opt_ciphersuite ) LDAP_FREE( tls_opt_ciphersuite ); - tls_opt_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL; - break; + if ( lo->ldo_tls_ciphersuite ) LDAP_FREE( lo->ldo_tls_ciphersuite ); + lo->ldo_tls_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; + case LDAP_OPT_X_TLS_RANDOM_FILE: + if ( ld != NULL ) + return -1; if (tls_opt_randfile ) LDAP_FREE (tls_opt_randfile ); tls_opt_randfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; + + case LDAP_OPT_X_TLS_NEWCTX: + if ( !arg ) return -1; + if ( lo->ldo_tls_ctx ) + SSL_CTX_free( lo->ldo_tls_ctx ); + lo->ldo_tls_ctx = NULL; + return ldap_int_tls_init_ctx( lo, *(int *)arg ); default: return -1; } @@ -1380,7 +1465,7 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) /* * compare host with name(s) in certificate */ - if (tls_opt_require_cert != LDAP_OPT_X_TLS_NEVER) { + if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER) { ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host ); if (ld->ld_errno != LDAP_SUCCESS) { return ld->ld_errno; @@ -1607,13 +1692,114 @@ tls_seed_PRNG( const char *randfile ) return 0; } -#if 0 +struct dhinfo { + int keylength; + const char *pem; + size_t size; +}; + + +/* From the OpenSSL 0.9.7 distro */ +static const char dhpem512[] = +"-----BEGIN DH PARAMETERS-----\n\ +MEYCQQDaWDwW2YUiidDkr3VvTMqS3UvlM7gE+w/tlO+cikQD7VdGUNNpmdsp13Yn\n\ +a6LT1BLiGPTdHghM9tgAPnxHdOgzAgEC\n\ +-----END DH PARAMETERS-----\n"; + +static const char dhpem1024[] = +"-----BEGIN DH PARAMETERS-----\n\ +MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq\n\ +/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx\n\ +/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC\n\ +-----END DH PARAMETERS-----\n"; + +static const char dhpem2048[] = +"-----BEGIN DH PARAMETERS-----\n\ +MIIBCAKCAQEA7ZKJNYJFVcs7+6J2WmkEYb8h86tT0s0h2v94GRFS8Q7B4lW9aG9o\n\ +AFO5Imov5Jo0H2XMWTKKvbHbSe3fpxJmw/0hBHAY8H/W91hRGXKCeyKpNBgdL8sh\n\ +z22SrkO2qCnHJ6PLAMXy5fsKpFmFor2tRfCzrfnggTXu2YOzzK7q62bmqVdmufEo\n\ +pT8igNcLpvZxk5uBDvhakObMym9mX3rAEBoe8PwttggMYiiw7NuJKO4MqD1llGkW\n\ +aVM8U2ATsCun1IKHrRxynkE1/MJ86VHeYYX8GZt2YA8z+GuzylIOKcMH6JAWzMwA\n\ +Gbatw6QwizOhr9iMjZ0B26TE3X8LvW84wwIBAg==\n\ +-----END DH PARAMETERS-----\n"; + +static const char dhpem4096[] = +"-----BEGIN DH PARAMETERS-----\n\ +MIICCAKCAgEA/urRnb6vkPYc/KEGXWnbCIOaKitq7ySIq9dTH7s+Ri59zs77zty7\n\ +vfVlSe6VFTBWgYjD2XKUFmtqq6CqXMhVX5ElUDoYDpAyTH85xqNFLzFC7nKrff/H\n\ +TFKNttp22cZE9V0IPpzedPfnQkE7aUdmF9JnDyv21Z/818O93u1B4r0szdnmEvEF\n\ +bKuIxEHX+bp0ZR7RqE1AeifXGJX3d6tsd2PMAObxwwsv55RGkn50vHO4QxtTARr1\n\ +rRUV5j3B3oPMgC7Offxx+98Xn45B1/G0Prp11anDsR1PGwtaCYipqsvMwQUSJtyE\n\ +EOQWk+yFkeMe4vWv367eEi0Sd/wnC+TSXBE3pYvpYerJ8n1MceI5GQTdarJ77OW9\n\ +bGTHmxRsLSCM1jpLdPja5jjb4siAa6EHc4qN9c/iFKS3PQPJEnX7pXKBRs5f7AF3\n\ +W3RIGt+G9IVNZfXaS7Z/iCpgzgvKCs0VeqN38QsJGtC1aIkwOeyjPNy2G6jJ4yqH\n\ +ovXYt/0mc00vCWeSNS1wren0pR2EiLxX0ypjjgsU1mk/Z3b/+zVf7fZSIB+nDLjb\n\ +NPtUlJCVGnAeBK1J1nG3TQicqowOXoM6ISkdaXj5GPJdXHab2+S7cqhKGv5qC7rR\n\ +jT6sx7RUr0CNTxzLI7muV2/a4tGmj0PSdXQdsZ7tw7gbXlaWT1+MM2MCAQI=\n\ +-----END DH PARAMETERS-----\n"; + +static const struct dhinfo dhpem[] = { + { 512, dhpem512, sizeof(dhpem512) }, + { 1024, dhpem1024, sizeof(dhpem1024) }, + { 2048, dhpem2048, sizeof(dhpem2048) }, + { 4096, dhpem4096, sizeof(dhpem4096) }, + { 0, NULL, 0 } +}; + static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ) { - return NULL; -} + struct dhplist *p = NULL; + BIO *b = NULL; + DH *dh = NULL; + int i; + + /* Do we have params of this length already? */ +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex ); +#endif + for ( p = dhparams; p; p=p->next ) { + if ( p->keylength == key_length ) { +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex ); +#endif + return p->param; + } + } + + /* No - check for hardcoded params */ + + for (i=0; dhpem[i].keylength; i++) { + if ( dhpem[i].keylength == key_length ) { + b = BIO_new_mem_buf( (char *)dhpem[i].pem, dhpem[i].size ); + break; + } + } + + if ( b ) { + dh = PEM_read_bio_DHparams( b, NULL, NULL, NULL ); + BIO_free( b ); + } + + /* Generating on the fly is expensive/slow... */ + if ( !dh ) { + dh = DH_generate_parameters( key_length, DH_GENERATOR_2, NULL, NULL ); + } + if ( dh ) { + p = LDAP_MALLOC( sizeof(struct dhplist) ); + if ( p != NULL ) { + p->keylength = key_length; + p->param = dh; + p->next = dhparams; + dhparams = p; + } + } + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex ); #endif + return dh; +} #endif void * @@ -1681,7 +1867,7 @@ ldap_install_tls( LDAP *ld ) #ifndef HAVE_TLS return LDAP_NOT_SUPPORTED; #else - if ( ld->ld_sb != NULL && ldap_pvt_tls_inplace( ld->ld_sb ) != 0 ) { + if ( ldap_tls_inplace( ld ) ) { return LDAP_LOCAL_ERROR; } @@ -1703,7 +1889,7 @@ ldap_start_tls_s ( LDAP *ld, /* XXYYZ: this initiates operation only on default connection! */ - if ( ld->ld_sb != NULL && ldap_pvt_tls_inplace( ld->ld_sb ) != 0 ) { + if ( ldap_tls_inplace( ld ) ) { return LDAP_LOCAL_ERROR; }