Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Apache/modules/ssl/   (Apache Software Stiftung Version 2.4.65©)  Datei vom 7.6.2025 mit Größe 62 kB image not shown  

Quelle  ssl_engine_config.c   Sprache: C

 
/* 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 "ssl_private.h"

#include "util_mutex.h"
#include "ap_provider.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->sesscache_mode         = SSL_SESS_CACHE_OFF;
    mc->sesscache              = 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);
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
    mc->szCryptoDevice         = NULL;
#endif
#ifdef HAVE_OCSP_STAPLING
    mc->stapling_cache         = NULL;
    mc->stapling_cache_mutex   = NULL;
    mc->stapling_refresh_mutex = NULL;
#endif

#ifdef HAVE_OPENSSL_KEYLOG
    mc->keylog_file = NULL;
#endif
#ifdef HAVE_FIPS
    mc->fips = UNSET;
#endif

    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
**  _________________________________________________________________
*/


#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->vhost_id_len           = 0;     /* set during module init */
    sc->session_cache_timeout  = UNSET;
    sc->cipher_server_pref     = UNSET;
    sc->insecure_reneg         = UNSET;
#ifdef HAVE_TLSEXT
    sc->strict_sni_vhost_check = SSL_ENABLED_UNSET;
#endif
#ifndef OPENSSL_NO_COMP
    sc->compression            = UNSET;
#endif
    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(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_certkeys_array(apr_pool_t *p,
                                                apr_array_header_t *base,
                                                apr_array_header_t *add,
                                                apr_array_header_t *mrg)
{
    int i;

    /*
     * pick up to CERTKEYS_IDX_MAX+1 entries from "add" (in which case they
     * they "knock out" their corresponding entries in "base", emulating
     * the behavior with cfgMergeString in releases up to 2.4.7)
     */

    for (i = 0; i < add->nelts && i <= CERTKEYS_IDX_MAX; i++) {
        APR_ARRAY_PUSH(mrg, const char *) = APR_ARRAY_IDX(add, i, const char *);
    }

    /* add remaining ones from "base" */
    while (i < base->nelts) {
        APR_ARRAY_PUSH(mrg, const char *) = APR_ARRAY_IDX(base, i, const char *);
        i++;
    }

    /* and finally, append the rest of "add" (if there are any) */
    for (i = CERTKEYS_IDX_MAX+1; i < add->nelts; i++) {
        APR_ARRAY_PUSH(mrg, const char *) = APR_ARRAY_IDX(add, i, const char *);
    }
}

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);

    /*
     * For better backwards compatibility with releases up to 2.4.7,
     * merging global and vhost-level SSLCertificateFile and
     * SSLCertificateKeyFile directives needs special treatment.
     * See also PR 56306 and 56353.
     */

    modssl_ctx_cfg_merge_certkeys_array(p, base->pks->cert_files,
                                        add->pks->cert_files,
                                        mrg->pks->cert_files);
    modssl_ctx_cfg_merge_certkeys_array(p, base->pks->key_files,
                                        add->pks->key_files,
                                        mrg->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(insecure_reneg);
#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 <Proxy> 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);
}

/*
 *  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 (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)
{
    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_RAND_EGD
        seed->nSrc   = SSL_RSSRC_EGD;
        seed->cpPath = ap_server_root_relative(mc->pPool, 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(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, 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_FALSE;
        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server, APLOGNO(10510)
                     "'SSLEngine optional' is no longer supported");
        return NULL;
    }

    return "Argument must be On or Off";
}

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_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)
{
#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);

}

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;
    }

    /* 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, "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;
    }

    /* 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;
}

void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
{
    apr_file_t *out = NULL;
    if (!ap_exists_config_define("DUMP_CERTS")) {
        return;
    }
    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;
    }

}

98%


¤ Dauer der Verarbeitung: 0.42 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.