X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=libraries%2Flibldap%2Ftls.c;h=afe55f0775bf70f0f8044c822d3e6ba19d38d6cb;hb=2b0819c4a9209784f762ec154ce4721038522a8a;hp=b4d580f923c008197adafa6aa6e87c3e6ab21cf4;hpb=44a3160feced5d381640317a150d531a7f64aa42;p=openldap diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index b4d580f923..afe55f0775 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -31,6 +31,7 @@ #include #include #include +#include #elif defined( HAVE_SSL_H ) #include #endif @@ -97,6 +98,17 @@ static void tls_init_threads( void ) } #endif /* LDAP_R_COMPILE */ +/* + * Tear down the TLS subsystem. Should only be called once. + */ +void +ldap_pvt_tls_destroy( void ) +{ + SSL_CTX_free(tls_def_ctx); + EVP_cleanup(); + ERR_free_strings(); +} + /* * Initialize TLS subsystem. Should be called only once. */ @@ -143,7 +155,8 @@ ldap_pvt_tls_init_def_ctx( void ) } if ( tls_opt_ciphersuite && !SSL_CTX_set_cipher_list( tls_def_ctx, - tls_opt_ciphersuite ) ) { + tls_opt_ciphersuite ) ) + { Debug( LDAP_DEBUG_ANY, "TLS: could not set cipher list %s.\n", tls_opt_ciphersuite, 0, 0 ); @@ -156,17 +169,21 @@ ldap_pvt_tls_init_def_ctx( void ) tls_opt_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_cacertdir,0); + 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(); 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); + 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 : "", + 0 ); tls_report_error(); goto error_exit; } @@ -175,7 +192,8 @@ ldap_pvt_tls_init_def_ctx( void ) if ( tls_opt_keyfile && !SSL_CTX_use_PrivateKey_file( tls_def_ctx, tls_opt_keyfile, - SSL_FILETYPE_PEM ) ) { + SSL_FILETYPE_PEM ) ) + { Debug( LDAP_DEBUG_ANY, "TLS: could not use key file `%s'.\n", tls_opt_keyfile,0,0); @@ -185,7 +203,8 @@ ldap_pvt_tls_init_def_ctx( void ) if ( tls_opt_certfile && !SSL_CTX_use_certificate_file( tls_def_ctx, tls_opt_certfile, - SSL_FILETYPE_PEM ) ) { + SSL_FILETYPE_PEM ) ) + { Debug( LDAP_DEBUG_ANY, "TLS: could not use certificate `%s'.\n", tls_opt_certfile,0,0); @@ -193,7 +212,8 @@ ldap_pvt_tls_init_def_ctx( void ) goto error_exit; } if ( ( tls_opt_certfile || tls_opt_keyfile ) && - !SSL_CTX_check_private_key( tls_def_ctx ) ) { + !SSL_CTX_check_private_key( tls_def_ctx ) ) + { Debug( LDAP_DEBUG_ANY, "TLS: private key mismatch.\n", 0,0,0); @@ -478,7 +498,7 @@ sb_tls_bio_read( BIO *b, char *buf, int len ) } static int -sb_tls_bio_write( BIO *b, char *buf, int len ) +sb_tls_bio_write( BIO *b, const char *buf, int len ) { struct tls_data *p; int ret; @@ -491,7 +511,7 @@ sb_tls_bio_write( BIO *b, char *buf, int len ) if ( p == NULL || p->sbiod == NULL ) return 0; - ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, buf, len ); + ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len ); BIO_clear_retry_flags( b ); if ( ret < 0 && errno == EWOULDBLOCK ) @@ -501,7 +521,7 @@ sb_tls_bio_write( BIO *b, char *buf, int len ) } static long -sb_tls_bio_ctrl( BIO *b, int cmd, long num, char *ptr ) +sb_tls_bio_ctrl( BIO *b, int cmd, long num, void *ptr ) { if ( cmd == BIO_CTRL_FLUSH ) { /* The OpenSSL library needs this */ @@ -517,7 +537,7 @@ sb_tls_bio_gets( BIO *b, char *buf, int len ) } static int -sb_tls_bio_puts( BIO *b, char *str ) +sb_tls_bio_puts( BIO *b, const char *str ) { return sb_tls_bio_write( b, str, strlen( str ) ); } @@ -745,6 +765,94 @@ ldap_pvt_tls_get_peer_hostname( void *s ) return p; } +int +ldap_pvt_tls_check_hostname( void *s, char *name ) +{ + int i, ret = LDAP_LOCAL_ERROR; + X509 *x; + + x = SSL_get_peer_certificate((SSL *)s); + if (!x) + { + Debug( LDAP_DEBUG_ANY, + "TLS: unable to get peer certificate.\n", + 0, 0, 0 ); + return ret; + } + + i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); + if (i >= 0) + { + X509_EXTENSION *ex; + STACK_OF(GENERAL_NAME) *alt; + + ex = X509_get_ext(x, i); + alt = X509V3_EXT_d2i(ex); + if (alt) + { + int n, len1, len2; + char *domain; + GENERAL_NAME *gn; + X509V3_EXT_METHOD *method; + + len1 = strlen(name); + n = sk_GENERAL_NAME_num(alt); + domain = strchr(name, '.'); + if (domain) + len2 = len1 - (domain-name); + for (i=0; itype == GEN_DNS) + { + char *sn = ASN1_STRING_data(gn->d.ia5); + int sl = ASN1_STRING_length(gn->d.ia5); + + /* Is this an exact match? */ + if ((len1 == sl) && !strncasecmp(name, sn, len1)) + break; + + /* Is this a wildcard match? */ + if ((*sn == '*') && domain && (len2 == sl-1) && + !strncasecmp(domain, sn+1, len2)) + break; + } + } + method = X509V3_EXT_get(ex); + method->ext_free(alt); + if (i < n) /* Found a match */ + ret = LDAP_SUCCESS; + } + } + + if (ret != LDAP_SUCCESS) + { + X509_NAME *xn; + char buf[2048]; + + xn = X509_get_subject_name(x); + + if (X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)) + == -1) + { + Debug( LDAP_DEBUG_ANY, + "TLS: unable to get common name from peer certificate.\n", + 0, 0, 0 ); + } else if (strcasecmp(name, buf)) + { + Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " + "common name in certificate (%s).\n", + name, buf, 0 ); + ret = LDAP_CONNECT_ERROR; + } else + { + ret = LDAP_SUCCESS; + } + } + X509_free(x); + return ret; +} + const char * ldap_pvt_tls_get_peer_issuer( void *s ) { @@ -778,13 +886,13 @@ ldap_int_tls_config( LDAP *ld, int option, const char *arg ) case LDAP_OPT_X_TLS_CERTFILE: case LDAP_OPT_X_TLS_KEYFILE: case LDAP_OPT_X_TLS_RANDOM_FILE: - return ldap_pvt_tls_set_option( NULL, option, (void *) arg ); + return ldap_pvt_tls_set_option( ld, option, (void *) arg ); case LDAP_OPT_X_TLS_REQUIRE_CERT: i = ( ( strcasecmp( arg, "on" ) == 0 ) || ( strcasecmp( arg, "yes" ) == 0) || ( strcasecmp( arg, "true" ) == 0 ) ); - return ldap_pvt_tls_set_option( NULL, option, (void *) &i ); + return ldap_pvt_tls_set_option( ld, option, (void *) &i ); case LDAP_OPT_X_TLS: i = -1; @@ -958,9 +1066,7 @@ int ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) { Sockbuf *sb = conn->lconn_sb; - void *ctx = ld->ld_defconn->lconn_tls_ctx; char *host; - char *peer_cert_cn; void *ssl; if( srv ) { @@ -969,41 +1075,30 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) host = conn->lconn_server->lud_host; } + /* avoid NULL host */ + if( host == NULL ) host = "localhost"; + (void) ldap_pvt_tls_init(); /* * Fortunately, the lib uses blocking io... */ if ( ldap_int_tls_connect( ld, conn ) < 0 ) { - return LDAP_CONNECT_ERROR; + ld->ld_errno = LDAP_CONNECT_ERROR; + return (ld->ld_errno); } ssl = (void *) ldap_pvt_tls_sb_ctx( sb ); assert( ssl != NULL ); /* - * compare host with name in certificate + * compare host with name(s) in certificate */ - - peer_cert_cn = ldap_pvt_tls_get_peer_hostname( ssl ); - if ( !peer_cert_cn ) { - /* could not get hostname from peer certificate */ - Debug( LDAP_DEBUG_ANY, - "TLS: unable to get common name from peer certificate.\n", - 0, 0, 0 ); - return LDAP_LOCAL_ERROR; - } - - if ( strcasecmp( host, peer_cert_cn ) != 0 ) { - Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " - "common name in certificate (%s).\n", - host, peer_cert_cn, 0 ); - LDAP_FREE( peer_cert_cn ); - return LDAP_CONNECT_ERROR; + ld->ld_errno = ldap_pvt_tls_check_hostname( ssl, host ); + if (ld->ld_errno != LDAP_SUCCESS) { + return ld->ld_errno; } - LDAP_FREE( peer_cert_cn ); - /* * set SASL properties to TLS ssf and authid */ @@ -1015,7 +1110,7 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) ssf = ldap_pvt_tls_get_strength( ssl ); authid = ldap_pvt_tls_get_peer( ssl ); - (void) ldap_int_sasl_external( ld, authid, ssf ); + (void) ldap_int_sasl_external( ld, conn, authid, ssf ); } return LDAP_SUCCESS;