From 7b65f898c65e1530a006d8f96d26fe5b59521d10 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga <kurt@openldap.org> Date: Tue, 4 Sep 2001 00:13:46 +0000 Subject: [PATCH] Import RFC 2830 cert check --- libraries/libldap/tls.c | 115 +++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 20 deletions(-) diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index b4d580f923..90a11429d8 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; i<n; i++) + { + gn = sk_GENERAL_NAME_value(alt, i); + if (gn->type == 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,7 +1048,6 @@ 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 ) { @@ -975,35 +1062,23 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) * 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 */ -- GitLab