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