From e5172dff9bcf8c2de8426a74fbddbe3bbf1851e4 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Fri, 30 Mar 2018 09:22:48 +0200 Subject: Add public spice_server_set_tls_options() method Its main goal is to allow to set the minimum TLS version that we want spice-server to use. By default we limit ourselves to TLSv1.1 or newer connections. By using this API, one can configure spice-server to accept TLSv1.0 connections too, or on the contrary it can restrict connections to TLSv1.2-only. The other arguments are redundant with the ones already present in spice_server_set_tls(). However, tying this with the setting of the TLS port is a bit odd if one day we want to support multiple TLS ports. --- server/reds.c | 72 ++++++++++++++++++++++++++++++++++++------------ server/spice-server.h | 10 +++++++ server/spice-server.syms | 5 ++++ 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/server/reds.c b/server/reds.c index f3f6e24c..df0b225b 100644 --- a/server/reds.c +++ b/server/reds.c @@ -161,6 +161,7 @@ typedef struct RedSSLParameters { char ca_certificate_file[256]; char dh_key_file[256]; char ciphersuite[256]; + SpiceTLSProtocolVersion min_version; } RedSSLParameters; /* SPICE configuration set through the public spice_server_set_xxx APIS */ @@ -2770,6 +2771,44 @@ static gpointer openssl_global_init(gpointer arg) return NULL; } +static int reds_set_min_tls_version(RedsState *reds) +{ + /* By default, connections will be restricted to TLSv1.1 or newer. */ +#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION + int min_tls_version; + + switch (reds->config->ssl_parameters.min_version) { + case SPICE_TLS_PROTOCOL_TLSv1_0: + min_tls_version = TLS1_VERSION; + break; + case SPICE_TLS_PROTOCOL_TLSv1_1: + min_tls_version = TLS1_1_VERSION; + break; + case SPICE_TLS_PROTOCOL_TLSv1_2: + min_tls_version = TLS1_2_VERSION; + break; + default: + g_return_val_if_reached(-1); + } + SSL_CTX_set_min_proto_version(reds->ctx, min_tls_version); + /* This should be set by default with OpenSSL 1.1.0, which is also the + * version which introduced SSL_CTX_set_min_proto_version + */ + SSL_CTX_set_options(reds->ctx, SSL_OP_NO_COMPRESSION); +#else + long ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION; + if (reds->config->ssl_parameters.min_version > SPICE_TLS_PROTOCOL_TLSv1_0) { + ssl_options |= SSL_OP_NO_TLSv1_0; + } + if (reds->config->ssl_parameters.min_tls_version > SPICE_TLS_PROTOCOL_TLSv1_1) { + ssl_options |= SSL_OP_NO_TLSv1_1; + } + SSL_CTX_set_options(reds->ctx, ssl_options); +#endif + + return 0; +} + static int reds_init_ssl(RedsState *reds) { static GOnce openssl_once = G_ONCE_INIT; @@ -2787,17 +2826,11 @@ static int reds_init_ssl(RedsState *reds) return -1; } - /* Limit connection to TLSv1.1 or newer. */ -#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION - SSL_CTX_set_min_proto_version(reds->ctx, TLS1_1_VERSION); - /* This should be set by default with OpenSSL 1.1.0, which is also the - * version which introduced SSL_CTX_set_min_proto_version - */ - SSL_CTX_set_options(reds->ctx, SSL_OP_NO_COMPRESSION); -#else - long ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_NO_TLSv1; - SSL_CTX_set_options(reds->ctx, ssl_options); -#endif + return_code = reds_set_min_tls_version(reds); + if (return_code != 0) { + spice_warning("Failed to set minimum TLS version"); + return -1; + } /* Load our keys and certificates*/ return_code = SSL_CTX_use_certificate_chain_file(reds->ctx, reds->config->ssl_parameters.certs_file); @@ -3828,15 +3861,19 @@ SPICE_GNUC_VISIBLE int spice_server_set_ticket(SpiceServer *reds, return 0; } -static int spice_server_set_tls_options(SpiceServer *s, - const char *ca_cert_file, const char *certs_file, - const char *private_key_file, const char *key_passwd, - const char *dh_key_file, const char *ciphersuite) +SPICE_GNUC_VISIBLE int spice_server_set_tls_options(SpiceServer *s, SpiceTLSProtocolVersion min_version, + const char *ca_cert_file, const char *certs_file, + const char *private_key_file, const char *key_passwd, + const char *dh_key_file, const char *ciphersuite) { if (ca_cert_file == NULL || certs_file == NULL || private_key_file == NULL) { return -1; } + if ((min_version < SPICE_TLS_PROTOCOL_TLSv1_0) || (min_version > SPICE_TLS_PROTOCOL_TLSv1_2)) { + return -1; + } memset(&s->config->ssl_parameters, 0, sizeof(s->config->ssl_parameters)); + s->config->ssl_parameters.min_version = SPICE_TLS_PROTOCOL_TLSv1_1; g_strlcpy(s->config->ssl_parameters.ca_certificate_file, ca_cert_file, sizeof(s->config->ssl_parameters.ca_certificate_file)); @@ -3857,11 +3894,12 @@ static int spice_server_set_tls_options(SpiceServer *s, g_strlcpy(s->config->ssl_parameters.dh_key_file, dh_key_file, sizeof(s->config->ssl_parameters.dh_key_file)); } + s->config->ssl_parameters.min_version = min_version; return 0; } -int spice_server_set_tls(SpiceServer *s, int port, +SPICE_GNUC_VISIBLE int spice_server_set_tls(SpiceServer *s, int port, const char *ca_cert_file, const char *certs_file, const char *private_key_file, const char *key_passwd, const char *dh_key_file, const char *ciphersuite) @@ -3870,7 +3908,7 @@ int spice_server_set_tls(SpiceServer *s, int port, if (port <= 0 || port > 0xffff) { return -1; } - res = spice_server_set_tls_options(s, + res = spice_server_set_tls_options(s, SPICE_TLS_PROTOCOL_TLSv1_1, ca_cert_file, certs_file, private_key_file, key_passwd, dh_key_file, ciphersuite); diff --git a/server/spice-server.h b/server/spice-server.h index 5f572f4f..43819138 100644 --- a/server/spice-server.h +++ b/server/spice-server.h @@ -44,6 +44,12 @@ void spice_server_destroy(SpiceServer *s); #define SPICE_ADDR_FLAG_IPV6_ONLY (1 << 1) #define SPICE_ADDR_FLAG_UNIX_ONLY (1 << 2) +typedef enum { + SPICE_TLS_PROTOCOL_TLSv1_0, + SPICE_TLS_PROTOCOL_TLSv1_1, + SPICE_TLS_PROTOCOL_TLSv1_2 +} SpiceTLSProtocolVersion; + int spice_server_set_compat_version(SpiceServer *s, spice_compat_version_t version); int spice_server_set_port(SpiceServer *s, int port); @@ -59,6 +65,10 @@ int spice_server_set_tls(SpiceServer *s, int port, const char *ca_cert_file, const char *certs_file, const char *private_key_file, const char *key_passwd, const char *dh_key_file, const char *ciphersuite); +int spice_server_set_tls_options(SpiceServer *s, SpiceTLSProtocolVersion min_version, + const char *ca_cert_file, const char *certs_file, + const char *private_key_file, const char *key_passwd, + const char *dh_key_file, const char *ciphersuite); int spice_server_add_client(SpiceServer *s, int socket, int skip_auth); int spice_server_add_ssl_client(SpiceServer *s, int socket, int skip_auth); diff --git a/server/spice-server.syms b/server/spice-server.syms index edf04a42..90d5ee84 100644 --- a/server/spice-server.syms +++ b/server/spice-server.syms @@ -173,3 +173,8 @@ SPICE_SERVER_0.13.2 { global: spice_server_set_video_codecs; } SPICE_SERVER_0.13.1; + +SPICE_SERVER_0.14.1 { +global: + spice_server_set_tls_options; +} SPICE_SERVER_0.13.2; -- cgit v1.2.3