From: Howard Chu Date: Sun, 2 Sep 2001 11:23:28 +0000 (+0000) Subject: Full implementation of server identity checking per RFC2830 section 3.6 X-Git-Tag: LDBM_PRE_GIANT_RWLOCK~1134 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=b10e0029a5fd49f36f5ca2e75a1fc41285a3d72c;p=openldap Full implementation of server identity checking per RFC2830 section 3.6 --- diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index b4d580f923..c4a683edc2 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -745,6 +745,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 ) { @@ -960,8 +1048,8 @@ 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; + int ret; if( srv ) { host = srv->lud_host; @@ -982,27 +1070,12 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) 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; - } - - LDAP_FREE( peer_cert_cn ); + ret = ldap_pvt_tls_check_hostname( ssl, host ); + if (ret != LDAP_SUCCESS) + return ret; /* * set SASL properties to TLS ssf and authid