You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by jo...@apache.org on 2009/10/25 18:21:11 UTC

svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Author: jorton
Date: Sun Oct 25 17:21:10 2009
New Revision: 829619

URL: http://svn.apache.org/viewvc?rev=829619&view=rev
Log:
Add support for OCSP "stapling":

* modules/ssl/ssl_util_stapling.c: New file.

* modules/ssl/config.m4, modules/ssl/mod_ssl.dsp: Build it.

* modules/ssl/ssl_toolkit_compat.h: Define HAVE_OCSP_STAPLING if
  OpenSSL is of suitable version (>= 0.9.8g) and capability (TLS
  extension support enabled).

* modules/ssl/mod_ssl.c: Add config directives.

* modules/ssl/ssl_private.h: Add prototypes for new functions.
  (SSLModConfigRec): Add fields for stapling socache instance and
  associated mutex.
  (modssl_ctx_t): Add config fields for stapling.

* modules/ssl/ssl_engine_init.c (ssl_init_Module, ssl_init_Child):
  Call the stapling initialization functions.

* modules/ssl/ssl_engine_config.c: Add config hooks.

* modules/ssl/ssl_scache.c: Create, initialize and destroy the socache
  instance for OCSP responses.

Submitted by: Dr Stephen Henson <shenson oss-institute.org>

Added:
    httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c
Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/modules/ssl/config.m4
    httpd/httpd/trunk/modules/ssl/mod_ssl.c
    httpd/httpd/trunk/modules/ssl/mod_ssl.dsp
    httpd/httpd/trunk/modules/ssl/ssl_engine_config.c
    httpd/httpd/trunk/modules/ssl/ssl_engine_init.c
    httpd/httpd/trunk/modules/ssl/ssl_private.h
    httpd/httpd/trunk/modules/ssl/ssl_scache.c
    httpd/httpd/trunk/modules/ssl/ssl_toolkit_compat.h

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sun Oct 25 17:21:10 2009
@@ -10,6 +10,9 @@
      mod_proxy_ftp: NULL pointer dereference on error paths.
      [Stefan Fritsch <sf fritsch.de>, Joe Orton]
 
+  *) mod_ssl: Add support for OCSP Stapling.  PR 43822.  
+     [Dr Stephen Henson <shenson oss-institute.org>]
+
   *) mod_socache_shmcb: Allow parens in file name if cache size is given.
      Fixes SSLSessionCache directive mis-parsing parens in pathname.
      PR 47945. [Stefan Fritsch]

Modified: httpd/httpd/trunk/modules/ssl/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/config.m4?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/config.m4 (original)
+++ httpd/httpd/trunk/modules/ssl/config.m4 Sun Oct 25 17:21:10 2009
@@ -40,6 +40,7 @@
 ssl_expr_parse.lo dnl
 ssl_expr_scan.lo dnl
 ssl_scache.lo dnl
+ssl_util_stapling.lo dnl
 ssl_util.lo dnl
 ssl_util_ssl.lo dnl
 ssl_engine_ocsp.lo dnl

Modified: httpd/httpd/trunk/modules/ssl/mod_ssl.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/mod_ssl.c?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/mod_ssl.c (original)
+++ httpd/httpd/trunk/modules/ssl/mod_ssl.c Sun Oct 25 17:21:10 2009
@@ -197,6 +197,36 @@
     SSL_CMD_SRV(OCSPOverrideResponder, FLAG,
                "Force use of the default responder URL ('on', 'off')")
 
+#ifdef HAVE_OCSP_STAPLING
+    /*
+     * OCSP Stapling options
+     */
+    SSL_CMD_SRV(StaplingMutex, TAKE1, AP_ALL_AVAILABLE_MUTEXES_STRING)
+    SSL_CMD_SRV(StaplingCache, TAKE1,
+                "SSL Stapling Response Cache storage "
+                "(`dbm:/path/to/file')")
+    SSL_CMD_SRV(UseStapling, FLAG,
+                "SSL switch for the OCSP Stapling protocol " "(`on', `off')")
+    SSL_CMD_SRV(StaplingResponseTimeSkew, TAKE1,
+                "SSL stapling option for maximum time difference in OCSP responses")
+    SSL_CMD_SRV(StaplingResponderTimeout, TAKE1,
+                "SSL stapling option for OCSP responder timeout")
+    SSL_CMD_SRV(StaplingResponseMaxAge, TAKE1,
+                "SSL stapling option for maximum age of OCSP responses")
+    SSL_CMD_SRV(StaplingStandardCacheTimeout, TAKE1,
+                "SSL stapling option for normal OCSP Response Cache Lifetime")
+    SSL_CMD_SRV(StaplingReturnResponderErrors, FLAG,
+                "SSL stapling switch to return Status Errors Back to Client"
+		"(`on', `off')")
+    SSL_CMD_SRV(StaplingFakeTryLater, FLAG,
+                "SSL stapling switch to send tryLater response to client on error "
+		"(`on', `off')")
+    SSL_CMD_SRV(StaplingErrorCacheTimeout, TAKE1,
+                "SSL stapling option for OCSP Response Error Cache Lifetime")
+    SSL_CMD_SRV(StaplingForceURL, TAKE1,
+                "SSL stapling option to Force the OCSP Stapling URL")
+#endif
+
     /* Deprecated directives. */
     AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL,
       "SSLLog directive is no longer supported - use ErrorLog."),

Modified: httpd/httpd/trunk/modules/ssl/mod_ssl.dsp
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/mod_ssl.dsp?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/mod_ssl.dsp (original)
+++ httpd/httpd/trunk/modules/ssl/mod_ssl.dsp Sun Oct 25 17:21:10 2009
@@ -210,6 +210,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\ssl_util_stapling.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\ssl_util.c
 # End Source File
 # Begin Source File

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_config.c?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_config.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_config.c Sun Oct 25 17:21:10 2009
@@ -73,6 +73,13 @@
 #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
     mc->szCryptoDevice         = NULL;
 #endif
+#ifdef HAVE_OCSP_STAPLING
+    mc->stapling_cache                  = NULL;
+    mc->stapling_mutex_mode             = SSL_MUTEXMODE_UNSET;
+    mc->stapling_mutex_mech             = APR_LOCK_DEFAULT;
+    mc->stapling_mutex_file            = NULL;
+    mc->stapling_mutex                 = NULL;
+#endif
 
     memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys));
 
@@ -129,6 +136,18 @@
     mctx->ocsp_enabled        = FALSE;
     mctx->ocsp_force_default  = FALSE;
     mctx->ocsp_responder      = NULL;
+
+#ifdef HAVE_OCSP_STAPLING
+    mctx->stapling_enabled                   = UNSET;
+    mctx->stapling_resptime_skew      = UNSET;
+    mctx->stapling_resp_maxage        = UNSET;
+    mctx->stapling_cache_timeout  = UNSET;
+    mctx->stapling_return_errors = UNSET;
+    mctx->stapling_fake_trylater          = UNSET;
+    mctx->stapling_errcache_timeout     = UNSET;
+    mctx->stapling_responder_timeout      = UNSET;
+    mctx->stapling_force_url   		= NULL;
+#endif
 }
 
 static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc,
@@ -227,6 +246,17 @@
     cfgMergeBool(ocsp_enabled);
     cfgMergeBool(ocsp_force_default);
     cfgMerge(ocsp_responder, NULL);
+#ifdef HAVE_OCSP_STAPLING
+    cfgMergeBool(stapling_enabled);
+    cfgMergeInt(stapling_resptime_skew);
+    cfgMergeInt(stapling_resp_maxage);
+    cfgMergeInt(stapling_cache_timeout);
+    cfgMergeBool(stapling_return_errors);
+    cfgMergeBool(stapling_fake_trylater);
+    cfgMergeInt(stapling_errcache_timeout);
+    cfgMergeInt(stapling_responder_timeout);
+    cfgMerge(stapling_force_url, NULL);
+#endif
 }
 
 static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base,
@@ -1461,6 +1491,188 @@
 #endif
 }
 
+#ifdef HAVE_OCSP_STAPLING
+
+const char *ssl_cmd_SSLStaplingCache(cmd_parms *cmd,
+                                    void *dcfg,
+                                    const char *arg)
+{
+    SSLModConfigRec *mc = myModConfig(cmd->server);
+    const char *err, *sep, *name;
+
+    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+        return err;
+    }
+
+    /* Argument is of form 'name:args' or just 'name'. */
+    sep = ap_strchr_c(arg, ':');
+    if (sep) {
+        name = apr_pstrmemdup(cmd->pool, arg, sep - arg);
+        sep++;
+    }
+    else {
+        name = arg;
+    }
+
+    /* Find the provider of given name. */
+    mc->stapling_cache = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP,
+                                            name,
+                                            AP_SOCACHE_PROVIDER_VERSION);
+    if (mc->stapling_cache) {
+        /* Cache found; create it, passing anything beyond the colon. */
+        err = mc->stapling_cache->create(&mc->stapling_cache_context,
+                                         sep, cmd->temp_pool, 
+                                         cmd->pool);
+    }
+    else {
+        apr_array_header_t *name_list;
+        const char *all_names;
+        
+        /* Build a comma-separated list of all registered provider
+         * names: */
+        name_list = ap_list_provider_names(cmd->pool, 
+                                           AP_SOCACHE_PROVIDER_GROUP,
+                                           AP_SOCACHE_PROVIDER_VERSION);
+        all_names = apr_array_pstrcat(cmd->pool, name_list, ',');
+        
+        err = apr_psprintf(cmd->pool, "'%s' stapling cache not supported "
+                           "(known names: %s)", name, all_names);
+    }
+
+    if (err) {
+        return apr_psprintf(cmd->pool, "SSLStaplingCache: %s", err);
+    }
+    
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingMutex(cmd_parms *cmd,
+                                     void *dcfg,
+                                     const char *arg_)
+{
+    apr_status_t rv;
+    const char *err;
+    SSLModConfigRec *mc = myModConfig(cmd->server);
+
+    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+        return err;
+    }
+
+    if (ssl_config_global_isfixed(mc)) {
+        return NULL;
+    }
+
+    rv = ap_parse_mutex(arg_, cmd->server->process->pool,
+                        &mc->stapling_mutex_mech, &mc->stapling_mutex_file);
+
+    if (rv == APR_ENOLOCK) {
+        mc->stapling_mutex_mode  = SSL_MUTEXMODE_NONE;
+        return NULL;
+    } 
+    else if (rv == APR_ENOTIMPL) {
+        return apr_pstrcat(cmd->pool, "Invalid SSLStaplingMutex argument ",
+                           arg_,
+                           " (" AP_ALL_AVAILABLE_MUTEXES_STRING ")", NULL);
+    } 
+    else if (rv == APR_BADARG) {
+        return apr_pstrcat(cmd->pool, "Invalid SSLStaplingMutex filepath ",
+                           arg_, NULL);
+    }
+
+    mc->stapling_mutex_mode  = SSL_MUTEXMODE_USED;
+
+    return NULL;
+}
+
+const char *ssl_cmd_SSLUseStapling(cmd_parms *cmd, void *dcfg, int flag)
+{   
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_enabled = flag ? TRUE : FALSE;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingResponseTimeSkew(cmd_parms *cmd, void *dcfg,
+                                                    const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_resptime_skew = atoi(arg);
+    if (sc->server->stapling_resptime_skew < 0) {
+        return "SSLstapling_resptime_skew: invalid argument";
+    }
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingResponseMaxAge(cmd_parms *cmd, void *dcfg,
+                                                    const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_resp_maxage = atoi(arg);
+    if (sc->server->stapling_resp_maxage < 0) {
+        return "SSLstapling_resp_maxage: invalid argument";
+    }
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingStandardCacheTimeout(cmd_parms *cmd, void *dcfg,
+                                                    const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_cache_timeout = atoi(arg);
+    if (sc->server->stapling_cache_timeout < 0) {
+        return "SSLstapling_cache_timeout: invalid argument";
+    }
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingErrorCacheTimeout(cmd_parms *cmd, void *dcfg,
+                                                 const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_errcache_timeout = atoi(arg);
+    if (sc->server->stapling_errcache_timeout < 0) {
+        return "SSLstapling_errcache_timeout: invalid argument";
+    }
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingReturnResponderErrors(cmd_parms *cmd,
+                                                     void *dcfg, int flag)
+{   
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_return_errors = flag ? TRUE : FALSE;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingFakeTryLater(cmd_parms *cmd,
+                                            void *dcfg, int flag)
+{   
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_fake_trylater = flag ? TRUE : FALSE;
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingResponderTimeout(cmd_parms *cmd, void *dcfg,
+                                                const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_responder_timeout = atoi(arg);
+    sc->server->stapling_responder_timeout *= APR_USEC_PER_SEC;
+    if (sc->server->stapling_responder_timeout < 0) {
+        return "SSLstapling_responder_timeout: invalid argument";
+    }
+    return NULL;
+}
+
+const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *cmd, void *dcfg,
+                                        const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    sc->server->stapling_force_url = arg;
+    return NULL;
+}
+
+#endif /* HAVE_OCSP_STAPLING */
+
 void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
 {
     if (!ap_exists_config_define("DUMP_CERTS")) {

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_init.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_init.c?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_init.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_init.c Sun Oct 25 17:21:10 2009
@@ -249,6 +249,13 @@
     if (!ssl_mutex_init(base_server, p)) {
         return HTTP_INTERNAL_SERVER_ERROR;
     }
+#ifdef HAVE_OCSP_STAPLING
+    if (!ssl_stapling_mutex_init(base_server, p)) {
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    ssl_stapling_ex_init();
+#endif
 
     /*
      * initialize session caching
@@ -382,6 +389,15 @@
         ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
         ssl_die();
     }
+
+#ifdef HAVE_OCSP_STAPLING
+    /*
+     * OCSP Stapling support, status_request extension
+     */
+    if ((mctx->pkp == FALSE) && (mctx->stapling_enabled == TRUE)) {
+        modssl_init_stapling(s, p, ptemp, mctx);
+    }
+#endif
 }
 #endif
 
@@ -773,6 +789,15 @@
         ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
         ssl_die();
     }
+  
+#ifdef HAVE_OCSP_STAPLING
+    if ((mctx->pkp == FALSE) && (mctx->stapling_enabled == TRUE)) {
+        if (!ssl_stapling_init_cert(s, mctx, cert)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                         "Unable to configure server certificate for stapling");
+        }
+    }
+#endif
 
     mctx->pks->certs[idx] = cert;
 
@@ -1246,6 +1271,9 @@
 
     /* open the mutex lockfile */
     ssl_mutex_reinit(s, p);
+#ifdef HAVE_OCSP_STAPLING
+    ssl_stapling_mutex_reinit(s, p);
+#endif
 }
 
 #define MODSSL_CFG_ITEM_FREE(func, item) \

Modified: httpd/httpd/trunk/modules/ssl/ssl_private.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_private.h?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_private.h (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_private.h Sun Oct 25 17:21:10 2009
@@ -391,6 +391,16 @@
 #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
     const char     *szCryptoDevice;
 #endif
+
+#ifdef HAVE_OCSP_STAPLING
+    const ap_socache_provider_t *stapling_cache;
+    ap_socache_instance_t *stapling_cache_context;
+    ssl_mutexmode_t stapling_mutex_mode;
+    apr_lockmech_e  stapling_mutex_mech;
+    const char     *stapling_mutex_file;
+    apr_global_mutex_t   *stapling_mutex;
+#endif
+
     struct {
         void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10;
     } rCtx;
@@ -457,6 +467,19 @@
     const char  *crl_file;
     X509_STORE  *crl;
 
+#ifdef HAVE_OCSP_STAPLING
+    /** OCSP stapling options */
+    BOOL        stapling_enabled;
+    long        stapling_resptime_skew;
+    long        stapling_resp_maxage;
+    int         stapling_cache_timeout;
+    BOOL        stapling_return_errors;
+    BOOL        stapling_fake_trylater;
+    int         stapling_errcache_timeout;
+    apr_interval_time_t stapling_responder_timeout;
+    const char *stapling_force_url;
+#endif
+
     modssl_auth_ctx_t auth;
 
     BOOL ocsp_enabled; /* true if OCSP verification enabled */
@@ -614,6 +637,24 @@
 int ssl_proxy_enable(conn_rec *c);
 int ssl_engine_disable(conn_rec *c);
 
+/** OCSP Stapling Support */
+#ifdef HAVE_OCSP_STAPLING
+const char *ssl_cmd_SSLStaplingMutex(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLStaplingCache(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLUseStapling(cmd_parms *, void *, int);
+const char *ssl_cmd_SSLStaplingResponseTimeSkew(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLStaplingResponseMaxAge(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLStaplingStandardCacheTimeout(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLStaplingErrorCacheTimeout(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLStaplingReturnResponderErrors(cmd_parms *, void *, int);
+const char *ssl_cmd_SSLStaplingFakeTryLater(cmd_parms *, void *, int);
+const char *ssl_cmd_SSLStaplingResponderTimeout(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLStaplingForceURL(cmd_parms *, void *, const char *);
+void         modssl_init_stapling(server_rec *, apr_pool_t *, apr_pool_t *, modssl_ctx_t *);
+void         ssl_stapling_ex_init(void);
+int          ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x);
+#endif
+
 /**  I/O  */
 void         ssl_io_filter_init(conn_rec *, request_rec *r, SSL *);
 void         ssl_io_filter_register(apr_pool_t *);
@@ -670,6 +711,9 @@
 int          ssl_mutex_on(server_rec *);
 int          ssl_mutex_off(server_rec *);
 
+int          ssl_stapling_mutex_init(server_rec *, apr_pool_t *);
+int          ssl_stapling_mutex_reinit(server_rec *, apr_pool_t *);
+
 /**  Logfile Support  */
 void         ssl_die(void);
 void         ssl_log_ssl_error(const char *, int, int, server_rec *);

Modified: httpd/httpd/trunk/modules/ssl/ssl_scache.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_scache.c?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_scache.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_scache.c Sun Oct 25 17:21:10 2009
@@ -57,6 +57,22 @@
         return;
     }
 
+#ifdef HAVE_OCSP_STAPLING
+    if (mc->stapling_cache) {
+        memset(&hints, 0, sizeof hints);
+        hints.avg_obj_size = 1500;
+        hints.avg_id_len = 20;
+        hints.expiry_interval = 300;
+    
+        rv = mc->stapling_cache->init(mc->stapling_cache_context,
+                                     "mod_ssl-stapling", &hints, s, p);
+        if (rv) {
+            /* ABORT ABORT etc. */
+            ssl_die();
+        }
+    }
+#endif
+
     /*
      * Warn the user that he should use the session cache.
      * But we can operate without it, of course.
@@ -73,7 +89,7 @@
     hints.avg_id_len = 30;
     hints.expiry_interval = 30;
     
-    rv = mc->sesscache->init(mc->sesscache_context, "mod_ssl", &hints, s, p);
+    rv = mc->sesscache->init(mc->sesscache_context, "mod_ssl-session", &hints, s, p);
     if (rv) {
         /* ABORT ABORT etc. */
         ssl_die();
@@ -87,6 +103,13 @@
     if (mc->sesscache) {
         mc->sesscache->destroy(mc->sesscache_context, s);
     }
+
+#ifdef HAVE_OCSP_STAPLING
+    if (mc->stapling_cache) {
+        mc->stapling_cache->destroy(mc->stapling_cache_context, s);
+    }
+#endif
+
 }
 
 BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen,

Modified: httpd/httpd/trunk/modules/ssl/ssl_toolkit_compat.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_toolkit_compat.h?rev=829619&r1=829618&r2=829619&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_toolkit_compat.h (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_toolkit_compat.h Sun Oct 25 17:21:10 2009
@@ -147,6 +147,12 @@
 
 #define HAVE_SSL_X509V3_EXT_d2i
 
+#if (OPENSSL_VERSION_NUMBER >= 0x00908080)
+#ifndef OPENSSL_NO_TLSEXT
+#define HAVE_OCSP_STAPLING
+#endif
+#endif
+
 #ifndef PEM_F_DEF_CALLBACK
 #ifdef PEM_F_PEM_DEF_CALLBACK
 /** In OpenSSL 0.9.8 PEM_F_DEF_CALLBACK was renamed */

Added: httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c?rev=829619&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c (added)
+++ httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c Sun Oct 25 17:21:10 2009
@@ -0,0 +1,699 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*                      _             _
+ *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
+ * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
+ * | | | | | | (_) | (_| |   \__ \__ \ |
+ * |_| |_| |_|\___/ \__,_|___|___/___/_|
+ *                      |_____|
+ *  ssl_stapling.c
+ *  OCSP Stapling Support
+ */
+                             /* ``Where's the spoons?
+                                  Where's the spoons? 
+                                  Where's the bloody spoons?''
+                                            -- Alexei Sayle          */
+
+#include "ssl_private.h"
+#include "ap_mpm.h"
+#include "apr_thread_mutex.h"
+
+#ifdef AP_NEED_SET_MUTEX_PERMS
+#include "unixd.h"
+#endif
+
+#ifdef HAVE_OCSP_STAPLING
+
+/**
+ * Maxiumum OCSP stapling response size. This should be the response for a
+ * single certificate and will typically include the responder certificate chain
+ * so 10K should be more than enough.
+ *
+ */
+
+#define MAX_STAPLING_DER 10240
+
+/* Cached info stored in certificate ex_info. */
+typedef struct {
+    /* Index in session cache SHA1 hash of certificate */
+    UCHAR idx[20];
+    /* Certificate ID for OCSP requests or NULL if ID cannot be determined */
+    OCSP_CERTID *cid;
+    /* Responder details */
+    char *uri;
+} certinfo;
+
+static void certinfo_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+                                        int idx, long argl, void *argp)
+{
+    certinfo *cinf = ptr;
+
+    if (!cinf)
+        return;
+    if (cinf->uri)
+        OPENSSL_free(cinf->uri);
+    OPENSSL_free(cinf);
+}
+
+static int stapling_ex_idx = -1;
+
+void ssl_stapling_ex_init(void)
+{
+    if (stapling_ex_idx != -1)
+        return;
+    stapling_ex_idx = X509_get_ex_new_index(0, "X509 cached OCSP info", 0, 0,
+                                            certinfo_free);
+}
+
+static X509 *stapling_get_issuer(modssl_ctx_t *mctx, X509 *x)
+{
+    X509 *issuer = NULL;
+    int i;
+    X509_STORE *st = SSL_CTX_get_cert_store(mctx->ssl_ctx);
+    X509_STORE_CTX inctx;
+
+    for (i = 0; i < sk_X509_num(mctx->ssl_ctx->extra_certs); i++) {
+	issuer = sk_X509_value(mctx->ssl_ctx->extra_certs, i);
+        if (X509_check_issued(issuer, x) == X509_V_OK) {
+            CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
+            return issuer;
+        }
+    }
+
+    if (!X509_STORE_CTX_init(&inctx, st, NULL, NULL))
+        return 0;
+    if (X509_STORE_CTX_get1_issuer(&issuer, &inctx, x) <= 0)
+	issuer = NULL;
+    X509_STORE_CTX_cleanup(&inctx);
+    return issuer;
+
+}
+
+int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x)
+{
+    certinfo *cinf;
+    X509 *issuer = NULL;
+    STACK *aia = NULL;
+
+    if (x == NULL)
+        return 0;
+    cinf  = X509_get_ex_data(x, stapling_ex_idx);
+    if (cinf) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                        "ssl_stapling_init_cert: certificate already initialized!");
+        return 0;
+    }
+    cinf = OPENSSL_malloc(sizeof(certinfo));
+    if (!cinf) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                        "ssl_stapling_init_cert: error allocating memory!");
+        return 0;
+    }
+    cinf->cid = NULL;
+    cinf->uri = NULL;
+    X509_set_ex_data(x, stapling_ex_idx, cinf);
+
+    issuer = stapling_get_issuer(mctx, x);
+
+    if (issuer == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                    "ssl_stapling_init_cert: Can't retrieve issuer certificate!");
+        return 0;
+    }
+
+    cinf->cid = OCSP_cert_to_id(NULL, x, issuer);
+    X509_free(issuer);
+    if (!cinf->cid)
+        return 0;
+    X509_digest(x, EVP_sha1(), cinf->idx, NULL);
+
+    aia = X509_get1_ocsp(x);
+    if (aia)
+        cinf->uri = sk_pop(aia);
+    if (!cinf->uri && !mctx->stapling_force_url) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                         "ssl_stapling_init_cert: no responder URL");
+    }
+    if (aia)
+        X509_email_free(aia);
+    return 1;
+}
+
+static certinfo *stapling_get_cert_info(server_rec *s, modssl_ctx_t *mctx,
+                                        SSL *ssl)
+{
+    certinfo *cinf;
+    X509 *x;
+    x = SSL_get_certificate(ssl);
+    if (x == NULL)
+        return NULL;
+    cinf  = X509_get_ex_data(x, stapling_ex_idx);
+    if (cinf && cinf->cid)
+        return cinf;
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
+                 "stapling_get_cert_info: stapling not supported for certificate");
+    return NULL;
+}
+
+/*
+ * OCSP response caching code. The response is preceded by a flag value
+ * which indicates whether the response was invalid when it was stored.
+ * the purpose of this flag is to avoid repeated queries to a server
+ * which has given an invalid response while allowing a response which
+ * has subsequently become invalid to be retried immediately.
+ *
+ * The key for the cache is the hash of the certificate the response
+ * is for.
+ */
+static BOOL stapling_cache_response(server_rec *s, modssl_ctx_t *mctx,
+                                    OCSP_RESPONSE *rsp, certinfo *cinf,
+                                    BOOL ok, apr_pool_t *pool)
+{
+    SSLModConfigRec *mc = myModConfig(s);
+    unsigned char resp_der[MAX_STAPLING_DER];
+    unsigned char *p;
+    int resp_derlen;
+    BOOL rv;
+    time_t timeout;
+
+    resp_derlen = i2d_OCSP_RESPONSE(rsp, NULL) + 1;
+
+    if (resp_derlen <= 0) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "OCSP stapling response encode error??");
+        return FALSE;
+    }
+
+    if (resp_derlen > sizeof resp_der) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "OCSP stapling response too big (%u bytes)", resp_derlen);
+        return FALSE;
+    }
+
+
+    p = resp_der;
+
+    if (ok == TRUE) {
+        *p++ = 1;
+        timeout = mctx->stapling_cache_timeout;
+    } else {
+        *p++ = 0;
+        timeout = mctx->stapling_errcache_timeout;
+    }
+
+    timeout += time(NULL);
+
+    i2d_OCSP_RESPONSE(rsp, &p);
+
+    rv = mc->stapling_cache->store(mc->stapling_cache_context, s,
+                                   cinf->idx, sizeof(cinf->idx),
+                                   timeout, resp_der, resp_derlen, pool);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_cache_response: OCSP response session store error!");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+static BOOL stapling_get_cached_response(server_rec *s, OCSP_RESPONSE **prsp,
+                                         BOOL *pok, certinfo *cinf,
+                                         apr_pool_t *pool)
+{
+    SSLModConfigRec *mc = myModConfig(s);
+    apr_status_t rv;
+    OCSP_RESPONSE *rsp;
+    unsigned char resp_der[MAX_STAPLING_DER];
+    const unsigned char *p;
+    unsigned int resp_derlen = MAX_STAPLING_DER;
+
+    rv = mc->stapling_cache->retrieve(mc->stapling_cache_context, s,
+                                      cinf->idx, sizeof(cinf->idx),
+                                      resp_der, &resp_derlen, pool);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "stapling_get_cached_response: cache miss");
+        return TRUE;
+    }
+    if (resp_derlen <= 1) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_get_cached_response: response length invalid??");
+        return TRUE;
+    }
+    p = resp_der;
+    if (pok) {
+        if (*p)
+            *pok = TRUE;
+        else
+            *pok = FALSE;
+    }
+    p++;
+    resp_derlen--;
+    rsp = d2i_OCSP_RESPONSE(NULL, &p, resp_derlen);
+    if (!rsp) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_get_cached_response: response parse error??");
+        return TRUE;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "stapling_get_cached_response: cache hit");
+
+    *prsp = rsp;
+    
+    return TRUE;
+}
+
+static int stapling_set_response(SSL *ssl, OCSP_RESPONSE *rsp)
+{
+    int rspderlen;
+    unsigned char *rspder = NULL;
+
+    rspderlen = i2d_OCSP_RESPONSE(rsp, &rspder);
+    if (rspderlen <= 0)
+        return 0;
+    SSL_set_tlsext_status_ocsp_resp(ssl, rspder, rspderlen);
+    return 1;
+}
+
+static int stapling_check_response(server_rec *s, modssl_ctx_t *mctx,
+                                   certinfo *cinf, OCSP_RESPONSE *rsp,
+                                   BOOL *pok)
+{
+    int status, reason;
+    OCSP_BASICRESP *bs = NULL;
+    ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+    int response_status = OCSP_response_status(rsp);
+
+    if (pok)
+        *pok = FALSE;
+    /* Check to see if response is an error. If so we automatically accept
+     * it because it would have expired from the cache if it was time to
+     * retry.
+     */
+    if (response_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+        if (mctx->stapling_return_errors)
+            return SSL_TLSEXT_ERR_OK;
+        else 
+            return SSL_TLSEXT_ERR_NOACK;
+    }
+
+    bs = OCSP_response_get1_basic(rsp);
+    if (bs == NULL) {
+        /* If we can't parse response just pass it to client */
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_check_response: Error Parsing Response!");
+        return SSL_TLSEXT_ERR_OK;
+    }
+
+    if (!OCSP_resp_find_status(bs, cinf->cid, &status, &reason, &rev,
+                               &thisupd, &nextupd)) {
+        /* If ID not present just pass back to client */
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_check_response: certificate ID not present in response!");
+    } else {
+        if (OCSP_check_validity(thisupd, nextupd,
+                                mctx->stapling_resptime_skew,
+                                mctx->stapling_resp_maxage)) {
+            if (pok)
+                *pok = TRUE;
+        } 
+        else {
+            /* If pok is not NULL response was direct from a responder and 
+             * the times should be valide. If pok is NULL the response was
+             * retrieved from cache and it is expected to subsequently expire
+             */
+            if (pok) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                             "stapling_check_response: response times invalid");
+            } else {
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                             "stapling_check_response: cached response expired");
+            }
+ 
+            OCSP_BASICRESP_free(bs); 
+            return SSL_TLSEXT_ERR_NOACK;
+        }
+    }
+ 
+    OCSP_BASICRESP_free(bs); 
+
+    return SSL_TLSEXT_ERR_OK;
+}
+
+static BOOL stapling_renew_response(server_rec *s, modssl_ctx_t *mctx, SSL *ssl,
+                                    certinfo *cinf, OCSP_RESPONSE **prsp,
+                                    apr_pool_t *pool)
+{
+    conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
+    apr_pool_t *vpool;
+    OCSP_REQUEST *req = NULL;
+    OCSP_CERTID *id = NULL;
+    STACK_OF(X509_EXTENSION) *exts;
+    int i;
+    BOOL ok = FALSE;
+    BOOL rv = TRUE;
+    const char *ocspuri;
+    apr_uri_t uri;
+
+    *prsp = NULL;
+    /* Build up OCSP query from server certificate info */
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "stapling_renew_response: querying responder");
+
+    req = OCSP_REQUEST_new();
+    if (!req)
+        goto err;
+    id = OCSP_CERTID_dup(cinf->cid);
+    if (!id)
+        goto err;
+    if (!OCSP_request_add0_id(req, id))
+        goto err;
+    id = NULL;
+    /* Add any extensions to the request */
+    SSL_get_tlsext_status_exts(ssl, &exts);
+    for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
+        X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+        if (!OCSP_REQUEST_add_ext(req, ext, -1))
+            goto err;
+    }
+
+    if (mctx->stapling_force_url)
+        ocspuri = mctx->stapling_force_url;
+    else
+        ocspuri = cinf->uri;
+    
+    /* Create a temporary pool to constrain memory use */
+    apr_pool_create(&vpool, conn->pool);
+
+    ok = apr_uri_parse(vpool, ocspuri, &uri);
+    if (ok != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_renew_response: Error parsing uri %s",
+                      ocspuri);
+	rv = FALSE;
+	goto done;
+    } else if (strcmp(uri.scheme, "http")) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_renew_response: Unsupported uri %s", ocspuri);
+	rv = FALSE;
+	goto done;
+    }
+
+    *prsp = modssl_dispatch_ocsp_request(&uri, mctx->stapling_responder_timeout,
+                                         req, conn, vpool);
+ 
+    apr_pool_destroy(vpool);
+
+    if (!*prsp) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_renew_response: responder error");
+        if (mctx->stapling_fake_trylater) { 
+            *prsp = OCSP_response_create(OCSP_RESPONSE_STATUS_TRYLATER, NULL);
+        } 
+        else {
+            goto done;
+        }
+    } else {
+        int response_status = OCSP_response_status(*prsp);
+
+        if (response_status == OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                        "stapling_renew_response: query response received");
+            stapling_check_response(s, mctx, cinf, *prsp, &ok);
+            if (ok == FALSE) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                             "stapling_renew_response: error in retreived response!");
+            }
+        } else {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                         "stapling_renew_response: responder error %s",
+                         OCSP_response_status_str(response_status));
+        }
+    }
+    if (stapling_cache_response(s, mctx, *prsp, cinf, ok, pool) == FALSE) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "stapling_renew_response: error caching response!");
+    }
+
+done:
+    if (id)
+        OCSP_CERTID_free(id);
+    if (req)
+        OCSP_REQUEST_free(req);
+    return rv;
+err:
+    rv = FALSE;
+    goto done;
+}
+
+/*
+ * SSLStaplingMutex operations. Similar to SSL mutex except a mutex is
+ * mandatory if stapling is enabled.
+ */
+int ssl_stapling_mutex_init(server_rec *s, apr_pool_t *p)
+{
+    SSLModConfigRec *mc = myModConfig(s);
+    SSLSrvConfigRec *sc = mySrvConfig(s);
+    apr_status_t rv;
+
+    if (mc->stapling_mutex || sc->server->stapling_enabled != TRUE) {
+        return TRUE;
+    }
+    if (mc->stapling_mutex_mode == SSL_MUTEXMODE_NONE
+        || mc->stapling_mutex_mode == SSL_MUTEXMODE_UNSET) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                     "An SSLStaplingMutex is required for OCSP Stapling");
+        return FALSE;
+    }
+
+    if ((rv = apr_global_mutex_create(&mc->stapling_mutex,
+                                      mc->stapling_mutex_file,
+                                      mc->stapling_mutex_mech, s->process->pool))
+            != APR_SUCCESS) {
+        if (mc->stapling_mutex_file)
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                         "Cannot create SSLStaplingMutex with file `%s'",
+                         mc->stapling_mutex_file);
+        else
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                         "Cannot create SSLStaplingMutex");
+        return FALSE;
+    }
+
+#ifdef AP_NEED_SET_MUTEX_PERMS
+    rv = ap_unixd_set_global_mutex_perms(mc->stapling_mutex);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                     "Could not set permissions on ssl_mutex; check User "
+                     "and Group directives");
+        return FALSE;
+    }
+#endif
+    return TRUE;
+}
+
+int ssl_stapling_mutex_reinit(server_rec *s, apr_pool_t *p)
+{
+    SSLModConfigRec *mc = myModConfig(s);
+    apr_status_t rv;
+
+    if (mc->stapling_mutex == NULL) {
+        return TRUE;
+    }
+
+    if ((rv = apr_global_mutex_child_init(&mc->stapling_mutex,
+                                 mc->stapling_mutex_file, p)) != APR_SUCCESS) {
+        if (mc->stapling_mutex_file) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                         "Cannot reinit SSLMutex with file `%s'",
+                         mc->szMutexFile);
+        }
+        else {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
+                         "Cannot reinit SSLMutex");
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static int stapling_mutex_on(server_rec *s)
+{
+    SSLModConfigRec *mc = myModConfig(s);
+    apr_status_t rv;
+
+    if ((rv = apr_global_mutex_lock(mc->stapling_mutex)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
+                     "Failed to acquire OCSP stapling lock");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static int stapling_mutex_off(server_rec *s)
+{
+    SSLModConfigRec *mc = myModConfig(s);
+    apr_status_t rv;
+
+    if ((rv = apr_global_mutex_unlock(mc->stapling_mutex)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
+                     "Failed to release OCSP stapling lock");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/* Certificate Status callback. This is called when a client includes a
+ * certificate status request extension.
+ *
+ * Check for cached responses in session cache. If valid send back to
+ * client.  If absent or no longer valid query responder and update
+ * cache. */
+static int stapling_cb(SSL *ssl, void *arg)
+{
+    conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
+    server_rec *s       = conn->base_server;
+
+    SSLSrvConfigRec *sc = mySrvConfig(s);
+    SSLConnRec *sslconn = myConnConfig(conn);
+    modssl_ctx_t *mctx  = myCtxConfig(sslconn, sc);
+    certinfo *cinf = NULL;
+    OCSP_RESPONSE *rsp = NULL;
+    int rv;
+    BOOL ok;
+
+    if (sc->server->stapling_enabled != TRUE) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "stapling_cb: OCSP Stapling disabled");
+        return SSL_TLSEXT_ERR_NOACK;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "stapling_cb: OCSP Stapling callback called");
+
+    cinf = stapling_get_cert_info(s, mctx, ssl);
+    if (cinf == NULL) {
+        return SSL_TLSEXT_ERR_NOACK;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "stapling_cb: retrieved cached certificate data");
+
+    /* Check to see if we already have a response for this certificate */
+    stapling_mutex_on(s);
+
+    rv = stapling_get_cached_response(s, &rsp, &ok, cinf, conn->pool);
+    if (rv == FALSE) {
+        stapling_mutex_off(s);
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+
+    if (rsp) {
+        /* see if response is acceptable */
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "stapling_cb: retrieved cached response");
+        rv = stapling_check_response(s, mctx, cinf, rsp, NULL);
+        if (rv == SSL_TLSEXT_ERR_ALERT_FATAL) {
+            OCSP_RESPONSE_free(rsp);
+            stapling_mutex_off(s);
+            return SSL_TLSEXT_ERR_ALERT_FATAL;
+        } 
+        else if (rv == SSL_TLSEXT_ERR_NOACK) {
+            /* Error in response. If this error was not present when it was
+             * stored (i.e. response no longer valid) then it can be
+             * renewed straight away.
+             *
+             * If the error *was* present at the time it was stored then we
+             * don't renew the response straight away we just wait for the
+             * cached response to expire.
+             */
+            if (ok) {
+                OCSP_RESPONSE_free(rsp);
+                rsp = NULL;
+            }
+            else if (!mctx->stapling_return_errors) {
+                OCSP_RESPONSE_free(rsp);
+                stapling_mutex_off(s);
+                return SSL_TLSEXT_ERR_NOACK;
+            }
+        }
+    }
+
+    if (rsp == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "stapling_cb: renewing cached response");
+        rv = stapling_renew_response(s, mctx, ssl, cinf, &rsp, conn->pool);
+
+        if (rv == FALSE) {
+            stapling_mutex_off(s);
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                         "stapling_cb: fatal error");
+            return SSL_TLSEXT_ERR_ALERT_FATAL;
+        }
+    }
+    stapling_mutex_off(s);
+
+    if (rsp) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "stapling_cb: setting response");
+        if (!stapling_set_response(ssl, rsp))
+            return SSL_TLSEXT_ERR_ALERT_FATAL;
+        return SSL_TLSEXT_ERR_OK;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "stapling_cb: no response available");
+
+    return SSL_TLSEXT_ERR_NOACK;
+
+}
+
+void modssl_init_stapling(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, 
+                          modssl_ctx_t *mctx)
+{
+    SSL_CTX *ctx = mctx->ssl_ctx;
+    SSLModConfigRec *mc = myModConfig(s);
+
+    if (mc->stapling_cache == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                 "SSLStapling: no stapling cache available");
+        ssl_die();
+    }
+    /* Set some default values for parameters if they are not set */
+    if (mctx->stapling_resptime_skew == UNSET) {
+        mctx->stapling_resptime_skew = 60 * 5;
+    }
+    if (mctx->stapling_cache_timeout == UNSET) {
+        mctx->stapling_cache_timeout = 3600;
+    }
+    if (mctx->stapling_return_errors == UNSET) {
+        mctx->stapling_return_errors = TRUE;
+    }
+    if (mctx->stapling_fake_trylater == UNSET) {
+        mctx->stapling_fake_trylater = TRUE;
+    }
+    if (mctx->stapling_errcache_timeout == UNSET) {
+        mctx->stapling_errcache_timeout = 600;
+    }
+    if (mctx->stapling_responder_timeout == UNSET) {
+        mctx->stapling_responder_timeout = 10 * APR_USEC_PER_SEC;
+    }
+    SSL_CTX_set_tlsext_status_cb(ctx, stapling_cb);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "OCSP stapling initialized");
+}
+
+#endif



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Dr Stephen Henson <sh...@oss-institute.org>.
Guenter Knauf wrote:
> 
> After I defined HAVE_OCSP manually with CFLAGS I come to next error in
> line 110 of ssl_utl_stapling.c where STACK is not defined; I've searched
> both OpenSSL 0.9.8 and 1.0.0 branches, but couldnt find anything but
> only _STACK in crypto/stack/stack.h with the hint:
> /* Use STACK_OF(...) instead */
> so shouldnt line 110 be:
> Index: ssl_util_stapling.c
> ===================================================================
> --- ssl_util_stapling.c (revision 830045)
> +++ ssl_util_stapling.c (working copy)
> @@ -107,7 +107,7 @@
>  {
>      certinfo *cinf;
>      X509 *issuer = NULL;
> -    STACK *aia = NULL;
> +    STACK_OF(OPENSSL_STRING) *aia = NULL;
> 
>      if (x == NULL)
>          return 0;
> 

Erk, shows how long it was since I wrote that. OPENSSL_STRING is only defined in
 1.0.0. It should work with STACK in 0.9.8 though: that is defined in
crypto/stack/stack.h I'll work on a fix for both branches.

Steve.
-- 
Dr Stephen N. Henson. Senior Technical/Cryptography Advisor,
Open Source Software Institute: www.oss-institute.org
OpenSSL Core team: www.openssl.org

Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Ruediger Pluem <rp...@apache.org>.

On 10/28/2009 04:05 PM, Guenter Knauf wrote:
> Hi Joe,
> Joe Orton schrieb:
>> Hiya, I'm not sure I follow this.  HAVE_OCSP should be defined by the 
>> build system iff openssl/ocsp.h is present - the Netware scripts may 
>> need to be updated for this.  I've updated the #if's to check for 
>> HAVE_OCSP in r830554; does this work for you?
> yes, works noe for the case where HAVE_OCSP is not defined; that was
> what I also was thinking of.
> 
> but I still cant find anything in the OpenSSL sources where HAVE_OCSP
> should get defined? I've searched through 0.9.8 / 1.0.0 witgh my NetWare
> builds as well as through 1.0.0 of my Linux build, cant find ...
> In which file do you have this macro defined with your build?
> what am I missing?

Have a look at modules/ssl/config.m4:

AC_DEFUN([CHECK_OCSP], [
AC_CHECK_HEADERS(openssl/ocsp.h,·
  [AC_DEFINE([HAVE_OCSP], 1, [Define if OCSP is supported by OpenSSL])]
)
])


Regards

Rüdiger


Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Guenter Knauf <fu...@apache.org>.
Hi Joe,
Joe Orton schrieb:
> Hiya, I'm not sure I follow this.  HAVE_OCSP should be defined by the 
> build system iff openssl/ocsp.h is present - the Netware scripts may 
> need to be updated for this.  I've updated the #if's to check for 
> HAVE_OCSP in r830554; does this work for you?
yes, works noe for the case where HAVE_OCSP is not defined; that was
what I also was thinking of.

but I still cant find anything in the OpenSSL sources where HAVE_OCSP
should get defined? I've searched through 0.9.8 / 1.0.0 witgh my NetWare
builds as well as through 1.0.0 of my Linux build, cant find ...
In which file do you have this macro defined with your build?
what am I missing?

Gün.



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Guenter Knauf <fu...@apache.org>.
Steve,
Dr Stephen Henson schrieb:
> Guenter Knauf wrote:
>> Well, I guess its possible to do that - but isnt it possible to depend
>> on a OpenSSL version number here?
>>
> 
> How far do we have to go back here? OCSP support has been in OpenSSL since
> version 0.9.7 release 19 Feb 2003.
yep, found that just too - so a check for version 0.9.7 would do unless
this header is only conditionally installed (which I doubt) ...

Gün.



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Guenter Knauf <fu...@apache.org>.
Ruediger Pluem schrieb:
> We do not need it only for OCSP stapling but also for "normal" OCSP support.
> See ssl_util_ocsp.c
> So HAVE_OCSP IMHO still makes sense. Or we need to rely everywhere entirely
> on the OPENSSL_VERSION_NUMBER macro for deciding whether we have OCSP /  OCSP stapling support.
thanks! Missed that ...
have now changed this:
http://svn.apache.org/viewvc?rev=830765&view=rev
this should work (and works with my tests) since all files which use
HAVE_OCSP either include ssl_toolkit_compat.h directly, or via
ssl_private.h ...

provided this works correctly, is it enough to just delete the check
part in the m4 file?

thanks, Gün.



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Ruediger Pluem <rp...@apache.org>.

On 10/28/2009 04:40 PM, Guenter Knauf wrote:
> Dr Stephen Henson schrieb:
>> Guenter Knauf wrote:
>>> Well, I guess its possible to do that - but isnt it possible to depend
>>> on a OpenSSL version number here?
>>>
>> How far do we have to go back here? OCSP support has been in OpenSSL since
>> version 0.9.7 release 19 Feb 2003.
> we have:
> 
> +#if OPENSSL_VERSION_NUMBER >= 0x00908080 && defined(HAVE_OCSP) \
> +    && !defined(OPENSSL_NO_TLSEXT)
>  #define HAVE_OCSP_STAPLING
>  #endif
> 
> so we only support HAVE_OCSP_STAPLING with OpenSSL >= 0x00908080, and it
> seems that we dont need to include openssl/ocsp.h if we dont set
> HAVE_OCSP_STAPLING, so lets just move the above check up, and modify to:
> 
> #if (OPENSSL_VERSION_NUMBER >= 0x00908080) \
>      && !defined(OPENSSL_NO_TLSEXT)
> #define HAVE_OCSP_STAPLING
> #include <openssl/ocsp.h>
> #endif
> 
> and no further need for a HAVE_OCSP define on any platform ...
> 
> comments?

We do not need it only for OCSP stapling but also for "normal" OCSP support.
See ssl_util_ocsp.c
So HAVE_OCSP IMHO still makes sense. Or we need to rely everywhere entirely
on the OPENSSL_VERSION_NUMBER macro for deciding whether we have OCSP /  OCSP stapling support.

Regards

Rüdiger

Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Guenter Knauf <fu...@apache.org>.
Dr Stephen Henson schrieb:
> Guenter Knauf wrote:
>> Well, I guess its possible to do that - but isnt it possible to depend
>> on a OpenSSL version number here?
>>
> 
> How far do we have to go back here? OCSP support has been in OpenSSL since
> version 0.9.7 release 19 Feb 2003.
we have:

+#if OPENSSL_VERSION_NUMBER >= 0x00908080 && defined(HAVE_OCSP) \
+    && !defined(OPENSSL_NO_TLSEXT)
 #define HAVE_OCSP_STAPLING
 #endif

so we only support HAVE_OCSP_STAPLING with OpenSSL >= 0x00908080, and it
seems that we dont need to include openssl/ocsp.h if we dont set
HAVE_OCSP_STAPLING, so lets just move the above check up, and modify to:

#if (OPENSSL_VERSION_NUMBER >= 0x00908080) \
     && !defined(OPENSSL_NO_TLSEXT)
#define HAVE_OCSP_STAPLING
#include <openssl/ocsp.h>
#endif

and no further need for a HAVE_OCSP define on any platform ...

comments?

Gün.



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Dr Stephen Henson <sh...@oss-institute.org>.
Guenter Knauf wrote:
> 
> Well, I guess its possible to do that - but isnt it possible to depend
> on a OpenSSL version number here?
> 

How far do we have to go back here? OCSP support has been in OpenSSL since
version 0.9.7 release 19 Feb 2003.

Steve.
-- 
Dr Stephen N. Henson. Senior Technical/Cryptography Advisor,
Open Source Software Institute: www.oss-institute.org
OpenSSL Core team: www.openssl.org

Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Guenter Knauf <fu...@apache.org>.
Joe,
Joe Orton schrieb:
> Hiya, I'm not sure I follow this.  HAVE_OCSP should be defined by the 
> build system iff openssl/ocsp.h is present - the Netware scripts may 
> need to be updated for this.  I've updated the #if's to check for 
or maybe I misunderstood you here: do you mean I should modify the
NetWare makefile for mod_ssl to check for presence of openssl/ocsp.h,
and add HAVE_OCSP to CFLAGS depending on the result?

Well, I guess its possible to do that - but isnt it possible to depend
on a OpenSSL version number here?

Gün.



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Joe Orton <jo...@redhat.com>.
On Tue, Oct 27, 2009 at 03:14:55AM +0100, Guenter Knauf wrote:
> Hi Joe, Steve,
> I have some probs with getting this compiled;
> first its inclear for me from where HAVE_OCSP should get defined in  
> ssl_toolkit.compat.h - for me it seems its not defined in line 42, thus
> #include <openssl/ocsp.h>
> in line 44 is not included, and causes compile errors on NetWare since  
> later on in line 150 we have:
> #if (OPENSSL_VERSION_NUMBER >= 0x00908080)
> #ifndef OPENSSL_NO_TLSEXT
> #define HAVE_OCSP_STAPLING
> #endif
> #endif
> so HAVE_OCSP_STAPLING gets defined when !OPENSSL_NO_TLSEXT although  
> ocsp.h was not included.

Hiya, I'm not sure I follow this.  HAVE_OCSP should be defined by the 
build system iff openssl/ocsp.h is present - the Netware scripts may 
need to be updated for this.  I've updated the #if's to check for 
HAVE_OCSP in r830554; does this work for you?

(In case you didn't see my other message, thanks a lot for fixing the 
indenting!)

Regards, Joe

Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Guenter Knauf <fu...@apache.org>.
Hi Joe, Steve,
I have some probs with getting this compiled;
first its inclear for me from where HAVE_OCSP should get defined in 
ssl_toolkit.compat.h - for me it seems its not defined in line 42, thus
#include <openssl/ocsp.h>
in line 44 is not included, and causes compile errors on NetWare since 
later on in line 150 we have:
#if (OPENSSL_VERSION_NUMBER >= 0x00908080)
#ifndef OPENSSL_NO_TLSEXT
#define HAVE_OCSP_STAPLING
#endif
#endif
so HAVE_OCSP_STAPLING gets defined when !OPENSSL_NO_TLSEXT although 
ocsp.h was not included.

After I defined HAVE_OCSP manually with CFLAGS I come to next error in 
line 110 of ssl_utl_stapling.c where STACK is not defined; I've searched 
both OpenSSL 0.9.8 and 1.0.0 branches, but couldnt find anything but 
only _STACK in crypto/stack/stack.h with the hint:
/* Use STACK_OF(...) instead */
so shouldnt line 110 be:
Index: ssl_util_stapling.c
===================================================================
--- ssl_util_stapling.c (revision 830045)
+++ ssl_util_stapling.c (working copy)
@@ -107,7 +107,7 @@
  {
      certinfo *cinf;
      X509 *issuer = NULL;
-    STACK *aia = NULL;
+    STACK_OF(OPENSSL_STRING) *aia = NULL;

      if (x == NULL)
          return 0;

Gün.



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Dan Poirier <po...@pobox.com>.
Ruediger Pluem <rp...@apache.org> writes:

> On 10/26/2009 01:37 PM, Dan Poirier wrote:
>> jorton@apache.org writes:
>> 
>>> Author: jorton
>>> Date: Sun Oct 25 17:21:10 2009
>>> New Revision: 829619
>> ...
>>> +const char *ssl_cmd_SSLStaplingResponseTimeSkew(cmd_parms *cmd, void *dcfg,
>>> +                                                    const char *arg)
>>> +{
>>> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
>>> +    sc->server->stapling_resptime_skew = atoi(arg);
>>> +    if (sc->server->stapling_resptime_skew < 0) {
>>> +        return "SSLstapling_resptime_skew: invalid argument";
>>> +    }
>>> +    return NULL;
>>> +}
>> 
>> Shouldn't we check these arguments for validity before using them,
>> rather than after?
>
> Where do we use them so far?
> The are the functions to process the directives.

I meant that we assign a new value to the configuration before we know
whether that new value is valid.

It now occurs to me that while the code in isolation looks suspicious,
returning an error means the server won't start, so the point is moot.
Never mind.

Dan

Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Ruediger Pluem <rp...@apache.org>.

On 10/26/2009 01:37 PM, Dan Poirier wrote:
> jorton@apache.org writes:
> 
>> Author: jorton
>> Date: Sun Oct 25 17:21:10 2009
>> New Revision: 829619
> ...
>> +const char *ssl_cmd_SSLStaplingResponseTimeSkew(cmd_parms *cmd, void *dcfg,
>> +                                                    const char *arg)
>> +{
>> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
>> +    sc->server->stapling_resptime_skew = atoi(arg);
>> +    if (sc->server->stapling_resptime_skew < 0) {
>> +        return "SSLstapling_resptime_skew: invalid argument";
>> +    }
>> +    return NULL;
>> +}
>> +
>> +const char *ssl_cmd_SSLStaplingResponseMaxAge(cmd_parms *cmd, void *dcfg,
>> +                                                    const char *arg)
>> +{
>> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
>> +    sc->server->stapling_resp_maxage = atoi(arg);
>> +    if (sc->server->stapling_resp_maxage < 0) {
>> +        return "SSLstapling_resp_maxage: invalid argument";
>> +    }
>> +    return NULL;
>> +}
>> +
>> +const char *ssl_cmd_SSLStaplingStandardCacheTimeout(cmd_parms *cmd, void *dcfg,
>> +                                                    const char *arg)
>> +{
>> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
>> +    sc->server->stapling_cache_timeout = atoi(arg);
>> +    if (sc->server->stapling_cache_timeout < 0) {
>> +        return "SSLstapling_cache_timeout: invalid argument";
>> +    }
>> +    return NULL;
>> +}
>> +
>> +const char *ssl_cmd_SSLStaplingErrorCacheTimeout(cmd_parms *cmd, void *dcfg,
>> +                                                 const char *arg)
>> +{
>> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
>> +    sc->server->stapling_errcache_timeout = atoi(arg);
>> +    if (sc->server->stapling_errcache_timeout < 0) {
>> +        return "SSLstapling_errcache_timeout: invalid argument";
>> +    }
>> +    return NULL;
>> +}
> ...
>> +const char *ssl_cmd_SSLStaplingResponderTimeout(cmd_parms *cmd, void *dcfg,
>> +                                                const char *arg)
>> +{
>> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
>> +    sc->server->stapling_responder_timeout = atoi(arg);
>> +    sc->server->stapling_responder_timeout *= APR_USEC_PER_SEC;
>> +    if (sc->server->stapling_responder_timeout < 0) {
>> +        return "SSLstapling_responder_timeout: invalid argument";
>> +    }
>> +    return NULL;
>> +}
> 
> Shouldn't we check these arguments for validity before using them,
> rather than after?

Where do we use them so far?
The are the functions to process the directives.

Regards

Rüdiger



Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Dan Poirier <po...@pobox.com>.
jorton@apache.org writes:

> Author: jorton
> Date: Sun Oct 25 17:21:10 2009
> New Revision: 829619
...
> +const char *ssl_cmd_SSLStaplingResponseTimeSkew(cmd_parms *cmd, void *dcfg,
> +                                                    const char *arg)
> +{
> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
> +    sc->server->stapling_resptime_skew = atoi(arg);
> +    if (sc->server->stapling_resptime_skew < 0) {
> +        return "SSLstapling_resptime_skew: invalid argument";
> +    }
> +    return NULL;
> +}
> +
> +const char *ssl_cmd_SSLStaplingResponseMaxAge(cmd_parms *cmd, void *dcfg,
> +                                                    const char *arg)
> +{
> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
> +    sc->server->stapling_resp_maxage = atoi(arg);
> +    if (sc->server->stapling_resp_maxage < 0) {
> +        return "SSLstapling_resp_maxage: invalid argument";
> +    }
> +    return NULL;
> +}
> +
> +const char *ssl_cmd_SSLStaplingStandardCacheTimeout(cmd_parms *cmd, void *dcfg,
> +                                                    const char *arg)
> +{
> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
> +    sc->server->stapling_cache_timeout = atoi(arg);
> +    if (sc->server->stapling_cache_timeout < 0) {
> +        return "SSLstapling_cache_timeout: invalid argument";
> +    }
> +    return NULL;
> +}
> +
> +const char *ssl_cmd_SSLStaplingErrorCacheTimeout(cmd_parms *cmd, void *dcfg,
> +                                                 const char *arg)
> +{
> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
> +    sc->server->stapling_errcache_timeout = atoi(arg);
> +    if (sc->server->stapling_errcache_timeout < 0) {
> +        return "SSLstapling_errcache_timeout: invalid argument";
> +    }
> +    return NULL;
> +}
...
> +const char *ssl_cmd_SSLStaplingResponderTimeout(cmd_parms *cmd, void *dcfg,
> +                                                const char *arg)
> +{
> +    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
> +    sc->server->stapling_responder_timeout = atoi(arg);
> +    sc->server->stapling_responder_timeout *= APR_USEC_PER_SEC;
> +    if (sc->server->stapling_responder_timeout < 0) {
> +        return "SSLstapling_responder_timeout: invalid argument";
> +    }
> +    return NULL;
> +}

Shouldn't we check these arguments for validity before using them,
rather than after?

Dan

Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Joe Orton <jo...@redhat.com>.
On Mon, Oct 26, 2009 at 12:44:17AM +0100, Ruediger Pluem wrote:
> On 10/25/2009 06:21 PM, jorton@apache.org wrote:
> > Author: jorton
> > Date: Sun Oct 25 17:21:10 2009
> > New Revision: 829619
> > 
> > URL: http://svn.apache.org/viewvc?rev=829619&view=rev
> > Log:
> > Add support for OCSP "stapling":
...
> Will there be documentation patches for the new directives?

Yes, I will try to get that done, I might not have time until after 
ApacheCon though.

Thanks greatly for the review!

> > +    timeout += time(NULL);
> 
> Shouldn't we use apr_time_now here?

Yup, fixed in r830551.

> > +
> > +    i2d_OCSP_RESPONSE(rsp, &p);
> 
> Is this correct? p is already char *. So &p would be char **.
> If p gets changed by i2d_OCSP_RESPONSE our flag set above would get lost ???

This is correct.  The preceding lines:

    p = resp_der;

    if (ok == TRUE) {
        *p++ = 1;
        timeout = mctx->stapling_cache_timeout;
    } 
    else {
        *p++ = 0;
        timeout = mctx->stapling_errcache_timeout;
    }


set the flag value in the first byte of the data block.  The i2d_* 
macros all take a char ** pointer, and move the pointer to the next byte 
after the serialized data.  (see e.g. the man page for i2d_X509)

> > +    p++;
> > +    resp_derlen--;
> > +    rsp = d2i_OCSP_RESPONSE(NULL, &p, resp_derlen);
> 
> Why &p and not p?

As above, the d2i_ macros also take a char ** pointer and move it to the 
first byte after the encoded OCSP_RESPONSE.

...
> I guess we are missing some indention here.

Sorry about that - Guenter has fixed it all, thanks Guenter!

> > +done:
> > +    if (id)
> > +        OCSP_CERTID_free(id);
> > +    if (req)
> > +        OCSP_REQUEST_free(req);
> > +    return rv;
> > +err:
> > +    rv = FALSE;
> > +    goto done;
> 
> Looks a little bit like spaghetti code :-).

It's a bit annoying; it could be done using pool cleanups but that adds 
significant complexity, or by in-lining the _free calls everywhere, 
which is a bit error-pront.  Not really sure either alternative is 
better.  C sucks ;)

> > + * Check for cached responses in session cache. If valid send back to
> > + * client.  If absent or no longer valid query responder and update
> > + * cache. */
> > +static int stapling_cb(SSL *ssl, void *arg)
> > +{
> > +    conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
> > +    server_rec *s       = conn->base_server;
> 
> Shouldn't we use mySrvFromConn(conn) here instead of conn->base_server?

Yup, fixed in r830546.

Thanks again!

Regards, Joe

Re: svn commit: r829619 - in /httpd/httpd/trunk: ./ modules/ssl/

Posted by Ruediger Pluem <rp...@apache.org>.

On 10/25/2009 06:21 PM, jorton@apache.org wrote:
> Author: jorton
> Date: Sun Oct 25 17:21:10 2009
> New Revision: 829619
> 
> URL: http://svn.apache.org/viewvc?rev=829619&view=rev
> Log:
> Add support for OCSP "stapling":
> 
> * modules/ssl/ssl_util_stapling.c: New file.
> 
> * modules/ssl/config.m4, modules/ssl/mod_ssl.dsp: Build it.
> 
> * modules/ssl/ssl_toolkit_compat.h: Define HAVE_OCSP_STAPLING if
>   OpenSSL is of suitable version (>= 0.9.8g) and capability (TLS
>   extension support enabled).
> 
> * modules/ssl/mod_ssl.c: Add config directives.
> 
> * modules/ssl/ssl_private.h: Add prototypes for new functions.
>   (SSLModConfigRec): Add fields for stapling socache instance and
>   associated mutex.
>   (modssl_ctx_t): Add config fields for stapling.
> 
> * modules/ssl/ssl_engine_init.c (ssl_init_Module, ssl_init_Child):
>   Call the stapling initialization functions.
> 
> * modules/ssl/ssl_engine_config.c: Add config hooks.
> 
> * modules/ssl/ssl_scache.c: Create, initialize and destroy the socache
>   instance for OCSP responses.
> 
> Submitted by: Dr Stephen Henson <shenson oss-institute.org>

Will there be documentation patches for the new directives?

> 
> Added:
>     httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c
> Modified:
>     httpd/httpd/trunk/CHANGES
>     httpd/httpd/trunk/modules/ssl/config.m4
>     httpd/httpd/trunk/modules/ssl/mod_ssl.c
>     httpd/httpd/trunk/modules/ssl/mod_ssl.dsp
>     httpd/httpd/trunk/modules/ssl/ssl_engine_config.c
>     httpd/httpd/trunk/modules/ssl/ssl_engine_init.c
>     httpd/httpd/trunk/modules/ssl/ssl_private.h
>     httpd/httpd/trunk/modules/ssl/ssl_scache.c
>     httpd/httpd/trunk/modules/ssl/ssl_toolkit_compat.h
> 

> Added: httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c?rev=829619&view=auto
> ==============================================================================
> --- httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c (added)
> +++ httpd/httpd/trunk/modules/ssl/ssl_util_stapling.c Sun Oct 25 17:21:10 2009

> +/*
> + * OCSP response caching code. The response is preceded by a flag value
> + * which indicates whether the response was invalid when it was stored.
> + * the purpose of this flag is to avoid repeated queries to a server
> + * which has given an invalid response while allowing a response which
> + * has subsequently become invalid to be retried immediately.
> + *
> + * The key for the cache is the hash of the certificate the response
> + * is for.
> + */
> +static BOOL stapling_cache_response(server_rec *s, modssl_ctx_t *mctx,
> +                                    OCSP_RESPONSE *rsp, certinfo *cinf,
> +                                    BOOL ok, apr_pool_t *pool)
> +{
> +    SSLModConfigRec *mc = myModConfig(s);
> +    unsigned char resp_der[MAX_STAPLING_DER];
> +    unsigned char *p;
> +    int resp_derlen;
> +    BOOL rv;
> +    time_t timeout;
> +
> +    resp_derlen = i2d_OCSP_RESPONSE(rsp, NULL) + 1;
> +
> +    if (resp_derlen <= 0) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "OCSP stapling response encode error??");
> +        return FALSE;
> +    }
> +
> +    if (resp_derlen > sizeof resp_der) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "OCSP stapling response too big (%u bytes)", resp_derlen);
> +        return FALSE;
> +    }
> +
> +
> +    p = resp_der;
> +
> +    if (ok == TRUE) {
> +        *p++ = 1;
> +        timeout = mctx->stapling_cache_timeout;
> +    } else {
> +        *p++ = 0;
> +        timeout = mctx->stapling_errcache_timeout;
> +    }
> +
> +    timeout += time(NULL);

Shouldn't we use apr_time_now here?

> +
> +    i2d_OCSP_RESPONSE(rsp, &p);

Is this correct? p is already char *. So &p would be char **.
If p gets changed by i2d_OCSP_RESPONSE our flag set above would get lost ???

> +
> +    rv = mc->stapling_cache->store(mc->stapling_cache_context, s,
> +                                   cinf->idx, sizeof(cinf->idx),
> +                                   timeout, resp_der, resp_derlen, pool);
> +    if (rv != APR_SUCCESS) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "stapling_cache_response: OCSP response session store error!");
> +        return FALSE;
> +    }
> +    
> +    return TRUE;
> +}
> +
> +static BOOL stapling_get_cached_response(server_rec *s, OCSP_RESPONSE **prsp,
> +                                         BOOL *pok, certinfo *cinf,
> +                                         apr_pool_t *pool)
> +{
> +    SSLModConfigRec *mc = myModConfig(s);
> +    apr_status_t rv;
> +    OCSP_RESPONSE *rsp;
> +    unsigned char resp_der[MAX_STAPLING_DER];
> +    const unsigned char *p;
> +    unsigned int resp_derlen = MAX_STAPLING_DER;
> +
> +    rv = mc->stapling_cache->retrieve(mc->stapling_cache_context, s,
> +                                      cinf->idx, sizeof(cinf->idx),
> +                                      resp_der, &resp_derlen, pool);
> +    if (rv != APR_SUCCESS) {
> +        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                     "stapling_get_cached_response: cache miss");
> +        return TRUE;
> +    }
> +    if (resp_derlen <= 1) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "stapling_get_cached_response: response length invalid??");
> +        return TRUE;
> +    }
> +    p = resp_der;
> +    if (pok) {
> +        if (*p)
> +            *pok = TRUE;
> +        else
> +            *pok = FALSE;
> +    }
> +    p++;
> +    resp_derlen--;
> +    rsp = d2i_OCSP_RESPONSE(NULL, &p, resp_derlen);

Why &p and not p?

> +    if (!rsp) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "stapling_get_cached_response: response parse error??");
> +        return TRUE;
> +    }
> +    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                 "stapling_get_cached_response: cache hit");
> +
> +    *prsp = rsp;
> +    
> +    return TRUE;
> +}
> +

> +static BOOL stapling_renew_response(server_rec *s, modssl_ctx_t *mctx, SSL *ssl,
> +                                    certinfo *cinf, OCSP_RESPONSE **prsp,
> +                                    apr_pool_t *pool)
> +{
> +    conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
> +    apr_pool_t *vpool;
> +    OCSP_REQUEST *req = NULL;
> +    OCSP_CERTID *id = NULL;
> +    STACK_OF(X509_EXTENSION) *exts;
> +    int i;
> +    BOOL ok = FALSE;
> +    BOOL rv = TRUE;
> +    const char *ocspuri;
> +    apr_uri_t uri;
> +
> +    *prsp = NULL;
> +    /* Build up OCSP query from server certificate info */
> +    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                 "stapling_renew_response: querying responder");
> +
> +    req = OCSP_REQUEST_new();
> +    if (!req)
> +        goto err;
> +    id = OCSP_CERTID_dup(cinf->cid);
> +    if (!id)
> +        goto err;
> +    if (!OCSP_request_add0_id(req, id))
> +        goto err;
> +    id = NULL;
> +    /* Add any extensions to the request */
> +    SSL_get_tlsext_status_exts(ssl, &exts);
> +    for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
> +        X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
> +        if (!OCSP_REQUEST_add_ext(req, ext, -1))
> +            goto err;
> +    }
> +
> +    if (mctx->stapling_force_url)
> +        ocspuri = mctx->stapling_force_url;
> +    else
> +        ocspuri = cinf->uri;
> +    
> +    /* Create a temporary pool to constrain memory use */
> +    apr_pool_create(&vpool, conn->pool);
> +
> +    ok = apr_uri_parse(vpool, ocspuri, &uri);
> +    if (ok != APR_SUCCESS) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "stapling_renew_response: Error parsing uri %s",
> +                      ocspuri);
> +	rv = FALSE;
> +	goto done;

I guess we are missing some indention here.

> +    } else if (strcmp(uri.scheme, "http")) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "stapling_renew_response: Unsupported uri %s", ocspuri);
> +	rv = FALSE;
> +	goto done;

I guess we are missing some indention here.

> +    }
> +
> +    *prsp = modssl_dispatch_ocsp_request(&uri, mctx->stapling_responder_timeout,
> +                                         req, conn, vpool);
> + 
> +    apr_pool_destroy(vpool);
> +
> +    if (!*prsp) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "stapling_renew_response: responder error");
> +        if (mctx->stapling_fake_trylater) { 
> +            *prsp = OCSP_response_create(OCSP_RESPONSE_STATUS_TRYLATER, NULL);
> +        } 
> +        else {
> +            goto done;
> +        }
> +    } else {
> +        int response_status = OCSP_response_status(*prsp);
> +
> +        if (response_status == OCSP_RESPONSE_STATUS_SUCCESSFUL) {
> +            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                        "stapling_renew_response: query response received");
> +            stapling_check_response(s, mctx, cinf, *prsp, &ok);
> +            if (ok == FALSE) {
> +                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                             "stapling_renew_response: error in retreived response!");
> +            }
> +        } else {
> +            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                         "stapling_renew_response: responder error %s",
> +                         OCSP_response_status_str(response_status));
> +        }
> +    }
> +    if (stapling_cache_response(s, mctx, *prsp, cinf, ok, pool) == FALSE) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                     "stapling_renew_response: error caching response!");
> +    }
> +
> +done:
> +    if (id)
> +        OCSP_CERTID_free(id);
> +    if (req)
> +        OCSP_REQUEST_free(req);
> +    return rv;
> +err:
> +    rv = FALSE;
> +    goto done;

Looks a little bit like spaghetti code :-).

> +}
> +

> +/* Certificate Status callback. This is called when a client includes a
> + * certificate status request extension.
> + *
> + * Check for cached responses in session cache. If valid send back to
> + * client.  If absent or no longer valid query responder and update
> + * cache. */
> +static int stapling_cb(SSL *ssl, void *arg)
> +{
> +    conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
> +    server_rec *s       = conn->base_server;

Shouldn't we use mySrvFromConn(conn) here instead of conn->base_server?

> +
> +    SSLSrvConfigRec *sc = mySrvConfig(s);
> +    SSLConnRec *sslconn = myConnConfig(conn);
> +    modssl_ctx_t *mctx  = myCtxConfig(sslconn, sc);
> +    certinfo *cinf = NULL;
> +    OCSP_RESPONSE *rsp = NULL;
> +    int rv;
> +    BOOL ok;
> +
> +    if (sc->server->stapling_enabled != TRUE) {
> +        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                     "stapling_cb: OCSP Stapling disabled");
> +        return SSL_TLSEXT_ERR_NOACK;
> +    }
> +
> +    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                 "stapling_cb: OCSP Stapling callback called");
> +
> +    cinf = stapling_get_cert_info(s, mctx, ssl);
> +    if (cinf == NULL) {
> +        return SSL_TLSEXT_ERR_NOACK;
> +    }
> +
> +    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                 "stapling_cb: retrieved cached certificate data");
> +
> +    /* Check to see if we already have a response for this certificate */
> +    stapling_mutex_on(s);
> +
> +    rv = stapling_get_cached_response(s, &rsp, &ok, cinf, conn->pool);
> +    if (rv == FALSE) {
> +        stapling_mutex_off(s);
> +        return SSL_TLSEXT_ERR_ALERT_FATAL;
> +    }
> +
> +    if (rsp) {
> +        /* see if response is acceptable */
> +        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                     "stapling_cb: retrieved cached response");
> +        rv = stapling_check_response(s, mctx, cinf, rsp, NULL);
> +        if (rv == SSL_TLSEXT_ERR_ALERT_FATAL) {
> +            OCSP_RESPONSE_free(rsp);
> +            stapling_mutex_off(s);
> +            return SSL_TLSEXT_ERR_ALERT_FATAL;
> +        } 
> +        else if (rv == SSL_TLSEXT_ERR_NOACK) {
> +            /* Error in response. If this error was not present when it was
> +             * stored (i.e. response no longer valid) then it can be
> +             * renewed straight away.
> +             *
> +             * If the error *was* present at the time it was stored then we
> +             * don't renew the response straight away we just wait for the
> +             * cached response to expire.
> +             */
> +            if (ok) {
> +                OCSP_RESPONSE_free(rsp);
> +                rsp = NULL;
> +            }
> +            else if (!mctx->stapling_return_errors) {
> +                OCSP_RESPONSE_free(rsp);
> +                stapling_mutex_off(s);
> +                return SSL_TLSEXT_ERR_NOACK;
> +            }
> +        }
> +    }
> +
> +    if (rsp == NULL) {
> +        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                     "stapling_cb: renewing cached response");
> +        rv = stapling_renew_response(s, mctx, ssl, cinf, &rsp, conn->pool);
> +
> +        if (rv == FALSE) {
> +            stapling_mutex_off(s);
> +            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
> +                         "stapling_cb: fatal error");
> +            return SSL_TLSEXT_ERR_ALERT_FATAL;
> +        }
> +    }
> +    stapling_mutex_off(s);
> +
> +    if (rsp) {
> +        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                     "stapling_cb: setting response");
> +        if (!stapling_set_response(ssl, rsp))
> +            return SSL_TLSEXT_ERR_ALERT_FATAL;
> +        return SSL_TLSEXT_ERR_OK;
> +    }
> +    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                 "stapling_cb: no response available");
> +
> +    return SSL_TLSEXT_ERR_NOACK;
> +
> +}
> +


Regards

Rüdiger