Commit ba0d112f authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

tls: keep credentials when HTTP reconnects

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.
parent 3b14b639
...@@ -45,9 +45,12 @@ struct vlc_tls ...@@ -45,9 +45,12 @@ struct vlc_tls
int (*handshake) (struct vlc_tls *); int (*handshake) (struct vlc_tls *);
}; };
VLC_API vlc_tls_t *vlc_tls_ClientCreate (vlc_object_t *, int fd, VLC_API vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *, int fd,
const char *hostname); const char *host);
VLC_API void vlc_tls_ClientDelete (vlc_tls_t *); 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 */ /* 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)) # define tls_Send( a, b, c ) (((vlc_tls_t *)a)->sock.pf_send (a, b, c))
...@@ -70,16 +73,12 @@ struct vlc_tls_creds ...@@ -70,16 +73,12 @@ struct vlc_tls_creds
void (*close) (vlc_tls_creds_t *, vlc_tls_t *); 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 *, vlc_tls_creds_t *vlc_tls_ServerCreate (vlc_object_t *,
const char *cert, const char *key); 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 #define vlc_tls_ServerDelete vlc_tls_Delete
int vlc_tls_ServerAddCA (vlc_tls_creds_t *srv, const char *path); int vlc_tls_ServerAddCA (vlc_tls_creds_t *srv, const char *path);
int vlc_tls_ServerAddCRL (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 #endif
...@@ -139,7 +139,8 @@ struct access_sys_t ...@@ -139,7 +139,8 @@ struct access_sys_t
{ {
int fd; int fd;
bool b_error; bool b_error;
vlc_tls_t *p_tls; vlc_tls_creds_t *p_creds;
vlc_tls_t *p_tls;
v_socket_t *p_vs; v_socket_t *p_vs;
/* From uri */ /* From uri */
...@@ -164,7 +165,6 @@ struct access_sys_t ...@@ -164,7 +165,6 @@ struct access_sys_t
char *psz_location; char *psz_location;
bool b_mms; bool b_mms;
bool b_icecast; bool b_icecast;
bool b_ssl;
#ifdef HAVE_ZLIB_H #ifdef HAVE_ZLIB_H
bool b_compressed; bool b_compressed;
struct struct
...@@ -269,7 +269,6 @@ static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access, ...@@ -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_user_agent = NULL;
p_sys->psz_referrer = NULL; p_sys->psz_referrer = NULL;
p_sys->b_pace_control = true; p_sys->b_pace_control = true;
p_sys->b_ssl = false;
#ifdef HAVE_ZLIB_H #ifdef HAVE_ZLIB_H
p_sys->b_compressed = false; p_sys->b_compressed = false;
/* 15 is the max windowBits, +32 to enable optional gzip decoding */ /* 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, ...@@ -314,7 +313,9 @@ static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
if( !strncmp( psz_access, "https", 5 ) ) if( !strncmp( psz_access, "https", 5 ) )
{ {
/* HTTP over SSL */ /* 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 ) if( p_sys->url.i_port <= 0 )
p_sys->url.i_port = 443; p_sys->url.i_port = 443;
} }
...@@ -600,6 +601,7 @@ connect: ...@@ -600,6 +601,7 @@ connect:
free( p_sys->psz_referrer ); free( p_sys->psz_referrer );
Disconnect( p_access ); Disconnect( p_access );
vlc_tls_Delete( p_sys->p_creds );
cookies = p_sys->cookies; cookies = p_sys->cookies;
#ifdef HAVE_ZLIB_H #ifdef HAVE_ZLIB_H
inflateEnd( &p_sys->inflate.stream ); inflateEnd( &p_sys->inflate.stream );
...@@ -692,6 +694,7 @@ error: ...@@ -692,6 +694,7 @@ error:
free( p_sys->psz_referrer ); free( p_sys->psz_referrer );
Disconnect( p_access ); Disconnect( p_access );
vlc_tls_Delete( p_sys->p_creds );
if( p_sys->cookies ) if( p_sys->cookies )
{ {
...@@ -733,6 +736,7 @@ static void Close( vlc_object_t *p_this ) ...@@ -733,6 +736,7 @@ static void Close( vlc_object_t *p_this )
free( p_sys->psz_referrer ); free( p_sys->psz_referrer );
Disconnect( p_access ); Disconnect( p_access );
vlc_tls_Delete( p_sys->p_creds );
if( p_sys->cookies ) if( p_sys->cookies )
{ {
...@@ -1156,7 +1160,7 @@ static int Connect( access_t *p_access, uint64_t i_tell ) ...@@ -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)); setsockopt (p_sys->fd, SOL_SOCKET, SO_KEEPALIVE, &(int){ 1 }, sizeof (int));
/* Initialize TLS/SSL session */ /* Initialize TLS/SSL session */
if( p_sys->b_ssl ) if( p_sys->p_creds != NULL )
{ {
/* CONNECT to establish TLS tunnel through HTTP proxy */ /* CONNECT to establish TLS tunnel through HTTP proxy */
if( p_sys->b_proxy ) if( p_sys->b_proxy )
...@@ -1220,8 +1224,8 @@ static int Connect( access_t *p_access, uint64_t i_tell ) ...@@ -1220,8 +1224,8 @@ static int Connect( access_t *p_access, uint64_t i_tell )
} }
/* TLS/SSL handshake */ /* TLS/SSL handshake */
p_sys->p_tls = vlc_tls_ClientCreate( VLC_OBJECT(p_access), p_sys->fd, p_sys->p_tls = vlc_tls_ClientSessionCreate( p_sys->p_creds, p_sys->fd,
p_sys->url.psz_host ); p_sys->url.psz_host );
if( p_sys->p_tls == NULL ) if( p_sys->p_tls == NULL )
{ {
msg_Err( p_access, "cannot establish HTTP/TLS session" ); msg_Err( p_access, "cannot establish HTTP/TLS session" );
...@@ -1450,9 +1454,9 @@ static int Request( access_t *p_access, uint64_t i_tell ) ...@@ -1450,9 +1454,9 @@ static int Request( access_t *p_access, uint64_t i_tell )
* handle it as everyone does. */ * handle it as everyone does. */
if( p[0] == '/' ) 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, if( asprintf(&psz_new_loc, "http%s://%s%s", psz_http_ext,
p_sys->url.psz_host, p) < 0 ) p_sys->url.psz_host, p) < 0 )
...@@ -1632,7 +1636,7 @@ static void Disconnect( access_t *p_access ) ...@@ -1632,7 +1636,7 @@ static void Disconnect( access_t *p_access )
if( p_sys->p_tls != NULL) 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_tls = NULL;
p_sys->p_vs = NULL; p_sys->p_vs = NULL;
} }
......
...@@ -414,7 +414,9 @@ subpicture_region_ChainDelete ...@@ -414,7 +414,9 @@ subpicture_region_ChainDelete
subpicture_region_Delete subpicture_region_Delete
subpicture_region_New subpicture_region_New
vlc_tls_ClientCreate vlc_tls_ClientCreate
vlc_tls_ClientDelete vlc_tls_Delete
vlc_tls_ClientSessionCreate
vlc_tls_SessionDelete
ToCharset ToCharset
update_Check update_Check
update_Delete update_Delete
......
...@@ -95,13 +95,37 @@ vlc_tls_ServerCreate (vlc_object_t *obj, const char *cert_path, ...@@ -95,13 +95,37 @@ vlc_tls_ServerCreate (vlc_object_t *obj, const char *cert_path,
return NULL; return NULL;
} }
msg_Dbg (srv, "TLS server plugin initialized");
return srv; 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 * @param srv TLS server object to be destroyed, or NULL
*/ */
void vlc_tls_Delete (vlc_tls_creds_t *crd) void vlc_tls_Delete (vlc_tls_creds_t *crd)
...@@ -170,37 +194,22 @@ int vlc_tls_ServerSessionHandshake (vlc_tls_t *ses) ...@@ -170,37 +194,22 @@ int vlc_tls_ServerSessionHandshake (vlc_tls_t *ses)
} }
/** /**
* Allocates a client's TLS credentials and shakes hands through the network. * Performs client side of TLS handshake through a connected socket, and
* This is a blocking network operation. * establishes a secure channel. This is a blocking network operation.
* *
* @param fd stream socket through which to establish the secure communication * @param fd stream socket through which to establish the secure communication
* layer. * 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. * @return NULL on error.
**/ **/
vlc_tls_t * vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd,
vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname) 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); vlc_tls_t *session = vlc_tls_SessionCreate (crd, fd, hostname);
if (session == NULL) if (session == NULL)
goto error; return NULL;
/* TODO: do this directly in the TLS plugin */ /* TODO: do this directly in the TLS plugin */
int val; int val;
...@@ -212,27 +221,7 @@ vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname) ...@@ -212,27 +221,7 @@ vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname)
{ {
msg_Err (session, "TLS client session handshake error"); msg_Err (session, "TLS client session handshake error");
vlc_tls_SessionDelete (session); vlc_tls_SessionDelete (session);
goto error; session = NULL;
} }
msg_Dbg (session, "TLS client session initialized");
return session; 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);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment