]> Git Repo - qemu.git/blobdiff - crypto/tlssession.c
crypto: Implement TLS Pre-Shared Keys (PSK).
[qemu.git] / crypto / tlssession.c
index 373552942cceca5d7c77d3b5eae1cc0dee2a1e42..66a6fbe19c9c8344f1b8727dc1465d64c8d1743d 100644 (file)
  *
  */
 
+#include "qemu/osdep.h"
 #include "crypto/tlssession.h"
 #include "crypto/tlscredsanon.h"
+#include "crypto/tlscredspsk.h"
 #include "crypto/tlscredsx509.h"
+#include "qapi/error.h"
 #include "qemu/acl.h"
 #include "trace.h"
 
@@ -86,6 +89,14 @@ qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
     return session->readFunc(buf, len, session->opaque);
 }
 
+#define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH"
+
+#if GNUTLS_VERSION_MAJOR >= 3
+#define TLS_ECDHE_PSK "+ECDHE-PSK:"
+#else
+#define TLS_ECDHE_PSK ""
+#endif
+#define TLS_PRIORITY_ADDITIONAL_PSK TLS_ECDHE_PSK "+DHE-PSK:+PSK"
 
 QCryptoTLSSession *
 qcrypto_tls_session_new(QCryptoTLSCreds *creds,
@@ -130,14 +141,25 @@ 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:%s",
+                                   creds->priority,
+                                   TLS_PRIORITY_ADDITIONAL_ANON);
+        } else {
+            prio = g_strdup(CONFIG_TLS_PRIORITY ":"
+                            TLS_PRIORITY_ADDITIONAL_ANON);
+        }
+
+        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,
@@ -152,14 +174,54 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
                        gnutls_strerror(ret));
             goto error;
         }
+    } else if (object_dynamic_cast(OBJECT(creds),
+                                   TYPE_QCRYPTO_TLS_CREDS_PSK)) {
+        QCryptoTLSCredsPSK *pcreds = QCRYPTO_TLS_CREDS_PSK(creds);
+        char *prio;
+
+        if (creds->priority != NULL) {
+            prio = g_strdup_printf("%s:%s",
+                                   creds->priority,
+                                   TLS_PRIORITY_ADDITIONAL_PSK);
+        } else {
+            prio = g_strdup(CONFIG_TLS_PRIORITY ":"
+                            TLS_PRIORITY_ADDITIONAL_PSK);
+        }
+
+        ret = gnutls_priority_set_direct(session->handle, prio, NULL);
+        if (ret < 0) {
+            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_PSK,
+                                         pcreds->data.server);
+        } else {
+            ret = gnutls_credentials_set(session->handle,
+                                         GNUTLS_CRD_PSK,
+                                         pcreds->data.client);
+        }
+        if (ret < 0) {
+            error_setg(errp, "Cannot set session credentials: %s",
+                       gnutls_strerror(ret));
+            goto error;
+        }
     } 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 = CONFIG_TLS_PRIORITY;
+        }
 
-        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,
@@ -337,16 +399,26 @@ qcrypto_tls_session_check_credentials(QCryptoTLSSession *session,
 {
     if (object_dynamic_cast(OBJECT(session->creds),
                             TYPE_QCRYPTO_TLS_CREDS_ANON)) {
+        trace_qcrypto_tls_session_check_creds(session, "nop");
+        return 0;
+    } else if (object_dynamic_cast(OBJECT(session->creds),
+                            TYPE_QCRYPTO_TLS_CREDS_PSK)) {
+        trace_qcrypto_tls_session_check_creds(session, "nop");
         return 0;
     } else if (object_dynamic_cast(OBJECT(session->creds),
                             TYPE_QCRYPTO_TLS_CREDS_X509)) {
         if (session->creds->verifyPeer) {
-            return qcrypto_tls_session_check_certificate(session,
-                                                         errp);
+            int ret = qcrypto_tls_session_check_certificate(session,
+                                                            errp);
+            trace_qcrypto_tls_session_check_creds(session,
+                                                  ret == 0 ? "pass" : "fail");
+            return ret;
         } else {
+            trace_qcrypto_tls_session_check_creds(session, "skip");
             return 0;
         }
     } else {
+        trace_qcrypto_tls_session_check_creds(session, "error");
         error_setg(errp, "Unexpected credential type %s",
                    object_get_typename(OBJECT(session->creds)));
         return -1;
This page took 0.028043 seconds and 4 git commands to generate.