]> git.sesse.net Git - vlc/commitdiff
tls: keep credentials when HTTP reconnects
authorRémi Denis-Courmont <remi@remlab.net>
Sat, 29 Sep 2012 13:52:13 +0000 (16:52 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Sat, 29 Sep 2012 18:26:43 +0000 (21:26 +0300)
Keeping the credentials container saves some times, as we do not need
to load and parse all of the 100+ Certificate Authorities again.
In the future, it will also avoid reloading the stored public keys
(i.e. security exceptions), or asking for user confirmation again.

Given how the HTTP access is written, the credentials are now preserved
upon seeking. Unfortunately, they are not recycled across redirections
as access_t.p_sys gets destroyed internally. This also does not work
across multiple inputs - support from the instance or input manager
would be required.

include/vlc_tls.h
modules/access/http.c
src/libvlccore.sym
src/network/tls.c

index 59ef7c21802632ee9530361b618c37f92f8a3162..d732d16d1703f4fb9b590527a464266bc37d9836 100644 (file)
@@ -45,9 +45,12 @@ struct vlc_tls
     int  (*handshake) (struct vlc_tls *);
 };
 
-VLC_API vlc_tls_t *vlc_tls_ClientCreate (vlc_object_t *, int fd,
-                                         const char *hostname);
-VLC_API void vlc_tls_ClientDelete (vlc_tls_t *);
+VLC_API vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *, int fd,
+                                                const char *host);
+vlc_tls_t *vlc_tls_ServerSessionCreate (vlc_tls_creds_t *, int fd);
+int vlc_tls_ServerSessionHandshake (vlc_tls_t *);
+VLC_API void vlc_tls_SessionDelete (vlc_tls_t *);
+#define vlc_tls_ServerSessionDelete vlc_tls_SessionDelete
 
 /* NOTE: It is assumed that a->sock.p_sys = a */
 # define tls_Send( a, b, c ) (((vlc_tls_t *)a)->sock.pf_send (a, b, c))
@@ -70,16 +73,12 @@ struct vlc_tls_creds
     void (*close) (vlc_tls_creds_t *, vlc_tls_t *);
 };
 
+VLC_API vlc_tls_creds_t *vlc_tls_ClientCreate (vlc_object_t *);
 vlc_tls_creds_t *vlc_tls_ServerCreate (vlc_object_t *,
                                        const char *cert, const char *key);
-void vlc_tls_Delete (vlc_tls_creds_t *);
+VLC_API void vlc_tls_Delete (vlc_tls_creds_t *);
 #define vlc_tls_ServerDelete vlc_tls_Delete
 int vlc_tls_ServerAddCA (vlc_tls_creds_t *srv, const char *path);
 int vlc_tls_ServerAddCRL (vlc_tls_creds_t *srv, const char *path);
 
-vlc_tls_t *vlc_tls_ServerSessionCreate (vlc_tls_creds_t *, int fd);
-int vlc_tls_ServerSessionHandshake (vlc_tls_t *);
-void vlc_tls_SessionDelete (vlc_tls_t *);
-#define vlc_tls_ServerSessionDelete vlc_tls_SessionDelete
-
 #endif
index baa1a594f4b3f1460210315d7b8c546940e97669..226333b5a88630189af8c1c8f0e852b075f6eb67 100644 (file)
@@ -139,7 +139,8 @@ struct access_sys_t
 {
     int fd;
     bool b_error;
-    vlc_tls_t  *p_tls;
+    vlc_tls_creds_t *p_creds;
+    vlc_tls_t *p_tls;
     v_socket_t *p_vs;
 
     /* From uri */
@@ -164,7 +165,6 @@ struct access_sys_t
     char       *psz_location;
     bool b_mms;
     bool b_icecast;
-    bool b_ssl;
 #ifdef HAVE_ZLIB_H
     bool b_compressed;
     struct
@@ -269,7 +269,6 @@ static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
     p_sys->psz_user_agent = NULL;
     p_sys->psz_referrer = NULL;
     p_sys->b_pace_control = true;
-    p_sys->b_ssl = false;
 #ifdef HAVE_ZLIB_H
     p_sys->b_compressed = false;
     /* 15 is the max windowBits, +32 to enable optional gzip decoding */
@@ -314,7 +313,9 @@ static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
     if( !strncmp( psz_access, "https", 5 ) )
     {
         /* HTTP over SSL */
-        p_sys->b_ssl = true;
+        p_sys->p_creds = vlc_tls_ClientCreate( p_this );
+        if( p_sys->p_creds == NULL )
+            goto error;
         if( p_sys->url.i_port <= 0 )
             p_sys->url.i_port = 443;
     }
@@ -600,6 +601,7 @@ connect:
         free( p_sys->psz_referrer );
 
         Disconnect( p_access );
+        vlc_tls_Delete( p_sys->p_creds );
         cookies = p_sys->cookies;
 #ifdef HAVE_ZLIB_H
         inflateEnd( &p_sys->inflate.stream );
@@ -692,6 +694,7 @@ error:
     free( p_sys->psz_referrer );
 
     Disconnect( p_access );
+    vlc_tls_Delete( p_sys->p_creds );
 
     if( p_sys->cookies )
     {
@@ -733,6 +736,7 @@ static void Close( vlc_object_t *p_this )
     free( p_sys->psz_referrer );
 
     Disconnect( p_access );
+    vlc_tls_Delete( p_sys->p_creds );
 
     if( p_sys->cookies )
     {
@@ -1156,7 +1160,7 @@ static int Connect( access_t *p_access, uint64_t i_tell )
     setsockopt (p_sys->fd, SOL_SOCKET, SO_KEEPALIVE, &(int){ 1 }, sizeof (int));
 
     /* Initialize TLS/SSL session */
-    if( p_sys->b_ssl )
+    if( p_sys->p_creds != NULL )
     {
         /* CONNECT to establish TLS tunnel through HTTP proxy */
         if( p_sys->b_proxy )
@@ -1220,8 +1224,8 @@ static int Connect( access_t *p_access, uint64_t i_tell )
         }
 
         /* TLS/SSL handshake */
-        p_sys->p_tls = vlc_tls_ClientCreate( VLC_OBJECT(p_access), p_sys->fd,
-                                             p_sys->url.psz_host );
+        p_sys->p_tls = vlc_tls_ClientSessionCreate( p_sys->p_creds, p_sys->fd,
+                                                    p_sys->url.psz_host );
         if( p_sys->p_tls == NULL )
         {
             msg_Err( p_access, "cannot establish HTTP/TLS session" );
@@ -1450,9 +1454,9 @@ static int Request( access_t *p_access, uint64_t i_tell )
              * handle it as everyone does. */
             if( p[0] == '/' )
             {
-                const char *psz_http_ext = p_sys->b_ssl ? "s" : "" ;
+                const char *psz_http_ext = p_sys->p_tls ? "s" : "" ;
 
-                if( p_sys->url.i_port == ( p_sys->b_ssl ? 443 : 80 ) )
+                if( p_sys->url.i_port == ( p_sys->p_tls ? 443 : 80 ) )
                 {
                     if( asprintf(&psz_new_loc, "http%s://%s%s", psz_http_ext,
                                  p_sys->url.psz_host, p) < 0 )
@@ -1632,7 +1636,7 @@ static void Disconnect( access_t *p_access )
 
     if( p_sys->p_tls != NULL)
     {
-        vlc_tls_ClientDelete( p_sys->p_tls );
+        vlc_tls_SessionDelete( p_sys->p_tls );
         p_sys->p_tls = NULL;
         p_sys->p_vs = NULL;
     }
index c7ec811bebf47893a16470c51d54c36a80da243d..0c36f01a96c7733319bc643a4b5f57fae1c712f9 100644 (file)
@@ -414,7 +414,9 @@ subpicture_region_ChainDelete
 subpicture_region_Delete
 subpicture_region_New
 vlc_tls_ClientCreate
-vlc_tls_ClientDelete
+vlc_tls_Delete
+vlc_tls_ClientSessionCreate
+vlc_tls_SessionDelete
 ToCharset
 update_Check
 update_Delete
index 07402639925bdf725c0f4f72fd3e3791e520c41f..0c0583d19d21d36341a7c6a9cbc5dd924788d9f0 100644 (file)
@@ -95,13 +95,37 @@ vlc_tls_ServerCreate (vlc_object_t *obj, const char *cert_path,
         return NULL;
     }
 
-    msg_Dbg (srv, "TLS server plugin initialized");
     return srv;
 }
 
+/**
+ * Allocates TLS credentials for a client.
+ * Credentials can be cached and reused across multiple TLS sessions.
+ *
+ * @return TLS credentials object, or NULL on error.
+ **/
+vlc_tls_creds_t *vlc_tls_ClientCreate (vlc_object_t *obj)
+{
+    vlc_tls_creds_t *crd = vlc_custom_create (obj, sizeof (*crd),
+                                              "tls client");
+    if (unlikely(crd == NULL))
+        return NULL;
+
+    crd->module = vlc_module_load (crd, "tls client", NULL, false,
+                                   tls_client_load, crd);
+    if (crd->module == NULL)
+    {
+        msg_Err (crd, "TLS client plugin not available");
+        vlc_object_release (crd);
+        return NULL;
+    }
+
+    return crd;
+}
 
 /**
- * Releases data allocated with vlc_tls_ServerCreate().
+ * Releases data allocated with vlc_tls_ClientCreate() or
+ * vlc_tls_ServerCreate().
  * @param srv TLS server object to be destroyed, or NULL
  */
 void vlc_tls_Delete (vlc_tls_creds_t *crd)
@@ -170,37 +194,22 @@ int vlc_tls_ServerSessionHandshake (vlc_tls_t *ses)
 }
 
 /**
- * Allocates a client's TLS credentials and shakes hands through the network.
- * This is a blocking network operation.
+ * Performs client side of TLS handshake through a connected socket, and
+ * establishes a secure channel. This is a blocking network operation.
  *
  * @param fd stream socket through which to establish the secure communication
  * layer.
- * @param psz_hostname Server Name Indication to pass to the server, or NULL.
+ * @param hostname expected server name, used both as Server Name Indication
+ *                 and as expected Common Name of the peer's certificate.
  *
  * @return NULL on error.
  **/
-vlc_tls_t *
-vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname)
+vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd,
+                                        const char *hostname)
 {
-    vlc_tls_creds_t *crd = vlc_custom_create (obj, sizeof (*crd),
-                                              "tls client");
-    if (unlikely(crd == NULL))
-        return NULL;
-
-    crd->module = vlc_module_load (crd, "tls client", NULL, false,
-                                   tls_client_load, crd);
-    if (crd->module == NULL)
-    {
-        msg_Err (crd, "TLS client plugin not available");
-        vlc_object_release (crd);
-        return NULL;
-    }
-
-    /* TODO: separate credentials and sessions, so we do not reload the
-     * credentials every time the HTTP access seeks... */
     vlc_tls_t *session = vlc_tls_SessionCreate (crd, fd, hostname);
     if (session == NULL)
-        goto error;
+        return NULL;
 
     /* TODO: do this directly in the TLS plugin */
     int val;
@@ -212,27 +221,7 @@ vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname)
     {
         msg_Err (session, "TLS client session handshake error");
         vlc_tls_SessionDelete (session);
-        goto error;
+        session = NULL;
     }
-    msg_Dbg (session, "TLS client session initialized");
     return session;
-error:
-    vlc_tls_Delete (crd);
-    return NULL;
-}
-
-
-/**
- * Releases data allocated with vlc_tls_ClientCreate().
- * It is your job to close the underlying socket.
- */
-void vlc_tls_ClientDelete (vlc_tls_t *session)
-{
-    if (session == NULL)
-        return;
-
-    vlc_tls_creds_t *cl = (vlc_tls_creds_t *)(session->p_parent);
-
-    vlc_tls_SessionDelete (session);
-    vlc_tls_Delete (cl);
 }