blob: 23949af915e97e365e8ad57973bfdcd69eb46ae8 [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{
128#if (HA_OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
129 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
206#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
207/* 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 */
William Lallemandb3246942021-06-09 16:46:12 +0200321#ifdef HAVE_SSL_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}
William Lallemandb3246942021-06-09 16:46:12 +0200356#else
357static int ssl_parse_global_keylog(char **args, int section_type, struct proxy *curpx,
Christopher Faulet6d436322021-06-21 11:17:30 +0200358 struct proxy *defpx, const char *file, int line,
William Lallemandb3246942021-06-09 16:46:12 +0200359 char **err)
360{
361 memprintf(err, "'%s' requires at least OpenSSL 1.1.1.", args[0]);
362 return -1;
363}
William Lallemand7d42ef52020-07-06 11:41:30 +0200364#endif
365
William Lallemanddad31052020-05-14 17:47:32 +0200366/* parse "ssl.force-private-cache".
367 * Returns <0 on alert, >0 on warning, 0 on success.
368 */
369static int ssl_parse_global_private_cache(char **args, int section_type, struct proxy *curpx,
370 struct proxy *defpx, const char *file, int line,
371 char **err)
372{
373 if (too_many_args(0, args, err, NULL))
374 return -1;
375
376 global_ssl.private_cache = 1;
377 return 0;
378}
379
380/* parse "ssl.lifetime".
381 * Returns <0 on alert, >0 on warning, 0 on success.
382 */
383static int ssl_parse_global_lifetime(char **args, int section_type, struct proxy *curpx,
384 struct proxy *defpx, const char *file, int line,
385 char **err)
386{
387 const char *res;
388
389 if (too_many_args(1, args, err, NULL))
390 return -1;
391
392 if (*(args[1]) == 0) {
393 memprintf(err, "'%s' expects ssl sessions <lifetime> in seconds as argument.", args[0]);
394 return -1;
395 }
396
397 res = parse_time_err(args[1], &global_ssl.life_time, TIME_UNIT_S);
398 if (res == PARSE_TIME_OVER) {
399 memprintf(err, "timer overflow in argument '%s' to <%s> (maximum value is 2147483647 s or ~68 years).",
400 args[1], args[0]);
401 return -1;
402 }
403 else if (res == PARSE_TIME_UNDER) {
404 memprintf(err, "timer underflow in argument '%s' to <%s> (minimum non-null value is 1 s).",
405 args[1], args[0]);
406 return -1;
407 }
408 else if (res) {
409 memprintf(err, "unexpected character '%c' in argument to <%s>.", *res, args[0]);
410 return -1;
411 }
412 return 0;
413}
414
415#ifndef OPENSSL_NO_DH
416/* parse "ssl-dh-param-file".
417 * Returns <0 on alert, >0 on warning, 0 on success.
418 */
419static int ssl_parse_global_dh_param_file(char **args, int section_type, struct proxy *curpx,
420 struct proxy *defpx, const char *file, int line,
421 char **err)
422{
423 if (too_many_args(1, args, err, NULL))
424 return -1;
425
426 if (*(args[1]) == 0) {
427 memprintf(err, "'%s' expects a file path as an argument.", args[0]);
428 return -1;
429 }
430
431 if (ssl_sock_load_global_dh_param_from_file(args[1])) {
432 memprintf(err, "'%s': unable to load DH parameters from file <%s>.", args[0], args[1]);
433 return -1;
434 }
435 return 0;
436}
437
438/* parse "ssl.default-dh-param".
439 * Returns <0 on alert, >0 on warning, 0 on success.
440 */
441static int ssl_parse_global_default_dh(char **args, int section_type, struct proxy *curpx,
442 struct proxy *defpx, const char *file, int line,
443 char **err)
444{
445 if (too_many_args(1, args, err, NULL))
446 return -1;
447
448 if (*(args[1]) == 0) {
449 memprintf(err, "'%s' expects an integer argument.", args[0]);
450 return -1;
451 }
452
453 global_ssl.default_dh_param = atoi(args[1]);
454 if (global_ssl.default_dh_param < 1024) {
455 memprintf(err, "'%s' expects a value >= 1024.", args[0]);
456 return -1;
457 }
458 return 0;
459}
460#endif
461
462
463/*
464 * parse "ssl-load-extra-files".
465 * multiple arguments are allowed: "bundle", "sctl", "ocsp", "issuer", "all", "none"
466 */
467static int ssl_parse_global_extra_files(char **args, int section_type, struct proxy *curpx,
468 struct proxy *defpx, const char *file, int line,
469 char **err)
470{
471 int i;
472 int gf = SSL_GF_NONE;
473
474 if (*(args[1]) == 0)
475 goto err_arg;
476
477 for (i = 1; *args[i]; i++) {
478
479 if (!strcmp("bundle", args[i])) {
480 gf |= SSL_GF_BUNDLE;
481
482 } else if (!strcmp("sctl", args[i])) {
483 gf |= SSL_GF_SCTL;
484
485 } else if (!strcmp("ocsp", args[i])){
486 gf |= SSL_GF_OCSP;
487
488 } else if (!strcmp("issuer", args[i])){
489 gf |= SSL_GF_OCSP_ISSUER;
490
491 } else if (!strcmp("key", args[i])) {
492 gf |= SSL_GF_KEY;
493
494 } else if (!strcmp("none", args[i])) {
495 if (gf != SSL_GF_NONE)
496 goto err_alone;
497 gf = SSL_GF_NONE;
498 i++;
499 break;
500
501 } else if (!strcmp("all", args[i])) {
502 if (gf != SSL_GF_NONE)
503 goto err_alone;
504 gf = SSL_GF_ALL;
505 i++;
506 break;
507 } else {
508 goto err_arg;
509 }
510 }
511 /* break from loop but there are still arguments */
512 if (*args[i])
513 goto err_alone;
514
515 global_ssl.extra_files = gf;
516
517 return 0;
518
519err_alone:
520 memprintf(err, "'%s' 'none' and 'all' can be only used alone", args[0]);
521 return -1;
522
523err_arg:
524 memprintf(err, "'%s' expects one or multiple arguments (none, all, bundle, sctl, ocsp, issuer).", args[0]);
525 return -1;
526}
527
528
William Lallemand8e8581e2020-10-20 17:36:46 +0200529/* parse 'ssl-load-extra-del-ext */
530static int ssl_parse_global_extra_noext(char **args, int section_type, struct proxy *curpx,
531 struct proxy *defpx, const char *file, int line,
532 char **err)
533{
534 global_ssl.extra_files_noext = 1;
535 return 0;
536}
537
William Lallemanddad31052020-05-14 17:47:32 +0200538/***************************** Bind keyword Parsing ********************************************/
539
540/* for ca-file and ca-verify-file */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100541static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char **ca_file_p, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200542{
543 if (!*args[cur_arg + 1]) {
544 memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
545 return ERR_ALERT | ERR_FATAL;
546 }
547
548 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
549 memprintf(ca_file_p, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
550 else
551 memprintf(ca_file_p, "%s", args[cur_arg + 1]);
552
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100553 if (!ssl_store_load_locations_file(*ca_file_p, !from_cli)) {
William Lallemanddad31052020-05-14 17:47:32 +0200554 memprintf(err, "'%s' : unable to load %s", args[cur_arg], *ca_file_p);
555 return ERR_ALERT | ERR_FATAL;
556 }
557 return 0;
558}
559
560/* parse the "ca-file" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100561static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200562{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100563 return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, from_cli, err);
William Lallemanddad31052020-05-14 17:47:32 +0200564}
565static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
566{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100567 return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200568}
569
570/* parse the "ca-verify-file" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100571static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200572{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100573 return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_verify_file, from_cli, err);
William Lallemanddad31052020-05-14 17:47:32 +0200574}
575static int bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
576{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100577 return ssl_bind_parse_ca_verify_file(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200578}
579
580/* parse the "ca-sign-file" bind keyword */
581static int bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
582{
583 if (!*args[cur_arg + 1]) {
584 memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
585 return ERR_ALERT | ERR_FATAL;
586 }
587
588 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
589 memprintf(&conf->ca_sign_file, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
590 else
591 memprintf(&conf->ca_sign_file, "%s", args[cur_arg + 1]);
592
593 return 0;
594}
595
596/* parse the "ca-sign-pass" bind keyword */
597static int bind_parse_ca_sign_pass(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
598{
599 if (!*args[cur_arg + 1]) {
600 memprintf(err, "'%s' : missing CAkey password", args[cur_arg]);
601 return ERR_ALERT | ERR_FATAL;
602 }
603 memprintf(&conf->ca_sign_pass, "%s", args[cur_arg + 1]);
604 return 0;
605}
606
607/* parse the "ciphers" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100608static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200609{
610 if (!*args[cur_arg + 1]) {
611 memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
612 return ERR_ALERT | ERR_FATAL;
613 }
614
615 free(conf->ciphers);
616 conf->ciphers = strdup(args[cur_arg + 1]);
617 return 0;
618}
619static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
620{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100621 return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200622}
623
624#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
625/* parse the "ciphersuites" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100626static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200627{
628 if (!*args[cur_arg + 1]) {
629 memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
630 return ERR_ALERT | ERR_FATAL;
631 }
632
633 free(conf->ciphersuites);
634 conf->ciphersuites = strdup(args[cur_arg + 1]);
635 return 0;
636}
637static int bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
638{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100639 return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200640}
641#endif
642
643/* parse the "crt" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
644static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
645{
646 char path[MAXPATHLEN];
647
648 if (!*args[cur_arg + 1]) {
649 memprintf(err, "'%s' : missing certificate location", args[cur_arg]);
650 return ERR_ALERT | ERR_FATAL;
651 }
652
653 if ((*args[cur_arg + 1] != '/' ) && global_ssl.crt_base) {
654 if ((strlen(global_ssl.crt_base) + 1 + strlen(args[cur_arg + 1]) + 1) > MAXPATHLEN) {
655 memprintf(err, "'%s' : path too long", args[cur_arg]);
656 return ERR_ALERT | ERR_FATAL;
657 }
658 snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, args[cur_arg + 1]);
659 return ssl_sock_load_cert(path, conf, err);
660 }
661
662 return ssl_sock_load_cert(args[cur_arg + 1], conf, err);
663}
664
665/* parse the "crt-list" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
666static int bind_parse_crt_list(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
667{
668 int err_code;
669
670 if (!*args[cur_arg + 1]) {
671 memprintf(err, "'%s' : missing certificate location", args[cur_arg]);
672 return ERR_ALERT | ERR_FATAL;
673 }
674
675 err_code = ssl_sock_load_cert_list_file(args[cur_arg + 1], 0, conf, px, err);
676 if (err_code)
677 memprintf(err, "'%s' : %s", args[cur_arg], *err);
678
679 return err_code;
680}
681
682/* parse the "crl-file" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100683static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200684{
685#ifndef X509_V_FLAG_CRL_CHECK
686 memprintf(err, "'%s' : library does not support CRL verify", args[cur_arg]);
687 return ERR_ALERT | ERR_FATAL;
688#else
689 if (!*args[cur_arg + 1]) {
690 memprintf(err, "'%s' : missing CRLfile path", args[cur_arg]);
691 return ERR_ALERT | ERR_FATAL;
692 }
693
694 if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base)
695 memprintf(&conf->crl_file, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]);
696 else
697 memprintf(&conf->crl_file, "%s", args[cur_arg + 1]);
698
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100699 if (!ssl_store_load_locations_file(conf->crl_file, !from_cli)) {
William Lallemanddad31052020-05-14 17:47:32 +0200700 memprintf(err, "'%s' : unable to load %s", args[cur_arg], conf->crl_file);
701 return ERR_ALERT | ERR_FATAL;
702 }
703 return 0;
704#endif
705}
706static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
707{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100708 return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200709}
710
711/* parse the "curves" bind keyword keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100712static int ssl_bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200713{
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +0500714#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +0200715 if (!*args[cur_arg + 1]) {
716 memprintf(err, "'%s' : missing curve suite", args[cur_arg]);
717 return ERR_ALERT | ERR_FATAL;
718 }
719 conf->curves = strdup(args[cur_arg + 1]);
720 return 0;
721#else
722 memprintf(err, "'%s' : library does not support curve suite", args[cur_arg]);
723 return ERR_ALERT | ERR_FATAL;
724#endif
725}
726static int bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
727{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100728 return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200729}
730
731/* parse the "ecdhe" bind keyword keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100732static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200733{
Ilya Shipitsin6f7bcf62021-03-21 12:50:47 +0500734#if !defined(SSL_CTX_set_tmp_ecdh)
William Lallemanddad31052020-05-14 17:47:32 +0200735 memprintf(err, "'%s' : library does not support elliptic curve Diffie-Hellman (too old)", args[cur_arg]);
736 return ERR_ALERT | ERR_FATAL;
737#elif defined(OPENSSL_NO_ECDH)
738 memprintf(err, "'%s' : library does not support elliptic curve Diffie-Hellman (disabled via OPENSSL_NO_ECDH)", args[cur_arg]);
739 return ERR_ALERT | ERR_FATAL;
740#else
741 if (!*args[cur_arg + 1]) {
742 memprintf(err, "'%s' : missing named curve", args[cur_arg]);
743 return ERR_ALERT | ERR_FATAL;
744 }
745
746 conf->ecdhe = strdup(args[cur_arg + 1]);
747
748 return 0;
749#endif
750}
751static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
752{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100753 return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200754}
755
756/* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */
757static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
758{
759 int code;
760 char *p = args[cur_arg + 1];
761 unsigned long long *ignerr = &conf->crt_ignerr;
762
763 if (!*p) {
764 memprintf(err, "'%s' : missing error IDs list", args[cur_arg]);
765 return ERR_ALERT | ERR_FATAL;
766 }
767
768 if (strcmp(args[cur_arg], "ca-ignore-err") == 0)
769 ignerr = &conf->ca_ignerr;
770
771 if (strcmp(p, "all") == 0) {
772 *ignerr = ~0ULL;
773 return 0;
774 }
775
776 while (p) {
777 code = atoi(p);
778 if ((code <= 0) || (code > 63)) {
779 memprintf(err, "'%s' : ID '%d' out of range (1..63) in error IDs list '%s'",
780 args[cur_arg], code, args[cur_arg + 1]);
781 return ERR_ALERT | ERR_FATAL;
782 }
783 *ignerr |= 1ULL << code;
784 p = strchr(p, ',');
785 if (p)
786 p++;
787 }
788
789 return 0;
790}
791
792/* parse tls_method_options "no-xxx" and "force-xxx" */
793static int parse_tls_method_options(char *arg, struct tls_version_filter *methods, char **err)
794{
795 uint16_t v;
796 char *p;
797 p = strchr(arg, '-');
798 if (!p)
799 goto fail;
800 p++;
801 if (!strcmp(p, "sslv3"))
802 v = CONF_SSLV3;
803 else if (!strcmp(p, "tlsv10"))
804 v = CONF_TLSV10;
805 else if (!strcmp(p, "tlsv11"))
806 v = CONF_TLSV11;
807 else if (!strcmp(p, "tlsv12"))
808 v = CONF_TLSV12;
809 else if (!strcmp(p, "tlsv13"))
810 v = CONF_TLSV13;
811 else
812 goto fail;
813 if (!strncmp(arg, "no-", 3))
814 methods->flags |= methodVersions[v].flag;
815 else if (!strncmp(arg, "force-", 6))
816 methods->min = methods->max = v;
817 else
818 goto fail;
819 return 0;
820 fail:
821 memprintf(err, "'%s' : option not implemented", arg);
822 return ERR_ALERT | ERR_FATAL;
823}
824
825static int bind_parse_tls_method_options(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
826{
827 return parse_tls_method_options(args[cur_arg], &conf->ssl_conf.ssl_methods, err);
828}
829
830static int srv_parse_tls_method_options(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
831{
832 return parse_tls_method_options(args[*cur_arg], &newsrv->ssl_ctx.methods, err);
833}
834
835/* parse tls_method min/max: "ssl-min-ver" and "ssl-max-ver" */
836static int parse_tls_method_minmax(char **args, int cur_arg, struct tls_version_filter *methods, char **err)
837{
838 uint16_t i, v = 0;
839 char *argv = args[cur_arg + 1];
840 if (!*argv) {
841 memprintf(err, "'%s' : missing the ssl/tls version", args[cur_arg]);
842 return ERR_ALERT | ERR_FATAL;
843 }
844 for (i = CONF_TLSV_MIN; i <= CONF_TLSV_MAX; i++)
845 if (!strcmp(argv, methodVersions[i].name))
846 v = i;
847 if (!v) {
848 memprintf(err, "'%s' : unknown ssl/tls version", args[cur_arg + 1]);
849 return ERR_ALERT | ERR_FATAL;
850 }
851 if (!strcmp("ssl-min-ver", args[cur_arg]))
852 methods->min = v;
853 else if (!strcmp("ssl-max-ver", args[cur_arg]))
854 methods->max = v;
855 else {
856 memprintf(err, "'%s' : option not implemented", args[cur_arg]);
857 return ERR_ALERT | ERR_FATAL;
858 }
859 return 0;
860}
861
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100862static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200863{
William Lallemand8177ad92020-05-20 16:49:02 +0200864 int ret;
865
William Lallemanddad31052020-05-14 17:47:32 +0200866#if (HA_OPENSSL_VERSION_NUMBER < 0x10101000L) && !defined(OPENSSL_IS_BORINGSSL)
867 ha_warning("crt-list: ssl-min-ver and ssl-max-ver are not supported with this Openssl version (skipped).\n");
868#endif
William Lallemand8177ad92020-05-20 16:49:02 +0200869 ret = parse_tls_method_minmax(args, cur_arg, &conf->ssl_methods_cfg, err);
870 if (ret != ERR_NONE)
871 return ret;
William Lallemanddad31052020-05-14 17:47:32 +0200872
William Lallemand8177ad92020-05-20 16:49:02 +0200873 conf->ssl_methods.min = conf->ssl_methods_cfg.min;
874 conf->ssl_methods.max = conf->ssl_methods_cfg.max;
875
876 return ret;
877}
William Lallemanddad31052020-05-14 17:47:32 +0200878static int bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
879{
880 return parse_tls_method_minmax(args, cur_arg, &conf->ssl_conf.ssl_methods, err);
881}
882
883static int srv_parse_tls_method_minmax(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
884{
885 return parse_tls_method_minmax(args, *cur_arg, &newsrv->ssl_ctx.methods, err);
886}
887
888/* parse the "no-tls-tickets" bind keyword */
889static int bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
890{
891 conf->ssl_options |= BC_SSL_O_NO_TLS_TICKETS;
892 return 0;
893}
894
895/* parse the "allow-0rtt" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100896static int ssl_bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200897{
898 conf->early_data = 1;
899 return 0;
900}
901
902static int bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
903{
904 conf->ssl_conf.early_data = 1;
905 return 0;
906}
907
908/* parse the "npn" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100909static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +0200910{
911#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
912 char *p1, *p2;
913
914 if (!*args[cur_arg + 1]) {
915 memprintf(err, "'%s' : missing the comma-delimited NPN protocol suite", args[cur_arg]);
916 return ERR_ALERT | ERR_FATAL;
917 }
918
919 free(conf->npn_str);
920
921 /* the NPN string is built as a suite of (<len> <name>)*,
922 * so we reuse each comma to store the next <len> and need
923 * one more for the end of the string.
924 */
925 conf->npn_len = strlen(args[cur_arg + 1]) + 1;
926 conf->npn_str = calloc(1, conf->npn_len + 1);
927 memcpy(conf->npn_str + 1, args[cur_arg + 1], conf->npn_len);
928
929 /* replace commas with the name length */
930 p1 = conf->npn_str;
931 p2 = p1 + 1;
932 while (1) {
933 p2 = memchr(p1 + 1, ',', conf->npn_str + conf->npn_len - (p1 + 1));
934 if (!p2)
935 p2 = p1 + 1 + strlen(p1 + 1);
936
937 if (p2 - (p1 + 1) > 255) {
938 *p2 = '\0';
939 memprintf(err, "'%s' : NPN protocol name too long : '%s'", args[cur_arg], p1 + 1);
940 return ERR_ALERT | ERR_FATAL;
941 }
942
943 *p1 = p2 - (p1 + 1);
944 p1 = p2;
945
946 if (!*p2)
947 break;
948
949 *(p2++) = '\0';
950 }
951 return 0;
952#else
953 memprintf(err, "'%s' : library does not support TLS NPN extension", args[cur_arg]);
954 return ERR_ALERT | ERR_FATAL;
955#endif
956}
957
958static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
959{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +0100960 return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +0200961}
962
963
964/* Parses a alpn string and converts it to the right format for the SSL api */
965int ssl_sock_parse_alpn(char *arg, char **alpn_str, int *alpn_len, char **err)
966{
967 char *p1, *p2, *alpn = NULL;
968 int len, ret = 0;
969
970 *alpn_str = NULL;
971 *alpn_len = 0;
972
973 if (!*arg) {
974 memprintf(err, "missing the comma-delimited ALPN protocol suite");
975 goto error;
976 }
977
978 /* the ALPN string is built as a suite of (<len> <name>)*,
979 * so we reuse each comma to store the next <len> and need
980 * one more for the end of the string.
981 */
982 len = strlen(arg) + 1;
983 alpn = calloc(1, len+1);
984 if (!alpn) {
985 memprintf(err, "'%s' : out of memory", arg);
986 goto error;
987 }
988 memcpy(alpn+1, arg, len);
989
990 /* replace commas with the name length */
991 p1 = alpn;
992 p2 = p1 + 1;
993 while (1) {
994 p2 = memchr(p1 + 1, ',', alpn + len - (p1 + 1));
995 if (!p2)
996 p2 = p1 + 1 + strlen(p1 + 1);
997
998 if (p2 - (p1 + 1) > 255) {
999 *p2 = '\0';
1000 memprintf(err, "ALPN protocol name too long : '%s'", p1 + 1);
1001 goto error;
1002 }
1003
1004 *p1 = p2 - (p1 + 1);
1005 p1 = p2;
1006
1007 if (!*p2)
1008 break;
1009
1010 *(p2++) = '\0';
1011 }
1012
1013 *alpn_str = alpn;
1014 *alpn_len = len;
1015
1016 out:
1017 return ret;
1018
1019 error:
1020 free(alpn);
1021 ret = ERR_ALERT | ERR_FATAL;
1022 goto out;
1023}
1024
1025/* parse the "alpn" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001026static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +02001027{
1028#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1029 int ret;
1030
1031 free(conf->alpn_str);
1032
1033 ret = ssl_sock_parse_alpn(args[cur_arg + 1], &conf->alpn_str, &conf->alpn_len, err);
1034 if (ret)
1035 memprintf(err, "'%s' : %s", args[cur_arg], *err);
1036 return ret;
1037#else
1038 memprintf(err, "'%s' : library does not support TLS ALPN extension", args[cur_arg]);
1039 return ERR_ALERT | ERR_FATAL;
1040#endif
1041}
1042
1043static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1044{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001045 return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +02001046}
1047
1048/* parse the "ssl" bind keyword */
1049static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1050{
1051 conf->xprt = &ssl_sock;
1052 conf->is_ssl = 1;
1053
1054 if (global_ssl.listen_default_ciphers && !conf->ssl_conf.ciphers)
1055 conf->ssl_conf.ciphers = strdup(global_ssl.listen_default_ciphers);
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +05001056#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +02001057 if (global_ssl.listen_default_curves && !conf->ssl_conf.curves)
1058 conf->ssl_conf.curves = strdup(global_ssl.listen_default_curves);
1059#endif
1060#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1061 if (global_ssl.listen_default_ciphersuites && !conf->ssl_conf.ciphersuites)
1062 conf->ssl_conf.ciphersuites = strdup(global_ssl.listen_default_ciphersuites);
1063#endif
1064 conf->ssl_options |= global_ssl.listen_default_ssloptions;
1065 conf->ssl_conf.ssl_methods.flags |= global_ssl.listen_default_sslmethods.flags;
1066 if (!conf->ssl_conf.ssl_methods.min)
1067 conf->ssl_conf.ssl_methods.min = global_ssl.listen_default_sslmethods.min;
1068 if (!conf->ssl_conf.ssl_methods.max)
1069 conf->ssl_conf.ssl_methods.max = global_ssl.listen_default_sslmethods.max;
1070
1071 return 0;
1072}
1073
1074/* parse the "prefer-client-ciphers" bind keyword */
1075static int bind_parse_pcc(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1076{
1077 conf->ssl_options |= BC_SSL_O_PREF_CLIE_CIPH;
1078 return 0;
1079}
1080
1081/* parse the "generate-certificates" bind keyword */
1082static int bind_parse_generate_certs(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1083{
1084#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
1085 conf->generate_certs = 1;
1086#else
1087 memprintf(err, "%sthis version of openssl cannot generate SSL certificates.\n",
1088 err && *err ? *err : "");
1089#endif
1090 return 0;
1091}
1092
1093/* parse the "strict-sni" bind keyword */
1094static int bind_parse_strict_sni(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1095{
1096 conf->strict_sni = 1;
1097 return 0;
1098}
1099
1100/* parse the "tls-ticket-keys" bind keyword */
1101static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1102{
1103#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
1104 FILE *f = NULL;
1105 int i = 0;
1106 char thisline[LINESIZE];
1107 struct tls_keys_ref *keys_ref = NULL;
1108
1109 if (!*args[cur_arg + 1]) {
1110 memprintf(err, "'%s' : missing TLS ticket keys file path", args[cur_arg]);
1111 goto fail;
1112 }
1113
1114 keys_ref = tlskeys_ref_lookup(args[cur_arg + 1]);
1115 if (keys_ref) {
1116 keys_ref->refcount++;
1117 conf->keys_ref = keys_ref;
1118 return 0;
1119 }
1120
1121 keys_ref = calloc(1, sizeof(*keys_ref));
1122 if (!keys_ref) {
1123 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1124 goto fail;
1125 }
1126
1127 keys_ref->tlskeys = malloc(TLS_TICKETS_NO * sizeof(union tls_sess_key));
1128 if (!keys_ref->tlskeys) {
1129 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1130 goto fail;
1131 }
1132
1133 if ((f = fopen(args[cur_arg + 1], "r")) == NULL) {
1134 memprintf(err, "'%s' : unable to load ssl tickets keys file", args[cur_arg+1]);
1135 goto fail;
1136 }
1137
1138 keys_ref->filename = strdup(args[cur_arg + 1]);
1139 if (!keys_ref->filename) {
1140 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
1141 goto fail;
1142 }
1143
1144 keys_ref->key_size_bits = 0;
1145 while (fgets(thisline, sizeof(thisline), f) != NULL) {
1146 int len = strlen(thisline);
1147 int dec_size;
1148
1149 /* Strip newline characters from the end */
1150 if(thisline[len - 1] == '\n')
1151 thisline[--len] = 0;
1152
1153 if(thisline[len - 1] == '\r')
1154 thisline[--len] = 0;
1155
1156 dec_size = base64dec(thisline, len, (char *) (keys_ref->tlskeys + i % TLS_TICKETS_NO), sizeof(union tls_sess_key));
1157 if (dec_size < 0) {
1158 memprintf(err, "'%s' : unable to decode base64 key on line %d", args[cur_arg+1], i + 1);
1159 goto fail;
1160 }
1161 else if (!keys_ref->key_size_bits && (dec_size == sizeof(struct tls_sess_key_128))) {
1162 keys_ref->key_size_bits = 128;
1163 }
1164 else if (!keys_ref->key_size_bits && (dec_size == sizeof(struct tls_sess_key_256))) {
1165 keys_ref->key_size_bits = 256;
1166 }
1167 else if (((dec_size != sizeof(struct tls_sess_key_128)) && (dec_size != sizeof(struct tls_sess_key_256)))
1168 || ((dec_size == sizeof(struct tls_sess_key_128) && (keys_ref->key_size_bits != 128)))
1169 || ((dec_size == sizeof(struct tls_sess_key_256) && (keys_ref->key_size_bits != 256)))) {
1170 memprintf(err, "'%s' : wrong sized key on line %d", args[cur_arg+1], i + 1);
1171 goto fail;
1172 }
1173 i++;
1174 }
1175
1176 if (i < TLS_TICKETS_NO) {
1177 memprintf(err, "'%s' : please supply at least %d keys in the tls-tickets-file", args[cur_arg+1], TLS_TICKETS_NO);
1178 goto fail;
1179 }
1180
1181 fclose(f);
1182
1183 /* Use penultimate key for encryption, handle when TLS_TICKETS_NO = 1 */
1184 i -= 2;
1185 keys_ref->tls_ticket_enc_index = i < 0 ? 0 : i % TLS_TICKETS_NO;
1186 keys_ref->unique_id = -1;
1187 keys_ref->refcount = 1;
1188 HA_RWLOCK_INIT(&keys_ref->lock);
1189 conf->keys_ref = keys_ref;
1190
1191 LIST_ADD(&tlskeys_reference, &keys_ref->list);
1192
1193 return 0;
1194
1195 fail:
1196 if (f)
1197 fclose(f);
1198 if (keys_ref) {
1199 free(keys_ref->filename);
1200 free(keys_ref->tlskeys);
1201 free(keys_ref);
1202 }
1203 return ERR_ALERT | ERR_FATAL;
1204
1205#else
1206 memprintf(err, "'%s' : TLS ticket callback extension not supported", args[cur_arg]);
1207 return ERR_ALERT | ERR_FATAL;
1208#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
1209}
1210
1211/* parse the "verify" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001212static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +02001213{
1214 if (!*args[cur_arg + 1]) {
1215 memprintf(err, "'%s' : missing verify method", args[cur_arg]);
1216 return ERR_ALERT | ERR_FATAL;
1217 }
1218
1219 if (strcmp(args[cur_arg + 1], "none") == 0)
1220 conf->verify = SSL_SOCK_VERIFY_NONE;
1221 else if (strcmp(args[cur_arg + 1], "optional") == 0)
1222 conf->verify = SSL_SOCK_VERIFY_OPTIONAL;
1223 else if (strcmp(args[cur_arg + 1], "required") == 0)
1224 conf->verify = SSL_SOCK_VERIFY_REQUIRED;
1225 else {
1226 memprintf(err, "'%s' : unknown verify method '%s', only 'none', 'optional', and 'required' are supported\n",
1227 args[cur_arg], args[cur_arg + 1]);
1228 return ERR_ALERT | ERR_FATAL;
1229 }
1230
1231 return 0;
1232}
1233static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1234{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001235 return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +02001236}
1237
1238/* parse the "no-ca-names" bind keyword */
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001239static int ssl_bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
William Lallemanddad31052020-05-14 17:47:32 +02001240{
1241 conf->no_ca_names = 1;
1242 return 0;
1243}
1244static int bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1245{
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001246 return ssl_bind_parse_no_ca_names(args, cur_arg, px, &conf->ssl_conf, 0, err);
William Lallemanddad31052020-05-14 17:47:32 +02001247}
1248
1249/***************************** "server" keywords Parsing ********************************************/
1250
1251/* parse the "npn" bind keyword */
1252static int srv_parse_npn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1253{
1254#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1255 char *p1, *p2;
1256
1257 if (!*args[*cur_arg + 1]) {
1258 memprintf(err, "'%s' : missing the comma-delimited NPN protocol suite", args[*cur_arg]);
1259 return ERR_ALERT | ERR_FATAL;
1260 }
1261
1262 free(newsrv->ssl_ctx.npn_str);
1263
1264 /* the NPN string is built as a suite of (<len> <name>)*,
1265 * so we reuse each comma to store the next <len> and need
1266 * one more for the end of the string.
1267 */
1268 newsrv->ssl_ctx.npn_len = strlen(args[*cur_arg + 1]) + 1;
1269 newsrv->ssl_ctx.npn_str = calloc(1, newsrv->ssl_ctx.npn_len + 1);
1270 memcpy(newsrv->ssl_ctx.npn_str + 1, args[*cur_arg + 1],
1271 newsrv->ssl_ctx.npn_len);
1272
1273 /* replace commas with the name length */
1274 p1 = newsrv->ssl_ctx.npn_str;
1275 p2 = p1 + 1;
1276 while (1) {
1277 p2 = memchr(p1 + 1, ',', newsrv->ssl_ctx.npn_str +
1278 newsrv->ssl_ctx.npn_len - (p1 + 1));
1279 if (!p2)
1280 p2 = p1 + 1 + strlen(p1 + 1);
1281
1282 if (p2 - (p1 + 1) > 255) {
1283 *p2 = '\0';
1284 memprintf(err, "'%s' : NPN protocol name too long : '%s'", args[*cur_arg], p1 + 1);
1285 return ERR_ALERT | ERR_FATAL;
1286 }
1287
1288 *p1 = p2 - (p1 + 1);
1289 p1 = p2;
1290
1291 if (!*p2)
1292 break;
1293
1294 *(p2++) = '\0';
1295 }
1296 return 0;
1297#else
1298 memprintf(err, "'%s' : library does not support TLS NPN extension", args[*cur_arg]);
1299 return ERR_ALERT | ERR_FATAL;
1300#endif
1301}
1302
1303/* parse the "alpn" or the "check-alpn" server keyword */
1304static int srv_parse_alpn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1305{
1306#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1307 char **alpn_str;
1308 int *alpn_len;
1309 int ret;
1310
1311 if (*args[*cur_arg] == 'c') {
1312 alpn_str = &newsrv->check.alpn_str;
1313 alpn_len = &newsrv->check.alpn_len;
1314 } else {
1315 alpn_str = &newsrv->ssl_ctx.alpn_str;
1316 alpn_len = &newsrv->ssl_ctx.alpn_len;
1317
1318 }
1319
1320 free(*alpn_str);
1321 ret = ssl_sock_parse_alpn(args[*cur_arg + 1], alpn_str, alpn_len, err);
1322 if (ret)
1323 memprintf(err, "'%s' : %s", args[*cur_arg], *err);
1324 return ret;
1325#else
1326 memprintf(err, "'%s' : library does not support TLS ALPN extension", args[*cur_arg]);
1327 return ERR_ALERT | ERR_FATAL;
1328#endif
1329}
1330
1331/* parse the "ca-file" server keyword */
1332static int srv_parse_ca_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1333{
1334 if (!*args[*cur_arg + 1]) {
1335 memprintf(err, "'%s' : missing CAfile path", args[*cur_arg]);
1336 return ERR_ALERT | ERR_FATAL;
1337 }
1338
1339 if ((*args[*cur_arg + 1] != '/') && global_ssl.ca_base)
1340 memprintf(&newsrv->ssl_ctx.ca_file, "%s/%s", global_ssl.ca_base, args[*cur_arg + 1]);
1341 else
1342 memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]);
1343
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001344 if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file, 1)) {
William Lallemanddad31052020-05-14 17:47:32 +02001345 memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.ca_file);
1346 return ERR_ALERT | ERR_FATAL;
1347 }
1348 return 0;
1349}
1350
1351/* parse the "check-sni" server keyword */
1352static int srv_parse_check_sni(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1353{
1354 if (!*args[*cur_arg + 1]) {
1355 memprintf(err, "'%s' : missing SNI", args[*cur_arg]);
1356 return ERR_ALERT | ERR_FATAL;
1357 }
1358
1359 newsrv->check.sni = strdup(args[*cur_arg + 1]);
1360 if (!newsrv->check.sni) {
1361 memprintf(err, "'%s' : failed to allocate memory", args[*cur_arg]);
1362 return ERR_ALERT | ERR_FATAL;
1363 }
1364 return 0;
1365
1366}
1367
1368/* parse the "check-ssl" server keyword */
1369static int srv_parse_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1370{
1371 newsrv->check.use_ssl = 1;
1372 if (global_ssl.connect_default_ciphers && !newsrv->ssl_ctx.ciphers)
1373 newsrv->ssl_ctx.ciphers = strdup(global_ssl.connect_default_ciphers);
1374#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1375 if (global_ssl.connect_default_ciphersuites && !newsrv->ssl_ctx.ciphersuites)
1376 newsrv->ssl_ctx.ciphersuites = strdup(global_ssl.connect_default_ciphersuites);
1377#endif
1378 newsrv->ssl_ctx.options |= global_ssl.connect_default_ssloptions;
1379 newsrv->ssl_ctx.methods.flags |= global_ssl.connect_default_sslmethods.flags;
1380 if (!newsrv->ssl_ctx.methods.min)
1381 newsrv->ssl_ctx.methods.min = global_ssl.connect_default_sslmethods.min;
1382 if (!newsrv->ssl_ctx.methods.max)
1383 newsrv->ssl_ctx.methods.max = global_ssl.connect_default_sslmethods.max;
1384
1385 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
1401#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1402/* 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
Remi Tricot-Le Bretonbcec63e2021-03-23 16:41:53 +01001433 if (!ssl_store_load_locations_file(newsrv->ssl_ctx.crl_file, 1)) {
William Lallemanddad31052020-05-14 17:47:32 +02001434 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{
1444 if (!*args[*cur_arg + 1]) {
1445 memprintf(err, "'%s' : missing certificate file path", args[*cur_arg]);
1446 return ERR_ALERT | ERR_FATAL;
1447 }
1448
1449 if ((*args[*cur_arg + 1] != '/') && global_ssl.crt_base)
1450 memprintf(&newsrv->ssl_ctx.client_crt, "%s/%s", global_ssl.crt_base, args[*cur_arg + 1]);
1451 else
1452 memprintf(&newsrv->ssl_ctx.client_crt, "%s", args[*cur_arg + 1]);
1453
1454 return 0;
1455}
1456
1457/* parse the "no-check-ssl" server keyword */
1458static int srv_parse_no_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1459{
1460 newsrv->check.use_ssl = -1;
1461 free(newsrv->ssl_ctx.ciphers);
1462 newsrv->ssl_ctx.ciphers = NULL;
1463 newsrv->ssl_ctx.options &= ~global_ssl.connect_default_ssloptions;
1464 return 0;
1465}
1466
1467/* parse the "no-send-proxy-v2-ssl" server keyword */
1468static int srv_parse_no_send_proxy_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1469{
1470 newsrv->pp_opts &= ~SRV_PP_V2;
1471 newsrv->pp_opts &= ~SRV_PP_V2_SSL;
1472 return 0;
1473}
1474
1475/* parse the "no-send-proxy-v2-ssl-cn" server keyword */
1476static int srv_parse_no_send_proxy_cn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1477{
1478 newsrv->pp_opts &= ~SRV_PP_V2;
1479 newsrv->pp_opts &= ~SRV_PP_V2_SSL;
1480 newsrv->pp_opts &= ~SRV_PP_V2_SSL_CN;
1481 return 0;
1482}
1483
1484/* parse the "no-ssl" server keyword */
1485static int srv_parse_no_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1486{
1487 newsrv->use_ssl = -1;
1488 free(newsrv->ssl_ctx.ciphers);
1489 newsrv->ssl_ctx.ciphers = NULL;
1490 return 0;
1491}
1492
1493/* parse the "allow-0rtt" server keyword */
1494static int srv_parse_allow_0rtt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1495{
1496 newsrv->ssl_ctx.options |= SRV_SSL_O_EARLY_DATA;
1497 return 0;
1498}
1499
1500/* parse the "no-ssl-reuse" server keyword */
1501static int srv_parse_no_ssl_reuse(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1502{
1503 newsrv->ssl_ctx.options |= SRV_SSL_O_NO_REUSE;
1504 return 0;
1505}
1506
1507/* parse the "no-tls-tickets" server keyword */
1508static int srv_parse_no_tls_tickets(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1509{
1510 newsrv->ssl_ctx.options |= SRV_SSL_O_NO_TLS_TICKETS;
1511 return 0;
1512}
1513/* parse the "send-proxy-v2-ssl" server keyword */
1514static int srv_parse_send_proxy_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1515{
1516 newsrv->pp_opts |= SRV_PP_V2;
1517 newsrv->pp_opts |= SRV_PP_V2_SSL;
1518 return 0;
1519}
1520
1521/* parse the "send-proxy-v2-ssl-cn" server keyword */
1522static int srv_parse_send_proxy_cn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1523{
1524 newsrv->pp_opts |= SRV_PP_V2;
1525 newsrv->pp_opts |= SRV_PP_V2_SSL;
1526 newsrv->pp_opts |= SRV_PP_V2_SSL_CN;
1527 return 0;
1528}
1529
1530/* parse the "sni" server keyword */
1531static int srv_parse_sni(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1532{
1533#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
1534 memprintf(err, "'%s' : the current SSL library doesn't support the SNI TLS extension", args[*cur_arg]);
1535 return ERR_ALERT | ERR_FATAL;
1536#else
1537 char *arg;
1538
1539 arg = args[*cur_arg + 1];
1540 if (!*arg) {
1541 memprintf(err, "'%s' : missing sni expression", args[*cur_arg]);
1542 return ERR_ALERT | ERR_FATAL;
1543 }
1544
1545 free(newsrv->sni_expr);
1546 newsrv->sni_expr = strdup(arg);
1547
1548 return 0;
1549#endif
1550}
1551
1552/* parse the "ssl" server keyword */
1553static int srv_parse_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1554{
1555 newsrv->use_ssl = 1;
1556 if (global_ssl.connect_default_ciphers && !newsrv->ssl_ctx.ciphers)
1557 newsrv->ssl_ctx.ciphers = strdup(global_ssl.connect_default_ciphers);
1558#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1559 if (global_ssl.connect_default_ciphersuites && !newsrv->ssl_ctx.ciphersuites)
1560 newsrv->ssl_ctx.ciphersuites = strdup(global_ssl.connect_default_ciphersuites);
1561#endif
1562 newsrv->ssl_ctx.options |= global_ssl.connect_default_ssloptions;
1563 newsrv->ssl_ctx.methods.flags |= global_ssl.connect_default_sslmethods.flags;
1564
1565 if (!newsrv->ssl_ctx.methods.min)
1566 newsrv->ssl_ctx.methods.min = global_ssl.connect_default_sslmethods.min;
1567
1568 if (!newsrv->ssl_ctx.methods.max)
1569 newsrv->ssl_ctx.methods.max = global_ssl.connect_default_sslmethods.max;
1570
1571
1572 return 0;
1573}
1574
1575/* parse the "ssl-reuse" server keyword */
1576static int srv_parse_ssl_reuse(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1577{
1578 newsrv->ssl_ctx.options &= ~SRV_SSL_O_NO_REUSE;
1579 return 0;
1580}
1581
1582/* parse the "tls-tickets" server keyword */
1583static int srv_parse_tls_tickets(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1584{
1585 newsrv->ssl_ctx.options &= ~SRV_SSL_O_NO_TLS_TICKETS;
1586 return 0;
1587}
1588
1589/* parse the "verify" server keyword */
1590static int srv_parse_verify(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1591{
1592 if (!*args[*cur_arg + 1]) {
1593 memprintf(err, "'%s' : missing verify method", args[*cur_arg]);
1594 return ERR_ALERT | ERR_FATAL;
1595 }
1596
1597 if (strcmp(args[*cur_arg + 1], "none") == 0)
1598 newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_NONE;
1599 else if (strcmp(args[*cur_arg + 1], "required") == 0)
1600 newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_REQUIRED;
1601 else {
1602 memprintf(err, "'%s' : unknown verify method '%s', only 'none' and 'required' are supported\n",
1603 args[*cur_arg], args[*cur_arg + 1]);
1604 return ERR_ALERT | ERR_FATAL;
1605 }
1606
1607 return 0;
1608}
1609
1610/* parse the "verifyhost" server keyword */
1611static int srv_parse_verifyhost(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1612{
1613 if (!*args[*cur_arg + 1]) {
1614 memprintf(err, "'%s' : missing hostname to verify against", args[*cur_arg]);
1615 return ERR_ALERT | ERR_FATAL;
1616 }
1617
1618 free(newsrv->ssl_ctx.verify_host);
1619 newsrv->ssl_ctx.verify_host = strdup(args[*cur_arg + 1]);
1620
1621 return 0;
1622}
1623
1624/* parse the "ssl-default-bind-options" keyword in global section */
1625static int ssl_parse_default_bind_options(char **args, int section_type, struct proxy *curpx,
1626 struct proxy *defpx, const char *file, int line,
1627 char **err) {
1628 int i = 1;
1629
1630 if (*(args[i]) == 0) {
1631 memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
1632 return -1;
1633 }
1634 while (*(args[i])) {
1635 if (!strcmp(args[i], "no-tls-tickets"))
1636 global_ssl.listen_default_ssloptions |= BC_SSL_O_NO_TLS_TICKETS;
1637 else if (!strcmp(args[i], "prefer-client-ciphers"))
1638 global_ssl.listen_default_ssloptions |= BC_SSL_O_PREF_CLIE_CIPH;
1639 else if (!strcmp(args[i], "ssl-min-ver") || !strcmp(args[i], "ssl-max-ver")) {
1640 if (!parse_tls_method_minmax(args, i, &global_ssl.listen_default_sslmethods, err))
1641 i++;
1642 else {
1643 memprintf(err, "%s on global statement '%s'.", *err, args[0]);
1644 return -1;
1645 }
1646 }
1647 else if (parse_tls_method_options(args[i], &global_ssl.listen_default_sslmethods, err)) {
1648 memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
1649 return -1;
1650 }
1651 i++;
1652 }
1653 return 0;
1654}
1655
1656/* parse the "ssl-default-server-options" keyword in global section */
1657static int ssl_parse_default_server_options(char **args, int section_type, struct proxy *curpx,
1658 struct proxy *defpx, const char *file, int line,
1659 char **err) {
1660 int i = 1;
1661
1662 if (*(args[i]) == 0) {
1663 memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
1664 return -1;
1665 }
1666 while (*(args[i])) {
1667 if (!strcmp(args[i], "no-tls-tickets"))
1668 global_ssl.connect_default_ssloptions |= SRV_SSL_O_NO_TLS_TICKETS;
1669 else if (!strcmp(args[i], "ssl-min-ver") || !strcmp(args[i], "ssl-max-ver")) {
1670 if (!parse_tls_method_minmax(args, i, &global_ssl.connect_default_sslmethods, err))
1671 i++;
1672 else {
1673 memprintf(err, "%s on global statement '%s'.", *err, args[0]);
1674 return -1;
1675 }
1676 }
1677 else if (parse_tls_method_options(args[i], &global_ssl.connect_default_sslmethods, err)) {
1678 memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
1679 return -1;
1680 }
1681 i++;
1682 }
1683 return 0;
1684}
1685
1686/* parse the "ca-base" / "crt-base" keywords in global section.
1687 * Returns <0 on alert, >0 on warning, 0 on success.
1688 */
1689static int ssl_parse_global_ca_crt_base(char **args, int section_type, struct proxy *curpx,
1690 struct proxy *defpx, const char *file, int line,
1691 char **err)
1692{
1693 char **target;
1694
1695 target = (args[0][1] == 'a') ? &global_ssl.ca_base : &global_ssl.crt_base;
1696
1697 if (too_many_args(1, args, err, NULL))
1698 return -1;
1699
1700 if (*target) {
1701 memprintf(err, "'%s' already specified.", args[0]);
1702 return -1;
1703 }
1704
1705 if (*(args[1]) == 0) {
1706 memprintf(err, "global statement '%s' expects a directory path as an argument.", args[0]);
1707 return -1;
1708 }
1709 *target = strdup(args[1]);
1710 return 0;
1711}
1712
1713/* parse the "ssl-skip-self-issued-ca" keyword in global section. */
1714static int ssl_parse_skip_self_issued_ca(char **args, int section_type, struct proxy *curpx,
1715 struct proxy *defpx, const char *file, int line,
1716 char **err)
1717{
William Lallemand9a1d8392020-08-10 17:28:23 +02001718#ifdef SSL_CTX_build_cert_chain
William Lallemanddad31052020-05-14 17:47:32 +02001719 global_ssl.skip_self_issued_ca = 1;
1720 return 0;
William Lallemand9a1d8392020-08-10 17:28:23 +02001721#else
1722 memprintf(err, "global statement '%s' requires at least OpenSSL 1.0.2.", args[0]);
1723 return -1;
1724#endif
William Lallemanddad31052020-05-14 17:47:32 +02001725}
1726
1727
1728
1729
1730
1731/* Note: must not be declared <const> as its list will be overwritten.
1732 * Please take care of keeping this list alphabetically sorted, doing so helps
1733 * all code contributors.
1734 * Optional keywords are also declared with a NULL ->parse() function so that
1735 * the config parser can report an appropriate error when a known keyword was
1736 * not enabled.
1737 */
1738
1739/* the <ssl_bind_kws> keywords are used for crt-list parsing, they *MUST* be safe
1740 * with their proxy argument NULL and must only fill the ssl_bind_conf */
1741struct ssl_bind_kw ssl_bind_kws[] = {
1742 { "allow-0rtt", ssl_bind_parse_allow_0rtt, 0 }, /* allow 0-RTT */
1743 { "alpn", ssl_bind_parse_alpn, 1 }, /* set ALPN supported protocols */
1744 { "ca-file", ssl_bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */
1745 { "ca-verify-file", ssl_bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */
1746 { "ciphers", ssl_bind_parse_ciphers, 1 }, /* set SSL cipher suite */
1747#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1748 { "ciphersuites", ssl_bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */
1749#endif
1750 { "crl-file", ssl_bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */
1751 { "curves", ssl_bind_parse_curves, 1 }, /* set SSL curve suite */
1752 { "ecdhe", ssl_bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
1753 { "no-ca-names", ssl_bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
1754 { "npn", ssl_bind_parse_npn, 1 }, /* set NPN supported protocols */
1755 { "ssl-min-ver", ssl_bind_parse_tls_method_minmax,1 }, /* minimum version */
1756 { "ssl-max-ver", ssl_bind_parse_tls_method_minmax,1 }, /* maximum version */
1757 { "verify", ssl_bind_parse_verify, 1 }, /* set SSL verify method */
1758 { NULL, NULL, 0 },
1759};
1760
1761/* no initcall for ssl_bind_kws, these ones are parsed in the parser loop */
1762
1763static struct bind_kw_list bind_kws = { "SSL", { }, {
1764 { "allow-0rtt", bind_parse_allow_0rtt, 0 }, /* Allow 0RTT */
1765 { "alpn", bind_parse_alpn, 1 }, /* set ALPN supported protocols */
1766 { "ca-file", bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */
1767 { "ca-verify-file", bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */
1768 { "ca-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth > 0 */
1769 { "ca-sign-file", bind_parse_ca_sign_file, 1 }, /* set CAFile used to generate and sign server certs */
1770 { "ca-sign-pass", bind_parse_ca_sign_pass, 1 }, /* set CAKey passphrase */
1771 { "ciphers", bind_parse_ciphers, 1 }, /* set SSL cipher suite */
1772#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1773 { "ciphersuites", bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */
1774#endif
1775 { "crl-file", bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */
1776 { "crt", bind_parse_crt, 1 }, /* load SSL certificates from this location */
1777 { "crt-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth == 0 */
1778 { "crt-list", bind_parse_crt_list, 1 }, /* load a list of crt from this location */
1779 { "curves", bind_parse_curves, 1 }, /* set SSL curve suite */
1780 { "ecdhe", bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
1781 { "force-sslv3", bind_parse_tls_method_options, 0 }, /* force SSLv3 */
1782 { "force-tlsv10", bind_parse_tls_method_options, 0 }, /* force TLSv10 */
1783 { "force-tlsv11", bind_parse_tls_method_options, 0 }, /* force TLSv11 */
1784 { "force-tlsv12", bind_parse_tls_method_options, 0 }, /* force TLSv12 */
1785 { "force-tlsv13", bind_parse_tls_method_options, 0 }, /* force TLSv13 */
1786 { "generate-certificates", bind_parse_generate_certs, 0 }, /* enable the server certificates generation */
1787 { "no-ca-names", bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
1788 { "no-sslv3", bind_parse_tls_method_options, 0 }, /* disable SSLv3 */
1789 { "no-tlsv10", bind_parse_tls_method_options, 0 }, /* disable TLSv10 */
1790 { "no-tlsv11", bind_parse_tls_method_options, 0 }, /* disable TLSv11 */
1791 { "no-tlsv12", bind_parse_tls_method_options, 0 }, /* disable TLSv12 */
1792 { "no-tlsv13", bind_parse_tls_method_options, 0 }, /* disable TLSv13 */
1793 { "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
1794 { "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */
1795 { "ssl-min-ver", bind_parse_tls_method_minmax, 1 }, /* minimum version */
1796 { "ssl-max-ver", bind_parse_tls_method_minmax, 1 }, /* maximum version */
1797 { "strict-sni", bind_parse_strict_sni, 0 }, /* refuse negotiation if sni doesn't match a certificate */
1798 { "tls-ticket-keys", bind_parse_tls_ticket_keys, 1 }, /* set file to load TLS ticket keys from */
1799 { "verify", bind_parse_verify, 1 }, /* set SSL verify method */
1800 { "npn", bind_parse_npn, 1 }, /* set NPN supported protocols */
1801 { "prefer-client-ciphers", bind_parse_pcc, 0 }, /* prefer client ciphers */
1802 { NULL, NULL, 0 },
1803}};
1804
1805INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
1806
1807/* Note: must not be declared <const> as its list will be overwritten.
1808 * Please take care of keeping this list alphabetically sorted, doing so helps
1809 * all code contributors.
1810 * Optional keywords are also declared with a NULL ->parse() function so that
1811 * the config parser can report an appropriate error when a known keyword was
1812 * not enabled.
1813 */
1814static struct srv_kw_list srv_kws = { "SSL", { }, {
1815 { "allow-0rtt", srv_parse_allow_0rtt, 0, 1 }, /* Allow using early data on this server */
1816 { "alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN supported protocols */
1817 { "ca-file", srv_parse_ca_file, 1, 1 }, /* set CAfile to process verify server cert */
1818 { "check-alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN used for checks */
1819 { "check-sni", srv_parse_check_sni, 1, 1 }, /* set SNI */
1820 { "check-ssl", srv_parse_check_ssl, 0, 1 }, /* enable SSL for health checks */
1821 { "ciphers", srv_parse_ciphers, 1, 1 }, /* select the cipher suite */
1822#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1823 { "ciphersuites", srv_parse_ciphersuites, 1, 1 }, /* select the cipher suite */
1824#endif
1825 { "crl-file", srv_parse_crl_file, 1, 1 }, /* set certificate revocation list file use on server cert verify */
1826 { "crt", srv_parse_crt, 1, 1 }, /* set client certificate */
1827 { "force-sslv3", srv_parse_tls_method_options, 0, 1 }, /* force SSLv3 */
1828 { "force-tlsv10", srv_parse_tls_method_options, 0, 1 }, /* force TLSv10 */
1829 { "force-tlsv11", srv_parse_tls_method_options, 0, 1 }, /* force TLSv11 */
1830 { "force-tlsv12", srv_parse_tls_method_options, 0, 1 }, /* force TLSv12 */
1831 { "force-tlsv13", srv_parse_tls_method_options, 0, 1 }, /* force TLSv13 */
1832 { "no-check-ssl", srv_parse_no_check_ssl, 0, 1 }, /* disable SSL for health checks */
1833 { "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1 }, /* do not send PROXY protocol header v2 with SSL info */
1834 { "no-send-proxy-v2-ssl-cn", srv_parse_no_send_proxy_cn, 0, 1 }, /* do not send PROXY protocol header v2 with CN */
1835 { "no-ssl", srv_parse_no_ssl, 0, 1 }, /* disable SSL processing */
1836 { "no-ssl-reuse", srv_parse_no_ssl_reuse, 0, 1 }, /* disable session reuse */
1837 { "no-sslv3", srv_parse_tls_method_options, 0, 0 }, /* disable SSLv3 */
1838 { "no-tlsv10", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv10 */
1839 { "no-tlsv11", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv11 */
1840 { "no-tlsv12", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv12 */
1841 { "no-tlsv13", srv_parse_tls_method_options, 0, 0 }, /* disable TLSv13 */
1842 { "no-tls-tickets", srv_parse_no_tls_tickets, 0, 1 }, /* disable session resumption tickets */
1843 { "npn", srv_parse_npn, 1, 1 }, /* Set NPN supported protocols */
1844 { "send-proxy-v2-ssl", srv_parse_send_proxy_ssl, 0, 1 }, /* send PROXY protocol header v2 with SSL info */
1845 { "send-proxy-v2-ssl-cn", srv_parse_send_proxy_cn, 0, 1 }, /* send PROXY protocol header v2 with CN */
1846 { "sni", srv_parse_sni, 1, 1 }, /* send SNI extension */
1847 { "ssl", srv_parse_ssl, 0, 1 }, /* enable SSL processing */
1848 { "ssl-min-ver", srv_parse_tls_method_minmax, 1, 1 }, /* minimum version */
1849 { "ssl-max-ver", srv_parse_tls_method_minmax, 1, 1 }, /* maximum version */
1850 { "ssl-reuse", srv_parse_ssl_reuse, 0, 1 }, /* enable session reuse */
1851 { "tls-tickets", srv_parse_tls_tickets, 0, 1 }, /* enable session resumption tickets */
1852 { "verify", srv_parse_verify, 1, 1 }, /* set SSL verify method */
1853 { "verifyhost", srv_parse_verifyhost, 1, 1 }, /* require that SSL cert verifies for hostname */
1854 { NULL, NULL, 0, 0 },
1855}};
1856
1857INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
1858
1859static struct cfg_kw_list cfg_kws = {ILH, {
1860 { CFG_GLOBAL, "ca-base", ssl_parse_global_ca_crt_base },
1861 { CFG_GLOBAL, "crt-base", ssl_parse_global_ca_crt_base },
1862 { CFG_GLOBAL, "issuers-chain-path", ssl_load_global_issuers_from_path },
1863 { CFG_GLOBAL, "maxsslconn", ssl_parse_global_int },
1864 { CFG_GLOBAL, "ssl-default-bind-options", ssl_parse_default_bind_options },
1865 { CFG_GLOBAL, "ssl-default-server-options", ssl_parse_default_server_options },
1866#ifndef OPENSSL_NO_DH
1867 { CFG_GLOBAL, "ssl-dh-param-file", ssl_parse_global_dh_param_file },
1868#endif
1869 { CFG_GLOBAL, "ssl-mode-async", ssl_parse_global_ssl_async },
1870#ifndef OPENSSL_NO_ENGINE
1871 { CFG_GLOBAL, "ssl-engine", ssl_parse_global_ssl_engine },
1872#endif
1873 { CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
1874 { CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
1875#ifndef OPENSSL_NO_DH
1876 { CFG_GLOBAL, "tune.ssl.default-dh-param", ssl_parse_global_default_dh },
1877#endif
1878 { CFG_GLOBAL, "tune.ssl.force-private-cache", ssl_parse_global_private_cache },
1879 { CFG_GLOBAL, "tune.ssl.lifetime", ssl_parse_global_lifetime },
1880 { CFG_GLOBAL, "tune.ssl.maxrecord", ssl_parse_global_int },
1881 { CFG_GLOBAL, "tune.ssl.ssl-ctx-cache-size", ssl_parse_global_int },
1882 { CFG_GLOBAL, "tune.ssl.capture-cipherlist-size", ssl_parse_global_capture_cipherlist },
William Lallemand7d42ef52020-07-06 11:41:30 +02001883 { CFG_GLOBAL, "tune.ssl.keylog", ssl_parse_global_keylog },
William Lallemanddad31052020-05-14 17:47:32 +02001884 { CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
1885 { CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
Ilya Shipitsin0aa8c292020-11-04 00:39:07 +05001886#if defined(SSL_CTX_set1_curves_list)
William Lallemanddad31052020-05-14 17:47:32 +02001887 { CFG_GLOBAL, "ssl-default-bind-curves", ssl_parse_global_curves },
1888#endif
1889#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
1890 { CFG_GLOBAL, "ssl-default-bind-ciphersuites", ssl_parse_global_ciphersuites },
1891 { CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
1892#endif
1893 { CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
William Lallemand8e8581e2020-10-20 17:36:46 +02001894 { CFG_GLOBAL, "ssl-load-extra-del-ext", ssl_parse_global_extra_noext },
William Lallemanddad31052020-05-14 17:47:32 +02001895 { 0, NULL, NULL },
1896}};
1897
1898INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);