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