1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004-2005 VideoLAN
7 * Authors: Remi Denis-Courmont <rem # videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
27 * - client-side server cert validation (?).
31 /*****************************************************************************
33 *****************************************************************************/
41 #include <gnutls/gnutls.h>
44 #define CACHE_EXPIRATION 3600
47 /*****************************************************************************
49 *****************************************************************************/
50 static int Open ( vlc_object_t * );
51 static void Close( vlc_object_t * );
53 #define DH_BITS_TEXT N_("Diffie-Hellman prime bits")
54 #define DH_BITS_LONGTEXT N_( \
55 "Allows you to modify the Diffie-Hellman prime's number of bits " \
56 "(used for TLS or SSL-based server-side encryption)." )
58 #define CACHE_EXPIRATION_TEXT N_("Expiration time for resumed TLS sessions")
59 #define CACHE_EXPIRATION_LONGTEXT N_( \
60 "Defines the delay before resumed TLS sessions will be expired " \
63 #define CACHE_SIZE_TEXT N_("Number of resumed TLS sessions")
64 #define CACHE_SIZE_LONGTEXT N_( \
65 "Allows you to modify the maximum number of resumed TLS sessions that " \
66 "the cache will hold." )
68 #define CHECK_CERT_TEXT N_("Check TLS/SSL server certificate validity")
69 #define CHECK_CERT_LONGTEXT N_( \
70 "Ensures that server certificate is valid " \
71 "(ie. signed by an approved Certificate Authority)." )
73 #define CHECK_HOSTNAME_TEXT N_("Check TLS/SSL server hostname in certificate")
74 #define CHECK_HOSTNAME_LONGTEXT N_( \
75 "Ensures that server hostname in certificate match requested host name." )
78 set_shortname( "GnuTLS" );
79 set_description( _("GnuTLS TLS encryption layer") );
80 set_capability( "tls", 1 );
81 set_callbacks( Open, Close );
82 set_category( CAT_ADVANCED );
83 set_subcategory( SUBCAT_ADVANCED_MISC );
86 add_bool( "tls-check-cert", VLC_FALSE, NULL, CHECK_CERT_TEXT,
87 CHECK_CERT_LONGTEXT, VLC_FALSE );
88 add_bool( "tls-check-hostname", VLC_FALSE, NULL, CHECK_HOSTNAME_TEXT,
89 CHECK_HOSTNAME_LONGTEXT, VLC_FALSE );
92 add_integer( "dh-bits", DH_BITS, NULL, DH_BITS_TEXT,
93 DH_BITS_LONGTEXT, VLC_TRUE );
94 add_integer( "tls-cache-expiration", CACHE_EXPIRATION, NULL,
95 CACHE_EXPIRATION_TEXT, CACHE_EXPIRATION_LONGTEXT, VLC_TRUE );
96 add_integer( "tls-cache-size", CACHE_SIZE, NULL, CACHE_SIZE_TEXT,
97 CACHE_SIZE_LONGTEXT, VLC_TRUE );
101 #define MAX_SESSION_ID 32
102 #define MAX_SESSION_DATA 1024
104 typedef struct saved_session_t
106 char id[MAX_SESSION_ID];
107 char data[MAX_SESSION_DATA];
114 typedef struct tls_server_sys_t
116 gnutls_certificate_credentials x509_cred;
117 gnutls_dh_params dh_params;
119 struct saved_session_t *p_cache;
120 struct saved_session_t *p_store;
122 vlc_mutex_t cache_lock;
124 int (*pf_handshake2)( tls_session_t * );
128 typedef struct tls_session_sys_t
130 gnutls_session session;
131 vlc_bool_t b_handshaked;
135 typedef struct tls_client_sys_t
137 struct tls_session_sys_t session;
138 gnutls_certificate_credentials x509_cred;
143 _get_Int (vlc_object_t *p_this, const char *var)
147 if( var_Get( p_this, var, &value ) != VLC_SUCCESS )
149 var_Create( p_this, var, VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
150 var_Get( p_this, var, &value );
156 #define get_Int( a, b ) _get_Int( (vlc_object_t *)(a), (b) )
159 /*****************************************************************************
161 *****************************************************************************
162 * Sends data through a TLS session.
163 *****************************************************************************/
165 gnutls_Send( void *p_session, const void *buf, int i_length )
168 tls_session_sys_t *p_sys;
170 p_sys = (tls_session_sys_t *)(((tls_session_t *)p_session)->p_sys);
172 val = gnutls_record_send( p_sys->session, buf, i_length );
173 /* TODO: handle fatal error */
174 return val < 0 ? -1 : val;
178 /*****************************************************************************
180 *****************************************************************************
181 * Receives data through a TLS session.
182 *****************************************************************************/
184 gnutls_Recv( void *p_session, void *buf, int i_length )
187 tls_session_sys_t *p_sys;
189 p_sys = (tls_session_sys_t *)(((tls_session_t *)p_session)->p_sys);
191 val = gnutls_record_recv( p_sys->session, buf, i_length );
192 /* TODO: handle fatal error */
193 return val < 0 ? -1 : val;
197 /*****************************************************************************
198 * tls_Session(Continue)?Handshake:
199 *****************************************************************************
200 * Establishes TLS session with a peer through socket <fd>.
201 * Returns -1 on error (you need not and must not call tls_SessionClose)
202 * 0 on succesful handshake completion, 1 if more would-be blocking recv is
203 * needed, 2 if more would-be blocking send is required.
204 *****************************************************************************/
206 gnutls_ContinueHandshake( tls_session_t *p_session)
208 tls_session_sys_t *p_sys;
211 p_sys = (tls_session_sys_t *)(p_session->p_sys);
213 /* TODO: handle fatal error */
214 val = gnutls_handshake( p_sys->session );
215 if( ( val == GNUTLS_E_AGAIN ) || ( val == GNUTLS_E_INTERRUPTED ) )
216 return 1 + gnutls_record_get_direction( p_sys->session );
220 msg_Err( p_session, "TLS handshake failed : %s",
221 gnutls_strerror( val ) );
222 p_session->pf_close( p_session );
226 p_sys->b_handshaked = VLC_TRUE;
231 gnutls_HandshakeAndValidate( tls_session_t *p_session )
235 val = gnutls_ContinueHandshake( p_session );
240 val = gnutls_certificate_verify_peers2( ((tls_session_sys_t *)
241 (p_session->p_sys))->session,
246 msg_Err( p_session, "TLS certificate verification failed : %s",
247 gnutls_strerror( val ) );
248 p_session->pf_close( p_session );
254 msg_Warn( p_session, "TLS session : access denied" );
255 if( status & GNUTLS_CERT_INVALID )
256 msg_Dbg( p_session, "certificate could not be verified" );
257 if( status & GNUTLS_CERT_REVOKED )
258 msg_Dbg( p_session, "certificate was revoked" );
259 if( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
260 msg_Dbg( p_session, "certificate's signer was not found" );
261 if( status & GNUTLS_CERT_SIGNER_NOT_CA )
262 msg_Dbg( p_session, "certificate's signer is not a CA" );
263 p_session->pf_close( p_session );
267 msg_Dbg( p_session, "TLS certificate verified" );
275 gnutls_BeginHandshake( tls_session_t *p_session, int fd,
276 const char *psz_hostname )
278 tls_session_sys_t *p_sys;
280 p_sys = (tls_session_sys_t *)(p_session->p_sys);
282 gnutls_transport_set_ptr (p_sys->session, (gnutls_transport_ptr)fd);
283 if( psz_hostname != NULL )
284 gnutls_server_name_set( p_sys->session, GNUTLS_NAME_DNS, psz_hostname,
285 strlen( psz_hostname ) );
287 return p_session->pf_handshake2( p_session );
290 /*****************************************************************************
292 *****************************************************************************
293 * Terminates TLS session and releases session data.
294 *****************************************************************************/
296 gnutls_SessionClose( tls_session_t *p_session )
298 tls_session_sys_t *p_sys;
300 p_sys = (tls_session_sys_t *)(p_session->p_sys);
302 if( p_sys->b_handshaked == VLC_TRUE )
303 gnutls_bye( p_sys->session, GNUTLS_SHUT_WR );
304 gnutls_deinit( p_sys->session );
306 vlc_object_detach( p_session );
307 vlc_object_destroy( p_session );
313 gnutls_ClientDelete( tls_session_t *p_session )
315 /* On the client-side, credentials are re-allocated per session */
316 gnutls_certificate_credentials x509_cred =
317 ((tls_client_sys_t *)(p_session->p_sys))->x509_cred;
319 gnutls_SessionClose( p_session );
321 /* credentials must be free'd *after* gnutls_deinit() */
322 gnutls_certificate_free_credentials( x509_cred );
326 /*****************************************************************************
328 *****************************************************************************
329 * Initializes client-side TLS session data.
330 *****************************************************************************/
331 static tls_session_t *
332 gnutls_ClientCreate( tls_t *p_tls )
334 tls_session_t *p_session = NULL;
335 tls_client_sys_t *p_sys = NULL;
337 const int cert_type_priority[3] =
343 p_sys = (tls_client_sys_t *)malloc( sizeof(struct tls_client_sys_t) );
347 p_session = (struct tls_session_t *)vlc_object_create ( p_tls, sizeof(struct tls_session_t) );
348 if( p_session == NULL )
354 p_session->p_sys = p_sys;
355 p_session->sock.p_sys = p_session;
356 p_session->sock.pf_send = gnutls_Send;
357 p_session->sock.pf_recv = gnutls_Recv;
358 p_session->pf_handshake = gnutls_BeginHandshake;
359 p_session->pf_handshake2 = gnutls_ContinueHandshake;
360 p_session->pf_close = gnutls_ClientDelete;
362 p_sys->session.b_handshaked = VLC_FALSE;
364 vlc_object_attach( p_session, p_tls );
366 i_val = gnutls_certificate_allocate_credentials( &p_sys->x509_cred );
369 msg_Err( p_tls, "Cannot allocate X509 credentials : %s",
370 gnutls_strerror( i_val ) );
375 if( psz_ca_path != NULL )
377 i_val = gnutls_certificate_set_x509_trust_file( p_sys->x509_cred,
379 GNUTLS_X509_FMT_PEM );
382 msg_Err( p_tls, "Cannot add trusted CA (%s) : %s", psz_ca_path,
383 gnutls_strerror( i_val ) );
384 gnutls_certificate_free_credentials( p_sys->x509_cred );
389 i_val = gnutls_init( &p_sys->session.session, GNUTLS_CLIENT );
392 msg_Err( p_tls, "Cannot initialize TLS session : %s",
393 gnutls_strerror( i_val ) );
394 gnutls_certificate_free_credentials( p_sys->x509_cred );
398 i_val = gnutls_set_default_priority( p_sys->session.session );
401 msg_Err( p_tls, "Cannot set ciphers priorities : %s",
402 gnutls_strerror( i_val ) );
403 gnutls_deinit( p_sys->session.session );
404 gnutls_certificate_free_credentials( p_sys->x509_cred );
408 i_val = gnutls_certificate_type_set_priority( p_sys->session.session,
409 cert_type_priority );
412 msg_Err( p_tls, "Cannot set certificate type priorities : %s",
413 gnutls_strerror( i_val ) );
414 gnutls_deinit( p_sys->session.session );
415 gnutls_certificate_free_credentials( p_sys->x509_cred );
419 i_val = gnutls_credentials_set( p_sys->session.session,
420 GNUTLS_CRD_CERTIFICATE,
424 msg_Err( p_tls, "Cannot set TLS session credentials : %s",
425 gnutls_strerror( i_val ) );
426 gnutls_deinit( p_sys->session.session );
427 gnutls_certificate_free_credentials( p_sys->x509_cred );
434 vlc_object_detach( p_session );
435 vlc_object_destroy( p_session );
442 /*****************************************************************************
443 * TLS session resumption callbacks
444 *****************************************************************************/
445 static int cb_store( void *p_server, gnutls_datum key, gnutls_datum data )
447 tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
449 if( ( p_sys->i_cache_size == 0 )
450 || ( key.size > MAX_SESSION_ID )
451 || ( data.size > MAX_SESSION_DATA ) )
454 vlc_mutex_lock( &p_sys->cache_lock );
456 memcpy( p_sys->p_store->id, key.data, key.size);
457 memcpy( p_sys->p_store->data, data.data, data.size );
458 p_sys->p_store->i_idlen = key.size;
459 p_sys->p_store->i_datalen = data.size;
462 if( ( p_sys->p_store - p_sys->p_cache ) == p_sys->i_cache_size )
463 p_sys->p_store = p_sys->p_cache;
465 vlc_mutex_unlock( &p_sys->cache_lock );
471 static const gnutls_datum err_datum = { NULL, 0 };
473 static gnutls_datum cb_fetch( void *p_server, gnutls_datum key )
475 tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
476 saved_session_t *p_session, *p_end;
478 p_session = p_sys->p_cache;
479 p_end = p_session + p_sys->i_cache_size;
481 vlc_mutex_lock( &p_sys->cache_lock );
483 while( p_session < p_end )
485 if( ( p_session->i_idlen == key.size )
486 && !memcmp( p_session->id, key.data, key.size ) )
490 data.size = p_session->i_datalen;
492 data.data = gnutls_malloc( data.size );
493 if( data.data == NULL )
495 vlc_mutex_unlock( &p_sys->cache_lock );
499 memcpy( data.data, p_session->data, data.size );
500 vlc_mutex_unlock( &p_sys->cache_lock );
506 vlc_mutex_unlock( &p_sys->cache_lock );
512 static int cb_delete( void *p_server, gnutls_datum key )
514 tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
515 saved_session_t *p_session, *p_end;
517 p_session = p_sys->p_cache;
518 p_end = p_session + p_sys->i_cache_size;
520 vlc_mutex_lock( &p_sys->cache_lock );
522 while( p_session < p_end )
524 if( ( p_session->i_idlen == key.size )
525 && !memcmp( p_session->id, key.data, key.size ) )
527 p_session->i_datalen = p_session->i_idlen = 0;
528 vlc_mutex_unlock( &p_sys->cache_lock );
534 vlc_mutex_unlock( &p_sys->cache_lock );
540 /*****************************************************************************
541 * tls_ServerSessionPrepare:
542 *****************************************************************************
543 * Initializes server-side TLS session data.
544 *****************************************************************************/
545 static tls_session_t *
546 gnutls_ServerSessionPrepare( tls_server_t *p_server )
548 tls_session_t *p_session;
549 tls_server_sys_t *p_server_sys;
550 gnutls_session session;
553 p_session = vlc_object_create( p_server, sizeof (struct tls_session_t) );
554 if( p_session == NULL )
557 p_session->p_sys = malloc( sizeof(struct tls_session_sys_t) );
558 if( p_session->p_sys == NULL )
560 vlc_object_destroy( p_session );
564 vlc_object_attach( p_session, p_server );
566 p_server_sys = (tls_server_sys_t *)p_server->p_sys;
567 p_session->sock.p_sys = p_session;
568 p_session->sock.pf_send = gnutls_Send;
569 p_session->sock.pf_recv = gnutls_Recv;
570 p_session->pf_handshake = gnutls_BeginHandshake;
571 p_session->pf_handshake2 = p_server_sys->pf_handshake2;
572 p_session->pf_close = gnutls_SessionClose;
574 ((tls_session_sys_t *)p_session->p_sys)->b_handshaked = VLC_FALSE;
576 i_val = gnutls_init( &session, GNUTLS_SERVER );
579 msg_Err( p_server, "Cannot initialize TLS session : %s",
580 gnutls_strerror( i_val ) );
584 ((tls_session_sys_t *)p_session->p_sys)->session = session;
586 i_val = gnutls_set_default_priority( session );
589 msg_Err( p_server, "Cannot set ciphers priorities : %s",
590 gnutls_strerror( i_val ) );
591 gnutls_deinit( session );
595 i_val = gnutls_credentials_set( session, GNUTLS_CRD_CERTIFICATE,
596 p_server_sys->x509_cred );
599 msg_Err( p_server, "Cannot set TLS session credentials : %s",
600 gnutls_strerror( i_val ) );
601 gnutls_deinit( session );
605 if( p_session->pf_handshake2 == gnutls_HandshakeAndValidate )
606 gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUIRE );
608 gnutls_dh_set_prime_bits( session, get_Int( p_server, "dh-bits" ) );
610 /* Session resumption support */
611 gnutls_db_set_cache_expiration( session, get_Int( p_server,
612 "tls-cache-expiration" ) );
613 gnutls_db_set_retrieve_function( session, cb_fetch );
614 gnutls_db_set_remove_function( session, cb_delete );
615 gnutls_db_set_store_function( session, cb_store );
616 gnutls_db_set_ptr( session, p_server );
621 free( p_session->p_sys );
622 vlc_object_detach( p_session );
623 vlc_object_destroy( p_session );
628 /*****************************************************************************
630 *****************************************************************************
631 * Releases data allocated with tls_ServerCreate.
632 *****************************************************************************/
634 gnutls_ServerDelete( tls_server_t *p_server )
636 tls_server_sys_t *p_sys;
637 p_sys = (tls_server_sys_t *)p_server->p_sys;
639 vlc_mutex_destroy( &p_sys->cache_lock );
640 free( p_sys->p_cache );
642 vlc_object_detach( p_server );
643 vlc_object_destroy( p_server );
645 /* all sessions depending on the server are now deinitialized */
646 gnutls_certificate_free_credentials( p_sys->x509_cred );
647 gnutls_dh_params_deinit( p_sys->dh_params );
652 /*****************************************************************************
654 *****************************************************************************
655 * Adds one or more certificate authorities.
656 * Returns -1 on error, 0 on success.
657 *****************************************************************************/
659 gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
662 tls_server_sys_t *p_sys;
664 p_sys = (tls_server_sys_t *)(p_server->p_sys);
666 val = gnutls_certificate_set_x509_trust_file( p_sys->x509_cred,
668 GNUTLS_X509_FMT_PEM );
671 msg_Err( p_server, "Cannot add trusted CA (%s) : %s", psz_ca_path,
672 gnutls_strerror( val ) );
675 msg_Dbg( p_server, " %d trusted CA added (%s)", val, psz_ca_path );
677 /* enables peer's certificate verification */
678 p_sys->pf_handshake2 = gnutls_HandshakeAndValidate;
684 /*****************************************************************************
686 *****************************************************************************
687 * Adds a certificates revocation list to be sent to TLS clients.
688 * Returns -1 on error, 0 on success.
689 *****************************************************************************/
691 gnutls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path )
695 val = gnutls_certificate_set_x509_crl_file( ((tls_server_sys_t *)
696 (p_server->p_sys))->x509_cred,
698 GNUTLS_X509_FMT_PEM );
701 msg_Err( p_server, "Cannot add CRL (%s) : %s", psz_crl_path,
702 gnutls_strerror( val ) );
705 msg_Dbg( p_server, "%d CRL added (%s)", val, psz_crl_path );
710 /*****************************************************************************
712 *****************************************************************************
713 * Allocates a whole server's TLS credentials.
714 * Returns NULL on error.
715 *****************************************************************************/
716 static tls_server_t *
717 gnutls_ServerCreate( tls_t *p_tls, const char *psz_cert_path,
718 const char *psz_key_path )
720 tls_server_t *p_server;
721 tls_server_sys_t *p_sys;
724 msg_Dbg( p_tls, "Creating TLS server" );
726 p_sys = (tls_server_sys_t *)malloc( sizeof(struct tls_server_sys_t) );
730 p_sys->i_cache_size = get_Int( p_tls, "tls-cache-size" );
731 p_sys->p_cache = (struct saved_session_t *)calloc( p_sys->i_cache_size,
732 sizeof( struct saved_session_t ) );
733 if( p_sys->p_cache == NULL )
738 p_sys->p_store = p_sys->p_cache;
740 p_server = vlc_object_create( p_tls, sizeof(struct tls_server_t) );
741 if( p_server == NULL )
743 free( p_sys->p_cache );
748 vlc_object_attach( p_server, p_tls );
750 p_server->p_sys = p_sys;
751 p_server->pf_delete = gnutls_ServerDelete;
752 p_server->pf_add_CA = gnutls_ServerAddCA;
753 p_server->pf_add_CRL = gnutls_ServerAddCRL;
754 p_server->pf_session_prepare = gnutls_ServerSessionPrepare;
756 /* No certificate validation by default */
757 p_sys->pf_handshake2 = gnutls_ContinueHandshake;
759 /* FIXME: check for errors */
760 vlc_mutex_init( p_server, &p_sys->cache_lock );
762 /* Sets server's credentials */
763 val = gnutls_certificate_allocate_credentials( &p_sys->x509_cred );
766 msg_Err( p_server, "Cannot allocate X509 credentials : %s",
767 gnutls_strerror( val ) );
771 val = gnutls_certificate_set_x509_key_file( p_sys->x509_cred,
772 psz_cert_path, psz_key_path,
773 GNUTLS_X509_FMT_PEM );
776 msg_Err( p_server, "Cannot set certificate chain or private key : %s",
777 gnutls_strerror( val ) );
778 gnutls_certificate_free_credentials( p_sys->x509_cred );
783 * - regenerate these regularly
784 * - support other ciper suites
786 val = gnutls_dh_params_init( &p_sys->dh_params );
789 msg_Dbg( p_server, "Computing Diffie Hellman ciphers parameters" );
790 val = gnutls_dh_params_generate2( p_sys->dh_params,
791 get_Int( p_tls, "dh-bits" ) );
795 msg_Err( p_server, "Cannot initialize DH cipher suites : %s",
796 gnutls_strerror( val ) );
797 gnutls_certificate_free_credentials( p_sys->x509_cred );
800 msg_Dbg( p_server, "Ciphers parameters computed" );
802 gnutls_certificate_set_dh_params( p_sys->x509_cred, p_sys->dh_params);
807 vlc_mutex_destroy( &p_sys->cache_lock );
808 vlc_object_detach( p_server );
809 vlc_object_destroy( p_server );
815 /*****************************************************************************
816 * gcrypt thread option VLC implementation:
817 *****************************************************************************/
818 vlc_object_t *__p_gcry_data;
820 static int gcry_vlc_mutex_init( void **p_sys )
823 vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc( sizeof( vlc_mutex_t ) );
828 i_val = vlc_mutex_init( __p_gcry_data, p_lock );
836 static int gcry_vlc_mutex_destroy( void **p_sys )
839 vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
841 i_val = vlc_mutex_destroy( p_lock );
846 static int gcry_vlc_mutex_lock( void **p_sys )
848 return vlc_mutex_lock( (vlc_mutex_t *)*p_sys );
851 static int gcry_vlc_mutex_unlock( void **lock )
853 return vlc_mutex_unlock( (vlc_mutex_t *)*lock );
856 static struct gcry_thread_cbs gcry_threads_vlc =
858 GCRY_THREAD_OPTION_USER,
861 gcry_vlc_mutex_destroy,
863 gcry_vlc_mutex_unlock
867 /*****************************************************************************
868 * Module initialization
869 *****************************************************************************/
871 Open( vlc_object_t *p_this )
873 tls_t *p_tls = (tls_t *)p_this;
875 vlc_value_t lock, count;
877 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
878 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
879 vlc_mutex_lock( lock.p_address );
881 /* Initialize GnuTLS only once */
882 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
883 var_Get( p_this->p_libvlc, "gnutls_count", &count);
885 if( count.i_int == 0)
887 const char *psz_version;
889 __p_gcry_data = VLC_OBJECT( p_this->p_vlc );
891 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
892 if( gnutls_global_init( ) )
894 msg_Warn( p_this, "cannot initialize GnuTLS" );
895 vlc_mutex_unlock( lock.p_address );
899 * FIXME: in fact, we currently depends on 1.0.17, but it breaks on
900 * Debian which as a patched 1.0.16 (which we can use).
902 psz_version = gnutls_check_version( "1.0.16" );
903 if( psz_version == NULL )
905 gnutls_global_deinit( );
906 vlc_mutex_unlock( lock.p_address );
907 msg_Err( p_this, "unsupported GnuTLS version" );
910 msg_Dbg( p_this, "GnuTLS v%s initialized", psz_version );
914 var_Set( p_this->p_libvlc, "gnutls_count", count);
915 vlc_mutex_unlock( lock.p_address );
917 p_tls->pf_server_create = gnutls_ServerCreate;
918 p_tls->pf_client_create = gnutls_ClientCreate;
923 /*****************************************************************************
924 * Module deinitialization
925 *****************************************************************************/
927 Close( vlc_object_t *p_this )
929 /*tls_t *p_tls = (tls_t *)p_this;
930 tls_sys_t *p_sys = (tls_sys_t *)(p_this->p_sys);*/
932 vlc_value_t lock, count;
934 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
935 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
936 vlc_mutex_lock( lock.p_address );
938 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
939 var_Get( p_this->p_libvlc, "gnutls_count", &count);
941 var_Set( p_this->p_libvlc, "gnutls_count", count);
943 if( count.i_int == 0 )
945 gnutls_global_deinit( );
946 msg_Dbg( p_this, "GnuTLS deinitialized" );
949 vlc_mutex_unlock( lock.p_address );