From 13f12430d48b62e2304e0e5a7c607279af68b98a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 6 Jun 2016 09:52:07 +0100 Subject: [PATCH] crypto: add support for TLS priority string override The gnutls default priority is either "NORMAL" (most historical versions of gnutls) which is a built-in label in gnutls code, or "@SYSTEM" (latest gnutls on Fedora at least) which refers to an admin customizable entry in a gnutls config file. Regardless of which default is used by a distro, they are both global defaults applying to all applications using gnutls. If a single application on the system needs to use a weaker set of crypto priorities, this potentially forces the weakness onto all applications. Or conversely if a single application wants a strong default than all others, it can't do this via the global config file. This adds an extra parameter to the tls credential object which allows the mgmt app / user to explicitly provide a priority string to QEMU when configuring TLS. For example, to use the "NORMAL" priority, but disable SSL 3.0 one can now configure QEMU thus: $QEMU -object tls-creds-x509,id=tls0,dir=/home/berrange/qemutls,\ priority="NORMAL:-VERS-SSL3.0" \ ..other args... If creating tls-creds-anon, whatever priority the user specifies will always have "+ANON-DH" appended to it, since that's mandatory to make the anonymous credentials work. Signed-off-by: Daniel P. Berrange --- crypto/tlscreds.c | 26 ++++++++++++++++++++++++++ crypto/tlssession.c | 26 +++++++++++++++++++------- include/crypto/tlscreds.h | 1 + 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c index 1620e126ae..a8965531b6 100644 --- a/crypto/tlscreds.c +++ b/crypto/tlscreds.c @@ -178,6 +178,27 @@ qcrypto_tls_creds_prop_get_dir(Object *obj, } +static void +qcrypto_tls_creds_prop_set_priority(Object *obj, + const char *value, + Error **errp G_GNUC_UNUSED) +{ + QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); + + creds->priority = g_strdup(value); +} + + +static char * +qcrypto_tls_creds_prop_get_priority(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); + + return g_strdup(creds->priority); +} + + static void qcrypto_tls_creds_prop_set_endpoint(Object *obj, int value, @@ -216,6 +237,10 @@ qcrypto_tls_creds_class_init(ObjectClass *oc, void *data) qcrypto_tls_creds_prop_get_endpoint, qcrypto_tls_creds_prop_set_endpoint, NULL); + object_class_property_add_str(oc, "priority", + qcrypto_tls_creds_prop_get_priority, + qcrypto_tls_creds_prop_set_priority, + NULL); } @@ -234,6 +259,7 @@ qcrypto_tls_creds_finalize(Object *obj) QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); g_free(creds->dir); + g_free(creds->priority); } diff --git a/crypto/tlssession.c b/crypto/tlssession.c index a543e5a576..2112d2934a 100644 --- a/crypto/tlssession.c +++ b/crypto/tlssession.c @@ -132,14 +132,22 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds, if (object_dynamic_cast(OBJECT(creds), TYPE_QCRYPTO_TLS_CREDS_ANON)) { QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds); + char *prio; - ret = gnutls_priority_set_direct(session->handle, - "NORMAL:+ANON-DH", NULL); + if (creds->priority != NULL) { + prio = g_strdup_printf("%s:+ANON-DH", creds->priority); + } else { + prio = g_strdup("NORMAL:+ANON-DH"); + } + + ret = gnutls_priority_set_direct(session->handle, prio, NULL); if (ret < 0) { - error_setg(errp, "Unable to set TLS session priority: %s", - gnutls_strerror(ret)); + error_setg(errp, "Unable to set TLS session priority %s: %s", + prio, gnutls_strerror(ret)); + g_free(prio); goto error; } + g_free(prio); if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { ret = gnutls_credentials_set(session->handle, GNUTLS_CRD_ANON, @@ -157,11 +165,15 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds, } else if (object_dynamic_cast(OBJECT(creds), TYPE_QCRYPTO_TLS_CREDS_X509)) { QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds); + const char *prio = creds->priority; + if (!prio) { + prio = "NORMAL"; + } - ret = gnutls_set_default_priority(session->handle); + ret = gnutls_priority_set_direct(session->handle, prio, NULL); if (ret < 0) { - error_setg(errp, "Cannot set default TLS session priority: %s", - gnutls_strerror(ret)); + error_setg(errp, "Cannot set default TLS session priority %s: %s", + prio, gnutls_strerror(ret)); goto error; } ret = gnutls_credentials_set(session->handle, diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h index 8e2babd533..59e91875c1 100644 --- a/include/crypto/tlscreds.h +++ b/include/crypto/tlscreds.h @@ -54,6 +54,7 @@ struct QCryptoTLSCreds { gnutls_dh_params_t dh_params; #endif bool verifyPeer; + char *priority; };