]> git.sesse.net Git - vlc/commitdiff
Rework/simplify the TLS plugin interface (LibVLC <-> tls plugin).
authorRémi Denis-Courmont <rem@videolan.org>
Sat, 22 Sep 2007 11:21:35 +0000 (11:21 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Sat, 22 Sep 2007 11:21:35 +0000 (11:21 +0000)
Remove the singleton pattern. Still very much work in progress.

include/vlc_common.h
include/vlc_objects.h
include/vlc_tls.h
modules/misc/gnutls.c
src/misc/objects.c
src/network/tls.c

index 78f7c36d174bb0476249cd901971b81357d06528..84eb662b32bac7c109b5279c41ee17fc214cf796 100644 (file)
@@ -411,7 +411,6 @@ typedef struct httpd_redirect_t httpd_redirect_t;
 typedef struct httpd_stream_t httpd_stream_t;
 
 /* TLS support */
-typedef struct tls_t tls_t;
 typedef struct tls_server_t tls_server_t;
 typedef struct tls_session_t tls_session_t;
 
index 75eb384c67e43aabe441c7670d1433d704ae03aa..62398e81b0ba584867f7542bc74853e3711c3565 100644 (file)
@@ -60,7 +60,7 @@
 #define VLC_OBJECT_FILTER      (-22)
 #define VLC_OBJECT_VOD         (-23)
 #define VLC_OBJECT_SPU         (-24)
-#define VLC_OBJECT_TLS         (-25)
+/*#define VLC_OBJECT_xxx         (-25) - formerly TLS */
 #define VLC_OBJECT_SD          (-26)
 #define VLC_OBJECT_XML         (-27)
 #define VLC_OBJECT_OSDMENU     (-28)
index 0472959e40c56489b5272231eecde69ac5d38ffc..38b81eb295bf79c09abed523e9e72f68097c3032 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
- * tls.c: TLS wrapper
+ * tls.c: Transport Layer Security API
  *****************************************************************************
- * Copyright (C) 2004-2005 the VideoLAN team
+ * Copyright (C) 2004-2007 the VideoLAN team
  * $Id$
  *
  * Authors: Rémi Denis-Courmont <rem # videolan.org>
 
 # include <vlc_network.h>
 
-struct tls_t
-{
-    VLC_COMMON_MEMBERS
-
-    /* Module properties */
-    module_t  *p_module;
-    void *p_sys;
-
-    tls_server_t * (*pf_server_create) ( tls_t *, const char *,
-                                         const char * );
-    tls_session_t * (*pf_client_create) ( tls_t * );
-};
+typedef struct tls_server_sys_t tls_server_sys_t;
 
 struct tls_server_t
 {
     VLC_COMMON_MEMBERS
 
-    void *p_sys;
-
-    void (*pf_delete) ( tls_server_t * );
+    module_t  *p_module;
+    tls_server_sys_t *p_sys;
 
     int (*pf_add_CA) ( tls_server_t *, const char * );
     int (*pf_add_CRL) ( tls_server_t *, const char * );
@@ -57,11 +45,14 @@ struct tls_server_t
     tls_session_t * (*pf_session_prepare) ( tls_server_t * );
 };
 
+typedef struct tls_session_sys_t tls_session_sys_t;
+
 struct tls_session_t
 {
     VLC_COMMON_MEMBERS
 
-    void *p_sys;
+    module_t  *p_module;
+    tls_session_sys_t *p_sys;
 
     struct virtual_socket_t sock;
     int (*pf_handshake) ( tls_session_t *, int, const char * );
index ea39050db5b3c7da8284689ccf140f7ab4988e96..7769cba3e13fbd1980b31120b4d8974071b7e9cf 100644 (file)
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 
-#define DH_BITS             1024
-#define CACHE_EXPIRATION    3600
+#define DH_BITS           1024
+#define CACHE_TIMEOUT     3600
 #define CACHE_SIZE          64
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-static int  Open ( vlc_object_t * );
-static void Close( vlc_object_t * );
+static int  OpenClient  (vlc_object_t *);
+static void CloseClient (vlc_object_t *);
+static int  OpenServer  (vlc_object_t *);
+static void CloseServer (vlc_object_t *);
 
 #define DH_BITS_TEXT N_("Diffie-Hellman prime bits")
 #define DH_BITS_LONGTEXT N_( \
@@ -65,8 +67,8 @@ static void Close( vlc_object_t * );
     "used for TLS or SSL-based server-side encryption. This is generally " \
     "not needed." )
 
-#define CACHE_EXPIRATION_TEXT N_("Expiration time for resumed TLS sessions")
-#define CACHE_EXPIRATION_LONGTEXT N_( \
+#define CACHE_TIMEOUT_TEXT N_("Expiration time for resumed TLS sessions")
+#define CACHE_TIMEOUT_LONGTEXT N_( \
     "It is possible to cache the resumed TLS sessions. This is the expiration "\
     "time of the sessions stored in this cache, in seconds." )
 
@@ -82,9 +84,9 @@ static void Close( vlc_object_t * );
 
 vlc_module_begin();
     set_shortname( "GnuTLS" );
-    set_description( _("GnuTLS TLS encryption layer") );
-    set_capability( "tls", 1 );
-    set_callbacks( Open, Close );
+    set_description( _("GnuTLS transport layer security") );
+    set_capability( "tls client", 1 );
+    set_callbacks( OpenClient, CloseClient );
     set_category( CAT_ADVANCED );
     set_subcategory( SUBCAT_ADVANCED_MISC );
 
@@ -92,55 +94,135 @@ vlc_module_begin();
               CHECK_CERT_LONGTEXT, VLC_FALSE );
     add_obsolete_bool( "tls-check-hostname" );
 
-    add_integer( "gnutls-dh-bits", DH_BITS, NULL, DH_BITS_TEXT,
-                 DH_BITS_LONGTEXT, VLC_TRUE );
-    add_integer( "gnutls-cache-expiration", CACHE_EXPIRATION, NULL,
-                 CACHE_EXPIRATION_TEXT, CACHE_EXPIRATION_LONGTEXT, VLC_TRUE );
-    add_integer( "gnutls-cache-size", CACHE_SIZE, NULL, CACHE_SIZE_TEXT,
-                 CACHE_SIZE_LONGTEXT, VLC_TRUE );
+    add_submodule();
+        set_description( _("GnuTLS server") );
+        set_capability( "tls server", 1 );
+        set_category( CAT_ADVANCED );
+        set_subcategory( SUBCAT_ADVANCED_MISC );
+        set_callbacks( OpenServer, CloseServer );
+
+        add_integer( "gnutls-dh-bits", DH_BITS, NULL, DH_BITS_TEXT,
+                    DH_BITS_LONGTEXT, VLC_TRUE );
+        add_integer( "gnutls-cache-timeout", CACHE_TIMEOUT, NULL,
+                    CACHE_TIMEOUT_TEXT, CACHE_TIMEOUT_LONGTEXT, VLC_TRUE );
+        add_integer( "gnutls-cache-size", CACHE_SIZE, NULL, CACHE_SIZE_TEXT,
+                    CACHE_SIZE_LONGTEXT, VLC_TRUE );
 vlc_module_end();
 
 
-#define MAX_SESSION_ID    32
-#define MAX_SESSION_DATA  1024
 
-typedef struct saved_session_t
+#ifdef LIBVLC_USE_PTHREAD
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+# define gcry_threads_vlc gcry_threads_pthread
+#else
+/**
+ * gcrypt thread option VLC implementation
+ */
+
+# define NEED_THREAD_CONTEXT 1
+static vlc_object_t *__p_gcry_data = NULL;
+
+static int gcry_vlc_mutex_init( void **p_sys )
 {
-    char id[MAX_SESSION_ID];
-    char data[MAX_SESSION_DATA];
+    int i_val;
+    vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc( sizeof( vlc_mutex_t ) );
 
-    unsigned i_idlen;
-    unsigned i_datalen;
-} saved_session_t;
+    if( p_lock == NULL)
+        return ENOMEM;
 
+    i_val = vlc_mutex_init( __p_gcry_data, p_lock );
+    if( i_val )
+        free( p_lock );
+    else
+        *p_sys = p_lock;
+    return i_val;
+}
 
-typedef struct tls_server_sys_t
+static int gcry_vlc_mutex_destroy( void **p_sys )
 {
-    gnutls_certificate_credentials  x509_cred;
-    gnutls_dh_params                dh_params;
+    int i_val;
+    vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
 
-    struct saved_session_t          *p_cache;
-    struct saved_session_t          *p_store;
-    int                             i_cache_size;
-    vlc_mutex_t                     cache_lock;
+    i_val = vlc_mutex_destroy( p_lock );
+    free( p_lock );
+    return i_val;
+}
 
-    int                             (*pf_handshake2)( tls_session_t * );
-} tls_server_sys_t;
+static int gcry_vlc_mutex_lock( void **p_sys )
+{
+    return vlc_mutex_lock( (vlc_mutex_t *)*p_sys );
+}
 
+static int gcry_vlc_mutex_unlock( void **lock )
+{
+    return vlc_mutex_unlock( (vlc_mutex_t *)*lock );
+}
 
-typedef struct tls_session_sys_t
+static struct gcry_thread_cbs gcry_threads_vlc =
 {
-    gnutls_session  session;
-    char            *psz_hostname;
-    vlc_bool_t      b_handshaked;
-} tls_session_sys_t;
+    GCRY_THREAD_OPTION_USER,
+    NULL,
+    gcry_vlc_mutex_init,
+    gcry_vlc_mutex_destroy,
+    gcry_vlc_mutex_lock,
+    gcry_vlc_mutex_unlock
+};
+#endif
 
 
-typedef struct tls_client_sys_t
+/**
+ * Initializes GnuTLS with proper locking.
+ * @return VLC_SUCCESS on success, a VLC error code otherwise.
+ */
+static int gnutls_Init (vlc_object_t *p_this)
 {
-    struct tls_session_sys_t       session;
-    gnutls_certificate_credentials x509_cred;
-} tls_client_sys_t;
+    int ret = VLC_EGENERIC;
+
+    vlc_mutex_t *lock = var_GetGlobalMutex ("gnutls_mutex");
+    vlc_mutex_lock (lock);
+
+    /* This should probably be removed/fixed. It will screw up with multiple
+     * LibVLC instances. */
+#ifdef NEED_THREAD_CONTEXT
+    __p_gcry_data = VLC_OBJECT (p_this->p_libvlc);
+#endif
+
+    gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
+    if (gnutls_global_init ())
+    {
+        msg_Err (p_this, "cannot initialize GnuTLS");
+        goto error;
+    }
+
+    const char *psz_version = gnutls_check_version ("1.3.3");
+    if (psz_version == NULL)
+    {
+        msg_Err (p_this, "unsupported GnuTLS version");
+        gnutls_global_deinit ();
+        goto error;
+    }
+
+    msg_Dbg (p_this, "GnuTLS v%s initialized", psz_version);
+    ret = VLC_SUCCESS;
+
+error:
+    vlc_mutex_unlock (lock);
+    return ret;
+}
+
+
+/**
+ * Deinitializes GnuTLS.
+ */
+static void gnutls_Deinit (vlc_object_t *p_this)
+{
+    vlc_mutex_t *lock = var_GetGlobalMutex( "gnutls_mutex" );
+    vlc_mutex_lock (lock);
+
+    gnutls_global_deinit ();
+    msg_Dbg (p_this, "GnuTLS deinitialized");
+    vlc_mutex_unlock (lock);
+}
 
 
 static int gnutls_Error (vlc_object_t *obj, int val)
@@ -148,15 +230,15 @@ static int gnutls_Error (vlc_object_t *obj, int val)
     switch (val)
     {
         case GNUTLS_E_AGAIN:
-#if ! defined(WIN32)
+#ifndef WIN32
             errno = EAGAIN;
             break;
 #endif
             /* WinSock does not return EAGAIN, return EINTR instead */
 
         case GNUTLS_E_INTERRUPTED:
-#if defined(WIN32)
-            WSASetLastError(WSAEINTR);
+#ifdef WIN32
+            WSASetLastError (WSAEINTR);
 #else
             errno = EINTR;
 #endif
@@ -164,12 +246,12 @@ static int gnutls_Error (vlc_object_t *obj, int val)
 
         default:
             msg_Err (obj, "%s", gnutls_strerror (val));
-#ifdef DEBUG
+#ifndef NDEBUG
             if (!gnutls_error_is_fatal (val))
                 msg_Err (obj, "Error above should be handled");
 #endif
-#if defined(WIN32)
-            WSASetLastError(WSAECONNRESET);
+#ifdef WIN32
+            WSASetLastError (WSAECONNRESET);
 #else
             errno = ECONNRESET;
 #endif
@@ -178,6 +260,14 @@ static int gnutls_Error (vlc_object_t *obj, int val)
 }
 
 
+struct tls_session_sys_t
+{
+    gnutls_session  session;
+    char                          *psz_hostname;
+    vlc_bool_t      b_handshaked;
+};
+
+
 /**
  * Sends data through a TLS session.
  */
@@ -210,14 +300,11 @@ gnutls_Recv( void *p_session, void *buf, int i_length )
 }
 
 
-/*****************************************************************************
- * tls_Session(Continue)?Handshake:
- *****************************************************************************
- * Establishes TLS session with a peer through socket <fd>.
- * Returns -1 on error (you need not and must not call tls_SessionClose)
+/**
+ * @return -1 on error (you need not and must not call tls_SessionClose())
  * 0 on succesful handshake completion, 1 if more would-be blocking recv is
  * needed, 2 if more would-be blocking send is required.
- *****************************************************************************/
+ */
 static int
 gnutls_ContinueHandshake( tls_session_t *p_session)
 {
@@ -385,9 +472,7 @@ static int
 gnutls_BeginHandshake( tls_session_t *p_session, int fd,
                        const char *psz_hostname )
 {
-    tls_session_sys_t *p_sys;
-
-    p_sys = (tls_session_sys_t *)(p_session->p_sys);
+    tls_session_sys_t *p_sys = p_session->p_sys;
 
     gnutls_transport_set_ptr (p_sys->session, (gnutls_transport_ptr)(intptr_t)fd);
 
@@ -406,31 +491,6 @@ gnutls_BeginHandshake( tls_session_t *p_session, int fd,
     return p_session->pf_handshake2( p_session );
 }
 
-/**
- * Terminates TLS session and releases session data.
- * You still have to close the socket yourself.
- */
-static void
-gnutls_SessionClose( tls_session_t *p_session )
-{
-    tls_session_sys_t *p_sys;
-
-    p_sys = (tls_session_sys_t *)(p_session->p_sys);
-
-    if( p_sys->b_handshaked == VLC_TRUE )
-        gnutls_bye( p_sys->session, GNUTLS_SHUT_WR );
-    gnutls_deinit( p_sys->session );
-
-    if( p_sys->psz_hostname != NULL )
-        free( p_sys->psz_hostname );
-
-    vlc_object_detach( p_session );
-    vlc_object_destroy( p_session );
-
-    free( p_sys );
-}
-
-
 typedef int (*tls_prio_func) (gnutls_session_t, const int *);
 
 static int
@@ -535,20 +595,6 @@ gnutls_SessionPrioritize (vlc_object_t *obj, gnutls_session_t session)
 }
 
 
-static void
-gnutls_ClientDelete( tls_session_t *p_session )
-{
-    /* On the client-side, credentials are re-allocated per session */
-    gnutls_certificate_credentials x509_cred =
-                        ((tls_client_sys_t *)(p_session->p_sys))->x509_cred;
-
-    gnutls_SessionClose( p_session );
-
-    /* credentials must be free'd *after* gnutls_deinit() */
-    gnutls_certificate_free_credentials( x509_cred );
-}
-
-
 static int
 gnutls_Addx509File( vlc_object_t *p_this,
                     gnutls_certificate_credentials cred,
@@ -659,62 +705,65 @@ gnutls_Addx509File( vlc_object_t *p_this,
 }
 
 
+/** TLS client session data */
+typedef struct tls_client_sys_t
+{
+    struct tls_session_sys_t       session;
+    gnutls_certificate_credentials x509_cred;
+} tls_client_sys_t;
+
+
 /**
  * Initializes a client-side TLS session.
  */
-static tls_session_t *
-gnutls_ClientCreate( tls_t *p_tls )
+static int OpenClient (vlc_object_t *obj)
 {
-    tls_session_t *p_session = NULL;
-    tls_client_sys_t *p_sys = NULL;
+    tls_session_t *p_session = (tls_session_t *)obj;
     int i_val;
 
-    p_sys = (tls_client_sys_t *)malloc( sizeof(struct tls_client_sys_t) );
-    if( p_sys == NULL )
-        return NULL;
+    if (gnutls_Init (obj))
+        return VLC_EGENERIC;
 
-    p_session = (struct tls_session_t *)vlc_object_create ( p_tls, sizeof(struct tls_session_t) );
-    if( p_session == NULL )
+    tls_client_sys_t *p_sys = malloc (sizeof (*p_sys));
+    if (p_sys == NULL)
     {
-        free( p_sys );
-        return NULL;
+        gnutls_Deinit (obj);
+        return VLC_ENOMEM;
     }
 
-    p_session->p_sys = p_sys;
+    p_session->p_sys = &p_sys->session;
     p_session->sock.p_sys = p_session;
     p_session->sock.pf_send = gnutls_Send;
     p_session->sock.pf_recv = gnutls_Recv;
     p_session->pf_handshake = gnutls_BeginHandshake;
-    p_session->pf_close = gnutls_ClientDelete;
+    p_session->pf_close = NULL;
 
     p_sys->session.b_handshaked = VLC_FALSE;
     p_sys->session.psz_hostname = NULL;
 
-    vlc_object_attach( p_session, p_tls );
-
-    const char *homedir = p_tls->p_libvlc->psz_datadir,
+    const char *homedir = obj->p_libvlc->psz_datadir,
                *datadir = config_GetDataDir ();
     size_t l1 = strlen (homedir), l2 = strlen (datadir);
     char path[((l1 > l2) ? l1 : l2) + sizeof ("/ssl/private")];
     //                              > sizeof ("/ssl/certs")
     //                              > sizeof ("/ca-certificates.crt")
 
-    i_val = gnutls_certificate_allocate_credentials( &p_sys->x509_cred );
-    if( i_val != 0 )
+    i_val = gnutls_certificate_allocate_credentials (&p_sys->x509_cred);
+    if (i_val != 0)
     {
-        msg_Err( p_tls, "cannot allocate X509 credentials: %s",
-                 gnutls_strerror( i_val ) );
+        msg_Err (obj, "cannot allocate X509 credentials: %s",
+                 gnutls_strerror (i_val));
         goto error;
     }
 
-    if (var_CreateGetBool (p_tls, "tls-check-cert"))
+    if (var_CreateGetBool (obj, "tls-check-cert"))
     {
         sprintf (path, "%s/ssl/certs", homedir);
-        gnutls_Addx509Directory ((vlc_object_t *)p_session,
+        gnutls_Addx509Directory (VLC_OBJECT (p_session),
                                   p_sys->x509_cred, path, VLC_FALSE);
 
         sprintf (path, "%s/ca-certificates.crt", datadir);
-        gnutls_Addx509File ((vlc_object_t *)p_session,
+        gnutls_Addx509File (VLC_OBJECT (p_session),
                             p_sys->x509_cred, path, VLC_FALSE);
         p_session->pf_handshake2 = gnutls_HandshakeAndValidate;
     }
@@ -722,15 +771,15 @@ gnutls_ClientCreate( tls_t *p_tls )
         p_session->pf_handshake2 = gnutls_ContinueHandshake;
 
     sprintf (path, "%s/ssl/private", homedir);
-    gnutls_Addx509Directory ((vlc_object_t *)p_session, p_sys->x509_cred,
+    gnutls_Addx509Directory (VLC_OBJECT (p_session), p_sys->x509_cred,
                              path, VLC_TRUE);
 
     i_val = gnutls_init( &p_sys->session.session, GNUTLS_CLIENT );
-    if( i_val != 0 )
+    if (i_val != 0)
     {
-        msg_Err( p_tls, "cannot initialize TLS session: %s",
-                 gnutls_strerror( i_val ) );
-        gnutls_certificate_free_credentials( p_sys->x509_cred );
+        msg_Err (obj, "cannot initialize TLS session: %s",
+                 gnutls_strerror (i_val));
+        gnutls_certificate_free_credentials (p_sys->x509_cred);
         goto error;
     }
 
@@ -738,34 +787,78 @@ gnutls_ClientCreate( tls_t *p_tls )
                                   p_sys->session.session))
         goto s_error;
 
-    i_val = gnutls_credentials_setp_sys->session.session,
+    i_val = gnutls_credentials_set (p_sys->session.session,
                                     GNUTLS_CRD_CERTIFICATE,
-                                    p_sys->x509_cred );
-    if( i_val < 0 )
+                                    p_sys->x509_cred);
+    if (i_val < 0)
     {
-        msg_Err( p_tls, "cannot set TLS session credentials: %s",
-                 gnutls_strerror( i_val ) );
+        msg_Err (obj, "cannot set TLS session credentials: %s",
+                 gnutls_strerror (i_val));
         goto s_error;
     }
 
-    return p_session;
+    return VLC_SUCCESS;
 
 s_error:
-    gnutls_deinit( p_sys->session.session );
-    gnutls_certificate_free_credentials( p_sys->x509_cred );
-
+    gnutls_deinit (p_sys->session.session);
+    gnutls_certificate_free_credentials (p_sys->x509_cred);
 error:
-    vlc_object_detach( p_session );
-    vlc_object_destroy( p_session );
-    free( p_sys );
+    gnutls_Deinit (obj);
+    free (p_sys);
+    return VLC_EGENERIC;
+}
 
-    return NULL;
+
+static void CloseClient (vlc_object_t *obj)
+{
+    tls_session_t *client = (tls_session_t *)obj;
+    tls_client_sys_t *p_sys = (tls_client_sys_t *)(client->p_sys);
+
+    if (p_sys->session.b_handshaked == VLC_TRUE)
+        gnutls_bye (p_sys->session.session, GNUTLS_SHUT_WR);
+    gnutls_deinit (p_sys->session.session);
+    /* credentials must be free'd *after* gnutls_deinit() */
+    gnutls_certificate_free_credentials (p_sys->x509_cred);
+
+    gnutls_Deinit (obj);
+    free (p_sys->session.psz_hostname);
+    free (p_sys);
 }
 
 
+/**
+ * Server-side TLS
+ */
+struct tls_server_sys_t
+{
+    gnutls_certificate_credentials  x509_cred;
+    gnutls_dh_params                dh_params;
+
+    struct saved_session_t          *p_cache;
+    struct saved_session_t          *p_store;
+    int                             i_cache_size;
+    vlc_mutex_t                     cache_lock;
+
+    int                             (*pf_handshake2)( tls_session_t * );
+};
+
+
 /**
  * TLS session resumption callbacks (server-side)
  */
+#define MAX_SESSION_ID    32
+#define MAX_SESSION_DATA  1024
+
+typedef struct saved_session_t
+{
+    char id[MAX_SESSION_ID];
+    char data[MAX_SESSION_DATA];
+
+    unsigned i_idlen;
+    unsigned i_datalen;
+} saved_session_t;
+
+
 static int cb_store( void *p_server, gnutls_datum key, gnutls_datum data )
 {
     tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
@@ -792,10 +885,9 @@ static int cb_store( void *p_server, gnutls_datum key, gnutls_datum data )
 }
 
 
-static const gnutls_datum err_datum = { NULL, 0 };
-
 static gnutls_datum cb_fetch( void *p_server, gnutls_datum key )
 {
+    static const gnutls_datum err_datum = { NULL, 0 };
     tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
     saved_session_t *p_session, *p_end;
 
@@ -861,6 +953,26 @@ static int cb_delete( void *p_server, gnutls_datum key )
 }
 
 
+/**
+ * Terminates TLS session and releases session data.
+ * You still have to close the socket yourself.
+ */
+static void
+gnutls_SessionClose( tls_session_t *p_session )
+{
+    tls_session_sys_t *p_sys = p_session->p_sys;
+
+    if( p_sys->b_handshaked == VLC_TRUE )
+        gnutls_bye( p_sys->session, GNUTLS_SHUT_WR );
+    gnutls_deinit( p_sys->session );
+
+    vlc_object_detach( p_session );
+    vlc_object_destroy( p_session );
+
+    free( p_sys );
+}
+
+
 /**
  * Initializes a server-side TLS session.
  */
@@ -885,7 +997,7 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server )
 
     vlc_object_attach( p_session, p_server );
 
-    p_server_sys = (tls_server_sys_t *)p_server->p_sys;
+    p_server_sys = p_server->p_sys;
     p_session->sock.p_sys = p_session;
     p_session->sock.pf_send = gnutls_Send;
     p_session->sock.pf_recv = gnutls_Recv;
@@ -893,8 +1005,8 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server )
     p_session->pf_handshake2 = p_server_sys->pf_handshake2;
     p_session->pf_close = gnutls_SessionClose;
 
-    ((tls_session_sys_t *)p_session->p_sys)->b_handshaked = VLC_FALSE;
-    ((tls_session_sys_t *)p_session->p_sys)->psz_hostname = NULL;
+    p_session->p_sys->b_handshaked = VLC_FALSE;
+    p_session->p_sys->psz_hostname = NULL;
 
     i_val = gnutls_init( &session, GNUTLS_SERVER );
     if( i_val != 0 )
@@ -904,7 +1016,7 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server )
         goto error;
     }
 
-    ((tls_session_sys_t *)p_session->p_sys)->session = session;
+    p_session->p_sys->session = session;
 
     if (gnutls_SessionPrioritize (VLC_OBJECT (p_session), session))
     {
@@ -946,35 +1058,13 @@ error:
 }
 
 
-/**
- * Releases data allocated with tls_ServerCreate().
- */
-static void
-gnutls_ServerDelete( tls_server_t *p_server )
-{
-    tls_server_sys_t *p_sys;
-    p_sys = (tls_server_sys_t *)p_server->p_sys;
-
-    vlc_mutex_destroy( &p_sys->cache_lock );
-    free( p_sys->p_cache );
-
-    vlc_object_detach( p_server );
-    vlc_object_destroy( p_server );
-
-    /* all sessions depending on the server are now deinitialized */
-    gnutls_certificate_free_credentials( p_sys->x509_cred );
-    gnutls_dh_params_deinit( p_sys->dh_params );
-    free( p_sys );
-}
-
-
 /**
  * Adds one or more certificate authorities.
  *
  * @param psz_ca_path (Unicode) path to an x509 certificates list.
  *
  * @return -1 on error, 0 on success.
- *****************************************************************************/
+ */
 static int
 gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
 {
@@ -1035,46 +1125,33 @@ gnutls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path )
 
 /**
  * Allocates a whole server's TLS credentials.
- *
- * @return NULL on error.
  */
-static tls_server_t *
-gnutls_ServerCreate( tls_t *p_tls, const char *psz_cert_path,
-                     const char *psz_key_path )
+static int OpenServer (vlc_object_t *obj)
 {
-    tls_server_t *p_server;
+    tls_server_t *p_server = (tls_server_t *)obj;
     tls_server_sys_t *p_sys;
-    char *psz_local_key, *psz_local_cert;
     int val;
 
-    msg_Dbg( p_tls, "creating TLS server" );
+    if (gnutls_Init (obj))
+        return VLC_EGENERIC;
+
+    msg_Dbg (obj, "creating TLS server");
 
     p_sys = (tls_server_sys_t *)malloc( sizeof(struct tls_server_sys_t) );
     if( p_sys == NULL )
-        return NULL;
+        return VLC_ENOMEM;
 
-    p_sys->i_cache_size = config_GetInt (p_tls, "gnutls-cache-size");
-    p_sys->p_cache = (struct saved_session_t *)calloc( p_sys->i_cache_size,
-                                           sizeof( struct saved_session_t ) );
-    if( p_sys->p_cache == NULL )
+    p_sys->i_cache_size = config_GetInt (obj, "gnutls-cache-size");
+    p_sys->p_cache = calloc (p_sys->i_cache_size,
+                             sizeof (struct saved_session_t));
+    if (p_sys->p_cache == NULL)
     {
-        free( p_sys );
-        return NULL;
+        free (p_sys);
+        return VLC_ENOMEM;
     }
-    p_sys->p_store = p_sys->p_cache;
-
-    p_server = vlc_object_create( p_tls, sizeof(struct tls_server_t) );
-    if( p_server == NULL )
-    {
-        free( p_sys->p_cache );
-        free( p_sys );
-        return NULL;
-    }
-
-    vlc_object_attach( p_server, p_tls );
 
+    p_sys->p_store = p_sys->p_cache;
     p_server->p_sys = p_sys;
-    p_server->pf_delete = gnutls_ServerDelete;
     p_server->pf_add_CA = gnutls_ServerAddCA;
     p_server->pf_add_CRL = gnutls_ServerAddCRL;
     p_server->pf_session_prepare = gnutls_ServerSessionPrepare;
@@ -1093,13 +1170,18 @@ gnutls_ServerCreate( tls_t *p_tls, const char *psz_cert_path,
         goto error;
     }
 
-    psz_local_cert = ToLocale( psz_cert_path );
-    psz_local_key = ToLocale( psz_key_path );
-    val = gnutls_certificate_set_x509_key_file( p_sys->x509_cred,
+    char *psz_cert_path = var_GetNonEmptyString (obj, "tls-x509-cert");
+    char *psz_key_path = var_GetNonEmptyString (obj, "tls-x509-key");
+    const char *psz_local_cert = ToLocale (psz_cert_path);
+    const char *psz_local_key = ToLocale (psz_key_path);
+    val = gnutls_certificate_set_x509_key_file (p_sys->x509_cred,
                                                 psz_local_cert, psz_local_key,
                                                 GNUTLS_X509_FMT_PEM );
-    LocaleFree( psz_cert_path );
-    LocaleFree( psz_key_path );
+    LocaleFree (psz_key_path);
+    free (psz_key_path);
+    LocaleFree (psz_cert_path);
+    free (psz_cert_path);
+
     if( val < 0 )
     {
         msg_Err( p_server, "cannot set certificate chain or private key: %s",
@@ -1116,8 +1198,8 @@ gnutls_ServerCreate( tls_t *p_tls, const char *psz_cert_path,
     if( val >= 0 )
     {
         msg_Dbg( p_server, "computing Diffie Hellman ciphers parameters" );
-        val = gnutls_dh_params_generate2p_sys->dh_params,
-                                          config_GetInt( p_tls, "gnutls-dh-bits" ) );
+        val = gnutls_dh_params_generate2 (p_sys->dh_params,
+                                          config_GetInt (obj, "gnutls-dh-bits"));
     }
     if( val < 0 )
     {
@@ -1130,144 +1212,29 @@ gnutls_ServerCreate( tls_t *p_tls, const char *psz_cert_path,
 
     gnutls_certificate_set_dh_params( p_sys->x509_cred, p_sys->dh_params);
 
-    return p_server;
+    return VLC_SUCCESS;
 
 error:
-    vlc_mutex_destroy( &p_sys->cache_lock );
-    vlc_object_detach( p_server );
-    vlc_object_destroy( p_server );
-    free( p_sys );
-    return NULL;
+    vlc_mutex_destroy (&p_sys->cache_lock);
+    free (p_sys->p_cache);
+    free (p_sys);
+    return VLC_EGENERIC;
 }
 
-
-#ifdef LIBVLC_USE_PTHREAD
-GCRY_THREAD_OPTION_PTHREAD_IMPL;
-# define gcry_threads_vlc gcry_threads_pthread
-#else
 /**
- * gcrypt thread option VLC implementation
+ * Destroys a TLS server object.
  */
-
-# define NEED_THREAD_CONTEXT 1
-static vlc_object_t *__p_gcry_data;
-
-static int gcry_vlc_mutex_init( void **p_sys )
-{
-    int i_val;
-    vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc( sizeof( vlc_mutex_t ) );
-
-    if( p_lock == NULL)
-        return ENOMEM;
-
-    i_val = vlc_mutex_init( __p_gcry_data, p_lock );
-    if( i_val )
-        free( p_lock );
-    else
-        *p_sys = p_lock;
-    return i_val;
-}
-
-static int gcry_vlc_mutex_destroy( void **p_sys )
-{
-    int i_val;
-    vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
-
-    i_val = vlc_mutex_destroy( p_lock );
-    free( p_lock );
-    return i_val;
-}
-
-static int gcry_vlc_mutex_lock( void **p_sys )
-{
-    return vlc_mutex_lock( (vlc_mutex_t *)*p_sys );
-}
-
-static int gcry_vlc_mutex_unlock( void **lock )
-{
-    return vlc_mutex_unlock( (vlc_mutex_t *)*lock );
-}
-
-static struct gcry_thread_cbs gcry_threads_vlc =
-{
-    GCRY_THREAD_OPTION_USER,
-    NULL,
-    gcry_vlc_mutex_init,
-    gcry_vlc_mutex_destroy,
-    gcry_vlc_mutex_lock,
-    gcry_vlc_mutex_unlock
-};
-#endif
-
-
-/*****************************************************************************
- * Module initialization
- *****************************************************************************/
-static unsigned refs = 0;
-
-static int
-Open( vlc_object_t *p_this )
+static void CloseServer (vlc_object_t *p_server)
 {
-    tls_t *p_tls = (tls_t *)p_this;
-    vlc_mutex_t *lock;
-
-    lock = var_GetGlobalMutex( "gnutls_mutex" );
-    vlc_mutex_lock( lock );
-
-    /* Initialize GnuTLS only once */
-    if( refs == 0 )
-    {
-#ifdef NEED_THREAD_CONTEXT
-        __p_gcry_data = VLC_OBJECT( p_this->p_libvlc );
-#endif
-
-        gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
-        if( gnutls_global_init( ) )
-        {
-            msg_Warn( p_this, "cannot initialize GnuTLS" );
-            vlc_mutex_unlock( lock );
-            return VLC_EGENERIC;
-        }
-
-        const char *psz_version = gnutls_check_version( "1.2.9" );
-        if( psz_version == NULL )
-        {
-            gnutls_global_deinit( );
-            vlc_mutex_unlock( lock );
-            msg_Err( p_this, "unsupported GnuTLS version" );
-            return VLC_EGENERIC;
-        }
-        msg_Dbg( p_this, "GnuTLS v%s initialized", psz_version );
-    }
-
-    refs++;
-    vlc_mutex_unlock( lock );
-
-    p_tls->pf_server_create = gnutls_ServerCreate;
-    p_tls->pf_client_create = gnutls_ClientCreate;
-    return VLC_SUCCESS;
-}
-
-
-/*****************************************************************************
- * Module deinitialization
- *****************************************************************************/
-static void
-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_mutex_t *lock;
+    tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
 
-    lock = var_GetGlobalMutex( "gnutls_mutex" );
-    vlc_mutex_lock( lock );
+    vlc_mutex_destroy (&p_sys->cache_lock);
+    free (p_sys->p_cache);
 
-    if( --refs == 0 )
-    {
-        gnutls_global_deinit( );
-        msg_Dbg( p_this, "GnuTLS deinitialized" );
-    }
+    /* all sessions depending on the server are now deinitialized */
+    gnutls_certificate_free_credentials (p_sys->x509_cred);
+    gnutls_dh_params_deinit (p_sys->dh_params);
+    free (p_sys);
 
-    vlc_mutex_unlock( lock );
+    gnutls_Deinit (p_server);
 }
index 9eb6a8f2a8b78d91c1ef876e989109b514962c9b..22d89e8d5e9e4bc6b5dc75f35893b15313e44c8b 100644 (file)
@@ -299,10 +299,6 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type )
             i_size = sizeof( vod_t );
             psz_type = "vod server";
             break;
-        case VLC_OBJECT_TLS:
-            i_size = sizeof( tls_t );
-            psz_type = "tls";
-            break;
         case VLC_OBJECT_XML:
             i_size = sizeof( xml_t );
             psz_type = "xml";
index c74be68bdb81ad82cb53b71ef0eb18b295f5fcf6..8ff6d392fe1caa90037d4b279044310662ec9f45 100644 (file)
  */
 
 #include <vlc/vlc.h>
+#include "libvlc.h"
 
 #include <vlc_tls.h>
 
-static tls_t *
-tls_Init( vlc_object_t *p_this )
-{
-    tls_t *p_tls;
-    vlc_value_t lockval;
-
-    var_Create( p_this->p_libvlc, "tls_mutex", VLC_VAR_MUTEX );
-    var_Get( p_this->p_libvlc, "tls_mutex", &lockval );
-    vlc_mutex_lock( lockval.p_address );
-
-    p_tls = vlc_object_find( p_this, VLC_OBJECT_TLS, FIND_ANYWHERE );
-
-    if( p_tls == NULL )
-    {
-        p_tls = vlc_object_create( p_this, VLC_OBJECT_TLS );
-        if( p_tls == NULL )
-        {
-            vlc_mutex_unlock( lockval.p_address );
-            return NULL;
-        }
-
-        p_tls->p_module = module_Need( p_tls, "tls", 0, 0 );
-        if( p_tls->p_module == NULL )
-        {
-            msg_Err( p_tls, "TLS/SSL provider not found" );
-            vlc_mutex_unlock( lockval.p_address );
-            vlc_object_destroy( p_tls );
-            return NULL;
-        }
-
-        vlc_object_attach( p_tls, p_this->p_libvlc );
-        vlc_object_yield( p_tls );
-        msg_Dbg( p_tls, "TLS/SSL provider initialized" );
-    }
-    vlc_mutex_unlock( lockval.p_address );
-
-    return p_tls;
-}
-
-static void
-tls_Deinit( tls_t *p_tls )
-{
-    int i;
-    vlc_value_t lockval;
-
-    var_Get( p_tls->p_libvlc, "tls_mutex", &lockval );
-    vlc_mutex_lock( lockval.p_address );
-
-    vlc_object_release( p_tls );
-    i = p_tls->i_refcount;
-    if( i == 0 )
-        vlc_object_detach( p_tls );
-
-    vlc_mutex_unlock( lockval.p_address );
-
-    if( i == 0 )
-    {
-        module_Unneed( p_tls, p_tls->p_module );
-        msg_Dbg( p_tls, "TLS/SSL provider deinitialized" );
-        vlc_object_destroy( p_tls );
-    }
-}
-
 /**
  * Allocates a whole server's TLS credentials.
  *
- * @param psz_cert required (Unicode) path to an x509 certificate.
- * @param psz_key required (Unicode) path to the PKCS private key for
- * the certificate.
+ * @param cert_path required (Unicode) path to an x509 certificate,
+ *                  if NULL, anonymous key exchange will be used.
+ * @param key_path (UTF-8) path to the PKCS private key for the certificate,
+ *                 if NULL; cert_path will be used.
  *
  * @return NULL on error.
  */
 tls_server_t *
-tls_ServerCreate( vlc_object_t *p_this, const char *psz_cert,
-                  const char *psz_key )
+tls_ServerCreate (vlc_object_t *obj, const char *cert_path,
+                  const char *key_path)
 {
-    tls_t *p_tls;
-    tls_server_t *p_server;
+    tls_server_t *srv;
 
-    p_tls = tls_Init( p_this );
-    if( p_tls == NULL )
+    srv = (tls_server_t *)vlc_custom_create (obj, sizeof (*srv),
+                                             VLC_OBJECT_GENERIC,
+                                             "tls server");
+    if (srv == NULL)
         return NULL;
 
-    if( psz_key == NULL )
-        psz_key = psz_cert;
+    var_Create (srv, "tls-x509-cert", VLC_VAR_STRING);
+    var_Create (srv, "tls-x509-key", VLC_VAR_STRING);
 
-    p_server = p_tls->pf_server_create( p_tls, psz_cert, psz_key );
-    if( p_server != NULL )
+    if (cert_path != NULL)
     {
-        msg_Dbg( p_tls, "TLS/SSL server initialized" );
-        return p_server;
+        var_SetString (srv, "tls-x509-cert", cert_path);
+
+        if (key_path == NULL)
+            key_path = cert_path;
+        var_SetString (srv, "tls-x509-key", key_path);
     }
-    else
-        msg_Err( p_tls, "TLS/SSL server error" );
 
-    tls_Deinit( p_tls );
-    return NULL;
+    srv->p_module = module_Need (srv, "tls server", 0, 0);
+    if (srv->p_module == NULL)
+    {
+        msg_Err (srv, "TLS server plugin not available");
+        vlc_object_destroy (srv);
+        return NULL;
+    }
+
+    vlc_object_attach (srv, obj);
+    msg_Dbg (srv, "TLS server plugin initialized");
+    return srv;
 }
 
 
 /**
  * Releases data allocated with tls_ServerCreate.
+ * @param srv TLS server object to be destroyed, or NULL
  */
-void
-tls_ServerDelete( tls_server_t *p_server )
+void tls_ServerDelete (tls_server_t *srv)
 {
-    tls_t *p_tls = (tls_t *)p_server->p_parent;
+    if (srv == NULL)
+        return;
 
-    p_server->pf_delete( p_server );
-
-    tls_Deinit( p_tls );
+    module_Unneed (srv, srv->p_module);
+    vlc_object_detach (srv);
+    vlc_object_destroy (srv);
 }
 
 
@@ -156,36 +105,38 @@ tls_ServerDelete( tls_server_t *p_server )
  * @return NULL on error.
  **/
 tls_session_t *
-tls_ClientCreate( vlc_object_t *p_this, int fd, const char *psz_hostname )
+tls_ClientCreate (vlc_object_t *obj, int fd, const char *psz_hostname)
 {
-    tls_t *p_tls;
-    tls_session_t *p_session;
+    tls_session_t *cl;
+
+    cl = (tls_session_t *)vlc_custom_create (obj, sizeof (*cl),
+                                             VLC_OBJECT_GENERIC,
+                                             "tls client");
+    if (cl == NULL)
+        return NULL;
 
-    p_tls = tls_Init( p_this );
-    if( p_tls == NULL )
+    cl->p_module = module_Need (cl, "tls client", 0, 0);
+    if (cl->p_module == NULL)
+    {
+        msg_Err (cl, "TLS client plugin not available");
+        vlc_object_destroy (cl);
         return NULL;
-    p_session = p_tls->pf_client_create( p_tls );
-    if( p_session != NULL )
+    }
+
+    int val = tls_ClientSessionHandshake (cl, fd, psz_hostname);
+    while (val > 0)
+        val = tls_SessionContinueHandshake (cl);
+
+    if (val == 0)
     {
-        int i_val;
-
-        for( i_val = tls_ClientSessionHandshake( p_session, fd,
-                                                 psz_hostname );
-             i_val > 0;
-             i_val = tls_SessionContinueHandshake( p_session ) );
-
-        if( i_val == 0 )
-        {
-            msg_Dbg( p_this, "TLS/SSL client initialized" );
-            return p_session;
-        }
-        msg_Err( p_this, "TLS/SSL session handshake error" );
+        msg_Dbg (cl, "TLS client session initialized");
+        vlc_object_attach (cl, obj);
+        return cl;
     }
-    else
-        msg_Err( p_this, "TLS/SSL client error" );
+    msg_Err (cl, "TLS client session handshake error");
 
-    tls_Deinit( p_tls );
+    module_Unneed (cl, cl->p_module);
+    vlc_object_destroy (cl);
     return NULL;
 }
 
@@ -194,12 +145,12 @@ tls_ClientCreate( vlc_object_t *p_this, int fd, const char *psz_hostname )
  * Releases data allocated with tls_ClientCreate.
  * It is your job to close the underlying socket.
  */
-void
-tls_ClientDelete( tls_session_t *p_session )
+void tls_ClientDelete (tls_session_t *cl)
 {
-    tls_t *p_tls = (tls_t *)p_session->p_parent;
-
-    p_session->pf_close( p_session );
+    if (cl == NULL)
+        return;
 
-    tls_Deinit( p_tls );
+    module_Unneed (cl, cl->p_module);
+    vlc_object_detach (cl);
+    vlc_object_destroy (cl);
 }