--- openldap-2.3.43/libraries/libldap/tls.c.orig 2010-02-08 13:58:47.000000000 +0100 +++ openldap-2.3.43/libraries/libldap/tls.c 2010-02-08 14:10:37.000000000 +0100 @@ -981,7 +981,7 @@ ldap_pvt_tls_check_hostname( LDAP *ld, v X509 *x; const char *name; char *ptr; - int ntype = IS_DNS; + int ntype = IS_DNS, nlen; #ifdef LDAP_PF_INET6 struct in6_addr addr; #else @@ -995,6 +995,7 @@ ldap_pvt_tls_check_hostname( LDAP *ld, v } else { name = name_in; } + nlen = strlen(name); x = tls_get_cert((SSL *)s); if (!x) { @@ -1028,15 +1029,14 @@ ldap_pvt_tls_check_hostname( LDAP *ld, v ex = X509_get_ext(x, i); alt = X509V3_EXT_d2i(ex); if (alt) { - int n, len1 = 0, len2 = 0; + int n, len2 = 0; char *domain = NULL; GENERAL_NAME *gn; if (ntype == IS_DNS) { - len1 = strlen(name); domain = strchr(name, '.'); if (domain) { - len2 = len1 - (domain-name); + len2 = nlen - (domain-name); } } n = sk_GENERAL_NAME_num(alt); @@ -1054,7 +1054,7 @@ ldap_pvt_tls_check_hostname( LDAP *ld, v if (sl == 0) continue; /* Is this an exact match? */ - if ((len1 == sl) && !strncasecmp(name, sn, len1)) { + if ((nlen == sl) && !strncasecmp(name, sn, nlen)) { break; } @@ -1094,13 +1094,28 @@ ldap_pvt_tls_check_hostname( LDAP *ld, v if (ret != LDAP_SUCCESS) { X509_NAME *xn; - char buf[2048]; - buf[0] = '\0'; + X509_NAME_ENTRY *ne; + ASN1_OBJECT *obj; + ASN1_STRING *cn = NULL; + int navas; + + /* find the last CN */ + obj = OBJ_nid2obj( NID_commonName ); + if ( !obj ) goto no_cn; /* should never happen */ xn = X509_get_subject_name(x); - if( X509_NAME_get_text_by_NID( xn, NID_commonName, - buf, sizeof(buf)) == -1) - { + navas = X509_NAME_entry_count( xn ); + for ( i=navas-1; i>=0; i-- ) { + ne = X509_NAME_get_entry( xn, i ); + if ( !OBJ_cmp( ne->object, obj )) { + cn = X509_NAME_ENTRY_get_data( ne ); + break; + } + } + + if( !cn ) + { +no_cn: Debug( LDAP_DEBUG_ANY, "TLS: unable to get common name from peer certificate.\n", 0, 0, 0 ); @@ -1111,21 +1126,20 @@ ldap_pvt_tls_check_hostname( LDAP *ld, v ld->ld_error = LDAP_STRDUP( _("TLS: unable to get CN from peer certificate")); - } else if (strcasecmp(name, buf) == 0 ) { + } else if ( cn->length == nlen && + strncasecmp( name, (char *) cn->data, nlen ) == 0 ) { ret = LDAP_SUCCESS; - } else if (( buf[0] == '*' ) && ( buf[1] == '.' )) { + } else if (( cn->data[0] == '*' ) && ( cn->data[1] == '.' )) { char *domain = strchr(name, '.'); if( domain ) { - size_t dlen = 0; - size_t sl; + size_t dlen; - sl = strlen(name); - dlen = sl - (domain-name); - sl = strlen(buf); + dlen = nlen - (domain-name); /* Is this a wildcard match? */ - if ((dlen == sl-1) && !strncasecmp(domain, &buf[1], dlen)) { + if ((dlen == cn->length-1) && + !strncasecmp(domain, (char *) &cn->data[1], dlen)) { ret = LDAP_SUCCESS; } } @@ -1133,8 +1147,8 @@ ldap_pvt_tls_check_hostname( LDAP *ld, v if( ret == LDAP_LOCAL_ERROR ) { Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " - "common name in certificate (%s).\n", - name, buf, 0 ); + "common name in certificate (%.*s).\n", + name, cn->length, cn->data ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error );