#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
-#define DH_BITS 1024
#define CACHE_TIMEOUT 3600
#define CACHE_SIZE 64
+#include "dhparams.h"
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
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_( \
- "This allows you to modify the Diffie-Hellman prime's number of bits, " \
- "used for TLS or SSL-based server-side encryption. This is generally " \
- "not needed." )
-
#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 "\
"This is the maximum number of resumed TLS sessions that " \
"the cache will hold." )
-#define CHECK_CERT_TEXT N_("Check TLS/SSL server certificate validity")
-#define CHECK_CERT_LONGTEXT N_( \
- "This ensures that the server certificate is valid " \
- "(i.e. signed by an approved Certification Authority)." )
-
vlc_module_begin();
set_shortname( "GnuTLS" );
set_description( _("GnuTLS transport layer security") );
set_category( CAT_ADVANCED );
set_subcategory( SUBCAT_ADVANCED_MISC );
- add_bool( "tls-check-cert", VLC_TRUE, NULL, CHECK_CERT_TEXT,
- CHECK_CERT_LONGTEXT, VLC_FALSE );
+ add_obsolete_bool( "tls-check-cert" );
add_obsolete_bool( "tls-check-hostname" );
add_submodule();
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_obsolete_integer( "gnutls-dh-bits" );
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,
{
int ret = VLC_EGENERIC;
- vlc_mutex_t *lock = var_GetGlobalMutex ("gnutls_mutex");
- vlc_mutex_lock (lock);
+ vlc_mutex_t *lock = var_AcquireMutex ("gnutls_mutex");
/* This should probably be removed/fixed. It will screw up with multiple
* LibVLC instances. */
*/
static void gnutls_Deinit (vlc_object_t *p_this)
{
- vlc_mutex_t *lock = var_GetGlobalMutex( "gnutls_mutex" );
- vlc_mutex_lock (lock);
+ vlc_mutex_t *lock = var_AcquireMutex( "gnutls_mutex" );
gnutls_global_deinit ();
msg_Dbg (p_this, "GnuTLS deinitialized");
struct tls_session_sys_t
{
- gnutls_session session;
- char *psz_hostname;
- vlc_bool_t b_handshaked;
+ gnutls_session_t session;
+ char *psz_hostname;
+ vlc_bool_t b_handshaked;
};
/**
- * @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.
+ * Starts or continues the TLS handshake.
+ *
+ * @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
gnutls_ContinueHandshake (tls_session_t *p_session)
#endif
msg_Err( p_session, "TLS handshake error: %s",
gnutls_strerror( val ) );
- p_session->pf_close( p_session );
return -1;
}
{
msg_Err( session, "Certificate verification failed: %s",
gnutls_strerror( val ) );
- goto error;
+ return -1;
}
if( status )
msg_Err( session,
"unknown certificate error (you found a bug in VLC)" );
- goto error;
+ return -1;
}
/* certificate (host)name verification */
- const gnutls_datum *data = gnutls_certificate_get_peers( p_sys->session,
- &(unsigned){0} );
+ const gnutls_datum_t *data;
+ data = gnutls_certificate_get_peers (p_sys->session, &(unsigned){0});
if( data == NULL )
{
msg_Err( session, "Peer certificate not available" );
- goto error;
+ return -1;
}
- gnutls_x509_crt cert;
+ gnutls_x509_crt_t cert;
val = gnutls_x509_crt_init( &cert );
if( 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 );
{
msg_Err( session, "Certificate import error: %s",
gnutls_strerror( val ) );
- goto crt_error;
+ goto error;
}
- if( p_sys->psz_hostname != NULL )
+ assert( p_sys->psz_hostname != NULL );
+ if ( !gnutls_x509_crt_check_hostname( cert, p_sys->psz_hostname ) )
{
- if ( !gnutls_x509_crt_check_hostname( cert, p_sys->psz_hostname ) )
- {
- msg_Err( session, "Certificate does not match \"%s\"",
- p_sys->psz_hostname );
- goto crt_error;
- }
+ msg_Err( session, "Certificate does not match \"%s\"",
+ p_sys->psz_hostname );
+ goto error;
}
- else
- msg_Warn( session, "Certificate and hostname were not verified" );
if( gnutls_x509_crt_get_expiration_time( cert ) < time( NULL ) )
{
msg_Err( session, "Certificate expired" );
- goto crt_error;
+ goto error;
}
if( gnutls_x509_crt_get_activation_time( cert ) > time ( NULL ) )
{
msg_Err( session, "Certificate not yet valid" );
- goto crt_error;
+ goto error;
}
gnutls_x509_crt_deinit( cert );
msg_Dbg( session, "TLS/x509 certificate verified" );
return 0;
-crt_error:
- gnutls_x509_crt_deinit( cert );
error:
- session->pf_close( session );
+ gnutls_x509_crt_deinit( cert );
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.
- *
- * @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_BeginHandshake( tls_session_t *p_session, int fd )
+static void
+gnutls_SetFD (tls_session_t *p_session, int fd)
{
- tls_session_sys_t *p_sys = p_session->p_sys;
-
- gnutls_transport_set_ptr (p_sys->session, (gnutls_transport_ptr)(intptr_t)fd);
-
- return p_session->pf_handshake2( p_session );
+ gnutls_transport_set_ptr (p_session->p_sys->session,
+ (gnutls_transport_ptr_t)(intptr_t)fd);
}
typedef int (*tls_prio_func) (gnutls_session_t, const int *);
static int
gnutls_Addx509File( vlc_object_t *p_this,
- gnutls_certificate_credentials cred,
+ gnutls_certificate_credentials_t cred,
const char *psz_path, vlc_bool_t b_priv );
static int
gnutls_Addx509Directory( vlc_object_t *p_this,
- gnutls_certificate_credentials cred,
+ gnutls_certificate_credentials_t cred,
const char *psz_dirname,
vlc_bool_t b_priv )
{
dir = utf8_opendir( psz_dirname );
if( dir == NULL )
{
- msg_Warn( p_this, "cannot open directory (%s): %m", psz_dirname );
- return VLC_EGENERIC;
+ if (errno != ENOENT)
+ {
+ msg_Err (p_this, "cannot open directory (%s): %m", psz_dirname);
+ return VLC_EGENERIC;
+ }
+
+ msg_Dbg (p_this, "creating empty certificate directory: %s",
+ psz_dirname);
+ utf8_mkdir (psz_dirname, b_priv ? 0700 : 0755);
+ return VLC_SUCCESS;
}
#ifdef S_ISLNK
else
/** TLS client session data */
typedef struct tls_client_sys_t
{
- struct tls_session_sys_t session;
- gnutls_certificate_credentials x509_cred;
+ struct tls_session_sys_t session;
+ gnutls_certificate_credentials_t x509_cred;
} tls_client_sys_t;
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 = NULL;
+ p_session->pf_set_fd = gnutls_SetFD;
p_sys->session.b_handshaked = VLC_FALSE;
- p_sys->session.psz_hostname = NULL;
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")];
+ char path[((l1 > l2) ? l1 : l2) + sizeof ("/ca-certificates.crt")];
+ // > sizeof ("/ssl/private")
// > sizeof ("/ssl/certs")
- // > sizeof ("/ca-certificates.crt")
i_val = gnutls_certificate_allocate_credentials (&p_sys->x509_cred);
if (i_val != 0)
goto error;
}
- if (var_CreateGetBool (obj, "tls-check-cert"))
- {
- sprintf (path, "%s/ssl/certs", homedir);
- gnutls_Addx509Directory (VLC_OBJECT (p_session),
- p_sys->x509_cred, path, VLC_FALSE);
-
- sprintf (path, "%s/ca-certificates.crt", datadir);
- gnutls_Addx509File (VLC_OBJECT (p_session),
- p_sys->x509_cred, path, VLC_FALSE);
- p_session->pf_handshake2 = gnutls_HandshakeAndValidate;
- }
- else
- p_session->pf_handshake2 = gnutls_ContinueHandshake;
+ sprintf (path, "%s/ssl", homedir);
+ utf8_mkdir (path, 0755);
+
+ sprintf (path, "%s/ssl/certs", homedir);
+ gnutls_Addx509Directory (VLC_OBJECT (p_session),
+ p_sys->x509_cred, path, VLC_FALSE);
+
+ sprintf (path, "%s/ca-certificates.crt", datadir);
+ gnutls_Addx509File (VLC_OBJECT (p_session),
+ p_sys->x509_cred, path, VLC_FALSE);
+ p_session->pf_handshake = gnutls_HandshakeAndValidate;
+ /*p_session->pf_handshake = gnutls_ContinueHandshake;*/
sprintf (path, "%s/ssl/private", homedir);
gnutls_Addx509Directory (VLC_OBJECT (p_session), p_sys->x509_cred,
p_sys->session.session))
goto s_error;
+ /* minimum DH prime bits */
+ gnutls_dh_set_prime_bits (p_sys->session.session, 1024);
+
i_val = gnutls_credentials_set (p_sys->session.session,
GNUTLS_CRD_CERTIFICATE,
p_sys->x509_cred);
}
char *servername = var_GetNonEmptyString (p_session, "tls-server-name");
- if (servername != NULL )
- {
- p_sys->session.psz_hostname = servername;
- gnutls_server_name_set (p_sys->session.session, GNUTLS_NAME_DNS,
- servername, strlen (servername));
- }
+ if (servername == NULL )
+ msg_Err (p_session, "server name missing for TLS session");
+
+ p_sys->session.psz_hostname = servername;
+ gnutls_server_name_set (p_sys->session.session, GNUTLS_NAME_DNS,
+ servername, strlen (servername));
return VLC_SUCCESS;
*/
struct tls_server_sys_t
{
- gnutls_certificate_credentials x509_cred;
- gnutls_dh_params dh_params;
+ gnutls_certificate_credentials_t x509_cred;
+ gnutls_dh_params_t dh_params;
struct saved_session_t *p_cache;
struct saved_session_t *p_store;
- int i_cache_size;
- vlc_mutex_t cache_lock;
+ int i_cache_size;
+ vlc_mutex_t cache_lock;
- int (*pf_handshake2)( tls_session_t * );
+ int (*pf_handshake) (tls_session_t *);
};
static gnutls_datum cb_fetch( void *p_server, gnutls_datum key )
{
- static const gnutls_datum err_datum = { NULL, 0 };
+ static const gnutls_datum_t err_datum = { NULL, 0 };
tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
saved_session_t *p_session, *p_end;
if( ( p_session->i_idlen == key.size )
&& !memcmp( p_session->id, key.data, key.size ) )
{
- gnutls_datum data;
+ gnutls_datum_t data;
data.size = p_session->i_datalen;
* You still have to close the socket yourself.
*/
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;
+ (void)p_server;
if( p_sys->b_handshaked == VLC_TRUE )
gnutls_bye( p_sys->session, GNUTLS_SHUT_WR );
{
tls_session_t *p_session;
tls_server_sys_t *p_server_sys;
- gnutls_session session;
+ gnutls_session_t session;
int i_val;
p_session = vlc_object_create( p_server, sizeof (struct tls_session_t) );
return NULL;
}
- vlc_object_attach( p_session, p_server );
-
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;
- p_session->pf_handshake = gnutls_BeginHandshake;
- p_session->pf_handshake2 = p_server_sys->pf_handshake2;
- p_session->pf_close = gnutls_SessionClose;
+ p_session->pf_set_fd = gnutls_SetFD;
+ p_session->pf_handshake = p_server_sys->pf_handshake;
p_session->p_sys->b_handshaked = VLC_FALSE;
p_session->p_sys->psz_hostname = NULL;
goto error;
}
- if( p_session->pf_handshake2 == gnutls_HandshakeAndValidate )
- gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUIRE );
-
- i_val = config_GetInt (p_server, "gnutls-dh-bits");
- gnutls_dh_set_prime_bits (session, i_val);
+ if (p_session->pf_handshake == gnutls_HandshakeAndValidate)
+ gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
/* Session resumption support */
- i_val = config_GetInt (p_server, "gnutls-cache-expiration");
+ i_val = config_GetInt (p_server, "gnutls-cache-timeout");
gnutls_db_set_cache_expiration (session, i_val);
gnutls_db_set_retrieve_function( session, cb_fetch );
gnutls_db_set_remove_function( session, cb_delete );
msg_Dbg( p_server, " %d trusted CA added (%s)", val, psz_ca_path );
/* enables peer's certificate verification */
- p_sys->pf_handshake2 = gnutls_HandshakeAndValidate;
+ p_sys->pf_handshake = gnutls_HandshakeAndValidate;
return VLC_SUCCESS;
}
p_sys->p_store = p_sys->p_cache;
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_session_prepare = gnutls_ServerSessionPrepare;
+ p_server->pf_open = gnutls_ServerSessionPrepare;
+ p_server->pf_close = gnutls_SessionClose;
/* 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 );
val = gnutls_certificate_set_x509_key_file (p_sys->x509_cred,
psz_local_cert, psz_local_key,
GNUTLS_X509_FMT_PEM );
- LocaleFree (psz_key_path);
+ LocaleFree (psz_local_key);
free (psz_key_path);
- LocaleFree (psz_cert_path);
+ LocaleFree (psz_local_cert);
free (psz_cert_path);
if( val < 0 )
}
/* FIXME:
- * - regenerate these regularly
* - support other ciper suites
*/
- val = gnutls_dh_params_init( &p_sys->dh_params );
- if( val >= 0 )
+ val = gnutls_dh_params_init (&p_sys->dh_params);
+ if (val >= 0)
{
- msg_Dbg( p_server, "computing Diffie Hellman ciphers parameters" );
- val = gnutls_dh_params_generate2 (p_sys->dh_params,
- config_GetInt (obj, "gnutls-dh-bits"));
+ const gnutls_datum_t data = {
+ .data = (unsigned char *)dh_params,
+ .size = sizeof (dh_params) - 1,
+ };
+
+ val = gnutls_dh_params_import_pkcs3 (p_sys->dh_params, &data,
+ GNUTLS_X509_FMT_PEM);
+ if (val == 0)
+ gnutls_certificate_set_dh_params (p_sys->x509_cred,
+ p_sys->dh_params);
}
- if( val < 0 )
+ if (val < 0)
{
- msg_Err( p_server, "cannot initialize DH cipher suites: %s",
- gnutls_strerror( val ) );
- gnutls_certificate_free_credentials( p_sys->x509_cred );
- goto error;
+ msg_Err (p_server, "cannot initialize DHE cipher suites: %s",
+ gnutls_strerror (val));
}
- msg_Dbg( p_server, "ciphers parameters computed" );
-
- gnutls_certificate_set_dh_params( p_sys->x509_cred, p_sys->dh_params);
return VLC_SUCCESS;