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;