/* 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_engine_config.c * Apache Configuration Directives */ /* ``Damned if you do, damned if you don't.'' -- Unknown */ #include #include #include "ssl_private.h" #include "ssl_policies.h" #include "util_mutex.h" #include "ap_provider.h" /* _________________________________________________________________ ** ** Support for Global Configuration ** _________________________________________________________________ */ static SSLModConfigRec *ssl_config_global_create(apr_pool_t *pool, server_rec *s) { SSLModConfigRec *mc; if (ap_server_conf && s != ap_server_conf) { SSLSrvConfigRec *sc = mySrvConfig(ap_server_conf); AP_DEBUG_ASSERT(sc->mc); return sc->mc; } mc = apr_pcalloc(pool, sizeof(*mc)); /* * initialize per-module configuration */ mc->sesscache_mode = SSL_SESS_CACHE_OFF; #ifdef MODSSL_USE_SSLRAND mc->aRandSeed = apr_array_make(pool, 4, sizeof(ssl_randseed_t)); #endif #ifdef HAVE_FIPS mc->fips = UNSET; #endif mc->retained = ap_retained_data_get(MODSSL_RETAINED_KEY); if (!mc->retained) { /* Allocate the retained data; the hash table is allocated out * of the process pool. */ mc->retained = ap_retained_data_create(MODSSL_RETAINED_KEY, sizeof *mc->retained); mc->retained->privkeys = apr_hash_make(s->process->pool); mc->retained->key_ids = apr_hash_make(s->process->pool); } return mc; } void ssl_config_global_fix(SSLModConfigRec *mc) { mc->bFixed = TRUE; } BOOL ssl_config_global_isfixed(SSLModConfigRec *mc) { return mc->bFixed; } /* _________________________________________________________________ ** ** Configuration handling ** _________________________________________________________________ */ #ifdef HAVE_SSL_CONF_CMD static apr_status_t modssl_ctx_config_cleanup(void *ctx) { SSL_CONF_CTX_free(ctx); return APR_SUCCESS; } #endif static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) { mctx->sc = NULL; /* set during module init */ mctx->ssl_ctx = NULL; /* set during module init */ mctx->pks = NULL; mctx->pkp = NULL; #ifdef HAVE_TLS_SESSION_TICKETS mctx->ticket_key = NULL; #endif mctx->protocol = SSL_PROTOCOL_DEFAULT; mctx->protocol_set = 0; mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET; mctx->pphrase_dialog_path = NULL; mctx->cert_chain = NULL; mctx->crl_path = NULL; mctx->crl_file = NULL; mctx->crl_check_mask = UNSET; mctx->auth.ca_cert_path = NULL; mctx->auth.ca_cert_file = NULL; mctx->auth.cipher_suite = NULL; mctx->auth.verify_depth = UNSET; mctx->auth.verify_mode = SSL_CVERIFY_UNSET; mctx->auth.tls13_ciphers = NULL; mctx->ocsp_mask = UNSET; mctx->ocsp_force_default = UNSET; mctx->ocsp_responder = NULL; mctx->ocsp_resptime_skew = UNSET; mctx->ocsp_resp_maxage = UNSET; mctx->ocsp_responder_timeout = UNSET; mctx->ocsp_use_request_nonce = UNSET; mctx->proxy_uri = NULL; /* Set OCSP Responder Certificate Verification variable */ mctx->ocsp_noverify = UNSET; /* Set OCSP Responder File variables */ mctx->ocsp_verify_flags = 0; mctx->ocsp_certs_file = NULL; mctx->ocsp_certs = 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 #ifdef HAVE_SRP mctx->srp_vfile = NULL; mctx->srp_unknown_user_seed = NULL; mctx->srp_vbase = NULL; #endif #ifdef HAVE_SSL_CONF_CMD mctx->ssl_ctx_config = SSL_CONF_CTX_new(); apr_pool_cleanup_register(p, mctx->ssl_ctx_config, modssl_ctx_config_cleanup, apr_pool_cleanup_null); SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_FILE); SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_SERVER); SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_CERTIFICATE); mctx->ssl_ctx_param = apr_array_make(p, 5, sizeof(ssl_ctx_param_t)); #endif mctx->ssl_check_peer_cn = UNSET; mctx->ssl_check_peer_name = UNSET; mctx->ssl_check_peer_expire = UNSET; } static void modssl_ctx_init_server(SSLSrvConfigRec *sc, apr_pool_t *p) { modssl_ctx_t *mctx; mctx = sc->server = apr_palloc(p, sizeof(*sc->server)); modssl_ctx_init(mctx, p); mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks)); mctx->pks->cert_files = apr_array_make(p, 3, sizeof(char *)); mctx->pks->key_files = apr_array_make(p, 3, sizeof(char *)); #ifdef HAVE_TLS_SESSION_TICKETS mctx->ticket_key = apr_pcalloc(p, sizeof(*mctx->ticket_key)); #endif } static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) { SSLSrvConfigRec *sc = apr_palloc(p, sizeof(*sc)); sc->mc = NULL; sc->enabled = SSL_ENABLED_UNSET; sc->vhost_id = NULL; /* set during module init */ sc->session_cache_timeout = UNSET; sc->cipher_server_pref = UNSET; #ifdef HAVE_TLSEXT sc->strict_sni_vhost_check = SSL_ENABLED_UNSET; #endif #ifndef OPENSSL_NO_COMP sc->compression = UNSET; #endif sc->clienthello_vars = UNSET; sc->session_tickets = UNSET; modssl_ctx_init_server(sc, p); return sc; } /* * Create per-server SSL configuration */ void *ssl_config_server_create(apr_pool_t *p, server_rec *s) { SSLSrvConfigRec *sc = ssl_config_server_new(p); sc->mc = ssl_config_global_create(p, s); return sc; } #define cfgMerge(el,unset) mrg->el = (add->el == (unset)) ? base->el : add->el #define cfgMergeArray(el) mrg->el = apr_array_append(p, base->el, add->el) #define cfgMergeString(el) cfgMerge(el, NULL) #define cfgMergeBool(el) cfgMerge(el, UNSET) #define cfgMergeInt(el) cfgMerge(el, UNSET) /* * Merge per-server SSL configurations */ static void modssl_ctx_cfg_merge(apr_pool_t *p, modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { if (add->protocol_set) { mrg->protocol_set = 1; mrg->protocol = add->protocol; } else { mrg->protocol_set = base->protocol_set; mrg->protocol = base->protocol; } cfgMerge(pphrase_dialog_type, SSL_PPTYPE_UNSET); cfgMergeString(pphrase_dialog_path); cfgMergeString(cert_chain); cfgMerge(crl_path, NULL); cfgMerge(crl_file, NULL); cfgMergeInt(crl_check_mask); cfgMergeString(auth.ca_cert_path); cfgMergeString(auth.ca_cert_file); cfgMergeString(auth.cipher_suite); cfgMergeInt(auth.verify_depth); cfgMerge(auth.verify_mode, SSL_CVERIFY_UNSET); cfgMergeString(auth.tls13_ciphers); cfgMergeInt(ocsp_mask); cfgMergeBool(ocsp_force_default); cfgMerge(ocsp_responder, NULL); cfgMergeInt(ocsp_resptime_skew); cfgMergeInt(ocsp_resp_maxage); cfgMergeInt(ocsp_responder_timeout); cfgMergeBool(ocsp_use_request_nonce); cfgMerge(proxy_uri, NULL); /* Set OCSP Responder Certificate Verification directive */ cfgMergeBool(ocsp_noverify); /* Set OCSP Responder File directive for importing */ cfgMerge(ocsp_certs_file, 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 #ifdef HAVE_SRP cfgMergeString(srp_vfile); cfgMergeString(srp_unknown_user_seed); #endif #ifdef HAVE_SSL_CONF_CMD cfgMergeArray(ssl_ctx_param); #endif cfgMergeBool(ssl_check_peer_cn); cfgMergeBool(ssl_check_peer_name); cfgMergeBool(ssl_check_peer_expire); } static void modssl_ctx_cfg_merge_server(apr_pool_t *p, modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { modssl_ctx_cfg_merge(p, base, add, mrg); cfgMergeArray(pks->cert_files); cfgMergeArray(pks->key_files); cfgMergeString(pks->ca_name_path); cfgMergeString(pks->ca_name_file); #ifdef HAVE_TLS_SESSION_TICKETS cfgMergeString(ticket_key->file_path); #endif } void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) { SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev; SSLSrvConfigRec *add = (SSLSrvConfigRec *)addv; SSLSrvConfigRec *mrg = ssl_config_server_new(p); cfgMerge(mc, NULL); cfgMerge(enabled, SSL_ENABLED_UNSET); cfgMergeInt(session_cache_timeout); cfgMergeBool(cipher_server_pref); cfgMergeBool(clienthello_vars); #ifdef HAVE_TLSEXT cfgMerge(strict_sni_vhost_check, SSL_ENABLED_UNSET); #endif #ifndef OPENSSL_NO_COMP cfgMergeBool(compression); #endif cfgMergeBool(session_tickets); modssl_ctx_cfg_merge_server(p, base->server, add->server, mrg->server); return mrg; } /* * Create per-directory SSL configuration */ static void modssl_ctx_init_proxy(SSLDirConfigRec *dc, apr_pool_t *p) { modssl_ctx_t *mctx; mctx = dc->proxy = apr_palloc(p, sizeof(*dc->proxy)); modssl_ctx_init(mctx, p); mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp)); mctx->pkp->cert_file = NULL; mctx->pkp->cert_path = NULL; mctx->pkp->ca_cert_file = NULL; mctx->pkp->certs = NULL; mctx->pkp->ca_certs = NULL; } void *ssl_config_perdir_create(apr_pool_t *p, char *dir) { SSLDirConfigRec *dc = apr_palloc(p, sizeof(*dc)); dc->bSSLRequired = FALSE; dc->aRequirement = apr_array_make(p, 4, sizeof(ssl_require_t)); dc->nOptions = SSL_OPT_NONE|SSL_OPT_RELSET; dc->nOptionsAdd = SSL_OPT_NONE; dc->nOptionsDel = SSL_OPT_NONE; dc->szCipherSuite = NULL; dc->nVerifyClient = SSL_CVERIFY_UNSET; dc->nVerifyDepth = UNSET; dc->szUserName = NULL; dc->nRenegBufferSize = UNSET; dc->proxy_enabled = UNSET; modssl_ctx_init_proxy(dc, p); dc->proxy_post_config = FALSE; return dc; } /* * Merge per-directory SSL configurations */ static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p, modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { modssl_ctx_cfg_merge(p, base, add, mrg); cfgMergeString(pkp->cert_file); cfgMergeString(pkp->cert_path); cfgMergeString(pkp->ca_cert_file); cfgMergeString(pkp->certs); cfgMergeString(pkp->ca_certs); } void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv) { SSLDirConfigRec *base = (SSLDirConfigRec *)basev; SSLDirConfigRec *add = (SSLDirConfigRec *)addv; SSLDirConfigRec *mrg = (SSLDirConfigRec *)apr_palloc(p, sizeof(*mrg)); cfgMerge(bSSLRequired, FALSE); cfgMergeArray(aRequirement); if (add->nOptions & SSL_OPT_RELSET) { mrg->nOptionsAdd = (base->nOptionsAdd & ~(add->nOptionsDel)) | add->nOptionsAdd; mrg->nOptionsDel = (base->nOptionsDel & ~(add->nOptionsAdd)) | add->nOptionsDel; mrg->nOptions = (base->nOptions & ~(mrg->nOptionsDel)) | mrg->nOptionsAdd; } else { mrg->nOptions = add->nOptions; mrg->nOptionsAdd = add->nOptionsAdd; mrg->nOptionsDel = add->nOptionsDel; } cfgMergeString(szCipherSuite); cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET); cfgMergeInt(nVerifyDepth); cfgMergeString(szUserName); cfgMergeInt(nRenegBufferSize); mrg->proxy_post_config = add->proxy_post_config; if (!mrg->proxy_post_config) { cfgMergeBool(proxy_enabled); modssl_ctx_init_proxy(mrg, p); modssl_ctx_cfg_merge_proxy(p, base->proxy, add->proxy, mrg->proxy); /* Since ssl_proxy_section_post_config() hook won't be called if there * is no SSLProxy* in this dir config, the ssl_ctx may still be NULL * here at runtime. Merging it is either a no-op (NULL => NULL) because * we are still before post config, or we really want to reuse the one * from the upper/server context (outside of sections). */ cfgMerge(proxy->ssl_ctx, NULL); } else { /* The post_config hook has already merged and initialized the * proxy context, use it. */ mrg->proxy_enabled = add->proxy_enabled; mrg->proxy = add->proxy; } return mrg; } /* Simply merge conf with base into conf, no third party. */ void ssl_config_proxy_merge(apr_pool_t *p, SSLDirConfigRec *base, SSLDirConfigRec *conf) { if (conf->proxy_enabled == UNSET) { conf->proxy_enabled = base->proxy_enabled; } modssl_ctx_cfg_merge_proxy(p, base->proxy, conf->proxy, conf->proxy); } /* _________________________________________________________________ ** ** Policy handling ** _________________________________________________________________ */ static void add_policy(apr_hash_t *policies, apr_pool_t *p, const char *name, int protocols, const char *ssl_ciphers, const char *tls13_ciphers, int honor_order, int compression, int session_tickets) { SSLSrvConfigRec *policy; policy = ssl_config_server_new(p); if (protocols) { policy->server->protocol_set = 1; policy->server->protocol = protocols; } if (ssl_ciphers) { policy->server->auth.cipher_suite = ssl_ciphers; } if (tls13_ciphers) { policy->server->auth.tls13_ciphers = tls13_ciphers; } #ifndef OPENSSL_NO_COMP policy->compression = compression ? TRUE : FALSE; #endif policy->session_tickets = session_tickets ? TRUE : FALSE; apr_hash_set(policies, name, APR_HASH_KEY_STRING, policy); } static apr_hash_t *get_policies(apr_pool_t *p) { apr_hash_t *policies; void *vp; apr_pool_userdata_get(&vp, SSL_MOD_POLICIES_KEY, p); if (vp) { return vp; /* reused for lifetime of the pool */ } policies = apr_hash_make(p); #if SSL_POLICY_MODERN add_policy(policies, p, "modern", SSL_POLICY_MODERN_PROTOCOLS, SSL_POLICY_MODERN_SSL_CIPHERS, SSL_POLICY_MODERN_TLS13_CIPHERS, SSL_POLICY_HONOR_ORDER, SSL_POLICY_COMPRESSION, SSL_POLICY_SESSION_TICKETS); #endif #if SSL_POLICY_INTERMEDIATE add_policy(policies, p, "intermediate", SSL_POLICY_INTERMEDIATE_PROTOCOLS, SSL_POLICY_INTERMEDIATE_SSL_CIPHERS, SSL_POLICY_INTERMEDIATE_TLS13_CIPHERS, SSL_POLICY_HONOR_ORDER, SSL_POLICY_COMPRESSION, SSL_POLICY_SESSION_TICKETS); #endif #if SSL_POLICY_OLD add_policy(policies, p, "old", SSL_POLICY_OLD_PROTOCOLS, SSL_POLICY_OLD_SSL_CIPHERS, SSL_POLICY_OLD_TLS13_CIPHERS, SSL_POLICY_HONOR_ORDER, SSL_POLICY_COMPRESSION, SSL_POLICY_SESSION_TICKETS); #endif apr_pool_userdata_set(policies, SSL_MOD_POLICIES_KEY, apr_pool_cleanup_null, p); return policies; } static int policy_collect_names(void *baton, const void *key, apr_ssize_t klen, const void *val) { apr_array_header_t *names = baton; APR_ARRAY_PUSH(names, const char *) = (const char*)key; return 1; } static int qstrcmp(const void *v1, const void *v2) { return strcmp(*(const char**)v1, *(const char**)v2); } static apr_array_header_t *get_policy_names(apr_pool_t *p) { apr_array_header_t *names = apr_array_make(p, 10, sizeof(const char*)); apr_hash_t *policies = get_policies(p); if (policies) { apr_hash_do(policy_collect_names, names, policies); qsort(names->elts, names->nelts, sizeof(const char*), qstrcmp); } return names; } SSLSrvConfigRec *ssl_policy_lookup(apr_pool_t *pool, const char *name) { apr_hash_t *policies = get_policies(pool); return apr_hash_get(policies, name, APR_HASH_KEY_STRING); } const char *ssl_cmd_SSLPolicyApply(cmd_parms *cmd, void *mconfig, const char *arg) { SSLSrvConfigRec *mrg, *sc = mySrvConfig(cmd->server); SSLSrvConfigRec *policy; policy = ssl_policy_lookup(cmd->pool, arg); if (policy) { mrg = ssl_config_server_merge(cmd->pool, policy, sc); /* apply in place */ memcpy(sc, mrg, sizeof(*sc)); return NULL; } return apr_pstrcat(cmd->pool, "An SSLPolicy with the name '", arg, "' does not exist", NULL); } /* * Configuration functions for particular directives */ const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; int arglen = strlen(arg); if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (strcEQ(arg, "builtin")) { sc->server->pphrase_dialog_type = SSL_PPTYPE_BUILTIN; sc->server->pphrase_dialog_path = NULL; } else if ((arglen > 5) && strEQn(arg, "exec:", 5)) { sc->server->pphrase_dialog_type = SSL_PPTYPE_FILTER; sc->server->pphrase_dialog_path = ap_server_root_relative(cmd->pool, arg+5); if (!sc->server->pphrase_dialog_path) { return apr_pstrcat(cmd->pool, "Invalid SSLPassPhraseDialog exec: path ", arg+5, NULL); } if (!ssl_util_path_check(SSL_PCM_EXISTS, sc->server->pphrase_dialog_path, cmd->pool)) { return apr_pstrcat(cmd->pool, "SSLPassPhraseDialog: file '", sc->server->pphrase_dialog_path, "' does not exist", NULL); } } else if ((arglen > 1) && (arg[0] == '|')) { sc->server->pphrase_dialog_type = SSL_PPTYPE_PIPE; sc->server->pphrase_dialog_path = arg + 1; } else { return "SSLPassPhraseDialog: Invalid argument"; } return NULL; } const char *ssl_cmd_SSLCryptoDevice(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); const char *err; #if MODSSL_HAVE_ENGINE_API ENGINE *e; #endif if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (!mc) { return "SSLCryptoDevice: cannot be used inside SSLPolicyDefine"; } if (strcEQ(arg, "builtin")) { mc->szCryptoDevice = NULL; } #if MODSSL_HAVE_ENGINE_API else if ((e = ENGINE_by_id(arg))) { mc->szCryptoDevice = arg; ENGINE_free(e); } #endif else { err = "SSLCryptoDevice: Invalid argument; must be one of: " "'builtin' (none)"; #if MODSSL_HAVE_ENGINE_API e = ENGINE_get_first(); while (e) { err = apr_pstrcat(cmd->pool, err, ", '", ENGINE_get_id(e), "' (", ENGINE_get_name(e), ")", NULL); /* Iterate; this call implicitly decrements the refcount * on the 'old' e, per the docs in engine.h. */ e = ENGINE_get_next(e); } #endif return err; } return NULL; } const char *ssl_cmd_SSLRandomSeed(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2, const char *arg3) { #ifdef MODSSL_USE_SSLRAND SSLModConfigRec *mc = myModConfig(cmd->server); const char *err; ssl_randseed_t *seed; int arg2len = strlen(arg2); /* replace: check_no_policy_and(flags) */ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (!mc) { return "SSLRandomSeed: cannot be used inside SSLPolicyDefine"; } if (ssl_config_global_isfixed(mc)) { return NULL; } seed = apr_array_push(mc->aRandSeed); if (strcEQ(arg1, "startup")) { seed->nCtx = SSL_RSCTX_STARTUP; } else if (strcEQ(arg1, "connect")) { seed->nCtx = SSL_RSCTX_CONNECT; } else { return apr_pstrcat(cmd->pool, "SSLRandomSeed: " "invalid context: `", arg1, "'", NULL); } if ((arg2len > 5) && strEQn(arg2, "file:", 5)) { seed->nSrc = SSL_RSSRC_FILE; seed->cpPath = ap_server_root_relative(cmd->pool, arg2+5); } else if ((arg2len > 5) && strEQn(arg2, "exec:", 5)) { seed->nSrc = SSL_RSSRC_EXEC; seed->cpPath = ap_server_root_relative(cmd->pool, arg2+5); } else if ((arg2len > 4) && strEQn(arg2, "egd:", 4)) { #ifdef HAVE_RAND_EGD seed->nSrc = SSL_RSSRC_EGD; seed->cpPath = ap_server_root_relative(cmd->pool, arg2+4); #else return apr_pstrcat(cmd->pool, "Invalid SSLRandomSeed entropy source `", arg2, "': This version of " MODSSL_LIBRARY_NAME " does not support the Entropy Gathering Daemon " "(EGD).", NULL); #endif } else if (strcEQ(arg2, "builtin")) { seed->nSrc = SSL_RSSRC_BUILTIN; seed->cpPath = NULL; } else { seed->nSrc = SSL_RSSRC_FILE; seed->cpPath = ap_server_root_relative(cmd->pool, arg2); } if (seed->nSrc != SSL_RSSRC_BUILTIN) { if (!seed->cpPath) { return apr_pstrcat(cmd->pool, "Invalid SSLRandomSeed path ", arg2, NULL); } if (!ssl_util_path_check(SSL_PCM_EXISTS, seed->cpPath, cmd->pool)) { return apr_pstrcat(cmd->pool, "SSLRandomSeed: source path '", seed->cpPath, "' does not exist", NULL); } } if (!arg3) { seed->nBytes = 0; /* read whole file */ } else { if (seed->nSrc == SSL_RSSRC_BUILTIN) { return "SSLRandomSeed: byte specification not " "allowed for builtin seed source"; } seed->nBytes = atoi(arg3); if (seed->nBytes < 0) { return "SSLRandomSeed: invalid number of bytes specified"; } } #else ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(10235) "SSLRandomSeed is deprecated and has no effect " "with OpenSSL 1.1.1 and later"); #endif return NULL; } const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); if (!strcasecmp(arg, "On")) { sc->enabled = SSL_ENABLED_TRUE; return NULL; } else if (!strcasecmp(arg, "Off")) { sc->enabled = SSL_ENABLED_FALSE; return NULL; } else if (!strcasecmp(arg, "Optional")) { sc->enabled = SSL_ENABLED_OPTIONAL; return NULL; } return "Argument must be On, Off, or Optional"; } const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag) { #ifdef HAVE_FIPS SSLModConfigRec *mc = myModConfig(cmd->server); #endif const char *err; if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } #ifdef HAVE_FIPS if ((mc->fips != UNSET) && (mc->fips != (BOOL)(flag ? TRUE : FALSE))) return "Conflicting SSLFIPS options, cannot be both On and Off"; mc->fips = flag ? TRUE : FALSE; #else if (flag) return "SSLFIPS invalid, rebuild httpd and openssl compiled for FIPS"; #endif return NULL; } const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; if (arg2 == NULL) { arg2 = arg1; arg1 = "SSL"; } if (!strcmp("SSL", arg1)) { /* always disable null and export ciphers */ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); if (cmd->path) { dc->szCipherSuite = arg2; } else { sc->server->auth.cipher_suite = arg2; } return NULL; } #if SSL_HAVE_PROTOCOL_TLSV1_3 else if (!strcmp("TLSv1.3", arg1)) { if (cmd->path) { return "TLSv1.3 ciphers cannot be set inside a directory context"; } sc->server->auth.tls13_ciphers = arg2; return NULL; } #endif return apr_pstrcat(cmd->pool, "protocol '", arg1, "' not supported", NULL); } #define SSL_FLAGS_CHECK_FILE \ (SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO) #define SSL_FLAGS_CHECK_DIR \ (SSL_PCM_EXISTS|SSL_PCM_ISDIR) static const char *ssl_cmd_check_file(cmd_parms *parms, const char **file) { const char *filepath; /* If only dumping the config, don't verify the paths */ if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) { return NULL; } filepath = ap_server_root_relative(parms->pool, *file); if (!filepath) { return apr_pstrcat(parms->pool, parms->cmd->name, ": Invalid file path ", *file, NULL); } *file = filepath; if (ssl_util_path_check(SSL_FLAGS_CHECK_FILE, *file, parms->pool)) { return NULL; } return apr_pstrcat(parms->pool, parms->cmd->name, ": file '", *file, "' does not exist or is empty", NULL); } const char *ssl_cmd_SSLCompression(cmd_parms *cmd, void *dcfg, int flag) { #if !defined(OPENSSL_NO_COMP) SSLSrvConfigRec *sc = mySrvConfig(cmd->server); #ifndef SSL_OP_NO_COMPRESSION const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err) return "This version of OpenSSL does not support enabling " "SSLCompression within sections."; #endif if (flag) { /* Some (packaged) versions of OpenSSL do not support * compression by default. Enabling this directive would not * have the desired effect, so fail with an error. */ STACK_OF(SSL_COMP) *meths = SSL_COMP_get_compression_methods(); if (sk_SSL_COMP_num(meths) == 0) { return "This version of OpenSSL does not have any compression methods " "available, cannot enable SSLCompression."; } } sc->compression = flag ? TRUE : FALSE; #else if (flag) { return "Setting Compression mode unsupported; not implemented by the SSL library"; } #endif return NULL; } const char *ssl_cmd_SSLClientHelloVars(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->clienthello_vars = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag) { #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->cipher_server_pref = flag?TRUE:FALSE; return NULL; #else return "SSLHonorCipherOrder unsupported; not implemented by the SSL library"; #endif } const char *ssl_cmd_SSLSessionTickets(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); #ifndef SSL_OP_NO_TICKET return "This version of OpenSSL does not support using " "SSLSessionTickets."; #endif sc->session_tickets = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag) { return "The SSLInsecureRenegotiation directive is no longer supported"; } static const char *ssl_cmd_check_dir(cmd_parms *parms, const char **dir) { const char *dirpath = ap_server_root_relative(parms->pool, *dir); if (!dirpath) { return apr_pstrcat(parms->pool, parms->cmd->name, ": Invalid dir path ", *dir, NULL); } *dir = dirpath; if (ssl_util_path_check(SSL_FLAGS_CHECK_DIR, *dir, parms->pool)) { return NULL; } return apr_pstrcat(parms->pool, parms->cmd->name, ": directory '", *dir, "' does not exist", NULL); } const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; /* Only check for non-ENGINE based certs. */ if (!modssl_is_engine_id(arg) && (err = ssl_cmd_check_file(cmd, &arg))) { return err; } *(const char **)apr_array_push(sc->server->pks->cert_files) = arg; return NULL; } const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; /* Check keyfile exists for non-ENGINE keys. */ if (!modssl_is_engine_id(arg) && (err = ssl_cmd_check_file(cmd, &arg))) { return err; } *(const char **)apr_array_push(sc->server->pks->key_files) = arg; return NULL; } const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } sc->server->cert_chain = arg; return NULL; } #ifdef HAVE_TLS_SESSION_TICKETS const char *ssl_cmd_SSLSessionTicketKeyFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } sc->server->ticket_key->file_path = arg; return NULL; } #endif #define NO_PER_DIR_SSL_CA \ "Your SSL library does not have support for per-directory CA" const char *ssl_cmd_SSLCACertificatePath(cmd_parms *cmd, void *dcfg, const char *arg) { /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } if (cmd->path) { return NO_PER_DIR_SSL_CA; } /* XXX: bring back per-dir */ sc->server->auth.ca_cert_path = arg; return NULL; } const char *ssl_cmd_SSLCACertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } if (cmd->path) { return NO_PER_DIR_SSL_CA; } /* XXX: bring back per-dir */ sc->server->auth.ca_cert_file = arg; return NULL; } const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } sc->server->pks->ca_name_path = arg; return NULL; } const char *ssl_cmd_SSLCADNRequestFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } sc->server->pks->ca_name_file = arg; return NULL; } const char *ssl_cmd_SSLCARevocationPath(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } sc->server->crl_path = arg; return NULL; } const char *ssl_cmd_SSLCARevocationFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } sc->server->crl_file = arg; return NULL; } static const char *ssl_cmd_crlcheck_parse(cmd_parms *parms, const char *arg, int *mask) { const char *w; w = ap_getword_conf(parms->temp_pool, &arg); if (strcEQ(w, "none")) { *mask = SSL_CRLCHECK_NONE; } else if (strcEQ(w, "leaf")) { *mask = SSL_CRLCHECK_LEAF; } else if (strcEQ(w, "chain")) { *mask = SSL_CRLCHECK_CHAIN; } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", w, "'", NULL); } while (*arg) { w = ap_getword_conf(parms->temp_pool, &arg); if (strcEQ(w, "no_crl_for_cert_ok")) { *mask |= SSL_CRLCHECK_NO_CRL_FOR_CERT_OK; } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", w, "'", NULL); } } return NULL; } const char *ssl_cmd_SSLCARevocationCheck(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); return ssl_cmd_crlcheck_parse(cmd, arg, &sc->server->crl_check_mask); } static const char *ssl_cmd_verify_parse(cmd_parms *parms, const char *arg, ssl_verify_t *id) { if (strcEQ(arg, "none") || strcEQ(arg, "off")) { *id = SSL_CVERIFY_NONE; } else if (strcEQ(arg, "optional")) { *id = SSL_CVERIFY_OPTIONAL; } else if (strcEQ(arg, "require") || strcEQ(arg, "on")) { *id = SSL_CVERIFY_REQUIRE; } else if (strcEQ(arg, "optional_no_ca")) { *id = SSL_CVERIFY_OPTIONAL_NO_CA; } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", arg, "'", NULL); } return NULL; } const char *ssl_cmd_SSLVerifyClient(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ssl_verify_t mode = SSL_CVERIFY_NONE; const char *err; if ((err = ssl_cmd_verify_parse(cmd, arg, &mode))) { return err; } if (cmd->path) { dc->nVerifyClient = mode; } else { sc->server->auth.verify_mode = mode; } return NULL; } static const char *ssl_cmd_verify_depth_parse(cmd_parms *parms, const char *arg, int *depth) { if ((*depth = atoi(arg)) >= 0) { return NULL; } return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", arg, "'", NULL); } const char *ssl_cmd_SSLVerifyDepth(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; SSLSrvConfigRec *sc = mySrvConfig(cmd->server); int depth; const char *err; if ((err = ssl_cmd_verify_depth_parse(cmd, arg, &depth))) { return err; } if (cmd->path) { dc->nVerifyDepth = depth; } else { sc->server->auth.verify_depth = depth; } return NULL; } const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); const char *err, *sep, *name; long enabled_flags; if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (!mc) { return "SSLSessionCache: cannot be used inside SSLPolicyDefine"; } /* The OpenSSL session cache mode must have both the flags * SSL_SESS_CACHE_SERVER and SSL_SESS_CACHE_NO_INTERNAL set if a * session cache is configured; NO_INTERNAL prevents the * OpenSSL-internal session cache being used in addition to the * "external" (mod_ssl-provided) cache, which otherwise causes * additional memory consumption. */ enabled_flags = SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL; if (strcEQ(arg, "none")) { /* Nothing to do; session cache will be off. */ } else if (strcEQ(arg, "nonenotnull")) { /* ### Having a separate mode for this seems logically * unnecessary; the stated purpose of sending non-empty * session IDs would be better fixed in OpenSSL or simply * doing it by default if "none" is used. */ mc->sesscache_mode = enabled_flags; } else { /* 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->sesscache = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP, name, AP_SOCACHE_PROVIDER_VERSION); if (mc->sesscache) { /* Cache found; create it, passing anything beyond the colon. */ mc->sesscache_mode = enabled_flags; err = mc->sesscache->create(&mc->sesscache_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' session cache not supported " "(known names: %s). Maybe you need to load the " "appropriate socache module (mod_socache_%s?).", name, all_names, name); } } if (err) { return apr_psprintf(cmd->pool, "SSLSessionCache: %s", err); } return NULL; } const char *ssl_cmd_SSLSessionCacheTimeout(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->session_cache_timeout = atoi(arg); if (sc->session_cache_timeout < 0) { return "SSLSessionCacheTimeout: Invalid argument"; } return NULL; } const char *ssl_cmd_SSLOptions(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; ssl_opt_t opt; int first = TRUE; char action, *w; while (*arg) { w = ap_getword_conf(cmd->temp_pool, &arg); action = NUL; if ((*w == '+') || (*w == '-')) { action = *(w++); } else if (first) { dc->nOptions = SSL_OPT_NONE; first = FALSE; } if (strcEQ(w, "StdEnvVars")) { opt = SSL_OPT_STDENVVARS; } else if (strcEQ(w, "ExportCertData")) { opt = SSL_OPT_EXPORTCERTDATA; } else if (strcEQ(w, "ExportBase64CertData")) { opt = SSL_OPT_EXPORTCB64DATA; } else if (strcEQ(w, "FakeBasicAuth")) { opt = SSL_OPT_FAKEBASICAUTH; } else if (strcEQ(w, "StrictRequire")) { opt = SSL_OPT_STRICTREQUIRE; } else if (strcEQ(w, "OptRenegotiate")) { opt = SSL_OPT_OPTRENEGOTIATE; } else if (strcEQ(w, "LegacyDNStringFormat")) { opt = SSL_OPT_LEGACYDNFORMAT; } else { return apr_pstrcat(cmd->pool, "SSLOptions: Illegal option '", w, "'", NULL); } if (action == '-') { dc->nOptionsAdd &= ~opt; dc->nOptionsDel |= opt; dc->nOptions &= ~opt; } else if (action == '+') { dc->nOptionsAdd |= opt; dc->nOptionsDel &= ~opt; dc->nOptions |= opt; } else { dc->nOptions = opt; dc->nOptionsAdd = opt; dc->nOptionsDel = SSL_OPT_NONE; } } return NULL; } const char *ssl_cmd_SSLRequireSSL(cmd_parms *cmd, void *dcfg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->bSSLRequired = TRUE; return NULL; } const char *ssl_cmd_SSLRequire(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t)); ssl_require_t *require; const char *errstring; info->flags = AP_EXPR_FLAG_SSL_EXPR_COMPAT; info->filename = cmd->directive->filename; info->line_number = cmd->directive->line_num; info->module_index = APLOG_MODULE_INDEX; errstring = ap_expr_parse(cmd->pool, cmd->temp_pool, info, arg, NULL); if (errstring) { return apr_pstrcat(cmd->pool, "SSLRequire: ", errstring, NULL); } require = apr_array_push(dc->aRequirement); require->cpExpr = arg; require->mpExpr = info; return NULL; } const char *ssl_cmd_SSLRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = dcfg; int val; val = atoi(arg); if (val < 0) { return apr_pstrcat(cmd->pool, "Invalid size for SSLRenegBufferSize: ", arg, NULL); } dc->nRenegBufferSize = val; return NULL; } static const char *ssl_cmd_protocol_parse(cmd_parms *parms, const char *arg, ssl_proto_t *options) { ssl_proto_t thisopt; *options = SSL_PROTOCOL_NONE; while (*arg) { char *w = ap_getword_conf(parms->temp_pool, &arg); char action = '\0'; if ((*w == '+') || (*w == '-')) { action = *(w++); } if (strcEQ(w, "SSLv2")) { if (action == '-') { continue; } else { return "SSLProtocol: SSLv2 is no longer supported"; } } else if (strcEQ(w, "SSLv3")) { #ifdef OPENSSL_NO_SSL3 if (action != '-') { return "SSLv3 not supported by this version of OpenSSL"; } /* Nothing to do, the flag is not present to be toggled */ continue; #else thisopt = SSL_PROTOCOL_SSLV3; #endif } else if (strcEQ(w, "TLSv1")) { thisopt = SSL_PROTOCOL_TLSV1; } #ifdef HAVE_TLSV1_X else if (strcEQ(w, "TLSv1.1")) { thisopt = SSL_PROTOCOL_TLSV1_1; } else if (strcEQ(w, "TLSv1.2")) { thisopt = SSL_PROTOCOL_TLSV1_2; } else if (SSL_HAVE_PROTOCOL_TLSV1_3 && strcEQ(w, "TLSv1.3")) { thisopt = SSL_PROTOCOL_TLSV1_3; } #endif else if (strcEQ(w, "all")) { thisopt = SSL_PROTOCOL_ALL; } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Illegal protocol '", w, "'", NULL); } if (action == '-') { *options &= ~thisopt; } else if (action == '+') { *options |= thisopt; } else { if (*options != SSL_PROTOCOL_NONE) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, APLOGNO(02532) "%s: Protocol '%s' overrides already set parameter(s). " "Check if a +/- prefix is missing.", parms->cmd->name, w); } *options = thisopt; } } return NULL; } const char *ssl_cmd_SSLProtocol(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->protocol_set = 1; return ssl_cmd_protocol_parse(cmd, arg, &sc->server->protocol); } const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->proxy_enabled = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLProxyProtocol(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->proxy->protocol_set = 1; return ssl_cmd_protocol_parse(cmd, arg, &dc->proxy->protocol); } const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; if (arg2 == NULL) { arg2 = arg1; arg1 = "SSL"; } if (!strcmp("SSL", arg1)) { /* always disable null and export ciphers */ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); dc->proxy->auth.cipher_suite = arg2; return NULL; } #if SSL_HAVE_PROTOCOL_TLSV1_3 else if (!strcmp("TLSv1.3", arg1)) { dc->proxy->auth.tls13_ciphers = arg2; return NULL; } #endif return apr_pstrcat(cmd->pool, "protocol '", arg1, "' not supported", NULL); } const char *ssl_cmd_SSLProxyVerify(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; ssl_verify_t mode = SSL_CVERIFY_NONE; const char *err; if ((err = ssl_cmd_verify_parse(cmd, arg, &mode))) { return err; } dc->proxy->auth.verify_mode = mode; return NULL; } const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; int depth; const char *err; if ((err = ssl_cmd_verify_depth_parse(cmd, arg, &depth))) { return err; } dc->proxy->auth.verify_depth = depth; return NULL; } const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } dc->proxy->auth.ca_cert_file = arg; return NULL; } const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } dc->proxy->auth.ca_cert_path = arg; return NULL; } const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } dc->proxy->crl_path = arg; return NULL; } const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } dc->proxy->crl_file = arg; return NULL; } const char *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; return ssl_cmd_crlcheck_parse(cmd, arg, &dc->proxy->crl_check_mask); } const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } dc->proxy->pkp->cert_file = arg; return NULL; } const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } dc->proxy->pkp->cert_path = arg; return NULL; } const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } dc->proxy->pkp->ca_cert_file = arg; return NULL; } const char *ssl_cmd_SSLUserName(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->szUserName = arg; return NULL; } static const char *ssl_cmd_ocspcheck_parse(cmd_parms *parms, const char *arg, int *mask) { const char *w; w = ap_getword_conf(parms->temp_pool, &arg); if (strcEQ(w, "off")) { *mask = SSL_OCSPCHECK_NONE; } else if (strcEQ(w, "leaf")) { *mask = SSL_OCSPCHECK_LEAF; } else if (strcEQ(w, "on")) { *mask = SSL_OCSPCHECK_CHAIN; } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", w, "'", NULL); } while (*arg) { w = ap_getword_conf(parms->temp_pool, &arg); if (strcEQ(w, "no_ocsp_for_cert_ok")) { *mask |= SSL_OCSPCHECK_NO_OCSP_FOR_CERT_OK; } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", w, "'", NULL); } } return NULL; } const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); #ifdef OPENSSL_NO_OCSP if (flag) { return "OCSP support disabled in SSL library; cannot enable " "OCSP validation"; } #endif return ssl_cmd_ocspcheck_parse(cmd, arg, &sc->server->ocsp_mask); } const char *ssl_cmd_SSLOCSPOverrideResponder(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->ocsp_force_default = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLOCSPDefaultResponder(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->ocsp_responder = arg; return NULL; } const char *ssl_cmd_SSLOCSPResponseTimeSkew(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->ocsp_resptime_skew = atoi(arg); if (sc->server->ocsp_resptime_skew < 0) { return "SSLOCSPResponseTimeSkew: invalid argument"; } return NULL; } const char *ssl_cmd_SSLOCSPResponseMaxAge(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->ocsp_resp_maxage = atoi(arg); if (sc->server->ocsp_resp_maxage < 0) { return "SSLOCSPResponseMaxAge: invalid argument"; } return NULL; } const char *ssl_cmd_SSLOCSPResponderTimeout(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->ocsp_responder_timeout = apr_time_from_sec(atoi(arg)); if (sc->server->ocsp_responder_timeout < 0) { return "SSLOCSPResponderTimeout: invalid argument"; } return NULL; } const char *ssl_cmd_SSLOCSPUseRequestNonce(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->ocsp_use_request_nonce = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLOCSPProxyURL(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->proxy_uri = apr_palloc(cmd->pool, sizeof(apr_uri_t)); if (apr_uri_parse(cmd->pool, arg, sc->server->proxy_uri) != APR_SUCCESS) { return apr_psprintf(cmd->pool, "SSLOCSPProxyURL: Cannot parse URL %s", arg); } return NULL; } /* Set OCSP responder certificate verification directive */ const char *ssl_cmd_SSLOCSPNoVerify(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->ocsp_noverify = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->proxy->ssl_check_peer_expire = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->proxy->ssl_check_peer_cn = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLProxyCheckPeerName(cmd_parms *cmd, void *dcfg, int flag) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->proxy->ssl_check_peer_name = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag) { #ifdef HAVE_TLSEXT SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->strict_sni_vhost_check = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE; return NULL; #else return "SSLStrictSNIVHostCheck failed; OpenSSL is not built with support " "for TLS extensions and SNI indication. Refer to the " "documentation, and build a compatible version of OpenSSL."; #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; } if (!mc) { return "SSLStaplingCache: cannot be used inside SSLPolicyDefine"; } /* 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) Maybe you need to load the " "appropriate socache module (mod_socache_%s?)", name, all_names, name); } if (err) { return apr_psprintf(cmd->pool, "SSLStaplingCache: %s", err); } 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 "SSLStaplingResponseTimeSkew: 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 "SSLStaplingResponseMaxAge: 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 "SSLStaplingStandardCacheTimeout: 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 "SSLStaplingErrorCacheTimeout: 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 "SSLStaplingResponderTimeout: 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 */ #ifdef HAVE_SSL_CONF_CMD const char *ssl_cmd_SSLOpenSSLConfCmd(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); SSL_CONF_CTX *cctx = sc->server->ssl_ctx_config; int value_type = SSL_CONF_cmd_value_type(cctx, arg1); const char *err; ssl_ctx_param_t *param; if (value_type == SSL_CONF_TYPE_UNKNOWN) { return apr_psprintf(cmd->pool, "'%s': invalid OpenSSL configuration command", arg1); } if (value_type == SSL_CONF_TYPE_FILE) { if ((err = ssl_cmd_check_file(cmd, &arg2))) return err; } else if (value_type == SSL_CONF_TYPE_DIR) { if ((err = ssl_cmd_check_dir(cmd, &arg2))) return err; } if (strcEQ(arg1, "CipherString")) { /* always disable null and export ciphers */ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); } param = apr_array_push(sc->server->ssl_ctx_param); param->name = arg1; param->value = arg2; return NULL; } #endif #ifdef HAVE_SRP const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) return err; /* SRP_VBASE_init takes char*, not const char* */ sc->server->srp_vfile = apr_pstrdup(cmd->pool, arg); return NULL; } const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); /* SRP_VBASE_new takes char*, not const char* */ sc->server->srp_unknown_user_seed = apr_pstrdup(cmd->pool, arg); return NULL; } #endif /* HAVE_SRP */ /* OCSP Responder File Function to read in value */ const char *ssl_cmd_SSLOCSPResponderCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } sc->server->ocsp_certs_file = arg; return NULL; } static void ssl_srv_dump(SSLSrvConfigRec *sc, apr_pool_t *p, apr_file_t *out, const char *indent, const char **psep); static void ssl_policy_dump(SSLSrvConfigRec *policy, apr_pool_t *p, apr_file_t *out, const char *indent); void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) { apr_file_t *out = NULL; if (ap_exists_config_define("DUMP_CERTS") && ap_exists_config_define("DUMP_CA_CERTS")) { return; } if (ap_exists_config_define("DUMP_CERTS")) { apr_file_open_stdout(&out, pconf); apr_file_printf(out, "Server certificates:\n"); /* Dump the filenames of all configured server certificates to * stdout. */ while (s) { SSLSrvConfigRec *sc = mySrvConfig(s); if (sc && sc->server && sc->server->pks) { modssl_pk_server_t *const pks = sc->server->pks; int i; for (i = 0; (i < pks->cert_files->nelts) && APR_ARRAY_IDX(pks->cert_files, i, const char *); i++) { apr_file_printf(out, " %s\n", APR_ARRAY_IDX(pks->cert_files, i, const char *)); } } s = s->next; } return; } if (ap_exists_config_define("DUMP_CA_CERTS")) { apr_file_open_stdout(&out, pconf); apr_file_printf(out, "Server CA certificates:\n"); /* Dump the filenames of all configured server CA certificates to * stdout. */ while (s) { SSLSrvConfigRec *sc = mySrvConfig(s); if (sc && sc->server) { if (sc->server->auth.ca_cert_path) { apr_file_printf(out, " %s\n", sc->server->auth.ca_cert_path); } if (sc->server->auth.ca_cert_file) { apr_file_printf(out, " %s\n", sc->server->auth.ca_cert_file); } } s = s->next; } return; } if (ap_exists_config_define("DUMP_SSL_POLICIES")) { apr_array_header_t *names = get_policy_names(pconf); SSLSrvConfigRec *policy; const char *name, *sep = ""; int i; apr_file_open_stdout(&out, pconf); apr_file_printf(out, "SSLPolicies: {"); for (i = 0; i < names->nelts; ++i) { name = APR_ARRAY_IDX(names, i, const char*); policy = ssl_policy_lookup(pconf, name); if (policy) { apr_file_printf(out, "%s\n \"%s\": {", sep, name); sep = ", "; ssl_policy_dump(policy, pconf, out, " "); apr_file_printf(out, "\n }"); } } apr_file_printf(out, "\n}\n"); return; } } /* _________________________________________________________________ ** ** Dump Config Data ** _________________________________________________________________ */ static const char *json_quote(const char *s, apr_pool_t *p) { const char *src, *dq = s; int n = 0; while ((dq = ap_strchr_c(dq, '\"'))) { ++n; ++dq; } if (n > 0) { char *dst, c; src = s; s = dst = apr_pcalloc(p, strlen(s) + n + 1); while ((c = *src++)) { if (c == '\"') { *dst++ = '\\'; } *dst++ = c; } } return s; } static void val_str_dump(apr_file_t *out, const char *key, const char *val, apr_pool_t *p, const char *indent, const char **psep) { if (val) { /* TODO: JSON quote string val */ apr_file_printf(out, "%s\n%s\"%s\": \"%s\"", *psep, indent, key, json_quote(val, p)); *psep = ", "; } } static void val_str_array_dump(apr_file_t *out, const char *key, apr_array_header_t *val, apr_pool_t *p, const char *indent, const char **psep) { if (val && val->nelts > 0) { const char *s; int i; for (i = 0; i < val->nelts; ++i) { s = APR_ARRAY_IDX(val, i, const char*); val_str_dump(out, key, s, p, indent, psep); } } } static void val_long_dump(apr_file_t *out, const char *key, long val, apr_pool_t *p, const char *indent, const char **psep) { if (val != UNSET) { apr_file_printf(out, "%s\n%s\"%s\": %ld", *psep, indent, key, val); *psep = ", "; } } static void val_itime_dump(apr_file_t *out, const char *key, apr_interval_time_t val, apr_pool_t *p, const char *indent, const char **psep) { if (val != UNSET) { apr_file_printf(out, "%s\n%s\"%s\": %f", *psep, indent, key, ((double)val/APR_USEC_PER_SEC)); *psep = ", "; } } static void val_onoff_dump(apr_file_t *out, const char *key, BOOL val, apr_pool_t *p, const char *indent, const char **psep) { if (val != UNSET) { val_str_dump(out, key, val? "on" : "off", p, indent, psep); } } static void val_uri_dump(apr_file_t *out, const char *key, apr_uri_t *val, apr_pool_t *p, const char *indent, const char **psep) { if (val) { val_str_dump(out, key, apr_uri_unparse(p, val, 0), p, indent, psep); } } static void val_verify_dump(apr_file_t *out, const char *key, ssl_verify_t mode, apr_pool_t *p, const char *indent, const char **psep) { switch (mode) { case SSL_CVERIFY_NONE: val_str_dump(out, key, "none", p, indent, psep); return; case SSL_CVERIFY_OPTIONAL: val_str_dump(out, key, "optional", p, indent, psep); return; case SSL_CVERIFY_REQUIRE: val_str_dump(out, key, "require", p, indent, psep); return; case SSL_CVERIFY_OPTIONAL_NO_CA: val_str_dump(out, key, "optional_no_ca", p, indent, psep); return; default: return; } } static void val_enabled_dump(apr_file_t *out, const char *key, ssl_enabled_t val, apr_pool_t *p, const char *indent, const char **psep) { switch (val) { case SSL_ENABLED_FALSE: val_str_dump(out, key, "off", p, indent, psep); return; case SSL_ENABLED_TRUE: val_str_dump(out, key, "on", p, indent, psep); return; case SSL_ENABLED_OPTIONAL: val_str_dump(out, key, "optional", p, indent, psep); return; default: return; } } static void val_pphrase_dump(apr_file_t *out, const char *key, ssl_pphrase_t pphrase_type, const char *path, apr_pool_t *p, const char *indent, const char **psep) { switch (pphrase_type) { case SSL_PPTYPE_BUILTIN: val_str_dump(out, key, "builtin", p, indent, psep); return; case SSL_PPTYPE_FILTER: val_str_dump(out, key, apr_pstrcat(p, "|", path, NULL), p, indent, psep); return; case SSL_PPTYPE_PIPE: val_str_dump(out, key, apr_pstrcat(p, "exec:", path, NULL), p, indent, psep); return; default: return; } } static void val_crl_check_dump(apr_file_t *out, const char *key, int mask, apr_pool_t *p, const char *indent, const char **psep) { if (mask != UNSET) { if (mask == SSL_CRLCHECK_NONE) { val_str_dump(out, key, "none", p, indent, psep); } else if (mask == SSL_CRLCHECK_LEAF) { val_str_dump(out, key, "leaf", p, indent, psep); } else if (mask == SSL_CRLCHECK_CHAIN) { val_str_dump(out, key, "chain", p, indent, psep); } else if (mask == (SSL_CRLCHECK_CHAIN|SSL_CRLCHECK_NO_CRL_FOR_CERT_OK)) { val_str_dump(out, key, "chain no_crl_for_cert_ok", p, indent, psep); } else { val_str_dump(out, key, "???", p, indent, psep); } } } static const char *protocol_str(ssl_proto_t proto, apr_pool_t *p) { if (SSL_PROTOCOL_NONE == proto) { return "none"; } else if (SSL_PROTOCOL_ALL == proto) { return "all"; } else { /* icing: I think it is nuts that we define our own IETF protocol constants * only when the linked *SSL lib supports them. */ apr_array_header_t *names = apr_array_make(p, 5, sizeof(const char*)); if ((1<<4) & proto) { APR_ARRAY_PUSH(names, const char*) = "+TLSv1.2"; } if ((1<<3) & proto) { APR_ARRAY_PUSH(names, const char*) = "+TLSv1.1"; } if ((1<<2) & proto) { APR_ARRAY_PUSH(names, const char*) = "+TLSv1.0"; } if ((1<<1) & proto) { APR_ARRAY_PUSH(names, const char*) = "+SSLv3"; } return apr_array_pstrcat(p, names, ' '); } } #define DMP_STRING(k,v) \ val_str_dump(out, k, v, p, indent, psep) #define DMP_LONG(k,v) \ val_long_dump(out, k, v, p, indent, psep) #define DMP_ITIME(k,v) \ val_itime_dump(out, k, v, p, indent, psep) #define DMP_STRARR(k,v) \ val_str_array_dump(out, k, v, p, indent, psep) #define DMP_VERIFY(k,v) \ val_verify_dump(out, k, v, p, indent, psep) #define DMP_ON_OFF(k,v) \ val_onoff_dump(out, k, v, p, indent, psep) #define DMP_URI(k,v) \ val_uri_dump(out, k, v, p, indent, psep) #define DMP_CRLCHK(k,v) \ val_crl_check_dump(out, k, v, p, indent, psep) #define DMP_PHRASE(k,v, v2) \ val_pphrase_dump(out, k, v, v2, p, indent, psep) #define DMP_ENABLD(k,v) \ val_enabled_dump(out, k, v, p, indent, psep) #define DMP_OPTION(n,v) \ val_option_dump(out, "SSLOption", n, v, \ dc->nOptions, dc->nOptionsAdd, dc->nOptionsDel, p, indent, psep); static void modssl_auth_ctx_dump(modssl_auth_ctx_t *auth, apr_pool_t *p, int proxy, apr_file_t *out, const char *indent, const char **psep) { DMP_STRING(proxy? "SSLProxyCipherSuite" : "SSLCipherSuite", auth->cipher_suite); #if SSL_HAVE_PROTOCOL_TLSV1_3 if (auth->tls13_ciphers) { DMP_STRING(proxy? "SSLProxyCipherSuite" : "SSLCipherSuite", apr_pstrcat(p, "TLSv1.3 ", auth->tls13_ciphers, NULL)); } #endif DMP_VERIFY(proxy? "SSLProxyVerify" : "SSLVerifyClient", auth->verify_mode); DMP_LONG( proxy? "SSLProxyVerify" : "SSLVerifyDepth", auth->verify_depth); DMP_STRING(proxy? "SSLProxyCACertificateFile" : "SSLCACertificateFile", auth->ca_cert_file); DMP_STRING(proxy? "SSLProxyCACertificatePath" : "SSLCACertificatePath", auth->ca_cert_path); } static void modssl_ctx_dump(modssl_ctx_t *ctx, apr_pool_t *p, int proxy, apr_file_t *out, const char *indent, const char **psep) { #ifdef HAVE_SSL_CONF_CMD int i; #endif if (ctx->protocol_set) { DMP_STRING(proxy? "SSLProxyProtocol" : "SSLProtocol", protocol_str(ctx->protocol, p)); } modssl_auth_ctx_dump(&ctx->auth, p, proxy, out, indent, psep); DMP_STRING(proxy? "SSLProxyCARevocationFile" : "SSLCARevocationFile", ctx->crl_file); DMP_STRING(proxy? "SSLProxyCARevocationPath" : "SSLCARevocationPath", ctx->crl_path); DMP_CRLCHK(proxy? "SSLProxyCARevocationCheck" : "SSLCARevocationCheck", ctx->crl_check_mask); if (!proxy) { DMP_PHRASE("SSLPassPhraseDialog", ctx->pphrase_dialog_type, ctx->pphrase_dialog_path); if (ctx->pks) { DMP_STRING("SSLCADNRequestFile", ctx->pks->ca_name_file); DMP_STRING("SSLCADNRequestPath", ctx->pks->ca_name_path); DMP_STRARR("SSLCertificateFile", ctx->pks->cert_files); DMP_STRARR("SSLCertificateKeyFile", ctx->pks->key_files); } #ifdef HAVE_OCSP_STAPLING DMP_ON_OFF("SSLUseStapling", ctx->stapling_enabled); DMP_LONG( "SSLStaplingResponseTimeSkew", ctx->stapling_resptime_skew); DMP_LONG( "SSLStaplingResponseMaxAge", ctx->stapling_resp_maxage); DMP_LONG( "SSLStaplingStandardCacheTimeout", ctx->stapling_cache_timeout); DMP_ON_OFF("SSLStaplingReturnResponderErrors", ctx->stapling_return_errors); DMP_ON_OFF("SSLStaplingFakeTryLater", ctx->stapling_fake_trylater); DMP_LONG( "SSLStaplingErrorCacheTimeout", ctx->stapling_errcache_timeout); DMP_ITIME( "SSLStaplingResponderTimeout", ctx->stapling_responder_timeout); DMP_STRING("SSLStaplingForceURL", ctx->stapling_force_url); #endif /* if HAVE_OCSP_STAPLING */ #ifdef HAVE_SRP DMP_STRING("SSLSRPUnknownUserSeed", ctx->srp_unknown_user_seed); DMP_STRING("SSLSRPVerifierFile", ctx->srp_vfile); #endif DMP_LONG( "SSLOCSPEnable", ctx->ocsp_mask); DMP_ON_OFF("SSLOCSPOverrideResponder", ctx->ocsp_force_default); DMP_STRING("SSLOCSPDefaultResponder", ctx->ocsp_responder); DMP_LONG( "SSLOCSPResponseTimeSkew", ctx->ocsp_resptime_skew); DMP_LONG( "SSLOCSPResponseMaxAge", ctx->ocsp_resp_maxage); DMP_ITIME( "SSLOCSPResponderTimeout", ctx->ocsp_responder_timeout); DMP_ON_OFF("SSLOCSPUseRequestNonce", ctx->ocsp_use_request_nonce); DMP_URI( "SSLOCSPProxyURL", ctx->proxy_uri); DMP_ON_OFF("SSLOCSPNoVerify", ctx->ocsp_noverify); DMP_STRING("SSLOCSPResponderCertificateFile", ctx->ocsp_certs_file); #ifdef HAVE_SSL_CONF_CMD if (ctx->ssl_ctx_param && ctx->ssl_ctx_param->nelts > 0) { ssl_ctx_param_t *param = (ssl_ctx_param_t *)ctx->ssl_ctx_param->elts; for (i = 0; i < ctx->ssl_ctx_param->nelts; ++i, ++param) { apr_file_printf(out, "%s\n%s\"%s\": \"%s %s\"", *psep, indent, "SSLOpenSSLConfCmd", json_quote(param->name, p), json_quote(param->value, p)); *psep = ", "; } } #endif #ifdef HAVE_TLS_SESSION_TICKETS if (ctx->ticket_key) { DMP_STRING("SSLSessionTicketKeyFile", ctx->ticket_key->file_path); } #endif } else { /* proxy */ if (ctx->pkp) { DMP_STRING("SSLProxyMachineCertificateFile", ctx->pkp->cert_file); DMP_STRING("SSLProxyMachineCertificatePath", ctx->pkp->cert_path); DMP_STRING("SSLProxyMachineCertificateChainFile", ctx->pkp->ca_cert_file); } DMP_ON_OFF("SSLProxyCheckPeerCN", ctx->ssl_check_peer_cn); DMP_ON_OFF("SSLProxyCheckPeerName", ctx->ssl_check_peer_cn); DMP_ON_OFF("SSLProxyCheckPeerExpire", ctx->ssl_check_peer_expire); } } static void ssl_srv_dump(SSLSrvConfigRec *sc, apr_pool_t *p, apr_file_t *out, const char *indent, const char **psep) { DMP_ENABLD("SSLEngine", sc->enabled); DMP_ON_OFF("SSLHonorCipherOrder", sc->cipher_server_pref); #ifndef OPENSSL_NO_COMP DMP_ON_OFF("SSLCompression", sc->compression); #endif modssl_ctx_dump(sc->server, p, 0, out, indent, psep); DMP_LONG( "SSLSessionCacheTimeout", sc->session_cache_timeout); DMP_ON_OFF("SSLStrictSNIVHostCheck", sc->strict_sni_vhost_check); DMP_ON_OFF("SSLSessionTickets", sc->session_tickets); } static void ssl_policy_dump(SSLSrvConfigRec *policy, apr_pool_t *p, apr_file_t *out, const char *indent) { const char *sep = ""; ssl_srv_dump(policy, p, out, indent, &sep); }