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_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 gnutls_session session;
552 p_session = vlc_object_create( p_server, sizeof (struct tls_session_t) );
553 if( p_session == NULL )
556 p_session->p_sys = malloc( sizeof(struct tls_session_sys_t) );
557 if( p_session->p_sys == NULL )
559 vlc_object_destroy( p_session );
563 vlc_object_attach( p_session, p_server );
565 p_session->sock.p_sys = p_session;
566 p_session->sock.pf_send = gnutls_Send;
567 p_session->sock.pf_recv = gnutls_Recv;
568 p_session->pf_handshake = gnutls_BeginHandshake;
569 p_session->pf_handshake2 = ((tls_server_sys_t *)
570 (p_server->p_sys))->pf_handshake2;
571 p_session->pf_close = gnutls_SessionClose;
573 ((tls_session_sys_t *)p_session->p_sys)->b_handshaked = VLC_FALSE;
575 i_val = gnutls_init( &session, GNUTLS_SERVER );
578 msg_Err( p_server, "Cannot initialize TLS session : %s",
579 gnutls_strerror( i_val ) );
583 ((tls_session_sys_t *)p_session->p_sys)->session = session;
585 i_val = gnutls_set_default_priority( session );
588 msg_Err( p_server, "Cannot set ciphers priorities : %s",
589 gnutls_strerror( i_val ) );
590 gnutls_deinit( session );
594 i_val = gnutls_credentials_set( session, GNUTLS_CRD_CERTIFICATE,
595 ((tls_server_sys_t *)(p_server->p_sys))
599 msg_Err( p_server, "Cannot set TLS session credentials : %s",
600 gnutls_strerror( i_val ) );
601 gnutls_deinit( session );
605 /* TODO: support for client authentication */
606 /*gnutls_certificate_server_set_request( p_session->session,
607 GNUTLS_CERT_REQUEST ); */
609 gnutls_dh_set_prime_bits( session, get_Int( p_server, "dh-bits" ) );
611 /* Session resumption support */
612 gnutls_db_set_cache_expiration( session, get_Int( p_server,
613 "tls-cache-expiration" ) );
614 gnutls_db_set_retrieve_function( session, cb_fetch );
615 gnutls_db_set_remove_function( session, cb_delete );
616 gnutls_db_set_store_function( session, cb_store );
617 gnutls_db_set_ptr( session, p_server );
622 free( p_session->p_sys );
623 vlc_object_detach( p_session );
624 vlc_object_destroy( p_session );
629 /*****************************************************************************
631 *****************************************************************************
632 * Releases data allocated with tls_ServerCreate.
633 *****************************************************************************/
635 gnutls_ServerDelete( tls_server_t *p_server )
637 tls_server_sys_t *p_sys;
638 p_sys = (tls_server_sys_t *)p_server->p_sys;
640 vlc_mutex_destroy( &p_sys->cache_lock );
641 free( p_sys->p_cache );
643 vlc_object_detach( p_server );
644 vlc_object_destroy( p_server );
646 /* all sessions depending on the server are now deinitialized */
647 gnutls_certificate_free_credentials( p_sys->x509_cred );
648 gnutls_dh_params_deinit( p_sys->dh_params );
653 /*****************************************************************************
655 *****************************************************************************
656 * Adds one or more certificate authorities.
657 * Returns -1 on error, 0 on success.
658 *****************************************************************************/
660 gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
663 tls_server_sys_t *p_sys;
665 p_sys = (tls_server_sys_t *)(p_server->p_sys);
667 val = gnutls_certificate_set_x509_trust_file( p_sys->x509_cred,
669 GNUTLS_X509_FMT_PEM );
672 msg_Err( p_server, "Cannot add trusted CA (%s) : %s", psz_ca_path,
673 gnutls_strerror( val ) );
676 msg_Dbg( p_server, " %d trusted CA added (%s)", val, psz_ca_path );
678 /* enables peer's certificate verification */
679 p_sys->pf_handshake2 = gnutls_HandshakeAndValidate;
685 /*****************************************************************************
687 *****************************************************************************
688 * Adds a certificates revocation list to be sent to TLS clients.
689 * Returns -1 on error, 0 on success.
690 *****************************************************************************/
692 gnutls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path )
696 val = gnutls_certificate_set_x509_crl_file( ((tls_server_sys_t *)
697 (p_server->p_sys))->x509_cred,
699 GNUTLS_X509_FMT_PEM );
702 msg_Err( p_server, "Cannot add CRL (%s) : %s", psz_crl_path,
703 gnutls_strerror( val ) );
706 msg_Dbg( p_server, "%d CRL added (%s)", val, psz_crl_path );
711 /*****************************************************************************
713 *****************************************************************************
714 * Allocates a whole server's TLS credentials.
715 * Returns NULL on error.
716 *****************************************************************************/
717 static tls_server_t *
718 gnutls_ServerCreate( tls_t *p_tls, const char *psz_cert_path,
719 const char *psz_key_path )
721 tls_server_t *p_server;
722 tls_server_sys_t *p_sys;
725 msg_Dbg( p_tls, "Creating TLS server" );
727 p_sys = (tls_server_sys_t *)malloc( sizeof(struct tls_server_sys_t) );
731 p_sys->i_cache_size = get_Int( p_tls, "tls-cache-size" );
732 p_sys->p_cache = (struct saved_session_t *)calloc( p_sys->i_cache_size,
733 sizeof( struct saved_session_t ) );
734 if( p_sys->p_cache == NULL )
739 p_sys->p_store = p_sys->p_cache;
741 p_server = vlc_object_create( p_tls, sizeof(struct tls_server_t) );
742 if( p_server == NULL )
744 free( p_sys->p_cache );
749 vlc_object_attach( p_server, p_tls );
751 p_server->p_sys = p_sys;
752 p_server->pf_delete = gnutls_ServerDelete;
753 p_server->pf_add_CA = gnutls_ServerAddCA;
754 p_server->pf_add_CRL = gnutls_ServerAddCRL;
755 p_server->pf_session_prepare = gnutls_ServerSessionPrepare;
757 /* No certificate validation by default */
758 p_sys->pf_handshake2 = gnutls_ContinueHandshake;
760 /* FIXME: check for errors */
761 vlc_mutex_init( p_server, &p_sys->cache_lock );
763 /* Sets server's credentials */
764 val = gnutls_certificate_allocate_credentials( &p_sys->x509_cred );
767 msg_Err( p_server, "Cannot allocate X509 credentials : %s",
768 gnutls_strerror( val ) );
772 val = gnutls_certificate_set_x509_key_file( p_sys->x509_cred,
773 psz_cert_path, psz_key_path,
774 GNUTLS_X509_FMT_PEM );
777 msg_Err( p_server, "Cannot set certificate chain or private key : %s",
778 gnutls_strerror( val ) );
779 gnutls_certificate_free_credentials( p_sys->x509_cred );
784 * - regenerate these regularly
785 * - support other ciper suites
787 val = gnutls_dh_params_init( &p_sys->dh_params );
790 msg_Dbg( p_server, "Computing Diffie Hellman ciphers parameters" );
791 val = gnutls_dh_params_generate2( p_sys->dh_params,
792 get_Int( p_tls, "dh-bits" ) );
796 msg_Err( p_server, "Cannot initialize DH cipher suites : %s",
797 gnutls_strerror( val ) );
798 gnutls_certificate_free_credentials( p_sys->x509_cred );
801 msg_Dbg( p_server, "Ciphers parameters computed" );
803 gnutls_certificate_set_dh_params( p_sys->x509_cred, p_sys->dh_params);
808 vlc_mutex_destroy( &p_sys->cache_lock );
809 vlc_object_detach( p_server );
810 vlc_object_destroy( p_server );
816 /*****************************************************************************
817 * gcrypt thread option VLC implementation:
818 *****************************************************************************/
819 vlc_object_t *__p_gcry_data;
821 static int gcry_vlc_mutex_init( void **p_sys )
824 vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc( sizeof( vlc_mutex_t ) );
829 i_val = vlc_mutex_init( __p_gcry_data, p_lock );
837 static int gcry_vlc_mutex_destroy( void **p_sys )
840 vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
842 i_val = vlc_mutex_destroy( p_lock );
847 static int gcry_vlc_mutex_lock( void **p_sys )
849 return vlc_mutex_lock( (vlc_mutex_t *)*p_sys );
852 static int gcry_vlc_mutex_unlock( void **lock )
854 return vlc_mutex_unlock( (vlc_mutex_t *)*lock );
857 static struct gcry_thread_cbs gcry_threads_vlc =
859 GCRY_THREAD_OPTION_USER,
862 gcry_vlc_mutex_destroy,
864 gcry_vlc_mutex_unlock
868 /*****************************************************************************
869 * Module initialization
870 *****************************************************************************/
872 Open( vlc_object_t *p_this )
874 tls_t *p_tls = (tls_t *)p_this;
876 vlc_value_t lock, count;
878 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
879 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
880 vlc_mutex_lock( lock.p_address );
882 /* Initialize GnuTLS only once */
883 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
884 var_Get( p_this->p_libvlc, "gnutls_count", &count);
886 if( count.i_int == 0)
888 const char *psz_version;
890 __p_gcry_data = VLC_OBJECT( p_this->p_vlc );
892 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
893 if( gnutls_global_init( ) )
895 msg_Warn( p_this, "cannot initialize GnuTLS" );
896 vlc_mutex_unlock( lock.p_address );
900 * FIXME: in fact, we currently depends on 1.0.17, but it breaks on
901 * Debian which as a patched 1.0.16 (which we can use).
903 psz_version = gnutls_check_version( "1.0.16" );
904 if( psz_version == NULL )
906 gnutls_global_deinit( );
907 vlc_mutex_unlock( lock.p_address );
908 msg_Err( p_this, "unsupported GnuTLS version" );
911 msg_Dbg( p_this, "GnuTLS v%s initialized", psz_version );
915 var_Set( p_this->p_libvlc, "gnutls_count", count);
916 vlc_mutex_unlock( lock.p_address );
918 p_tls->pf_server_create = gnutls_ServerCreate;
919 p_tls->pf_client_create = gnutls_ClientCreate;
924 /*****************************************************************************
925 * Module deinitialization
926 *****************************************************************************/
928 Close( vlc_object_t *p_this )
930 /*tls_t *p_tls = (tls_t *)p_this;
931 tls_sys_t *p_sys = (tls_sys_t *)(p_this->p_sys);*/
933 vlc_value_t lock, count;
935 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
936 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
937 vlc_mutex_lock( lock.p_address );
939 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
940 var_Get( p_this->p_libvlc, "gnutls_count", &count);
942 var_Set( p_this->p_libvlc, "gnutls_count", count);
944 if( count.i_int == 0 )
946 gnutls_global_deinit( );
947 msg_Dbg( p_this, "GnuTLS deinitialized" );
950 vlc_mutex_unlock( lock.p_address );