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 #include <assert.h>
17 #include <apr_lib.h>
18 #include <apr_strings.h>
19 #include <apr_version.h>
20 
21 #include <httpd.h>
22 #include <http_core.h>
23 #include <http_config.h>
24 #include <http_log.h>
25 #include <http_main.h>
26 #include <ap_socache.h>
27 
28 #include <rustls.h>
29 
30 #include "tls_cert.h"
31 #include "tls_proto.h"
32 #include "tls_conf.h"
33 #include "tls_util.h"
34 #include "tls_var.h"
35 #include "tls_cache.h"
36 
37 
38 extern module AP_MODULE_DECLARE_DATA tls_module;
39 APLOG_USE_MODULE(tls);
40 
conf_global_get_or_make(apr_pool_t * pool,server_rec * s)41 static tls_conf_global_t *conf_global_get_or_make(apr_pool_t *pool, server_rec *s)
42 {
43     tls_conf_global_t *gconf;
44 
45     /* we create this only once for apache's one ap_server_conf.
46      * If this gets called for another server, we should already have
47      * done it for ap_server_conf. */
48     if (ap_server_conf && s != ap_server_conf) {
49         tls_conf_server_t *sconf = tls_conf_server_get(ap_server_conf);
50         ap_assert(sconf);
51         ap_assert(sconf->global);
52         return sconf->global;
53     }
54 
55     gconf = apr_pcalloc(pool, sizeof(*gconf));
56     gconf->ap_server = ap_server_conf;
57     gconf->status = TLS_CONF_ST_INIT;
58     gconf->proto = tls_proto_init(pool, s);
59     gconf->proxy_configs = apr_array_make(pool, 10, sizeof(tls_conf_proxy_t*));
60 
61     gconf->var_lookups = apr_hash_make(pool);
62     tls_var_init_lookup_hash(pool, gconf->var_lookups);
63     gconf->session_cache_spec = "default";
64 
65     return gconf;
66 }
67 
tls_conf_server_get(server_rec * s)68 tls_conf_server_t *tls_conf_server_get(server_rec *s)
69 {
70     tls_conf_server_t *sc = ap_get_module_config(s->module_config, &tls_module);
71     ap_assert(sc);
72     return sc;
73 }
74 
75 
76 #define CONF_S_NAME(s)  (s && s->server_hostname? s->server_hostname : "default")
77 
tls_conf_create_svr(apr_pool_t * pool,server_rec * s)78 void *tls_conf_create_svr(apr_pool_t *pool, server_rec *s)
79 {
80     tls_conf_server_t *conf;
81 
82     conf = apr_pcalloc(pool, sizeof(*conf));
83     conf->global = conf_global_get_or_make(pool, s);
84     conf->server = s;
85 
86     conf->enabled = TLS_FLAG_UNSET;
87     conf->cert_specs = apr_array_make(pool, 3, sizeof(tls_cert_spec_t*));
88     conf->honor_client_order = TLS_FLAG_UNSET;
89     conf->strict_sni = TLS_FLAG_UNSET;
90     conf->tls_protocol_min = TLS_FLAG_UNSET;
91     conf->tls_pref_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));;
92     conf->tls_supp_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));;
93     return conf;
94 }
95 
96 #define MERGE_INT(base, add, field) \
97     (add->field == TLS_FLAG_UNSET)? base->field : add->field;
98 
tls_conf_merge_svr(apr_pool_t * pool,void * basev,void * addv)99 void *tls_conf_merge_svr(apr_pool_t *pool, void *basev, void *addv)
100 {
101     tls_conf_server_t *base = basev;
102     tls_conf_server_t *add = addv;
103     tls_conf_server_t *nconf;
104 
105     nconf = apr_pcalloc(pool, sizeof(*nconf));
106     nconf->server = add->server;
107     nconf->global = add->global? add->global : base->global;
108 
109     nconf->enabled = MERGE_INT(base, add, enabled);
110     nconf->cert_specs = apr_array_append(pool, base->cert_specs, add->cert_specs);
111     nconf->tls_protocol_min = MERGE_INT(base, add, tls_protocol_min);
112     nconf->tls_pref_ciphers = add->tls_pref_ciphers->nelts?
113         add->tls_pref_ciphers : base->tls_pref_ciphers;
114     nconf->tls_supp_ciphers = add->tls_supp_ciphers->nelts?
115         add->tls_supp_ciphers : base->tls_supp_ciphers;
116     nconf->honor_client_order = MERGE_INT(base, add, honor_client_order);
117     nconf->client_ca = add->client_ca? add->client_ca : base->client_ca;
118     nconf->client_auth = (add->client_auth != TLS_CLIENT_AUTH_UNSET)?
119         add->client_auth : base->client_auth;
120     nconf->var_user_name = add->var_user_name? add->var_user_name : base->var_user_name;
121     return nconf;
122 }
123 
tls_conf_dir_get(request_rec * r)124 tls_conf_dir_t *tls_conf_dir_get(request_rec *r)
125 {
126     tls_conf_dir_t *dc = ap_get_module_config(r->per_dir_config, &tls_module);
127     ap_assert(dc);
128     return dc;
129 }
130 
tls_conf_dir_server_get(server_rec * s)131 tls_conf_dir_t *tls_conf_dir_server_get(server_rec *s)
132 {
133     tls_conf_dir_t *dc = ap_get_module_config(s->lookup_defaults, &tls_module);
134     ap_assert(dc);
135     return dc;
136 }
137 
tls_conf_create_dir(apr_pool_t * pool,char * dir)138 void *tls_conf_create_dir(apr_pool_t *pool, char *dir)
139 {
140     tls_conf_dir_t *conf;
141 
142     (void)dir;
143     conf = apr_pcalloc(pool, sizeof(*conf));
144     conf->std_env_vars = TLS_FLAG_UNSET;
145     conf->proxy_enabled = TLS_FLAG_UNSET;
146     conf->proxy_protocol_min = TLS_FLAG_UNSET;
147     conf->proxy_pref_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));;
148     conf->proxy_supp_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));;
149     conf->proxy_machine_cert_specs = apr_array_make(pool, 3, sizeof(tls_cert_spec_t*));
150     return conf;
151 }
152 
153 
same_proxy_settings(tls_conf_dir_t * a,tls_conf_dir_t * b)154 static int same_proxy_settings(tls_conf_dir_t *a, tls_conf_dir_t *b)
155 {
156     return a->proxy_ca == b->proxy_ca;
157 }
158 
dir_assign_merge(tls_conf_dir_t * dest,apr_pool_t * pool,tls_conf_dir_t * base,tls_conf_dir_t * add)159 static void dir_assign_merge(
160     tls_conf_dir_t *dest, apr_pool_t *pool, tls_conf_dir_t *base, tls_conf_dir_t *add)
161 {
162     tls_conf_dir_t local;
163 
164     memset(&local, 0, sizeof(local));
165     local.std_env_vars = MERGE_INT(base, add, std_env_vars);
166     local.export_cert_vars = MERGE_INT(base, add, export_cert_vars);
167     local.proxy_enabled = MERGE_INT(base, add, proxy_enabled);
168     local.proxy_ca = add->proxy_ca? add->proxy_ca : base->proxy_ca;
169     local.proxy_protocol_min = MERGE_INT(base, add, proxy_protocol_min);
170     local.proxy_pref_ciphers = add->proxy_pref_ciphers->nelts?
171         add->proxy_pref_ciphers : base->proxy_pref_ciphers;
172     local.proxy_supp_ciphers = add->proxy_supp_ciphers->nelts?
173         add->proxy_supp_ciphers : base->proxy_supp_ciphers;
174     local.proxy_machine_cert_specs = apr_array_append(pool,
175         base->proxy_machine_cert_specs, add->proxy_machine_cert_specs);
176     if (local.proxy_enabled == TLS_FLAG_TRUE) {
177         if (add->proxy_config) {
178             local.proxy_config = same_proxy_settings(&local, add)? add->proxy_config : NULL;
179         }
180         else if (base->proxy_config) {
181             local.proxy_config = same_proxy_settings(&local, base)? add->proxy_config : NULL;
182         }
183     }
184     memcpy(dest, &local, sizeof(*dest));
185 }
186 
tls_conf_merge_dir(apr_pool_t * pool,void * basev,void * addv)187 void *tls_conf_merge_dir(apr_pool_t *pool, void *basev, void *addv)
188 {
189     tls_conf_dir_t *base = basev;
190     tls_conf_dir_t *add = addv;
191     tls_conf_dir_t *nconf = apr_pcalloc(pool, sizeof(*nconf));
192     dir_assign_merge(nconf, pool, base, add);
193     return nconf;
194 }
195 
tls_conf_dir_set_options_defaults(apr_pool_t * pool,tls_conf_dir_t * dc)196 static void tls_conf_dir_set_options_defaults(apr_pool_t *pool, tls_conf_dir_t *dc)
197 {
198     (void)pool;
199     dc->std_env_vars = TLS_FLAG_FALSE;
200     dc->export_cert_vars = TLS_FLAG_FALSE;
201 }
202 
tls_conf_server_apply_defaults(tls_conf_server_t * sc,apr_pool_t * p)203 apr_status_t tls_conf_server_apply_defaults(tls_conf_server_t *sc, apr_pool_t *p)
204 {
205     (void)p;
206     if (sc->enabled == TLS_FLAG_UNSET) sc->enabled = TLS_FLAG_FALSE;
207     if (sc->tls_protocol_min == TLS_FLAG_UNSET) sc->tls_protocol_min = 0;
208     if (sc->honor_client_order == TLS_FLAG_UNSET) sc->honor_client_order = TLS_FLAG_TRUE;
209     if (sc->strict_sni == TLS_FLAG_UNSET) sc->strict_sni = TLS_FLAG_TRUE;
210     if (sc->client_auth == TLS_CLIENT_AUTH_UNSET) sc->client_auth = TLS_CLIENT_AUTH_NONE;
211     return APR_SUCCESS;
212 }
213 
tls_conf_dir_apply_defaults(tls_conf_dir_t * dc,apr_pool_t * p)214 apr_status_t tls_conf_dir_apply_defaults(tls_conf_dir_t *dc, apr_pool_t *p)
215 {
216     (void)p;
217     if (dc->std_env_vars == TLS_FLAG_UNSET) dc->std_env_vars = TLS_FLAG_FALSE;
218     if (dc->export_cert_vars == TLS_FLAG_UNSET) dc->export_cert_vars = TLS_FLAG_FALSE;
219     if (dc->proxy_enabled == TLS_FLAG_UNSET) dc->proxy_enabled = TLS_FLAG_FALSE;
220     return APR_SUCCESS;
221 }
222 
tls_conf_proxy_make(apr_pool_t * p,tls_conf_dir_t * dc,tls_conf_global_t * gc,server_rec * s)223 tls_conf_proxy_t *tls_conf_proxy_make(
224     apr_pool_t *p, tls_conf_dir_t *dc, tls_conf_global_t *gc, server_rec *s)
225 {
226     tls_conf_proxy_t *pc = apr_pcalloc(p, sizeof(*pc));
227     pc->defined_in = s;
228     pc->global = gc;
229     pc->proxy_ca = dc->proxy_ca;
230     pc->proxy_protocol_min = dc->proxy_protocol_min;
231     pc->proxy_pref_ciphers = dc->proxy_pref_ciphers;
232     pc->proxy_supp_ciphers = dc->proxy_supp_ciphers;
233     pc->machine_cert_specs = dc->proxy_machine_cert_specs;
234     pc->machine_certified_keys = apr_array_make(p, 3, sizeof(const rustls_certified_key*));
235     return pc;
236 }
237 
tls_proxy_section_post_config(apr_pool_t * p,apr_pool_t * plog,apr_pool_t * ptemp,server_rec * s,ap_conf_vector_t * section_config)238 int tls_proxy_section_post_config(
239     apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s,
240     ap_conf_vector_t *section_config)
241 {
242     tls_conf_dir_t *proxy_dc, *server_dc;
243     tls_conf_server_t *sc;
244 
245     /* mod_proxy collects the <Proxy>...</Proxy> sections per server (base server or virtualhost)
246      * and in its post_config hook, calls our function registered at its hook for each with
247      * s - the server they were define in
248      * section_config - the set of dir_configs for a <Proxy> section
249      *
250      * If none of _our_ config directives had been used, here or in the server, we get a NULL.
251      * Which means we have to do nothing. Otherwise, we add to `proxy_dc` the
252      * settings from `server_dc` - since this is not automagically done by apache.
253      *
254      * `proxy_dc` is then complete and tells us if we handle outgoing connections
255      * here and with what parameter settings.
256      */
257     (void)ptemp; (void)plog;
258     ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
259         "%s: tls_proxy_section_post_config called", s->server_hostname);
260     proxy_dc = ap_get_module_config(section_config, &tls_module);
261     if (!proxy_dc) goto cleanup;
262     server_dc = ap_get_module_config(s->lookup_defaults, &tls_module);
263     ap_assert(server_dc);
264     dir_assign_merge(proxy_dc, p, server_dc, proxy_dc);
265     tls_conf_dir_apply_defaults(proxy_dc, p);
266     if (proxy_dc->proxy_enabled && !proxy_dc->proxy_config) {
267         /* remember `proxy_dc` for subsequent configuration of outoing TLS setups */
268         sc = tls_conf_server_get(s);
269         proxy_dc->proxy_config = tls_conf_proxy_make(p, proxy_dc, sc->global, s);
270         ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
271             "%s: adding proxy_conf to globals in proxy_post_config_section",
272             s->server_hostname);
273         APR_ARRAY_PUSH(sc->global->proxy_configs, tls_conf_proxy_t*) = proxy_dc->proxy_config;
274     }
275 cleanup:
276     return OK;
277 }
278 
cmd_check_file(cmd_parms * cmd,const char * fpath)279 static const char *cmd_check_file(cmd_parms *cmd, const char *fpath)
280 {
281     char *real_path;
282 
283     /* just a dump of the configuration, dont resolve/check */
284     if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) {
285         return NULL;
286     }
287     real_path = ap_server_root_relative(cmd->pool, fpath);
288     if (!real_path) {
289         return apr_pstrcat(cmd->pool, cmd->cmd->name,
290                            ": Invalid file path ", fpath, NULL);
291     }
292     if (!tls_util_is_file(cmd->pool, real_path)) {
293         return apr_pstrcat(cmd->pool, cmd->cmd->name,
294                            ": file '", real_path,
295                            "' does not exist or is empty", NULL);
296     }
297     return NULL;
298 }
299 
tls_conf_add_engine(cmd_parms * cmd,void * dc,const char * v)300 static const char *tls_conf_add_engine(cmd_parms *cmd, void *dc, const char*v)
301 {
302     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
303     tls_conf_global_t *gc = sc->global;
304     const char *err = NULL;
305     char *host, *scope_id;
306     apr_port_t port;
307     apr_sockaddr_t *sa;
308     server_addr_rec *sar;
309     apr_status_t rv;
310 
311     (void)dc;
312     /* Example of use:
313      * TLSEngine 443
314      * TLSEngine hostname:443
315      * TLSEngine 91.0.0.1:443
316      * TLSEngine [::0]:443
317      */
318     rv = apr_parse_addr_port(&host, &scope_id, &port, v, cmd->pool);
319     if (APR_SUCCESS != rv) {
320         err = apr_pstrcat(cmd->pool, cmd->cmd->name,
321                           ": invalid address/port in '", v, "'", NULL);
322         goto cleanup;
323     }
324 
325     /* translate host/port to a sockaddr that we can match with incoming connections */
326     rv = apr_sockaddr_info_get(&sa, host, APR_UNSPEC, port, 0, cmd->pool);
327     if (APR_SUCCESS != rv) {
328         err = apr_pstrcat(cmd->pool, cmd->cmd->name,
329                           ": unable to get sockaddr for '", host, "'", NULL);
330         goto cleanup;
331     }
332 
333     if (scope_id) {
334 #if APR_VERSION_AT_LEAST(1,7,0)
335         rv = apr_sockaddr_zone_set(sa, scope_id);
336         if (APR_SUCCESS != rv) {
337             err = apr_pstrcat(cmd->pool, cmd->cmd->name,
338                               ": error setting ipv6 scope id: '", scope_id, "'", NULL);
339             goto cleanup;
340         }
341 #else
342         err = apr_pstrcat(cmd->pool, cmd->cmd->name,
343                           ": IPv6 scopes not supported by your APR: '", scope_id, "'", NULL);
344         goto cleanup;
345 #endif
346     }
347 
348     sar = apr_pcalloc(cmd->pool, sizeof(*sar));
349     sar->host_addr = sa;
350     sar->virthost = host;
351     sar->host_port = port;
352 
353     sar->next = gc->tls_addresses;
354     gc->tls_addresses = sar;
355 cleanup:
356     return err;
357 }
358 
flag_value(const char * arg)359 static int flag_value(
360     const char *arg)
361 {
362     if (!strcasecmp(arg, "On")) {
363         return TLS_FLAG_TRUE;
364     }
365     else if (!strcasecmp(arg, "Off")) {
366         return TLS_FLAG_FALSE;
367     }
368     return TLS_FLAG_UNSET;
369 }
370 
flag_err(cmd_parms * cmd,const char * v)371 static const char *flag_err(
372     cmd_parms *cmd, const char *v)
373 {
374     return apr_pstrcat(cmd->pool, cmd->cmd->name,
375         ": value must be 'On' or 'Off': '", v, "'", NULL);
376 }
377 
tls_conf_add_certificate(cmd_parms * cmd,void * dc,const char * cert_file,const char * pkey_file)378 static const char *tls_conf_add_certificate(
379     cmd_parms *cmd, void *dc, const char *cert_file, const char *pkey_file)
380 {
381     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
382     const char *err = NULL, *fpath;
383     tls_cert_spec_t *cert;
384 
385     (void)dc;
386     if (NULL != (err = cmd_check_file(cmd, cert_file))) goto cleanup;
387     /* key file may be NULL, in which case cert_file must contain the key PEM */
388     if (pkey_file && NULL != (err = cmd_check_file(cmd, pkey_file))) goto cleanup;
389 
390     cert = apr_pcalloc(cmd->pool, sizeof(*cert));
391     fpath = ap_server_root_relative(cmd->pool, cert_file);
392     if (!tls_util_is_file(cmd->pool, fpath)) {
393         return apr_pstrcat(cmd->pool, cmd->cmd->name,
394             ": unable to find certificate file: '", fpath, "'", NULL);
395     }
396     cert->cert_file = cert_file;
397     if (pkey_file) {
398         fpath = ap_server_root_relative(cmd->pool, pkey_file);
399         if (!tls_util_is_file(cmd->pool, fpath)) {
400             return apr_pstrcat(cmd->pool, cmd->cmd->name,
401                 ": unable to find certificate key file: '", fpath, "'", NULL);
402         }
403     }
404     cert->pkey_file = pkey_file;
405     *(const tls_cert_spec_t **)apr_array_push(sc->cert_specs) = cert;
406 
407 cleanup:
408     return err;
409 }
410 
parse_ciphers(cmd_parms * cmd,tls_conf_global_t * gc,const char * nop_name,int argc,char * const argv[],apr_array_header_t * ciphers)411 static const char *parse_ciphers(
412     cmd_parms *cmd,
413     tls_conf_global_t *gc,
414     const char *nop_name,
415     int argc, char *const argv[],
416     apr_array_header_t *ciphers)
417 {
418     apr_array_clear(ciphers);
419     if (argc > 1 || apr_strnatcasecmp(nop_name, argv[0])) {
420         apr_uint16_t cipher;
421         int i;
422 
423         for (i = 0; i < argc; ++i) {
424             char *name, *last = NULL;
425             const char *value = argv[i];
426 
427             name = apr_strtok(apr_pstrdup(cmd->pool, value), ":", &last);
428             while (name) {
429                 if (tls_proto_get_cipher_by_name(gc->proto, name, &cipher) != APR_SUCCESS) {
430                     return apr_pstrcat(cmd->pool, cmd->cmd->name,
431                             ": cipher not recognized '", name, "'", NULL);
432                 }
433                 APR_ARRAY_PUSH(ciphers, apr_uint16_t) = cipher;
434                 name = apr_strtok(NULL, ":", &last);
435             }
436         }
437     }
438     return NULL;
439 }
440 
tls_conf_set_preferred_ciphers(cmd_parms * cmd,void * dc,int argc,char * const argv[])441 static const char *tls_conf_set_preferred_ciphers(
442     cmd_parms *cmd, void *dc, int argc, char *const argv[])
443 {
444     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
445     const char *err = NULL;
446 
447     (void)dc;
448     if (!argc) {
449         err = "specify the TLS ciphers to prefer or 'default' for the rustls default ordering.";
450         goto cleanup;
451     }
452     err = parse_ciphers(cmd, sc->global, "default", argc, argv, sc->tls_pref_ciphers);
453 cleanup:
454     return err;
455 }
456 
tls_conf_set_suppressed_ciphers(cmd_parms * cmd,void * dc,int argc,char * const argv[])457 static const char *tls_conf_set_suppressed_ciphers(
458     cmd_parms *cmd, void *dc, int argc, char *const argv[])
459 {
460     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
461     const char *err = NULL;
462 
463     (void)dc;
464     if (!argc) {
465         err = "specify the TLS ciphers to never use or 'none'.";
466         goto cleanup;
467     }
468     err = parse_ciphers(cmd, sc->global, "none", argc, argv, sc->tls_supp_ciphers);
469 cleanup:
470     return err;
471 }
472 
tls_conf_set_honor_client_order(cmd_parms * cmd,void * dc,const char * v)473 static const char *tls_conf_set_honor_client_order(
474     cmd_parms *cmd, void *dc, const char *v)
475 {
476     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
477     int flag = flag_value(v);
478 
479     (void)dc;
480     if (TLS_FLAG_UNSET == flag) return flag_err(cmd, v);
481     sc->honor_client_order = flag;
482     return NULL;
483 }
484 
tls_conf_set_strict_sni(cmd_parms * cmd,void * dc,const char * v)485 static const char *tls_conf_set_strict_sni(
486     cmd_parms *cmd, void *dc, const char *v)
487 {
488     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
489     int flag = flag_value(v);
490 
491     (void)dc;
492     if (TLS_FLAG_UNSET == flag) return flag_err(cmd, v);
493     sc->strict_sni = flag;
494     return NULL;
495 }
496 
get_min_protocol(cmd_parms * cmd,const char * v,int * pmin)497 static const char *get_min_protocol(
498     cmd_parms *cmd, const char *v, int *pmin)
499 {
500     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
501     const char *err = NULL;
502 
503     if (!apr_strnatcasecmp("default", v)) {
504         *pmin = 0;
505     }
506     else if (*v && v[strlen(v)-1] == '+') {
507         char *name = apr_pstrdup(cmd->pool, v);
508         name[strlen(name)-1] = '\0';
509         *pmin = tls_proto_get_version_by_name(sc->global->proto, name);
510         if (!*pmin) {
511             err = apr_pstrcat(cmd->pool, cmd->cmd->name,
512                 ": unrecognized protocol version specifier (try TLSv1.2+ or TLSv1.3+): '", v, "'", NULL);
513             goto cleanup;
514         }
515     }
516     else {
517         err = apr_pstrcat(cmd->pool, cmd->cmd->name,
518             ": value must be 'default', 'TLSv1.2+' or 'TLSv1.3+': '", v, "'", NULL);
519         goto cleanup;
520     }
521 cleanup:
522     return err;
523 }
524 
tls_conf_set_protocol(cmd_parms * cmd,void * dc,const char * v)525 static const char *tls_conf_set_protocol(
526     cmd_parms *cmd, void *dc, const char *v)
527 {
528     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
529     (void)dc;
530     return get_min_protocol(cmd, v, &sc->tls_protocol_min);
531 }
532 
tls_conf_set_options(cmd_parms * cmd,void * dcv,int argc,char * const argv[])533 static const char *tls_conf_set_options(
534     cmd_parms *cmd, void *dcv, int argc, char *const argv[])
535 {
536     tls_conf_dir_t *dc = dcv;
537     const char *err = NULL, *option;
538     int i, val;
539 
540     /* Are we only having deltas (+/-) or do we reset the options? */
541     for (i = 0; i < argc; ++i) {
542         if (argv[i][0] != '+' && argv[i][0] != '-') {
543             tls_conf_dir_set_options_defaults(cmd->pool, dc);
544             break;
545         }
546     }
547 
548     for (i = 0; i < argc; ++i) {
549         option = argv[i];
550         if (!apr_strnatcasecmp("Defaults", option)) {
551             dc->std_env_vars = TLS_FLAG_FALSE;
552             dc->export_cert_vars = TLS_FLAG_FALSE;
553         }
554         else {
555             val = TLS_FLAG_TRUE;
556             if (*option == '+' || *option == '-') {
557                 val = (*option == '+')? TLS_FLAG_TRUE : TLS_FLAG_FALSE;
558                 ++option;
559             }
560 
561             if (!apr_strnatcasecmp("StdEnvVars", option)) {
562                 dc->std_env_vars = val;
563             }
564             else if (!apr_strnatcasecmp("ExportCertData", option)) {
565                 dc->export_cert_vars = val;
566             }
567             else {
568                 err = apr_pstrcat(cmd->pool, cmd->cmd->name,
569                                    ": unknown option '", option, "'", NULL);
570                 goto cleanup;
571             }
572         }
573     }
574 cleanup:
575     return err;
576 }
577 
tls_conf_set_session_cache(cmd_parms * cmd,void * dc,const char * value)578 static const char *tls_conf_set_session_cache(
579     cmd_parms *cmd, void *dc, const char *value)
580 {
581     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
582     const char *err = NULL;
583 
584     (void)dc;
585     if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) goto cleanup;
586 
587     err = tls_cache_set_specification(value, sc->global, cmd->pool, cmd->temp_pool);
588 cleanup:
589     return err;
590 }
591 
tls_conf_set_proxy_engine(cmd_parms * cmd,void * dir_conf,int flag)592 static const char *tls_conf_set_proxy_engine(cmd_parms *cmd, void *dir_conf, int flag)
593 {
594     tls_conf_dir_t *dc = dir_conf;
595     (void)cmd;
596     dc->proxy_enabled = flag ? TLS_FLAG_TRUE : TLS_FLAG_FALSE;
597     return NULL;
598 }
599 
tls_conf_set_proxy_ca(cmd_parms * cmd,void * dir_conf,const char * proxy_ca)600 static const char *tls_conf_set_proxy_ca(
601     cmd_parms *cmd, void *dir_conf, const char *proxy_ca)
602 {
603     tls_conf_dir_t *dc = dir_conf;
604     const char *err = NULL;
605 
606     if (strcasecmp(proxy_ca, "default") && NULL != (err = cmd_check_file(cmd, proxy_ca))) goto cleanup;
607     dc->proxy_ca = proxy_ca;
608 cleanup:
609     return err;
610 }
611 
tls_conf_set_proxy_protocol(cmd_parms * cmd,void * dir_conf,const char * v)612 static const char *tls_conf_set_proxy_protocol(
613     cmd_parms *cmd, void *dir_conf, const char *v)
614 {
615     tls_conf_dir_t *dc = dir_conf;
616     return get_min_protocol(cmd, v, &dc->proxy_protocol_min);
617 }
618 
tls_conf_set_proxy_preferred_ciphers(cmd_parms * cmd,void * dir_conf,int argc,char * const argv[])619 static const char *tls_conf_set_proxy_preferred_ciphers(
620     cmd_parms *cmd, void *dir_conf, int argc, char *const argv[])
621 {
622     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
623     tls_conf_dir_t *dc = dir_conf;
624     const char *err = NULL;
625 
626     if (!argc) {
627         err = "specify the proxy TLS ciphers to prefer or 'default' for the rustls default ordering.";
628         goto cleanup;
629     }
630     err = parse_ciphers(cmd, sc->global, "default", argc, argv, dc->proxy_pref_ciphers);
631 cleanup:
632     return err;
633 }
634 
tls_conf_set_proxy_suppressed_ciphers(cmd_parms * cmd,void * dir_conf,int argc,char * const argv[])635 static const char *tls_conf_set_proxy_suppressed_ciphers(
636     cmd_parms *cmd, void *dir_conf, int argc, char *const argv[])
637 {
638     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
639     tls_conf_dir_t *dc = dir_conf;
640     const char *err = NULL;
641 
642     if (!argc) {
643         err = "specify the proxy TLS ciphers to never use or 'none'.";
644         goto cleanup;
645     }
646     err = parse_ciphers(cmd, sc->global, "none", argc, argv, dc->proxy_supp_ciphers);
647 cleanup:
648     return err;
649 }
650 
651 #if TLS_CLIENT_CERTS
652 
tls_conf_set_client_ca(cmd_parms * cmd,void * dc,const char * client_ca)653 static const char *tls_conf_set_client_ca(
654     cmd_parms *cmd, void *dc, const char *client_ca)
655 {
656     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
657     const char *err;
658 
659     (void)dc;
660     if (NULL != (err = cmd_check_file(cmd, client_ca))) goto cleanup;
661     sc->client_ca = client_ca;
662 cleanup:
663     return err;
664 }
665 
tls_conf_set_client_auth(cmd_parms * cmd,void * dc,const char * mode)666 static const char *tls_conf_set_client_auth(
667     cmd_parms *cmd, void *dc, const char *mode)
668 {
669     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
670     const char *err = NULL;
671     (void)dc;
672     if (!strcasecmp(mode, "required")) {
673         sc->client_auth = TLS_CLIENT_AUTH_REQUIRED;
674     }
675     else if (!strcasecmp(mode, "optional")) {
676         sc->client_auth = TLS_CLIENT_AUTH_OPTIONAL;
677     }
678     else if (!strcasecmp(mode, "none")) {
679         sc->client_auth = TLS_CLIENT_AUTH_NONE;
680     }
681     else {
682         err = apr_pstrcat(cmd->pool, cmd->cmd->name,
683             ": unknown value: '", mode, "', use required/optional/none.", NULL);
684     }
685     return err;
686 }
687 
tls_conf_set_user_name(cmd_parms * cmd,void * dc,const char * var_user_name)688 static const char *tls_conf_set_user_name(
689     cmd_parms *cmd, void *dc, const char *var_user_name)
690 {
691     tls_conf_server_t *sc = tls_conf_server_get(cmd->server);
692     (void)dc;
693     sc->var_user_name = var_user_name;
694     return NULL;
695 }
696 
697 #endif /* if TLS_CLIENT_CERTS */
698 
699 #if TLS_MACHINE_CERTS
700 
tls_conf_add_proxy_machine_certificate(cmd_parms * cmd,void * dir_conf,const char * cert_file,const char * pkey_file)701 static const char *tls_conf_add_proxy_machine_certificate(
702     cmd_parms *cmd, void *dir_conf, const char *cert_file, const char *pkey_file)
703 {
704     tls_conf_dir_t *dc = dir_conf;
705     const char *err = NULL, *fpath;
706     tls_cert_spec_t *cert;
707 
708     (void)dc;
709     if (NULL != (err = cmd_check_file(cmd, cert_file))) goto cleanup;
710     /* key file may be NULL, in which case cert_file must contain the key PEM */
711     if (pkey_file && NULL != (err = cmd_check_file(cmd, pkey_file))) goto cleanup;
712 
713     cert = apr_pcalloc(cmd->pool, sizeof(*cert));
714     fpath = ap_server_root_relative(cmd->pool, cert_file);
715     if (!tls_util_is_file(cmd->pool, fpath)) {
716         return apr_pstrcat(cmd->pool, cmd->cmd->name,
717             ": unable to find certificate file: '", fpath, "'", NULL);
718     }
719     cert->cert_file = cert_file;
720     if (pkey_file) {
721         fpath = ap_server_root_relative(cmd->pool, pkey_file);
722         if (!tls_util_is_file(cmd->pool, fpath)) {
723             return apr_pstrcat(cmd->pool, cmd->cmd->name,
724                 ": unable to find certificate key file: '", fpath, "'", NULL);
725         }
726     }
727     cert->pkey_file = pkey_file;
728     *(const tls_cert_spec_t **)apr_array_push(dc->proxy_machine_cert_specs) = cert;
729 
730 cleanup:
731     return err;
732 }
733 
734 #endif  /* if TLS_MACHINE_CERTS */
735 
736 const command_rec tls_conf_cmds[] = {
737     AP_INIT_TAKE12("TLSCertificate", tls_conf_add_certificate, NULL, RSRC_CONF,
738         "Add a certificate to the server by specifying a file containing the "
739         "certificate PEM, followed by its chain PEMs. The PEM of the key must "
740         "either also be there or can be given as a separate file."),
741     AP_INIT_TAKE_ARGV("TLSCiphersPrefer", tls_conf_set_preferred_ciphers, NULL, RSRC_CONF,
742         "Set the TLS ciphers to prefer when negotiating with a client."),
743     AP_INIT_TAKE_ARGV("TLSCiphersSuppress", tls_conf_set_suppressed_ciphers, NULL, RSRC_CONF,
744         "Set the TLS ciphers to never use when negotiating with a client."),
745     AP_INIT_TAKE1("TLSHonorClientOrder", tls_conf_set_honor_client_order, NULL, RSRC_CONF,
746         "Set 'on' to have the server honor client preferences in cipher suites, default off."),
747     AP_INIT_TAKE1("TLSEngine", tls_conf_add_engine, NULL, RSRC_CONF,
748         "Specify an address+port where the module shall handle incoming TLS connections."),
749     AP_INIT_TAKE_ARGV("TLSOptions", tls_conf_set_options, NULL, OR_OPTIONS,
750         "En-/disables optional features in the module."),
751     AP_INIT_TAKE1("TLSProtocol", tls_conf_set_protocol, NULL, RSRC_CONF,
752         "Set the minimum TLS protocol version to use."),
753     AP_INIT_TAKE1("TLSStrictSNI", tls_conf_set_strict_sni, NULL, RSRC_CONF,
754         "Set strictness of client server name (SNI) check against hosts, default on."),
755     AP_INIT_TAKE1("TLSSessionCache", tls_conf_set_session_cache, NULL, RSRC_CONF,
756         "Set which cache to use for TLS sessions."),
757     AP_INIT_FLAG("TLSProxyEngine", tls_conf_set_proxy_engine, NULL, RSRC_CONF|PROXY_CONF,
758         "Enable TLS encryption of outgoing connections in this location/server."),
759     AP_INIT_TAKE1("TLSProxyCA", tls_conf_set_proxy_ca, NULL, RSRC_CONF|PROXY_CONF,
760         "Set the trust anchors for certificates from proxied backend servers from a PEM file."),
761     AP_INIT_TAKE1("TLSProxyProtocol", tls_conf_set_proxy_protocol, NULL, RSRC_CONF|PROXY_CONF,
762         "Set the minimum TLS protocol version to use for proxy connections."),
763     AP_INIT_TAKE_ARGV("TLSProxyCiphersPrefer", tls_conf_set_proxy_preferred_ciphers, NULL, RSRC_CONF|PROXY_CONF,
764         "Set the TLS ciphers to prefer when negotiating a proxy connection."),
765     AP_INIT_TAKE_ARGV("TLSProxyCiphersSuppress", tls_conf_set_proxy_suppressed_ciphers, NULL, RSRC_CONF|PROXY_CONF,
766         "Set the TLS ciphers to never use when negotiating a proxy connection."),
767 #if TLS_CLIENT_CERTS
768     AP_INIT_TAKE1("TLSClientCA", tls_conf_set_client_ca, NULL, RSRC_CONF,
769         "Set the trust anchors for client certificates from a PEM file."),
770     AP_INIT_TAKE1("TLSClientCertificate", tls_conf_set_client_auth, NULL, RSRC_CONF,
771         "If TLS client authentication is 'required', 'optional' or 'none'."),
772     AP_INIT_TAKE1("TLSUserName", tls_conf_set_user_name, NULL, RSRC_CONF,
773         "Set the SSL variable to be used as user name."),
774 #endif  /* if TLS_CLIENT_CERTS */
775 #if TLS_MACHINE_CERTS
776     AP_INIT_TAKE12("TLSProxyMachineCertificate", tls_conf_add_proxy_machine_certificate, NULL, RSRC_CONF|PROXY_CONF,
777         "Add a certificate to be used as client certificate on a proxy connection. "),
778 #endif  /* if TLS_MACHINE_CERTS */
779     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
780 };
781