]> git.sesse.net Git - vlc/blobdiff - modules/misc/gnutls.c
Qt: translate wizard buttons (fix #13753)
[vlc] / modules / misc / gnutls.c
index a09af8ad8d2019846941bdd659cc6984f8829864..c76061ee385da89481b133c9d58b03c251ea3cd7 100644 (file)
@@ -22,6 +22,8 @@
 # include "config.h"
 #endif
 
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
 #include <errno.h>
 #include <assert.h>
@@ -45,7 +47,7 @@ static int gnutls_Init (vlc_object_t *obj)
         msg_Err (obj, "unsupported GnuTLS version");
         return -1;
     }
-    msg_Dbg (p_this, "using GnuTLS verson %s", version);
+    msg_Dbg (obj, "using GnuTLS version %s", version);
     return 0;
 }
 
@@ -59,13 +61,13 @@ static vlc_mutex_t gnutls_mutex = VLC_STATIC_MUTEX;
  */
 static int gnutls_Init (vlc_object_t *obj)
 {
-    const char *version = gnutls_check_version ("3.1.9");
+    const char *version = gnutls_check_version ("3.1.11");
     if (version == NULL)
     {
         msg_Err (obj, "unsupported GnuTLS version");
         return -1;
     }
-    msg_Dbg (obj, "using GnuTLS verson %s", version);
+    msg_Dbg (obj, "using GnuTLS version %s", version);
 
     if (gnutls_check_version ("3.3.0") == NULL)
     {
@@ -161,7 +163,8 @@ static int gnutls_Recv (void *opaque, void *buf, size_t length)
 }
 
 static int gnutls_SessionOpen (vlc_tls_t *tls, int type,
-                               gnutls_certificate_credentials_t x509, int fd)
+                               gnutls_certificate_credentials_t x509, int fd,
+                               const char *const *alpn)
 {
     gnutls_session_t session;
     const char *errp;
@@ -195,6 +198,31 @@ static int gnutls_SessionOpen (vlc_tls_t *tls, int type,
         goto error;
     }
 
+    if (alpn != NULL)
+    {
+        gnutls_datum_t *protv = NULL;
+        unsigned protc = 0;
+
+        while (*alpn != NULL)
+        {
+            gnutls_datum_t *n = realloc(protv, sizeof (*protv) * (protc + 1));
+            if (unlikely(n == NULL))
+            {
+                free(protv);
+                goto error;
+            }
+            protv = n;
+
+            protv[protc].data = (void *)*alpn;
+            protv[protc].size = strlen(*alpn);
+            protc++;
+            alpn++;
+        }
+
+        val = gnutls_alpn_set_protocols (session, protv, protc, 0);
+        free (protv);
+    }
+
     gnutls_transport_set_int (session, fd);
 
     tls->sys = session;
@@ -215,7 +243,7 @@ error:
  * 1 if more would-be blocking recv is needed,
  * 2 if more would-be blocking send is required.
  */
-static int gnutls_ContinueHandshake (vlc_tls_t *tls)
+static int gnutls_ContinueHandshake (vlc_tls_t *tls, char **restrict alp)
 {
     gnutls_session_t session = tls->sys;
     int val;
@@ -231,7 +259,7 @@ static int gnutls_ContinueHandshake (vlc_tls_t *tls)
         switch (val)
         {
             case GNUTLS_E_SUCCESS:
-                return 0;
+                goto done;
             case GNUTLS_E_AGAIN:
             case GNUTLS_E_INTERRUPTED:
                 /* I/O event: return to caller's poll() loop */
@@ -245,6 +273,26 @@ static int gnutls_ContinueHandshake (vlc_tls_t *tls)
 #endif
     msg_Err (tls, "TLS handshake error: %s", gnutls_strerror (val));
     return -1;
+
+done:
+    if (alp != NULL)
+    {
+        gnutls_datum_t datum;
+
+        val = gnutls_alpn_get_selected_protocol (session, &datum);
+        if (val == 0)
+        {
+            if (memchr (datum.data, 0, datum.size) != NULL)
+                return -1; /* Other end is doing something fishy?! */
+
+            *alp = strndup ((char *)datum.data, datum.size);
+            if (unlikely(*alp == NULL))
+                return -1;
+        }
+        else
+            *alp = NULL;
+    }
+    return 0;
 }
 
 /**
@@ -262,9 +310,10 @@ static void gnutls_SessionClose (vlc_tls_t *tls)
 }
 
 static int gnutls_ClientSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
-                                     int fd, const char *hostname)
+                                     int fd, const char *hostname,
+                                     const char *const *alpn)
 {
-    int val = gnutls_SessionOpen (tls, GNUTLS_CLIENT, crd->sys, fd);
+    int val = gnutls_SessionOpen (tls, GNUTLS_CLIENT, crd->sys, fd, alpn);
     if (val != VLC_SUCCESS)
         return val;
 
@@ -282,9 +331,9 @@ static int gnutls_ClientSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
 }
 
 static int gnutls_ClientHandshake (vlc_tls_t *tls, const char *host,
-                                   const char *service)
+                                   const char *service, char **restrict alp)
 {
-    int val = gnutls_ContinueHandshake (tls);
+    int val = gnutls_ContinueHandshake (tls, alp);
     if (val)
         return val;
 
@@ -468,18 +517,19 @@ typedef struct vlc_tls_creds_sys
  * Initializes a server-side TLS session.
  */
 static int gnutls_ServerSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
-                                     int fd, const char *hostname)
+                                     int fd, const char *hostname,
+                                     const char *const *alpn)
 {
     vlc_tls_creds_sys_t *sys = crd->sys;
 
     assert (hostname == NULL);
-    return gnutls_SessionOpen (tls, GNUTLS_SERVER, sys->x509_cred, fd);
+    return gnutls_SessionOpen (tls, GNUTLS_SERVER, sys->x509_cred, fd, alpn);
 }
 
 static int gnutls_ServerHandshake (vlc_tls_t *tls, const char *host,
-                                   const char *service)
+                                   const char *service, char **restrict alp)
 {
-    int val = gnutls_ContinueHandshake (tls);
+    int val = gnutls_ContinueHandshake (tls, alp);
     if (val == 0)
         tls->sock.p_sys = tls;
 
@@ -499,7 +549,10 @@ static int OpenServer (vlc_tls_creds_t *crd, const char *cert, const char *key)
 
     vlc_tls_creds_sys_t *sys = malloc (sizeof (*sys));
     if (unlikely(sys == NULL))
-        goto error;
+    {
+        gnutls_Deinit ();
+        return VLC_ENOMEM;
+    }
 
     /* Sets server's credentials */
     val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
@@ -507,7 +560,9 @@ static int OpenServer (vlc_tls_creds_t *crd, const char *cert, const char *key)
     {
         msg_Err (crd, "cannot allocate credentials: %s",
                  gnutls_strerror (val));
-        goto error;
+        free (sys);
+        gnutls_Deinit ();
+        return VLC_ENOMEM;
     }
 
     block_t *certblock = block_FilePath (cert);
@@ -515,7 +570,7 @@ static int OpenServer (vlc_tls_creds_t *crd, const char *cert, const char *key)
     {
         msg_Err (crd, "cannot read certificate chain from %s: %s", cert,
                  vlc_strerror_c(errno));
-        return VLC_EGENERIC;
+        goto error;
     }
 
     block_t *keyblock = block_FilePath (key);
@@ -524,7 +579,7 @@ static int OpenServer (vlc_tls_creds_t *crd, const char *cert, const char *key)
         msg_Err (crd, "cannot read private key from %s: %s", key,
                  vlc_strerror_c(errno));
         block_Release (certblock);
-        return VLC_EGENERIC;
+        goto error;
     }
 
     gnutls_datum_t pub = {
@@ -577,6 +632,7 @@ static int OpenServer (vlc_tls_creds_t *crd, const char *cert, const char *key)
     return VLC_SUCCESS;
 
 error:
+    gnutls_certificate_free_credentials (sys->x509_cred);
     free (sys);
     gnutls_Deinit ();
     return VLC_EGENERIC;