1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*                      _             _
18 *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
19 * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
20 * | | | | | | (_) | (_| |   \__ \__ \ |
21 * |_| |_| |_|\___/ \__,_|___|___/___/_|
22 *                      |_____|
23 *  ssl_engine_config.c
24 *  Apache Configuration Directives
25 */
26                                      /* ``Damned if you do,
27                                           damned if you don't.''
28                                               -- Unknown        */
29#include "ssl_private.h"
30
31/*  _________________________________________________________________
32**
33**  Support for Global Configuration
34**  _________________________________________________________________
35*/
36
37#define SSL_MOD_CONFIG_KEY "ssl_module"
38
39SSLModConfigRec *ssl_config_global_create(server_rec *s)
40{
41    apr_pool_t *pool = s->process->pool;
42    SSLModConfigRec *mc;
43    void *vmc;
44
45    apr_pool_userdata_get(&vmc, SSL_MOD_CONFIG_KEY, pool);
46    if (vmc) {
47        return vmc; /* reused for lifetime of the server */
48    }
49
50    /*
51     * allocate an own subpool which survives server restarts
52     */
53    mc = (SSLModConfigRec *)apr_palloc(pool, sizeof(*mc));
54    mc->pPool = pool;
55    mc->bFixed = FALSE;
56
57    /*
58     * initialize per-module configuration
59     */
60    mc->nSessionCacheMode      = SSL_SCMODE_UNSET;
61    mc->szSessionCacheDataFile = NULL;
62    mc->nSessionCacheDataSize  = 0;
63    mc->pSessionCacheDataMM    = NULL;
64    mc->pSessionCacheDataRMM   = NULL;
65    mc->tSessionCacheDataTable = NULL;
66    mc->nMutexMode             = SSL_MUTEXMODE_UNSET;
67    mc->nMutexMech             = APR_LOCK_DEFAULT;
68    mc->szMutexFile            = NULL;
69    mc->pMutex                 = NULL;
70    mc->aRandSeed              = apr_array_make(pool, 4,
71                                                sizeof(ssl_randseed_t));
72    mc->tVHostKeys             = apr_hash_make(pool);
73    mc->tPrivateKey            = apr_hash_make(pool);
74    mc->tPublicCert            = apr_hash_make(pool);
75#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
76    mc->szCryptoDevice         = NULL;
77#endif
78
79    memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys));
80
81    apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY,
82                          apr_pool_cleanup_null,
83                          pool);
84
85    return mc;
86}
87
88void ssl_config_global_fix(SSLModConfigRec *mc)
89{
90    mc->bFixed = TRUE;
91}
92
93BOOL ssl_config_global_isfixed(SSLModConfigRec *mc)
94{
95    return mc->bFixed;
96}
97
98/*  _________________________________________________________________
99**
100**  Configuration handling
101**  _________________________________________________________________
102*/
103
104static void modssl_ctx_init(modssl_ctx_t *mctx)
105{
106    mctx->sc                  = NULL; /* set during module init */
107
108    mctx->ssl_ctx             = NULL; /* set during module init */
109
110    mctx->pks                 = NULL;
111    mctx->pkp                 = NULL;
112
113    mctx->protocol            = SSL_PROTOCOL_ALL;
114
115    mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET;
116    mctx->pphrase_dialog_path = NULL;
117
118    mctx->cert_chain          = NULL;
119
120    mctx->crl_path            = NULL;
121    mctx->crl_file            = NULL;
122    mctx->crl                 = NULL; /* set during module init */
123
124    mctx->auth.ca_cert_path   = NULL;
125    mctx->auth.ca_cert_file   = NULL;
126    mctx->auth.cipher_suite   = NULL;
127    mctx->auth.verify_depth   = UNSET;
128    mctx->auth.verify_mode    = SSL_CVERIFY_UNSET;
129}
130
131static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc,
132                                  apr_pool_t *p)
133{
134    modssl_ctx_t *mctx;
135
136    mctx = sc->proxy = apr_palloc(p, sizeof(*sc->proxy));
137
138    modssl_ctx_init(mctx);
139
140    mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp));
141
142    mctx->pkp->cert_file = NULL;
143    mctx->pkp->cert_path = NULL;
144    mctx->pkp->ca_cert_file = NULL;
145    mctx->pkp->certs     = NULL;
146    mctx->pkp->ca_certs  = NULL;
147}
148
149static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
150                                   apr_pool_t *p)
151{
152    modssl_ctx_t *mctx;
153
154    mctx = sc->server = apr_palloc(p, sizeof(*sc->server));
155
156    modssl_ctx_init(mctx);
157
158    mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks));
159
160    /* mctx->pks->... certs/keys are set during module init */
161}
162
163static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p)
164{
165    SSLSrvConfigRec *sc = apr_palloc(p, sizeof(*sc));
166
167    sc->mc                     = NULL;
168    sc->enabled                = SSL_ENABLED_FALSE;
169    sc->proxy_enabled          = UNSET;
170    sc->vhost_id               = NULL;  /* set during module init */
171    sc->vhost_id_len           = 0;     /* set during module init */
172    sc->session_cache_timeout  = UNSET;
173    sc->cipher_server_pref     = UNSET;
174    sc->insecure_reneg         = UNSET;
175    sc->proxy_ssl_check_peer_expire = SSL_ENABLED_UNSET;
176    sc->proxy_ssl_check_peer_cn     = SSL_ENABLED_UNSET;
177#ifndef OPENSSL_NO_TLSEXT
178    sc->strict_sni_vhost_check = SSL_ENABLED_UNSET;
179#endif
180#ifdef HAVE_FIPS
181    sc->fips                   = UNSET;
182#endif
183#ifndef OPENSSL_NO_COMP
184    sc->compression            = UNSET;
185#endif
186    sc->allow_empty_fragments  = UNSET;
187
188    modssl_ctx_init_proxy(sc, p);
189
190    modssl_ctx_init_server(sc, p);
191
192    return sc;
193}
194
195/*
196 *  Create per-server SSL configuration
197 */
198void *ssl_config_server_create(apr_pool_t *p, server_rec *s)
199{
200    SSLSrvConfigRec *sc = ssl_config_server_new(p);
201
202    sc->mc = ssl_config_global_create(s);
203
204    return sc;
205}
206
207#define cfgMerge(el,unset)  mrg->el = (add->el == (unset)) ? base->el : add->el
208#define cfgMergeArray(el)   mrg->el = apr_array_append(p, add->el, base->el)
209#define cfgMergeString(el)  cfgMerge(el, NULL)
210#define cfgMergeBool(el)    cfgMerge(el, UNSET)
211#define cfgMergeInt(el)     cfgMerge(el, UNSET)
212
213static void modssl_ctx_cfg_merge(modssl_ctx_t *base,
214                                 modssl_ctx_t *add,
215                                 modssl_ctx_t *mrg)
216{
217    cfgMerge(protocol, SSL_PROTOCOL_ALL);
218
219    cfgMerge(pphrase_dialog_type, SSL_PPTYPE_UNSET);
220    cfgMergeString(pphrase_dialog_path);
221
222    cfgMergeString(cert_chain);
223
224    cfgMerge(crl_path, NULL);
225    cfgMerge(crl_file, NULL);
226
227    cfgMergeString(auth.ca_cert_path);
228    cfgMergeString(auth.ca_cert_file);
229    cfgMergeString(auth.cipher_suite);
230    cfgMergeInt(auth.verify_depth);
231    cfgMerge(auth.verify_mode, SSL_CVERIFY_UNSET);
232}
233
234static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base,
235                                       modssl_ctx_t *add,
236                                       modssl_ctx_t *mrg)
237{
238    modssl_ctx_cfg_merge(base, add, mrg);
239
240    cfgMergeString(pkp->cert_file);
241    cfgMergeString(pkp->cert_path);
242    cfgMergeString(pkp->ca_cert_file);
243}
244
245static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base,
246                                        modssl_ctx_t *add,
247                                        modssl_ctx_t *mrg)
248{
249    int i;
250
251    modssl_ctx_cfg_merge(base, add, mrg);
252
253    for (i = 0; i < SSL_AIDX_MAX; i++) {
254        cfgMergeString(pks->cert_files[i]);
255        cfgMergeString(pks->key_files[i]);
256    }
257
258    cfgMergeString(pks->ca_name_path);
259    cfgMergeString(pks->ca_name_file);
260}
261
262/*
263 *  Merge per-server SSL configurations
264 */
265void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
266{
267    SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev;
268    SSLSrvConfigRec *add  = (SSLSrvConfigRec *)addv;
269    SSLSrvConfigRec *mrg  = ssl_config_server_new(p);
270
271    cfgMerge(mc, NULL);
272    cfgMerge(enabled, SSL_ENABLED_UNSET);
273    cfgMergeBool(proxy_enabled);
274    cfgMergeInt(session_cache_timeout);
275    cfgMergeBool(cipher_server_pref);
276    cfgMergeBool(insecure_reneg);
277    cfgMerge(proxy_ssl_check_peer_expire, SSL_ENABLED_UNSET);
278    cfgMerge(proxy_ssl_check_peer_cn, SSL_ENABLED_UNSET);
279#ifndef OPENSSL_NO_TLSEXT
280    cfgMerge(strict_sni_vhost_check, SSL_ENABLED_UNSET);
281#endif
282#ifdef HAVE_FIPS
283    cfgMergeBool(fips);
284#endif
285#ifndef OPENSSL_NO_COMP
286    cfgMergeBool(compression);
287#endif
288    cfgMergeBool(allow_empty_fragments);
289
290    modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy);
291
292    modssl_ctx_cfg_merge_server(base->server, add->server, mrg->server);
293
294    return mrg;
295}
296
297/*
298 *  Create per-directory SSL configuration
299 */
300void *ssl_config_perdir_create(apr_pool_t *p, char *dir)
301{
302    SSLDirConfigRec *dc = apr_palloc(p, sizeof(*dc));
303
304    dc->bSSLRequired  = FALSE;
305    dc->aRequirement  = apr_array_make(p, 4, sizeof(ssl_require_t));
306    dc->nOptions      = SSL_OPT_NONE|SSL_OPT_RELSET;
307    dc->nOptionsAdd   = SSL_OPT_NONE;
308    dc->nOptionsDel   = SSL_OPT_NONE;
309
310    dc->szCipherSuite          = NULL;
311    dc->nVerifyClient          = SSL_CVERIFY_UNSET;
312    dc->nVerifyDepth           = UNSET;
313
314    dc->szCACertificatePath    = NULL;
315    dc->szCACertificateFile    = NULL;
316    dc->szUserName             = NULL;
317
318    dc->nRenegBufferSize = UNSET;
319
320    return dc;
321}
322
323/*
324 *  Merge per-directory SSL configurations
325 */
326void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv)
327{
328    SSLDirConfigRec *base = (SSLDirConfigRec *)basev;
329    SSLDirConfigRec *add  = (SSLDirConfigRec *)addv;
330    SSLDirConfigRec *mrg  = (SSLDirConfigRec *)apr_palloc(p, sizeof(*mrg));
331
332    cfgMerge(bSSLRequired, FALSE);
333    cfgMergeArray(aRequirement);
334
335    if (add->nOptions & SSL_OPT_RELSET) {
336        mrg->nOptionsAdd =
337            (base->nOptionsAdd & ~(add->nOptionsDel)) | add->nOptionsAdd;
338        mrg->nOptionsDel =
339            (base->nOptionsDel & ~(add->nOptionsAdd)) | add->nOptionsDel;
340        mrg->nOptions    =
341            (base->nOptions    & ~(mrg->nOptionsDel)) | mrg->nOptionsAdd;
342    }
343    else {
344        mrg->nOptions    = add->nOptions;
345        mrg->nOptionsAdd = add->nOptionsAdd;
346        mrg->nOptionsDel = add->nOptionsDel;
347    }
348
349    cfgMergeString(szCipherSuite);
350    cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET);
351    cfgMergeInt(nVerifyDepth);
352
353    cfgMergeString(szCACertificatePath);
354    cfgMergeString(szCACertificateFile);
355    cfgMergeString(szUserName);
356
357    cfgMergeInt(nRenegBufferSize);
358
359    return mrg;
360}
361
362/*
363 *  Configuration functions for particular directives
364 */
365
366const char *ssl_cmd_SSLMutex(cmd_parms *cmd,
367                             void *dcfg,
368                             const char *arg_)
369{
370    const char *err;
371    SSLModConfigRec *mc = myModConfig(cmd->server);
372    /* Split arg_ into meth and file */
373    char *meth = apr_pstrdup(cmd->temp_pool, arg_);
374    char *file = strchr(meth, ':');
375    if (file) {
376        *(file++) = '\0';
377        if (!*file) {
378            file = NULL;
379        }
380    }
381
382    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
383        return err;
384    }
385
386    if (ssl_config_global_isfixed(mc)) {
387        return NULL;
388    }
389    if (!strcasecmp(meth, "none") || !strcasecmp(meth, "no")) {
390        mc->nMutexMode  = SSL_MUTEXMODE_NONE;
391        return NULL;
392    }
393
394    /* APR determines temporary filename unless overridden below,
395     * we presume file indicates an szMutexFile is a file path
396     * unless the method sets szMutexFile=file and NULLs file
397     */
398    mc->nMutexMode  = SSL_MUTEXMODE_USED;
399    mc->szMutexFile = NULL;
400
401    /* NOTE: previously, 'yes' implied 'sem' */
402    if (!strcasecmp(meth, "default") || !strcasecmp(meth, "yes")) {
403        mc->nMutexMech = APR_LOCK_DEFAULT;
404    }
405#if APR_HAS_FCNTL_SERIALIZE
406    else if ((!strcasecmp(meth, "fcntl") || !strcasecmp(meth, "file")) && file) {
407        mc->nMutexMech = APR_LOCK_FCNTL;
408    }
409#endif
410#if APR_HAS_FLOCK_SERIALIZE
411    else if ((!strcasecmp(meth, "flock") || !strcasecmp(meth, "file")) && file) {
412        mc->nMutexMech = APR_LOCK_FLOCK;
413    }
414#endif
415#if APR_HAS_POSIXSEM_SERIALIZE
416    else if (!strcasecmp(meth, "posixsem") || !strcasecmp(meth, "sem")) {
417        mc->nMutexMech = APR_LOCK_POSIXSEM;
418        /* Posix/SysV semaphores aren't file based, use the literal name
419         * if provided and fall back on APR's default if not.  Today, APR
420         * will ignore it, but once supported it has an absurdly short limit.
421         */
422        if (file) {
423            mc->szMutexFile = apr_pstrdup(cmd->server->process->pool, file);
424
425            file = NULL;
426        }
427    }
428#endif
429#if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM)
430    else if (!strcasecmp(meth, "sysvsem") || !strcasecmp(meth, "sem")) {
431        mc->nMutexMech = APR_LOCK_SYSVSEM;
432    }
433#endif
434#if APR_HAS_PROC_PTHREAD_SERIALIZE
435    else if (!strcasecmp(meth, "pthread")) {
436        mc->nMutexMech = APR_LOCK_PROC_PTHREAD;
437    }
438#endif
439    else {
440        return apr_pstrcat(cmd->pool, "Invalid SSLMutex argument ", arg_,
441                           " (", ssl_valid_ssl_mutex_string, ")", NULL);
442    }
443
444    /* Unless the method above assumed responsibility for setting up
445     * mc->szMutexFile and NULLing out file, presume it is a file we
446     * are looking to use
447     */
448    if (file) {
449        mc->szMutexFile = ap_server_root_relative(cmd->server->process->pool, file);
450        if (!mc->szMutexFile) {
451            return apr_pstrcat(cmd->pool, "Invalid SSLMutex ", meth,
452                               ": filepath ", file, NULL);
453        }
454    }
455
456    return NULL;
457}
458
459const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *cmd,
460                                        void *dcfg,
461                                        const char *arg)
462{
463    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
464    const char *err;
465    int arglen = strlen(arg);
466
467    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
468        return err;
469    }
470
471    if (strcEQ(arg, "builtin")) {
472        sc->server->pphrase_dialog_type  = SSL_PPTYPE_BUILTIN;
473        sc->server->pphrase_dialog_path = NULL;
474    }
475    else if ((arglen > 5) && strEQn(arg, "exec:", 5)) {
476        sc->server->pphrase_dialog_type  = SSL_PPTYPE_FILTER;
477        sc->server->pphrase_dialog_path =
478            ap_server_root_relative(cmd->pool, arg+5);
479        if (!sc->server->pphrase_dialog_path) {
480            return apr_pstrcat(cmd->pool,
481                               "Invalid SSLPassPhraseDialog exec: path ",
482                               arg+5, NULL);
483        }
484        if (!ssl_util_path_check(SSL_PCM_EXISTS,
485                                 sc->server->pphrase_dialog_path,
486                                 cmd->pool))
487        {
488            return apr_pstrcat(cmd->pool,
489                               "SSLPassPhraseDialog: file '",
490                               sc->server->pphrase_dialog_path,
491                               "' does not exist", NULL);
492        }
493
494    }
495    else if ((arglen > 1) && (arg[0] == '|')) {
496        sc->server->pphrase_dialog_type  = SSL_PPTYPE_PIPE;
497        sc->server->pphrase_dialog_path = arg + 1;
498    }
499    else {
500        return "SSLPassPhraseDialog: Invalid argument";
501    }
502
503    return NULL;
504}
505
506#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
507const char *ssl_cmd_SSLCryptoDevice(cmd_parms *cmd,
508                                    void *dcfg,
509                                    const char *arg)
510{
511    SSLModConfigRec *mc = myModConfig(cmd->server);
512    const char *err;
513    ENGINE *e;
514
515    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
516        return err;
517    }
518
519    if (strcEQ(arg, "builtin")) {
520        mc->szCryptoDevice = NULL;
521    }
522    else if ((e = ENGINE_by_id(arg))) {
523        mc->szCryptoDevice = arg;
524        ENGINE_free(e);
525    }
526    else {
527        err = "SSLCryptoDevice: Invalid argument; must be one of: "
528              "'builtin' (none)";
529        e = ENGINE_get_first();
530        while (e) {
531            ENGINE *en;
532            err = apr_pstrcat(cmd->pool, err, ", '", ENGINE_get_id(e),
533                                         "' (", ENGINE_get_name(e), ")", NULL);
534            en = ENGINE_get_next(e);
535            ENGINE_free(e);
536            e = en;
537        }
538        return err;
539    }
540
541    return NULL;
542}
543#endif
544
545const char *ssl_cmd_SSLRandomSeed(cmd_parms *cmd,
546                                  void *dcfg,
547                                  const char *arg1,
548                                  const char *arg2,
549                                  const char *arg3)
550{
551    SSLModConfigRec *mc = myModConfig(cmd->server);
552    const char *err;
553    ssl_randseed_t *seed;
554    int arg2len = strlen(arg2);
555
556    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
557        return err;
558    }
559
560    if (ssl_config_global_isfixed(mc)) {
561        return NULL;
562    }
563
564    seed = apr_array_push(mc->aRandSeed);
565
566    if (strcEQ(arg1, "startup")) {
567        seed->nCtx = SSL_RSCTX_STARTUP;
568    }
569    else if (strcEQ(arg1, "connect")) {
570        seed->nCtx = SSL_RSCTX_CONNECT;
571    }
572    else {
573        return apr_pstrcat(cmd->pool, "SSLRandomSeed: "
574                           "invalid context: `", arg1, "'",
575                           NULL);
576    }
577
578    if ((arg2len > 5) && strEQn(arg2, "file:", 5)) {
579        seed->nSrc   = SSL_RSSRC_FILE;
580        seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5);
581    }
582    else if ((arg2len > 5) && strEQn(arg2, "exec:", 5)) {
583        seed->nSrc   = SSL_RSSRC_EXEC;
584        seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5);
585    }
586    else if ((arg2len > 4) && strEQn(arg2, "egd:", 4)) {
587#ifdef HAVE_SSL_RAND_EGD
588        seed->nSrc   = SSL_RSSRC_EGD;
589        seed->cpPath = ap_server_root_relative(mc->pPool, arg2+4);
590#else
591    return "egd not supported with this SSL toolkit";
592#endif
593    }
594    else if (strcEQ(arg2, "builtin")) {
595        seed->nSrc   = SSL_RSSRC_BUILTIN;
596        seed->cpPath = NULL;
597    }
598    else {
599        seed->nSrc   = SSL_RSSRC_FILE;
600        seed->cpPath = ap_server_root_relative(mc->pPool, arg2);
601    }
602
603    if (seed->nSrc != SSL_RSSRC_BUILTIN) {
604        if (!seed->cpPath) {
605            return apr_pstrcat(cmd->pool,
606                               "Invalid SSLRandomSeed path ",
607                               arg2, NULL);
608        }
609        if (!ssl_util_path_check(SSL_PCM_EXISTS, seed->cpPath, cmd->pool)) {
610            return apr_pstrcat(cmd->pool,
611                               "SSLRandomSeed: source path '",
612                               seed->cpPath, "' does not exist", NULL);
613        }
614    }
615
616    if (!arg3) {
617        seed->nBytes = 0; /* read whole file */
618    }
619    else {
620        if (seed->nSrc == SSL_RSSRC_BUILTIN) {
621            return "SSLRandomSeed: byte specification not "
622                   "allowed for builtin seed source";
623        }
624
625        seed->nBytes = atoi(arg3);
626
627        if (seed->nBytes < 0) {
628            return "SSLRandomSeed: invalid number of bytes specified";
629        }
630    }
631
632    return NULL;
633}
634
635const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg)
636{
637    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
638
639    if (!strcasecmp(arg, "On")) {
640        sc->enabled = SSL_ENABLED_TRUE;
641        return NULL;
642    }
643    else if (!strcasecmp(arg, "Off")) {
644        sc->enabled = SSL_ENABLED_FALSE;
645        return NULL;
646    }
647    else if (!strcasecmp(arg, "Optional")) {
648        sc->enabled = SSL_ENABLED_OPTIONAL;
649        return NULL;
650    }
651
652    return "Argument must be On, Off, or Optional";
653}
654
655const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag)
656{
657#ifdef HAVE_FIPS
658    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
659#endif
660    const char *err;
661
662    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
663        return err;
664    }
665
666#ifdef HAVE_FIPS
667    if ((sc->fips != UNSET) && (sc->fips != (BOOL)(flag ? TRUE : FALSE)))
668        return "Conflicting SSLFIPS options, cannot be both On and Off";
669    sc->fips = flag ? TRUE : FALSE;
670#else
671    if (flag)
672        return "SSLFIPS invalid, rebuild httpd and openssl compiled for FIPS";
673#endif
674
675    return NULL;
676}
677
678const char *ssl_cmd_SSLAllowEmptyFragments(cmd_parms *cmd, void *dcfg, int flag)
679{
680    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
681    const char *err;
682
683    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
684        return err;
685    }
686
687    if ((sc->allow_empty_fragments != UNSET) && (sc->allow_empty_fragments != (BOOL)(flag ? TRUE : FALSE)))
688        return "Conflicting SSLAllowEmptyFragments options, cannot be both On and Off";
689    sc->allow_empty_fragments = flag ? TRUE : FALSE;
690
691    return NULL;
692}
693
694const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd,
695                                   void *dcfg,
696                                   const char *arg)
697{
698    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
699    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
700
701    if (cmd->path) {
702        dc->szCipherSuite = arg;
703    }
704    else {
705        sc->server->auth.cipher_suite = arg;
706    }
707
708    return NULL;
709}
710
711#define SSL_FLAGS_CHECK_FILE \
712    (SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO)
713
714#define SSL_FLAGS_CHECK_DIR \
715    (SSL_PCM_EXISTS|SSL_PCM_ISDIR)
716
717static const char *ssl_cmd_check_file(cmd_parms *parms,
718                                      const char **file)
719{
720    const char *filepath = ap_server_root_relative(parms->pool, *file);
721
722    if (!filepath) {
723        return apr_pstrcat(parms->pool, parms->cmd->name,
724                           ": Invalid file path ", *file, NULL);
725    }
726    *file = filepath;
727
728    if (ssl_util_path_check(SSL_FLAGS_CHECK_FILE, *file, parms->pool)) {
729        return NULL;
730    }
731
732    return apr_pstrcat(parms->pool, parms->cmd->name,
733                       ": file '", *file,
734                       "' does not exist or is empty", NULL);
735
736}
737
738const char *ssl_cmd_SSLCompression(cmd_parms *cmd, void *dcfg, int flag)
739{
740#if !defined(OPENSSL_NO_COMP)
741    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
742#ifndef SSL_OP_NO_COMPRESSION
743    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
744    if (err)
745        return "This version of openssl does not support configuring "
746               "compression within <VirtualHost> sections.";
747#endif
748    sc->compression = flag ? TRUE : FALSE;
749    return NULL;
750#else
751    return "Setting Compression mode unsupported; not implemented by the SSL library";
752#endif
753}
754
755const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag)
756{
757#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
758    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
759    sc->cipher_server_pref = flag?TRUE:FALSE;
760    return NULL;
761#else
762    return "SSLHonorCiperOrder unsupported; not implemented by the SSL library";
763#endif
764}
765
766const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag)
767{
768#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
769    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
770    sc->insecure_reneg = flag?TRUE:FALSE;
771    return NULL;
772#else
773    return "The SSLInsecureRenegotiation directive is not available "
774        "with this SSL library";
775#endif
776}
777
778
779static const char *ssl_cmd_check_dir(cmd_parms *parms,
780                                     const char **dir)
781{
782    const char *dirpath = ap_server_root_relative(parms->pool, *dir);
783
784    if (!dirpath) {
785        return apr_pstrcat(parms->pool, parms->cmd->name,
786                           ": Invalid dir path ", *dir, NULL);
787    }
788    *dir = dirpath;
789
790    if (ssl_util_path_check(SSL_FLAGS_CHECK_DIR, *dir, parms->pool)) {
791        return NULL;
792    }
793
794    return apr_pstrcat(parms->pool, parms->cmd->name,
795                       ": directory '", *dir,
796                       "' does not exist", NULL);
797
798}
799
800#define SSL_AIDX_CERTS 1
801#define SSL_AIDX_KEYS  2
802
803static const char *ssl_cmd_check_aidx_max(cmd_parms *parms,
804                                          const char *arg,
805                                          int idx)
806{
807    SSLSrvConfigRec *sc = mySrvConfig(parms->server);
808    const char *err, *desc=NULL, **files=NULL;
809    int i;
810
811    if ((err = ssl_cmd_check_file(parms, &arg))) {
812        return err;
813    }
814
815    switch (idx) {
816      case SSL_AIDX_CERTS:
817        desc = "certificates";
818        files = sc->server->pks->cert_files;
819        break;
820      case SSL_AIDX_KEYS:
821        desc = "private keys";
822        files = sc->server->pks->key_files;
823        break;
824    }
825
826    for (i = 0; i < SSL_AIDX_MAX; i++) {
827        if (!files[i]) {
828            files[i] = arg;
829            return NULL;
830        }
831    }
832
833    return apr_psprintf(parms->pool,
834                        "%s: only up to %d "
835                        "different %s per virtual host allowed",
836                         parms->cmd->name, SSL_AIDX_MAX, desc);
837}
838
839const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd,
840                                       void *dcfg,
841                                       const char *arg)
842{
843
844    const char *err;
845
846    if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_CERTS))) {
847        return err;
848    }
849
850    return NULL;
851}
852
853const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *cmd,
854                                          void *dcfg,
855                                          const char *arg)
856{
857    const char *err;
858
859    if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_KEYS))) {
860        return err;
861    }
862
863    return NULL;
864}
865
866const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd,
867                                            void *dcfg,
868                                            const char *arg)
869{
870    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
871    const char *err;
872
873    if ((err = ssl_cmd_check_file(cmd, &arg))) {
874        return err;
875    }
876
877    sc->server->cert_chain = arg;
878
879    return NULL;
880}
881
882#define NO_PER_DIR_SSL_CA \
883    "Your ssl library does not have support for per-directory CA"
884
885#ifdef HAVE_SSL_SET_CERT_STORE
886#   define MODSSL_HAVE_SSL_SET_CERT_STORE 1
887#else
888#   define MODSSL_HAVE_SSL_SET_CERT_STORE 0
889#endif
890
891#define MODSSL_SET_CA(f) \
892    if (cmd->path) \
893        if (MODSSL_HAVE_SSL_SET_CERT_STORE) \
894            dc->f = arg; \
895        else \
896            return NO_PER_DIR_SSL_CA; \
897    else \
898        sc->f = arg \
899
900const char *ssl_cmd_SSLCACertificatePath(cmd_parms *cmd,
901                                         void *dcfg,
902                                         const char *arg)
903{
904    /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/
905    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
906    const char *err;
907
908    if ((err = ssl_cmd_check_dir(cmd, &arg))) {
909        return err;
910    }
911
912    /* XXX: bring back per-dir */
913    sc->server->auth.ca_cert_path = arg;
914
915    return NULL;
916}
917
918const char *ssl_cmd_SSLCACertificateFile(cmd_parms *cmd,
919                                         void *dcfg,
920                                         const char *arg)
921{
922    /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/
923    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
924    const char *err;
925
926    if ((err = ssl_cmd_check_file(cmd, &arg))) {
927        return err;
928    }
929
930    /* XXX: bring back per-dir */
931    sc->server->auth.ca_cert_file = arg;
932
933    return NULL;
934}
935
936const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *cmd, void *dcfg,
937                                       const char *arg)
938{
939    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
940    const char *err;
941
942    if ((err = ssl_cmd_check_dir(cmd, &arg))) {
943        return err;
944    }
945
946    sc->server->pks->ca_name_path = arg;
947
948    return NULL;
949}
950
951const char *ssl_cmd_SSLCADNRequestFile(cmd_parms *cmd, void *dcfg,
952                                       const char *arg)
953{
954    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
955    const char *err;
956
957    if ((err = ssl_cmd_check_file(cmd, &arg))) {
958        return err;
959    }
960
961    sc->server->pks->ca_name_file = arg;
962
963    return NULL;
964}
965
966const char *ssl_cmd_SSLCARevocationPath(cmd_parms *cmd,
967                                        void *dcfg,
968                                        const char *arg)
969{
970    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
971    const char *err;
972
973    if ((err = ssl_cmd_check_dir(cmd, &arg))) {
974        return err;
975    }
976
977    sc->server->crl_path = arg;
978
979    return NULL;
980}
981
982const char *ssl_cmd_SSLCARevocationFile(cmd_parms *cmd,
983                                        void *dcfg,
984                                        const char *arg)
985{
986    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
987    const char *err;
988
989    if ((err = ssl_cmd_check_file(cmd, &arg))) {
990        return err;
991    }
992
993    sc->server->crl_file = arg;
994
995    return NULL;
996}
997
998static const char *ssl_cmd_verify_parse(cmd_parms *parms,
999                                        const char *arg,
1000                                        ssl_verify_t *id)
1001{
1002    if (strcEQ(arg, "none") || strcEQ(arg, "off")) {
1003        *id = SSL_CVERIFY_NONE;
1004    }
1005    else if (strcEQ(arg, "optional")) {
1006        *id = SSL_CVERIFY_OPTIONAL;
1007    }
1008    else if (strcEQ(arg, "require") || strcEQ(arg, "on")) {
1009        *id = SSL_CVERIFY_REQUIRE;
1010    }
1011    else if (strcEQ(arg, "optional_no_ca")) {
1012        *id = SSL_CVERIFY_OPTIONAL_NO_CA;
1013    }
1014    else {
1015        return apr_pstrcat(parms->temp_pool, parms->cmd->name,
1016                           ": Invalid argument '", arg, "'",
1017                           NULL);
1018    }
1019
1020    return NULL;
1021}
1022
1023const char *ssl_cmd_SSLVerifyClient(cmd_parms *cmd,
1024                                    void *dcfg,
1025                                    const char *arg)
1026{
1027    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
1028    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1029    ssl_verify_t mode;
1030    const char *err;
1031
1032    if ((err = ssl_cmd_verify_parse(cmd, arg, &mode))) {
1033        return err;
1034    }
1035
1036    if (cmd->path) {
1037        dc->nVerifyClient = mode;
1038    }
1039    else {
1040        sc->server->auth.verify_mode = mode;
1041    }
1042
1043    return NULL;
1044}
1045
1046static const char *ssl_cmd_verify_depth_parse(cmd_parms *parms,
1047                                              const char *arg,
1048                                              int *depth)
1049{
1050    if ((*depth = atoi(arg)) >= 0) {
1051        return NULL;
1052    }
1053
1054    return apr_pstrcat(parms->temp_pool, parms->cmd->name,
1055                       ": Invalid argument '", arg, "'",
1056                       NULL);
1057}
1058
1059const char *ssl_cmd_SSLVerifyDepth(cmd_parms *cmd,
1060                                   void *dcfg,
1061                                   const char *arg)
1062{
1063    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
1064    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1065    int depth;
1066    const char *err;
1067
1068    if ((err = ssl_cmd_verify_depth_parse(cmd, arg, &depth))) {
1069        return err;
1070    }
1071
1072    if (cmd->path) {
1073        dc->nVerifyDepth = depth;
1074    }
1075    else {
1076        sc->server->auth.verify_depth = depth;
1077    }
1078
1079    return NULL;
1080}
1081
1082#define MODSSL_NO_SHARED_MEMORY_ERROR \
1083    "SSLSessionCache: shared memory cache not useable on this platform"
1084
1085const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd,
1086                                    void *dcfg,
1087                                    const char *arg)
1088{
1089    SSLModConfigRec *mc = myModConfig(cmd->server);
1090    const char *err, *colon;
1091    char *cp, *cp2;
1092    int arglen = strlen(arg);
1093
1094    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
1095        return err;
1096    }
1097
1098    if (ssl_config_global_isfixed(mc)) {
1099        return NULL;
1100    }
1101
1102    if (strcEQ(arg, "none")) {
1103        mc->nSessionCacheMode      = SSL_SCMODE_NONE;
1104        mc->szSessionCacheDataFile = NULL;
1105    }
1106    else if (strcEQ(arg, "nonenotnull")) {
1107        mc->nSessionCacheMode      = SSL_SCMODE_NONE_NOT_NULL;
1108        mc->szSessionCacheDataFile = NULL;
1109    }
1110    else if ((arglen > 4) && strcEQn(arg, "dbm:", 4)) {
1111        mc->nSessionCacheMode      = SSL_SCMODE_DBM;
1112        mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, arg+4);
1113        if (!mc->szSessionCacheDataFile) {
1114            return apr_psprintf(cmd->pool,
1115                                "SSLSessionCache: Invalid cache file path %s",
1116                                arg+4);
1117        }
1118    }
1119    else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) ||
1120             ((arglen > 6) && strcEQn(arg, "shmht:", 6)) ||
1121             ((arglen > 6) && strcEQn(arg, "shmcb:", 6))) {
1122#if !APR_HAS_SHARED_MEMORY
1123        return MODSSL_NO_SHARED_MEMORY_ERROR;
1124#endif
1125        mc->nSessionCacheMode      = SSL_SCMODE_SHMCB;
1126        colon = ap_strchr_c(arg, ':');
1127        mc->szSessionCacheDataFile =
1128            ap_server_root_relative(mc->pPool, colon+1);
1129        if (!mc->szSessionCacheDataFile) {
1130            return apr_psprintf(cmd->pool,
1131                                "SSLSessionCache: Invalid cache file path %s",
1132                                colon+1);
1133        }
1134        mc->tSessionCacheDataTable = NULL;
1135        mc->nSessionCacheDataSize  = 1024*512; /* 512KB */
1136
1137        if ((cp = strchr(mc->szSessionCacheDataFile, '('))) {
1138            *cp++ = NUL;
1139
1140            if (!(cp2 = strchr(cp, ')'))) {
1141                return "SSLSessionCache: Invalid argument: "
1142                       "no closing parenthesis";
1143            }
1144
1145            *cp2 = NUL;
1146
1147            mc->nSessionCacheDataSize = atoi(cp);
1148
1149            if (mc->nSessionCacheDataSize < 8192) {
1150                return "SSLSessionCache: Invalid argument: "
1151                       "size has to be >= 8192 bytes";
1152
1153            }
1154
1155            if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) {
1156                return apr_psprintf(cmd->pool,
1157                                    "SSLSessionCache: Invalid argument: "
1158                                    "size has to be < %d bytes on this "
1159                                    "platform", APR_SHM_MAXSIZE);
1160
1161            }
1162        }
1163    }
1164    else if ((arglen > 3) && strcEQn(arg, "dc:", 3)) {
1165#ifdef HAVE_DISTCACHE
1166        mc->nSessionCacheMode      = SSL_SCMODE_DC;
1167        mc->szSessionCacheDataFile = apr_pstrdup(mc->pPool, arg+3);
1168        if (!mc->szSessionCacheDataFile) {
1169            return apr_pstrcat(cmd->pool,
1170                               "SSLSessionCache: Invalid cache file path: ",
1171                               arg+3, NULL);
1172        }
1173#else
1174        return "SSLSessionCache: distcache support disabled";
1175#endif
1176    }
1177    else {
1178        return "SSLSessionCache: Invalid argument";
1179    }
1180
1181    return NULL;
1182}
1183
1184const char *ssl_cmd_SSLSessionCacheTimeout(cmd_parms *cmd,
1185                                           void *dcfg,
1186                                           const char *arg)
1187{
1188    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1189
1190    sc->session_cache_timeout = atoi(arg);
1191
1192    if (sc->session_cache_timeout < 0) {
1193        return "SSLSessionCacheTimeout: Invalid argument";
1194    }
1195
1196    return NULL;
1197}
1198
1199const char *ssl_cmd_SSLOptions(cmd_parms *cmd,
1200                               void *dcfg,
1201                               const char *arg)
1202{
1203    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
1204    ssl_opt_t opt;
1205    int first = TRUE;
1206    char action, *w;
1207
1208    while (*arg) {
1209        w = ap_getword_conf(cmd->pool, &arg);
1210        action = NUL;
1211
1212        if ((*w == '+') || (*w == '-')) {
1213            action = *(w++);
1214        }
1215        else if (first) {
1216            dc->nOptions = SSL_OPT_NONE;
1217            first = FALSE;
1218        }
1219
1220        if (strcEQ(w, "StdEnvVars")) {
1221            opt = SSL_OPT_STDENVVARS;
1222        }
1223        else if (strcEQ(w, "ExportCertData")) {
1224            opt = SSL_OPT_EXPORTCERTDATA;
1225        }
1226        else if (strcEQ(w, "FakeBasicAuth")) {
1227            opt = SSL_OPT_FAKEBASICAUTH;
1228        }
1229        else if (strcEQ(w, "StrictRequire")) {
1230            opt = SSL_OPT_STRICTREQUIRE;
1231        }
1232        else if (strcEQ(w, "OptRenegotiate")) {
1233            opt = SSL_OPT_OPTRENEGOTIATE;
1234        }
1235        else {
1236            return apr_pstrcat(cmd->pool,
1237                               "SSLOptions: Illegal option '", w, "'",
1238                               NULL);
1239        }
1240
1241        if (action == '-') {
1242            dc->nOptionsAdd &= ~opt;
1243            dc->nOptionsDel |=  opt;
1244            dc->nOptions    &= ~opt;
1245        }
1246        else if (action == '+') {
1247            dc->nOptionsAdd |=  opt;
1248            dc->nOptionsDel &= ~opt;
1249            dc->nOptions    |=  opt;
1250        }
1251        else {
1252            dc->nOptions    = opt;
1253            dc->nOptionsAdd = opt;
1254            dc->nOptionsDel = SSL_OPT_NONE;
1255        }
1256    }
1257
1258    return NULL;
1259}
1260
1261const char *ssl_cmd_SSLRequireSSL(cmd_parms *cmd, void *dcfg)
1262{
1263    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
1264
1265    dc->bSSLRequired = TRUE;
1266
1267    return NULL;
1268}
1269
1270const char *ssl_cmd_SSLRequire(cmd_parms *cmd,
1271                               void *dcfg,
1272                               const char *arg)
1273{
1274    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
1275    ssl_expr *expr;
1276    ssl_require_t *require;
1277
1278    if (!(expr = ssl_expr_comp(cmd->pool, (char *)arg))) {
1279        return apr_pstrcat(cmd->pool, "SSLRequire: ",
1280                           ssl_expr_get_error(), NULL);
1281    }
1282
1283    require = apr_array_push(dc->aRequirement);
1284    require->cpExpr = apr_pstrdup(cmd->pool, arg);
1285    require->mpExpr = expr;
1286
1287    return NULL;
1288}
1289
1290const char *ssl_cmd_SSLRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg)
1291{
1292    SSLDirConfigRec *dc = dcfg;
1293    int val;
1294
1295    val = atoi(arg);
1296    if (val < 0) {
1297        return apr_pstrcat(cmd->pool, "Invalid size for SSLRenegBufferSize: ",
1298                           arg, NULL);
1299    }
1300    dc->nRenegBufferSize = val;
1301
1302    return NULL;
1303}
1304
1305static const char *ssl_cmd_protocol_parse(cmd_parms *parms,
1306                                          const char *arg,
1307                                          ssl_proto_t *options)
1308{
1309    ssl_proto_t thisopt;
1310
1311    *options = SSL_PROTOCOL_NONE;
1312
1313    while (*arg) {
1314        char *w = ap_getword_conf(parms->temp_pool, &arg);
1315        char action = '\0';
1316
1317        if ((*w == '+') || (*w == '-')) {
1318            action = *(w++);
1319        }
1320
1321        if (strcEQ(w, "SSLv2")) {
1322#ifdef OPENSSL_NO_SSL2
1323            if (action != '-') {
1324                return "SSLv2 not supported by this version of OpenSSL";
1325            }
1326            /* Nothing to do, the flag is not present to be toggled */
1327            continue;
1328#else
1329            thisopt = SSL_PROTOCOL_SSLV2;
1330#endif
1331        }
1332        else if (strcEQ(w, "SSLv3")) {
1333            thisopt = SSL_PROTOCOL_SSLV3;
1334        }
1335        else if (strcEQ(w, "TLSv1")) {
1336            thisopt = SSL_PROTOCOL_TLSV1;
1337        }
1338#ifdef HAVE_TLSV1_X
1339        else if (strcEQ(w, "TLSv1.1")) {
1340            thisopt = SSL_PROTOCOL_TLSV1_1;
1341        }
1342        else if (strcEQ(w, "TLSv1.2")) {
1343            thisopt = SSL_PROTOCOL_TLSV1_2;
1344        }
1345#endif
1346        else if (strcEQ(w, "all")) {
1347            thisopt = SSL_PROTOCOL_ALL;
1348        }
1349        else {
1350            return apr_pstrcat(parms->temp_pool,
1351                               parms->cmd->name,
1352                               ": Illegal protocol '",
1353                               w, "'", NULL);
1354        }
1355
1356        if (action == '-') {
1357            *options &= ~thisopt;
1358        }
1359        else if (action == '+') {
1360            *options |= thisopt;
1361        }
1362        else {
1363            *options = thisopt;
1364        }
1365    }
1366
1367    return NULL;
1368}
1369
1370const char *ssl_cmd_SSLProtocol(cmd_parms *cmd,
1371                                void *dcfg,
1372                                const char *arg)
1373{
1374    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1375
1376    return ssl_cmd_protocol_parse(cmd, arg, &sc->server->protocol);
1377}
1378
1379const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag)
1380{
1381    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1382
1383    sc->proxy_enabled = flag ? TRUE : FALSE;
1384
1385    return NULL;
1386}
1387
1388const char *ssl_cmd_SSLProxyProtocol(cmd_parms *cmd,
1389                                     void *dcfg,
1390                                     const char *arg)
1391{
1392    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1393
1394    return ssl_cmd_protocol_parse(cmd, arg, &sc->proxy->protocol);
1395}
1396
1397const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd,
1398                                        void *dcfg,
1399                                        const char *arg)
1400{
1401    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1402
1403    sc->proxy->auth.cipher_suite = arg;
1404
1405    return NULL;
1406}
1407
1408const char *ssl_cmd_SSLProxyVerify(cmd_parms *cmd,
1409                                   void *dcfg,
1410                                   const char *arg)
1411{
1412    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1413    ssl_verify_t mode;
1414    const char *err;
1415
1416    if ((err = ssl_cmd_verify_parse(cmd, arg, &mode))) {
1417        return err;
1418    }
1419
1420    sc->proxy->auth.verify_mode = mode;
1421
1422    return NULL;
1423}
1424
1425const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd,
1426                                        void *dcfg,
1427                                        const char *arg)
1428{
1429    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1430    int depth;
1431    const char *err;
1432
1433    if ((err = ssl_cmd_verify_depth_parse(cmd, arg, &depth))) {
1434        return err;
1435    }
1436
1437    sc->proxy->auth.verify_depth = depth;
1438
1439    return NULL;
1440}
1441
1442const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *cmd,
1443                                              void *dcfg,
1444                                              const char *arg)
1445{
1446    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1447    const char *err;
1448
1449    if ((err = ssl_cmd_check_file(cmd, &arg))) {
1450        return err;
1451    }
1452
1453    sc->proxy->auth.ca_cert_file = arg;
1454
1455    return NULL;
1456}
1457
1458const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *cmd,
1459                                              void *dcfg,
1460                                              const char *arg)
1461{
1462    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1463    const char *err;
1464
1465    if ((err = ssl_cmd_check_dir(cmd, &arg))) {
1466        return err;
1467    }
1468
1469    sc->proxy->auth.ca_cert_path = arg;
1470
1471    return NULL;
1472}
1473
1474const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *cmd,
1475                                             void *dcfg,
1476                                             const char *arg)
1477{
1478    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1479    const char *err;
1480
1481    if ((err = ssl_cmd_check_dir(cmd, &arg))) {
1482        return err;
1483    }
1484
1485    sc->proxy->crl_path = arg;
1486
1487    return NULL;
1488}
1489
1490const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *cmd,
1491                                             void *dcfg,
1492                                             const char *arg)
1493{
1494    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1495    const char *err;
1496
1497    if ((err = ssl_cmd_check_file(cmd, &arg))) {
1498        return err;
1499    }
1500
1501    sc->proxy->crl_file = arg;
1502
1503    return NULL;
1504}
1505
1506const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd,
1507                                                   void *dcfg,
1508                                                   const char *arg)
1509{
1510    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1511    const char *err;
1512
1513    if ((err = ssl_cmd_check_file(cmd, &arg))) {
1514        return err;
1515    }
1516
1517    sc->proxy->pkp->cert_file = arg;
1518
1519    return NULL;
1520}
1521
1522const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *cmd,
1523                                                   void *dcfg,
1524                                                   const char *arg)
1525{
1526    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1527    const char *err;
1528
1529    if ((err = ssl_cmd_check_dir(cmd, &arg))) {
1530        return err;
1531    }
1532
1533    sc->proxy->pkp->cert_path = arg;
1534
1535    return NULL;
1536}
1537
1538const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *cmd,
1539                                                   void *dcfg,
1540                                                   const char *arg)
1541{
1542    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1543    const char *err;
1544
1545    if ((err = ssl_cmd_check_file(cmd, &arg))) {
1546        return err;
1547    }
1548
1549    sc->proxy->pkp->ca_cert_file = arg;
1550
1551    return NULL;
1552}
1553
1554const char *ssl_cmd_SSLUserName(cmd_parms *cmd, void *dcfg,
1555                                const char *arg)
1556{
1557    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
1558    dc->szUserName = arg;
1559    return NULL;
1560}
1561
1562const char *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag)
1563{
1564    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1565
1566    sc->proxy_ssl_check_peer_expire = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
1567
1568    return NULL;
1569}
1570
1571const char *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag)
1572{
1573    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1574
1575    sc->proxy_ssl_check_peer_cn = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
1576
1577    return NULL;
1578}
1579
1580const char  *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag)
1581{
1582#ifndef OPENSSL_NO_TLSEXT
1583    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
1584
1585    sc->strict_sni_vhost_check = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
1586
1587    return NULL;
1588#else
1589    return "SSLStrictSNIVHostCheck failed; OpenSSL is not built with support "
1590           "for TLS extensions and SNI indication. Refer to the "
1591           "documentation, and build a compatible version of OpenSSL.";
1592#endif
1593}
1594
1595void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
1596{
1597    if (!ap_exists_config_define("DUMP_CERTS")) {
1598        return;
1599    }
1600
1601    /* Dump the filenames of all configured server certificates to
1602     * stdout. */
1603    while (s) {
1604        SSLSrvConfigRec *sc = mySrvConfig(s);
1605
1606        if (sc && sc->server && sc->server->pks) {
1607            modssl_pk_server_t *const pks = sc->server->pks;
1608            int i;
1609
1610            for (i = 0; (i < SSL_AIDX_MAX) && pks->cert_files[i]; i++) {
1611                printf("%s\n", pks->cert_files[i]);
1612            }
1613        }
1614
1615        s = s->next;
1616    }
1617
1618}
1619