/* 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 "mod_ssl.h" /* _________________________________________________________________ ** ** Support for Global Configuration ** _________________________________________________________________ */ #define SSL_MOD_CONFIG_KEY "ssl_module" SSLModConfigRec *ssl_config_global_create(server_rec *s) { apr_pool_t *pool = s->process->pool; SSLModConfigRec *mc; void *vmc; apr_pool_userdata_get(&vmc, SSL_MOD_CONFIG_KEY, pool); if (vmc) { return vmc; /* reused for lifetime of the server */ } /* * allocate an own subpool which survives server restarts */ mc = (SSLModConfigRec *)apr_palloc(pool, sizeof(*mc)); mc->pPool = pool; mc->bFixed = FALSE; /* * initialize per-module configuration */ mc->nSessionCacheMode = SSL_SCMODE_UNSET; mc->szSessionCacheDataFile = NULL; mc->nSessionCacheDataSize = 0; mc->pSessionCacheDataMM = NULL; mc->pSessionCacheDataRMM = NULL; mc->tSessionCacheDataTable = NULL; mc->nMutexMode = SSL_MUTEXMODE_UNSET; mc->nMutexMech = APR_LOCK_DEFAULT; mc->szMutexFile = NULL; mc->pMutex = NULL; mc->aRandSeed = apr_array_make(pool, 4, sizeof(ssl_randseed_t)); mc->tVHostKeys = apr_hash_make(pool); mc->tPrivateKey = apr_hash_make(pool); mc->tPublicCert = apr_hash_make(pool); #ifdef SSL_EXPERIMENTAL_ENGINE mc->szCryptoDevice = NULL; #endif memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys)); apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY, apr_pool_cleanup_null, 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 ** _________________________________________________________________ */ static void modssl_ctx_init(modssl_ctx_t *mctx) { mctx->sc = NULL; /* set during module init */ mctx->ssl_ctx = NULL; /* set during module init */ mctx->pks = NULL; mctx->pkp = NULL; mctx->protocol = SSL_PROTOCOL_ALL; 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 = NULL; /* set during module init */ 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; } static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, apr_pool_t *p) { modssl_ctx_t *mctx; mctx = sc->proxy = apr_palloc(p, sizeof(*sc->proxy)); modssl_ctx_init(mctx); mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp)); mctx->pkp->cert_file = NULL; mctx->pkp->cert_path = NULL; mctx->pkp->certs = NULL; } 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); mctx->pks = apr_palloc(p, sizeof(*mctx->pks)); memset((void*)mctx->pks->cert_files, 0, sizeof(mctx->pks->cert_files)); memset((void*)mctx->pks->key_files, 0, sizeof(mctx->pks->key_files)); /* certs/keys are set during module init */ memset(mctx->pks->certs, 0, sizeof(mctx->pks->certs)); memset(mctx->pks->keys, 0, sizeof(mctx->pks->keys)); } static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) { SSLSrvConfigRec *sc = apr_palloc(p, sizeof(*sc)); sc->mc = NULL; sc->enabled = UNSET; sc->proxy_enabled = UNSET; sc->vhost_id = NULL; /* set during module init */ sc->vhost_id_len = 0; /* set during module init */ sc->session_cache_timeout = UNSET; sc->insecure_reneg = UNSET; modssl_ctx_init_proxy(sc, p); 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(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, add->el, base->el) #define cfgMergeString(el) cfgMerge(el, NULL) #define cfgMergeBool(el) cfgMerge(el, UNSET) #define cfgMergeInt(el) cfgMerge(el, UNSET) static void modssl_ctx_cfg_merge(modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { cfgMerge(protocol, SSL_PROTOCOL_ALL); cfgMerge(pphrase_dialog_type, SSL_PPTYPE_UNSET); cfgMergeString(pphrase_dialog_path); cfgMergeString(cert_chain); cfgMerge(crl_path, NULL); cfgMerge(crl_file, NULL); 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); } static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { modssl_ctx_cfg_merge(base, add, mrg); cfgMergeString(pkp->cert_file); cfgMergeString(pkp->cert_path); } static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { int i; modssl_ctx_cfg_merge(base, add, mrg); for (i = 0; i < SSL_AIDX_MAX; i++) { cfgMergeString(pks->cert_files[i]); cfgMergeString(pks->key_files[i]); } } /* * Merge per-server SSL configurations */ 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); cfgMergeBool(enabled); cfgMergeBool(proxy_enabled); cfgMergeInt(session_cache_timeout); cfgMergeBool(insecure_reneg); modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy); modssl_ctx_cfg_merge_server(base->server, add->server, mrg->server); return mrg; } /* * Create per-directory SSL configuration */ 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->szCACertificatePath = NULL; dc->szCACertificateFile = NULL; dc->szUserName = NULL; return dc; } /* * Merge per-directory SSL configurations */ 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(szCACertificatePath); cfgMergeString(szCACertificateFile); cfgMergeString(szUserName); return mrg; } /* * Configuration functions for particular directives */ const char *ssl_cmd_SSLMutex(cmd_parms *cmd, void *dcfg, const char *arg) { const char *err; SSLModConfigRec *mc = myModConfig(cmd->server); if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (ssl_config_global_isfixed(mc)) { return NULL; } if (strcEQ(arg, "none") || strcEQ(arg, "no")) { mc->nMutexMode = SSL_MUTEXMODE_NONE; } /* NOTE: previously, 'yes' implied 'sem' */ else if (strcEQ(arg, "default") || strcEQ(arg, "yes")) { mc->nMutexMode = SSL_MUTEXMODE_USED; mc->nMutexMech = APR_LOCK_DEFAULT; mc->szMutexFile = NULL; /* APR determines temporary filename */ } #if APR_HAS_FLOCK_SERIALIZE else if (strlen(arg) > 6 && strcEQn(arg, "flock:", 6)) { const char *file = ap_server_root_relative(cmd->pool, arg+6); if (!file) { return apr_pstrcat(cmd->pool, "Invalid SSLMutex flock: path ", arg+6, NULL); } mc->nMutexMode = SSL_MUTEXMODE_USED; mc->nMutexMech = APR_LOCK_FLOCK; mc->szMutexFile = apr_psprintf(mc->pPool, "%s.%lu", file, (unsigned long)getpid()); } #endif #if APR_HAS_FCNTL_SERIALIZE else if (strlen(arg) > 6 && strcEQn(arg, "fcntl:", 6)) { const char *file = ap_server_root_relative(cmd->pool, arg+6); if (!file) { return apr_pstrcat(cmd->pool, "Invalid SSLMutex fcntl: path ", arg+6, NULL); } mc->nMutexMode = SSL_MUTEXMODE_USED; mc->nMutexMech = APR_LOCK_FCNTL; mc->szMutexFile = apr_psprintf(mc->pPool, "%s.%lu", file, (unsigned long)getpid()); } #endif #if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM) else if (strcEQ(arg, "sysvsem")) { mc->nMutexMode = SSL_MUTEXMODE_USED; mc->nMutexMech = APR_LOCK_SYSVSEM; mc->szMutexFile = NULL; /* APR determines temporary filename */ } #endif #if APR_HAS_POSIXSEM_SERIALIZE else if (strcEQ(arg, "posixsem")) { mc->nMutexMode = SSL_MUTEXMODE_USED; mc->nMutexMech = APR_LOCK_POSIXSEM; mc->szMutexFile = NULL; /* APR determines temporary filename */ } #endif #if APR_HAS_PROC_PTHREAD_SERIALIZE else if (strcEQ(arg, "pthread")) { mc->nMutexMode = SSL_MUTEXMODE_USED; mc->nMutexMech = APR_LOCK_PROC_PTHREAD; mc->szMutexFile = NULL; /* APR determines temporary filename */ } #endif #if APR_HAS_FLOCK_SERIALIZE || APR_HAS_FCNTL_SERIALIZE else if (strlen(arg) > 5 && strcEQn(arg, "file:", 5)) { const char *file = ap_server_root_relative(cmd->pool, arg+5); if (!file) { return apr_pstrcat(cmd->pool, "Invalid SSLMutex file: path ", arg+5, NULL); } mc->nMutexMode = SSL_MUTEXMODE_USED; #if APR_HAS_FLOCK_SERIALIZE mc->nMutexMech = APR_LOCK_FLOCK; #endif #if APR_HAS_FCNTL_SERIALIZE mc->nMutexMech = APR_LOCK_FCNTL; #endif mc->szMutexFile = apr_psprintf(mc->pPool, "%s.%lu", file, (unsigned long)getpid()); } #endif #if (APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM)) || APR_HAS_POSIXSEM_SERIALIZE else if (strcEQ(arg, "sem")) { mc->nMutexMode = SSL_MUTEXMODE_USED; #if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM) mc->nMutexMech = APR_LOCK_SYSVSEM; #endif #if APR_HAS_POSIXSEM_SERIALIZE mc->nMutexMech = APR_LOCK_POSIXSEM; #endif mc->szMutexFile = NULL; /* APR determines temporary filename */ } #endif else { return apr_pstrcat(cmd->pool, "Invalid SSLMutex argument ", arg, " (", ssl_valid_ssl_mutex_string, ")", NULL); } return NULL; } 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; /* ### This is broken, exec: may contain args, no? */ 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; } #ifdef SSL_EXPERIMENTAL_ENGINE const char *ssl_cmd_SSLCryptoDevice(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); const char *err; ENGINE *e; #if SSL_LIBRARY_VERSION >= 0x00907000 static int loaded_engines = FALSE; /* early loading to make sure the engines are already available for ENGINE_by_id() above... */ if (!loaded_engines) { ENGINE_load_builtin_engines(); loaded_engines = TRUE; } #endif if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (strcEQ(arg, "builtin")) { mc->szCryptoDevice = NULL; } else if ((e = ENGINE_by_id(arg))) { mc->szCryptoDevice = arg; ENGINE_free(e); } else { return "SSLCryptoDevice: Invalid argument"; } return NULL; } #endif const char *ssl_cmd_SSLRandomSeed(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2, const char *arg3) { SSLModConfigRec *mc = myModConfig(cmd->server); const char *err; ssl_randseed_t *seed; int arg2len = strlen(arg2); if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } 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(mc->pPool, arg2+5); } else if ((arg2len > 5) && strEQn(arg2, "exec:", 5)) { seed->nSrc = SSL_RSSRC_EXEC; seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5); } else if ((arg2len > 4) && strEQn(arg2, "egd:", 4)) { #ifdef HAVE_SSL_RAND_EGD seed->nSrc = SSL_RSSRC_EGD; seed->cpPath = ap_server_root_relative(mc->pPool, arg2+4); #else return "egd not supported with this SSL toolkit"; #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(mc->pPool, 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"; } } return NULL; } const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->enabled = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; if (cmd->path) { dc->szCipherSuite = arg; } else { sc->server->auth.cipher_suite = arg; } return 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 = 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_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag) { #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->insecure_reneg = flag?TRUE:FALSE; return NULL; #else return "The SSLInsecureRenegotiation directive is not available " "with this SSL library"; #endif } 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); } #define SSL_AIDX_CERTS 1 #define SSL_AIDX_KEYS 2 static const char *ssl_cmd_check_aidx_max(cmd_parms *parms, const char *arg, int idx) { SSLSrvConfigRec *sc = mySrvConfig(parms->server); const char *err, *desc=NULL, **files=NULL; int i; if ((err = ssl_cmd_check_file(parms, &arg))) { return err; } switch (idx) { case SSL_AIDX_CERTS: desc = "certificates"; files = sc->server->pks->cert_files; break; case SSL_AIDX_KEYS: desc = "private keys"; files = sc->server->pks->key_files; break; } for (i = 0; i < SSL_AIDX_MAX; i++) { if (!files[i]) { files[i] = arg; return NULL; } } return apr_psprintf(parms->pool, "%s: only up to %d " "different %s per virtual host allowed", parms->cmd->name, SSL_AIDX_MAX, desc); } const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { const char *err; if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_CERTS))) { return err; } return NULL; } const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *cmd, void *dcfg, const char *arg) { const char *err; if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_KEYS))) { return err; } 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; } #define NO_PER_DIR_SSL_CA \ "Your ssl library does not have support for per-directory CA" #ifdef HAVE_SSL_SET_CERT_STORE # define MODSSL_HAVE_SSL_SET_CERT_STORE 1 #else # define MODSSL_HAVE_SSL_SET_CERT_STORE 0 #endif #define MODSSL_SET_CA(f) \ if (cmd->path) \ if (MODSSL_HAVE_SSL_SET_CERT_STORE) \ dc->f = arg; \ else \ return NO_PER_DIR_SSL_CA; \ else \ sc->f = arg \ 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; } /* 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; } /* XXX: bring back per-dir */ sc->server->auth.ca_cert_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_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; 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; } #define MODSSL_NO_SHARED_MEMORY_ERROR \ "SSLSessionCache: shared memory cache not useable on this platform" const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); const char *err, *colon; char *cp, *cp2; int arglen = strlen(arg); if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (ssl_config_global_isfixed(mc)) { return NULL; } if (strcEQ(arg, "none")) { mc->nSessionCacheMode = SSL_SCMODE_NONE; mc->szSessionCacheDataFile = NULL; } else if ((arglen > 4) && strcEQn(arg, "dbm:", 4)) { mc->nSessionCacheMode = SSL_SCMODE_DBM; mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, arg+4); if (!mc->szSessionCacheDataFile) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid cache file path %s", arg+4); } } else if ((arglen > 6) && strcEQn(arg, "shmht:", 6)) { #if !APR_HAS_SHARED_MEMORY return MODSSL_NO_SHARED_MEMORY_ERROR; #endif mc->nSessionCacheMode = SSL_SCMODE_SHMHT; colon = ap_strchr_c(arg, ':'); mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, colon+1); if (!mc->szSessionCacheDataFile) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid cache file path %s", colon+1); } mc->tSessionCacheDataTable = NULL; mc->nSessionCacheDataSize = 1024*512; /* 512KB */ if ((cp = strchr(mc->szSessionCacheDataFile, '('))) { *cp++ = NUL; if (!(cp2 = strchr(cp, ')'))) { return "SSLSessionCache: Invalid argument: " "no closing parenthesis"; } *cp2 = NUL; mc->nSessionCacheDataSize = atoi(cp); if (mc->nSessionCacheDataSize < 8192) { return "SSLSessionCache: Invalid argument: " "size has to be >= 8192 bytes"; } if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid argument: " "size has to be < %d bytes on this " "platform", APR_SHM_MAXSIZE); } } } else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) || ((arglen > 6) && strcEQn(arg, "shmcb:", 6))) { #if !APR_HAS_SHARED_MEMORY return MODSSL_NO_SHARED_MEMORY_ERROR; #endif mc->nSessionCacheMode = SSL_SCMODE_SHMCB; colon = ap_strchr_c(arg, ':'); mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, colon+1); if (!mc->szSessionCacheDataFile) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid cache file path %s", colon+1); } mc->tSessionCacheDataTable = NULL; mc->nSessionCacheDataSize = 1024*512; /* 512KB */ if ((cp = strchr(mc->szSessionCacheDataFile, '('))) { *cp++ = NUL; if (!(cp2 = strchr(cp, ')'))) { return "SSLSessionCache: Invalid argument: " "no closing parenthesis"; } *cp2 = NUL; mc->nSessionCacheDataSize = atoi(cp); if (mc->nSessionCacheDataSize < 8192) { return "SSLSessionCache: Invalid argument: " "size has to be >= 8192 bytes"; } if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid argument: " "size has to be < %d bytes on this " "platform", APR_SHM_MAXSIZE); } } } else { return "SSLSessionCache: Invalid argument"; } 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->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, "CompatEnvVars")) { opt = SSL_OPT_COMPATENVVARS; } else if (strcEQ(w, "ExportCertData")) { opt = SSL_OPT_EXPORTCERTDATA; } 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 { 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; ssl_expr *expr; ssl_require_t *require; if (!(expr = ssl_expr_comp(cmd->pool, (char *)arg))) { return apr_pstrcat(cmd->pool, "SSLRequire: ", ssl_expr_get_error(), NULL); } require = apr_array_push(dc->aRequirement); require->cpExpr = apr_pstrdup(cmd->pool, arg); require->mpExpr = expr; 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")) { thisopt = SSL_PROTOCOL_SSLV2; } else if (strcEQ(w, "SSLv3")) { thisopt = SSL_PROTOCOL_SSLV3; } else if (strcEQ(w, "TLSv1")) { thisopt = SSL_PROTOCOL_TLSV1; } else if (strcEQ(w, "all")) { thisopt = SSL_PROTOCOL_ALL; } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Illegal protocol '", w, "'", NULL); } if (action == '-') { *options &= ~thisopt; } else if (action == '+') { *options |= thisopt; } else { *options = thisopt; } } return NULL; } const char *ssl_cmd_SSLProtocol(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); return ssl_cmd_protocol_parse(cmd, arg, &sc->server->protocol); } const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->proxy_enabled = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLProxyProtocol(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); return ssl_cmd_protocol_parse(cmd, arg, &sc->proxy->protocol); } const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->proxy->auth.cipher_suite = arg; return NULL; } const char *ssl_cmd_SSLProxyVerify(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ssl_verify_t mode; const char *err; if ((err = ssl_cmd_verify_parse(cmd, arg, &mode))) { return err; } sc->proxy->auth.verify_mode = mode; return NULL; } const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); int depth; const char *err; if ((err = ssl_cmd_verify_depth_parse(cmd, arg, &depth))) { return err; } sc->proxy->auth.verify_depth = depth; return NULL; } const char *ssl_cmd_SSLProxyCACertificateFile(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->proxy->auth.ca_cert_file = arg; return NULL; } const char *ssl_cmd_SSLProxyCACertificatePath(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->proxy->auth.ca_cert_path = arg; return NULL; } const char *ssl_cmd_SSLProxyCARevocationPath(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->proxy->crl_path = arg; return NULL; } const char *ssl_cmd_SSLProxyCARevocationFile(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->proxy->crl_file = arg; return NULL; } const char *ssl_cmd_SSLProxyMachineCertificateFile(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->proxy->pkp->cert_file = arg; return NULL; } const char *ssl_cmd_SSLProxyMachineCertificatePath(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->proxy->pkp->cert_path = 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; }