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

Fix TLS session cleanup

parent bd807d2a
...@@ -42,7 +42,8 @@ struct tls_server_t ...@@ -42,7 +42,8 @@ struct tls_server_t
int (*pf_add_CA) ( tls_server_t *, const char * ); int (*pf_add_CA) ( tls_server_t *, const char * );
int (*pf_add_CRL) ( tls_server_t *, const char * ); int (*pf_add_CRL) ( tls_server_t *, const char * );
tls_session_t * (*pf_session_prepare) ( tls_server_t * ); tls_session_t * (*pf_open) ( tls_server_t * );
void (*pf_close) ( tls_server_t *, tls_session_t * );
}; };
typedef struct tls_session_sys_t tls_session_sys_t; typedef struct tls_session_sys_t tls_session_sys_t;
...@@ -55,53 +56,24 @@ struct tls_session_t ...@@ -55,53 +56,24 @@ struct tls_session_t
tls_session_sys_t *p_sys; tls_session_sys_t *p_sys;
struct virtual_socket_t sock; struct virtual_socket_t sock;
int (*pf_handshake) ( tls_session_t *, int ); void (*pf_set_fd) ( tls_session_t *, int );
int (*pf_handshake2) ( tls_session_t * ); int (*pf_handshake) ( tls_session_t * );
void (*pf_close) ( tls_session_t * );
}; };
/***************************************************************************** tls_server_t *tls_ServerCreate (vlc_object_t *, const char *, const char *);
* tls_ServerCreate: void tls_ServerDelete (tls_server_t *);
***************************************************************************** int tls_ServerAddCA (tls_server_t *srv, const char *path);
* Allocates a whole server's TLS credentials. int tls_ServerAddCRL (tls_server_t *srv, const char *path);
* Returns NULL on error.
*****************************************************************************/
VLC_EXPORT( tls_server_t *, tls_ServerCreate, ( vlc_object_t *, const char *, const char * ) );
/*****************************************************************************
* tls_ServerAddCA:
*****************************************************************************
* Adds one or more certificate authorities.
* Returns -1 on error, 0 on success.
*****************************************************************************/
# define tls_ServerAddCA( a, b ) (((tls_server_t *)a)->pf_add_CA (a, b))
/*****************************************************************************
* tls_ServerAddCRL:
*****************************************************************************
* Adds a certificates revocation list to be sent to TLS clients.
* Returns -1 on error, 0 on success.
*****************************************************************************/
# define tls_ServerAddCRL( a, b ) (((tls_server_t *)a)->pf_add_CRL (a, b))
VLC_EXPORT( void, tls_ServerDelete, ( tls_server_t * ) );
tls_session_t *tls_ServerSessionPrepare (tls_server_t *);
# define tls_ServerSessionPrepare( a ) (((tls_server_t *)a)->pf_session_prepare (a)) int tls_ServerSessionHandshake (tls_session_t *, int fd);
# define tls_ServerSessionHandshake( a, b ) (((tls_session_t *)a)->pf_handshake (a, b)) int tls_SessionContinueHandshake (tls_session_t *);
# define tls_ServerSessionClose( a ) (((tls_session_t *)a)->pf_close (a)) void tls_ServerSessionClose (tls_session_t *);
VLC_EXPORT( tls_session_t *, tls_ClientCreate, ( vlc_object_t *, int, const char * ) ); VLC_EXPORT( tls_session_t *, tls_ClientCreate, ( vlc_object_t *, int, const char * ) );
VLC_EXPORT( void, tls_ClientDelete, ( tls_session_t * ) ); VLC_EXPORT( void, tls_ClientDelete, ( tls_session_t * ) );
# define tls_ClientSessionHandshake( a, b ) (((tls_session_t *)a)->pf_handshake (a, b))
# define tls_SessionContinueHandshake( a ) (((tls_session_t *)a)->pf_handshake2 (a))
/* 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 ) (((tls_session_t *)a)->sock.pf_send (a, b, c )) # define tls_Send( a, b, c ) (((tls_session_t *)a)->sock.pf_send (a, b, c ))
......
...@@ -301,9 +301,11 @@ gnutls_Recv( void *p_session, void *buf, int i_length ) ...@@ -301,9 +301,11 @@ gnutls_Recv( void *p_session, void *buf, int i_length )
/** /**
* @return -1 on error (you need not and must not call tls_SessionClose()) * Starts or continues the TLS handshake.
* 0 on succesful handshake completion, 1 if more would-be blocking recv is *
* needed, 2 if more would-be blocking send is required. * @return -1 on fatal error, 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 static int
gnutls_ContinueHandshake (tls_session_t *p_session) gnutls_ContinueHandshake (tls_session_t *p_session)
...@@ -325,7 +327,6 @@ gnutls_ContinueHandshake (tls_session_t *p_session) ...@@ -325,7 +327,6 @@ gnutls_ContinueHandshake (tls_session_t *p_session)
#endif #endif
msg_Err( p_session, "TLS handshake error: %s", msg_Err( p_session, "TLS handshake error: %s",
gnutls_strerror( val ) ); gnutls_strerror( val ) );
p_session->pf_close( p_session );
return -1; return -1;
} }
...@@ -373,7 +374,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session ) ...@@ -373,7 +374,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
{ {
msg_Err( session, "Certificate verification failed: %s", msg_Err( session, "Certificate verification failed: %s",
gnutls_strerror( val ) ); gnutls_strerror( val ) );
goto error; return -1;
} }
if( status ) if( status )
...@@ -392,7 +393,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session ) ...@@ -392,7 +393,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
msg_Err( session, msg_Err( session,
"unknown certificate error (you found a bug in VLC)" ); "unknown certificate error (you found a bug in VLC)" );
goto error; return -1;
} }
/* certificate (host)name verification */ /* certificate (host)name verification */
...@@ -401,7 +402,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session ) ...@@ -401,7 +402,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
if( data == NULL ) if( data == NULL )
{ {
msg_Err( session, "Peer certificate not available" ); msg_Err( session, "Peer certificate not available" );
goto error; return -1;
} }
gnutls_x509_crt cert; gnutls_x509_crt cert;
...@@ -409,7 +410,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session ) ...@@ -409,7 +410,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
if( val ) if( val )
{ {
msg_Err( session, "x509 fatal error: %s", gnutls_strerror( val ) ); msg_Err( session, "x509 fatal error: %s", gnutls_strerror( val ) );
goto error; return -1;
} }
val = gnutls_x509_crt_import( cert, data, GNUTLS_X509_FMT_DER ); val = gnutls_x509_crt_import( cert, data, GNUTLS_X509_FMT_DER );
...@@ -417,7 +418,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session ) ...@@ -417,7 +418,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
{ {
msg_Err( session, "Certificate import error: %s", msg_Err( session, "Certificate import error: %s",
gnutls_strerror( val ) ); gnutls_strerror( val ) );
goto crt_error; goto error;
} }
if( p_sys->psz_hostname != NULL ) if( p_sys->psz_hostname != NULL )
...@@ -426,7 +427,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session ) ...@@ -426,7 +427,7 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
{ {
msg_Err( session, "Certificate does not match \"%s\"", msg_Err( session, "Certificate does not match \"%s\"",
p_sys->psz_hostname ); p_sys->psz_hostname );
goto crt_error; goto error;
} }
} }
else else
...@@ -435,43 +436,34 @@ gnutls_HandshakeAndValidate( tls_session_t *session ) ...@@ -435,43 +436,34 @@ gnutls_HandshakeAndValidate( tls_session_t *session )
if( gnutls_x509_crt_get_expiration_time( cert ) < time( NULL ) ) if( gnutls_x509_crt_get_expiration_time( cert ) < time( NULL ) )
{ {
msg_Err( session, "Certificate expired" ); msg_Err( session, "Certificate expired" );
goto crt_error; goto error;
} }
if( gnutls_x509_crt_get_activation_time( cert ) > time ( NULL ) ) if( gnutls_x509_crt_get_activation_time( cert ) > time ( NULL ) )
{ {
msg_Err( session, "Certificate not yet valid" ); msg_Err( session, "Certificate not yet valid" );
goto crt_error; goto error;
} }
gnutls_x509_crt_deinit( cert ); gnutls_x509_crt_deinit( cert );
msg_Dbg( session, "TLS/x509 certificate verified" ); msg_Dbg( session, "TLS/x509 certificate verified" );
return 0; return 0;
crt_error:
gnutls_x509_crt_deinit( cert );
error: error:
session->pf_close( session ); gnutls_x509_crt_deinit( cert );
return -1; return -1;
} }
/** /**
* Starts negociation of a TLS session. * Sets the operating system file descriptor backend for the TLS sesison.
* *
* @param fd stream socket already connected with the peer. * @param fd stream socket already connected with the peer.
*
* @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 static void
gnutls_BeginHandshake( tls_session_t *p_session, int fd ) gnutls_SetFD (tls_session_t *p_session, int fd)
{ {
tls_session_sys_t *p_sys = p_session->p_sys; gnutls_transport_set_ptr (p_session->p_sys->session,
(gnutls_transport_ptr)(intptr_t)fd);
gnutls_transport_set_ptr (p_sys->session, (gnutls_transport_ptr)(intptr_t)fd);
return p_session->pf_handshake2( p_session );
} }
typedef int (*tls_prio_func) (gnutls_session_t, const int *); typedef int (*tls_prio_func) (gnutls_session_t, const int *);
...@@ -718,8 +710,7 @@ static int OpenClient (vlc_object_t *obj) ...@@ -718,8 +710,7 @@ static int OpenClient (vlc_object_t *obj)
p_session->sock.p_sys = p_session; p_session->sock.p_sys = p_session;
p_session->sock.pf_send = gnutls_Send; p_session->sock.pf_send = gnutls_Send;
p_session->sock.pf_recv = gnutls_Recv; p_session->sock.pf_recv = gnutls_Recv;
p_session->pf_handshake = gnutls_BeginHandshake; p_session->pf_set_fd = gnutls_SetFD;
p_session->pf_close = NULL;
p_sys->session.b_handshaked = VLC_FALSE; p_sys->session.b_handshaked = VLC_FALSE;
p_sys->session.psz_hostname = NULL; p_sys->session.psz_hostname = NULL;
...@@ -748,10 +739,10 @@ static int OpenClient (vlc_object_t *obj) ...@@ -748,10 +739,10 @@ static int OpenClient (vlc_object_t *obj)
sprintf (path, "%s/ca-certificates.crt", datadir); sprintf (path, "%s/ca-certificates.crt", datadir);
gnutls_Addx509File (VLC_OBJECT (p_session), gnutls_Addx509File (VLC_OBJECT (p_session),
p_sys->x509_cred, path, VLC_FALSE); p_sys->x509_cred, path, VLC_FALSE);
p_session->pf_handshake2 = gnutls_HandshakeAndValidate; p_session->pf_handshake = gnutls_HandshakeAndValidate;
} }
else else
p_session->pf_handshake2 = gnutls_ContinueHandshake; p_session->pf_handshake = gnutls_ContinueHandshake;
sprintf (path, "%s/ssl/private", homedir); sprintf (path, "%s/ssl/private", homedir);
gnutls_Addx509Directory (VLC_OBJECT (p_session), p_sys->x509_cred, gnutls_Addx509Directory (VLC_OBJECT (p_session), p_sys->x509_cred,
...@@ -830,7 +821,7 @@ struct tls_server_sys_t ...@@ -830,7 +821,7 @@ struct tls_server_sys_t
int i_cache_size; int i_cache_size;
vlc_mutex_t cache_lock; vlc_mutex_t cache_lock;
int (*pf_handshake2)( tls_session_t * ); int (*pf_handshake)( tls_session_t * );
}; };
...@@ -949,9 +940,10 @@ static int cb_delete( void *p_server, gnutls_datum key ) ...@@ -949,9 +940,10 @@ static int cb_delete( void *p_server, gnutls_datum key )
* You still have to close the socket yourself. * You still have to close the socket yourself.
*/ */
static void static void
gnutls_SessionClose( tls_session_t *p_session ) gnutls_SessionClose (tls_server_t *p_server, tls_session_t *p_session)
{ {
tls_session_sys_t *p_sys = p_session->p_sys; tls_session_sys_t *p_sys = p_session->p_sys;
(void)p_server;
if( p_sys->b_handshaked == VLC_TRUE ) if( p_sys->b_handshaked == VLC_TRUE )
gnutls_bye( p_sys->session, GNUTLS_SHUT_WR ); gnutls_bye( p_sys->session, GNUTLS_SHUT_WR );
...@@ -986,15 +978,12 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server ) ...@@ -986,15 +978,12 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server )
return NULL; return NULL;
} }
vlc_object_attach( p_session, p_server );
p_server_sys = p_server->p_sys; p_server_sys = p_server->p_sys;
p_session->sock.p_sys = p_session; p_session->sock.p_sys = p_session;
p_session->sock.pf_send = gnutls_Send; p_session->sock.pf_send = gnutls_Send;
p_session->sock.pf_recv = gnutls_Recv; p_session->sock.pf_recv = gnutls_Recv;
p_session->pf_handshake = gnutls_BeginHandshake; p_session->pf_set_fd = gnutls_SetFD;
p_session->pf_handshake2 = p_server_sys->pf_handshake2; p_session->pf_handshake = p_server_sys->pf_handshake;
p_session->pf_close = gnutls_SessionClose;
p_session->p_sys->b_handshaked = VLC_FALSE; p_session->p_sys->b_handshaked = VLC_FALSE;
p_session->p_sys->psz_hostname = NULL; p_session->p_sys->psz_hostname = NULL;
...@@ -1025,8 +1014,8 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server ) ...@@ -1025,8 +1014,8 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server )
goto error; goto error;
} }
if( p_session->pf_handshake2 == gnutls_HandshakeAndValidate ) if (p_session->pf_handshake == gnutls_HandshakeAndValidate)
gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUIRE ); gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
i_val = config_GetInt (p_server, "gnutls-dh-bits"); i_val = config_GetInt (p_server, "gnutls-dh-bits");
gnutls_dh_set_prime_bits (session, i_val); gnutls_dh_set_prime_bits (session, i_val);
...@@ -1079,7 +1068,7 @@ gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path ) ...@@ -1079,7 +1068,7 @@ gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
msg_Dbg( p_server, " %d trusted CA added (%s)", val, psz_ca_path ); msg_Dbg( p_server, " %d trusted CA added (%s)", val, psz_ca_path );
/* enables peer's certificate verification */ /* enables peer's certificate verification */
p_sys->pf_handshake2 = gnutls_HandshakeAndValidate; p_sys->pf_handshake = gnutls_HandshakeAndValidate;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -1145,10 +1134,11 @@ static int OpenServer (vlc_object_t *obj) ...@@ -1145,10 +1134,11 @@ static int OpenServer (vlc_object_t *obj)
p_server->p_sys = p_sys; p_server->p_sys = p_sys;
p_server->pf_add_CA = gnutls_ServerAddCA; p_server->pf_add_CA = gnutls_ServerAddCA;
p_server->pf_add_CRL = gnutls_ServerAddCRL; p_server->pf_add_CRL = gnutls_ServerAddCRL;
p_server->pf_session_prepare = gnutls_ServerSessionPrepare; p_server->pf_open = gnutls_ServerSessionPrepare;
p_server->pf_close = gnutls_SessionClose;
/* No certificate validation by default */ /* No certificate validation by default */
p_sys->pf_handshake2 = gnutls_ContinueHandshake; p_sys->pf_handshake = gnutls_ContinueHandshake;
vlc_mutex_init( p_server, &p_sys->cache_lock ); vlc_mutex_init( p_server, &p_sys->cache_lock );
......
...@@ -311,8 +311,6 @@ __str_format_meta ...@@ -311,8 +311,6 @@ __str_format_meta
str_format_time str_format_time
tls_ClientCreate tls_ClientCreate
tls_ClientDelete tls_ClientDelete
tls_ServerCreate
tls_ServerDelete
ToLocale ToLocale
unescape_URI unescape_URI
unescape_URI_duplicate unescape_URI_duplicate
......
...@@ -94,6 +94,62 @@ void tls_ServerDelete (tls_server_t *srv) ...@@ -94,6 +94,62 @@ void tls_ServerDelete (tls_server_t *srv)
} }
/**
* Adds one or more certificate authorities from a file.
* @return -1 on error, 0 on success.
*/
int tls_ServerAddCA (tls_server_t *srv, const char *path)
{
return srv->pf_add_CA (srv, path);
}
/**
* Adds one or more certificate revocation list from a file.
* @return -1 on error, 0 on success.
*/
int tls_ServerAddCRL (tls_server_t *srv, const char *path)
{
return srv->pf_add_CRL (srv, path);
}
tls_session_t *tls_ServerSessionPrepare (tls_server_t *srv)
{
tls_session_t *ses;
ses = srv->pf_open (srv);
if (ses == NULL)
return NULL;
vlc_object_attach (ses, srv);
return ses;
}
void tls_ServerSessionClose (tls_session_t *ses)
{
tls_server_t *srv = (tls_server_t *)(ses->p_parent);
srv->pf_close (srv, ses);
}
int tls_ServerSessionHandshake (tls_session_t *ses, int fd)
{
ses->pf_set_fd (ses, fd);
return 2;
}
int tls_SessionContinueHandshake (tls_session_t *ses)
{
int val = ses->pf_handshake (ses);
if (val < 0)
tls_ServerSessionClose (ses);
return val;
}
/** /**
* Allocates a client's TLS credentials and shakes hands through the network. * Allocates a client's TLS credentials and shakes hands through the network.
* This is a blocking network operation. * This is a blocking network operation.
...@@ -108,6 +164,7 @@ tls_session_t * ...@@ -108,6 +164,7 @@ tls_session_t *
tls_ClientCreate (vlc_object_t *obj, int fd, const char *psz_hostname) tls_ClientCreate (vlc_object_t *obj, int fd, const char *psz_hostname)
{ {
tls_session_t *cl; tls_session_t *cl;
int val;
cl = (tls_session_t *)vlc_custom_create (obj, sizeof (*cl), cl = (tls_session_t *)vlc_custom_create (obj, sizeof (*cl),
VLC_OBJECT_GENERIC, VLC_OBJECT_GENERIC,
...@@ -132,9 +189,11 @@ tls_ClientCreate (vlc_object_t *obj, int fd, const char *psz_hostname) ...@@ -132,9 +189,11 @@ tls_ClientCreate (vlc_object_t *obj, int fd, const char *psz_hostname)
return NULL; return NULL;
} }
int val = tls_ClientSessionHandshake (cl, fd); cl->pf_set_fd (cl, fd);
while (val > 0)
val = tls_SessionContinueHandshake (cl); do
val = cl->pf_handshake (cl);
while (val > 0);
if (val == 0) if (val == 0)
{ {
......
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