]> git.ipfire.org Git - people/trikolon/ipfire-2.x.git/commitdiff
pound: Add patch to select certificates by their SANs.
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 6 Apr 2012 11:42:27 +0000 (13:42 +0200)
committerArne Fitzenreiter <arne_f@ipfire.org>
Sat, 7 Apr 2012 09:35:46 +0000 (11:35 +0200)
http://www.apsis.ch/pound/pound_list/archive/2012/2012-02/1329442080000#1329442080000

lfs/pound
src/patches/Pound-2.6-reneg-ciphers-altnames-nosslv2.patch [new file with mode: 0644]

index 1b9e523a1d8988f32879ec45a68e701a66509ae6..f2a7f5fecd821d2eff9a249ebeaa0170598a7976 100644 (file)
--- a/lfs/pound
+++ b/lfs/pound
@@ -32,7 +32,7 @@ DL_FROM    = $(URL_IPFIRE)
 DIR_APP    = $(DIR_SRC)/$(THISAPP)
 TARGET     = $(DIR_INFO)/$(THISAPP)
 PROG       = pound
-PAK_VER    = 3
+PAK_VER    = 4
 
 DEPS       = ""
 
@@ -78,6 +78,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
        cd $(DIR_APP) && patch -p4 < $(DIR_SRC)/src/patches/pound-2.6.patch
+       cd $(DIR_APP) && patch -p1 < $(DIR_SRC)/src/patches/Pound-2.6-reneg-ciphers-altnames-nosslv2.patch
        cd $(DIR_APP) && ./configure --prefix=/usr --sysconfdir=/etc --enable-cert1l
        cd $(DIR_APP) && make $(MAKETUNING)
        cd $(DIR_APP) && make install
diff --git a/src/patches/Pound-2.6-reneg-ciphers-altnames-nosslv2.patch b/src/patches/Pound-2.6-reneg-ciphers-altnames-nosslv2.patch
new file mode 100644 (file)
index 0000000..9c874c8
--- /dev/null
@@ -0,0 +1,452 @@
+diff -Naur Pound-2.6.orig/config.c Pound-2.6.reneg-ciphers-altnames-nosslv2/config.c
+--- Pound-2.6.orig/config.c    2011-12-28 14:57:45.000000000 +0100
++++ Pound-2.6.reneg-ciphers-altnames-nosslv2/config.c  2012-02-15 21:49:39.000000000 +0100
+@@ -31,6 +31,8 @@
+ #include    "pound.h"
++#include    <openssl/x509v3.h>
++
+ #ifdef MISS_FACILITYNAMES
+ /* This is lifted verbatim from the Linux sys/syslog.h */
+@@ -76,7 +78,7 @@
+ static regex_t  Err414, Err500, Err501, Err503, MaxRequest, HeadRemove, RewriteLocation, RewriteDestination;
+ static regex_t  Service, ServiceName, URL, HeadRequire, HeadDeny, BackEnd, Emergency, Priority, HAport, HAportAddr;
+ static regex_t  Redirect, RedirectN, TimeOut, Session, Type, TTL, ID, DynScale;
+-static regex_t  ClientCert, AddHeader, Ciphers, CAlist, VerifyList, CRLlist, NoHTTPS11;
++static regex_t  ClientCert, AddHeader, DisableSSLv2, SSLAllowClientRenegotiation, SSLHonorCipherOrder, Ciphers, CAlist, VerifyList, CRLlist, NoHTTPS11;
+ static regex_t  Grace, Include, ConnTO, IgnoreCase, HTTPS, HTTPSCert, Disabled, Threads, CNName;
+ static regmatch_t   matches[5];
+@@ -167,6 +169,53 @@
+     }
+ }
++unsigned char **
++get_subjectaltnames(X509 *x509, unsigned int *count)
++{
++    *count = 0;
++    unsigned int local_count = 0;
++    unsigned char **result = NULL;
++
++    STACK_OF(GENERAL_NAME) *san_stack = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);     
++
++    unsigned char *temp[sk_GENERAL_NAME_num(san_stack)];
++
++    GENERAL_NAME *name = NULL;
++    while(sk_GENERAL_NAME_num(san_stack) > 0)
++    {
++        name = sk_GENERAL_NAME_pop(san_stack);
++
++        switch(name->type)
++        {
++            case GEN_DNS:
++                temp[local_count] = strndup(ASN1_STRING_data(name->d.dNSName), ASN1_STRING_length(name->d.dNSName)+1);
++                if(temp[local_count] == NULL) { conf_err("out of memory"); }
++                local_count++;
++                break;
++            default:
++              logmsg(LOG_INFO, "unsupported subjectAltName type encountered: %i", name->type);
++        }
++
++        GENERAL_NAME_free(name);
++    }
++
++    result = (unsigned char**)malloc(sizeof(unsigned char*)*local_count);
++    if(result == NULL) { conf_err("out of memory"); }
++    int i;
++    for(i = 0;i < local_count; i++)
++    {
++        result[i] = strndup(temp[i], strlen(temp[i])+1);
++        if(result[i] == NULL) { conf_err("out of memory"); }
++
++        free(temp[i]);
++    }
++    *count = local_count;
++
++    sk_GENERAL_NAME_pop_free(san_stack, GENERAL_NAME_free);
++
++    return result;
++}
++
+ /*
+  * parse a back-end
+  */
+@@ -289,9 +338,12 @@
+         } else if(!regexec(&HTTPS, lin, 4, matches, 0)) {
+             if((res->ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
+                 conf_err("SSL_CTX_new failed - aborted");
++            SSL_CTX_set_app_data(res->ctx, res);
+             SSL_CTX_set_verify(res->ctx, SSL_VERIFY_NONE, NULL);
+             SSL_CTX_set_mode(res->ctx, SSL_MODE_AUTO_RETRY);
+             SSL_CTX_set_options(res->ctx, SSL_OP_ALL);
++            SSL_CTX_clear_options(res->ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
++            SSL_CTX_clear_options(res->ctx, SSL_OP_LEGACY_SERVER_CONNECT);
+             sprintf(lin, "%d-Pound-%ld", getpid(), random());
+             SSL_CTX_set_session_id_context(res->ctx, (unsigned char *)lin, strlen(lin));
+             SSL_CTX_set_tmp_rsa_callback(res->ctx, RSA_tmp_callback);
+@@ -299,6 +351,7 @@
+         } else if(!regexec(&HTTPSCert, lin, 4, matches, 0)) {
+             if((res->ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
+                 conf_err("SSL_CTX_new failed - aborted");
++            SSL_CTX_set_app_data(res->ctx, res);
+             lin[matches[1].rm_eo] = '\0';
+             if(SSL_CTX_use_certificate_chain_file(res->ctx, lin + matches[1].rm_so) != 1)
+                 conf_err("SSL_CTX_use_certificate_chain_file failed - aborted");
+@@ -309,6 +362,8 @@
+             SSL_CTX_set_verify(res->ctx, SSL_VERIFY_NONE, NULL);
+             SSL_CTX_set_mode(res->ctx, SSL_MODE_AUTO_RETRY);
+             SSL_CTX_set_options(res->ctx, SSL_OP_ALL);
++            SSL_CTX_clear_options(res->ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
++            SSL_CTX_clear_options(res->ctx, SSL_OP_LEGACY_SERVER_CONNECT);
+             sprintf(lin, "%d-Pound-%ld", getpid(), random());
+             SSL_CTX_set_session_id_context(res->ctx, (unsigned char *)lin, strlen(lin));
+             SSL_CTX_set_tmp_rsa_callback(res->ctx, RSA_tmp_callback);
+@@ -805,13 +860,23 @@
+     /* logmsg(LOG_DEBUG, "Received SSL SNI Header for servername %s", servername); */
+     SSL_set_SSL_CTX(ssl, NULL);
+-    for(pc = ctx; pc; pc = pc->next)
++    for(pc = ctx; pc; pc = pc->next) {
+         if(fnmatch(pc->server_name, server_name, 0) == 0) {
+             /* logmsg(LOG_DEBUG, "Found cert for %s", servername); */
+             SSL_set_SSL_CTX(ssl, pc->ctx);
+             return SSL_TLSEXT_ERR_OK;
+         }
+-
++        else if(pc->subjectAltNameCount > 0 && pc->subjectAltNames != NULL) {
++            int i;
++            for(i = 0; i < pc->subjectAltNameCount; i++) {
++                if(fnmatch(pc->subjectAltNames[i], server_name, 0) == 0) {
++                    SSL_set_SSL_CTX(ssl, pc->ctx);
++                    return SSL_TLSEXT_ERR_OK;
++                }
++            }
++        }
++    }
++    
+     /* logmsg(LOG_DEBUG, "No match for %s, default used", server_name); */
+     SSL_set_SSL_CTX(ssl, ctx->ctx);
+     return SSL_TLSEXT_ERR_OK;
+@@ -829,11 +894,15 @@
+     SERVICE     *svc;
+     MATCHER     *m;
+     int         has_addr, has_port, has_other;
++    long      ssl_op_enable, ssl_op_disable;
+     struct hostent      *host;
+     struct sockaddr_in  in;
+     struct sockaddr_in6 in6;
+     POUND_CTX   *pc;
++    ssl_op_enable = SSL_OP_ALL;
++    ssl_op_disable = SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION | SSL_OP_LEGACY_SERVER_CONNECT;
++
+     if((res = (LISTENER *)malloc(sizeof(LISTENER))) == NULL)
+         conf_err("ListenHTTPS config: out of memory - aborted");
+     memset(res, 0, sizeof(LISTENER));
+@@ -844,6 +913,8 @@
+     res->err500 = "An internal server error occurred. Please try again later.";
+     res->err501 = "This method may not be used.";
+     res->err503 = "The service is not available. Please try again later.";
++    res->allow_client_reneg = 0;
++    res->disable_ssl_v2 = 0;
+     res->log_level = log_level;
+     if(regcomp(&res->verb, xhttp[0], REG_ICASE | REG_NEWLINE | REG_EXTENDED))
+         conf_err("xHTTP bad default pattern - aborted");
+@@ -959,6 +1030,9 @@
+             fclose(fcert);
+             memset(server_name, '\0', MAXBUF);
+             X509_NAME_oneline(X509_get_subject_name(x509), server_name, MAXBUF - 1);
++            pc->subjectAltNameCount = 0;
++            pc->subjectAltNames = NULL;
++            pc->subjectAltNames = get_subjectaltnames(x509, &(pc->subjectAltNameCount));
+             X509_free(x509);
+             if(!regexec(&CNName, server_name, 4, matches, 0)) {
+                 server_name[matches[1].rm_eo] = '\0';
+@@ -1029,6 +1103,25 @@
+                 strcat(res->add_head, "\r\n");
+                 strcat(res->add_head, lin + matches[1].rm_so);
+             }
++      } else if(!regexec(&DisableSSLv2, lin, 4, matches, 0)) {
++          res->disable_ssl_v2 = 1;
++        } else if(!regexec(&SSLAllowClientRenegotiation, lin, 4, matches, 0)) {
++            res->allow_client_reneg = atoi(lin + matches[1].rm_so);
++            if (res->allow_client_reneg == 2) {
++                ssl_op_enable |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
++                ssl_op_disable &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
++            } else {
++                ssl_op_disable |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
++                ssl_op_enable &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
++            }
++        } else if(!regexec(&SSLHonorCipherOrder, lin, 4, matches, 0)) {
++            if (atoi(lin + matches[1].rm_so)) {
++                ssl_op_enable |= SSL_OP_CIPHER_SERVER_PREFERENCE;
++                ssl_op_disable &= ~SSL_OP_CIPHER_SERVER_PREFERENCE;
++            } else {
++                ssl_op_disable |= SSL_OP_CIPHER_SERVER_PREFERENCE;
++                ssl_op_enable &= ~SSL_OP_CIPHER_SERVER_PREFERENCE;
++            }
+         } else if(!regexec(&Ciphers, lin, 4, matches, 0)) {
+             has_other = 1;
+             if(res->ctx == NULL)
+@@ -1105,12 +1198,19 @@
+                 conf_err("ListenHTTPS: can't set SNI callback");
+ #endif
+             for(pc = res->ctx; pc; pc = pc->next) {
++                SSL_CTX_set_app_data(pc->ctx, res);
+                 SSL_CTX_set_mode(pc->ctx, SSL_MODE_AUTO_RETRY);
+-                SSL_CTX_set_options(pc->ctx, SSL_OP_ALL);
++                SSL_CTX_set_options(pc->ctx, ssl_op_enable);
++                SSL_CTX_clear_options(pc->ctx, ssl_op_disable);
++              if (res->disable_ssl_v2 == 1)
++              {
++                  SSL_CTX_set_options(pc->ctx, SSL_OP_NO_SSLv2);
++              }
+                 sprintf(lin, "%d-Pound-%ld", getpid(), random());
+                 SSL_CTX_set_session_id_context(pc->ctx, (unsigned char *)lin, strlen(lin));
+                 SSL_CTX_set_tmp_rsa_callback(pc->ctx, RSA_tmp_callback);
+                 SSL_CTX_set_tmp_dh_callback(pc->ctx, DH_tmp_callback);
++                SSL_CTX_set_info_callback(pc->ctx, SSLINFO_callback);
+             }
+             return res;
+         } else {
+@@ -1305,6 +1405,9 @@
+     || regcomp(&DynScale, "^[ \t]*DynScale[ \t]+([01])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+     || regcomp(&ClientCert, "^[ \t]*ClientCert[ \t]+([0-3])[ \t]+([1-9])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+     || regcomp(&AddHeader, "^[ \t]*AddHeader[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
++    || regcomp(&SSLAllowClientRenegotiation, "^[ \t]*SSLAllowClientRenegotiation[ \t]+([012])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
++    || regcomp(&DisableSSLv2, "^[ \t]*DisableSSLv2[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
++    || regcomp(&SSLHonorCipherOrder, "^[ \t]*SSLHonorCipherOrder[ \t]+([01])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+     || regcomp(&Ciphers, "^[ \t]*Ciphers[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+     || regcomp(&CAlist, "^[ \t]*CAlist[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+     || regcomp(&VerifyList, "^[ \t]*VerifyList[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+@@ -1463,6 +1566,9 @@
+     regfree(&DynScale);
+     regfree(&ClientCert);
+     regfree(&AddHeader);
++    regfree(&SSLAllowClientRenegotiation);
++    regfree(&DisableSSLv2);
++    regfree(&SSLHonorCipherOrder);
+     regfree(&Ciphers);
+     regfree(&CAlist);
+     regfree(&VerifyList);
+diff -Naur Pound-2.6.orig/http.c Pound-2.6.reneg-ciphers-altnames-nosslv2/http.c
+--- Pound-2.6.orig/http.c      2011-12-28 14:57:45.000000000 +0100
++++ Pound-2.6.reneg-ciphers-altnames-nosslv2/http.c    2012-02-15 21:44:46.000000000 +0100
+@@ -246,6 +246,11 @@
+ static int  err_to = -1;
++typedef struct {
++    int timeout;
++    RENEG_STATE *reneg_state;
++} BIO_ARG;
++
+ /*
+  * Time-out for client read/gets
+  * the SSL manual says not to do it, but it works well enough anyway...
+@@ -253,18 +258,32 @@
+ static long
+ bio_callback(BIO *const bio, const int cmd, const char *argp, int argi, long argl, long ret)
+ {
++    BIO_ARG *bio_arg;
+     struct pollfd   p;
+     int             to, p_res, p_err;
+     if(cmd != BIO_CB_READ && cmd != BIO_CB_WRITE)
+         return ret;
++    //logmsg(LOG_NOTICE, "bio callback");
+     /* a time-out already occured */
+-    if((to = *((int *)BIO_get_callback_arg(bio)) * 1000) < 0) {
++    if((bio_arg = (BIO_ARG*)BIO_get_callback_arg(bio))==NULL) return ret;
++    if((to = bio_arg->timeout * 1000) < 0) {
+         errno = ETIMEDOUT;
+         return -1;
+     }
++    /* Renegotiations */
++    //logmsg(LOG_NOTICE, "RENEG STATE %d", bio_arg->reneg_state==NULL?-1:*bio_arg->reneg_state);
++    if (bio_arg->reneg_state != NULL && *bio_arg->reneg_state == RENEG_ABORT) {
++        logmsg(LOG_NOTICE, "REJECTING renegotiated session");
++        errno = ECONNABORTED;
++        return -1;
++    }
++
++    //logmsg(LOG_NOTICE, "TO %d", to);
++    if (to == 0) return ret;
++
+     for(;;) {
+         memset(&p, 0, sizeof(p));
+         BIO_get_fd(bio, &p.fd);
+@@ -299,7 +318,7 @@
+             return -1;
+         case 0:
+             /* timeout - mark the BIO as unusable for the future */
+-            BIO_set_callback_arg(bio, (char *)&err_to);
++            bio_arg->timeout = err_to;
+ #ifdef  EBUG
+             logmsg(LOG_WARNING, "(%lx) CALLBACK timeout poll after %d secs: %s",
+                 pthread_self(), to / 1000, strerror(p_err));
+@@ -503,7 +522,14 @@
+     regmatch_t          matches[4];
+     struct linger       l;
+     double              start_req, end_req;
++    RENEG_STATE               reneg_state;
++    BIO_ARG           ba1, ba2;
++    reneg_state = RENEG_INIT;
++    ba1.reneg_state =  &reneg_state;
++    ba2.reneg_state = &reneg_state;
++    ba1.timeout = 0;
++    ba2.timeout = 0;
+     from_host = ((thr_arg *)arg)->from_host;
+     memcpy(&from_host_addr, from_host.ai_addr, from_host.ai_addrlen);
+     from_host.ai_addr = (struct sockaddr *)&from_host_addr;
+@@ -512,6 +538,8 @@
+     free(((thr_arg *)arg)->from_host.ai_addr);
+     free(arg);
++    if(lstn->allow_client_reneg) reneg_state = RENEG_ALLOW;
++
+     n = 1;
+     setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&n, sizeof(n));
+     l.l_onoff = 1;
+@@ -535,10 +563,11 @@
+         close(sock);
+         return;
+     }
+-    if(lstn->to > 0) {
+-        BIO_set_callback_arg(cl, (char *)&lstn->to);
++    //if(lstn->to > 0) {
++        ba1.timeout = lstn->to;
++        BIO_set_callback_arg(cl, (char *)&ba1);
+         BIO_set_callback(cl, bio_callback);
+-    }
++    //}
+     if(lstn->ctx != NULL) {
+         if((ssl = SSL_new(lstn->ctx->ctx)) == NULL) {
+@@ -547,6 +576,7 @@
+             BIO_free_all(cl);
+             return;
+         }
++        SSL_set_app_data(ssl, &reneg_state);
+         SSL_set_bio(ssl, cl, cl);
+         if((bb = BIO_new(BIO_f_ssl())) == NULL) {
+             logmsg(LOG_WARNING, "(%lx) BIO_new(Bio_f_ssl()) failed", pthread_self());
+@@ -848,7 +878,8 @@
+             }
+             BIO_set_close(be, BIO_CLOSE);
+             if(backend->to > 0) {
+-                BIO_set_callback_arg(be, (char *)&backend->to);
++                ba2.timeout = backend->to;
++                BIO_set_callback_arg(be, (char *)&ba2);
+                 BIO_set_callback(be, bio_callback);
+             }
+             if(backend->ctx != NULL) {
+diff -Naur Pound-2.6.orig/pound.8 Pound-2.6.reneg-ciphers-altnames-nosslv2/pound.8
+--- Pound-2.6.orig/pound.8     2011-12-28 14:57:45.000000000 +0100
++++ Pound-2.6.reneg-ciphers-altnames-nosslv2/pound.8   2012-02-15 21:44:46.000000000 +0100
+@@ -501,6 +501,19 @@
+ and
+ .I SSL_CTX_set_cipher_list(3).
+ .TP
++\fBSSLHonorCipherOrder\fR 0|1
++If this value is 1, the server will broadcast a preference to use \fBCiphers\fR in the
++order supplied in the \fBCiphers\fR directive.  If the value is 0, the server will treat
++the Ciphers list as the list of Ciphers it will accept, but no preference will be
++indicated.  Default value is 0.
++.TP
++\fBSSLAllowClientRenegotiation\fR 0|1|2
++If this value is 0, client initiated renegotiation will be disabled.  This will mitigate
++DoS exploits based on client renegotiation, regardless of the patch status of clients and
++servers related to "Secure renegotiation".  If the value is 1, secure renegotiation is
++supported.  If the value is 2, insecure renegotiation is supported, with unpatched
++clients.  /fBThis can lead to a DoS and a Man in the Middle attack!/fR  Default value is 0.
++.TP
+ \fBCAlist\fR "CAcert_file"
+ Set the list of "trusted" CA's for this server. The CAcert_file is a file containing
+ a sequence of CA certificates (PEM format). The names of the defined CA certificates
+diff -Naur Pound-2.6.orig/pound.h Pound-2.6.reneg-ciphers-altnames-nosslv2/pound.h
+--- Pound-2.6.orig/pound.h     2011-12-28 14:57:45.000000000 +0100
++++ Pound-2.6.reneg-ciphers-altnames-nosslv2/pound.h   2012-02-15 21:49:39.000000000 +0100
+@@ -380,6 +380,8 @@
+     SSL_CTX             *ctx;
+     char                *server_name;
+     struct _pound_ctx   *next;
++    unsigned int        subjectAltNameCount;
++    unsigned char       **subjectAltNames;
+ } POUND_CTX;
+ /* Listener definition */
+@@ -404,6 +406,8 @@
+     int                 rewr_dest;      /* rewrite destination header */
+     int                 disabled;       /* true if the listener is disabled */
+     int                 log_level;      /* log level for this listener */
++    int                 allow_client_reneg; /* Allow Client SSL Renegotiation */
++    int                disable_ssl_v2; /* Disable SSL version 2 */
+     SERVICE             *services;
+     struct _listener    *next;
+ }   LISTENER;
+@@ -419,6 +423,9 @@
+     struct _thr_arg *next;
+ }   thr_arg;                        /* argument to processing threads: socket, origin */
++/* Track SSL handshare/renegotiation so we can reject client-renegotiations. */
++typedef enum { RENEG_INIT=0, RENEG_REJECT, RENEG_ALLOW, RENEG_ABORT } RENEG_STATE;
++
+ /* Header types */
+ #define HEADER_ILLEGAL              -1
+ #define HEADER_OTHER                0
+@@ -591,6 +598,11 @@
+ extern DH   *DH_tmp_callback(SSL *, int, int);
+ /*
++ * Renegotiation callback
++ */
++extern void SSLINFO_callback(const SSL *s, int where, int rc);
++
++/*
+  * expiration stuff
+  */
+ #ifndef EXPIRE_TO
+diff -Naur Pound-2.6.orig/svc.c Pound-2.6.reneg-ciphers-altnames-nosslv2/svc.c
+--- Pound-2.6.orig/svc.c       2011-12-28 14:57:45.000000000 +0100
++++ Pound-2.6.reneg-ciphers-altnames-nosslv2/svc.c     2012-02-15 21:44:46.000000000 +0100
+@@ -1797,3 +1797,34 @@
+         close(ctl);
+     }
+ }
++
++void
++SSLINFO_callback(const SSL *ssl, int where, int rc)
++{
++    RENEG_STATE *reneg_state;
++
++    /* Get our thr_arg where we're tracking this connection info */
++    if ((reneg_state = (RENEG_STATE *)SSL_get_app_data(ssl)) == NULL) return;
++
++    /* If we're rejecting renegotiations, move to ABORT if Client Hello is being read. */
++    if ((where & SSL_CB_ACCEPT_LOOP) && *reneg_state == RENEG_REJECT) {
++        int state = SSL_get_state(ssl);
++
++        if (state == SSL3_ST_SR_CLNT_HELLO_A || state == SSL23_ST_SR_CLNT_HELLO_A) {
++           *reneg_state = RENEG_ABORT;
++           logmsg(LOG_WARNING,"rejecting client initiated renegotiation");
++        }
++    }
++    else if (where & SSL_CB_HANDSHAKE_DONE && *reneg_state == RENEG_INIT) {
++       // Reject any followup renegotiations
++       *reneg_state = RENEG_REJECT;
++    }
++
++    //if (where & SSL_CB_HANDSHAKE_START) logmsg(LOG_DEBUG, "handshake start");
++    //else if (where & SSL_CB_HANDSHAKE_DONE) logmsg(LOG_DEBUG, "handshake done");
++    //else if (where & SSL_CB_LOOP) logmsg(LOG_DEBUG, "loop");
++    //else if (where & SSL_CB_READ) logmsg(LOG_DEBUG, "read");
++    //else if (where & SSL_CB_WRITE) logmsg(LOG_DEBUG, "write");
++    //else if (where & SSL_CB_ALERT) logmsg(LOG_DEBUG, "alert");
++}
++