blob: 9ac3702e4920e51a6d72c7e53afabf954a7e8f6e [file] [log] [blame]
William Lallemanddad31052020-05-14 17:47:32 +02001/*
2 *
3 * Copyright (C) 2012 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
4 * Copyright (C) 2020 HAProxy Technologies, William Lallemand <wlallemand@haproxy.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 *
12 * Configuration parsing for SSL.
13 * This file is split in 3 parts:
14 * - global section parsing
15 * - bind keyword parsing
16 * - server keyword parsing
17 *
18 * Please insert the new keywords at the right place
19 */
20
21#define _GNU_SOURCE
22#include <ctype.h>
23#include <dirent.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
31#include <sys/stat.h>
32#include <sys/types.h>
33
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020034#include <haproxy/api.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020035#include <haproxy/base64.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020036#include <haproxy/cfgparse.h>
Willy Tarreau213e9902020-06-04 14:58:24 +020037#include <haproxy/listener.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +020038#include <haproxy/openssl-compat.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020039#include <haproxy/ssl_sock.h>
William Lallemanddad31052020-05-14 17:47:32 +020040
41
42/****************** Global Section Parsing ********************************************/
43
44static int ssl_load_global_issuers_from_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010045 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +020046 char **err)
47{
48 char *path;
49 struct dirent **de_list;
50 int i, n;
51 struct stat buf;
52 char *end;
53 char fp[MAXPATHLEN+1];
54
55 if (too_many_args(1, args, err, NULL))
56 return -1;
57
58 path = args[1];
59 if (*path == 0 || stat(path, &buf)) {
60 memprintf(err, "%sglobal statement '%s' expects a directory path as an argument.\n",
61 err && *err ? *err : "", args[0]);
62 return -1;
63 }
64 if (S_ISDIR(buf.st_mode) == 0) {
65 memprintf(err, "%sglobal statement '%s': %s is not a directory.\n",
66 err && *err ? *err : "", args[0], path);
67 return -1;
68 }
69
70 /* strip trailing slashes, including first one */
71 for (end = path + strlen(path) - 1; end >= path && *end == '/'; end--)
72 *end = 0;
73 /* path already parsed? */
74 if (global_ssl.issuers_chain_path && strcmp(global_ssl.issuers_chain_path, path) == 0)
75 return 0;
76 /* overwrite old issuers_chain_path */
77 free(global_ssl.issuers_chain_path);
78 global_ssl.issuers_chain_path = strdup(path);
79 ssl_free_global_issuers();
80
81 n = scandir(path, &de_list, 0, alphasort);
82 if (n < 0) {
83 memprintf(err, "%sglobal statement '%s': unable to scan directory '%s' : %s.\n",
84 err && *err ? *err : "", args[0], path, strerror(errno));
85 return -1;
86 }
87 for (i = 0; i < n; i++) {
88 struct dirent *de = de_list[i];
89 BIO *in = NULL;
90 char *warn = NULL;
91
92 snprintf(fp, sizeof(fp), "%s/%s", path, de->d_name);
93 free(de);
94 if (stat(fp, &buf) != 0) {
95 ha_warning("unable to stat certificate from file '%s' : %s.\n", fp, strerror(errno));
96 goto next;
97 }
98 if (!S_ISREG(buf.st_mode))
99 goto next;
100
101 in = BIO_new(BIO_s_file());
102 if (in == NULL)
103 goto next;
104 if (BIO_read_filename(in, fp) <= 0)
105 goto next;
106 ssl_load_global_issuer_from_BIO(in, fp, &warn);
107 if (warn) {
108 ha_warning("%s", warn);
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100109 ha_free(&warn);
William Lallemanddad31052020-05-14 17:47:32 +0200110 }
111 next:
112 if (in)
113 BIO_free(in);
114 }
115 free(de_list);
116
117 return 0;
118}
119
William Lallemanddad31052020-05-14 17:47:32 +0200120/* parse the "ssl-mode-async" keyword in global section.
121 * Returns <0 on alert, >0 on warning, 0 on success.
122 */
123static int ssl_parse_global_ssl_async(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100124 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200125 char **err)
126{
Ilya Shipitsinbdec3ba2020-11-14 01:56:34 +0500127#ifdef SSL_MODE_ASYNC
William Lallemanddad31052020-05-14 17:47:32 +0200128 global_ssl.async = 1;
129 global.ssl_used_async_engines = nb_engines;
130 return 0;
131#else
132 memprintf(err, "'%s': openssl library does not support async mode", args[0]);
133 return -1;
134#endif
135}
136
William Lallemand5520d6f2020-05-18 13:42:49 +0200137#ifndef OPENSSL_NO_ENGINE
William Lallemanddad31052020-05-14 17:47:32 +0200138/* parse the "ssl-engine" keyword in global section.
139 * Returns <0 on alert, >0 on warning, 0 on success.
140 */
141static int ssl_parse_global_ssl_engine(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100142 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200143 char **err)
144{
145 char *algo;
146 int ret = -1;
147
148 if (*(args[1]) == 0) {
149 memprintf(err, "global statement '%s' expects a valid engine name as an argument.", args[0]);
150 return ret;
151 }
152
153 if (*(args[2]) == 0) {
154 /* if no list of algorithms is given, it defaults to ALL */
155 algo = strdup("ALL");
156 goto add_engine;
157 }
158
159 /* otherwise the expected format is ssl-engine <engine_name> algo <list of algo> */
160 if (strcmp(args[2], "algo") != 0) {
161 memprintf(err, "global statement '%s' expects to have algo keyword.", args[0]);
162 return ret;
163 }
164
165 if (*(args[3]) == 0) {
166 memprintf(err, "global statement '%s' expects algorithm names as an argument.", args[0]);
167 return ret;
168 }
169 algo = strdup(args[3]);
170
171add_engine:
172 if (ssl_init_single_engine(args[1], algo)==0) {
173 openssl_engines_initialized++;
174 ret = 0;
175 }
176 free(algo);
177 return ret;
178}
179#endif
180
181/* parse the "ssl-default-bind-ciphers" / "ssl-default-server-ciphers" keywords
182 * in global section. Returns <0 on alert, >0 on warning, 0 on success.
183 */
184static int ssl_parse_global_ciphers(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100185 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200186 char **err)
187{
188 char **target;
189
190 target = (args[0][12] == 'b') ? &global_ssl.listen_default_ciphers : &global_ssl.connect_default_ciphers;
191
192 if (too_many_args(1, args, err, NULL))
193 return -1;
194
195 if (*(args[1]) == 0) {
196 memprintf(err, "global statement '%s' expects a cipher suite as an argument.", args[0]);
197 return -1;
198 }
199
200 free(*target);
201 *target = strdup(args[1]);
202 return 0;
203}
204
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +0500205#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +0200206/* parse the "ssl-default-bind-ciphersuites" / "ssl-default-server-ciphersuites" keywords
207 * in global section. Returns <0 on alert, >0 on warning, 0 on success.
208 */
209static int ssl_parse_global_ciphersuites(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100210 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200211 char **err)
212{
213 char **target;
214
215 target = (args[0][12] == 'b') ? &global_ssl.listen_default_ciphersuites : &global_ssl.connect_default_ciphersuites;
216
217 if (too_many_args(1, args, err, NULL))
218 return -1;
219
220 if (*(args[1]) == 0) {
221 memprintf(err, "global statement '%s' expects a cipher suite as an argument.", args[0]);
222 return -1;
223 }
224
225 free(*target);
226 *target = strdup(args[1]);
227 return 0;
228}
229#endif
230
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +0500231#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +0200232/*
233 * parse the "ssl-default-bind-curves" keyword in a global section.
234 * Returns <0 on alert, >0 on warning, 0 on success.
235 */
236static int ssl_parse_global_curves(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100237 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200238 char **err)
239{
240 char **target;
241 target = &global_ssl.listen_default_curves;
242
243 if (too_many_args(1, args, err, NULL))
244 return -1;
245
246 if (*(args[1]) == 0) {
247 memprintf(err, "global statement '%s' expects a curves suite as an arguments.", args[0]);
248 return -1;
249 }
250
251 free(*target);
252 *target = strdup(args[1]);
253 return 0;
254}
255#endif
256/* parse various global tune.ssl settings consisting in positive integers.
257 * Returns <0 on alert, >0 on warning, 0 on success.
258 */
259static int ssl_parse_global_int(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100260 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200261 char **err)
262{
263 int *target;
264
265 if (strcmp(args[0], "tune.ssl.cachesize") == 0)
266 target = &global.tune.sslcachesize;
267 else if (strcmp(args[0], "tune.ssl.maxrecord") == 0)
268 target = (int *)&global_ssl.max_record;
269 else if (strcmp(args[0], "tune.ssl.ssl-ctx-cache-size") == 0)
270 target = &global_ssl.ctx_cache;
271 else if (strcmp(args[0], "maxsslconn") == 0)
272 target = &global.maxsslconn;
273 else if (strcmp(args[0], "tune.ssl.capture-cipherlist-size") == 0)
274 target = &global_ssl.capture_cipherlist;
275 else {
276 memprintf(err, "'%s' keyword not unhandled (please report this bug).", args[0]);
277 return -1;
278 }
279
280 if (too_many_args(1, args, err, NULL))
281 return -1;
282
283 if (*(args[1]) == 0) {
284 memprintf(err, "'%s' expects an integer argument.", args[0]);
285 return -1;
286 }
287
288 *target = atoi(args[1]);
289 if (*target < 0) {
290 memprintf(err, "'%s' expects a positive numeric value.", args[0]);
291 return -1;
292 }
293 return 0;
294}
295
296static int ssl_parse_global_capture_cipherlist(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100297 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200298 char **err)
299{
300 int ret;
301
302 ret = ssl_parse_global_int(args, section_type, curpx, defpx, file, line, err);
303 if (ret != 0)
304 return ret;
305
306 if (pool_head_ssl_capture) {
307 memprintf(err, "'%s' is already configured.", args[0]);
308 return -1;
309 }
310
311 pool_head_ssl_capture = create_pool("ssl-capture", sizeof(struct ssl_capture) + global_ssl.capture_cipherlist, MEM_F_SHARED);
312 if (!pool_head_ssl_capture) {
313 memprintf(err, "Out of memory error.");
314 return -1;
315 }
316 return 0;
317}
318
William Lallemand7d42ef52020-07-06 11:41:30 +0200319/* init the SSLKEYLOGFILE pool */
Ilya Shipitsin04a5a442020-11-03 14:15:38 +0500320#ifdef HAVE_OPENSSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +0200321static int ssl_parse_global_keylog(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100322 const struct proxy *defpx, const char *file, int line,
William Lallemand7d42ef52020-07-06 11:41:30 +0200323 char **err)
324{
325
326 if (too_many_args(1, args, err, NULL))
327 return -1;
328
329 if (strcmp(args[1], "on") == 0)
330 global_ssl.keylog = 1;
331 else if (strcmp(args[1], "off") == 0)
332 global_ssl.keylog = 0;
333 else {
334 memprintf(err, "'%s' expects either 'on' or 'off' but got '%s'.", args[0], args[1]);
335 return -1;
336 }
337
338 if (pool_head_ssl_keylog) /* already configured */
339 return 0;
340
341 pool_head_ssl_keylog = create_pool("ssl-keylogfile", sizeof(struct ssl_keylog), MEM_F_SHARED);
342 if (!pool_head_ssl_keylog) {
343 memprintf(err, "Out of memory error.");
344 return -1;
345 }
346
347 pool_head_ssl_keylog_str = create_pool("ssl-keylogfile-str", sizeof(char) * SSL_KEYLOG_MAX_SECRET_SIZE, MEM_F_SHARED);
348 if (!pool_head_ssl_keylog_str) {
349 memprintf(err, "Out of memory error.");
350 return -1;
351 }
352
353 return 0;
354}
355#endif
356
William Lallemanddad31052020-05-14 17:47:32 +0200357/* parse "ssl.force-private-cache".
358 * Returns <0 on alert, >0 on warning, 0 on success.
359 */
360static int ssl_parse_global_private_cache(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100361 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200362 char **err)
363{
364 if (too_many_args(0, args, err, NULL))
365 return -1;
366
367 global_ssl.private_cache = 1;
368 return 0;
369}
370
371/* parse "ssl.lifetime".
372 * Returns <0 on alert, >0 on warning, 0 on success.
373 */
374static int ssl_parse_global_lifetime(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100375 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200376 char **err)
377{
378 const char *res;
379
380 if (too_many_args(1, args, err, NULL))
381 return -1;
382
383 if (*(args[1]) == 0) {
384 memprintf(err, "'%s' expects ssl sessions <lifetime> in seconds as argument.", args[0]);
385 return -1;
386 }
387
388 res = parse_time_err(args[1], &global_ssl.life_time, TIME_UNIT_S);
389 if (res == PARSE_TIME_OVER) {
390 memprintf(err, "timer overflow in argument '%s' to <%s> (maximum value is 2147483647 s or ~68 years).",
391 args[1], args[0]);
392 return -1;
393 }
394 else if (res == PARSE_TIME_UNDER) {
395 memprintf(err, "timer underflow in argument '%s' to <%s> (minimum non-null value is 1 s).",
396 args[1], args[0]);
397 return -1;
398 }
399 else if (res) {
400 memprintf(err, "unexpected character '%c' in argument to <%s>.", *res, args[0]);
401 return -1;
402 }
403 return 0;
404}
405
406#ifndef OPENSSL_NO_DH
407/* parse "ssl-dh-param-file".
408 * Returns <0 on alert, >0 on warning, 0 on success.
409 */
410static int ssl_parse_global_dh_param_file(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100411 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200412 char **err)
413{
414 if (too_many_args(1, args, err, NULL))
415 return -1;
416
417 if (*(args[1]) == 0) {
418 memprintf(err, "'%s' expects a file path as an argument.", args[0]);
419 return -1;
420 }
421
422 if (ssl_sock_load_global_dh_param_from_file(args[1])) {
423 memprintf(err, "'%s': unable to load DH parameters from file <%s>.", args[0], args[1]);
424 return -1;
425 }
426 return 0;
427}
428
429/* parse "ssl.default-dh-param".
430 * Returns <0 on alert, >0 on warning, 0 on success.
431 */
432static int ssl_parse_global_default_dh(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100433 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200434 char **err)
435{
436 if (too_many_args(1, args, err, NULL))
437 return -1;
438
439 if (*(args[1]) == 0) {
440 memprintf(err, "'%s' expects an integer argument.", args[0]);
441 return -1;
442 }
443
444 global_ssl.default_dh_param = atoi(args[1]);
445 if (global_ssl.default_dh_param < 1024) {
446 memprintf(err, "'%s' expects a value >= 1024.", args[0]);
447 return -1;
448 }
449 return 0;
450}
451#endif
452
453
454/*
455 * parse "ssl-load-extra-files".
456 * multiple arguments are allowed: "bundle", "sctl", "ocsp", "issuer", "all", "none"
457 */
458static int ssl_parse_global_extra_files(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100459 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +0200460 char **err)
461{
462 int i;
463 int gf = SSL_GF_NONE;
464
465 if (*(args[1]) == 0)
466 goto err_arg;
467
468 for (i = 1; *args[i]; i++) {
469
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100470 if (strcmp("bundle", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200471 gf |= SSL_GF_BUNDLE;
472
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100473 } else if (strcmp("sctl", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200474 gf |= SSL_GF_SCTL;
475
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100476 } else if (strcmp("ocsp", args[i]) == 0){
William Lallemanddad31052020-05-14 17:47:32 +0200477 gf |= SSL_GF_OCSP;
478
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100479 } else if (strcmp("issuer", args[i]) == 0){
William Lallemanddad31052020-05-14 17:47:32 +0200480 gf |= SSL_GF_OCSP_ISSUER;
481
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100482 } else if (strcmp("key", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200483 gf |= SSL_GF_KEY;
484
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100485 } else if (strcmp("none", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200486 if (gf != SSL_GF_NONE)
487 goto err_alone;
488 gf = SSL_GF_NONE;
489 i++;
490 break;
491
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100492 } else if (strcmp("all", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200493 if (gf != SSL_GF_NONE)
494 goto err_alone;
495 gf = SSL_GF_ALL;
496 i++;
497 break;
498 } else {
499 goto err_arg;
500 }
501 }
502 /* break from loop but there are still arguments */
503 if (*args[i])
504 goto err_alone;
505
506 global_ssl.extra_files = gf;
507
508 return 0;
509
510err_alone:
511 memprintf(err, "'%s' 'none' and 'all' can be only used alone", args[0]);
512 return -1;
513
514err_arg:
515 memprintf(err, "'%s' expects one or multiple arguments (none, all, bundle, sctl, ocsp, issuer).", args[0]);
516 return -1;
517}
518
519
William Lallemand8e8581e2020-10-20 17:36:46 +0200520/* parse 'ssl-load-extra-del-ext */
521static int ssl_parse_global_extra_noext(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100522 const struct proxy *defpx, const char *file, int line,
William Lallemand8e8581e2020-10-20 17:36:46 +0200523 char **err)
524{
525 global_ssl.extra_files_noext = 1;
526 return 0;
527}
528
William Lallemanddad31052020-05-14 17:47:32 +0200529/***************************** Bind keyword Parsing ********************************************/
530
531/* for ca-file and ca-verify-file */
532static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char **ca_file_p, char **err)
533{
534 if (!*args[cur_arg + 1]) {
535 memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
536 return ERR_ALERT | ERR_FATAL;
537 }
538
539 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
540 memprintf(ca_file_p, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
541 else
542 memprintf(ca_file_p, "%s", args[cur_arg + 1]);
543
544 if (!ssl_store_load_locations_file(*ca_file_p)) {
545 memprintf(err, "'%s' : unable to load %s", args[cur_arg], *ca_file_p);
546 return ERR_ALERT | ERR_FATAL;
547 }
548 return 0;
549}
550
551/* parse the "ca-file" bind keyword */
552static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
553{
554 return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, err);
555}
556static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
557{
558 return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, err);
559}
560
561/* parse the "ca-verify-file" bind keyword */
562static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
563{
564 return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_verify_file, err);
565}
566static int bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
567{
568 return ssl_bind_parse_ca_verify_file(args, cur_arg, px, &conf->ssl_conf, err);
569}
570
571/* parse the "ca-sign-file" bind keyword */
572static int bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
573{
574 if (!*args[cur_arg + 1]) {
575 memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
576 return ERR_ALERT | ERR_FATAL;
577 }
578
579 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
580 memprintf(&conf->ca_sign_file, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
581 else
582 memprintf(&conf->ca_sign_file, "%s", args[cur_arg + 1]);
583
584 return 0;
585}
586
587/* parse the "ca-sign-pass" bind keyword */
588static int bind_parse_ca_sign_pass(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
589{
590 if (!*args[cur_arg + 1]) {
591 memprintf(err, "'%s' : missing CAkey password", args[cur_arg]);
592 return ERR_ALERT | ERR_FATAL;
593 }
594 memprintf(&conf->ca_sign_pass, "%s", args[cur_arg + 1]);
595 return 0;
596}
597
598/* parse the "ciphers" bind keyword */
599static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
600{
601 if (!*args[cur_arg + 1]) {
602 memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
603 return ERR_ALERT | ERR_FATAL;
604 }
605
606 free(conf->ciphers);
607 conf->ciphers = strdup(args[cur_arg + 1]);
608 return 0;
609}
610static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
611{
612 return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, err);
613}
614
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +0500615#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +0200616/* parse the "ciphersuites" bind keyword */
617static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
618{
619 if (!*args[cur_arg + 1]) {
620 memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
621 return ERR_ALERT | ERR_FATAL;
622 }
623
624 free(conf->ciphersuites);
625 conf->ciphersuites = strdup(args[cur_arg + 1]);
626 return 0;
627}
628static int bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
629{
630 return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, err);
631}
632#endif
633
634/* parse the "crt" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
635static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
636{
637 char path[MAXPATHLEN];
638
639 if (!*args[cur_arg + 1]) {
640 memprintf(err, "'%s' : missing certificate location", args[cur_arg]);
641 return ERR_ALERT | ERR_FATAL;
642 }
643
644 if ((*args[cur_arg + 1] != '/' ) && global_ssl.crt_base) {
645 if ((strlen(global_ssl.crt_base) + 1 + strlen(args[cur_arg + 1]) + 1) > MAXPATHLEN) {
646 memprintf(err, "'%s' : path too long", args[cur_arg]);
647 return ERR_ALERT | ERR_FATAL;
648 }
649 snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, args[cur_arg + 1]);
650 return ssl_sock_load_cert(path, conf, err);
651 }
652
653 return ssl_sock_load_cert(args[cur_arg + 1], conf, err);
654}
655
656/* parse the "crt-list" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
657static int bind_parse_crt_list(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
658{
659 int err_code;
660
661 if (!*args[cur_arg + 1]) {
662 memprintf(err, "'%s' : missing certificate location", args[cur_arg]);
663 return ERR_ALERT | ERR_FATAL;
664 }
665
666 err_code = ssl_sock_load_cert_list_file(args[cur_arg + 1], 0, conf, px, err);
667 if (err_code)
668 memprintf(err, "'%s' : %s", args[cur_arg], *err);
669
670 return err_code;
671}
672
673/* parse the "crl-file" bind keyword */
674static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
675{
676#ifndef X509_V_FLAG_CRL_CHECK
677 memprintf(err, "'%s' : library does not support CRL verify", args[cur_arg]);
678 return ERR_ALERT | ERR_FATAL;
679#else
680 if (!*args[cur_arg + 1]) {
681 memprintf(err, "'%s' : missing CRLfile path", args[cur_arg]);
682 return ERR_ALERT | ERR_FATAL;
683 }
684
685 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
686 memprintf(&conf->crl_file, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
687 else
688 memprintf(&conf->crl_file, "%s", args[cur_arg + 1]);
689
690 if (!ssl_store_load_locations_file(conf->crl_file)) {
691 memprintf(err, "'%s' : unable to load %s", args[cur_arg], conf->crl_file);
692 return ERR_ALERT | ERR_FATAL;
693 }
694 return 0;
695#endif
696}
697static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
698{
699 return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, err);
700}
701
702/* parse the "curves" bind keyword keyword */
703static int ssl_bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
704{
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +0500705#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +0200706 if (!*args[cur_arg + 1]) {
707 memprintf(err, "'%s' : missing curve suite", args[cur_arg]);
708 return ERR_ALERT | ERR_FATAL;
709 }
710 conf->curves = strdup(args[cur_arg + 1]);
711 return 0;
712#else
713 memprintf(err, "'%s' : library does not support curve suite", args[cur_arg]);
714 return ERR_ALERT | ERR_FATAL;
715#endif
716}
717static int bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
718{
719 return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, err);
720}
721
722/* parse the "ecdhe" bind keyword keyword */
723static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
724{
725#if HA_OPENSSL_VERSION_NUMBER < 0x0090800fL
726 memprintf(err, "'%s' : library does not support elliptic curve Diffie-Hellman (too old)", args[cur_arg]);
727 return ERR_ALERT | ERR_FATAL;
728#elif defined(OPENSSL_NO_ECDH)
729 memprintf(err, "'%s' : library does not support elliptic curve Diffie-Hellman (disabled via OPENSSL_NO_ECDH)", args[cur_arg]);
730 return ERR_ALERT | ERR_FATAL;
731#else
732 if (!*args[cur_arg + 1]) {
733 memprintf(err, "'%s' : missing named curve", args[cur_arg]);
734 return ERR_ALERT | ERR_FATAL;
735 }
736
737 conf->ecdhe = strdup(args[cur_arg + 1]);
738
739 return 0;
740#endif
741}
742static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
743{
744 return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, err);
745}
746
747/* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */
748static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
749{
750 int code;
751 char *p = args[cur_arg + 1];
752 unsigned long long *ignerr = &conf->crt_ignerr;
753
754 if (!*p) {
755 memprintf(err, "'%s' : missing error IDs list", args[cur_arg]);
756 return ERR_ALERT | ERR_FATAL;
757 }
758
759 if (strcmp(args[cur_arg], "ca-ignore-err") == 0)
760 ignerr = &conf->ca_ignerr;
761
762 if (strcmp(p, "all") == 0) {
763 *ignerr = ~0ULL;
764 return 0;
765 }
766
767 while (p) {
768 code = atoi(p);
769 if ((code <= 0) || (code > 63)) {
770 memprintf(err, "'%s' : ID '%d' out of range (1..63) in error IDs list '%s'",
771 args[cur_arg], code, args[cur_arg + 1]);
772 return ERR_ALERT | ERR_FATAL;
773 }
774 *ignerr |= 1ULL << code;
775 p = strchr(p, ',');
776 if (p)
777 p++;
778 }
779
780 return 0;
781}
782
783/* parse tls_method_options "no-xxx" and "force-xxx" */
784static int parse_tls_method_options(char *arg, struct tls_version_filter *methods, char **err)
785{
786 uint16_t v;
787 char *p;
788 p = strchr(arg, '-');
789 if (!p)
790 goto fail;
791 p++;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100792 if (strcmp(p, "sslv3") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200793 v = CONF_SSLV3;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100794 else if (strcmp(p, "tlsv10") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200795 v = CONF_TLSV10;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100796 else if (strcmp(p, "tlsv11") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200797 v = CONF_TLSV11;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100798 else if (strcmp(p, "tlsv12") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200799 v = CONF_TLSV12;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100800 else if (strcmp(p, "tlsv13") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200801 v = CONF_TLSV13;
802 else
803 goto fail;
804 if (!strncmp(arg, "no-", 3))
805 methods->flags |= methodVersions[v].flag;
806 else if (!strncmp(arg, "force-", 6))
807 methods->min = methods->max = v;
808 else
809 goto fail;
810 return 0;
811 fail:
812 memprintf(err, "'%s' : option not implemented", arg);
813 return ERR_ALERT | ERR_FATAL;
814}
815
816static int bind_parse_tls_method_options(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
817{
818 return parse_tls_method_options(args[cur_arg], &conf->ssl_conf.ssl_methods, err);
819}
820
821static int srv_parse_tls_method_options(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
822{
823 return parse_tls_method_options(args[*cur_arg], &newsrv->ssl_ctx.methods, err);
824}
825
826/* parse tls_method min/max: "ssl-min-ver" and "ssl-max-ver" */
827static int parse_tls_method_minmax(char **args, int cur_arg, struct tls_version_filter *methods, char **err)
828{
829 uint16_t i, v = 0;
830 char *argv = args[cur_arg + 1];
831 if (!*argv) {
832 memprintf(err, "'%s' : missing the ssl/tls version", args[cur_arg]);
833 return ERR_ALERT | ERR_FATAL;
834 }
835 for (i = CONF_TLSV_MIN; i <= CONF_TLSV_MAX; i++)
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100836 if (strcmp(argv, methodVersions[i].name) == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200837 v = i;
838 if (!v) {
839 memprintf(err, "'%s' : unknown ssl/tls version", args[cur_arg + 1]);
840 return ERR_ALERT | ERR_FATAL;
841 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100842 if (strcmp("ssl-min-ver", args[cur_arg]) == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200843 methods->min = v;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100844 else if (strcmp("ssl-max-ver", args[cur_arg]) == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200845 methods->max = v;
846 else {
847 memprintf(err, "'%s' : option not implemented", args[cur_arg]);
848 return ERR_ALERT | ERR_FATAL;
849 }
850 return 0;
851}
852
853static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
854{
William Lallemand8177ad92020-05-20 16:49:02 +0200855 int ret;
856
William Lallemanddad31052020-05-14 17:47:32 +0200857#if (HA_OPENSSL_VERSION_NUMBER < 0x10101000L) && !defined(OPENSSL_IS_BORINGSSL)
858 ha_warning("crt-list: ssl-min-ver and ssl-max-ver are not supported with this Openssl version (skipped).\n");
859#endif
William Lallemand8177ad92020-05-20 16:49:02 +0200860 ret = parse_tls_method_minmax(args, cur_arg, &conf->ssl_methods_cfg, err);
861 if (ret != ERR_NONE)
862 return ret;
William Lallemanddad31052020-05-14 17:47:32 +0200863
William Lallemand8177ad92020-05-20 16:49:02 +0200864 conf->ssl_methods.min = conf->ssl_methods_cfg.min;
865 conf->ssl_methods.max = conf->ssl_methods_cfg.max;
866
867 return ret;
868}
William Lallemanddad31052020-05-14 17:47:32 +0200869static int bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
870{
871 return parse_tls_method_minmax(args, cur_arg, &conf->ssl_conf.ssl_methods, err);
872}
873
874static int srv_parse_tls_method_minmax(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
875{
876 return parse_tls_method_minmax(args, *cur_arg, &newsrv->ssl_ctx.methods, err);
877}
878
879/* parse the "no-tls-tickets" bind keyword */
880static int bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
881{
882 conf->ssl_options |= BC_SSL_O_NO_TLS_TICKETS;
883 return 0;
884}
885
886/* parse the "allow-0rtt" bind keyword */
887static int ssl_bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
888{
889 conf->early_data = 1;
890 return 0;
891}
892
893static int bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
894{
895 conf->ssl_conf.early_data = 1;
896 return 0;
897}
898
899/* parse the "npn" bind keyword */
900static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
901{
902#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
903 char *p1, *p2;
904
905 if (!*args[cur_arg + 1]) {
906 memprintf(err, "'%s' : missing the comma-delimited NPN protocol suite", args[cur_arg]);
907 return ERR_ALERT | ERR_FATAL;
908 }
909
910 free(conf->npn_str);
911
912 /* the NPN string is built as a suite of (<len> <name>)*,
913 * so we reuse each comma to store the next <len> and need
914 * one more for the end of the string.
915 */
916 conf->npn_len = strlen(args[cur_arg + 1]) + 1;
917 conf->npn_str = calloc(1, conf->npn_len + 1);
918 memcpy(conf->npn_str + 1, args[cur_arg + 1], conf->npn_len);
919
920 /* replace commas with the name length */
921 p1 = conf->npn_str;
922 p2 = p1 + 1;
923 while (1) {
924 p2 = memchr(p1 + 1, ',', conf->npn_str + conf->npn_len - (p1 + 1));
925 if (!p2)
926 p2 = p1 + 1 + strlen(p1 + 1);
927
928 if (p2 - (p1 + 1) > 255) {
929 *p2 = '\0';
930 memprintf(err, "'%s' : NPN protocol name too long : '%s'", args[cur_arg], p1 + 1);
931 return ERR_ALERT | ERR_FATAL;
932 }
933
934 *p1 = p2 - (p1 + 1);
935 p1 = p2;
936
937 if (!*p2)
938 break;
939
940 *(p2++) = '\0';
941 }
942 return 0;
943#else
944 memprintf(err, "'%s' : library does not support TLS NPN extension", args[cur_arg]);
945 return ERR_ALERT | ERR_FATAL;
946#endif
947}
948
949static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
950{
951 return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, err);
952}
953
954
955/* Parses a alpn string and converts it to the right format for the SSL api */
956int ssl_sock_parse_alpn(char *arg, char **alpn_str, int *alpn_len, char **err)
957{
958 char *p1, *p2, *alpn = NULL;
959 int len, ret = 0;
960
961 *alpn_str = NULL;
962 *alpn_len = 0;
963
964 if (!*arg) {
965 memprintf(err, "missing the comma-delimited ALPN protocol suite");
966 goto error;
967 }
968
969 /* the ALPN string is built as a suite of (<len> <name>)*,
970 * so we reuse each comma to store the next <len> and need
971 * one more for the end of the string.
972 */
973 len = strlen(arg) + 1;
974 alpn = calloc(1, len+1);
975 if (!alpn) {
976 memprintf(err, "'%s' : out of memory", arg);
977 goto error;
978 }
979 memcpy(alpn+1, arg, len);
980
981 /* replace commas with the name length */
982 p1 = alpn;
983 p2 = p1 + 1;
984 while (1) {
985 p2 = memchr(p1 + 1, ',', alpn + len - (p1 + 1));
986 if (!p2)
987 p2 = p1 + 1 + strlen(p1 + 1);
988
989 if (p2 - (p1 + 1) > 255) {
990 *p2 = '\0';
991 memprintf(err, "ALPN protocol name too long : '%s'", p1 + 1);
992 goto error;
993 }
994
995 *p1 = p2 - (p1 + 1);
996 p1 = p2;
997
998 if (!*p2)
999 break;
1000
1001 *(p2++) = '\0';
1002 }
1003
1004 *alpn_str = alpn;
1005 *alpn_len = len;
1006
1007 out:
1008 return ret;
1009
1010 error:
1011 free(alpn);
1012 ret = ERR_ALERT | ERR_FATAL;
1013 goto out;
1014}
1015
1016/* parse the "alpn" bind keyword */
1017static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
1018{
1019#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1020 int ret;
1021
1022 free(conf->alpn_str);
1023
1024 ret = ssl_sock_parse_alpn(args[cur_arg + 1], &conf->alpn_str, &conf->alpn_len, err);
1025 if (ret)
1026 memprintf(err, "'%s' : %s", args[cur_arg], *err);
1027 return ret;
1028#else
1029 memprintf(err, "'%s' : library does not support TLS ALPN extension", args[cur_arg]);
1030 return ERR_ALERT | ERR_FATAL;
1031#endif
1032}
1033
1034static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1035{
1036 return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, err);
1037}
1038
1039/* parse the "ssl" bind keyword */
1040static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1041{
Frédéric Lécaillee50afbd2020-11-23 11:33:12 +01001042 /* Do not change the xprt for QUIC. */
1043 if (conf->xprt != xprt_get(XPRT_QUIC))
1044 conf->xprt = &ssl_sock;
William Lallemanddad31052020-05-14 17:47:32 +02001045 conf->is_ssl = 1;
1046
1047 if (global_ssl.listen_default_ciphers && !conf->ssl_conf.ciphers)
1048 conf->ssl_conf.ciphers = strdup(global_ssl.listen_default_ciphers);
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +05001049#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +02001050 if (global_ssl.listen_default_curves && !conf->ssl_conf.curves)
1051 conf->ssl_conf.curves = strdup(global_ssl.listen_default_curves);
1052#endif
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001053#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001054 if (global_ssl.listen_default_ciphersuites && !conf->ssl_conf.ciphersuites)
1055 conf->ssl_conf.ciphersuites = strdup(global_ssl.listen_default_ciphersuites);
1056#endif
1057 conf->ssl_options |= global_ssl.listen_default_ssloptions;
1058 conf->ssl_conf.ssl_methods.flags |= global_ssl.listen_default_sslmethods.flags;
1059 if (!conf->ssl_conf.ssl_methods.min)
1060 conf->ssl_conf.ssl_methods.min = global_ssl.listen_default_sslmethods.min;
1061 if (!conf->ssl_conf.ssl_methods.max)
1062 conf->ssl_conf.ssl_methods.max = global_ssl.listen_default_sslmethods.max;
1063
1064 return 0;
1065}
1066
1067/* parse the "prefer-client-ciphers" bind keyword */
1068static int bind_parse_pcc(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1069{
1070 conf->ssl_options |= BC_SSL_O_PREF_CLIE_CIPH;
1071 return 0;
1072}
1073
1074/* parse the "generate-certificates" bind keyword */
1075static int bind_parse_generate_certs(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1076{
1077#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
1078 conf->generate_certs = 1;
1079#else
1080 memprintf(err, "%sthis version of openssl cannot generate SSL certificates.\n",
1081 err && *err ? *err : "");
1082#endif
1083 return 0;
1084}
1085
1086/* parse the "strict-sni" bind keyword */
1087static int bind_parse_strict_sni(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1088{
1089 conf->strict_sni = 1;
1090 return 0;
1091}
1092
1093/* parse the "tls-ticket-keys" bind keyword */
1094static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1095{
1096#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
1097 FILE *f = NULL;
1098 int i = 0;
1099 char thisline[LINESIZE];
1100 struct tls_keys_ref *keys_ref = NULL;
1101
1102 if (!*args[cur_arg + 1]) {
1103 memprintf(err, "'%s' : missing TLS ticket keys file path", args[cur_arg]);
1104 goto fail;
1105 }
1106
1107 keys_ref = tlskeys_ref_lookup(args[cur_arg + 1]);
1108 if (keys_ref) {
1109 keys_ref->refcount++;
1110 conf->keys_ref = keys_ref;
1111 return 0;
1112 }
1113
1114 keys_ref = calloc(1, sizeof(*keys_ref));
1115 if (!keys_ref) {
1116 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1117 goto fail;
1118 }
1119
1120 keys_ref->tlskeys = malloc(TLS_TICKETS_NO * sizeof(union tls_sess_key));
1121 if (!keys_ref->tlskeys) {
1122 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1123 goto fail;
1124 }
1125
1126 if ((f = fopen(args[cur_arg + 1], "r")) == NULL) {
1127 memprintf(err, "'%s' : unable to load ssl tickets keys file", args[cur_arg+1]);
1128 goto fail;
1129 }
1130
1131 keys_ref->filename = strdup(args[cur_arg + 1]);
1132 if (!keys_ref->filename) {
1133 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1134 goto fail;
1135 }
1136
1137 keys_ref->key_size_bits = 0;
1138 while (fgets(thisline, sizeof(thisline), f) != NULL) {
1139 int len = strlen(thisline);
1140 int dec_size;
1141
1142 /* Strip newline characters from the end */
1143 if(thisline[len - 1] == '\n')
1144 thisline[--len] = 0;
1145
1146 if(thisline[len - 1] == '\r')
1147 thisline[--len] = 0;
1148
1149 dec_size = base64dec(thisline, len, (char *) (keys_ref->tlskeys + i % TLS_TICKETS_NO), sizeof(union tls_sess_key));
1150 if (dec_size < 0) {
1151 memprintf(err, "'%s' : unable to decode base64 key on line %d", args[cur_arg+1], i + 1);
1152 goto fail;
1153 }
1154 else if (!keys_ref->key_size_bits && (dec_size == sizeof(struct tls_sess_key_128))) {
1155 keys_ref->key_size_bits = 128;
1156 }
1157 else if (!keys_ref->key_size_bits && (dec_size == sizeof(struct tls_sess_key_256))) {
1158 keys_ref->key_size_bits = 256;
1159 }
1160 else if (((dec_size != sizeof(struct tls_sess_key_128)) && (dec_size != sizeof(struct tls_sess_key_256)))
1161 || ((dec_size == sizeof(struct tls_sess_key_128) && (keys_ref->key_size_bits != 128)))
1162 || ((dec_size == sizeof(struct tls_sess_key_256) && (keys_ref->key_size_bits != 256)))) {
1163 memprintf(err, "'%s' : wrong sized key on line %d", args[cur_arg+1], i + 1);
1164 goto fail;
1165 }
1166 i++;
1167 }
1168
1169 if (i < TLS_TICKETS_NO) {
1170 memprintf(err, "'%s' : please supply at least %d keys in the tls-tickets-file", args[cur_arg+1], TLS_TICKETS_NO);
1171 goto fail;
1172 }
1173
1174 fclose(f);
1175
1176 /* Use penultimate key for encryption, handle when TLS_TICKETS_NO = 1 */
1177 i -= 2;
1178 keys_ref->tls_ticket_enc_index = i < 0 ? 0 : i % TLS_TICKETS_NO;
1179 keys_ref->unique_id = -1;
1180 keys_ref->refcount = 1;
1181 HA_RWLOCK_INIT(&keys_ref->lock);
1182 conf->keys_ref = keys_ref;
1183
1184 LIST_ADD(&tlskeys_reference, &keys_ref->list);
1185
1186 return 0;
1187
1188 fail:
1189 if (f)
1190 fclose(f);
1191 if (keys_ref) {
1192 free(keys_ref->filename);
1193 free(keys_ref->tlskeys);
1194 free(keys_ref);
1195 }
1196 return ERR_ALERT | ERR_FATAL;
1197
1198#else
1199 memprintf(err, "'%s' : TLS ticket callback extension not supported", args[cur_arg]);
1200 return ERR_ALERT | ERR_FATAL;
1201#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
1202}
1203
1204/* parse the "verify" bind keyword */
1205static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
1206{
1207 if (!*args[cur_arg + 1]) {
1208 memprintf(err, "'%s' : missing verify method", args[cur_arg]);
1209 return ERR_ALERT | ERR_FATAL;
1210 }
1211
1212 if (strcmp(args[cur_arg + 1], "none") == 0)
1213 conf->verify = SSL_SOCK_VERIFY_NONE;
1214 else if (strcmp(args[cur_arg + 1], "optional") == 0)
1215 conf->verify = SSL_SOCK_VERIFY_OPTIONAL;
1216 else if (strcmp(args[cur_arg + 1], "required") == 0)
1217 conf->verify = SSL_SOCK_VERIFY_REQUIRED;
1218 else {
1219 memprintf(err, "'%s' : unknown verify method '%s', only 'none', 'optional', and 'required' are supported\n",
1220 args[cur_arg], args[cur_arg + 1]);
1221 return ERR_ALERT | ERR_FATAL;
1222 }
1223
1224 return 0;
1225}
1226static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1227{
1228 return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, err);
1229}
1230
1231/* parse the "no-ca-names" bind keyword */
1232static int ssl_bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
1233{
1234 conf->no_ca_names = 1;
1235 return 0;
1236}
1237static int bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1238{
1239 return ssl_bind_parse_no_ca_names(args, cur_arg, px, &conf->ssl_conf, err);
1240}
1241
1242/***************************** "server" keywords Parsing ********************************************/
1243
1244/* parse the "npn" bind keyword */
1245static int srv_parse_npn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1246{
1247#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1248 char *p1, *p2;
1249
1250 if (!*args[*cur_arg + 1]) {
1251 memprintf(err, "'%s' : missing the comma-delimited NPN protocol suite", args[*cur_arg]);
1252 return ERR_ALERT | ERR_FATAL;
1253 }
1254
1255 free(newsrv->ssl_ctx.npn_str);
1256
1257 /* the NPN string is built as a suite of (<len> <name>)*,
1258 * so we reuse each comma to store the next <len> and need
1259 * one more for the end of the string.
1260 */
1261 newsrv->ssl_ctx.npn_len = strlen(args[*cur_arg + 1]) + 1;
1262 newsrv->ssl_ctx.npn_str = calloc(1, newsrv->ssl_ctx.npn_len + 1);
1263 memcpy(newsrv->ssl_ctx.npn_str + 1, args[*cur_arg + 1],
1264 newsrv->ssl_ctx.npn_len);
1265
1266 /* replace commas with the name length */
1267 p1 = newsrv->ssl_ctx.npn_str;
1268 p2 = p1 + 1;
1269 while (1) {
1270 p2 = memchr(p1 + 1, ',', newsrv->ssl_ctx.npn_str +
1271 newsrv->ssl_ctx.npn_len - (p1 + 1));
1272 if (!p2)
1273 p2 = p1 + 1 + strlen(p1 + 1);
1274
1275 if (p2 - (p1 + 1) > 255) {
1276 *p2 = '\0';
1277 memprintf(err, "'%s' : NPN protocol name too long : '%s'", args[*cur_arg], p1 + 1);
1278 return ERR_ALERT | ERR_FATAL;
1279 }
1280
1281 *p1 = p2 - (p1 + 1);
1282 p1 = p2;
1283
1284 if (!*p2)
1285 break;
1286
1287 *(p2++) = '\0';
1288 }
1289 return 0;
1290#else
1291 memprintf(err, "'%s' : library does not support TLS NPN extension", args[*cur_arg]);
1292 return ERR_ALERT | ERR_FATAL;
1293#endif
1294}
1295
1296/* parse the "alpn" or the "check-alpn" server keyword */
1297static int srv_parse_alpn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1298{
1299#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1300 char **alpn_str;
1301 int *alpn_len;
1302 int ret;
1303
1304 if (*args[*cur_arg] == 'c') {
1305 alpn_str = &newsrv->check.alpn_str;
1306 alpn_len = &newsrv->check.alpn_len;
1307 } else {
1308 alpn_str = &newsrv->ssl_ctx.alpn_str;
1309 alpn_len = &newsrv->ssl_ctx.alpn_len;
1310
1311 }
1312
1313 free(*alpn_str);
1314 ret = ssl_sock_parse_alpn(args[*cur_arg + 1], alpn_str, alpn_len, err);
1315 if (ret)
1316 memprintf(err, "'%s' : %s", args[*cur_arg], *err);
1317 return ret;
1318#else
1319 memprintf(err, "'%s' : library does not support TLS ALPN extension", args[*cur_arg]);
1320 return ERR_ALERT | ERR_FATAL;
1321#endif
1322}
1323
1324/* parse the "ca-file" server keyword */
1325static int srv_parse_ca_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1326{
1327 if (!*args[*cur_arg + 1]) {
1328 memprintf(err, "'%s' : missing CAfile path", args[*cur_arg]);
1329 return ERR_ALERT | ERR_FATAL;
1330 }
1331
1332 if ((*args[*cur_arg + 1] != '/') && global_ssl.ca_base)
1333 memprintf(&newsrv->ssl_ctx.ca_file, "%s/%s", global_ssl.ca_base, args[*cur_arg + 1]);
1334 else
1335 memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]);
1336
1337 if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file)) {
1338 memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.ca_file);
1339 return ERR_ALERT | ERR_FATAL;
1340 }
1341 return 0;
1342}
1343
1344/* parse the "check-sni" server keyword */
1345static int srv_parse_check_sni(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1346{
1347 if (!*args[*cur_arg + 1]) {
1348 memprintf(err, "'%s' : missing SNI", args[*cur_arg]);
1349 return ERR_ALERT | ERR_FATAL;
1350 }
1351
1352 newsrv->check.sni = strdup(args[*cur_arg + 1]);
1353 if (!newsrv->check.sni) {
1354 memprintf(err, "'%s' : failed to allocate memory", args[*cur_arg]);
1355 return ERR_ALERT | ERR_FATAL;
1356 }
1357 return 0;
1358
1359}
1360
William Dauchyfc52f522020-11-14 19:25:32 +01001361/* common function to init ssl_ctx */
1362static void ssl_sock_init_srv(struct server *s)
William Lallemanddad31052020-05-14 17:47:32 +02001363{
William Dauchyfc52f522020-11-14 19:25:32 +01001364 if (global_ssl.connect_default_ciphers && !s->ssl_ctx.ciphers)
1365 s->ssl_ctx.ciphers = strdup(global_ssl.connect_default_ciphers);
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001366#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Dauchyfc52f522020-11-14 19:25:32 +01001367 if (global_ssl.connect_default_ciphersuites && !s->ssl_ctx.ciphersuites)
1368 s->ssl_ctx.ciphersuites = strdup(global_ssl.connect_default_ciphersuites);
William Lallemanddad31052020-05-14 17:47:32 +02001369#endif
William Dauchyfc52f522020-11-14 19:25:32 +01001370 s->ssl_ctx.options |= global_ssl.connect_default_ssloptions;
1371 s->ssl_ctx.methods.flags |= global_ssl.connect_default_sslmethods.flags;
1372
1373 if (!s->ssl_ctx.methods.min)
1374 s->ssl_ctx.methods.min = global_ssl.connect_default_sslmethods.min;
William Lallemanddad31052020-05-14 17:47:32 +02001375
William Dauchyfc52f522020-11-14 19:25:32 +01001376 if (!s->ssl_ctx.methods.max)
1377 s->ssl_ctx.methods.max = global_ssl.connect_default_sslmethods.max;
1378}
1379
1380/* parse the "check-ssl" server keyword */
1381static int srv_parse_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1382{
1383 newsrv->check.use_ssl = 1;
1384 ssl_sock_init_srv(newsrv);
William Lallemanddad31052020-05-14 17:47:32 +02001385 return 0;
1386}
1387
1388/* parse the "ciphers" server keyword */
1389static int srv_parse_ciphers(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1390{
1391 if (!*args[*cur_arg + 1]) {
1392 memprintf(err, "'%s' : missing cipher suite", args[*cur_arg]);
1393 return ERR_ALERT | ERR_FATAL;
1394 }
1395
1396 free(newsrv->ssl_ctx.ciphers);
1397 newsrv->ssl_ctx.ciphers = strdup(args[*cur_arg + 1]);
1398 return 0;
1399}
1400
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001401#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001402/* parse the "ciphersuites" server keyword */
1403static int srv_parse_ciphersuites(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1404{
1405 if (!*args[*cur_arg + 1]) {
1406 memprintf(err, "'%s' : missing cipher suite", args[*cur_arg]);
1407 return ERR_ALERT | ERR_FATAL;
1408 }
1409
1410 free(newsrv->ssl_ctx.ciphersuites);
1411 newsrv->ssl_ctx.ciphersuites = strdup(args[*cur_arg + 1]);
1412 return 0;
1413}
1414#endif
1415
1416/* parse the "crl-file" server keyword */
1417static int srv_parse_crl_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1418{
1419#ifndef X509_V_FLAG_CRL_CHECK
1420 memprintf(err, "'%s' : library does not support CRL verify", args[*cur_arg]);
1421 return ERR_ALERT | ERR_FATAL;
1422#else
1423 if (!*args[*cur_arg + 1]) {
1424 memprintf(err, "'%s' : missing CRLfile path", args[*cur_arg]);
1425 return ERR_ALERT | ERR_FATAL;
1426 }
1427
1428 if ((*args[*cur_arg + 1] != '/') && global_ssl.ca_base)
1429 memprintf(&newsrv->ssl_ctx.crl_file, "%s/%s", global_ssl.ca_base, args[*cur_arg + 1]);
1430 else
1431 memprintf(&newsrv->ssl_ctx.crl_file, "%s", args[*cur_arg + 1]);
1432
1433 if (!ssl_store_load_locations_file(newsrv->ssl_ctx.crl_file)) {
1434 memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.crl_file);
1435 return ERR_ALERT | ERR_FATAL;
1436 }
1437 return 0;
1438#endif
1439}
1440
1441/* parse the "crt" server keyword */
1442static int srv_parse_crt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1443{
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001444 int retval = -1;
1445 char *path = NULL;
1446
William Lallemanddad31052020-05-14 17:47:32 +02001447 if (!*args[*cur_arg + 1]) {
1448 memprintf(err, "'%s' : missing certificate file path", args[*cur_arg]);
1449 return ERR_ALERT | ERR_FATAL;
1450 }
1451
1452 if ((*args[*cur_arg + 1] != '/') && global_ssl.crt_base)
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001453 memprintf(&path, "%s/%s", global_ssl.crt_base, args[*cur_arg + 1]);
William Lallemanddad31052020-05-14 17:47:32 +02001454 else
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001455 memprintf(&path, "%s", args[*cur_arg + 1]);
1456
1457 if (path) {
1458 retval = ssl_sock_load_srv_cert(path, newsrv, err);
1459 free(path);
1460 }
William Lallemanddad31052020-05-14 17:47:32 +02001461
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001462 return retval;
William Lallemanddad31052020-05-14 17:47:32 +02001463}
1464
1465/* parse the "no-check-ssl" server keyword */
1466static int srv_parse_no_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1467{
1468 newsrv->check.use_ssl = -1;
Willy Tarreau61cfdf42021-02-20 10:46:51 +01001469 ha_free(&newsrv->ssl_ctx.ciphers);
William Lallemanddad31052020-05-14 17:47:32 +02001470 newsrv->ssl_ctx.options &= ~global_ssl.connect_default_ssloptions;
1471 return 0;
1472}
1473
1474/* parse the "no-send-proxy-v2-ssl" server keyword */
1475static int srv_parse_no_send_proxy_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1476{
1477 newsrv->pp_opts &= ~SRV_PP_V2;
1478 newsrv->pp_opts &= ~SRV_PP_V2_SSL;
1479 return 0;
1480}
1481
1482/* parse the "no-send-proxy-v2-ssl-cn" server keyword */
1483static int srv_parse_no_send_proxy_cn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1484{
1485 newsrv->pp_opts &= ~SRV_PP_V2;
1486 newsrv->pp_opts &= ~SRV_PP_V2_SSL;
1487 newsrv->pp_opts &= ~SRV_PP_V2_SSL_CN;
1488 return 0;
1489}
1490
1491/* parse the "no-ssl" server keyword */
1492static int srv_parse_no_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1493{
William Dauchyf6370442020-11-14 19:25:33 +01001494 /* if default-server have use_ssl, prepare ssl settings */
1495 if (newsrv->use_ssl == 1)
1496 ssl_sock_init_srv(newsrv);
1497 else {
Willy Tarreau61cfdf42021-02-20 10:46:51 +01001498 ha_free(&newsrv->ssl_ctx.ciphers);
William Dauchyf6370442020-11-14 19:25:33 +01001499 }
William Lallemanddad31052020-05-14 17:47:32 +02001500 newsrv->use_ssl = -1;
William Lallemanddad31052020-05-14 17:47:32 +02001501 return 0;
1502}
1503
1504/* parse the "allow-0rtt" server keyword */
1505static int srv_parse_allow_0rtt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1506{
1507 newsrv->ssl_ctx.options |= SRV_SSL_O_EARLY_DATA;
1508 return 0;
1509}
1510
1511/* parse the "no-ssl-reuse" server keyword */
1512static int srv_parse_no_ssl_reuse(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1513{
1514 newsrv->ssl_ctx.options |= SRV_SSL_O_NO_REUSE;
1515 return 0;
1516}
1517
1518/* parse the "no-tls-tickets" server keyword */
1519static int srv_parse_no_tls_tickets(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1520{
1521 newsrv->ssl_ctx.options |= SRV_SSL_O_NO_TLS_TICKETS;
1522 return 0;
1523}
1524/* parse the "send-proxy-v2-ssl" server keyword */
1525static int srv_parse_send_proxy_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1526{
1527 newsrv->pp_opts |= SRV_PP_V2;
1528 newsrv->pp_opts |= SRV_PP_V2_SSL;
1529 return 0;
1530}
1531
1532/* parse the "send-proxy-v2-ssl-cn" server keyword */
1533static int srv_parse_send_proxy_cn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1534{
1535 newsrv->pp_opts |= SRV_PP_V2;
1536 newsrv->pp_opts |= SRV_PP_V2_SSL;
1537 newsrv->pp_opts |= SRV_PP_V2_SSL_CN;
1538 return 0;
1539}
1540
1541/* parse the "sni" server keyword */
1542static int srv_parse_sni(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1543{
1544#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
1545 memprintf(err, "'%s' : the current SSL library doesn't support the SNI TLS extension", args[*cur_arg]);
1546 return ERR_ALERT | ERR_FATAL;
1547#else
1548 char *arg;
1549
1550 arg = args[*cur_arg + 1];
1551 if (!*arg) {
1552 memprintf(err, "'%s' : missing sni expression", args[*cur_arg]);
1553 return ERR_ALERT | ERR_FATAL;
1554 }
1555
1556 free(newsrv->sni_expr);
1557 newsrv->sni_expr = strdup(arg);
1558
1559 return 0;
1560#endif
1561}
1562
1563/* parse the "ssl" server keyword */
1564static int srv_parse_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1565{
1566 newsrv->use_ssl = 1;
William Dauchyfc52f522020-11-14 19:25:32 +01001567 ssl_sock_init_srv(newsrv);
William Lallemanddad31052020-05-14 17:47:32 +02001568 return 0;
1569}
1570
1571/* parse the "ssl-reuse" server keyword */
1572static int srv_parse_ssl_reuse(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1573{
1574 newsrv->ssl_ctx.options &= ~SRV_SSL_O_NO_REUSE;
1575 return 0;
1576}
1577
1578/* parse the "tls-tickets" server keyword */
1579static int srv_parse_tls_tickets(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1580{
1581 newsrv->ssl_ctx.options &= ~SRV_SSL_O_NO_TLS_TICKETS;
1582 return 0;
1583}
1584
1585/* parse the "verify" server keyword */
1586static int srv_parse_verify(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1587{
1588 if (!*args[*cur_arg + 1]) {
1589 memprintf(err, "'%s' : missing verify method", args[*cur_arg]);
1590 return ERR_ALERT | ERR_FATAL;
1591 }
1592
1593 if (strcmp(args[*cur_arg + 1], "none") == 0)
1594 newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_NONE;
1595 else if (strcmp(args[*cur_arg + 1], "required") == 0)
1596 newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_REQUIRED;
1597 else {
1598 memprintf(err, "'%s' : unknown verify method '%s', only 'none' and 'required' are supported\n",
1599 args[*cur_arg], args[*cur_arg + 1]);
1600 return ERR_ALERT | ERR_FATAL;
1601 }
1602
1603 return 0;
1604}
1605
1606/* parse the "verifyhost" server keyword */
1607static int srv_parse_verifyhost(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1608{
1609 if (!*args[*cur_arg + 1]) {
1610 memprintf(err, "'%s' : missing hostname to verify against", args[*cur_arg]);
1611 return ERR_ALERT | ERR_FATAL;
1612 }
1613
1614 free(newsrv->ssl_ctx.verify_host);
1615 newsrv->ssl_ctx.verify_host = strdup(args[*cur_arg + 1]);
1616
1617 return 0;
1618}
1619
1620/* parse the "ssl-default-bind-options" keyword in global section */
1621static int ssl_parse_default_bind_options(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001622 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +02001623 char **err) {
1624 int i = 1;
1625
1626 if (*(args[i]) == 0) {
1627 memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
1628 return -1;
1629 }
1630 while (*(args[i])) {
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001631 if (strcmp(args[i], "no-tls-tickets") == 0)
William Lallemanddad31052020-05-14 17:47:32 +02001632 global_ssl.listen_default_ssloptions |= BC_SSL_O_NO_TLS_TICKETS;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001633 else if (strcmp(args[i], "prefer-client-ciphers") == 0)
William Lallemanddad31052020-05-14 17:47:32 +02001634 global_ssl.listen_default_ssloptions |= BC_SSL_O_PREF_CLIE_CIPH;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001635 else if (strcmp(args[i], "ssl-min-ver") == 0 || strcmp(args[i], "ssl-max-ver") == 0) {
William Lallemanddad31052020-05-14 17:47:32 +02001636 if (!parse_tls_method_minmax(args, i, &global_ssl.listen_default_sslmethods, err))
1637 i++;
1638 else {
1639 memprintf(err, "%s on global statement '%s'.", *err, args[0]);
1640 return -1;
1641 }
1642 }
1643 else if (parse_tls_method_options(args[i], &global_ssl.listen_default_sslmethods, err)) {
1644 memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
1645 return -1;
1646 }
1647 i++;
1648 }
1649 return 0;
1650}
1651
1652/* parse the "ssl-default-server-options" keyword in global section */
1653static int ssl_parse_default_server_options(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001654 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +02001655 char **err) {
1656 int i = 1;
1657
1658 if (*(args[i]) == 0) {
1659 memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
1660 return -1;
1661 }
1662 while (*(args[i])) {
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001663 if (strcmp(args[i], "no-tls-tickets") == 0)
William Lallemanddad31052020-05-14 17:47:32 +02001664 global_ssl.connect_default_ssloptions |= SRV_SSL_O_NO_TLS_TICKETS;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001665 else if (strcmp(args[i], "ssl-min-ver") == 0 || strcmp(args[i], "ssl-max-ver") == 0) {
William Lallemanddad31052020-05-14 17:47:32 +02001666 if (!parse_tls_method_minmax(args, i, &global_ssl.connect_default_sslmethods, err))
1667 i++;
1668 else {
1669 memprintf(err, "%s on global statement '%s'.", *err, args[0]);
1670 return -1;
1671 }
1672 }
1673 else if (parse_tls_method_options(args[i], &global_ssl.connect_default_sslmethods, err)) {
1674 memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
1675 return -1;
1676 }
1677 i++;
1678 }
1679 return 0;
1680}
1681
1682/* parse the "ca-base" / "crt-base" keywords in global section.
1683 * Returns <0 on alert, >0 on warning, 0 on success.
1684 */
1685static int ssl_parse_global_ca_crt_base(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001686 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +02001687 char **err)
1688{
1689 char **target;
1690
1691 target = (args[0][1] == 'a') ? &global_ssl.ca_base : &global_ssl.crt_base;
1692
1693 if (too_many_args(1, args, err, NULL))
1694 return -1;
1695
1696 if (*target) {
1697 memprintf(err, "'%s' already specified.", args[0]);
1698 return -1;
1699 }
1700
1701 if (*(args[1]) == 0) {
1702 memprintf(err, "global statement '%s' expects a directory path as an argument.", args[0]);
1703 return -1;
1704 }
1705 *target = strdup(args[1]);
1706 return 0;
1707}
1708
1709/* parse the "ssl-skip-self-issued-ca" keyword in global section. */
1710static int ssl_parse_skip_self_issued_ca(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001711 const struct proxy *defpx, const char *file, int line,
William Lallemanddad31052020-05-14 17:47:32 +02001712 char **err)
1713{
William Lallemand9a1d8392020-08-10 17:28:23 +02001714#ifdef SSL_CTX_build_cert_chain
William Lallemanddad31052020-05-14 17:47:32 +02001715 global_ssl.skip_self_issued_ca = 1;
1716 return 0;
William Lallemand9a1d8392020-08-10 17:28:23 +02001717#else
1718 memprintf(err, "global statement '%s' requires at least OpenSSL 1.0.2.", args[0]);
1719 return -1;
1720#endif
William Lallemanddad31052020-05-14 17:47:32 +02001721}
1722
1723
1724
1725
1726
1727/* Note: must not be declared <const> as its list will be overwritten.
1728 * Please take care of keeping this list alphabetically sorted, doing so helps
1729 * all code contributors.
1730 * Optional keywords are also declared with a NULL ->parse() function so that
1731 * the config parser can report an appropriate error when a known keyword was
1732 * not enabled.
1733 */
1734
1735/* the <ssl_bind_kws> keywords are used for crt-list parsing, they *MUST* be safe
1736 * with their proxy argument NULL and must only fill the ssl_bind_conf */
1737struct ssl_bind_kw ssl_bind_kws[] = {
1738 { "allow-0rtt", ssl_bind_parse_allow_0rtt, 0 }, /* allow 0-RTT */
1739 { "alpn", ssl_bind_parse_alpn, 1 }, /* set ALPN supported protocols */
1740 { "ca-file", ssl_bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */
1741 { "ca-verify-file", ssl_bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */
1742 { "ciphers", ssl_bind_parse_ciphers, 1 }, /* set SSL cipher suite */
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001743#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001744 { "ciphersuites", ssl_bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */
1745#endif
1746 { "crl-file", ssl_bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */
1747 { "curves", ssl_bind_parse_curves, 1 }, /* set SSL curve suite */
1748 { "ecdhe", ssl_bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
1749 { "no-ca-names", ssl_bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
1750 { "npn", ssl_bind_parse_npn, 1 }, /* set NPN supported protocols */
1751 { "ssl-min-ver", ssl_bind_parse_tls_method_minmax,1 }, /* minimum version */
1752 { "ssl-max-ver", ssl_bind_parse_tls_method_minmax,1 }, /* maximum version */
1753 { "verify", ssl_bind_parse_verify, 1 }, /* set SSL verify method */
1754 { NULL, NULL, 0 },
1755};
1756
1757/* no initcall for ssl_bind_kws, these ones are parsed in the parser loop */
1758
1759static struct bind_kw_list bind_kws = { "SSL", { }, {
1760 { "allow-0rtt", bind_parse_allow_0rtt, 0 }, /* Allow 0RTT */
1761 { "alpn", bind_parse_alpn, 1 }, /* set ALPN supported protocols */
1762 { "ca-file", bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */
1763 { "ca-verify-file", bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */
1764 { "ca-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth > 0 */
1765 { "ca-sign-file", bind_parse_ca_sign_file, 1 }, /* set CAFile used to generate and sign server certs */
1766 { "ca-sign-pass", bind_parse_ca_sign_pass, 1 }, /* set CAKey passphrase */
1767 { "ciphers", bind_parse_ciphers, 1 }, /* set SSL cipher suite */
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001768#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001769 { "ciphersuites", bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */
1770#endif
1771 { "crl-file", bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */
1772 { "crt", bind_parse_crt, 1 }, /* load SSL certificates from this location */
1773 { "crt-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth == 0 */
1774 { "crt-list", bind_parse_crt_list, 1 }, /* load a list of crt from this location */
1775 { "curves", bind_parse_curves, 1 }, /* set SSL curve suite */
1776 { "ecdhe", bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
1777 { "force-sslv3", bind_parse_tls_method_options, 0 }, /* force SSLv3 */
1778 { "force-tlsv10", bind_parse_tls_method_options, 0 }, /* force TLSv10 */
1779 { "force-tlsv11", bind_parse_tls_method_options, 0 }, /* force TLSv11 */
1780 { "force-tlsv12", bind_parse_tls_method_options, 0 }, /* force TLSv12 */
1781 { "force-tlsv13", bind_parse_tls_method_options, 0 }, /* force TLSv13 */
1782 { "generate-certificates", bind_parse_generate_certs, 0 }, /* enable the server certificates generation */
1783 { "no-ca-names", bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
1784 { "no-sslv3", bind_parse_tls_method_options, 0 }, /* disable SSLv3 */
1785 { "no-tlsv10", bind_parse_tls_method_options, 0 }, /* disable TLSv10 */
1786 { "no-tlsv11", bind_parse_tls_method_options, 0 }, /* disable TLSv11 */
1787 { "no-tlsv12", bind_parse_tls_method_options, 0 }, /* disable TLSv12 */
1788 { "no-tlsv13", bind_parse_tls_method_options, 0 }, /* disable TLSv13 */
1789 { "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
1790 { "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */
1791 { "ssl-min-ver", bind_parse_tls_method_minmax, 1 }, /* minimum version */
1792 { "ssl-max-ver", bind_parse_tls_method_minmax, 1 }, /* maximum version */
1793 { "strict-sni", bind_parse_strict_sni, 0 }, /* refuse negotiation if sni doesn't match a certificate */
1794 { "tls-ticket-keys", bind_parse_tls_ticket_keys, 1 }, /* set file to load TLS ticket keys from */
1795 { "verify", bind_parse_verify, 1 }, /* set SSL verify method */
1796 { "npn", bind_parse_npn, 1 }, /* set NPN supported protocols */
1797 { "prefer-client-ciphers", bind_parse_pcc, 0 }, /* prefer client ciphers */
1798 { NULL, NULL, 0 },
1799}};
1800
1801INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
1802
1803/* Note: must not be declared <const> as its list will be overwritten.
1804 * Please take care of keeping this list alphabetically sorted, doing so helps
1805 * all code contributors.
1806 * Optional keywords are also declared with a NULL ->parse() function so that
1807 * the config parser can report an appropriate error when a known keyword was
1808 * not enabled.
1809 */
1810static struct srv_kw_list srv_kws = { "SSL", { }, {
1811 { "allow-0rtt", srv_parse_allow_0rtt, 0, 1 }, /* Allow using early data on this server */
1812 { "alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN supported protocols */
1813 { "ca-file", srv_parse_ca_file, 1, 1 }, /* set CAfile to process verify server cert */
1814 { "check-alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN used for checks */
1815 { "check-sni", srv_parse_check_sni, 1, 1 }, /* set SNI */
1816 { "check-ssl", srv_parse_check_ssl, 0, 1 }, /* enable SSL for health checks */
1817 { "ciphers", srv_parse_ciphers, 1, 1 }, /* select the cipher suite */
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001818#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001819 { "ciphersuites", srv_parse_ciphersuites, 1, 1 }, /* select the cipher suite */
1820#endif
1821 { "crl-file", srv_parse_crl_file, 1, 1 }, /* set certificate revocation list file use on server cert verify */
1822 { "crt", srv_parse_crt, 1, 1 }, /* set client certificate */
1823 { "force-sslv3", srv_parse_tls_method_options, 0, 1 }, /* force SSLv3 */
1824 { "force-tlsv10", srv_parse_tls_method_options, 0, 1 }, /* force TLSv10 */
1825 { "force-tlsv11", srv_parse_tls_method_options, 0, 1 }, /* force TLSv11 */
1826 { "force-tlsv12", srv_parse_tls_method_options, 0, 1 }, /* force TLSv12 */
1827 { "force-tlsv13", srv_parse_tls_method_options, 0, 1 }, /* force TLSv13 */
1828 { "no-check-ssl", srv_parse_no_check_ssl, 0, 1 }, /* disable SSL for health checks */
1829 { "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1 }, /* do not send PROXY protocol header v2 with SSL info */
1830 { "no-send-proxy-v2-ssl-cn", srv_parse_no_send_proxy_cn, 0, 1 }, /* do not send PROXY protocol header v2 with CN */
1831 { "no-ssl", srv_parse_no_ssl, 0, 1 }, /* disable SSL processing */
1832 { "no-ssl-reuse", srv_parse_no_ssl_reuse, 0, 1 }, /* disable session reuse */
1833 { "no-sslv3", srv_parse_tls_method_options, 0, 0 }, /* disable SSLv3 */
1834 { "no-tlsv10", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv10 */
1835 { "no-tlsv11", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv11 */
1836 { "no-tlsv12", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv12 */
1837 { "no-tlsv13", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv13 */
1838 { "no-tls-tickets", srv_parse_no_tls_tickets, 0, 1 }, /* disable session resumption tickets */
1839 { "npn", srv_parse_npn, 1, 1 }, /* Set NPN supported protocols */
1840 { "send-proxy-v2-ssl", srv_parse_send_proxy_ssl, 0, 1 }, /* send PROXY protocol header v2 with SSL info */
1841 { "send-proxy-v2-ssl-cn", srv_parse_send_proxy_cn, 0, 1 }, /* send PROXY protocol header v2 with CN */
1842 { "sni", srv_parse_sni, 1, 1 }, /* send SNI extension */
1843 { "ssl", srv_parse_ssl, 0, 1 }, /* enable SSL processing */
1844 { "ssl-min-ver", srv_parse_tls_method_minmax, 1, 1 }, /* minimum version */
1845 { "ssl-max-ver", srv_parse_tls_method_minmax, 1, 1 }, /* maximum version */
1846 { "ssl-reuse", srv_parse_ssl_reuse, 0, 1 }, /* enable session reuse */
1847 { "tls-tickets", srv_parse_tls_tickets, 0, 1 }, /* enable session resumption tickets */
1848 { "verify", srv_parse_verify, 1, 1 }, /* set SSL verify method */
1849 { "verifyhost", srv_parse_verifyhost, 1, 1 }, /* require that SSL cert verifies for hostname */
1850 { NULL, NULL, 0, 0 },
1851}};
1852
1853INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
1854
1855static struct cfg_kw_list cfg_kws = {ILH, {
1856 { CFG_GLOBAL, "ca-base", ssl_parse_global_ca_crt_base },
1857 { CFG_GLOBAL, "crt-base", ssl_parse_global_ca_crt_base },
1858 { CFG_GLOBAL, "issuers-chain-path", ssl_load_global_issuers_from_path },
1859 { CFG_GLOBAL, "maxsslconn", ssl_parse_global_int },
1860 { CFG_GLOBAL, "ssl-default-bind-options", ssl_parse_default_bind_options },
1861 { CFG_GLOBAL, "ssl-default-server-options", ssl_parse_default_server_options },
1862#ifndef OPENSSL_NO_DH
1863 { CFG_GLOBAL, "ssl-dh-param-file", ssl_parse_global_dh_param_file },
1864#endif
1865 { CFG_GLOBAL, "ssl-mode-async", ssl_parse_global_ssl_async },
1866#ifndef OPENSSL_NO_ENGINE
1867 { CFG_GLOBAL, "ssl-engine", ssl_parse_global_ssl_engine },
1868#endif
1869 { CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
1870 { CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
1871#ifndef OPENSSL_NO_DH
1872 { CFG_GLOBAL, "tune.ssl.default-dh-param", ssl_parse_global_default_dh },
1873#endif
1874 { CFG_GLOBAL, "tune.ssl.force-private-cache", ssl_parse_global_private_cache },
1875 { CFG_GLOBAL, "tune.ssl.lifetime", ssl_parse_global_lifetime },
1876 { CFG_GLOBAL, "tune.ssl.maxrecord", ssl_parse_global_int },
1877 { CFG_GLOBAL, "tune.ssl.ssl-ctx-cache-size", ssl_parse_global_int },
1878 { CFG_GLOBAL, "tune.ssl.capture-cipherlist-size", ssl_parse_global_capture_cipherlist },
Ilya Shipitsin04a5a442020-11-03 14:15:38 +05001879#ifdef HAVE_OPENSSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001880 { CFG_GLOBAL, "tune.ssl.keylog", ssl_parse_global_keylog },
1881#endif
William Lallemanddad31052020-05-14 17:47:32 +02001882 { CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
1883 { CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +05001884#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +02001885 { CFG_GLOBAL, "ssl-default-bind-curves", ssl_parse_global_curves },
1886#endif
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001887#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001888 { CFG_GLOBAL, "ssl-default-bind-ciphersuites", ssl_parse_global_ciphersuites },
1889 { CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
1890#endif
1891 { CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
William Lallemand8e8581e2020-10-20 17:36:46 +02001892 { CFG_GLOBAL, "ssl-load-extra-del-ext", ssl_parse_global_extra_noext },
William Lallemanddad31052020-05-14 17:47:32 +02001893 { 0, NULL, NULL },
1894}};
1895
1896INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);