1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2026-06-09 21:08:41 +02:00

Allow configuration of TLS cipher suites.

Configuration of specific cipher suites may be required for compliance or to use preferred ciphers for security.

Cipher suites are applied to the entire process and cannot be configured on a per-connection basis, except that for object store clients (e.g. S3) verification can be disabled.
This commit is contained in:
Gunnar "Nick" Bluth
2026-01-08 03:17:17 +01:00
committed by GitHub
parent 5b4b20a8d7
commit fbc607a48b
12 changed files with 332 additions and 2 deletions
+12
View File
@@ -57,6 +57,18 @@
<p>Support for <proper>Azure</proper> managed identities.</p>
</release-item>
<release-item>
<github-issue id="2697"/>
<github-pull-request id="2700"/>
<release-item-contributor-list>
<release-item-contributor id="gunnar.bluth"/>
<release-item-reviewer id="david.steele"/>
</release-item-contributor-list>
<p>Allow configuration of TLS cipher suites.</p>
</release-item>
<release-item>
<github-pull-request id="2693"/>
+10
View File
@@ -952,6 +952,16 @@ option:
command: buffer-size
depend: tcp-keep-alive-count
# TLS allowed ciphers
tls-cipher-12:
section: global
type: string
required: false
command: buffer-size
tls-cipher-13:
inherit: tls-cipher-12
# Logging options
#---------------------------------------------------------------------------------------------------------------------------------
log-level-console:
+29
View File
@@ -430,6 +430,35 @@
<example>30</example>
</config-key>
<config-key id="tls-cipher-12" name="TLSv1.2 cipher suites">
<summary>Allowed TLSv1.2 cipher suites.</summary>
<text>
<p>All TLS connections between the <backrest/> client and server are encrypted. By default, connections to objects stores (e.g. <proper>S3</proper>) are also encrypted.</p>
<admonition type="note">The absolute minimum security level for any transport connection is TLSv1.2.</admonition>
<p>The accepted cipher suites can be adjusted if need arises. The example is reasonable choice unless you have specific security requirements. If unset (the default), the default of the underlying <proper>OpenSSL</proper> library applies.</p>
</text>
<example>HIGH:MEDIUM:+3DES:!aNULL</example>
</config-key>
<config-key id="tls-cipher-13" name="TLSv1.3 cipher suites">
<summary>Allowed TLSv1.3 cipher suites.</summary>
<text>
<p>All TLS connections between the <backrest/> client and server are encrypted. By default, connections to objects stores (e.g. <proper>S3</proper>) are also encrypted.</p>
<admonition type="note">The absolute minimum security level for any transport connection is TLSv1.2.</admonition>
<p>The accepted cipher suites can be adjusted if need arises. If unset (the default), the default of the underlying <proper>OpenSSL</proper> library applies.</p>
</text>
<example>TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256</example>
</config-key>
</config-key-list>
</config-section>
+48
View File
@@ -14,6 +14,17 @@ TLS Common
#include "common/user.h"
#include "storage/posix/storage.h"
/***********************************************************************************************************************************
Local variables
***********************************************************************************************************************************/
static struct TlsCommonLocal
{
MemContext *memContext; // Mem context for TLS common
String *tlsCipher12; // Allowed ciphers for TLSv1.2
String *tlsCipher13; // Allowed ciphers for TLSv1.3
} tlsCommonLocal;
/**********************************************************************************************************************************/
FN_EXTERN Buffer *
tlsAsn1ToBuf(const ASN1_STRING *const nameAsn1)
@@ -172,6 +183,35 @@ tlsCertKeyLoad(SSL_CTX *const context, const String *const certFile, const Strin
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
FN_EXTERN void
tlsInit(const String *const tlsCipher12, const String *const tlsCipher13)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, tlsCipher12);
FUNCTION_TEST_PARAM(STRING, tlsCipher13);
FUNCTION_TEST_END();
// Free old mem context (if any)
if (tlsCommonLocal.memContext != NULL)
memContextFree(tlsCommonLocal.memContext);
// Initialize mem context
MEM_CONTEXT_BEGIN(memContextTop())
{
MEM_CONTEXT_NEW_BEGIN(TlsCommon, .childQty = MEM_CONTEXT_QTY_MAX)
{
tlsCommonLocal.memContext = MEM_CONTEXT_NEW();
tlsCommonLocal.tlsCipher12 = strDup(tlsCipher12);
tlsCommonLocal.tlsCipher13 = strDup(tlsCipher13);
}
MEM_CONTEXT_NEW_END();
}
MEM_CONTEXT_END();
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
FN_EXTERN SSL_CTX *
tlsContext(const bool verifyPeer)
@@ -200,6 +240,14 @@ tlsContext(const bool verifyPeer)
{
// Set minimum TLS version to 1.2
cryptoError(SSL_CTX_set_min_proto_version(result, TLS1_2_VERSION) != 1, "unable to set minumum TLS version to 1.2");
// Set allowed ciphers for TLSv1.2 when configured
if (tlsCommonLocal.tlsCipher12 != NULL)
cryptoError(SSL_CTX_set_cipher_list(result, strZ(tlsCommonLocal.tlsCipher12)) != 1, "unable to set TLSv1.2 ciphers");
// Set allowed ciphers for TLSv1.3 when configured
if (tlsCommonLocal.tlsCipher13 != NULL)
cryptoError(SSL_CTX_set_ciphersuites(result, strZ(tlsCommonLocal.tlsCipher13)) != 1, "unable to set TLSv1.3 ciphers");
}
FUNCTION_TEST_RETURN_TYPE_P(SSL_CTX, result);
+3
View File
@@ -11,6 +11,9 @@ TLS Common
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
// Initialize TLS with allowed ciphers
FN_EXTERN void tlsInit(const String *tlsCipher12, const String *tlsCipher13);
// Convert an ASN1 string used in certificates to a Buffer
FN_EXTERN Buffer *tlsAsn1ToBuf(const ASN1_STRING *nameAsn1);
+5 -1
View File
@@ -132,6 +132,8 @@ Option constants
#define CFGOPT_TCP_KEEP_ALIVE_COUNT "tcp-keep-alive-count"
#define CFGOPT_TCP_KEEP_ALIVE_IDLE "tcp-keep-alive-idle"
#define CFGOPT_TCP_KEEP_ALIVE_INTERVAL "tcp-keep-alive-interval"
#define CFGOPT_TLS_CIPHER_12 "tls-cipher-12"
#define CFGOPT_TLS_CIPHER_13 "tls-cipher-13"
#define CFGOPT_TLS_SERVER_ADDRESS "tls-server-address"
#define CFGOPT_TLS_SERVER_AUTH "tls-server-auth"
#define CFGOPT_TLS_SERVER_CA_FILE "tls-server-ca-file"
@@ -142,7 +144,7 @@ Option constants
#define CFGOPT_VERBOSE "verbose"
#define CFGOPT_VERSION "version"
#define CFG_OPTION_TOTAL 190
#define CFG_OPTION_TOTAL 192
/***********************************************************************************************************************************
Option value constants
@@ -585,6 +587,8 @@ typedef enum
cfgOptTcpKeepAliveCount,
cfgOptTcpKeepAliveIdle,
cfgOptTcpKeepAliveInterval,
cfgOptTlsCipher12,
cfgOptTlsCipher13,
cfgOptTlsServerAddress,
cfgOptTlsServerAuth,
cfgOptTlsServerCaFile,
+8
View File
@@ -14,6 +14,7 @@ Configuration Load
#include "common/debug.h"
#include "common/io/io.h"
#include "common/io/socket/common.h"
#include "common/io/tls/common.h"
#include "common/log.h"
#include "common/memContext.h"
#include "config/config.intern.h"
@@ -492,6 +493,13 @@ cfgLoad(const unsigned int argListSize, const char *argList[])
cfgOptionTest(cfgOptTcpKeepAliveInterval) ? cfgOptionInt(cfgOptTcpKeepAliveInterval) : 0);
}
// Initialize TLS settings
if (cfgOptionValid(cfgOptTlsCipher12))
{
ASSERT(cfgOptionValid(cfgOptTlsCipher13));
tlsInit(cfgOptionStrNull(cfgOptTlsCipher12), cfgOptionStrNull(cfgOptTlsCipher13));
}
// Set IO buffer size (use the default for help to lower memory usage)
if (cfgOptionValid(cfgOptBufferSize) && !cfgCommandHelp())
ioBufferSizeSet(cfgOptionUInt(cfgOptBufferSize));
+138
View File
@@ -11138,6 +11138,142 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
), // opt/tcp-keep-alive-interval
), // opt/tcp-keep-alive-interval
// -----------------------------------------------------------------------------------------------------------------------------
PARSE_RULE_OPTION // opt/tls-cipher-12
( // opt/tls-cipher-12
PARSE_RULE_OPTION_NAME("tls-cipher-12"), // opt/tls-cipher-12
PARSE_RULE_OPTION_TYPE(String), // opt/tls-cipher-12
PARSE_RULE_OPTION_RESET(true), // opt/tls-cipher-12
PARSE_RULE_OPTION_REQUIRED(false), // opt/tls-cipher-12
PARSE_RULE_OPTION_SECTION(Global), // opt/tls-cipher-12
// opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/tls-cipher-12
( // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Annotate) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Backup) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Check) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Expire) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Info) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Manifest) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoGet) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoLs) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoPut) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoRm) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Restore) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Server) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ServerPing) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(StanzaCreate) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(StanzaDelete) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(StanzaUpgrade) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Verify) // opt/tls-cipher-12
), // opt/tls-cipher-12
// opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/tls-cipher-12
( // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-12
), // opt/tls-cipher-12
// opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/tls-cipher-12
( // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Backup) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Restore) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Verify) // opt/tls-cipher-12
), // opt/tls-cipher-12
// opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/tls-cipher-12
( // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Annotate) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Backup) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Check) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Expire) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Info) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Manifest) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoGet) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoLs) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoPut) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(RepoRm) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Restore) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(StanzaCreate) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(StanzaDelete) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(StanzaUpgrade) // opt/tls-cipher-12
PARSE_RULE_OPTION_COMMAND(Verify) // opt/tls-cipher-12
), // opt/tls-cipher-12
), // opt/tls-cipher-12
// -----------------------------------------------------------------------------------------------------------------------------
PARSE_RULE_OPTION // opt/tls-cipher-13
( // opt/tls-cipher-13
PARSE_RULE_OPTION_NAME("tls-cipher-13"), // opt/tls-cipher-13
PARSE_RULE_OPTION_TYPE(String), // opt/tls-cipher-13
PARSE_RULE_OPTION_RESET(true), // opt/tls-cipher-13
PARSE_RULE_OPTION_REQUIRED(false), // opt/tls-cipher-13
PARSE_RULE_OPTION_SECTION(Global), // opt/tls-cipher-13
// opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/tls-cipher-13
( // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Annotate) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Backup) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Check) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Expire) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Info) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Manifest) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoGet) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoLs) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoPut) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoRm) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Restore) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Server) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ServerPing) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(StanzaCreate) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(StanzaDelete) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(StanzaUpgrade) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Verify) // opt/tls-cipher-13
), // opt/tls-cipher-13
// opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/tls-cipher-13
( // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-13
), // opt/tls-cipher-13
// opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/tls-cipher-13
( // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Backup) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Restore) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Verify) // opt/tls-cipher-13
), // opt/tls-cipher-13
// opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/tls-cipher-13
( // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Annotate) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchiveGet) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(ArchivePush) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Backup) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Check) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Expire) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Info) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Manifest) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoGet) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoLs) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoPut) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(RepoRm) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Restore) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(StanzaCreate) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(StanzaDelete) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(StanzaUpgrade) // opt/tls-cipher-13
PARSE_RULE_OPTION_COMMAND(Verify) // opt/tls-cipher-13
), // opt/tls-cipher-13
), // opt/tls-cipher-13
// -----------------------------------------------------------------------------------------------------------------------------
PARSE_RULE_OPTION // opt/tls-server-address
( // opt/tls-server-address
PARSE_RULE_OPTION_NAME("tls-server-address"), // opt/tls-server-address
@@ -11741,6 +11877,8 @@ static const uint8_t optionResolveOrder[] =
cfgOptTcpKeepAliveCount, // opt-resolve-order
cfgOptTcpKeepAliveIdle, // opt-resolve-order
cfgOptTcpKeepAliveInterval, // opt-resolve-order
cfgOptTlsCipher12, // opt-resolve-order
cfgOptTlsCipher13, // opt-resolve-order
cfgOptTlsServerAddress, // opt-resolve-order
cfgOptTlsServerAuth, // opt-resolve-order
cfgOptTlsServerCaFile, // opt-resolve-order
+1
View File
@@ -530,6 +530,7 @@ unit:
include:
- common/io/socket/common
- common/io/tls/common
# ----------------------------------------------------------------------------------------------------------------------------
- name: exec
+2
View File
@@ -278,6 +278,8 @@ testRun(void)
" --tcp-keep-alive-count keep-alive count\n"
" --tcp-keep-alive-idle keep-alive idle time\n"
" --tcp-keep-alive-interval keep-alive interval time\n"
" --tls-cipher-12 allowed TLSv1.2 cipher suites\n"
" --tls-cipher-13 allowed TLSv1.3 cipher suites\n"
"\n"
"Log Options:\n"
"\n"
+58
View File
@@ -917,6 +917,64 @@ testRun(void)
}
HRN_FORK_END();
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("fail on mismatch between allowed TLS cipher suites");
HRN_FORK_BEGIN()
{
const unsigned int testPort = hrnServerPortNext();
HRN_FORK_CHILD_BEGIN(.prefix = "test server", .timeout = 5000)
{
TEST_RESULT_VOID(tlsInit(STRDEF("eNULL"), STRDEF("TLS_AES_256_GCM_SHA384")), "disallow TLS 1.2");
// Start server to test various certificate errors
TEST_ERROR_MULTI(
hrnServerRunP(
HRN_FORK_CHILD_READ(), hrnServerProtocolTls, testPort, .certificate = STRDEF(HRN_SERVER_CERT),
.key = STRDEF(HRN_SERVER_KEY), .address = STRDEF("::1")),
ServiceError,
// TLS >= 3
"TLS error [1:167772353] no shared cipher",
// TLS < 3
"TLS error [1:337678529] no shared cipher");
}
HRN_FORK_CHILD_END();
HRN_FORK_PARENT_BEGIN(.prefix = "test client", .timeout = 1000)
{
IoWrite *const tls = hrnServerScriptBegin(HRN_FORK_PARENT_WRITE(0));
// -----------------------------------------------------------------------------------------------------------------
TEST_TITLE("cipher suite mismatch");
hrnServerScriptAccept(tls);
hrnServerScriptClose(tls);
TEST_RESULT_VOID(tlsInit(STRDEF("COMPLEMENTOFALL"), STRDEF("TLS_AES_128_GCM_SHA256")), "disallow TLS 1.3");
TEST_ERROR_MULTI(
ioClientOpen(
tlsClientNewP(
sckClientNew(STRDEF("::1"), testPort, 5000, 5000), STRDEF("::1"), 0, 0, true,
.caFile = STRDEF(HRN_SERVER_CA))),
ServiceError,
// TLS >= 3
"TLS error [1:167773200] sslv3 alert handshake failure",
// TLS < 3
"TLS error [1:336151568] sslv3 alert handshake failure",
// TLS >= 3 Fedora/Alpine
"TLS error [1:167773200] ssl/tls alert handshake failure");
// -----------------------------------------------------------------------------------------------------------------
hrnServerScriptEnd(tls);
}
HRN_FORK_PARENT_END();
}
HRN_FORK_END();
TEST_RESULT_VOID(tlsInit(NULL, NULL), "init null tls ciphers");
// Server on IPv6
// -------------------------------------------------------------------------------------------------------------------------
HRN_FORK_BEGIN()
+18 -1
View File
@@ -731,12 +731,29 @@ testRun(void)
if (testBegin("cfgLoad()"))
{
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("dry-run valid, --no-dry-run");
TEST_TITLE("TLS cipher suites");
StringList *argList = strLstNew();
strLstAddZ(argList, PROJECT_BIN);
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
hrnCfgArgRawZ(argList, cfgOptLockPath, HRN_PATH "/lock");
hrnCfgArgRawZ(argList, cfgOptTlsCipher12, "HIGH:MEDIUM:+3DES:!aNULL");
hrnCfgArgRawZ(argList, cfgOptTlsCipher13, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256");
strLstAddZ(argList, CFGCMD_EXPIRE);
TEST_RESULT_VOID(cfgLoad(strLstSize(argList), strLstPtr(argList)), "load config");
TEST_RESULT_STR_Z(tlsCommonLocal.tlsCipher12, "HIGH:MEDIUM:+3DES:!aNULL", "check tls1.2 cipher suites");
TEST_RESULT_STR_Z(
tlsCommonLocal.tlsCipher13, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256", "check tls1.3 cipher suites");
cmdLockReleaseP();
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("dry-run valid, --no-dry-run");
argList = strLstNew();
strLstAddZ(argList, PROJECT_BIN);
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
hrnCfgArgRawZ(argList, cfgOptLockPath, HRN_PATH "/lock");
hrnCfgArgRawZ(argList, cfgOptLogLevelStderr, CFGOPTVAL_ARCHIVE_MODE_OFF_Z);
strLstAddZ(argList, CFGCMD_EXPIRE);