Accidently I mailed an unfinished version of the patch. Attached is the
correct version, that seems to run on my system.


Regards,
Matthias

-- 
Matthias Wimmer            USt-IdNr. DE244176643
Contact details:     http://matthias.wimmer.tel/
Description: <short summary of the patch>
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 mod-gnutls (0.5.10-1.1) unstable; urgency=low
 .
   [ Bastiaan Franciscus van den Dikkenberg ]
   * Non-maintainer upload.
   * Fix "default-tls file for apache" Added default-tls file
     (Closes: #558232)
   * Fix "configure: *** memcache library not found."
     added build-depensie to libapr-memcache-dev (Closes: #497097)
   * apache2-dev is releplaced by apache2-threaded-dev (Closes: #667626)
   * DEP-5 url changed in copyright file to new standard
Author: Bastiaan Franciscus van den Dikkenberg <[email protected]>
Bug-Debian: http://bugs.debian.org/497097
Bug-Debian: http://bugs.debian.org/558232
Bug-Debian: http://bugs.debian.org/667626

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: http://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: <YYYY-MM-DD>

--- mod-gnutls-0.5.10.orig/src/gnutls_hooks.c
+++ mod-gnutls-0.5.10/src/gnutls_hooks.c
@@ -243,75 +243,104 @@ 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, char ***cert_cn)
 {
 	int rv = 0, i;
 	size_t data_len;
+	size_t buffer_len;
+	int number_names;
+	int copied_names;
+	char *buffer;
 
 
 	_gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
-	*cert_cn = NULL;
 
-	data_len = 0;
+	// find number of alt names
+	number_names = 0;
+	buffer_len = 0;
+	buffer = NULL;
+	do {
+	    	data_len = buffer_len;
+		rv = gnutls_x509_crt_get_subject_alt_name(cert, number_names, buffer, &data_len, NULL);
+
+		// the first buffer we allocate, or we need bigger buffer
+		if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
+			// be prepared for longer names coming later without need to reallocate memory
+			buffer_len = data_len * 2;
+			buffer = apr_palloc(p, buffer_len);
+
+			data_len = buffer_len;
+			rv = gnutls_x509_crt_get_subject_alt_name(cert, number_names, buffer, &data_len, NULL);
+		}
+
+		// one more name available, the last one we count is a fail we can use to store the CN
+		number_names++;
+	} while (rv >= 0);
+
+	// allocate memory of the list of names, plus one for the terminating NULL
+	*cert_cn = apr_palloc(p, sizeof(char*) * (number_names + 2));
+
+	// first name we try to get is CN
+	copied_names = 0;
+	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;
+		buffer = apr_palloc(p, 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) {
+		(*cert_cn)[0] = apr_palloc(p, data_len + 1);
+		apr_cpystrn((*cert_cn)[0], buffer, data_len + 1);
+		copied_names++;
+	}
+
+	// now we have to find subject alternative names
+	for (i = 0; i < number_names - 1 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER; i++) {
+	    	data_len = buffer_len;
+		rv = gnutls_x509_crt_get_subject_alt_name(cert, i, buffer, &data_len, NULL);
+
+		// we only ever increased buffer size, should get no memory problem anymore
+
+		// on success, copy result in the list
+		if (rv == GNUTLS_SAN_DNSNAME) {
+			(*cert_cn)[copied_names] = apr_palloc(p, data_len + 1);
+			apr_cpystrn((*cert_cn)[copied_names], buffer, data_len + 1);
+			copied_names++;
 		}
 	}
 
-	return rv;
+	// terminate list
+	(*cert_cn)[copied_names + 1] = NULL;
+
+	return copied_names >= 1 ? 0 : -1;
 }
 
 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, char ***cert_cn)
 {
 	int rv = 0;
 	size_t data_len;
 
 
 	_gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
-	*cert_cn = NULL;
+	*cert_cn = apr_palloc(p, sizeof(char*) * 2);
+	(*cert_cn)[0] = NULL;
+	(*cert_cn)[1] = NULL;
 
 	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,
+		(*cert_cn)[0] = apr_palloc(p, data_len);
+		rv = gnutls_openpgp_crt_get_name(cert, 0, (*cert_cn)[0],
 						 &data_len);
 	} else {		/* No CN return subject alternative name */
 		ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
@@ -558,6 +587,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 +599,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; tsc->cert_cn[tried_name] != NULL; tried_name++) {
+
+		/* The CN can contain a * -- this will match those too. */
+		if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn[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'", tsc->cert_cn[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'", tsc->cert_cn[tried_name], x->sni_name);
 #endif
+		}
 
 	}
 	return 0;
@@ -602,6 +636,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 +696,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,
+			     tsc->cert_cn[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; tsc->cert_cn[i] != NULL; i++) [
+			if (ap_strcasecmp_match(sni_name, tsc->cert_cn[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'", tsc->cert_cn[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;
+    char** 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