1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004-2005 VideoLAN
7 * Authors: Remi Denis-Courmont <courmisch@via.ecp.fr>
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_free_credentials( ((tls_client_sys_t *)
317 (p_session->p_sys))->x509_cred );
318 gnutls_SessionClose( p_session );
322 /*****************************************************************************
324 *****************************************************************************
325 * Initializes client-side TLS session data.
326 *****************************************************************************/
327 static tls_session_t *
328 gnutls_ClientCreate( tls_t *p_tls )
330 tls_session_t *p_session = NULL;
331 tls_client_sys_t *p_sys = NULL;
333 const int cert_type_priority[3] =
339 p_sys = (tls_client_sys_t *)malloc( sizeof(struct tls_client_sys_t) );
343 p_session = (struct tls_session_t *)vlc_object_create ( p_tls, sizeof(struct tls_session_t) );
344 if( p_session == NULL )
350 p_session->p_sys = p_sys;
351 p_session->sock.p_sys = p_session;
352 p_session->sock.pf_send = gnutls_Send;
353 p_session->sock.pf_recv = gnutls_Recv;
354 p_session->pf_handshake = gnutls_BeginHandshake;
355 p_session->pf_handshake2 = gnutls_ContinueHandshake;
356 p_session->pf_close = gnutls_ClientDelete;
358 p_sys->session.b_handshaked = VLC_FALSE;
360 vlc_object_attach( p_session, p_tls );
362 i_val = gnutls_certificate_allocate_credentials( &p_sys->x509_cred );
365 msg_Err( p_tls, "Cannot allocate X509 credentials : %s",
366 gnutls_strerror( i_val ) );
371 if( psz_ca_path != NULL )
373 i_val = gnutls_certificate_set_x509_trust_file( p_sys->x509_cred,
375 GNUTLS_X509_FMT_PEM );
378 msg_Err( p_tls, "Cannot add trusted CA (%s) : %s", psz_ca_path,
379 gnutls_strerror( i_val ) );
380 gnutls_certificate_free_credentials( p_sys->x509_cred );
385 i_val = gnutls_init( &p_sys->session.session, GNUTLS_CLIENT );
388 msg_Err( p_tls, "Cannot initialize TLS session : %s",
389 gnutls_strerror( i_val ) );
390 gnutls_certificate_free_credentials( p_sys->x509_cred );
394 i_val = gnutls_set_default_priority( p_sys->session.session );
397 msg_Err( p_tls, "Cannot set ciphers priorities : %s",
398 gnutls_strerror( i_val ) );
399 gnutls_deinit( p_sys->session.session );
400 gnutls_certificate_free_credentials( p_sys->x509_cred );
404 i_val = gnutls_certificate_type_set_priority( p_sys->session.session,
405 cert_type_priority );
408 msg_Err( p_tls, "Cannot set certificate type priorities : %s",
409 gnutls_strerror( i_val ) );
410 gnutls_deinit( p_sys->session.session );
411 gnutls_certificate_free_credentials( p_sys->x509_cred );
415 i_val = gnutls_credentials_set( p_sys->session.session,
416 GNUTLS_CRD_CERTIFICATE,
420 msg_Err( p_tls, "Cannot set TLS session credentials : %s",
421 gnutls_strerror( i_val ) );
422 gnutls_deinit( p_sys->session.session );
423 gnutls_certificate_free_credentials( p_sys->x509_cred );
430 vlc_object_detach( p_session );
431 vlc_object_destroy( p_session );
438 /*****************************************************************************
439 * TLS session resumption callbacks
440 *****************************************************************************/
441 static int cb_store( void *p_server, gnutls_datum key, gnutls_datum data )
443 tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
445 if( ( p_sys->i_cache_size == 0 )
446 || ( key.size > MAX_SESSION_ID )
447 || ( data.size > MAX_SESSION_DATA ) )
450 vlc_mutex_lock( &p_sys->cache_lock );
452 memcpy( p_sys->p_store->id, key.data, key.size);
453 memcpy( p_sys->p_store->data, data.data, data.size );
454 p_sys->p_store->i_idlen = key.size;
455 p_sys->p_store->i_datalen = data.size;
458 if( ( p_sys->p_store - p_sys->p_cache ) == p_sys->i_cache_size )
459 p_sys->p_store = p_sys->p_cache;
461 vlc_mutex_unlock( &p_sys->cache_lock );
467 static const gnutls_datum err_datum = { NULL, 0 };
469 static gnutls_datum cb_fetch( void *p_server, gnutls_datum key )
471 tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
472 saved_session_t *p_session, *p_end;
474 p_session = p_sys->p_cache;
475 p_end = p_session + p_sys->i_cache_size;
477 vlc_mutex_lock( &p_sys->cache_lock );
479 while( p_session < p_end )
481 if( ( p_session->i_idlen == key.size )
482 && !memcmp( p_session->id, key.data, key.size ) )
486 data.size = p_session->i_datalen;
488 data.data = gnutls_malloc( data.size );
489 if( data.data == NULL )
491 vlc_mutex_unlock( &p_sys->cache_lock );
495 memcpy( data.data, p_session->data, data.size );
496 vlc_mutex_unlock( &p_sys->cache_lock );
502 vlc_mutex_unlock( &p_sys->cache_lock );
508 static int cb_delete( void *p_server, gnutls_datum key )
510 tls_server_sys_t *p_sys = ((tls_server_t *)p_server)->p_sys;
511 saved_session_t *p_session, *p_end;
513 p_session = p_sys->p_cache;
514 p_end = p_session + p_sys->i_cache_size;
516 vlc_mutex_lock( &p_sys->cache_lock );
518 while( p_session < p_end )
520 if( ( p_session->i_idlen == key.size )
521 && !memcmp( p_session->id, key.data, key.size ) )
523 p_session->i_datalen = p_session->i_idlen = 0;
524 vlc_mutex_unlock( &p_sys->cache_lock );
530 vlc_mutex_unlock( &p_sys->cache_lock );
536 /*****************************************************************************
537 * tls_ServerSessionPrepare:
538 *****************************************************************************
539 * Initializes server-side TLS session data.
540 *****************************************************************************/
541 static tls_session_t *
542 gnutls_ServerSessionPrepare( tls_server_t *p_server )
544 tls_session_t *p_session;
545 gnutls_session session;
548 p_session = vlc_object_create( p_server, sizeof (struct tls_session_t) );
549 if( p_session == NULL )
552 p_session->p_sys = malloc( sizeof(struct tls_session_sys_t) );
553 if( p_session->p_sys == NULL )
555 vlc_object_destroy( p_session );
559 vlc_object_attach( p_session, p_server );
561 p_session->sock.p_sys = p_session;
562 p_session->sock.pf_send = gnutls_Send;
563 p_session->sock.pf_recv = gnutls_Recv;
564 p_session->pf_handshake = gnutls_BeginHandshake;
565 p_session->pf_handshake2 = ((tls_server_sys_t *)
566 (p_server->p_sys))->pf_handshake2;
567 p_session->pf_close = gnutls_SessionClose;
569 ((tls_session_sys_t *)p_session->p_sys)->b_handshaked = VLC_FALSE;
571 i_val = gnutls_init( &session, GNUTLS_SERVER );
574 msg_Err( p_server, "Cannot initialize TLS session : %s",
575 gnutls_strerror( i_val ) );
579 ((tls_session_sys_t *)p_session->p_sys)->session = session;
581 i_val = gnutls_set_default_priority( session );
584 msg_Err( p_server, "Cannot set ciphers priorities : %s",
585 gnutls_strerror( i_val ) );
586 gnutls_deinit( session );
590 i_val = gnutls_credentials_set( session, GNUTLS_CRD_CERTIFICATE,
591 ((tls_server_sys_t *)(p_server->p_sys))
595 msg_Err( p_server, "Cannot set TLS session credentials : %s",
596 gnutls_strerror( i_val ) );
597 gnutls_deinit( session );
601 /* TODO: support for client authentication */
602 /*gnutls_certificate_server_set_request( p_session->session,
603 GNUTLS_CERT_REQUEST ); */
605 gnutls_dh_set_prime_bits( session, get_Int( p_server, "dh-bits" ) );
607 /* Session resumption support */
608 gnutls_db_set_cache_expiration( session, get_Int( p_server,
609 "tls-cache-expiration" ) );
610 gnutls_db_set_retrieve_function( session, cb_fetch );
611 gnutls_db_set_remove_function( session, cb_delete );
612 gnutls_db_set_store_function( session, cb_store );
613 gnutls_db_set_ptr( session, p_server );
618 free( p_session->p_sys );
619 vlc_object_detach( p_session );
620 vlc_object_destroy( p_session );
625 /*****************************************************************************
627 *****************************************************************************
628 * Releases data allocated with tls_ServerCreate.
629 *****************************************************************************/
631 gnutls_ServerDelete( tls_server_t *p_server )
633 tls_server_sys_t *p_sys;
635 p_sys = (tls_server_sys_t *)p_server->p_sys;
637 gnutls_certificate_free_credentials( p_sys->x509_cred );
638 gnutls_dh_params_deinit( p_sys->dh_params );
639 vlc_mutex_destroy( &p_sys->cache_lock );
641 vlc_object_detach( p_server );
642 vlc_object_destroy( p_server );
644 free( p_sys->p_cache );
649 /*****************************************************************************
651 *****************************************************************************
652 * Adds one or more certificate authorities.
653 * Returns -1 on error, 0 on success.
654 *****************************************************************************/
656 gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
659 tls_server_sys_t *p_sys;
661 p_sys = (tls_server_sys_t *)(p_server->p_sys);
663 val = gnutls_certificate_set_x509_trust_file( p_sys->x509_cred,
665 GNUTLS_X509_FMT_PEM );
668 msg_Err( p_server, "Cannot add trusted CA (%s) : %s", psz_ca_path,
669 gnutls_strerror( val ) );
672 msg_Dbg( p_server, " %d trusted CA added (%s)", val, psz_ca_path );
674 /* enables peer's certificate verification */
675 p_sys->pf_handshake2 = gnutls_HandshakeAndValidate;
681 /*****************************************************************************
683 *****************************************************************************
684 * Adds a certificates revocation list to be sent to TLS clients.
685 * Returns -1 on error, 0 on success.
686 *****************************************************************************/
688 gnutls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path )
692 val = gnutls_certificate_set_x509_crl_file( ((tls_server_sys_t *)
693 (p_server->p_sys))->x509_cred,
695 GNUTLS_X509_FMT_PEM );
698 msg_Err( p_server, "Cannot add CRL (%s) : %s", psz_crl_path,
699 gnutls_strerror( val ) );
702 msg_Dbg( p_server, "%d CRL added (%s)", val, psz_crl_path );
707 /*****************************************************************************
709 *****************************************************************************
710 * Allocates a whole server's TLS credentials.
711 * Returns NULL on error.
712 *****************************************************************************/
713 static tls_server_t *
714 gnutls_ServerCreate( tls_t *p_tls, const char *psz_cert_path,
715 const char *psz_key_path )
717 tls_server_t *p_server;
718 tls_server_sys_t *p_sys;
721 msg_Dbg( p_tls, "Creating TLS server" );
723 p_sys = (tls_server_sys_t *)malloc( sizeof(struct tls_server_sys_t) );
727 p_sys->i_cache_size = get_Int( p_tls, "tls-cache-size" );
728 p_sys->p_cache = (struct saved_session_t *)calloc( p_sys->i_cache_size,
729 sizeof( struct saved_session_t ) );
730 if( p_sys->p_cache == NULL )
735 p_sys->p_store = p_sys->p_cache;
737 p_server = vlc_object_create( p_tls, sizeof(struct tls_server_t) );
738 if( p_server == NULL )
740 free( p_sys->p_cache );
745 vlc_object_attach( p_server, p_tls );
747 p_server->p_sys = p_sys;
748 p_server->pf_delete = gnutls_ServerDelete;
749 p_server->pf_add_CA = gnutls_ServerAddCA;
750 p_server->pf_add_CRL = gnutls_ServerAddCRL;
751 p_server->pf_session_prepare = gnutls_ServerSessionPrepare;
753 /* No certificate validation by default */
754 p_sys->pf_handshake2 = gnutls_ContinueHandshake;
756 /* FIXME: check for errors */
757 vlc_mutex_init( p_server, &p_sys->cache_lock );
759 /* Sets server's credentials */
760 val = gnutls_certificate_allocate_credentials( &p_sys->x509_cred );
763 msg_Err( p_server, "Cannot allocate X509 credentials : %s",
764 gnutls_strerror( val ) );
768 val = gnutls_certificate_set_x509_key_file( p_sys->x509_cred,
769 psz_cert_path, psz_key_path,
770 GNUTLS_X509_FMT_PEM );
773 msg_Err( p_server, "Cannot set certificate chain or private key : %s",
774 gnutls_strerror( val ) );
775 gnutls_certificate_free_credentials( p_sys->x509_cred );
780 * - regenerate these regularly
781 * - support other ciper suites
783 val = gnutls_dh_params_init( &p_sys->dh_params );
786 msg_Dbg( p_server, "Computing Diffie Hellman ciphers parameters" );
787 val = gnutls_dh_params_generate2( p_sys->dh_params,
788 get_Int( p_tls, "dh-bits" ) );
792 msg_Err( p_server, "Cannot initialize DH cipher suites : %s",
793 gnutls_strerror( val ) );
794 gnutls_certificate_free_credentials( p_sys->x509_cred );
797 msg_Dbg( p_server, "Ciphers parameters computed" );
799 gnutls_certificate_set_dh_params( p_sys->x509_cred, p_sys->dh_params);
804 vlc_mutex_destroy( &p_sys->cache_lock );
805 vlc_object_detach( p_server );
806 vlc_object_destroy( p_server );
812 /*****************************************************************************
813 * gcrypt thread option VLC implementation:
814 *****************************************************************************/
815 vlc_object_t *__p_gcry_data;
817 static int gcry_vlc_mutex_init( void **p_sys )
820 vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc( sizeof( vlc_mutex_t ) );
825 i_val = vlc_mutex_init( __p_gcry_data, p_lock );
833 static int gcry_vlc_mutex_destroy( void **p_sys )
836 vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
838 i_val = vlc_mutex_destroy( p_lock );
843 static int gcry_vlc_mutex_lock( void **p_sys )
845 return vlc_mutex_lock( (vlc_mutex_t *)*p_sys );
848 static int gcry_vlc_mutex_unlock( void **lock )
850 return vlc_mutex_unlock( (vlc_mutex_t *)*lock );
853 static struct gcry_thread_cbs gcry_threads_vlc =
855 GCRY_THREAD_OPTION_USER,
858 gcry_vlc_mutex_destroy,
860 gcry_vlc_mutex_unlock
864 /*****************************************************************************
865 * Module initialization
866 *****************************************************************************/
868 Open( vlc_object_t *p_this )
870 tls_t *p_tls = (tls_t *)p_this;
872 vlc_value_t lock, count;
874 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
875 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
876 vlc_mutex_lock( lock.p_address );
878 /* Initialize GnuTLS only once */
879 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
880 var_Get( p_this->p_libvlc, "gnutls_count", &count);
882 if( count.i_int == 0)
884 const char *psz_version;
886 __p_gcry_data = VLC_OBJECT( p_this->p_vlc );
888 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
889 if( gnutls_global_init( ) )
891 msg_Warn( p_this, "cannot initialize GnuTLS" );
892 vlc_mutex_unlock( lock.p_address );
896 * FIXME: in fact, we currently depends on 1.0.17, but it breaks on
897 * Debian which as a patched 1.0.16 (which we can use).
899 psz_version = gnutls_check_version( "1.0.16" );
900 if( psz_version == NULL )
902 gnutls_global_deinit( );
903 vlc_mutex_unlock( lock.p_address );
904 msg_Err( p_this, "unsupported GnuTLS version" );
907 msg_Dbg( p_this, "GnuTLS v%s initialized", psz_version );
911 var_Set( p_this->p_libvlc, "gnutls_count", count);
912 vlc_mutex_unlock( lock.p_address );
914 p_tls->pf_server_create = gnutls_ServerCreate;
915 p_tls->pf_client_create = gnutls_ClientCreate;
920 /*****************************************************************************
921 * Module deinitialization
922 *****************************************************************************/
924 Close( vlc_object_t *p_this )
926 /*tls_t *p_tls = (tls_t *)p_this;
927 tls_sys_t *p_sys = (tls_sys_t *)(p_this->p_sys);*/
929 vlc_value_t lock, count;
931 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
932 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
933 vlc_mutex_lock( lock.p_address );
935 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
936 var_Get( p_this->p_libvlc, "gnutls_count", &count);
938 var_Set( p_this->p_libvlc, "gnutls_count", count);
940 if( count.i_int == 0 )
942 gnutls_global_deinit( );
943 msg_Dbg( p_this, "GnuTLS deinitialized" );
946 vlc_mutex_unlock( lock.p_address );