From: Howard Chu Date: Thu, 22 Jul 2021 20:07:21 +0000 (+0100) Subject: ITS#6248 support multiple CAcert dirs X-Git-Tag: OPENLDAP_REL_ENG_2_6_0~164 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dfcaa3f01e5796452d606b904c223446a198beaf;p=thirdparty%2Fopenldap.git ITS#6248 support multiple CAcert dirs --- diff --git a/doc/man/man3/ldap_get_option.3 b/doc/man/man3/ldap_get_option.3 index 25027ac7f2..fc5311e543 100644 --- a/doc/man/man3/ldap_get_option.3 +++ b/doc/man/man3/ldap_get_option.3 @@ -642,7 +642,8 @@ The TLS options are OpenLDAP specific. .\"Sets/gets the TLS mode. .TP .B LDAP_OPT_X_TLS_CACERTDIR -Sets/gets the path of the directory containing CA certificates. +Sets/gets the path of the directories containing CA certificates. +Multiple directories may be specified, separated by a semi-colon. .BR invalue must be .BR "const char *" ; diff --git a/doc/man/man5/ldap.conf.5 b/doc/man/man5/ldap.conf.5 index 17b7154991..3173014238 100644 --- a/doc/man/man5/ldap.conf.5 +++ b/doc/man/man5/ldap.conf.5 @@ -333,8 +333,9 @@ Specifies the file that contains certificates for all of the Certificate Authorities the client will recognize. .TP .B TLS_CACERTDIR -Specifies the path of a directory that contains Certificate Authority -certificates in separate individual files. The +Specifies the path of directories that contain Certificate Authority +certificates in separate individual files. Multiple directories may +be specified, separated by a semi-colon. The .B TLS_CACERT is always used before .B TLS_CACERTDIR. diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index f7e9029ffc..fdf0ae744d 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -926,10 +926,11 @@ the top-level CA should be present. Multiple certificates are simply appended to the file; the order is not significant. .TP .B olcTLSCACertificatePath: -Specifies the path of a directory that contains Certificate Authority +Specifies the path of directories that contain Certificate Authority certificates in separate individual files. Usually only one of this or the olcTLSCACertificateFile is defined. If both are specified, both -locations will be used. +locations will be used. Multiple directories may be specified, +separated by a semi-colon. .TP .B olcTLSCertificateFile: Specifies the file that contains the diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index b0b2f4a901..d0b8f18dc6 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -1156,10 +1156,11 @@ the top-level CA should be present. Multiple certificates are simply appended to the file; the order is not significant. .TP .B TLSCACertificatePath -Specifies the path of a directory that contains Certificate Authority +Specifies the path of directories that contain Certificate Authority certificates in separate individual files. Usually only one of this or the TLSCACertificateFile is used. If both are specified, both -locations will be used. +locations will be used. Multiple directories may be specified, +separated by a semi-colon. .TP .B TLSCertificateFile Specifies the file that contains the diff --git a/libraries/libldap/ldap-tls.h b/libraries/libldap/ldap-tls.h index 423d18195f..5ee28b964d 100644 --- a/libraries/libldap/ldap-tls.h +++ b/libraries/libldap/ldap-tls.h @@ -22,6 +22,8 @@ struct tls_impl; struct tls_ctx; struct tls_session; +#define CERTPATHSEP ";" + typedef struct tls_ctx tls_ctx; typedef struct tls_session tls_session; diff --git a/libraries/libldap/tls_g.c b/libraries/libldap/tls_g.c index 17bcc69f15..14a700f24b 100644 --- a/libraries/libldap/tls_g.c +++ b/libraries/libldap/tls_g.c @@ -195,21 +195,26 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server, char * } if (lo->ldo_tls_cacertdir != NULL) { - rc = gnutls_certificate_set_x509_trust_dir( - ctx->cred, - lt->lt_cacertdir, - GNUTLS_X509_FMT_PEM ); - if ( rc > 0 ) { - Debug2( LDAP_DEBUG_TRACE, - "TLS: loaded %d CA certificates from directory `%s'.\n", - rc, lt->lt_cacertdir ); - } else { - Debug1( LDAP_DEBUG_ANY, - "TLS: warning: no certificate found in CA certificate directory `%s'.\n", - lt->lt_cacertdir ); - /* only warn, no return */ - strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); + char **dirs = ldap_str2charray( lt->lt_cacertdir, CERTPATHSEP ); + int i; + for ( i=0; dirs[i]; i++ ) { + rc = gnutls_certificate_set_x509_trust_dir( + ctx->cred, + dirs[i], + GNUTLS_X509_FMT_PEM ); + if ( rc > 0 ) { + Debug2( LDAP_DEBUG_TRACE, + "TLS: loaded %d CA certificates from directory `%s'.\n", + rc, dirs[i] ); + } else { + Debug1( LDAP_DEBUG_ANY, + "TLS: warning: no certificate found in CA certificate directory `%s'.\n", + dirs[i] ); + /* only warn, no return */ + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); + } } + ldap_charray_free( dirs ); } if (lo->ldo_tls_cacertfile != NULL) { diff --git a/libraries/libldap/tls_o.c b/libraries/libldap/tls_o.c index 175bb14181..9c1f019499 100644 --- a/libraries/libldap/tls_o.c +++ b/libraries/libldap/tls_o.c @@ -170,21 +170,24 @@ tlso_ca_list( char * bundle, char * dir, X509 *cert ) if ( bundle ) { ca_list = SSL_load_client_CA_file( bundle ); } -#if defined(HAVE_DIRENT_H) || defined(dirent) if ( dir ) { - int freeit = 0; + char **dirs = ldap_str2charray( dir, CERTPATHSEP ); + int freeit = 0, i; 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; + for ( i=0; dirs[i]; i++ ) { + if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) && + freeit ) { + sk_X509_NAME_free( ca_list ); + ca_list = NULL; + break; + } } + ldap_charray_free( dirs ); } -#endif if ( cert ) { X509_NAME *xn = X509_get_subject_name( cert ); xn = X509_NAME_dup( xn ); @@ -445,15 +448,37 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server, char * return -1; } } - if (( lt->lt_cacertfile || lt->lt_cacertdir ) && !SSL_CTX_load_verify_locations( ctx, - lt->lt_cacertfile, lt->lt_cacertdir ) ) - { - Debug2( 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 : "" ); - tlso_report_error( errmsg ); - return -1; + if ( lt->lt_cacertfile || lt->lt_cacertdir ) { + char **dirs, *dummy = NULL; + if ( lt->lt_cacertdir ) { + dirs = ldap_str2charray( lt->lt_cacertdir, CERTPATHSEP ); + } else { + dirs = &dummy; + } + /* Start with the first dir in path */ + if ( !SSL_CTX_load_verify_locations( ctx, + lt->lt_cacertfile, dirs[0] ) ) + { + Debug2( LDAP_DEBUG_ANY, "TLS: " + "could not load verify locations (file:`%s',dir:`%s').\n", + lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", + dirs[0] ? dirs[0] : "" ); + tlso_report_error( errmsg ); + if ( dirs != &dummy ) + ldap_charray_free( dirs ); + return -1; + } + /* Then additional dirs, if any */ + if ( dirs != &dummy ) { + if ( dirs[1] ) { + int i; + X509_STORE *store = SSL_CTX_get_cert_store( ctx ); + X509_LOOKUP *lookup = X509_STORE_add_lookup( store, X509_LOOKUP_hash_dir() ); + for ( i=1; dirs[i]; i++ ) + X509_LOOKUP_add_dir( lookup, dirs[i], X509_FILETYPE_PEM ); + } + ldap_charray_free( dirs ); + } } if ( is_server ) {