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); } }
static void ssl_init_server_check(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modssl_ctx_t *mctx) { /* * check for important parameters and the * possibility that the user forgot to set them. */ if (!mctx->pks->cert_files[0]) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "No SSL Certificate set [hint: SSLCertificateFile]"); ssl_die(); } /* * Check for problematic re-initializations */ if (mctx->pks->certs[SSL_AIDX_RSA] || mctx->pks->certs[SSL_AIDX_DSA]) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Illegal attempt to re-initialise SSL for server " "(theoretically shouldn't happen!)"); ssl_die(); } }
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; }
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; }
/* * Open the SSL logfile */ void ssl_log_open(server_rec *s_main, server_rec *s, pool *p) { char *szLogFile; SSLSrvConfigRec *sc_main = mySrvConfig(s_main); SSLSrvConfigRec *sc = mySrvConfig(s); piped_log *pl; char *cp; /* * Short-circuit for inherited logfiles in order to save * filedescriptors in mass-vhost situation. Be careful, this works * fine because the close happens implicitly by the pool facility. */ if ( s != s_main && sc_main->fileLogFile != NULL && ( (sc->szLogFile == NULL) || ( sc->szLogFile != NULL && sc_main->szLogFile != NULL && strEQ(sc->szLogFile, sc_main->szLogFile)))) { sc->fileLogFile = sc_main->fileLogFile; } else if (sc->szLogFile != NULL) { if (strEQ(sc->szLogFile, "/dev/null")) return; else if (sc->szLogFile[0] == '|') { cp = sc->szLogFile+1; while (*cp == ' ' || *cp == '\t') cp++; szLogFile = ssl_util_server_root_relative(p, "log", cp); if ((pl = ap_open_piped_log(p, szLogFile)) == NULL) { ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, "Cannot open reliable pipe to SSL logfile filter %s", szLogFile); ssl_die(); } sc->fileLogFile = ap_pfdopen(p, ap_piped_log_write_fd(pl), "a"); setbuf(sc->fileLogFile, NULL); } else { szLogFile = ssl_util_server_root_relative(p, "log", sc->szLogFile); if ((sc->fileLogFile = ap_pfopen(p, szLogFile, "a")) == NULL) { ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, "Cannot open SSL logfile %s", szLogFile); ssl_die(); } setbuf(sc->fileLogFile, NULL); } } return; }
STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7) { PKCS7 *p7; STACK_OF(X509) *certs = NULL; FILE *f; f = fopen(pkcs7, "r"); if (!f) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02212) "Can't open %s", pkcs7); ssl_die(s); } p7 = PEM_read_PKCS7(f, NULL, NULL, NULL); if (!p7) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02274) "Can't read PKCS7 object %s", pkcs7); ssl_log_ssl_error(SSLLOG_MARK, APLOG_CRIT, s); exit(1); } switch (OBJ_obj2nid(p7->type)) { case NID_pkcs7_signed: certs = p7->d.sign->cert; p7->d.sign->cert = NULL; PKCS7_free(p7); break; case NID_pkcs7_signedAndEnveloped: certs = p7->d.signed_and_enveloped->cert; p7->d.signed_and_enveloped->cert = NULL; PKCS7_free(p7); break; default: ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02213) "Don't understand PKCS7 file %s", pkcs7); ssl_die(s); } if (!certs) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02214) "No certificates in %s", pkcs7); ssl_die(s); } fclose(f); return certs; }
void ssl_scache_dc_init(server_rec *s, apr_pool_t *p) { DC_CTX *ctx; SSLModConfigRec *mc = myModConfig(s); /* * Create a session context */ if (mc->szSessionCacheDataFile == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSLSessionCache required"); ssl_die(); } #if 0 /* If a "persistent connection" mode of operation is preferred, you *must* * also use the PIDCHECK flag to ensure fork()'d processes don't interlace * comms on the same connection as each other. */ #define SESSION_CTX_FLAGS SESSION_CTX_FLAG_PERSISTENT | \ SESSION_CTX_FLAG_PERSISTENT_PIDCHECK | \ SESSION_CTX_FLAG_PERSISTENT_RETRY | \ SESSION_CTX_FLAG_PERSISTENT_LATE #else /* This mode of operation will open a temporary connection to the 'target' * for each cache operation - this makes it safe against fork() * automatically. This mode is preferred when running a local proxy (over * unix domain sockets) because overhead is negligable and it reduces the * performance/stability danger of file-descriptor bloatage. */ #define SESSION_CTX_FLAGS 0 #endif ctx = DC_CTX_new(mc->szSessionCacheDataFile, SESSION_CTX_FLAGS); if (!ctx) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache failed to obtain context"); ssl_die(); } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "distributed scache context initialised"); /* * Success ... */ mc->tSessionCacheDataTable = ctx; return; }
static void ssl_init_ctx_verify(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; int verify = SSL_VERIFY_NONE; STACK_OF(X509_NAME) *ca_list; if (mctx->auth.verify_mode == SSL_CVERIFY_UNSET) { mctx->auth.verify_mode = SSL_CVERIFY_NONE; } if (mctx->auth.verify_depth == UNSET) { mctx->auth.verify_depth = 1; } /* * Configure callbacks for SSL context */ if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) { verify |= SSL_VERIFY_PEER_STRICT; } if ((mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL) || (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA)) { verify |= SSL_VERIFY_PEER; } SSL_CTX_set_verify(ctx, verify, ssl_callback_SSLVerify); /* * Configure Client Authentication details */ if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Configuring client authentication"); if (!SSL_CTX_load_verify_locations(ctx, MODSSL_PCHAR_CAST mctx->auth.ca_cert_file, MODSSL_PCHAR_CAST mctx->auth.ca_cert_path)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Unable to configure verify locations " "for client authentication"); ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); ssl_die(); } if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) { ca_list = ssl_init_FindCAList(s, ptemp, mctx->pks->ca_name_file, mctx->pks->ca_name_path); } else ca_list = ssl_init_FindCAList(s, ptemp, mctx->auth.ca_cert_file, mctx->auth.ca_cert_path); if (!ca_list) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Unable to determine list of acceptable " "CA certificates for client authentication"); ssl_die(); } SSL_CTX_set_client_CA_list(ctx, (STACK *)ca_list); } /* * Give a warning when no CAs were configured but client authentication * should take place. This cannot work. */ if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) { ca_list = (STACK_OF(X509_NAME) *)SSL_CTX_get_client_CA_list(ctx); if (sk_X509_NAME_num(ca_list) == 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Init: Oops, you want to request client " "authentication, but no CAs are known for " "verification!? [Hint: SSLCACertificate*]"); } }
static void ssl_init_ctx_protocol(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modssl_ctx_t *mctx) { SSL_CTX *ctx = NULL; MODSSL_SSL_METHOD_CONST SSL_METHOD *method = NULL; char *cp; int protocol = mctx->protocol; /* * Create the new per-server SSL context */ if (protocol == SSL_PROTOCOL_NONE) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "No SSL protocols available [hint: SSLProtocol]"); ssl_die(); } cp = apr_pstrcat(p, (protocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""), (protocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""), (protocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), NULL); cp[strlen(cp)-2] = NUL; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Creating new SSL context (protocols: %s)", cp); if (protocol == SSL_PROTOCOL_SSLV2) { method = mctx->pkp ? SSLv2_client_method() : /* proxy */ SSLv2_server_method(); /* server */ ctx = SSL_CTX_new(method); /* only SSLv2 is left */ } else { method = mctx->pkp ? SSLv23_client_method() : /* proxy */ SSLv23_server_method(); /* server */ ctx = SSL_CTX_new(method); /* be more flexible */ } mctx->ssl_ctx = ctx; SSL_CTX_set_options(ctx, SSL_OP_ALL); if (!(protocol & SSL_PROTOCOL_SSLV2)) { SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); } if (!(protocol & SSL_PROTOCOL_SSLV3)) { SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); } if (!(protocol & SSL_PROTOCOL_TLSV1)) { SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1); } #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE { SSLSrvConfigRec *sc = mySrvConfig(s); if (sc->cipher_server_pref == TRUE) { SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } } #endif SSL_CTX_set_app_data(ctx, s); /* * Configure additional context ingredients */ SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION /* * Disallow a session from being resumed during a renegotiation, * so that an acceptable cipher suite can be negotiated. */ SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif }
void ssl_scache_shmht_init(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); table_t *ta; int ta_errno; apr_size_t avail; int n; apr_status_t rv; /* * Create shared memory segment */ if (mc->szSessionCacheDataFile == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSLSessionCache required"); ssl_die(); } if ((rv = apr_shm_create(&(mc->pSessionCacheDataMM), mc->nSessionCacheDataSize, mc->szSessionCacheDataFile, mc->pPool)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Cannot allocate shared memory"); ssl_die(); } if ((rv = apr_rmm_init(&(mc->pSessionCacheDataRMM), NULL, apr_shm_baseaddr_get(mc->pSessionCacheDataMM), mc->nSessionCacheDataSize, mc->pPool)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Cannot initialize rmm"); ssl_die(); } ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "initialize MM %pp RMM %pp", mc->pSessionCacheDataMM, mc->pSessionCacheDataRMM); /* * Create hash table in shared memory segment */ avail = mc->nSessionCacheDataSize; n = (avail/2) / 1024; n = n < 10 ? 10 : n; /* * Passing server_rec as opt_param to table_alloc so that we can do * logging if required ssl_util_table. Otherwise, mc is sufficient. */ if ((ta = table_alloc(n, &ta_errno, ssl_scache_shmht_malloc, ssl_scache_shmht_calloc, ssl_scache_shmht_realloc, ssl_scache_shmht_free, s )) == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "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 */ ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Init: Created hash-table (%d buckets) " "in shared memory (%" APR_SIZE_T_FMT " bytes) for SSL session cache", n, avail); return; }
void ssl_scache_shmcb_init(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); void *shm_segment; apr_size_t shm_segsize; apr_status_t rv; SHMCBHeader *header; unsigned int num_subcache, num_idx, loop; /* Create shared memory segment */ if (mc->szSessionCacheDataFile == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSLSessionCache required"); ssl_die(); } /* Use anonymous shm by default, fall back on name-based. */ rv = apr_shm_create(&(mc->pSessionCacheDataMM), mc->nSessionCacheDataSize, NULL, mc->pPool); if (APR_STATUS_IS_ENOTIMPL(rv)) { /* For a name-based segment, remove it first in case of a * previous unclean shutdown. */ apr_shm_remove(mc->szSessionCacheDataFile, mc->pPool); rv = apr_shm_create(&(mc->pSessionCacheDataMM), mc->nSessionCacheDataSize, mc->szSessionCacheDataFile, mc->pPool); } if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "could not allocate shared memory for shmcb " "session cache"); ssl_die(); } shm_segment = apr_shm_baseaddr_get(mc->pSessionCacheDataMM); shm_segsize = apr_shm_size_get(mc->pSessionCacheDataMM); if (shm_segsize < (5 * sizeof(SHMCBHeader))) { /* the segment is ridiculously small, bail out */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "shared memory segment too small"); ssl_die(); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "shmcb_init allocated %" APR_SIZE_T_FMT " bytes of shared memory", shm_segsize); /* Discount the header */ shm_segsize -= sizeof(SHMCBHeader); /* Select the number of subcaches to create and how many indexes each * should contain based on the size of the memory (the header has already * been subtracted). Typical non-client-auth sslv3/tlsv1 sessions are * around 150 bytes, so erring to division by 120 helps ensure we would * exhaust data storage before index storage (except sslv2, where it's * *slightly* the other way). From there, we select the number of subcaches * to be a power of two, such that the number of indexes per subcache at * least twice the number of subcaches. */ num_idx = (shm_segsize) / 120; num_subcache = 256; while ((num_idx / num_subcache) < (2 * num_subcache)) num_subcache /= 2; num_idx /= num_subcache; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "for %" APR_SIZE_T_FMT " bytes (%" APR_SIZE_T_FMT " including header), recommending %u subcaches, " "%u indexes each", shm_segsize, shm_segsize + sizeof(SHMCBHeader), num_subcache, num_idx); if (num_idx < 5) { /* we're still too small, bail out */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "shared memory segment too small"); ssl_die(); } /* OK, we're sorted */ header = shm_segment; header->stat_stores = 0; header->stat_expiries = 0; header->stat_scrolled = 0; header->stat_retrieves_hit = 0; header->stat_retrieves_miss = 0; header->stat_removes_hit = 0; header->stat_removes_miss = 0; header->subcache_num = num_subcache; /* Convert the subcache size (in bytes) to a value that is suitable for * structure alignment on the host platform, by rounding down if necessary. * This assumes that sizeof(unsigned long) provides an appropriate * alignment unit. */ header->subcache_size = ((size_t)(shm_segsize / num_subcache) & ~(size_t)(sizeof(unsigned long) - 1)); header->subcache_data_offset = sizeof(SHMCBSubcache) + num_idx * sizeof(SHMCBIndex); header->subcache_data_size = header->subcache_size - header->subcache_data_offset; header->index_num = num_idx; /* Output trace info */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "shmcb_init_memory choices follow"); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "subcache_num = %u", header->subcache_num); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "subcache_size = %u", header->subcache_size); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "subcache_data_offset = %u", header->subcache_data_offset); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "subcache_data_size = %u", header->subcache_data_size); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "index_num = %u", header->index_num); /* The header is done, make the caches empty */ for (loop = 0; loop < header->subcache_num; loop++) { SHMCBSubcache *subcache = SHMCB_SUBCACHE(header, loop); subcache->idx_pos = subcache->idx_used = 0; subcache->data_pos = subcache->data_used = 0; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Shared memory session cache initialised"); /* Success ... */ mc->tSessionCacheDataTable = shm_segment; }