blob: faacc0ee04946a2e98aa64ba4aa15572111f8b46 [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,
45 struct proxy *defpx, const char *file, int line,
46 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);
109 free(warn);
110 warn = NULL;
111 }
112 next:
113 if (in)
114 BIO_free(in);
115 }
116 free(de_list);
117
118 return 0;
119}
120
William Lallemanddad31052020-05-14 17:47:32 +0200121/* parse the "ssl-mode-async" keyword in global section.
122 * Returns <0 on alert, >0 on warning, 0 on success.
123 */
124static int ssl_parse_global_ssl_async(char **args, int section_type, struct proxy *curpx,
125 struct proxy *defpx, const char *file, int line,
126 char **err)
127{
Ilya Shipitsinbdec3ba2020-11-14 01:56:34 +0500128#ifdef SSL_MODE_ASYNC
William Lallemanddad31052020-05-14 17:47:32 +0200129 global_ssl.async = 1;
130 global.ssl_used_async_engines = nb_engines;
131 return 0;
132#else
133 memprintf(err, "'%s': openssl library does not support async mode", args[0]);
134 return -1;
135#endif
136}
137
William Lallemand5520d6f2020-05-18 13:42:49 +0200138#ifndef OPENSSL_NO_ENGINE
William Lallemanddad31052020-05-14 17:47:32 +0200139/* parse the "ssl-engine" keyword in global section.
140 * Returns <0 on alert, >0 on warning, 0 on success.
141 */
142static int ssl_parse_global_ssl_engine(char **args, int section_type, struct proxy *curpx,
143 struct proxy *defpx, const char *file, int line,
144 char **err)
145{
146 char *algo;
147 int ret = -1;
148
149 if (*(args[1]) == 0) {
150 memprintf(err, "global statement '%s' expects a valid engine name as an argument.", args[0]);
151 return ret;
152 }
153
154 if (*(args[2]) == 0) {
155 /* if no list of algorithms is given, it defaults to ALL */
156 algo = strdup("ALL");
157 goto add_engine;
158 }
159
160 /* otherwise the expected format is ssl-engine <engine_name> algo <list of algo> */
161 if (strcmp(args[2], "algo") != 0) {
162 memprintf(err, "global statement '%s' expects to have algo keyword.", args[0]);
163 return ret;
164 }
165
166 if (*(args[3]) == 0) {
167 memprintf(err, "global statement '%s' expects algorithm names as an argument.", args[0]);
168 return ret;
169 }
170 algo = strdup(args[3]);
171
172add_engine:
173 if (ssl_init_single_engine(args[1], algo)==0) {
174 openssl_engines_initialized++;
175 ret = 0;
176 }
177 free(algo);
178 return ret;
179}
180#endif
181
182/* parse the "ssl-default-bind-ciphers" / "ssl-default-server-ciphers" keywords
183 * in global section. Returns <0 on alert, >0 on warning, 0 on success.
184 */
185static int ssl_parse_global_ciphers(char **args, int section_type, struct proxy *curpx,
186 struct proxy *defpx, const char *file, int line,
187 char **err)
188{
189 char **target;
190
191 target = (args[0][12] == 'b') ? &global_ssl.listen_default_ciphers : &global_ssl.connect_default_ciphers;
192
193 if (too_many_args(1, args, err, NULL))
194 return -1;
195
196 if (*(args[1]) == 0) {
197 memprintf(err, "global statement '%s' expects a cipher suite as an argument.", args[0]);
198 return -1;
199 }
200
201 free(*target);
202 *target = strdup(args[1]);
203 return 0;
204}
205
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +0500206#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +0200207/* parse the "ssl-default-bind-ciphersuites" / "ssl-default-server-ciphersuites" keywords
208 * in global section. Returns <0 on alert, >0 on warning, 0 on success.
209 */
210static int ssl_parse_global_ciphersuites(char **args, int section_type, struct proxy *curpx,
211 struct proxy *defpx, const char *file, int line,
212 char **err)
213{
214 char **target;
215
216 target = (args[0][12] == 'b') ? &global_ssl.listen_default_ciphersuites : &global_ssl.connect_default_ciphersuites;
217
218 if (too_many_args(1, args, err, NULL))
219 return -1;
220
221 if (*(args[1]) == 0) {
222 memprintf(err, "global statement '%s' expects a cipher suite as an argument.", args[0]);
223 return -1;
224 }
225
226 free(*target);
227 *target = strdup(args[1]);
228 return 0;
229}
230#endif
231
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +0500232#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +0200233/*
234 * parse the "ssl-default-bind-curves" keyword in a global section.
235 * Returns <0 on alert, >0 on warning, 0 on success.
236 */
237static int ssl_parse_global_curves(char **args, int section_type, struct proxy *curpx,
238 struct proxy *defpx, const char *file, int line,
239 char **err)
240{
241 char **target;
242 target = &global_ssl.listen_default_curves;
243
244 if (too_many_args(1, args, err, NULL))
245 return -1;
246
247 if (*(args[1]) == 0) {
248 memprintf(err, "global statement '%s' expects a curves suite as an arguments.", args[0]);
249 return -1;
250 }
251
252 free(*target);
253 *target = strdup(args[1]);
254 return 0;
255}
256#endif
257/* parse various global tune.ssl settings consisting in positive integers.
258 * Returns <0 on alert, >0 on warning, 0 on success.
259 */
260static int ssl_parse_global_int(char **args, int section_type, struct proxy *curpx,
261 struct proxy *defpx, const char *file, int line,
262 char **err)
263{
264 int *target;
265
266 if (strcmp(args[0], "tune.ssl.cachesize") == 0)
267 target = &global.tune.sslcachesize;
268 else if (strcmp(args[0], "tune.ssl.maxrecord") == 0)
269 target = (int *)&global_ssl.max_record;
270 else if (strcmp(args[0], "tune.ssl.ssl-ctx-cache-size") == 0)
271 target = &global_ssl.ctx_cache;
272 else if (strcmp(args[0], "maxsslconn") == 0)
273 target = &global.maxsslconn;
274 else if (strcmp(args[0], "tune.ssl.capture-cipherlist-size") == 0)
275 target = &global_ssl.capture_cipherlist;
276 else {
277 memprintf(err, "'%s' keyword not unhandled (please report this bug).", args[0]);
278 return -1;
279 }
280
281 if (too_many_args(1, args, err, NULL))
282 return -1;
283
284 if (*(args[1]) == 0) {
285 memprintf(err, "'%s' expects an integer argument.", args[0]);
286 return -1;
287 }
288
289 *target = atoi(args[1]);
290 if (*target < 0) {
291 memprintf(err, "'%s' expects a positive numeric value.", args[0]);
292 return -1;
293 }
294 return 0;
295}
296
297static int ssl_parse_global_capture_cipherlist(char **args, int section_type, struct proxy *curpx,
298 struct proxy *defpx, const char *file, int line,
299 char **err)
300{
301 int ret;
302
303 ret = ssl_parse_global_int(args, section_type, curpx, defpx, file, line, err);
304 if (ret != 0)
305 return ret;
306
307 if (pool_head_ssl_capture) {
308 memprintf(err, "'%s' is already configured.", args[0]);
309 return -1;
310 }
311
312 pool_head_ssl_capture = create_pool("ssl-capture", sizeof(struct ssl_capture) + global_ssl.capture_cipherlist, MEM_F_SHARED);
313 if (!pool_head_ssl_capture) {
314 memprintf(err, "Out of memory error.");
315 return -1;
316 }
317 return 0;
318}
319
William Lallemand7d42ef52020-07-06 11:41:30 +0200320/* init the SSLKEYLOGFILE pool */
Ilya Shipitsin04a5a442020-11-03 14:15:38 +0500321#ifdef HAVE_OPENSSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +0200322static int ssl_parse_global_keylog(char **args, int section_type, struct proxy *curpx,
323 struct proxy *defpx, const char *file, int line,
324 char **err)
325{
326
327 if (too_many_args(1, args, err, NULL))
328 return -1;
329
330 if (strcmp(args[1], "on") == 0)
331 global_ssl.keylog = 1;
332 else if (strcmp(args[1], "off") == 0)
333 global_ssl.keylog = 0;
334 else {
335 memprintf(err, "'%s' expects either 'on' or 'off' but got '%s'.", args[0], args[1]);
336 return -1;
337 }
338
339 if (pool_head_ssl_keylog) /* already configured */
340 return 0;
341
342 pool_head_ssl_keylog = create_pool("ssl-keylogfile", sizeof(struct ssl_keylog), MEM_F_SHARED);
343 if (!pool_head_ssl_keylog) {
344 memprintf(err, "Out of memory error.");
345 return -1;
346 }
347
348 pool_head_ssl_keylog_str = create_pool("ssl-keylogfile-str", sizeof(char) * SSL_KEYLOG_MAX_SECRET_SIZE, MEM_F_SHARED);
349 if (!pool_head_ssl_keylog_str) {
350 memprintf(err, "Out of memory error.");
351 return -1;
352 }
353
354 return 0;
355}
356#endif
357
William Lallemanddad31052020-05-14 17:47:32 +0200358/* parse "ssl.force-private-cache".
359 * Returns <0 on alert, >0 on warning, 0 on success.
360 */
361static int ssl_parse_global_private_cache(char **args, int section_type, struct proxy *curpx,
362 struct proxy *defpx, const char *file, int line,
363 char **err)
364{
365 if (too_many_args(0, args, err, NULL))
366 return -1;
367
368 global_ssl.private_cache = 1;
369 return 0;
370}
371
372/* parse "ssl.lifetime".
373 * Returns <0 on alert, >0 on warning, 0 on success.
374 */
375static int ssl_parse_global_lifetime(char **args, int section_type, struct proxy *curpx,
376 struct proxy *defpx, const char *file, int line,
377 char **err)
378{
379 const char *res;
380
381 if (too_many_args(1, args, err, NULL))
382 return -1;
383
384 if (*(args[1]) == 0) {
385 memprintf(err, "'%s' expects ssl sessions <lifetime> in seconds as argument.", args[0]);
386 return -1;
387 }
388
389 res = parse_time_err(args[1], &global_ssl.life_time, TIME_UNIT_S);
390 if (res == PARSE_TIME_OVER) {
391 memprintf(err, "timer overflow in argument '%s' to <%s> (maximum value is 2147483647 s or ~68 years).",
392 args[1], args[0]);
393 return -1;
394 }
395 else if (res == PARSE_TIME_UNDER) {
396 memprintf(err, "timer underflow in argument '%s' to <%s> (minimum non-null value is 1 s).",
397 args[1], args[0]);
398 return -1;
399 }
400 else if (res) {
401 memprintf(err, "unexpected character '%c' in argument to <%s>.", *res, args[0]);
402 return -1;
403 }
404 return 0;
405}
406
407#ifndef OPENSSL_NO_DH
408/* parse "ssl-dh-param-file".
409 * Returns <0 on alert, >0 on warning, 0 on success.
410 */
411static int ssl_parse_global_dh_param_file(char **args, int section_type, struct proxy *curpx,
412 struct proxy *defpx, const char *file, int line,
413 char **err)
414{
415 if (too_many_args(1, args, err, NULL))
416 return -1;
417
418 if (*(args[1]) == 0) {
419 memprintf(err, "'%s' expects a file path as an argument.", args[0]);
420 return -1;
421 }
422
423 if (ssl_sock_load_global_dh_param_from_file(args[1])) {
424 memprintf(err, "'%s': unable to load DH parameters from file <%s>.", args[0], args[1]);
425 return -1;
426 }
427 return 0;
428}
429
430/* parse "ssl.default-dh-param".
431 * Returns <0 on alert, >0 on warning, 0 on success.
432 */
433static int ssl_parse_global_default_dh(char **args, int section_type, struct proxy *curpx,
434 struct proxy *defpx, const char *file, int line,
435 char **err)
436{
437 if (too_many_args(1, args, err, NULL))
438 return -1;
439
440 if (*(args[1]) == 0) {
441 memprintf(err, "'%s' expects an integer argument.", args[0]);
442 return -1;
443 }
444
445 global_ssl.default_dh_param = atoi(args[1]);
446 if (global_ssl.default_dh_param < 1024) {
447 memprintf(err, "'%s' expects a value >= 1024.", args[0]);
448 return -1;
449 }
450 return 0;
451}
452#endif
453
454
455/*
456 * parse "ssl-load-extra-files".
457 * multiple arguments are allowed: "bundle", "sctl", "ocsp", "issuer", "all", "none"
458 */
459static int ssl_parse_global_extra_files(char **args, int section_type, struct proxy *curpx,
460 struct proxy *defpx, const char *file, int line,
461 char **err)
462{
463 int i;
464 int gf = SSL_GF_NONE;
465
466 if (*(args[1]) == 0)
467 goto err_arg;
468
469 for (i = 1; *args[i]; i++) {
470
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100471 if (strcmp("bundle", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200472 gf |= SSL_GF_BUNDLE;
473
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100474 } else if (strcmp("sctl", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200475 gf |= SSL_GF_SCTL;
476
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100477 } else if (strcmp("ocsp", args[i]) == 0){
William Lallemanddad31052020-05-14 17:47:32 +0200478 gf |= SSL_GF_OCSP;
479
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100480 } else if (strcmp("issuer", args[i]) == 0){
William Lallemanddad31052020-05-14 17:47:32 +0200481 gf |= SSL_GF_OCSP_ISSUER;
482
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100483 } else if (strcmp("key", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200484 gf |= SSL_GF_KEY;
485
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100486 } else if (strcmp("none", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200487 if (gf != SSL_GF_NONE)
488 goto err_alone;
489 gf = SSL_GF_NONE;
490 i++;
491 break;
492
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100493 } else if (strcmp("all", args[i]) == 0) {
William Lallemanddad31052020-05-14 17:47:32 +0200494 if (gf != SSL_GF_NONE)
495 goto err_alone;
496 gf = SSL_GF_ALL;
497 i++;
498 break;
499 } else {
500 goto err_arg;
501 }
502 }
503 /* break from loop but there are still arguments */
504 if (*args[i])
505 goto err_alone;
506
507 global_ssl.extra_files = gf;
508
509 return 0;
510
511err_alone:
512 memprintf(err, "'%s' 'none' and 'all' can be only used alone", args[0]);
513 return -1;
514
515err_arg:
516 memprintf(err, "'%s' expects one or multiple arguments (none, all, bundle, sctl, ocsp, issuer).", args[0]);
517 return -1;
518}
519
520
William Lallemand8e8581e2020-10-20 17:36:46 +0200521/* parse 'ssl-load-extra-del-ext */
522static int ssl_parse_global_extra_noext(char **args, int section_type, struct proxy *curpx,
523 struct proxy *defpx, const char *file, int line,
524 char **err)
525{
526 global_ssl.extra_files_noext = 1;
527 return 0;
528}
529
William Lallemanddad31052020-05-14 17:47:32 +0200530/***************************** Bind keyword Parsing ********************************************/
531
532/* for ca-file and ca-verify-file */
533static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char **ca_file_p, char **err)
534{
535 if (!*args[cur_arg + 1]) {
536 memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
537 return ERR_ALERT | ERR_FATAL;
538 }
539
540 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
541 memprintf(ca_file_p, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
542 else
543 memprintf(ca_file_p, "%s", args[cur_arg + 1]);
544
545 if (!ssl_store_load_locations_file(*ca_file_p)) {
546 memprintf(err, "'%s' : unable to load %s", args[cur_arg], *ca_file_p);
547 return ERR_ALERT | ERR_FATAL;
548 }
549 return 0;
550}
551
552/* parse the "ca-file" bind keyword */
553static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
554{
555 return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, err);
556}
557static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
558{
559 return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, err);
560}
561
562/* parse the "ca-verify-file" bind keyword */
563static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
564{
565 return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_verify_file, err);
566}
567static int bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
568{
569 return ssl_bind_parse_ca_verify_file(args, cur_arg, px, &conf->ssl_conf, err);
570}
571
572/* parse the "ca-sign-file" bind keyword */
573static int bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
574{
575 if (!*args[cur_arg + 1]) {
576 memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
577 return ERR_ALERT | ERR_FATAL;
578 }
579
580 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
581 memprintf(&conf->ca_sign_file, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
582 else
583 memprintf(&conf->ca_sign_file, "%s", args[cur_arg + 1]);
584
585 return 0;
586}
587
588/* parse the "ca-sign-pass" bind keyword */
589static int bind_parse_ca_sign_pass(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
590{
591 if (!*args[cur_arg + 1]) {
592 memprintf(err, "'%s' : missing CAkey password", args[cur_arg]);
593 return ERR_ALERT | ERR_FATAL;
594 }
595 memprintf(&conf->ca_sign_pass, "%s", args[cur_arg + 1]);
596 return 0;
597}
598
599/* parse the "ciphers" bind keyword */
600static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
601{
602 if (!*args[cur_arg + 1]) {
603 memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
604 return ERR_ALERT | ERR_FATAL;
605 }
606
607 free(conf->ciphers);
608 conf->ciphers = strdup(args[cur_arg + 1]);
609 return 0;
610}
611static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
612{
613 return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, err);
614}
615
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +0500616#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +0200617/* parse the "ciphersuites" bind keyword */
618static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
619{
620 if (!*args[cur_arg + 1]) {
621 memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
622 return ERR_ALERT | ERR_FATAL;
623 }
624
625 free(conf->ciphersuites);
626 conf->ciphersuites = strdup(args[cur_arg + 1]);
627 return 0;
628}
629static int bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
630{
631 return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, err);
632}
633#endif
634
635/* parse the "crt" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
636static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
637{
638 char path[MAXPATHLEN];
639
640 if (!*args[cur_arg + 1]) {
641 memprintf(err, "'%s' : missing certificate location", args[cur_arg]);
642 return ERR_ALERT | ERR_FATAL;
643 }
644
645 if ((*args[cur_arg + 1] != '/' ) && global_ssl.crt_base) {
646 if ((strlen(global_ssl.crt_base) + 1 + strlen(args[cur_arg + 1]) + 1) > MAXPATHLEN) {
647 memprintf(err, "'%s' : path too long", args[cur_arg]);
648 return ERR_ALERT | ERR_FATAL;
649 }
650 snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, args[cur_arg + 1]);
651 return ssl_sock_load_cert(path, conf, err);
652 }
653
654 return ssl_sock_load_cert(args[cur_arg + 1], conf, err);
655}
656
657/* parse the "crt-list" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
658static int bind_parse_crt_list(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
659{
660 int err_code;
661
662 if (!*args[cur_arg + 1]) {
663 memprintf(err, "'%s' : missing certificate location", args[cur_arg]);
664 return ERR_ALERT | ERR_FATAL;
665 }
666
667 err_code = ssl_sock_load_cert_list_file(args[cur_arg + 1], 0, conf, px, err);
668 if (err_code)
669 memprintf(err, "'%s' : %s", args[cur_arg], *err);
670
671 return err_code;
672}
673
674/* parse the "crl-file" bind keyword */
675static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
676{
677#ifndef X509_V_FLAG_CRL_CHECK
678 memprintf(err, "'%s' : library does not support CRL verify", args[cur_arg]);
679 return ERR_ALERT | ERR_FATAL;
680#else
681 if (!*args[cur_arg + 1]) {
682 memprintf(err, "'%s' : missing CRLfile path", args[cur_arg]);
683 return ERR_ALERT | ERR_FATAL;
684 }
685
686 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
687 memprintf(&conf->crl_file, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
688 else
689 memprintf(&conf->crl_file, "%s", args[cur_arg + 1]);
690
691 if (!ssl_store_load_locations_file(conf->crl_file)) {
692 memprintf(err, "'%s' : unable to load %s", args[cur_arg], conf->crl_file);
693 return ERR_ALERT | ERR_FATAL;
694 }
695 return 0;
696#endif
697}
698static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
699{
700 return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, err);
701}
702
703/* parse the "curves" bind keyword keyword */
704static int ssl_bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
705{
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +0500706#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +0200707 if (!*args[cur_arg + 1]) {
708 memprintf(err, "'%s' : missing curve suite", args[cur_arg]);
709 return ERR_ALERT | ERR_FATAL;
710 }
711 conf->curves = strdup(args[cur_arg + 1]);
712 return 0;
713#else
714 memprintf(err, "'%s' : library does not support curve suite", args[cur_arg]);
715 return ERR_ALERT | ERR_FATAL;
716#endif
717}
718static int bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
719{
720 return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, err);
721}
722
723/* parse the "ecdhe" bind keyword keyword */
724static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
725{
726#if HA_OPENSSL_VERSION_NUMBER < 0x0090800fL
727 memprintf(err, "'%s' : library does not support elliptic curve Diffie-Hellman (too old)", args[cur_arg]);
728 return ERR_ALERT | ERR_FATAL;
729#elif defined(OPENSSL_NO_ECDH)
730 memprintf(err, "'%s' : library does not support elliptic curve Diffie-Hellman (disabled via OPENSSL_NO_ECDH)", args[cur_arg]);
731 return ERR_ALERT | ERR_FATAL;
732#else
733 if (!*args[cur_arg + 1]) {
734 memprintf(err, "'%s' : missing named curve", args[cur_arg]);
735 return ERR_ALERT | ERR_FATAL;
736 }
737
738 conf->ecdhe = strdup(args[cur_arg + 1]);
739
740 return 0;
741#endif
742}
743static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
744{
745 return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, err);
746}
747
748/* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */
749static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
750{
751 int code;
752 char *p = args[cur_arg + 1];
753 unsigned long long *ignerr = &conf->crt_ignerr;
754
755 if (!*p) {
756 memprintf(err, "'%s' : missing error IDs list", args[cur_arg]);
757 return ERR_ALERT | ERR_FATAL;
758 }
759
760 if (strcmp(args[cur_arg], "ca-ignore-err") == 0)
761 ignerr = &conf->ca_ignerr;
762
763 if (strcmp(p, "all") == 0) {
764 *ignerr = ~0ULL;
765 return 0;
766 }
767
768 while (p) {
769 code = atoi(p);
770 if ((code <= 0) || (code > 63)) {
771 memprintf(err, "'%s' : ID '%d' out of range (1..63) in error IDs list '%s'",
772 args[cur_arg], code, args[cur_arg + 1]);
773 return ERR_ALERT | ERR_FATAL;
774 }
775 *ignerr |= 1ULL << code;
776 p = strchr(p, ',');
777 if (p)
778 p++;
779 }
780
781 return 0;
782}
783
784/* parse tls_method_options "no-xxx" and "force-xxx" */
785static int parse_tls_method_options(char *arg, struct tls_version_filter *methods, char **err)
786{
787 uint16_t v;
788 char *p;
789 p = strchr(arg, '-');
790 if (!p)
791 goto fail;
792 p++;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100793 if (strcmp(p, "sslv3") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200794 v = CONF_SSLV3;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100795 else if (strcmp(p, "tlsv10") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200796 v = CONF_TLSV10;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100797 else if (strcmp(p, "tlsv11") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200798 v = CONF_TLSV11;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100799 else if (strcmp(p, "tlsv12") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200800 v = CONF_TLSV12;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100801 else if (strcmp(p, "tlsv13") == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200802 v = CONF_TLSV13;
803 else
804 goto fail;
805 if (!strncmp(arg, "no-", 3))
806 methods->flags |= methodVersions[v].flag;
807 else if (!strncmp(arg, "force-", 6))
808 methods->min = methods->max = v;
809 else
810 goto fail;
811 return 0;
812 fail:
813 memprintf(err, "'%s' : option not implemented", arg);
814 return ERR_ALERT | ERR_FATAL;
815}
816
817static int bind_parse_tls_method_options(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
818{
819 return parse_tls_method_options(args[cur_arg], &conf->ssl_conf.ssl_methods, err);
820}
821
822static int srv_parse_tls_method_options(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
823{
824 return parse_tls_method_options(args[*cur_arg], &newsrv->ssl_ctx.methods, err);
825}
826
827/* parse tls_method min/max: "ssl-min-ver" and "ssl-max-ver" */
828static int parse_tls_method_minmax(char **args, int cur_arg, struct tls_version_filter *methods, char **err)
829{
830 uint16_t i, v = 0;
831 char *argv = args[cur_arg + 1];
832 if (!*argv) {
833 memprintf(err, "'%s' : missing the ssl/tls version", args[cur_arg]);
834 return ERR_ALERT | ERR_FATAL;
835 }
836 for (i = CONF_TLSV_MIN; i <= CONF_TLSV_MAX; i++)
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100837 if (strcmp(argv, methodVersions[i].name) == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200838 v = i;
839 if (!v) {
840 memprintf(err, "'%s' : unknown ssl/tls version", args[cur_arg + 1]);
841 return ERR_ALERT | ERR_FATAL;
842 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100843 if (strcmp("ssl-min-ver", args[cur_arg]) == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200844 methods->min = v;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100845 else if (strcmp("ssl-max-ver", args[cur_arg]) == 0)
William Lallemanddad31052020-05-14 17:47:32 +0200846 methods->max = v;
847 else {
848 memprintf(err, "'%s' : option not implemented", args[cur_arg]);
849 return ERR_ALERT | ERR_FATAL;
850 }
851 return 0;
852}
853
854static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
855{
William Lallemand8177ad92020-05-20 16:49:02 +0200856 int ret;
857
William Lallemanddad31052020-05-14 17:47:32 +0200858#if (HA_OPENSSL_VERSION_NUMBER < 0x10101000L) && !defined(OPENSSL_IS_BORINGSSL)
859 ha_warning("crt-list: ssl-min-ver and ssl-max-ver are not supported with this Openssl version (skipped).\n");
860#endif
William Lallemand8177ad92020-05-20 16:49:02 +0200861 ret = parse_tls_method_minmax(args, cur_arg, &conf->ssl_methods_cfg, err);
862 if (ret != ERR_NONE)
863 return ret;
William Lallemanddad31052020-05-14 17:47:32 +0200864
William Lallemand8177ad92020-05-20 16:49:02 +0200865 conf->ssl_methods.min = conf->ssl_methods_cfg.min;
866 conf->ssl_methods.max = conf->ssl_methods_cfg.max;
867
868 return ret;
869}
William Lallemanddad31052020-05-14 17:47:32 +0200870static int bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
871{
872 return parse_tls_method_minmax(args, cur_arg, &conf->ssl_conf.ssl_methods, err);
873}
874
875static int srv_parse_tls_method_minmax(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
876{
877 return parse_tls_method_minmax(args, *cur_arg, &newsrv->ssl_ctx.methods, err);
878}
879
880/* parse the "no-tls-tickets" bind keyword */
881static int bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
882{
883 conf->ssl_options |= BC_SSL_O_NO_TLS_TICKETS;
884 return 0;
885}
886
887/* parse the "allow-0rtt" bind keyword */
888static int ssl_bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
889{
890 conf->early_data = 1;
891 return 0;
892}
893
894static int bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
895{
896 conf->ssl_conf.early_data = 1;
897 return 0;
898}
899
900/* parse the "npn" bind keyword */
901static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
902{
903#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
904 char *p1, *p2;
905
906 if (!*args[cur_arg + 1]) {
907 memprintf(err, "'%s' : missing the comma-delimited NPN protocol suite", args[cur_arg]);
908 return ERR_ALERT | ERR_FATAL;
909 }
910
911 free(conf->npn_str);
912
913 /* the NPN string is built as a suite of (<len> <name>)*,
914 * so we reuse each comma to store the next <len> and need
915 * one more for the end of the string.
916 */
917 conf->npn_len = strlen(args[cur_arg + 1]) + 1;
918 conf->npn_str = calloc(1, conf->npn_len + 1);
919 memcpy(conf->npn_str + 1, args[cur_arg + 1], conf->npn_len);
920
921 /* replace commas with the name length */
922 p1 = conf->npn_str;
923 p2 = p1 + 1;
924 while (1) {
925 p2 = memchr(p1 + 1, ',', conf->npn_str + conf->npn_len - (p1 + 1));
926 if (!p2)
927 p2 = p1 + 1 + strlen(p1 + 1);
928
929 if (p2 - (p1 + 1) > 255) {
930 *p2 = '\0';
931 memprintf(err, "'%s' : NPN protocol name too long : '%s'", args[cur_arg], p1 + 1);
932 return ERR_ALERT | ERR_FATAL;
933 }
934
935 *p1 = p2 - (p1 + 1);
936 p1 = p2;
937
938 if (!*p2)
939 break;
940
941 *(p2++) = '\0';
942 }
943 return 0;
944#else
945 memprintf(err, "'%s' : library does not support TLS NPN extension", args[cur_arg]);
946 return ERR_ALERT | ERR_FATAL;
947#endif
948}
949
950static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
951{
952 return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, err);
953}
954
955
956/* Parses a alpn string and converts it to the right format for the SSL api */
957int ssl_sock_parse_alpn(char *arg, char **alpn_str, int *alpn_len, char **err)
958{
959 char *p1, *p2, *alpn = NULL;
960 int len, ret = 0;
961
962 *alpn_str = NULL;
963 *alpn_len = 0;
964
965 if (!*arg) {
966 memprintf(err, "missing the comma-delimited ALPN protocol suite");
967 goto error;
968 }
969
970 /* the ALPN string is built as a suite of (<len> <name>)*,
971 * so we reuse each comma to store the next <len> and need
972 * one more for the end of the string.
973 */
974 len = strlen(arg) + 1;
975 alpn = calloc(1, len+1);
976 if (!alpn) {
977 memprintf(err, "'%s' : out of memory", arg);
978 goto error;
979 }
980 memcpy(alpn+1, arg, len);
981
982 /* replace commas with the name length */
983 p1 = alpn;
984 p2 = p1 + 1;
985 while (1) {
986 p2 = memchr(p1 + 1, ',', alpn + len - (p1 + 1));
987 if (!p2)
988 p2 = p1 + 1 + strlen(p1 + 1);
989
990 if (p2 - (p1 + 1) > 255) {
991 *p2 = '\0';
992 memprintf(err, "ALPN protocol name too long : '%s'", p1 + 1);
993 goto error;
994 }
995
996 *p1 = p2 - (p1 + 1);
997 p1 = p2;
998
999 if (!*p2)
1000 break;
1001
1002 *(p2++) = '\0';
1003 }
1004
1005 *alpn_str = alpn;
1006 *alpn_len = len;
1007
1008 out:
1009 return ret;
1010
1011 error:
1012 free(alpn);
1013 ret = ERR_ALERT | ERR_FATAL;
1014 goto out;
1015}
1016
1017/* parse the "alpn" bind keyword */
1018static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
1019{
1020#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1021 int ret;
1022
1023 free(conf->alpn_str);
1024
1025 ret = ssl_sock_parse_alpn(args[cur_arg + 1], &conf->alpn_str, &conf->alpn_len, err);
1026 if (ret)
1027 memprintf(err, "'%s' : %s", args[cur_arg], *err);
1028 return ret;
1029#else
1030 memprintf(err, "'%s' : library does not support TLS ALPN extension", args[cur_arg]);
1031 return ERR_ALERT | ERR_FATAL;
1032#endif
1033}
1034
1035static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1036{
1037 return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, err);
1038}
1039
1040/* parse the "ssl" bind keyword */
1041static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1042{
Frédéric Lécaillee50afbd2020-11-23 11:33:12 +01001043 /* Do not change the xprt for QUIC. */
1044 if (conf->xprt != xprt_get(XPRT_QUIC))
1045 conf->xprt = &ssl_sock;
William Lallemanddad31052020-05-14 17:47:32 +02001046 conf->is_ssl = 1;
1047
1048 if (global_ssl.listen_default_ciphers && !conf->ssl_conf.ciphers)
1049 conf->ssl_conf.ciphers = strdup(global_ssl.listen_default_ciphers);
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +05001050#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +02001051 if (global_ssl.listen_default_curves && !conf->ssl_conf.curves)
1052 conf->ssl_conf.curves = strdup(global_ssl.listen_default_curves);
1053#endif
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001054#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001055 if (global_ssl.listen_default_ciphersuites && !conf->ssl_conf.ciphersuites)
1056 conf->ssl_conf.ciphersuites = strdup(global_ssl.listen_default_ciphersuites);
1057#endif
1058 conf->ssl_options |= global_ssl.listen_default_ssloptions;
1059 conf->ssl_conf.ssl_methods.flags |= global_ssl.listen_default_sslmethods.flags;
1060 if (!conf->ssl_conf.ssl_methods.min)
1061 conf->ssl_conf.ssl_methods.min = global_ssl.listen_default_sslmethods.min;
1062 if (!conf->ssl_conf.ssl_methods.max)
1063 conf->ssl_conf.ssl_methods.max = global_ssl.listen_default_sslmethods.max;
1064
1065 return 0;
1066}
1067
1068/* parse the "prefer-client-ciphers" bind keyword */
1069static int bind_parse_pcc(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1070{
1071 conf->ssl_options |= BC_SSL_O_PREF_CLIE_CIPH;
1072 return 0;
1073}
1074
1075/* parse the "generate-certificates" bind keyword */
1076static int bind_parse_generate_certs(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1077{
1078#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
1079 conf->generate_certs = 1;
1080#else
1081 memprintf(err, "%sthis version of openssl cannot generate SSL certificates.\n",
1082 err && *err ? *err : "");
1083#endif
1084 return 0;
1085}
1086
1087/* parse the "strict-sni" bind keyword */
1088static int bind_parse_strict_sni(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1089{
1090 conf->strict_sni = 1;
1091 return 0;
1092}
1093
1094/* parse the "tls-ticket-keys" bind keyword */
1095static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1096{
1097#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
1098 FILE *f = NULL;
1099 int i = 0;
1100 char thisline[LINESIZE];
1101 struct tls_keys_ref *keys_ref = NULL;
1102
1103 if (!*args[cur_arg + 1]) {
1104 memprintf(err, "'%s' : missing TLS ticket keys file path", args[cur_arg]);
1105 goto fail;
1106 }
1107
1108 keys_ref = tlskeys_ref_lookup(args[cur_arg + 1]);
1109 if (keys_ref) {
1110 keys_ref->refcount++;
1111 conf->keys_ref = keys_ref;
1112 return 0;
1113 }
1114
1115 keys_ref = calloc(1, sizeof(*keys_ref));
1116 if (!keys_ref) {
1117 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1118 goto fail;
1119 }
1120
1121 keys_ref->tlskeys = malloc(TLS_TICKETS_NO * sizeof(union tls_sess_key));
1122 if (!keys_ref->tlskeys) {
1123 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1124 goto fail;
1125 }
1126
1127 if ((f = fopen(args[cur_arg + 1], "r")) == NULL) {
1128 memprintf(err, "'%s' : unable to load ssl tickets keys file", args[cur_arg+1]);
1129 goto fail;
1130 }
1131
1132 keys_ref->filename = strdup(args[cur_arg + 1]);
1133 if (!keys_ref->filename) {
1134 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1135 goto fail;
1136 }
1137
1138 keys_ref->key_size_bits = 0;
1139 while (fgets(thisline, sizeof(thisline), f) != NULL) {
1140 int len = strlen(thisline);
1141 int dec_size;
1142
1143 /* Strip newline characters from the end */
1144 if(thisline[len - 1] == '\n')
1145 thisline[--len] = 0;
1146
1147 if(thisline[len - 1] == '\r')
1148 thisline[--len] = 0;
1149
1150 dec_size = base64dec(thisline, len, (char *) (keys_ref->tlskeys + i % TLS_TICKETS_NO), sizeof(union tls_sess_key));
1151 if (dec_size < 0) {
1152 memprintf(err, "'%s' : unable to decode base64 key on line %d", args[cur_arg+1], i + 1);
1153 goto fail;
1154 }
1155 else if (!keys_ref->key_size_bits && (dec_size == sizeof(struct tls_sess_key_128))) {
1156 keys_ref->key_size_bits = 128;
1157 }
1158 else if (!keys_ref->key_size_bits && (dec_size == sizeof(struct tls_sess_key_256))) {
1159 keys_ref->key_size_bits = 256;
1160 }
1161 else if (((dec_size != sizeof(struct tls_sess_key_128)) && (dec_size != sizeof(struct tls_sess_key_256)))
1162 || ((dec_size == sizeof(struct tls_sess_key_128) && (keys_ref->key_size_bits != 128)))
1163 || ((dec_size == sizeof(struct tls_sess_key_256) && (keys_ref->key_size_bits != 256)))) {
1164 memprintf(err, "'%s' : wrong sized key on line %d", args[cur_arg+1], i + 1);
1165 goto fail;
1166 }
1167 i++;
1168 }
1169
1170 if (i < TLS_TICKETS_NO) {
1171 memprintf(err, "'%s' : please supply at least %d keys in the tls-tickets-file", args[cur_arg+1], TLS_TICKETS_NO);
1172 goto fail;
1173 }
1174
1175 fclose(f);
1176
1177 /* Use penultimate key for encryption, handle when TLS_TICKETS_NO = 1 */
1178 i -= 2;
1179 keys_ref->tls_ticket_enc_index = i < 0 ? 0 : i % TLS_TICKETS_NO;
1180 keys_ref->unique_id = -1;
1181 keys_ref->refcount = 1;
1182 HA_RWLOCK_INIT(&keys_ref->lock);
1183 conf->keys_ref = keys_ref;
1184
1185 LIST_ADD(&tlskeys_reference, &keys_ref->list);
1186
1187 return 0;
1188
1189 fail:
1190 if (f)
1191 fclose(f);
1192 if (keys_ref) {
1193 free(keys_ref->filename);
1194 free(keys_ref->tlskeys);
1195 free(keys_ref);
1196 }
1197 return ERR_ALERT | ERR_FATAL;
1198
1199#else
1200 memprintf(err, "'%s' : TLS ticket callback extension not supported", args[cur_arg]);
1201 return ERR_ALERT | ERR_FATAL;
1202#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
1203}
1204
1205/* parse the "verify" bind keyword */
1206static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
1207{
1208 if (!*args[cur_arg + 1]) {
1209 memprintf(err, "'%s' : missing verify method", args[cur_arg]);
1210 return ERR_ALERT | ERR_FATAL;
1211 }
1212
1213 if (strcmp(args[cur_arg + 1], "none") == 0)
1214 conf->verify = SSL_SOCK_VERIFY_NONE;
1215 else if (strcmp(args[cur_arg + 1], "optional") == 0)
1216 conf->verify = SSL_SOCK_VERIFY_OPTIONAL;
1217 else if (strcmp(args[cur_arg + 1], "required") == 0)
1218 conf->verify = SSL_SOCK_VERIFY_REQUIRED;
1219 else {
1220 memprintf(err, "'%s' : unknown verify method '%s', only 'none', 'optional', and 'required' are supported\n",
1221 args[cur_arg], args[cur_arg + 1]);
1222 return ERR_ALERT | ERR_FATAL;
1223 }
1224
1225 return 0;
1226}
1227static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1228{
1229 return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, err);
1230}
1231
1232/* parse the "no-ca-names" bind keyword */
1233static int ssl_bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
1234{
1235 conf->no_ca_names = 1;
1236 return 0;
1237}
1238static int bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1239{
1240 return ssl_bind_parse_no_ca_names(args, cur_arg, px, &conf->ssl_conf, err);
1241}
1242
1243/***************************** "server" keywords Parsing ********************************************/
1244
1245/* parse the "npn" bind keyword */
1246static int srv_parse_npn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1247{
1248#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1249 char *p1, *p2;
1250
1251 if (!*args[*cur_arg + 1]) {
1252 memprintf(err, "'%s' : missing the comma-delimited NPN protocol suite", args[*cur_arg]);
1253 return ERR_ALERT | ERR_FATAL;
1254 }
1255
1256 free(newsrv->ssl_ctx.npn_str);
1257
1258 /* the NPN string is built as a suite of (<len> <name>)*,
1259 * so we reuse each comma to store the next <len> and need
1260 * one more for the end of the string.
1261 */
1262 newsrv->ssl_ctx.npn_len = strlen(args[*cur_arg + 1]) + 1;
1263 newsrv->ssl_ctx.npn_str = calloc(1, newsrv->ssl_ctx.npn_len + 1);
1264 memcpy(newsrv->ssl_ctx.npn_str + 1, args[*cur_arg + 1],
1265 newsrv->ssl_ctx.npn_len);
1266
1267 /* replace commas with the name length */
1268 p1 = newsrv->ssl_ctx.npn_str;
1269 p2 = p1 + 1;
1270 while (1) {
1271 p2 = memchr(p1 + 1, ',', newsrv->ssl_ctx.npn_str +
1272 newsrv->ssl_ctx.npn_len - (p1 + 1));
1273 if (!p2)
1274 p2 = p1 + 1 + strlen(p1 + 1);
1275
1276 if (p2 - (p1 + 1) > 255) {
1277 *p2 = '\0';
1278 memprintf(err, "'%s' : NPN protocol name too long : '%s'", args[*cur_arg], p1 + 1);
1279 return ERR_ALERT | ERR_FATAL;
1280 }
1281
1282 *p1 = p2 - (p1 + 1);
1283 p1 = p2;
1284
1285 if (!*p2)
1286 break;
1287
1288 *(p2++) = '\0';
1289 }
1290 return 0;
1291#else
1292 memprintf(err, "'%s' : library does not support TLS NPN extension", args[*cur_arg]);
1293 return ERR_ALERT | ERR_FATAL;
1294#endif
1295}
1296
1297/* parse the "alpn" or the "check-alpn" server keyword */
1298static int srv_parse_alpn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1299{
1300#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1301 char **alpn_str;
1302 int *alpn_len;
1303 int ret;
1304
1305 if (*args[*cur_arg] == 'c') {
1306 alpn_str = &newsrv->check.alpn_str;
1307 alpn_len = &newsrv->check.alpn_len;
1308 } else {
1309 alpn_str = &newsrv->ssl_ctx.alpn_str;
1310 alpn_len = &newsrv->ssl_ctx.alpn_len;
1311
1312 }
1313
1314 free(*alpn_str);
1315 ret = ssl_sock_parse_alpn(args[*cur_arg + 1], alpn_str, alpn_len, err);
1316 if (ret)
1317 memprintf(err, "'%s' : %s", args[*cur_arg], *err);
1318 return ret;
1319#else
1320 memprintf(err, "'%s' : library does not support TLS ALPN extension", args[*cur_arg]);
1321 return ERR_ALERT | ERR_FATAL;
1322#endif
1323}
1324
1325/* parse the "ca-file" server keyword */
1326static int srv_parse_ca_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1327{
1328 if (!*args[*cur_arg + 1]) {
1329 memprintf(err, "'%s' : missing CAfile path", args[*cur_arg]);
1330 return ERR_ALERT | ERR_FATAL;
1331 }
1332
1333 if ((*args[*cur_arg + 1] != '/') && global_ssl.ca_base)
1334 memprintf(&newsrv->ssl_ctx.ca_file, "%s/%s", global_ssl.ca_base, args[*cur_arg + 1]);
1335 else
1336 memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]);
1337
1338 if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file)) {
1339 memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.ca_file);
1340 return ERR_ALERT | ERR_FATAL;
1341 }
1342 return 0;
1343}
1344
1345/* parse the "check-sni" server keyword */
1346static int srv_parse_check_sni(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1347{
1348 if (!*args[*cur_arg + 1]) {
1349 memprintf(err, "'%s' : missing SNI", args[*cur_arg]);
1350 return ERR_ALERT | ERR_FATAL;
1351 }
1352
1353 newsrv->check.sni = strdup(args[*cur_arg + 1]);
1354 if (!newsrv->check.sni) {
1355 memprintf(err, "'%s' : failed to allocate memory", args[*cur_arg]);
1356 return ERR_ALERT | ERR_FATAL;
1357 }
1358 return 0;
1359
1360}
1361
William Dauchyfc52f522020-11-14 19:25:32 +01001362/* common function to init ssl_ctx */
1363static void ssl_sock_init_srv(struct server *s)
William Lallemanddad31052020-05-14 17:47:32 +02001364{
William Dauchyfc52f522020-11-14 19:25:32 +01001365 if (global_ssl.connect_default_ciphers && !s->ssl_ctx.ciphers)
1366 s->ssl_ctx.ciphers = strdup(global_ssl.connect_default_ciphers);
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001367#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Dauchyfc52f522020-11-14 19:25:32 +01001368 if (global_ssl.connect_default_ciphersuites && !s->ssl_ctx.ciphersuites)
1369 s->ssl_ctx.ciphersuites = strdup(global_ssl.connect_default_ciphersuites);
William Lallemanddad31052020-05-14 17:47:32 +02001370#endif
William Dauchyfc52f522020-11-14 19:25:32 +01001371 s->ssl_ctx.options |= global_ssl.connect_default_ssloptions;
1372 s->ssl_ctx.methods.flags |= global_ssl.connect_default_sslmethods.flags;
1373
1374 if (!s->ssl_ctx.methods.min)
1375 s->ssl_ctx.methods.min = global_ssl.connect_default_sslmethods.min;
William Lallemanddad31052020-05-14 17:47:32 +02001376
William Dauchyfc52f522020-11-14 19:25:32 +01001377 if (!s->ssl_ctx.methods.max)
1378 s->ssl_ctx.methods.max = global_ssl.connect_default_sslmethods.max;
1379}
1380
1381/* parse the "check-ssl" server keyword */
1382static int srv_parse_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1383{
1384 newsrv->check.use_ssl = 1;
1385 ssl_sock_init_srv(newsrv);
William Lallemanddad31052020-05-14 17:47:32 +02001386 return 0;
1387}
1388
1389/* parse the "ciphers" server keyword */
1390static int srv_parse_ciphers(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1391{
1392 if (!*args[*cur_arg + 1]) {
1393 memprintf(err, "'%s' : missing cipher suite", args[*cur_arg]);
1394 return ERR_ALERT | ERR_FATAL;
1395 }
1396
1397 free(newsrv->ssl_ctx.ciphers);
1398 newsrv->ssl_ctx.ciphers = strdup(args[*cur_arg + 1]);
1399 return 0;
1400}
1401
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001402#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001403/* parse the "ciphersuites" server keyword */
1404static int srv_parse_ciphersuites(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1405{
1406 if (!*args[*cur_arg + 1]) {
1407 memprintf(err, "'%s' : missing cipher suite", args[*cur_arg]);
1408 return ERR_ALERT | ERR_FATAL;
1409 }
1410
1411 free(newsrv->ssl_ctx.ciphersuites);
1412 newsrv->ssl_ctx.ciphersuites = strdup(args[*cur_arg + 1]);
1413 return 0;
1414}
1415#endif
1416
1417/* parse the "crl-file" server keyword */
1418static int srv_parse_crl_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1419{
1420#ifndef X509_V_FLAG_CRL_CHECK
1421 memprintf(err, "'%s' : library does not support CRL verify", args[*cur_arg]);
1422 return ERR_ALERT | ERR_FATAL;
1423#else
1424 if (!*args[*cur_arg + 1]) {
1425 memprintf(err, "'%s' : missing CRLfile path", args[*cur_arg]);
1426 return ERR_ALERT | ERR_FATAL;
1427 }
1428
1429 if ((*args[*cur_arg + 1] != '/') && global_ssl.ca_base)
1430 memprintf(&newsrv->ssl_ctx.crl_file, "%s/%s", global_ssl.ca_base, args[*cur_arg + 1]);
1431 else
1432 memprintf(&newsrv->ssl_ctx.crl_file, "%s", args[*cur_arg + 1]);
1433
1434 if (!ssl_store_load_locations_file(newsrv->ssl_ctx.crl_file)) {
1435 memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.crl_file);
1436 return ERR_ALERT | ERR_FATAL;
1437 }
1438 return 0;
1439#endif
1440}
1441
1442/* parse the "crt" server keyword */
1443static int srv_parse_crt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1444{
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001445 int retval = -1;
1446 char *path = NULL;
1447
William Lallemanddad31052020-05-14 17:47:32 +02001448 if (!*args[*cur_arg + 1]) {
1449 memprintf(err, "'%s' : missing certificate file path", args[*cur_arg]);
1450 return ERR_ALERT | ERR_FATAL;
1451 }
1452
1453 if ((*args[*cur_arg + 1] != '/') && global_ssl.crt_base)
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001454 memprintf(&path, "%s/%s", global_ssl.crt_base, args[*cur_arg + 1]);
William Lallemanddad31052020-05-14 17:47:32 +02001455 else
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001456 memprintf(&path, "%s", args[*cur_arg + 1]);
1457
1458 if (path) {
1459 retval = ssl_sock_load_srv_cert(path, newsrv, err);
1460 free(path);
1461 }
William Lallemanddad31052020-05-14 17:47:32 +02001462
Remi Tricot-Le Bretonbb470aa2021-01-25 17:19:45 +01001463 return retval;
William Lallemanddad31052020-05-14 17:47:32 +02001464}
1465
1466/* parse the "no-check-ssl" server keyword */
1467static int srv_parse_no_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1468{
1469 newsrv->check.use_ssl = -1;
1470 free(newsrv->ssl_ctx.ciphers);
1471 newsrv->ssl_ctx.ciphers = NULL;
1472 newsrv->ssl_ctx.options &= ~global_ssl.connect_default_ssloptions;
1473 return 0;
1474}
1475
1476/* parse the "no-send-proxy-v2-ssl" server keyword */
1477static int srv_parse_no_send_proxy_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1478{
1479 newsrv->pp_opts &= ~SRV_PP_V2;
1480 newsrv->pp_opts &= ~SRV_PP_V2_SSL;
1481 return 0;
1482}
1483
1484/* parse the "no-send-proxy-v2-ssl-cn" server keyword */
1485static int srv_parse_no_send_proxy_cn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1486{
1487 newsrv->pp_opts &= ~SRV_PP_V2;
1488 newsrv->pp_opts &= ~SRV_PP_V2_SSL;
1489 newsrv->pp_opts &= ~SRV_PP_V2_SSL_CN;
1490 return 0;
1491}
1492
1493/* parse the "no-ssl" server keyword */
1494static int srv_parse_no_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1495{
William Dauchyf6370442020-11-14 19:25:33 +01001496 /* if default-server have use_ssl, prepare ssl settings */
1497 if (newsrv->use_ssl == 1)
1498 ssl_sock_init_srv(newsrv);
1499 else {
1500 free(newsrv->ssl_ctx.ciphers);
1501 newsrv->ssl_ctx.ciphers = NULL;
1502 }
William Lallemanddad31052020-05-14 17:47:32 +02001503 newsrv->use_ssl = -1;
William Lallemanddad31052020-05-14 17:47:32 +02001504 return 0;
1505}
1506
1507/* parse the "allow-0rtt" server keyword */
1508static int srv_parse_allow_0rtt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1509{
1510 newsrv->ssl_ctx.options |= SRV_SSL_O_EARLY_DATA;
1511 return 0;
1512}
1513
1514/* parse the "no-ssl-reuse" server keyword */
1515static int srv_parse_no_ssl_reuse(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1516{
1517 newsrv->ssl_ctx.options |= SRV_SSL_O_NO_REUSE;
1518 return 0;
1519}
1520
1521/* parse the "no-tls-tickets" server keyword */
1522static int srv_parse_no_tls_tickets(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1523{
1524 newsrv->ssl_ctx.options |= SRV_SSL_O_NO_TLS_TICKETS;
1525 return 0;
1526}
1527/* parse the "send-proxy-v2-ssl" server keyword */
1528static int srv_parse_send_proxy_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1529{
1530 newsrv->pp_opts |= SRV_PP_V2;
1531 newsrv->pp_opts |= SRV_PP_V2_SSL;
1532 return 0;
1533}
1534
1535/* parse the "send-proxy-v2-ssl-cn" server keyword */
1536static int srv_parse_send_proxy_cn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1537{
1538 newsrv->pp_opts |= SRV_PP_V2;
1539 newsrv->pp_opts |= SRV_PP_V2_SSL;
1540 newsrv->pp_opts |= SRV_PP_V2_SSL_CN;
1541 return 0;
1542}
1543
1544/* parse the "sni" server keyword */
1545static int srv_parse_sni(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1546{
1547#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
1548 memprintf(err, "'%s' : the current SSL library doesn't support the SNI TLS extension", args[*cur_arg]);
1549 return ERR_ALERT | ERR_FATAL;
1550#else
1551 char *arg;
1552
1553 arg = args[*cur_arg + 1];
1554 if (!*arg) {
1555 memprintf(err, "'%s' : missing sni expression", args[*cur_arg]);
1556 return ERR_ALERT | ERR_FATAL;
1557 }
1558
1559 free(newsrv->sni_expr);
1560 newsrv->sni_expr = strdup(arg);
1561
1562 return 0;
1563#endif
1564}
1565
1566/* parse the "ssl" server keyword */
1567static int srv_parse_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1568{
1569 newsrv->use_ssl = 1;
William Dauchyfc52f522020-11-14 19:25:32 +01001570 ssl_sock_init_srv(newsrv);
William Lallemanddad31052020-05-14 17:47:32 +02001571 return 0;
1572}
1573
1574/* parse the "ssl-reuse" server keyword */
1575static int srv_parse_ssl_reuse(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1576{
1577 newsrv->ssl_ctx.options &= ~SRV_SSL_O_NO_REUSE;
1578 return 0;
1579}
1580
1581/* parse the "tls-tickets" server keyword */
1582static int srv_parse_tls_tickets(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1583{
1584 newsrv->ssl_ctx.options &= ~SRV_SSL_O_NO_TLS_TICKETS;
1585 return 0;
1586}
1587
1588/* parse the "verify" server keyword */
1589static int srv_parse_verify(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1590{
1591 if (!*args[*cur_arg + 1]) {
1592 memprintf(err, "'%s' : missing verify method", args[*cur_arg]);
1593 return ERR_ALERT | ERR_FATAL;
1594 }
1595
1596 if (strcmp(args[*cur_arg + 1], "none") == 0)
1597 newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_NONE;
1598 else if (strcmp(args[*cur_arg + 1], "required") == 0)
1599 newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_REQUIRED;
1600 else {
1601 memprintf(err, "'%s' : unknown verify method '%s', only 'none' and 'required' are supported\n",
1602 args[*cur_arg], args[*cur_arg + 1]);
1603 return ERR_ALERT | ERR_FATAL;
1604 }
1605
1606 return 0;
1607}
1608
1609/* parse the "verifyhost" server keyword */
1610static int srv_parse_verifyhost(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1611{
1612 if (!*args[*cur_arg + 1]) {
1613 memprintf(err, "'%s' : missing hostname to verify against", args[*cur_arg]);
1614 return ERR_ALERT | ERR_FATAL;
1615 }
1616
1617 free(newsrv->ssl_ctx.verify_host);
1618 newsrv->ssl_ctx.verify_host = strdup(args[*cur_arg + 1]);
1619
1620 return 0;
1621}
1622
1623/* parse the "ssl-default-bind-options" keyword in global section */
1624static int ssl_parse_default_bind_options(char **args, int section_type, struct proxy *curpx,
1625 struct proxy *defpx, const char *file, int line,
1626 char **err) {
1627 int i = 1;
1628
1629 if (*(args[i]) == 0) {
1630 memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
1631 return -1;
1632 }
1633 while (*(args[i])) {
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001634 if (strcmp(args[i], "no-tls-tickets") == 0)
William Lallemanddad31052020-05-14 17:47:32 +02001635 global_ssl.listen_default_ssloptions |= BC_SSL_O_NO_TLS_TICKETS;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001636 else if (strcmp(args[i], "prefer-client-ciphers") == 0)
William Lallemanddad31052020-05-14 17:47:32 +02001637 global_ssl.listen_default_ssloptions |= BC_SSL_O_PREF_CLIE_CIPH;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001638 else if (strcmp(args[i], "ssl-min-ver") == 0 || strcmp(args[i], "ssl-max-ver") == 0) {
William Lallemanddad31052020-05-14 17:47:32 +02001639 if (!parse_tls_method_minmax(args, i, &global_ssl.listen_default_sslmethods, err))
1640 i++;
1641 else {
1642 memprintf(err, "%s on global statement '%s'.", *err, args[0]);
1643 return -1;
1644 }
1645 }
1646 else if (parse_tls_method_options(args[i], &global_ssl.listen_default_sslmethods, err)) {
1647 memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
1648 return -1;
1649 }
1650 i++;
1651 }
1652 return 0;
1653}
1654
1655/* parse the "ssl-default-server-options" keyword in global section */
1656static int ssl_parse_default_server_options(char **args, int section_type, struct proxy *curpx,
1657 struct proxy *defpx, const char *file, int line,
1658 char **err) {
1659 int i = 1;
1660
1661 if (*(args[i]) == 0) {
1662 memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
1663 return -1;
1664 }
1665 while (*(args[i])) {
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001666 if (strcmp(args[i], "no-tls-tickets") == 0)
William Lallemanddad31052020-05-14 17:47:32 +02001667 global_ssl.connect_default_ssloptions |= SRV_SSL_O_NO_TLS_TICKETS;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001668 else if (strcmp(args[i], "ssl-min-ver") == 0 || strcmp(args[i], "ssl-max-ver") == 0) {
William Lallemanddad31052020-05-14 17:47:32 +02001669 if (!parse_tls_method_minmax(args, i, &global_ssl.connect_default_sslmethods, err))
1670 i++;
1671 else {
1672 memprintf(err, "%s on global statement '%s'.", *err, args[0]);
1673 return -1;
1674 }
1675 }
1676 else if (parse_tls_method_options(args[i], &global_ssl.connect_default_sslmethods, err)) {
1677 memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
1678 return -1;
1679 }
1680 i++;
1681 }
1682 return 0;
1683}
1684
1685/* parse the "ca-base" / "crt-base" keywords in global section.
1686 * Returns <0 on alert, >0 on warning, 0 on success.
1687 */
1688static int ssl_parse_global_ca_crt_base(char **args, int section_type, struct proxy *curpx,
1689 struct proxy *defpx, const char *file, int line,
1690 char **err)
1691{
1692 char **target;
1693
1694 target = (args[0][1] == 'a') ? &global_ssl.ca_base : &global_ssl.crt_base;
1695
1696 if (too_many_args(1, args, err, NULL))
1697 return -1;
1698
1699 if (*target) {
1700 memprintf(err, "'%s' already specified.", args[0]);
1701 return -1;
1702 }
1703
1704 if (*(args[1]) == 0) {
1705 memprintf(err, "global statement '%s' expects a directory path as an argument.", args[0]);
1706 return -1;
1707 }
1708 *target = strdup(args[1]);
1709 return 0;
1710}
1711
1712/* parse the "ssl-skip-self-issued-ca" keyword in global section. */
1713static int ssl_parse_skip_self_issued_ca(char **args, int section_type, struct proxy *curpx,
1714 struct proxy *defpx, const char *file, int line,
1715 char **err)
1716{
William Lallemand9a1d8392020-08-10 17:28:23 +02001717#ifdef SSL_CTX_build_cert_chain
William Lallemanddad31052020-05-14 17:47:32 +02001718 global_ssl.skip_self_issued_ca = 1;
1719 return 0;
William Lallemand9a1d8392020-08-10 17:28:23 +02001720#else
1721 memprintf(err, "global statement '%s' requires at least OpenSSL 1.0.2.", args[0]);
1722 return -1;
1723#endif
William Lallemanddad31052020-05-14 17:47:32 +02001724}
1725
1726
1727
1728
1729
1730/* Note: must not be declared <const> as its list will be overwritten.
1731 * Please take care of keeping this list alphabetically sorted, doing so helps
1732 * all code contributors.
1733 * Optional keywords are also declared with a NULL ->parse() function so that
1734 * the config parser can report an appropriate error when a known keyword was
1735 * not enabled.
1736 */
1737
1738/* the <ssl_bind_kws> keywords are used for crt-list parsing, they *MUST* be safe
1739 * with their proxy argument NULL and must only fill the ssl_bind_conf */
1740struct ssl_bind_kw ssl_bind_kws[] = {
1741 { "allow-0rtt", ssl_bind_parse_allow_0rtt, 0 }, /* allow 0-RTT */
1742 { "alpn", ssl_bind_parse_alpn, 1 }, /* set ALPN supported protocols */
1743 { "ca-file", ssl_bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */
1744 { "ca-verify-file", ssl_bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */
1745 { "ciphers", ssl_bind_parse_ciphers, 1 }, /* set SSL cipher suite */
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001746#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001747 { "ciphersuites", ssl_bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */
1748#endif
1749 { "crl-file", ssl_bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */
1750 { "curves", ssl_bind_parse_curves, 1 }, /* set SSL curve suite */
1751 { "ecdhe", ssl_bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
1752 { "no-ca-names", ssl_bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
1753 { "npn", ssl_bind_parse_npn, 1 }, /* set NPN supported protocols */
1754 { "ssl-min-ver", ssl_bind_parse_tls_method_minmax,1 }, /* minimum version */
1755 { "ssl-max-ver", ssl_bind_parse_tls_method_minmax,1 }, /* maximum version */
1756 { "verify", ssl_bind_parse_verify, 1 }, /* set SSL verify method */
1757 { NULL, NULL, 0 },
1758};
1759
1760/* no initcall for ssl_bind_kws, these ones are parsed in the parser loop */
1761
1762static struct bind_kw_list bind_kws = { "SSL", { }, {
1763 { "allow-0rtt", bind_parse_allow_0rtt, 0 }, /* Allow 0RTT */
1764 { "alpn", bind_parse_alpn, 1 }, /* set ALPN supported protocols */
1765 { "ca-file", bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */
1766 { "ca-verify-file", bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */
1767 { "ca-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth > 0 */
1768 { "ca-sign-file", bind_parse_ca_sign_file, 1 }, /* set CAFile used to generate and sign server certs */
1769 { "ca-sign-pass", bind_parse_ca_sign_pass, 1 }, /* set CAKey passphrase */
1770 { "ciphers", bind_parse_ciphers, 1 }, /* set SSL cipher suite */
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001771#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001772 { "ciphersuites", bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */
1773#endif
1774 { "crl-file", bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */
1775 { "crt", bind_parse_crt, 1 }, /* load SSL certificates from this location */
1776 { "crt-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth == 0 */
1777 { "crt-list", bind_parse_crt_list, 1 }, /* load a list of crt from this location */
1778 { "curves", bind_parse_curves, 1 }, /* set SSL curve suite */
1779 { "ecdhe", bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
1780 { "force-sslv3", bind_parse_tls_method_options, 0 }, /* force SSLv3 */
1781 { "force-tlsv10", bind_parse_tls_method_options, 0 }, /* force TLSv10 */
1782 { "force-tlsv11", bind_parse_tls_method_options, 0 }, /* force TLSv11 */
1783 { "force-tlsv12", bind_parse_tls_method_options, 0 }, /* force TLSv12 */
1784 { "force-tlsv13", bind_parse_tls_method_options, 0 }, /* force TLSv13 */
1785 { "generate-certificates", bind_parse_generate_certs, 0 }, /* enable the server certificates generation */
1786 { "no-ca-names", bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
1787 { "no-sslv3", bind_parse_tls_method_options, 0 }, /* disable SSLv3 */
1788 { "no-tlsv10", bind_parse_tls_method_options, 0 }, /* disable TLSv10 */
1789 { "no-tlsv11", bind_parse_tls_method_options, 0 }, /* disable TLSv11 */
1790 { "no-tlsv12", bind_parse_tls_method_options, 0 }, /* disable TLSv12 */
1791 { "no-tlsv13", bind_parse_tls_method_options, 0 }, /* disable TLSv13 */
1792 { "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
1793 { "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */
1794 { "ssl-min-ver", bind_parse_tls_method_minmax, 1 }, /* minimum version */
1795 { "ssl-max-ver", bind_parse_tls_method_minmax, 1 }, /* maximum version */
1796 { "strict-sni", bind_parse_strict_sni, 0 }, /* refuse negotiation if sni doesn't match a certificate */
1797 { "tls-ticket-keys", bind_parse_tls_ticket_keys, 1 }, /* set file to load TLS ticket keys from */
1798 { "verify", bind_parse_verify, 1 }, /* set SSL verify method */
1799 { "npn", bind_parse_npn, 1 }, /* set NPN supported protocols */
1800 { "prefer-client-ciphers", bind_parse_pcc, 0 }, /* prefer client ciphers */
1801 { NULL, NULL, 0 },
1802}};
1803
1804INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
1805
1806/* Note: must not be declared <const> as its list will be overwritten.
1807 * Please take care of keeping this list alphabetically sorted, doing so helps
1808 * all code contributors.
1809 * Optional keywords are also declared with a NULL ->parse() function so that
1810 * the config parser can report an appropriate error when a known keyword was
1811 * not enabled.
1812 */
1813static struct srv_kw_list srv_kws = { "SSL", { }, {
1814 { "allow-0rtt", srv_parse_allow_0rtt, 0, 1 }, /* Allow using early data on this server */
1815 { "alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN supported protocols */
1816 { "ca-file", srv_parse_ca_file, 1, 1 }, /* set CAfile to process verify server cert */
1817 { "check-alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN used for checks */
1818 { "check-sni", srv_parse_check_sni, 1, 1 }, /* set SNI */
1819 { "check-ssl", srv_parse_check_ssl, 0, 1 }, /* enable SSL for health checks */
1820 { "ciphers", srv_parse_ciphers, 1, 1 }, /* select the cipher suite */
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001821#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001822 { "ciphersuites", srv_parse_ciphersuites, 1, 1 }, /* select the cipher suite */
1823#endif
1824 { "crl-file", srv_parse_crl_file, 1, 1 }, /* set certificate revocation list file use on server cert verify */
1825 { "crt", srv_parse_crt, 1, 1 }, /* set client certificate */
1826 { "force-sslv3", srv_parse_tls_method_options, 0, 1 }, /* force SSLv3 */
1827 { "force-tlsv10", srv_parse_tls_method_options, 0, 1 }, /* force TLSv10 */
1828 { "force-tlsv11", srv_parse_tls_method_options, 0, 1 }, /* force TLSv11 */
1829 { "force-tlsv12", srv_parse_tls_method_options, 0, 1 }, /* force TLSv12 */
1830 { "force-tlsv13", srv_parse_tls_method_options, 0, 1 }, /* force TLSv13 */
1831 { "no-check-ssl", srv_parse_no_check_ssl, 0, 1 }, /* disable SSL for health checks */
1832 { "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1 }, /* do not send PROXY protocol header v2 with SSL info */
1833 { "no-send-proxy-v2-ssl-cn", srv_parse_no_send_proxy_cn, 0, 1 }, /* do not send PROXY protocol header v2 with CN */
1834 { "no-ssl", srv_parse_no_ssl, 0, 1 }, /* disable SSL processing */
1835 { "no-ssl-reuse", srv_parse_no_ssl_reuse, 0, 1 }, /* disable session reuse */
1836 { "no-sslv3", srv_parse_tls_method_options, 0, 0 }, /* disable SSLv3 */
1837 { "no-tlsv10", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv10 */
1838 { "no-tlsv11", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv11 */
1839 { "no-tlsv12", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv12 */
1840 { "no-tlsv13", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv13 */
1841 { "no-tls-tickets", srv_parse_no_tls_tickets, 0, 1 }, /* disable session resumption tickets */
1842 { "npn", srv_parse_npn, 1, 1 }, /* Set NPN supported protocols */
1843 { "send-proxy-v2-ssl", srv_parse_send_proxy_ssl, 0, 1 }, /* send PROXY protocol header v2 with SSL info */
1844 { "send-proxy-v2-ssl-cn", srv_parse_send_proxy_cn, 0, 1 }, /* send PROXY protocol header v2 with CN */
1845 { "sni", srv_parse_sni, 1, 1 }, /* send SNI extension */
1846 { "ssl", srv_parse_ssl, 0, 1 }, /* enable SSL processing */
1847 { "ssl-min-ver", srv_parse_tls_method_minmax, 1, 1 }, /* minimum version */
1848 { "ssl-max-ver", srv_parse_tls_method_minmax, 1, 1 }, /* maximum version */
1849 { "ssl-reuse", srv_parse_ssl_reuse, 0, 1 }, /* enable session reuse */
1850 { "tls-tickets", srv_parse_tls_tickets, 0, 1 }, /* enable session resumption tickets */
1851 { "verify", srv_parse_verify, 1, 1 }, /* set SSL verify method */
1852 { "verifyhost", srv_parse_verifyhost, 1, 1 }, /* require that SSL cert verifies for hostname */
1853 { NULL, NULL, 0, 0 },
1854}};
1855
1856INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
1857
1858static struct cfg_kw_list cfg_kws = {ILH, {
1859 { CFG_GLOBAL, "ca-base", ssl_parse_global_ca_crt_base },
1860 { CFG_GLOBAL, "crt-base", ssl_parse_global_ca_crt_base },
1861 { CFG_GLOBAL, "issuers-chain-path", ssl_load_global_issuers_from_path },
1862 { CFG_GLOBAL, "maxsslconn", ssl_parse_global_int },
1863 { CFG_GLOBAL, "ssl-default-bind-options", ssl_parse_default_bind_options },
1864 { CFG_GLOBAL, "ssl-default-server-options", ssl_parse_default_server_options },
1865#ifndef OPENSSL_NO_DH
1866 { CFG_GLOBAL, "ssl-dh-param-file", ssl_parse_global_dh_param_file },
1867#endif
1868 { CFG_GLOBAL, "ssl-mode-async", ssl_parse_global_ssl_async },
1869#ifndef OPENSSL_NO_ENGINE
1870 { CFG_GLOBAL, "ssl-engine", ssl_parse_global_ssl_engine },
1871#endif
1872 { CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
1873 { CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
1874#ifndef OPENSSL_NO_DH
1875 { CFG_GLOBAL, "tune.ssl.default-dh-param", ssl_parse_global_default_dh },
1876#endif
1877 { CFG_GLOBAL, "tune.ssl.force-private-cache", ssl_parse_global_private_cache },
1878 { CFG_GLOBAL, "tune.ssl.lifetime", ssl_parse_global_lifetime },
1879 { CFG_GLOBAL, "tune.ssl.maxrecord", ssl_parse_global_int },
1880 { CFG_GLOBAL, "tune.ssl.ssl-ctx-cache-size", ssl_parse_global_int },
1881 { CFG_GLOBAL, "tune.ssl.capture-cipherlist-size", ssl_parse_global_capture_cipherlist },
Ilya Shipitsin04a5a442020-11-03 14:15:38 +05001882#ifdef HAVE_OPENSSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001883 { CFG_GLOBAL, "tune.ssl.keylog", ssl_parse_global_keylog },
1884#endif
William Lallemanddad31052020-05-14 17:47:32 +02001885 { CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
1886 { CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +05001887#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +02001888 { CFG_GLOBAL, "ssl-default-bind-curves", ssl_parse_global_curves },
1889#endif
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +05001890#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemanddad31052020-05-14 17:47:32 +02001891 { CFG_GLOBAL, "ssl-default-bind-ciphersuites", ssl_parse_global_ciphersuites },
1892 { CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
1893#endif
1894 { CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
William Lallemand8e8581e2020-10-20 17:36:46 +02001895 { CFG_GLOBAL, "ssl-load-extra-del-ext", ssl_parse_global_extra_noext },
William Lallemanddad31052020-05-14 17:47:32 +02001896 { 0, NULL, NULL },
1897}};
1898
1899INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);