On Tue, Feb 22, 2000, [EMAIL PROTECTED] wrote:

> Full_Name: Dennis Norgord
> Version: 2.4.10-1.3.9
> OS: Redhat Linux 6.2
> Submission from: (NULL) (158.222.124.59)
> 
> There are three problems with the following configuration:
> 
> <VirtualHost  _default_:5000>
> ProxyRequests On
> RewriteEngine on
> RewriteRule ^/(.+) https://$1 [P]
> </VirtualHost>
> 
> This configuration can be used to -
>     http ==> Apache ==> https ==>
> 
> The request http://localhost:5000/www.verisign.com/
> fetches the page https://www.verisign.com
> 
> The three problems are:
> 1) Memory leak in ssl_engine_ext.c, function ssl_ext_mp_new_connection(). 
> ssl_ctx is allocated and never freed.  This results in over 1K bytes leaked per
> request.

The following patch should fix this: 

Index: ssl_engine_ext.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_ext.c,v
retrieving revision 1.31
diff -u -r1.31 ssl_engine_ext.c
--- ssl_engine_ext.c    1999/12/30 20:58:08 1.31
+++ ssl_engine_ext.c    2000/02/23 10:29:09
@@ -347,13 +347,17 @@
 {
     BUFF *fb = _fb;
     SSL *ssl;
+    SSL_CTX *ctx;
 
     ssl = ap_ctx_get(fb->ctx, "ssl");
     if (ssl != NULL) {
+        ctx = SSL_get_SSL_CTX(ssl);
         SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
         SSL_smart_shutdown(ssl);
         SSL_free(ssl);
         ap_ctx_set(fb->ctx, "ssl", NULL);
+        if (ctx != NULL)
+            SSL_CTX_free(ctx);
     }
     return;
 }

Can you confirm that it fixes the leak?

> 2) There is no mechanism to check the server certificate.

Yes, this is only available with the still pending SSLProxy*
functionality C2Net contributed. This is already ready but lacks
documentation since many months now. I append you patch which shows
you our latest state and allows you to test the enhanced HTTPS
proxy support. If someone contributes documentation for this stuff
it can immediately be released (just perhaps still wrapped with
SSL_EXPERIMENTAL).

> 3) Every request performs a full SSL handshake, even when to the same host.

Hmmm... yes, but this cannot be changed. Because the functionality
depends on mod_proxy and mod_proxy does not suppot keep-alive
connections and similar SSL optimizations which could be used.

                                       Ralf S. Engelschall
                                       [EMAIL PROTECTED]
                                       www.engelschall.com

Index: src/modules/proxy/mod_proxy.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/proxy/mod_proxy.c,v
retrieving revision 1.12
diff -u -r1.12 mod_proxy.c
--- src/modules/proxy/mod_proxy.c       2000/01/21 19:51:11     1.12
+++ src/modules/proxy/mod_proxy.c       2000/01/21 22:47:21
@@ -247,6 +247,10 @@
 static void proxy_init(server_rec *r, pool *p)
 {
     ap_proxy_garbage_init(r, p);
+#ifdef EAPI
+    ap_hook_use("ap::mod_proxy::init", 
+                AP_HOOK_SIG3(void,ptr,ptr), AP_HOOK_ALL, r, p);
+#endif
 }
 
 #ifdef EAPI
Index: src/modules/proxy/proxy_http.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/proxy/proxy_http.c,v
retrieving revision 1.14
diff -u -r1.14 proxy_http.c
--- src/modules/proxy/proxy_http.c      2000/01/21 19:51:11     1.14
+++ src/modules/proxy/proxy_http.c      2000/01/21 22:47:22
@@ -189,6 +189,9 @@
     const char *urlptr = NULL;
     const char *datestr;
     struct tbl_do_args tdo;
+#ifdef EAPI
+    char *peer;
+#endif
 
     void *sconf = r->server->module_config;
     proxy_server_conf *conf =
@@ -249,12 +252,18 @@
        err = ap_proxy_host2addr(proxyhost, &server_hp);
        if (err != NULL)
            return DECLINED;    /* try another */
+#ifdef EAPI
+       peer = ap_psprintf(p, "%s:%u", proxyhost, proxyport);  
+#endif
     }
     else {
        server.sin_port = htons(destport);
        err = ap_proxy_host2addr(desthost, &server_hp);
        if (err != NULL)
            return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, err);
+#ifdef EAPI
+       peer =  ap_psprintf(p, "%s:%u", desthost, destport);  
+#endif
     }
 
     sock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -315,9 +324,9 @@
     {
         char *errmsg = NULL;
         ap_hook_use("ap::mod_proxy::http::handler::new_connection", 
-                    AP_HOOK_SIG3(ptr,ptr,ptr), 
+                    AP_HOOK_SIG4(ptr,ptr,ptr,ptr), 
                     AP_HOOK_DECLINE(NULL),
-                    &errmsg, r, f);
+                    &errmsg, r, f, peer);
         if (errmsg != NULL)
             return ap_proxyerror(r, HTTP_BAD_GATEWAY, errmsg);
     }
Index: src/modules/ssl/mod_ssl.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/mod_ssl.c,v
retrieving revision 1.57
diff -u -r1.57 mod_ssl.c
--- src/modules/ssl/mod_ssl.c   1999/12/30 20:58:07     1.57
+++ src/modules/ssl/mod_ssl.c   1999/12/30 21:18:40
@@ -154,6 +154,34 @@
                "Enable or disable various SSL protocols"
                "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)")
 
+    /* 
+     * Proxy configuration for remote SSL connections
+     */
+    AP_SRV_CMD(ProxyProtocol, RAW_ARGS,
+               "SSL Proxy: enable or disable SSL protocol flavors "
+               "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)")
+    AP_SRV_CMD(ProxyCipherSuite, TAKE1,
+               "SSL Proxy: colon-delimited list of permitted SSL ciphers "
+               "(`XXX:...:XXX' - see manual)")
+    AP_SRV_CMD(ProxyVerify, FLAG,
+               "SSL Proxy: whether to verify the remote certificate "
+               "(`on' or `off')")
+    AP_SRV_CMD(ProxyVerifyDepth, TAKE1,
+               "SSL Proxy: maximum certificate verification depth "
+               "(`N' - number of intermediate certificates)")
+    AP_SRV_CMD(ProxyCACertificateFile, TAKE1,
+               "SSL Proxy: file containing server certificates "
+               "(`/path/to/file' - PEM encoded certificates)")
+    AP_SRV_CMD(ProxyCACertificatePath, TAKE1,
+               "SSL Proxy: directory containing server certificates "
+               "(`/path/to/dir' - contains PEM encoded certificates)")
+    AP_SRV_CMD(ProxyMachineCertificateFile, TAKE1,
+               "SSL Proxy: file containing client certificates "
+               "(`/path/to/file' - PEM encoded certificates)")
+    AP_SRV_CMD(ProxyMachineCertificatePath, TAKE1,
+               "SSL Proxy: directory containing client certificates "
+               "(`/path/to/dir' - contains PEM encoded certificates)")
+
     /*
      * Per-directory context configuration directives
      */
Index: src/modules/ssl/mod_ssl.h
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/mod_ssl.h,v
retrieving revision 1.121
diff -u -r1.121 mod_ssl.h
--- src/modules/ssl/mod_ssl.h   1999/12/30 20:58:07     1.121
+++ src/modules/ssl/mod_ssl.h   1999/12/30 21:18:40
@@ -572,6 +572,16 @@
     char        *szCARevocationPath;
     char        *szCARevocationFile;
     X509_STORE  *pRevocationStore;
+    /* Configuration details for proxy operation */
+    ssl_proto_t  nProxyProtocol;
+    int          bProxyVerify;
+    int          nProxyVerifyDepth;
+    char        *szProxyCACertificatePath;
+    char        *szProxyCACertificateFile;
+    char        *szProxyClientCertificateFile;
+    char        *szProxyClientCertificatePath;
+    char        *szProxyCipherSuite;
+    SSL_CTX     *pSSLProxyCtx;
 #ifdef SSL_VENDOR
     ap_ctx      *ctx;
 #endif
@@ -637,6 +647,14 @@
 const char  *ssl_cmd_SSLOptions(cmd_parms *, SSLDirConfigRec *, const char *);
 const char  *ssl_cmd_SSLRequireSSL(cmd_parms *, SSLDirConfigRec *, char *);
 const char  *ssl_cmd_SSLRequire(cmd_parms *, SSLDirConfigRec *, char *);
+const char  *ssl_cmd_SSLProxyProtocol(cmd_parms *, char *, const char *);
+const char  *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, char *, char *);
+const char  *ssl_cmd_SSLProxyVerify(cmd_parms *, char *, int);
+const char  *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, char *, char *);
+const char  *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, char *, char *);
+const char  *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, char *, char *);
+const char  *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, char *, char *);
+const char  *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, char *, char *);
 
 /*  module initialization  */
 void         ssl_init_Module(server_rec *, pool *);
Index: src/modules/ssl/ssl_engine_compat.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_compat.c,v
retrieving revision 1.26
diff -u -r1.26 ssl_engine_compat.c
--- src/modules/ssl/ssl_engine_compat.c 1999/12/30 20:58:07     1.26
+++ src/modules/ssl/ssl_engine_compat.c 1999/12/30 21:18:40
@@ -159,12 +159,7 @@
     CRM_ENTRY( CRM_CMD("SSL_CertificateLogDir"),     CRM_LOG("Not supported by 
mod_ssl")      )
     CRM_ENTRY( CRM_CMD("AuthCertDir"),               CRM_LOG("Not supported by 
mod_ssl")      )
     CRM_ENTRY( CRM_CMD("SSL_Group"),                 CRM_LOG("Not supported by 
mod_ssl")      )
-    CRM_ENTRY( CRM_CMD("SSLProxyMachineCertPath"),   CRM_LOG("Not supported by 
mod_ssl")      )
-    CRM_ENTRY( CRM_CMD("SSLProxyMachineCertFile"),   CRM_LOG("Not supported by 
mod_ssl")      )
-    CRM_ENTRY( CRM_CMD("SSLProxyCACertificatePath"), CRM_LOG("Not supported by 
mod_ssl")      )
-    CRM_ENTRY( CRM_CMD("SSLProxyCACertificateFile"), CRM_LOG("Not supported by 
mod_ssl")      )
-    CRM_ENTRY( CRM_CMD("SSLProxyVerifyDepth"),       CRM_LOG("Not supported by 
mod_ssl")      )
-    CRM_ENTRY( CRM_CMD("SSLProxyCipherList"),        CRM_LOG("Not supported by 
mod_ssl")      )
+    CRM_ENTRY( CRM_CMD("SSLProxyCipherList"),        CRM_SUB("SSLProxyCipherSuite")   
+        )
 
     CRM_END
 };
Index: src/modules/ssl/ssl_engine_config.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_config.c,v
retrieving revision 1.65
diff -u -r1.65 ssl_engine_config.c
--- src/modules/ssl/ssl_engine_config.c 1999/12/30 20:58:07     1.65
+++ src/modules/ssl/ssl_engine_config.c 1999/12/30 21:18:40
@@ -205,6 +205,15 @@
     sc->szCARevocationPath     = NULL;
     sc->szCARevocationFile     = NULL;
     sc->pRevocationStore       = NULL;
+    sc->nProxyVerifyDepth             = UNSET;
+    sc->szProxyCACertificatePath      = NULL;
+    sc->szProxyCACertificateFile      = NULL;
+    sc->szProxyClientCertificateFile  = NULL;
+    sc->szProxyClientCertificatePath  = NULL;
+    sc->szProxyCipherSuite            = NULL;
+    sc->nProxyProtocol                = SSL_PROTOCOL_ALL & ~SSL_PROTOCOL_TLSV1;
+    sc->bProxyVerify                  = UNSET;
+    sc->pSSLProxyCtx                  = NULL;
 
     (void)memset(sc->szPublicCertFile, 0, SSL_AIDX_MAX*sizeof(char *));
     (void)memset(sc->szPrivateKeyFile, 0, SSL_AIDX_MAX*sizeof(char *));
@@ -264,6 +273,16 @@
                 p, base, add, new);
 #endif
 
+    cfgMergeInt(nProxyVerifyDepth);
+    cfgMergeString(szProxyCACertificatePath);
+    cfgMergeString(szProxyCACertificateFile);
+    cfgMergeString(szProxyClientCertificateFile);
+    cfgMergeString(szProxyClientCertificatePath);
+    cfgMergeString(szProxyCipherSuite);
+    cfgMerge(nProxyProtocol, (SSL_PROTOCOL_ALL & ~SSL_PROTOCOL_TLSV1));
+    cfgMergeBool(bProxyVerify);
+    cfgMerge(pSSLProxyCtx, NULL);
+
     return new;
 }
 
@@ -869,6 +888,132 @@
             options = thisopt;
     }
     sc->nProtocol = options;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyProtocol(
+    cmd_parms *cmd, char *struct_ptr, const char *opt)
+{
+    SSLSrvConfigRec *sc;
+    ssl_proto_t options, thisopt;
+    char action;
+    char *w;
+
+    sc = mySrvConfig(cmd->server);
+    options = SSL_PROTOCOL_NONE;
+    while (opt[0] != NUL) {
+        w = ap_getword_conf(cmd->pool, &opt);
+
+        action = NUL;
+        if (*w == '+' || *w == '-')
+            action = *(w++);
+
+        if (strcEQ(w, "SSLv2"))
+            thisopt = SSL_PROTOCOL_SSLV2;
+        else if (strcEQ(w, "SSLv3"))
+            thisopt = SSL_PROTOCOL_SSLV3;
+        else if (strcEQ(w, "TLSv1"))
+            thisopt = SSL_PROTOCOL_TLSV1;
+        else if (strcEQ(w, "all"))
+            thisopt = SSL_PROTOCOL_ALL;
+        else
+            return ap_pstrcat(cmd->pool, "SSLProxyProtocol: "
+                              "Illegal protocol '", w, "'", NULL);
+        if (action == '-')
+            options &= ~thisopt;
+        else if (action == '+')
+            options |= thisopt;
+        else
+            options = thisopt;
+    }
+    sc->nProxyProtocol = options;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCipherSuite(
+    cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+    sc->szProxyCipherSuite = arg;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyVerify(
+    cmd_parms *cmd, char *struct_ptr, int flag)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+    sc->bProxyVerify = (flag ? TRUE : FALSE);
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyVerifyDepth(
+    cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    int d;
+
+    d = atoi(arg);
+    if (d < 0)
+        return "SSLProxyVerifyDepth: Invalid argument";
+    sc->nProxyVerifyDepth = d;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCACertificateFile(
+    cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    char *cpPath;
+
+    cpPath = ap_server_root_relative(cmd->pool, arg);
+    if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+        return ap_pstrcat(cmd->pool, "SSLProxyCACertificateFile: file '",
+                          cpPath, "' not exists or empty", NULL);
+    sc->szProxyCACertificateFile = cpPath;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCACertificatePath(
+    cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    char *cpPath;
+
+    cpPath = ap_server_root_relative(cmd->pool, arg);
+    if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath))
+        return ap_pstrcat(cmd->pool, "SSLProxyCACertificatePath: directory '",
+                          cpPath, "' does not exists", NULL);
+    sc->szProxyCACertificatePath = cpPath;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyMachineCertificateFile(
+    cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    char *cpPath;
+
+    cpPath = ap_server_root_relative(cmd->pool, arg);
+    if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+        return ap_pstrcat(cmd->pool, "SSLProxyMachineCertFile: file '",
+                          cpPath, "' not exists or empty", NULL);
+    sc->szProxyClientCertificateFile = cpPath;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyMachineCertificatePath(
+    cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    char *cpPath;
+
+    cpPath = ap_server_root_relative(cmd->pool, arg);
+    if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath))
+        return ap_pstrcat(cmd->pool, "SSLProxyMachineCertPath: directory '",
+                          cpPath, "' does not exists", NULL);
+    sc->szProxyClientCertificatePath = cpPath;
     return NULL;
 }
 
Index: src/modules/ssl/ssl_engine_ext.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_ext.c,v
retrieving revision 1.31
diff -u -r1.31 ssl_engine_ext.c
--- src/modules/ssl/ssl_engine_ext.c    1999/12/30 20:58:08     1.31
+++ src/modules/ssl/ssl_engine_ext.c    1999/12/30 21:19:10
@@ -213,18 +213,23 @@
 **  _________________________________________________________________
 */
 
-static int   ssl_ext_mp_canon(request_rec *r, char *url);
-static int   ssl_ext_mp_handler(request_rec *r, void *cr, char *url, char *proxyhost, 
int proxyport, char *protocol);
-static int   ssl_ext_mp_set_destport(request_rec *r);
-static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb);
-static void  ssl_ext_mp_close_connection(void *_fb);
-static int   ssl_ext_mp_write_host_header(request_rec *r, BUFF *fb, char *host, int 
port, char *portstr);
+static int   ssl_ext_mp_canon(request_rec *, char *);
+static int   ssl_ext_mp_handler(request_rec *, void *, char *, char *, int , char *);
+static int   ssl_ext_mp_set_destport(request_rec *);
+static char *ssl_ext_mp_new_connection(request_rec *, BUFF *, char *);
+static void  ssl_ext_mp_close_connection(void *);
+static int   ssl_ext_mp_write_host_header(request_rec *, BUFF *, char *, int, char *);
+static void  ssl_ext_mp_init(server_rec *, pool *);
+static int   ssl_ext_mp_verify_cb(int, X509_STORE_CTX *);
+static int   ssl_ext_mp_clientcert_cb(SSL *, X509 **, EVP_PKEY **);
 
 /*
  * register us ...
  */
 static void ssl_ext_mp_register(void)
 {
+    ap_hook_register("ap::mod_proxy::init",
+                     ssl_ext_mp_init, AP_HOOK_NOCTX);
     ap_hook_register("ap::mod_proxy::canon",
                      ssl_ext_mp_canon, AP_HOOK_NOCTX);
     ap_hook_register("ap::mod_proxy::handler",
@@ -240,6 +245,7 @@
 
 static void ssl_ext_mp_unregister(void)
 {
+    ap_hook_unregister("ap::mod_proxy::init", ssl_ext_mp_init);
     ap_hook_unregister("ap::mod_proxy::canon", ssl_ext_mp_canon);
     ap_hook_unregister("ap::mod_proxy::handler", ssl_ext_mp_handler);
     ap_hook_unregister("ap::mod_proxy::http::handler::set_destport",
@@ -251,6 +257,143 @@
     return;
 }
 
+/*
+ * SSL proxy initialization
+ */
+static void ssl_ext_mp_init(server_rec *s, pool *p)
+{
+    SSLSrvConfigRec *sc;
+    char *cpVHostID;
+    int nVerify;
+    SSL_CTX *ctx;
+    char *cp;
+    STACK_OF(X509_INFO) *sk;
+
+    /*
+     * Initialize each virtual server 
+     */
+    for (; s != NULL; s = s->next) {
+        sc = mySrvConfig(s);
+        cpVHostID = ssl_util_vhostid(p, s);
+        
+        if (sc->bProxyVerify == UNSET)
+            sc->bProxyVerify = FALSE;
+
+        /*
+         *  Create new SSL context and configure callbacks
+         */
+        if (sc->nProxyProtocol == SSL_PROTOCOL_NONE) {
+            ssl_log(s, SSL_LOG_ERROR,
+                    "Init: (%s) No Proxy SSL protocols available [hint: 
+SSLProxyProtocol]",
+                    cpVHostID);
+            ssl_die();
+        }
+        cp = ap_pstrcat(p, (sc->nProxyProtocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : 
+""), 
+                           (sc->nProxyProtocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : 
+""), 
+                           (sc->nProxyProtocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : 
+""), NULL);
+        cp[strlen(cp)-2] = NUL;
+        ssl_log(s, SSL_LOG_TRACE, 
+                "Init: (%s) Creating new proxy SSL context (protocols: %s)", 
+                cpVHostID, cp);
+        if (sc->nProxyProtocol == SSL_PROTOCOL_SSLV2)
+            ctx = SSL_CTX_new(SSLv2_client_method());  /* only SSLv2 is left */ 
+        else
+            ctx = SSL_CTX_new(SSLv23_client_method()); /* be more flexible */
+        if (ctx == NULL) {
+            ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+                    "Init: (%s) Unable to create SSL Proxy context", cpVHostID);
+            ssl_die();
+        }
+        sc->pSSLProxyCtx = ctx;
+        SSL_CTX_set_options(ctx, SSL_OP_ALL);
+        if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV2))
+            SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+        if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV3))
+            SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+        if (!(sc->nProxyProtocol & SSL_PROTOCOL_TLSV1)) 
+            SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
+
+        if (sc->szProxyClientCertificateFile || sc->szProxyClientCertificatePath) {
+            sk = sk_X509_INFO_new_null();
+            if (sc->szProxyClientCertificateFile) 
+                SSL_load_CrtAndKeyInfo_file(p, sk, sc->szProxyClientCertificateFile);
+            if (sc->szProxyClientCertificatePath)
+                SSL_load_CrtAndKeyInfo_path(p, sk, sc->szProxyClientCertificatePath);
+            ssl_log(s, SSL_LOG_TRACE, "Init: (%s) loaded %d client certs for SSL 
+proxy",
+                    cpVHostID, sk_X509_INFO_num(sk));
+            if (sk_X509_INFO_num(sk) > 0) {
+                SSL_CTX_set_client_cert_cb(ctx, ssl_ext_mp_clientcert_cb);
+                ap_ctx_set(sc->ctx, "ssl::proxy::clientcerts", (void *)sk);
+            }
+        }
+
+        /*
+         * Calculate OpenSSL verify type for verifying the remote server
+         * certificate. We either verify it against our list of CA's, or don't
+         * bother at all.
+         */
+        nVerify = SSL_VERIFY_NONE;
+        if (sc->bProxyVerify)
+            nVerify |= SSL_VERIFY_PEER;
+        if (   nVerify & SSL_VERIFY_PEER 
+            && sc->szProxyCACertificateFile == NULL 
+            && sc->szProxyCACertificatePath == NULL) {
+            ssl_log(s, SSL_LOG_ERROR,
+                    "Init: (%s) SSLProxyVerify set to On but no CA certificates 
+configured",
+                    cpVHostID);
+            ssl_die();
+        }
+        if (   nVerify & SSL_VERIFY_NONE
+            && (   sc->szProxyCACertificateFile != NULL
+                || sc->szProxyCACertificatePath != NULL)) {
+            ssl_log(s, SSL_LOG_WARN, 
+                    "init: (%s) CA certificates configured but ignored because 
+SSLProxyVerify is Off",
+                    cpVHostID);
+        }
+        SSL_CTX_set_verify(ctx, nVerify, ssl_ext_mp_verify_cb);
+
+        /*
+         * Enable session caching. We can safely use the same cache
+         * as used for communicating with the other clients.
+         */
+        SSL_CTX_sess_set_new_cb(sc->pSSLProxyCtx,    
+ssl_callback_NewSessionCacheEntry);
+        SSL_CTX_sess_set_get_cb(sc->pSSLProxyCtx,    
+ssl_callback_GetSessionCacheEntry);
+        SSL_CTX_sess_set_remove_cb(sc->pSSLProxyCtx, 
+ssl_callback_DelSessionCacheEntry);
+
+        /*
+         *  Configure SSL Cipher Suite
+         */
+        ssl_log(s, SSL_LOG_TRACE,
+                "Init: (%s) Configuring permitted SSL ciphers for SSL proxy", 
+cpVHostID);
+        if (sc->szProxyCipherSuite != NULL) {
+            if (!SSL_CTX_set_cipher_list(sc->pSSLProxyCtx, sc->szProxyCipherSuite)) {
+                ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+                        "Init: (%s) Unable to configure permitted SSL ciphers for SSL 
+Proxy",
+                        cpVHostID);
+                ssl_die();
+            }
+        }
+
+        /*
+         * Configure Client Authentication details
+         */
+        if (sc->szProxyCACertificateFile != NULL || sc->szProxyCACertificatePath != 
+NULL) {
+             ssl_log(s, SSL_LOG_DEBUG, 
+                     "Init: (%s) Configuring client verification locations for SSL 
+Proxy", 
+                     cpVHostID);
+             if (!SSL_CTX_load_verify_locations(sc->pSSLProxyCtx,
+                                                sc->szProxyCACertificateFile,
+                                                sc->szProxyCACertificatePath)) {
+                 ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, 
+                         "Init: (%s) Unable to configure SSL verify locations for SSL 
+proxy",
+                         cpVHostID);
+                 ssl_die();
+             }
+        }
+    }
+    return;
+}
+
 static int ssl_ext_mp_canon(request_rec *r, char *url)
 {
     int rc;
@@ -289,24 +432,30 @@
         return DEFAULT_HTTP_PORT;
 }
 
-static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb)
+static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb, char *peer)
 {
-    SSL_CTX *ssl_ctx;
     SSL *ssl;
     char *errmsg;
     int rc;
     char *cpVHostID;
     char *cpVHostMD5;
+    SSLSrvConfigRec *sc;
+    char *cp;
 
     if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PFALSE)
         return NULL;
+
+    /*
+     * Find context
+     */
+    sc = mySrvConfig(r->server);
     cpVHostID = ssl_util_vhostid(r->pool, r->server);
 
     /*
      * Create a SSL context and handle
      */
-    ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-    if ((ssl = SSL_new(ssl_ctx)) == NULL) {
+    ssl = SSL_new(sc->pSSLProxyCtx);
+    if (ssl == NULL) {
         errmsg = ap_pstrcat(r->pool, "SSL new failed (%s): ", cpVHostID,
                             ERR_reason_error_string(ERR_get_error()), NULL);
         ap_ctx_set(fb->ctx, "ssl", NULL);
@@ -321,7 +470,12 @@
         return errmsg;
     }
     SSL_set_fd(ssl, fb->fd);
+    SSL_set_app_data(ssl, fb->ctx);
     ap_ctx_set(fb->ctx, "ssl", ssl);
+    ap_ctx_set(fb->ctx, "ssl::proxy::server_rec", r->server);
+    ap_ctx_set(fb->ctx, "ssl::proxy::peer", peer);
+    ap_ctx_set(fb->ctx, "ssl::proxy::servername", cpVHostID);
+    ap_ctx_set(fb->ctx, "ssl::proxy::verifyerror", NULL);
 
     /*
      * Give us a chance to gracefully close the connection
@@ -333,8 +487,17 @@
      * Establish the SSL connection
      */
     if ((rc = SSL_connect(ssl)) <= 0) {
-        errmsg = ap_pstrcat(r->pool, "SSL connect failed (%s): ", cpVHostID,
-                            ERR_reason_error_string(ERR_get_error()), NULL);
+        if ((cp = (char *)ap_ctx_get(fb->ctx, "ssl::proxy::verifyerror")) != NULL) {
+            SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); 
+            SSL_smart_shutdown(ssl);
+            SSL_free(ssl);
+            ap_ctx_set(fb->ctx, "ssl", NULL);
+            ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+            return NULL;
+        }
+        errmsg = ap_psprintf(r->pool, "SSL proxy connect failed (%s): peer %s: %s",
+                             cpVHostID, peer, 
+ERR_reason_error_string(ERR_get_error()));
+        ssl_log(r->server, SSL_LOG_ERROR, errmsg);
         SSL_free(ssl);
         ap_ctx_set(fb->ctx, "ssl", NULL);
         return errmsg;
@@ -371,6 +534,179 @@
     return DECLINED;
 }
 
+/* 
+ * Callback for client certificate stuff.
+ * If the remote site sent us a SSLv3 list of acceptable CA's then trawl the
+ * table of client certs and send the first one that matches.
+ */
+static int ssl_ext_mp_clientcert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) 
+{
+    SSLSrvConfigRec *sc;
+    X509_NAME *xnx;
+    X509_NAME *issuer;
+    X509_INFO *xi;
+    char *peer;
+    char *servername;
+    server_rec *s;
+    ap_ctx *pCtx;
+    STACK_OF(X509_NAME) *sk;
+    STACK_OF(X509_INFO) *pcerts;
+    char *cp;
+    int i, j;
+    
+    pCtx       = (ap_ctx *)SSL_get_app_data(ssl);
+    s          = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
+    peer       = ap_ctx_get(pCtx, "ssl::proxy::peer");
+    servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
+
+    sc         = mySrvConfig(s);
+    pcerts     = ap_ctx_get(sc->ctx, "ssl::proxy::clientcerts");
+
+    ssl_log(s, SSL_LOG_DEBUG, "Proxy client certificate callback: (%s) entered");
+
+    if ((pcerts == NULL) || (sk_X509_INFO_num(pcerts) <= 0)) {
+        ssl_log(s, SSL_LOG_TRACE,
+                "Proxy client certificate callback: (%s) "
+                "site wanted client certificate but none available", 
+                servername);
+        return 0;
+    }                                                                     
+
+    sk = SSL_get_client_CA_list(ssl);
+
+    if ((sk == NULL) || (sk_X509_NAME_num(sk) <= 0)) {
+        /* 
+         * remote site didn't send us a list of acceptable CA certs, 
+         * so lets send the first one we came across 
+         */   
+        xi = sk_X509_INFO_value(pcerts, 0);
+        cp  = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
+        ssl_log(s, SSL_LOG_DEBUG,
+                "SSL Proxy: (%s) no acceptable CA list, sending %s", 
+                servername, cp != NULL ? cp : "-unknown-");
+        free(cp);
+        /* export structures to the caller */
+        *x509 = xi->x509;
+        *pkey = xi->x_pkey->dec_pkey;
+        /* prevent OpenSSL freeing these structures */
+        CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
+        CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
+        return 1;
+    }         
+
+    for (i = 0; i < sk_X509_NAME_num(sk); i++) {
+        xnx = sk_X509_NAME_value(sk, i);
+        for (j = 0; j < sk_X509_INFO_num(pcerts); j++) {
+            xi = sk_X509_INFO_value(pcerts,j);
+            issuer = X509_get_issuer_name(xi->x509);
+            if (X509_NAME_cmp(issuer, xnx) == 0) {
+                cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
+                ssl_log(s, SSL_LOG_DEBUG, "SSL Proxy: (%s) sending %s", 
+                        servername, cp != NULL ? cp : "-unknown-");
+                free(cp);
+                /* export structures to the caller */
+                *x509 = xi->x509;
+                *pkey = xi->x_pkey->dec_pkey;
+                /* prevent OpenSSL freeing these structures */
+                CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
+                CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
+                return 1;
+            }
+        }
+    }
+    ssl_log(s, SSL_LOG_TRACE,
+            "Proxy client certificate callback: (%s) "
+            "no client certificate found!?", servername);
+    return 0; 
+}
+
+/*
+ * This is the verify callback when we are connecting to a remote SSL server
+ * from the proxy. Information is passed in via the SSL "ctx" app_data
+ * mechanism. We pass in an Apache context in this field, which contains
+ * server_rec of the server making the proxy connection from the
+ * "ssl::proxy::server_rec" context.
+ *
+ * The result of the verification is passed back out to SSLERR via the return
+ * value. We also store the error message in the "proxyverifyfailed" context,
+ * so the caller of SSL_connect() can log a detailed error message.
+ */
+static int ssl_ext_mp_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+    SSLSrvConfigRec *sc;
+    X509 *xs;
+    int errnum;
+    int errdepth;
+    char *cp, *cp2;
+    ap_ctx *pCtx;
+    server_rec *s;
+    SSL *ssl;
+    char *peer;
+    char *servername;
+
+    ssl        = (SSL *)X509_STORE_CTX_get_app_data(ctx);
+    pCtx       = (ap_ctx *)SSL_get_app_data(ssl);
+    s          = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
+    peer       = ap_ctx_get(pCtx, "ssl::proxy::peer");
+    servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
+    sc         = mySrvConfig(s);
+
+    /*
+     * Get verify ingredients
+     */
+    xs       = X509_STORE_CTX_get_current_cert(ctx);
+    errnum   = X509_STORE_CTX_get_error(ctx);
+    errdepth = X509_STORE_CTX_get_error_depth(ctx);
+
+    /* 
+     * Log verification information
+     */
+    cp  = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
+    cp2 = X509_NAME_oneline(X509_get_issuer_name(xs),  NULL, 0);
+    ssl_log(s, SSL_LOG_DEBUG,
+            "SSL Proxy: (%s) Certificate Verification for remote server %s: "
+            "depth: %d, subject: %s, issuer: %s", 
+            servername, peer != NULL ? peer : "-unknown-",
+            errdepth, cp != NULL ? cp : "-unknown-", 
+            cp2 != NULL ? cp2 : "-unknown");
+    free(cp);
+    free(cp2);
+
+    /*
+     * If we already know it's not ok, log the real reason
+     */
+    if (!ok) {
+        ssl_log(s, SSL_LOG_ERROR,
+                "SSL Proxy: (%s) Certificate Verification failed for %s: "
+                "Error (%d): %s", servername,
+                peer != NULL ? peer : "-unknown-",
+                errnum, X509_verify_cert_error_string(errnum));
+        ap_ctx_set(pCtx, "ssl::proxy::verifyerror", 
+                   (void *)X509_verify_cert_error_string(errnum));
+        return ok;
+    }
+
+    /*
+     * Check the depth of the certificate chain
+     */
+    if (sc->nProxyVerifyDepth > 0) {
+        if (errdepth > sc->nProxyVerifyDepth) {
+            ssl_log(s, SSL_LOG_ERROR,
+                "SSL Proxy: (%s) Certificate Verification failed for %s: "
+                "Certificate Chain too long "
+                "(chain has %d certificates, but maximum allowed are only %d)", 
+                servername, peer, errdepth, sc->nProxyVerifyDepth);
+            ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
+                       (void 
+*)X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG));
+            ok = FALSE;
+        }
+    }
+
+    /*
+     * And finally signal OpenSSL the (perhaps changed) state
+     */
+    return (ok);
+}
 
 /*  _________________________________________________________________
 **
Index: src/modules/ssl/ssl_engine_init.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_init.c,v
retrieving revision 1.94
diff -u -r1.94 ssl_engine_init.c
--- src/modules/ssl/ssl_engine_init.c   2000/02/09 16:29:13     1.94
+++ src/modules/ssl/ssl_engine_init.c   2000/02/23 10:31:01
@@ -152,6 +152,8 @@
             sc->nVerifyClient = SSL_CVERIFY_NONE;
         if (sc->nVerifyDepth == UNSET)
             sc->nVerifyDepth = 1;
+        if (sc->nProxyVerifyDepth == UNSET)
+            sc->nProxyVerifyDepth = 1;
         if (sc->nSessionCacheTimeout == UNSET)
             sc->nSessionCacheTimeout = SSL_SESSION_CACHE_TIMEOUT;
         if (sc->nPassPhraseDialogType == SSL_PPTYPE_UNSET)
Index: src/modules/ssl/ssl_util_ssl.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_util_ssl.c,v
retrieving revision 1.19
diff -u -r1.19 ssl_util_ssl.c
--- src/modules/ssl/ssl_util_ssl.c      2000/02/06 13:34:52     1.19
+++ src/modules/ssl/ssl_util_ssl.c      2000/02/23 10:31:02
@@ -392,6 +392,57 @@
 
 /*  _________________________________________________________________
 **
+**  Low-Level CA Certificate Loading
+**  _________________________________________________________________
+*/
+
+BOOL SSL_load_CrtAndKeyInfo_file(pool *p, STACK_OF(X509_INFO) *sk, char *filename)
+{
+    BIO *in;
+
+    if ((in = BIO_new(BIO_s_file())) == NULL)
+        return FALSE;
+    if (BIO_read_filename(in, filename) <= 0) {
+        BIO_free(in);
+        return FALSE;
+    }
+    ERR_clear_error();
+    PEM_X509_INFO_read_bio(in, sk, NULL);
+    BIO_free(in);
+    return TRUE;
+}
+
+BOOL SSL_load_CrtAndKeyInfo_path(pool *p, STACK_OF(X509_INFO) *sk, char *pathname)
+{
+    struct stat st;
+    DIR *dir;
+    pool *sp;
+    struct dirent *nextent;
+    char *fullname;
+    BOOL ok;
+
+    sp = ap_make_sub_pool(p);
+    if ((dir = ap_popendir(sp, pathname)) == NULL) {
+        ap_destroy_pool(sp);
+        return FALSE;
+    }
+    ok = FALSE;
+    while ((nextent = readdir(dir)) != NULL) {
+        fullname = ap_pstrcat(sp, pathname, "/", nextent->d_name, NULL);
+        if (stat(fullname, &st) != 0)
+            continue;
+        if (!S_ISREG(st.st_mode))
+            continue;
+        if (SSL_load_CrtAndKeyInfo_file(sp, sk, fullname))
+            ok = TRUE;
+    }
+    ap_pclosedir(p, dir);
+    ap_destroy_pool(sp);
+    return ok;
+}              
+
+/*  _________________________________________________________________
+**
 **  Extra Server Certificate Chain Support
 **  _________________________________________________________________
 */
Index: src/modules/ssl/ssl_util_ssl.h
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_util_ssl.h,v
retrieving revision 1.15
diff -u -r1.15 ssl_util_ssl.h
--- src/modules/ssl/ssl_util_ssl.h      1999/12/30 20:58:09     1.15
+++ src/modules/ssl/ssl_util_ssl.h      1999/12/30 21:18:42
@@ -98,6 +98,8 @@
 BOOL        SSL_X509_isSGC(X509 *);
 BOOL        SSL_X509_getBC(X509 *, int *, int *);
 BOOL        SSL_X509_getCN(pool *, X509 *, char **);
+BOOL        SSL_load_CrtAndKeyInfo_file(pool *, STACK_OF(X509_INFO) *, char *);
+BOOL        SSL_load_CrtAndKeyInfo_path(pool *, STACK_OF(X509_INFO) *, char *);
 int         SSL_CTX_use_certificate_chain(SSL_CTX *, char *, int, int (*)());
 
 #endif /* SSL_UTIL_SSL_H */

______________________________________________________________________
Apache Interface to OpenSSL (mod_ssl)                   www.modssl.org
User Support Mailing List                      [EMAIL PROTECTED]
Automated List Manager                            [EMAIL PROTECTED]

Reply via email to