]> git.sesse.net Git - vlc/blobdiff - modules/misc/gnutls.c
Replaces xml special chars in image url
[vlc] / modules / misc / gnutls.c
index 866ed4e2691ff7c696d495f08f313992734dce8c..42e3973f87700a570d6fa2a40e140771cd353486 100644 (file)
@@ -26,7 +26,6 @@
  *****************************************************************************/
 
 #include <vlc/vlc.h>
-#include <stdlib.h>
 #include <errno.h>
 #include <time.h>
 
@@ -111,23 +110,6 @@ vlc_module_end();
 #define MAX_SESSION_ID    32
 #define MAX_SESSION_DATA  1024
 
-static const int proto_priority[] =
-{
-    GNUTLS_TLS1_1,
-    GNUTLS_TLS1_0,
-    GNUTLS_SSL3,
-    0
-};
-
-
-static const int cert_type_priority[] =
-{
-    GNUTLS_CRT_X509,
-    //GNUTLS_CRT_OPENPGP, TODO
-    0
-};
-
-
 typedef struct saved_session_t
 {
     char id[MAX_SESSION_ID];
@@ -167,6 +149,41 @@ typedef struct tls_client_sys_t
 } tls_client_sys_t;
 
 
+static int gnutls_Error (vlc_object_t *obj, int val)
+{
+    switch (val)
+    {
+        case GNUTLS_E_AGAIN:
+#if ! defined(WIN32)
+            errno = EAGAIN;
+            break;
+#endif
+            /* WinSock does not return EAGAIN, return EINTR instead */
+
+        case GNUTLS_E_INTERRUPTED:
+#if defined(WIN32)
+            WSASetLastError(WSAEINTR);
+#else
+            errno = EINTR;
+#endif
+            break;
+
+        default:
+            msg_Err (obj, "%s", gnutls_strerror (val));
+#ifdef DEBUG
+            if (!gnutls_error_is_fatal (val))
+                msg_Err (obj, "Error above should be handled");
+#endif
+#if defined(WIN32)
+            WSASetLastError(WSAECONNRESET);
+#else
+            errno = ECONNRESET;
+#endif
+    }
+    return -1;
+}
+
+
 /**
  * Sends data through a TLS session.
  */
@@ -179,8 +196,7 @@ gnutls_Send( void *p_session, const void *buf, int i_length )
     p_sys = (tls_session_sys_t *)(((tls_session_t *)p_session)->p_sys);
 
     val = gnutls_record_send( p_sys->session, buf, i_length );
-    /* TODO: handle fatal error */
-    return val < 0 ? -1 : val;
+    return (val < 0) ? gnutls_Error ((vlc_object_t *)p_session, val) : val;
 }
 
 
@@ -196,8 +212,7 @@ gnutls_Recv( void *p_session, void *buf, int i_length )
     p_sys = (tls_session_sys_t *)(((tls_session_t *)p_session)->p_sys);
 
     val = gnutls_record_recv( p_sys->session, buf, i_length );
-    /* TODO: handle fatal error */
-    return val < 0 ? -1 : val;
+    return (val < 0) ? gnutls_Error ((vlc_object_t *)p_session, val) : val;
 }
 
 
@@ -217,7 +232,6 @@ gnutls_ContinueHandshake( tls_session_t *p_session)
 
     p_sys = (tls_session_sys_t *)(p_session->p_sys);
 
-     /* TODO: handle fatal error */
 #ifdef WIN32
     WSASetLastError( 0 );
 #endif
@@ -230,7 +244,7 @@ gnutls_ContinueHandshake( tls_session_t *p_session)
 #ifdef WIN32
         msg_Dbg( p_session, "Winsock error %d", WSAGetLastError( ) );
 #endif
-        msg_Err( p_session, "TLS handshake failed: %s",
+        msg_Err( p_session, "TLS handshake error: %s",
                  gnutls_strerror( val ) );
         p_session->pf_close( p_session );
         return -1;
@@ -290,7 +304,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
         {
             if( status & e->flag )
             {
-                msg_Err( session, e->msg );
+                msg_Err( session, "%s", e->msg );
                 status &= ~e->flag;
             }
         }
@@ -324,7 +338,6 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
     {
         msg_Err( session, "Certificate import error: %s",
                  gnutls_strerror( val ) );
-        gnutls_x509_crt_deinit( cert );
         goto crt_error;
     }
 
@@ -426,35 +439,106 @@ gnutls_SessionClose( tls_session_t *p_session )
 }
 
 
+typedef int (*tls_prio_func) (gnutls_session_t, const int *);
+
 static int
-gnutls_SessionPrioritize (vlc_object_t *obj, gnutls_session_t session)
+gnutls_SetPriority (vlc_object_t *restrict obj, const char *restrict name,
+                    tls_prio_func func, gnutls_session_t session,
+                    const int *restrict values)
 {
-    int val;
-
-    val = gnutls_set_default_priority (session);
+    int val = func (session, values);
     if (val < 0)
     {
-        msg_Err (obj, "cannot set TLS priorities: %s",
+        msg_Err (obj, "cannot set %s priorities: %s", name,
                  gnutls_strerror (val));
         return VLC_EGENERIC;
     }
+    return VLC_SUCCESS;
+}
 
-    val = gnutls_protocol_set_priority (session, proto_priority);
-    if (val < 0)
+
+static int
+gnutls_SessionPrioritize (vlc_object_t *obj, gnutls_session_t session)
+{
+    /* Note that ordering matters (on the client side) */
+    static const int protos[] =
     {
-        msg_Err (obj, "cannot set protocols priorities: %s",
-                 gnutls_strerror (val));
-        return VLC_EGENERIC;
-    }
+        GNUTLS_TLS1_1,
+        GNUTLS_TLS1_0,
+        GNUTLS_SSL3,
+        0
+    };
+    static const int comps[] =
+    {
+        GNUTLS_COMP_DEFLATE,
+        GNUTLS_COMP_NULL,
+        0
+    };
+    static const int macs[] =
+    {
+        GNUTLS_MAC_SHA1,
+        GNUTLS_MAC_RMD160, // RIPEMD
+        GNUTLS_MAC_MD5,
+        //GNUTLS_MAC_MD2,
+        //GNUTLS_MAC_NULL,
+        0
+    };
+    static const int ciphers[] =
+    {
+        GNUTLS_CIPHER_AES_256_CBC,
+        GNUTLS_CIPHER_AES_128_CBC,
+        GNUTLS_CIPHER_3DES_CBC,
+        GNUTLS_CIPHER_ARCFOUR_128,
+        //GNUTLS_CIPHER_DES_CBC,
+        //GNUTLS_CIPHER_ARCFOUR_40,
+        //GNUTLS_CIPHER_RC2_40_CBC,
+        //GNUTLS_CIPHER_NULL,
+        0
+    };
+    static const int kx[] =
+    {
+        GNUTLS_KX_DHE_RSA,
+        GNUTLS_KX_DHE_DSS,
+        GNUTLS_KX_RSA,
+        //GNUTLS_KX_RSA_EXPORT,
+        //GNUTLS_KX_DHE_PSK, TODO
+        //GNUTLS_KX_PSK,     TODO
+        //GNUTLS_KX_SRP_RSA, TODO
+        //GNUTLS_KX_SRP_DSS, TODO
+        //GNUTLS_KX_SRP,     TODO
+        //GNUTLS_KX_ANON_DH,
+        0
+    };
+    static const int cert_types[] =
+    {
+        GNUTLS_CRT_X509,
+        //GNUTLS_CRT_OPENPGP, TODO
+        0
+    };
 
-    val = gnutls_certificate_type_set_priority (session, cert_type_priority);
+    int val = gnutls_set_default_priority (session);
     if (val < 0)
     {
-        msg_Err (obj, "cannot set certificate type priorities: %s",
+        msg_Err (obj, "cannot set default TLS priorities: %s",
                  gnutls_strerror (val));
         return VLC_EGENERIC;
     }
 
+    if (gnutls_SetPriority (obj, "protocols",
+                            gnutls_protocol_set_priority, session, protos)
+     || gnutls_SetPriority (obj, "compression algorithms",
+                            gnutls_compression_set_priority, session, comps)
+     || gnutls_SetPriority (obj, "MAC algorithms",
+                            gnutls_mac_set_priority, session, macs)
+     || gnutls_SetPriority (obj, "ciphers",
+                            gnutls_cipher_set_priority, session, ciphers)
+     || gnutls_SetPriority (obj, "key exchange algorithms",
+                            gnutls_kx_set_priority, session, kx)
+     || gnutls_SetPriority (obj, "certificate types",
+                            gnutls_certificate_type_set_priority, session,
+                            cert_types))
+        return VLC_EGENERIC;
+
     return VLC_SUCCESS;
 }
 
@@ -619,7 +703,7 @@ gnutls_ClientCreate( tls_t *p_tls )
     vlc_object_attach( p_session, p_tls );
 
     const char *homedir = p_tls->p_libvlc->psz_homedir,
-               *datadir = config_GetDataDir ((vlc_object_t *)p_session);
+               *datadir = config_GetDataDir ();
     size_t l1 = strlen (homedir), l2 = strlen (datadir);
     char path[((l1 > l2) ? l1 : l2) + sizeof ("/"CONFIG_DIR"/ssl/private")];
     //                              > sizeof ("/"CONFIG_DIR"/ssl/certs")
@@ -832,7 +916,6 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server )
 
     ((tls_session_sys_t *)p_session->p_sys)->session = session;
 
-    i_val = gnutls_set_default_priority( session );
     if (gnutls_SessionPrioritize (VLC_OBJECT (p_session), session))
     {
         gnutls_deinit( session );
@@ -1130,22 +1213,19 @@ static struct gcry_thread_cbs gcry_threads_vlc =
 /*****************************************************************************
  * Module initialization
  *****************************************************************************/
+static unsigned refs = 0;
+
 static int
 Open( vlc_object_t *p_this )
 {
     tls_t *p_tls = (tls_t *)p_this;
+    vlc_mutex_t *lock;
 
-    vlc_value_t lock, count;
-
-    var_Create( p_this->p_libvlc_global, "gnutls_mutex", VLC_VAR_MUTEX );
-    var_Get( p_this->p_libvlc_global, "gnutls_mutex", &lock );
-    vlc_mutex_lock( lock.p_address );
+    lock = var_GetGlobalMutex( "gnutls_mutex" );
+    vlc_mutex_lock( lock );
 
     /* Initialize GnuTLS only once */
-    var_Create( p_this->p_libvlc_global, "gnutls_count", VLC_VAR_INTEGER );
-    var_Get( p_this->p_libvlc_global, "gnutls_count", &count);
-
-    if( count.i_int == 0)
+    if( refs == 0 )
     {
 #ifdef NEED_THREAD_CONTEXT
         __p_gcry_data = VLC_OBJECT( p_this->p_libvlc );
@@ -1155,7 +1235,7 @@ Open( vlc_object_t *p_this )
         if( gnutls_global_init( ) )
         {
             msg_Warn( p_this, "cannot initialize GnuTLS" );
-            vlc_mutex_unlock( lock.p_address );
+            vlc_mutex_unlock( lock );
             return VLC_EGENERIC;
         }
 
@@ -1163,16 +1243,15 @@ Open( vlc_object_t *p_this )
         if( psz_version == NULL )
         {
             gnutls_global_deinit( );
-            vlc_mutex_unlock( lock.p_address );
+            vlc_mutex_unlock( lock );
             msg_Err( p_this, "unsupported GnuTLS version" );
             return VLC_EGENERIC;
         }
         msg_Dbg( p_this, "GnuTLS v%s initialized", psz_version );
     }
 
-    count.i_int++;
-    var_Set( p_this->p_libvlc_global, "gnutls_count", count);
-    vlc_mutex_unlock( lock.p_address );
+    refs++;
+    vlc_mutex_unlock( lock );
 
     p_tls->pf_server_create = gnutls_ServerCreate;
     p_tls->pf_client_create = gnutls_ClientCreate;
@@ -1189,22 +1268,16 @@ Close( vlc_object_t *p_this )
     /*tls_t *p_tls = (tls_t *)p_this;
     tls_sys_t *p_sys = (tls_sys_t *)(p_this->p_sys);*/
 
-    vlc_value_t lock, count;
-
-    var_Create( p_this->p_libvlc_global, "gnutls_mutex", VLC_VAR_MUTEX );
-    var_Get( p_this->p_libvlc_global, "gnutls_mutex", &lock );
-    vlc_mutex_lock( lock.p_address );
+    vlc_mutex_t *lock;
 
-    var_Create( p_this->p_libvlc_global, "gnutls_count", VLC_VAR_INTEGER );
-    var_Get( p_this->p_libvlc_global, "gnutls_count", &count);
-    count.i_int--;
-    var_Set( p_this->p_libvlc_global, "gnutls_count", count);
+    lock = var_GetGlobalMutex( "gnutls_mutex" );
+    vlc_mutex_lock( lock );
 
-    if( count.i_int == 0 )
+    if( --refs == 0 )
     {
         gnutls_global_deinit( );
         msg_Dbg( p_this, "GnuTLS deinitialized" );
     }
 
-    vlc_mutex_unlock( lock.p_address );
+    vlc_mutex_unlock( lock );
 }