From a337c74ea4ac29156e5e8d8ca200d7d6d46c670c Mon Sep 17 00:00:00 2001 From: Moritz Grimm Date: Fri, 4 Mar 2016 18:20:17 +0100 Subject: [PATCH] Update TLS configuration to match libshout requirements --- doc/ezstream.1.in.in | 37 +++++++++++++++++++------ examples/ezstream-full.xml | 21 ++++++++++---- src/cfg.c | 57 +++++++++++++++++++++++++++++--------- src/cfg.h | 17 ++++++++++-- src/cfg_private.h | 4 ++- src/cfg_xmlfile.c | 7 +++-- tests/check_cfg.c | 35 +++++++++++++++++------ tests/config-bad.xml | 3 +- 8 files changed, 139 insertions(+), 42 deletions(-) diff --git a/doc/ezstream.1.in.in b/doc/ezstream.1.in.in index 8a12000..b964b5b 100644 --- a/doc/ezstream.1.in.in +++ b/doc/ezstream.1.in.in @@ -172,33 +172,52 @@ Default: .It Sy \& .Pq Mandatory. Password to authenticate with on the server. +.It Sy \& +Configure the TLS encryption requirement for the server connection. +Possible values are: +.Pp +.Bl -tag -width 0|NO|FALSE -compact +.It Ar None +No TLS encryption will be attempted. +.It Ar May +Opportunistic TLS encryption may be used, if the server supports it +.Pq the default . +.It Ar Required +TLS encryption is required. +This is the only setting that is providing security against both passive and +active attackers. +.El +.It Sy \& +Configure allowed cipher suites for TLS. +.Pp +For example (modern cipher suites, PFS, no deprecated algorithms): +.Sy HIGH:!kRSA:!kECDH:!DH:!PKS:!aNULL:!eNULL:!3DES:!MD5:!SHA:!TLSv1 . +.Pp +Default: +.Em libshout default cipher suite .It Sy \& Directory in which OpenSSL finds root CA certificates for validating the .Ar HTTPS server identity. .Pp Default: -.Em no server validation +.Em system default .It Sy \& Path of a root CA bundle file for validating the .Ar HTTPS server identity. .Pp Default: -.Em no server validation +.Em system default .It Sy \& -X.503 client certificate for authentication on an +X.503 client certificate and key +.Pq in PEM format containing both certificate and key in the same file +for authentication on an .Ar HTTPS server. .Pp Default: .Em no client certificate authentication -.It Sy \& -Private key that matches the public key and certificate in -.Sy \& . -.Pp -Default: -.Em no client certificate authentication .It Sy \& Number of reconnect attempts in case of connection issues with the server, or 0 diff --git a/examples/ezstream-full.xml b/examples/ezstream-full.xml index 31c1392..23fe949 100644 --- a/examples/ezstream-full.xml +++ b/examples/ezstream-full.xml @@ -26,9 +26,20 @@ hackme + + Required + + + HIGH:!kRSA:!kECDH:!DH:!PKS:!aNULL:!eNULL:!3DES:!MD5:!SHA:!TLSv1 + /etc/ssl/certs @@ -38,12 +49,12 @@ --> /etc/ssl/certs/ca-certificates.crt - + /etc/ssl/ezstream.crt - - /etc/ssl/private/ezstream.key - 0 diff --git a/src/cfg.c b/src/cfg.c index c5dca02..a199a07 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -366,6 +366,36 @@ cfg_set_server_password(const char *password, const char **errstrp) return (0); } +int +cfg_set_server_tls(const char *tls, const char **errstrp) +{ + if (!tls || !tls[0]) { + if (errstrp) + *errstrp = "empty"; + return (-1); + } + + if (0 == strcasecmp("may", tls)) + cfg.server.tls = CFG_TLS_MAY; + else if (0 == strcasecmp("none", tls)) + cfg.server.tls = CFG_TLS_NONE; + else if (0 == strcasecmp("required", tls)) + cfg.server.tls = CFG_TLS_REQUIRED; + else { + if (NULL != errstrp) + *errstrp = "invalid"; + return (-1); + } + return (0); +} + +int +cfg_set_server_tls_cipher_suite(const char *suite, const char **errstrp) +{ + SET_STRLCPY(cfg.server.tls_cipher_suite, suite, errstrp); + return (0); +} + int cfg_set_server_ca_dir(const char *ca_dir, const char **errstrp) { @@ -387,13 +417,6 @@ cfg_set_server_client_cert(const char *client_cert, const char **errstrp) return (0); } -int -cfg_set_server_client_key(const char *client_key, const char **errstrp) -{ - SET_STRLCPY(cfg.server.client_key, client_key, errstrp); - return (0); -} - int cfg_set_server_reconnect_attempts(const char *num_str, const char **errstrp) { @@ -681,6 +704,20 @@ cfg_get_server_password(void) return (cfg.server.password[0] ? cfg.server.password : NULL); } +enum cfg_server_tls +cfg_get_server_tls(void) +{ + return (cfg.server.tls); +} + +const char * +cfg_get_server_tls_cipher_suite(void) +{ + return (cfg.server.tls_cipher_suite[0] + ? cfg.server.tls_cipher_suite + : NULL); +} + const char * cfg_get_server_ca_dir(void) { @@ -699,12 +736,6 @@ cfg_get_server_client_cert(void) return (cfg.server.client_cert[0] ? cfg.server.client_cert : NULL); } -const char * -cfg_get_server_client_key(void) -{ - return (cfg.server.client_key[0] ? cfg.server.client_key : NULL); -} - unsigned int cfg_get_server_reconnect_attempts(void) { diff --git a/src/cfg.h b/src/cfg.h index 69649ba..49d15c8 100644 --- a/src/cfg.h +++ b/src/cfg.h @@ -40,6 +40,14 @@ enum cfg_server_protocol { CFG_PROTO_MAX = CFG_PROTO_HTTPS, }; +enum cfg_server_tls { + CFG_TLS_MAY = 0, + CFG_TLS_NONE, + CFG_TLS_REQUIRED, + CFG_TLS_MIN = CFG_TLS_MAY, + CFG_TLS_MAX = CFG_TLS_REQUIRED, +}; + enum cfg_media_type { CFG_MEDIA_AUTODETECT = 0, CFG_MEDIA_FILE, @@ -91,10 +99,11 @@ int cfg_set_server_hostname(const char *, const char **); int cfg_set_server_port(const char *, const char **); int cfg_set_server_user(const char *, const char **); int cfg_set_server_password(const char *, const char **); +int cfg_set_server_tls(const char *, const char **); +int cfg_set_server_tls_cipher_suite(const char *, const char **); int cfg_set_server_ca_dir(const char *, const char **); int cfg_set_server_ca_file(const char *, const char **); int cfg_set_server_client_cert(const char *, const char **); -int cfg_set_server_client_key(const char *, const char **); int cfg_set_server_reconnect_attempts(const char *, const char **); int cfg_set_stream_mountpoint(const char *, const char **); @@ -144,14 +153,16 @@ const char * cfg_get_server_user(void); const char * cfg_get_server_password(void); +enum cfg_server_tls + cfg_get_server_tls(void); +const char * + cfg_get_server_tls_cipher_suite(void); const char * cfg_get_server_ca_dir(void); const char * cfg_get_server_ca_file(void); const char * cfg_get_server_client_cert(void); -const char * - cfg_get_server_client_key(void); unsigned int cfg_get_server_reconnect_attempts(void); diff --git a/src/cfg_private.h b/src/cfg_private.h index eb1dd2a..3249d48 100644 --- a/src/cfg_private.h +++ b/src/cfg_private.h @@ -26,6 +26,7 @@ #define EXTENSIONS_MAX 16 #define UCREDS_SIZE 256 +#define CSUITE_SIZE 2048 #define DEFAULT_PORT 8000 #define DEFAULT_USER "source" @@ -46,10 +47,11 @@ struct cfg { unsigned int port; char user[UCREDS_SIZE]; char password[UCREDS_SIZE]; + enum cfg_server_tls tls; + char tls_cipher_suite[CSUITE_SIZE]; char ca_dir[PATH_MAX]; char ca_file[PATH_MAX]; char client_cert[PATH_MAX]; - char client_key[PATH_MAX]; unsigned int reconnect_attempts; } server; struct stream { diff --git a/src/cfg_xmlfile.c b/src/cfg_xmlfile.c index 105acd0..53ef3b9 100644 --- a/src/cfg_xmlfile.c +++ b/src/cfg_xmlfile.c @@ -64,9 +64,11 @@ _cfg_xmlfile_parse_server(xmlDocPtr doc, xmlNodePtr cur) XML_STRCONFIG("server", cfg_set_server_port, "port"); XML_STRCONFIG("server", cfg_set_server_user, "user"); XML_STRCONFIG("server", cfg_set_server_password, "password"); + XML_STRCONFIG("server", cfg_set_server_tls, "tls"); + XML_STRCONFIG("server", cfg_set_server_tls_cipher_suite, + "tls_cipher_suite"); XML_STRCONFIG("server", cfg_set_server_ca_dir, "ca_dir"); XML_STRCONFIG("server", cfg_set_server_ca_file, "ca_file"); - XML_STRCONFIG("server", cfg_set_server_client_key, "client_key"); XML_STRCONFIG("server", cfg_set_server_client_cert, "client_cert"); XML_STRCONFIG("server", cfg_set_server_reconnect_attempts, "reconnect_attempts"); @@ -267,10 +269,11 @@ _cfg_xmlfile_parse_encoders(xmlDocPtr doc, xmlNodePtr cur) * port * user * password + * tls + * tls_cipher_suite * ca_dir * ca_file * client_cert - * client_key * reconnect_attempts * stream * mountpoint diff --git a/tests/check_cfg.c b/tests/check_cfg.c index 3680964..67d54e2 100644 --- a/tests/check_cfg.c +++ b/tests/check_cfg.c @@ -295,6 +295,31 @@ START_TEST(test_server_ca_dir) } END_TEST +START_TEST(test_server_tls) +{ + const char *errstr = NULL; + + ck_assert_int_eq(cfg_set_server_tls("", &errstr), -1); + ck_assert_str_eq(errstr, "empty"); + ck_assert_int_eq(cfg_set_server_tls("test", &errstr), -1); + ck_assert_str_eq(errstr, "invalid"); + ck_assert_int_eq(cfg_get_server_tls(), CFG_TLS_MAY); + ck_assert_int_eq(cfg_set_server_tls("None", NULL), 0); + ck_assert_int_eq(cfg_get_server_tls(), CFG_TLS_NONE); + ck_assert_int_eq(cfg_set_server_tls("Required", NULL), 0); + ck_assert_int_eq(cfg_get_server_tls(), CFG_TLS_REQUIRED); + ck_assert_int_eq(cfg_set_server_tls("May", NULL), 0); + ck_assert_int_eq(cfg_get_server_tls(), CFG_TLS_MAY); +} +END_TEST + +START_TEST(test_server_tls_cipher_suite) +{ + TEST_STRLCPY(cfg_set_server_tls_cipher_suite, + cfg_get_server_tls_cipher_suite, CSUITE_SIZE); +} +END_TEST + START_TEST(test_server_ca_file) { TEST_STRLCPY(cfg_set_server_ca_file, cfg_get_server_ca_file, PATH_MAX); @@ -308,13 +333,6 @@ START_TEST(test_server_client_cert) } END_TEST -START_TEST(test_server_client_key) -{ - TEST_STRLCPY(cfg_set_server_client_key, cfg_get_server_client_key, - PATH_MAX); -} -END_TEST - START_TEST(test_server_reconnect_attempts) { TEST_UINTNUM(cfg_set_server_reconnect_attempts, @@ -802,10 +820,11 @@ cfg_suite(void) tcase_add_test(tc_server, test_server_port); tcase_add_test(tc_server, test_server_user); tcase_add_test(tc_server, test_server_password); + tcase_add_test(tc_server, test_server_tls); + tcase_add_test(tc_server, test_server_tls_cipher_suite); tcase_add_test(tc_server, test_server_ca_dir); tcase_add_test(tc_server, test_server_ca_file); tcase_add_test(tc_server, test_server_client_cert); - tcase_add_test(tc_server, test_server_client_key); tcase_add_test(tc_server, test_server_reconnect_attempts); suite_add_tcase(s, tc_server); diff --git a/tests/config-bad.xml b/tests/config-bad.xml index 1b1adb4..d2d1713 100644 --- a/tests/config-bad.xml +++ b/tests/config-bad.xml @@ -8,10 +8,11 @@ + + -