SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); unsigned char dest[SSL_SESSION_MAX_DER]; unsigned int destlen = SSL_SESSION_MAX_DER; const unsigned char *ptr; apr_status_t rv; if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(s); } rv = mc->sesscache->retrieve(mc->sesscache_context, s, id, idlen, dest, &destlen, p); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(s); } if (rv != APR_SUCCESS) { return NULL; } ptr = dest; return d2i_SSL_SESSION(NULL, &ptr, destlen); }
void ssl_scache_shmht_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg) { SSLModConfigRec *mc = myModConfig(); void *vpKey; void *vpData; int nKey; int nData; int nElem; int nSize; int nAverage; nElem = 0; nSize = 0; ssl_mutex_on(s); if (table_first(mc->tSessionCacheDataTable, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { do { if (vpKey == NULL || vpData == NULL) continue; nElem += 1; nSize += nData; } while (table_next(mc->tSessionCacheDataTable, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE); } ssl_mutex_off(s); if (nSize > 0 && nElem > 0) nAverage = nSize / nElem; else nAverage = 0; func(ap_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg); func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg); func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg); return; }
void ssl_scache_init(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); /* * Warn the user that he should use the session cache. * But we can operate without it, of course. */ if (mc->nSessionCacheMode == SSL_SCMODE_UNSET) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Init: Session Cache is not configured " "[hint: SSLSessionCache]"); mc->nSessionCacheMode = SSL_SCMODE_NONE; return; } if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_init(s, p); else if ((mc->nSessionCacheMode == SSL_SCMODE_SHMHT) || (mc->nSessionCacheMode == SSL_SCMODE_SHMCB)) { void *data; const char *userdata_key = "ssl_scache_init"; apr_pool_userdata_get(&data, userdata_key, s->process->pool); if (!data) { apr_pool_userdata_set((const void *)1, userdata_key, apr_pool_cleanup_null, s->process->pool); return; } if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) ssl_scache_shmht_init(s, p); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_init(s, p); } }
int ssl_mutex_init(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); apr_status_t rv; if (mc->nMutexMode == SSL_MUTEXMODE_NONE) return TRUE; if ((rv = apr_global_mutex_create(&mc->pMutex, mc->szMutexFile, mc->nMutexMech, p)) != APR_SUCCESS) { if (mc->szMutexFile) ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Cannot create SSLMutex with file `%s'", mc->szMutexFile); else ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Cannot create SSLMutex"); return FALSE; } #ifdef MOD_SSL_SET_MUTEX_PERMS rv = unixd_set_global_mutex_perms(mc->pMutex); 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; }
static void *ssl_scache_shmht_realloc(void *opt_param, void *ptr, size_t size) { SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); apr_rmm_off_t off = apr_rmm_realloc(mc->pSessionCacheDataRMM, ptr, size); return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off); }
BOOL ssl_scache_shmht_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) { SSLModConfigRec *mc = myModConfig(); void *vp; UCHAR ucaData[SSL_SESSION_MAX_DER]; int nData; UCHAR *ucp; /* streamline session data */ if ((nData = i2d_SSL_SESSION(sess, NULL)) > sizeof(ucaData)) return FALSE; ucp = ucaData; i2d_SSL_SESSION(sess, &ucp); ssl_mutex_on(s); if (table_insert_kd(mc->tSessionCacheDataTable, id, idlen, NULL, sizeof(time_t)+nData, NULL, &vp, 1) != TABLE_ERROR_NONE) { ssl_mutex_off(s); return FALSE; } memcpy(vp, &expiry, sizeof(time_t)); memcpy((char *)vp+sizeof(time_t), ucaData, nData); ssl_mutex_off(s); /* allow the regular expiring to occur */ ssl_scache_shmht_expire(s); return TRUE; }
SSL_SESSION *ssl_scache_dc_retrieve(server_rec *s, UCHAR *id, int idlen) { unsigned char der[SSL_SESSION_MAX_DER]; unsigned int der_len; SSL_SESSION *pSession; MODSSL_D2I_SSL_SESSION_CONST unsigned char *pder = der; SSLModConfigRec *mc = myModConfig(s); DC_CTX *ctx = mc->tSessionCacheDataTable; /* Retrieve any corresponding session from the distributed cache context */ if (!DC_CTX_get_session(ctx, id, idlen, der, SSL_SESSION_MAX_DER, &der_len)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' MISS"); return NULL; } if (der_len > SSL_SESSION_MAX_DER) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'get_session' OVERFLOW"); return NULL; } pSession = d2i_SSL_SESSION(NULL, &pder, der_len); if (!pSession) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'get_session' CORRUPT"); return NULL; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' HIT"); return pSession; }
/* _________________________________________________________________ ** ** SSL Extension to mod_status ** _________________________________________________________________ */ static int ssl_ext_status_hook(request_rec *r, int flags) { SSLModConfigRec *mc = myModConfig(r->server); if (mc == NULL || flags & AP_STATUS_SHORT || mc->sesscache == NULL) return OK; ap_rputs("<hr>\n", r); ap_rputs("<table cellspacing=0 cellpadding=0>\n", r); ap_rputs("<tr><td bgcolor=\"#000000\">\n", r); ap_rputs("<b><font color=\"#ffffff\" face=\"Arial,Helvetica\">SSL/TLS Session Cache Status:</font></b>\r", r); ap_rputs("</td></tr>\n", r); ap_rputs("<tr><td bgcolor=\"#ffffff\">\n", r); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(r->server); } mc->sesscache->status(mc->sesscache_context, r, flags); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(r->server); } ap_rputs("</td></tr>\n", r); ap_rputs("</table>\n", r); return OK; }
SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); SSL_SESSION *pSession = NULL; SHMCBHeader *header = mc->tSessionCacheDataTable; SHMCBSubcache *subcache = SHMCB_MASK(header, id); ssl_mutex_on(s); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "ssl_scache_shmcb_retrieve (0x%02x -> subcache %d)", SHMCB_MASK_DBG(header, id)); if (idlen < 4) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " "(%u bytes)", idlen); goto done; } /* Get the session corresponding to the session_id or NULL if it doesn't * exist (or is flagged as "removed"). */ pSession = shmcb_subcache_retrieve(s, header, subcache, id, idlen); if (pSession) header->stat_retrieves_hit++; else header->stat_retrieves_miss++; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "leaving ssl_scache_shmcb_retrieve successfully"); done: ssl_mutex_off(s); return pSession; }
void ssl_init_Engine(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); ENGINE *e; if (mc->szCryptoDevice) { if (!(e = ENGINE_by_id(mc->szCryptoDevice))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Init: Failed to load Crypto Device API `%s'", mc->szCryptoDevice); ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); ssl_die(); } if (strEQ(mc->szCryptoDevice, "chil")) { ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0); } if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Init: Failed to enable Crypto Device API `%s'", mc->szCryptoDevice); ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); ssl_die(); } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Init: loaded Crypto Device API `%s'", mc->szCryptoDevice); ENGINE_free(e); } }
BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, apr_time_t expiry, SSL_SESSION *sess, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); unsigned char encoded[SSL_SESSION_MAX_DER], *ptr; unsigned int len; apr_status_t rv; /* Serialise the session. */ len = i2d_SSL_SESSION(sess, NULL); if (len > sizeof encoded) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01875) "session is too big (%u bytes)", len); return FALSE; } ptr = encoded; len = i2d_SSL_SESSION(sess, &ptr); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(s); } rv = mc->sesscache->store(mc->sesscache_context, s, id, idlen, expiry, encoded, len, p); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(s); } return rv == APR_SUCCESS ? TRUE : FALSE; }
static void ssl_tmp_keys_free(server_rec *s) { SSLModConfigRec *mc = myModConfig(s); MODSSL_TMP_KEYS_FREE(mc, RSA); MODSSL_TMP_KEYS_FREE(mc, DH); }
void ssl_scache_dc_kill(server_rec *s) { SSLModConfigRec *mc = myModConfig(s); if (mc->tSessionCacheDataTable) DC_CTX_free(mc->tSessionCacheDataTable); mc->tSessionCacheDataTable = NULL; }
const char *set_user(cmd_parms *cmd, void *dummy, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->user = arg; return NULL; }
static void ssl_scache_shmht_free(void *opt_param, void *ptr) { SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); apr_rmm_off_t off = apr_rmm_offset_get(mc->pSessionCacheDataRMM, ptr); apr_rmm_free(mc->pSessionCacheDataRMM, off); return; }
void ssl_scache_shmht_init(server_rec *s, pool *p) { SSLModConfigRec *mc = myModConfig(); AP_MM *mm; table_t *ta; int ta_errno; int avail; int n; /* * Create shared memory segment */ if (mc->szSessionCacheDataFile == NULL) { ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required"); ssl_die(); } if ((mm = ap_mm_create(mc->nSessionCacheDataSize, mc->szSessionCacheDataFile)) == NULL) { ssl_log(s, SSL_LOG_ERROR, "Cannot allocate shared memory: %s", ap_mm_error()); ssl_die(); } mc->pSessionCacheDataMM = mm; /* * Make sure the childs have access to the underlaying files */ ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1); /* * Create hash table in shared memory segment */ avail = ap_mm_available(mm); n = (avail/2) / 1024; n = n < 10 ? 10 : n; if ((ta = table_alloc(n, &ta_errno, ssl_scache_shmht_malloc, ssl_scache_shmht_calloc, ssl_scache_shmht_realloc, ssl_scache_shmht_free )) == NULL) { ssl_log(s, SSL_LOG_ERROR, "Cannot allocate hash table in shared memory: %s", table_strerror(ta_errno)); ssl_die(); } table_attr(ta, TABLE_FLAG_AUTO_ADJUST|TABLE_FLAG_ADJUST_DOWN); table_set_data_alignment(ta, sizeof(char *)); table_clear(ta); mc->tSessionCacheDataTable = ta; /* * Log the done work */ ssl_log(s, SSL_LOG_INFO, "Init: Created hash-table (%d buckets) " "in shared memory (%d bytes) for SSL session cache", n, avail); return; }
void ssl_scache_dc_status(request_rec *r, int flags, apr_pool_t *pool) { SSLModConfigRec *mc = myModConfig(r->server); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "distributed scache 'ssl_scache_dc_status'"); ap_rprintf(r, "cache type: <b>DC (Distributed Cache)</b>, " " target: <b>%s</b><br>", mc->szSessionCacheDataFile); }
void ssl_scache_shmht_expire(server_rec *s) { SSLModConfigRec *mc = myModConfig(); SSLSrvConfigRec *sc = mySrvConfig(s); static time_t tLast = 0; table_linear_t iterator; time_t tExpiresAt; void *vpKey; void *vpKeyThis; void *vpData; int nKey; int nKeyThis; int nData; int nElements = 0; int nDeleted = 0; int bDelete; int rc; time_t tNow; /* * make sure the expiration for still not-accessed session * cache entries is done only from time to time */ tNow = time(NULL); if (tNow < tLast+sc->nSessionCacheTimeout) return; tLast = tNow; ssl_mutex_on(s); if (table_first_r(mc->tSessionCacheDataTable, &iterator, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { do { bDelete = FALSE; nElements++; if (nData < sizeof(time_t) || vpData == NULL) bDelete = TRUE; else { memcpy(&tExpiresAt, vpData, sizeof(time_t)); if (tExpiresAt <= tNow) bDelete = TRUE; } vpKeyThis = vpKey; nKeyThis = nKey; rc = table_next_r(mc->tSessionCacheDataTable, &iterator, &vpKey, &nKey, &vpData, &nData); if (bDelete) { table_delete(mc->tSessionCacheDataTable, vpKeyThis, nKeyThis, NULL, NULL); nDeleted++; } } while (rc == TABLE_ERROR_NONE); } ssl_mutex_off(s); ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache (SHMHT) Expiry: " "old: %d, new: %d, removed: %d", nElements, nElements-nDeleted, nDeleted); return; }
apr_status_t ssl_scache_init(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); apr_status_t rv; struct ap_socache_hints hints; /* The very first invocation of this function will be the * post_config invocation during server startup; do nothing for * this first (and only the first) time through, since the pool * will be immediately cleared anyway. For every subsequent * invocation, initialize the configured cache. */ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) return APR_SUCCESS; #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) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01872) "Could not initialize stapling cache. Exiting."); return ssl_die(s); } } #endif /* * Warn the user that he should use the session cache. * But we can operate without it, of course. */ if (mc->sesscache == NULL) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01873) "Init: Session Cache is not configured " "[hint: SSLSessionCache]"); return APR_SUCCESS; } memset(&hints, 0, sizeof hints); hints.avg_obj_size = 150; hints.avg_id_len = 30; hints.expiry_interval = 30; rv = mc->sesscache->init(mc->sesscache_context, "mod_ssl-session", &hints, s, p); if (rv) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01874) "Could not initialize session cache. Exiting."); return ssl_die(s); } return APR_SUCCESS; }
void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(); /* remove value under key in table */ ssl_mutex_on(s); table_delete(mc->tSessionCacheDataTable, id, idlen, NULL, NULL); ssl_mutex_off(s); return; }
void ssl_scache_shmht_kill(server_rec *s) { SSLModConfigRec *mc = myModConfig(); if (mc->pSessionCacheDataMM != NULL) { ap_mm_destroy(mc->pSessionCacheDataMM); mc->pSessionCacheDataMM = NULL; } return; }
const char *nss_cmd_NSSDBPrefix(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->pDBPrefix = arg; return NULL; }
const char *nss_cmd_NSSCertificateDatabase(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->pCertificateDatabase = arg; return NULL; }
void ssl_scache_dc_remove(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); DC_CTX *ctx = mc->tSessionCacheDataTable; /* Remove any corresponding session from the distributed cache context */ if (!DC_CTX_remove_session(ctx, id, idlen)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'remove_session' MISS"); } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'remove_session' HIT"); } }
void ssl_scache_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg) { SSLModConfigRec *mc = myModConfig(s); if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_status(s, p, func, arg); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) ssl_scache_shmht_status(s, p, func, arg); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_status(s, p, func, arg); return; }
void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_remove(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) ssl_scache_shmht_remove(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_remove(s, id, idlen); return; }
void ssl_scache_kill(server_rec *s) { SSLModConfigRec *mc = myModConfig(s); if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_kill(s); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) ssl_scache_shmht_kill(s); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_kill(s); return; }
const char *nss_cmd_NSSSessionCacheTimeout(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); /* Deprecated. Store a value, if any, just to complain about it later. */ mc->session_cache_timeout = atoi(arg); return NULL; }
SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); SSL_SESSION *sess = NULL; if (mc->nSessionCacheMode == SSL_SCMODE_DBM) sess = ssl_scache_dbm_retrieve(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) sess = ssl_scache_shmht_retrieve(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) sess = ssl_scache_shmcb_retrieve(s, id, idlen); return sess; }
BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) { SSLModConfigRec *mc = myModConfig(s); BOOL rv = FALSE; if (mc->nSessionCacheMode == SSL_SCMODE_DBM) rv = ssl_scache_dbm_store(s, id, idlen, expiry, sess); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) rv = ssl_scache_shmht_store(s, id, idlen, expiry, sess); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) rv = ssl_scache_shmcb_store(s, id, idlen, expiry, sess); return rv; }