I have updated the patch I recently submitted. It should be more Apache
style now. Manual array handling has been replaced with APR
functionality.

-- 
Matthias Wimmer            USt-IdNr. DE244176643
Contact details:     http://matthias.wimmer.tel/
--- mod-gnutls-0.5.10.orig/src/gnutls_hooks.c
+++ mod-gnutls-0.5.10/src/gnutls_hooks.c
@@ -243,76 +243,82 @@ const char static_dh_params[] = "-----BE
  * Returns negative on error.
  */
 static int read_crt_cn(server_rec * s, apr_pool_t * p,
-		       gnutls_x509_crt_t cert, char **cert_cn)
+		       gnutls_x509_crt_t cert, apr_array_header_t **cert_cn)
 {
 	int rv = 0, i;
 	size_t data_len;
+	size_t buffer_len;
+	char *buffer;
 
 
 	_gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
-	*cert_cn = NULL;
 
-	data_len = 0;
+	/* prepare the array of names of a certificate */
+	*cert_cn = apr_array_make(p, 1, sizeof(const char*));
+
+	/* first name we try to get is the CN */
+	data_len = buffer_len;
 	rv = gnutls_x509_crt_get_dn_by_oid(cert,
 					   GNUTLS_OID_X520_COMMON_NAME,
-					   0, 0, NULL, &data_len);
+					   0, 0, buffer, &data_len);
 
 	if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
-		*cert_cn = apr_palloc(p, data_len);
+	    	buffer_len = data_len * 2;
+		buffer = apr_palloc(p, buffer_len);
+		data_len = buffer_len;
 		rv = gnutls_x509_crt_get_dn_by_oid(cert,
 						   GNUTLS_OID_X520_COMMON_NAME,
-						   0, 0, *cert_cn,
+						   0, 0, buffer,
 						   &data_len);
-	} else {		/* No CN return subject alternative name */
-		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-			     "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
-			     s->server_hostname, s->port);
-		rv = 0;
-		/* read subject alternative name */
-		for (i = 0; !(rv < 0); i++) {
-			data_len = 0;
-			rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
-								  NULL,
-								  &data_len,
-								  NULL);
-
-			if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
-			    && data_len > 1) {
-				/* FIXME: not very efficient. What if we have several alt names
-				 * before DNSName?
-				 */
-				*cert_cn = apr_palloc(p, data_len + 1);
-
-				rv = gnutls_x509_crt_get_subject_alt_name
-				    (cert, i, *cert_cn, &data_len, NULL);
-				(*cert_cn)[data_len] = 0;
+	}
 
-				if (rv == GNUTLS_SAN_DNSNAME)
-					break;
-			}
+	if (rv >= 0) {
+		*(const char**)apr_array_push(*cert_cn) = apr_pstrdup(p, buffer);
+	}
+
+	/* now we have to find subject alternative names */
+	for (i = 0; rv >= 0; i++) {
+	    	data_len = buffer_len;
+		rv = gnutls_x509_crt_get_subject_alt_name(cert, i, buffer, &data_len, NULL);
+
+		/* need bigger buffer? */
+		if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
+			buffer_len = data_len * 2;
+			buffer = apr_palloc(p, buffer_len);
+			data_len = buffer_len;
+
+			rv = gnutls_x509_crt_get_subject_alt_name(cert, i, buffer, &data_len, NULL);
+		}
+
+		/* on success, copy result in the list */
+		if (rv == GNUTLS_SAN_DNSNAME) {
+			*(const char**)apr_array_push(*cert_cn) = apr_pstrdup(p, buffer);
 		}
 	}
 
-	return rv;
+	return apr_is_empty_array(*cert_cn) ? -1 : 0;
 }
 
 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
-			  gnutls_openpgp_crt_t cert, char **cert_cn)
+			  gnutls_openpgp_crt_t cert, apr_array_header_t **cert_cn)
 {
 	int rv = 0;
 	size_t data_len;
+	char *buffer;
 
 
 	_gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
-	*cert_cn = NULL;
+	/* prepare the array of names of a certificate */
+	*cert_cn = apr_array_make(p, 1, sizeof(const char*));
 
 	data_len = 0;
 	rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
 
 	if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
-		*cert_cn = apr_palloc(p, data_len);
-		rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
-						 &data_len);
+		buffer = apr_palloc(p, data_len);
+		rv = gnutls_openpgp_crt_get_name(cert, 0, buffer, &data_len);
+		/* we do not reuse the buffer, can just use it */
+		*(const char**)apr_array_push(*cert_cn) = buffer;
 	} else {		/* No CN return subject alternative name */
 		ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
 			     "No name found in PGP certificate for '%s:%d'.",
@@ -558,6 +564,7 @@ typedef struct {
 
 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s)
 {
+	int tried_name = 0;
 	mgs_srvconf_rec *tsc;
 	vhost_cb_rec *x = baton;
 
@@ -569,31 +576,35 @@ static int vhost_cb(void *baton, conn_re
 		return 0;
 	}
 
-	/* The CN can contain a * -- this will match those too. */
-	if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
-		/* found a match */
+	/* try all names of the host */
+	for (tried_name = 0; tried_name < tsc->cert_cn->nelts; tried_name++) {
+
+		/* The CN can contain a * -- this will match those too. */
+		if (ap_strcasecmp_match(x->sni_name, ((const char**)tsc->cert_cn->elts)[tried_name]) == 0) {
+			/* found a match */
 #if MOD_GNUTLS_DEBUG
-		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-			     x->ctxt->c->base_server,
-			     "GnuTLS: Virtual Host CB: "
-			     "'%s' == '%s'", tsc->cert_cn, x->sni_name);
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+				     x->ctxt->c->base_server,
+				     "GnuTLS: Virtual Host CB: "
+				     "'%s' == '%s'", ((const char**)tsc->cert_cn->elts)[tried_name], x->sni_name);
 #endif
-		/* Because we actually change the server used here, we need to reset
-		 * things like ClientVerify.
-		 */
-		x->sc = tsc;
-		/* Shit. Crap. Dammit. We *really* should rehandshake here, as our
-		 * certificate structure *should* change when the server changes. 
-		 * acccckkkkkk. 
-		 */
-		return 1;
-	} else {
+			/* Because we actually change the server used here, we need to reset
+			 * things like ClientVerify.
+			 */
+			x->sc = tsc;
+			/* Shit. Crap. Dammit. We *really* should rehandshake here, as our
+			 * certificate structure *should* change when the server changes. 
+			 * acccckkkkkk. 
+			 */
+			return 1;
+		} else {
 #if MOD_GNUTLS_DEBUG
-		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-			     x->ctxt->c->base_server,
-			     "GnuTLS: Virtual Host CB: "
-			     "'%s' != '%s'", tsc->cert_cn, x->sni_name);
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+				     x->ctxt->c->base_server,
+				     "GnuTLS: Virtual Host CB: "
+				     "'%s' != '%s'", ((const char**)tsc->cert_cn->elts)[tried_name], x->sni_name);
 #endif
+		}
 
 	}
 	return 0;
@@ -602,6 +613,7 @@ static int vhost_cb(void *baton, conn_re
 
 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
 {
+	int i;
 	int rv;
 	unsigned int sni_type;
 	size_t data_len = MAX_HOST_LEN;
@@ -661,22 +673,24 @@ mgs_srvconf_rec *mgs_find_sni_server(gnu
 		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
 			     ctxt->c->base_server,
 			     "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X",
-			     tsc->cert_cn, rv,
+			     ((const char**)tsc->cert_cn->elts)[0], rv,
 			     gnutls_pk_algorithm_get_name
 			     (gnutls_x509_privkey_get_pk_algorithm
 			      (ctxt->sc->privkey_x509)), (unsigned int) s,
 			     (unsigned int) s->next, (unsigned int) tsc);
 #endif
 		/* The CN can contain a * -- this will match those too. */
-		if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
+		for (i = 0; i < tsc->cert_cn->nelts; i++) {
+			if (ap_strcasecmp_match(sni_name, ((const char**)tsc->cert_cn->elts)[i]) == 0) {
 #if MOD_GNUTLS_DEBUG
-			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-				     ctxt->c->base_server,
-				     "GnuTLS: Virtual Host: "
-				     "'%s' == '%s'", tsc->cert_cn,
-				     sni_name);
+				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+					     ctxt->c->base_server,
+					     "GnuTLS: Virtual Host: "
+					     "'%s' == '%s'", ((const char**)tsc->cert_cn->elts)[i],
+					     sni_name);
 #endif
-			return tsc;
+				return tsc;
+			}
 		}
 	}
 #endif
--- mod-gnutls-0.5.10.orig/include/mod_gnutls.h.in
+++ mod-gnutls-0.5.10/include/mod_gnutls.h.in
@@ -86,7 +86,7 @@ typedef struct
     gnutls_certificate_credentials_t certs;
     gnutls_srp_server_credentials_t srp_creds;
     gnutls_anon_server_credentials_t anon_creds;
-    char* cert_cn;
+    apr_array_header_t *cert_cn;
     gnutls_x509_crt_t certs_x509[MAX_CHAIN_SIZE]; /* A certificate chain */
     unsigned int certs_x509_num;
     gnutls_x509_privkey_t privkey_x509;

Reply via email to