1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004 VideoLAN
5 * $Id: httpd.c 8263 2004-07-24 09:06:58Z courmisch $
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 stuff,
28 * - server-side client cert validation,
29 * - client-side server cert validation (?).
33 /*****************************************************************************
35 *****************************************************************************/
43 #include <gnutls/gnutls.h>
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Open ( vlc_object_t * );
52 static void Close( vlc_object_t * );
54 #define DH_BITS_TEXT N_("Diffie-Hellman prime bits")
55 #define DH_BITS_LONGTEXT N_( \
56 "Allows you to modify the Diffie-Hellman prime's number of bits " \
57 "(used for TLS or SSL-based server-side encryption)." )
60 set_description( _("GnuTLS TLS encryption layer") );
61 set_capability( "tls", 1 );
62 set_callbacks( Open, Close );
64 add_integer( "dh-bits", DH_BITS, NULL, DH_BITS_TEXT,
65 DH_BITS_LONGTEXT, VLC_TRUE );
70 typedef struct tls_server_sys_t
72 gnutls_certificate_credentials x509_cred;
73 gnutls_dh_params dh_params;
77 typedef struct tls_session_sys_t
79 gnutls_session session;
83 typedef struct tls_client_sys_t
85 struct tls_session_sys_t session;
86 gnutls_certificate_credentials x509_cred;
90 /*****************************************************************************
92 *****************************************************************************
93 * Sends data through a TLS session.
94 *****************************************************************************/
96 gnutls_Send( void *p_session, const void *buf, int i_length )
99 tls_session_sys_t *p_sys;
101 p_sys = (tls_session_sys_t *)(((tls_session_t *)p_session)->p_sys);
103 val = gnutls_record_send( p_sys->session, buf, i_length );
104 /* TODO: handle fatal error */
105 return val < 0 ? -1 : val;
109 /*****************************************************************************
111 *****************************************************************************
112 * Receives data through a TLS session.
113 *****************************************************************************/
115 gnutls_Recv( void *p_session, void *buf, int i_length )
118 tls_session_sys_t *p_sys;
120 p_sys = (tls_session_sys_t *)(((tls_session_t *)p_session)->p_sys);
122 val = gnutls_record_recv( p_sys->session, buf, i_length );
123 /* TODO: handle fatal error */
124 return val < 0 ? -1 : val;
128 /*****************************************************************************
129 * tls_SessionHandshake:
130 *****************************************************************************
131 * Establishes TLS session with a peer through socket <fd>.
132 * Returns NULL on error (do NOT call tls_SessionClose in case of error or
133 * re-use the session structure).
134 *****************************************************************************/
135 static tls_session_t *
136 gnutls_SessionHandshake( tls_session_t *p_session, int fd )
138 tls_session_sys_t *p_sys;
141 p_sys = (tls_session_sys_t *)(p_session->p_sys);
143 gnutls_transport_set_ptr (p_sys->session, (gnutls_transport_ptr)fd);
146 /* TODO: handle fatal error */
147 val = gnutls_handshake( p_sys->session );
148 while( ( val == GNUTLS_E_AGAIN ) || ( val == GNUTLS_E_INTERRUPTED ) );
152 gnutls_deinit( p_sys->session );
153 msg_Err( p_session->p_tls, "TLS handshake failed : %s",
154 gnutls_strerror( val ) );
164 /*****************************************************************************
166 *****************************************************************************
167 * Terminates TLS session and releases session data.
168 *****************************************************************************/
170 gnutls_SessionClose( tls_session_t *p_session )
172 tls_session_sys_t *p_sys;
174 p_sys = (tls_session_sys_t *)(p_session->p_sys);
176 /* On the client-side, credentials are re-allocated per session */
177 if( p_session->p_server == NULL )
178 gnutls_certificate_free_credentials( ((tls_client_sys_t *)p_sys)
181 gnutls_bye( p_sys->session, GNUTLS_SHUT_WR );
182 gnutls_deinit( p_sys->session );
188 /*****************************************************************************
190 *****************************************************************************
191 * Initializes client-side TLS session data.
192 *****************************************************************************/
193 static tls_session_t *
194 gnutls_ClientCreate( tls_t *p_tls, const char *psz_ca_path )
196 tls_session_t *p_session;
197 tls_client_sys_t *p_sys;
199 const int cert_type_priority[3] =
205 p_sys = (tls_client_sys_t *)malloc( sizeof(struct tls_client_sys_t) );
209 i_val = gnutls_certificate_allocate_credentials( &p_sys->x509_cred );
212 msg_Err( p_tls, "Cannot allocate X509 credentials : %s",
213 gnutls_strerror( i_val ) );
218 if( psz_ca_path != NULL )
220 i_val = gnutls_certificate_set_x509_trust_file( p_sys->x509_cred,
222 GNUTLS_X509_FMT_PEM );
225 msg_Err( p_tls, "Cannot add trusted CA (%s) : %s", psz_ca_path,
226 gnutls_strerror( i_val ) );
227 gnutls_certificate_free_credentials( p_sys->x509_cred );
233 i_val = gnutls_init( &p_sys->session.session, GNUTLS_CLIENT );
236 msg_Err( p_tls, "Cannot initialize TLS session : %s",
237 gnutls_strerror( i_val ) );
238 gnutls_certificate_free_credentials( p_sys->x509_cred );
243 i_val = gnutls_set_default_priority( p_sys->session.session );
246 msg_Err( p_tls, "Cannot set ciphers priorities : %s",
247 gnutls_strerror( i_val ) );
248 gnutls_deinit( p_sys->session.session );
249 gnutls_certificate_free_credentials( p_sys->x509_cred );
254 i_val = gnutls_certificate_type_set_priority( p_sys->session.session,
255 cert_type_priority );
258 msg_Err( p_tls, "Cannot set certificate type priorities : %s",
259 gnutls_strerror( i_val ) );
260 gnutls_deinit( p_sys->session.session );
261 gnutls_certificate_free_credentials( p_sys->x509_cred );
266 i_val = gnutls_credentials_set( p_sys->session.session,
267 GNUTLS_CRD_CERTIFICATE,
271 msg_Err( p_tls, "Cannot set TLS session credentials : %s",
272 gnutls_strerror( i_val ) );
273 gnutls_deinit( p_sys->session.session );
274 gnutls_certificate_free_credentials( p_sys->x509_cred );
279 p_session = malloc( sizeof (struct tls_session_t) );
280 if( p_session == NULL )
282 gnutls_deinit( p_sys->session.session );
283 gnutls_certificate_free_credentials( p_sys->x509_cred );
288 p_session->p_tls = p_tls;
289 p_session->p_server = NULL;
290 p_session->p_sys = p_sys;
291 p_session->sock.p_sys = p_session;
292 p_session->sock.pf_send = gnutls_Send;
293 p_session->sock.pf_recv = gnutls_Recv;
294 p_session->pf_handshake = gnutls_SessionHandshake;
295 p_session->pf_close = gnutls_SessionClose;
301 /*****************************************************************************
302 * tls_ServerSessionPrepare:
303 *****************************************************************************
304 * Initializes server-side TLS session data.
305 *****************************************************************************/
306 static tls_session_t *
307 gnutls_ServerSessionPrepare( tls_server_t *p_server )
309 tls_session_t *p_session;
310 tls_session_sys_t *p_sys;
314 p_sys = (tls_session_sys_t *)malloc( sizeof(struct tls_session_sys_t) );
318 i_val = gnutls_init( &p_sys->session, GNUTLS_SERVER );
321 msg_Err( p_server->p_tls, "Cannot initialize TLS session : %s",
322 gnutls_strerror( i_val ) );
327 i_val = gnutls_set_default_priority( p_sys->session );
330 msg_Err( p_server->p_tls, "Cannot set ciphers priorities : %s",
331 gnutls_strerror( i_val ) );
332 gnutls_deinit( p_sys->session );
337 i_val = gnutls_credentials_set( p_sys->session, GNUTLS_CRD_CERTIFICATE,
338 ((tls_server_sys_t *)(p_server->p_sys))
342 msg_Err( p_server->p_tls, "Cannot set TLS session credentials : %s",
343 gnutls_strerror( i_val ) );
344 gnutls_deinit( p_sys->session );
349 /* TODO: support for client authentication */
350 /*gnutls_certificate_server_set_request( p_session->session,
351 GNUTLS_CERT_REQUEST ); */
353 if( var_Get( p_server->p_tls, "dh-bits", &bits ) != VLC_SUCCESS )
355 var_Create( p_server->p_tls, "dh-bits",
356 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
357 var_Get( p_server->p_tls, "dh-bits", &bits );
360 gnutls_dh_set_prime_bits( p_sys->session, bits.i_int );
362 p_session = malloc( sizeof (struct tls_session_t) );
363 if( p_session == NULL )
365 gnutls_deinit( p_sys->session );
370 p_session->p_tls = p_server->p_tls;
371 p_session->p_server = p_server;
372 p_session->p_sys = p_sys;
373 p_session->sock.p_sys = p_session;
374 p_session->sock.pf_send = gnutls_Send;
375 p_session->sock.pf_recv = gnutls_Recv;
376 p_session->pf_handshake = gnutls_SessionHandshake;
377 p_session->pf_close = gnutls_SessionClose;
383 /*****************************************************************************
385 *****************************************************************************
386 * Releases data allocated with tls_ServerCreate.
387 *****************************************************************************/
389 gnutls_ServerDelete( tls_server_t *p_server )
391 gnutls_certificate_free_credentials(
392 ((tls_server_sys_t *)(p_server->p_sys))
394 free( p_server->p_sys );
399 /*****************************************************************************
401 *****************************************************************************
402 * Adds one or more certificate authorities.
403 * TODO: we are not able to check the client credentials yet, so this function
405 * Returns -1 on error, 0 on success.
406 *****************************************************************************/
408 gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
412 val = gnutls_certificate_set_x509_trust_file( ((tls_server_sys_t *)
416 GNUTLS_X509_FMT_PEM );
419 msg_Err( p_server->p_tls, "Cannot add trusted CA (%s) : %s",
420 psz_ca_path, gnutls_strerror( val ) );
421 gnutls_ServerDelete( p_server );
424 msg_Dbg( p_server->p_tls, " %d trusted CA added (%s)", val,
430 /*****************************************************************************
432 *****************************************************************************
433 * Adds a certificates revocation list to be sent to TLS clients.
434 * Returns -1 on error, 0 on success.
435 *****************************************************************************/
437 gnutls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path )
441 val = gnutls_certificate_set_x509_crl_file( ((tls_server_sys_t *)
442 (p_server->p_sys))->x509_cred,
444 GNUTLS_X509_FMT_PEM );
447 msg_Err( p_server->p_tls, "Cannot add CRL (%s) : %s",
448 psz_crl_path, gnutls_strerror( val ) );
449 gnutls_ServerDelete( p_server );
452 msg_Dbg( p_server->p_tls, "%d CRL added (%s)", val, psz_crl_path );
457 /*****************************************************************************
459 *****************************************************************************
460 * Allocates a whole server's TLS credentials.
461 * Returns NULL on error.
462 *****************************************************************************/
463 static tls_server_t *
464 gnutls_ServerCreate( tls_t *p_this, const char *psz_cert_path,
465 const char *psz_key_path )
467 tls_server_t *p_server;
468 tls_server_sys_t *p_server_sys;
471 msg_Dbg( p_this, "Creating TLS server" );
473 p_server_sys = (tls_server_sys_t *)malloc( sizeof(struct tls_server_sys_t) );
474 if( p_server_sys == NULL )
477 /* Sets server's credentials */
478 val = gnutls_certificate_allocate_credentials( &p_server_sys->x509_cred );
481 msg_Err( p_this, "Cannot allocate X509 credentials : %s",
482 gnutls_strerror( val ) );
483 free( p_server_sys );
487 val = gnutls_certificate_set_x509_key_file( p_server_sys->x509_cred,
488 psz_cert_path, psz_key_path,
489 GNUTLS_X509_FMT_PEM );
492 msg_Err( p_this, "Cannot set certificate chain or private key : %s",
493 gnutls_strerror( val ) );
494 gnutls_certificate_free_credentials( p_server_sys->x509_cred );
495 free( p_server_sys );
499 /* FIXME: regenerate these regularly */
500 val = gnutls_dh_params_init( &p_server_sys->dh_params );
505 if( var_Get( p_this, "dh-bits", &bits ) != VLC_SUCCESS )
507 var_Create( p_this, "dh-bits",
508 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
509 var_Get( p_this, "dh-bits", &bits );
512 msg_Dbg( p_this, "Computing Diffie Hellman ciphers parameters" );
513 val = gnutls_dh_params_generate2( p_server_sys->dh_params,
518 msg_Err( p_this, "Cannot initialize DH cipher suites : %s",
519 gnutls_strerror( val ) );
520 gnutls_certificate_free_credentials( p_server_sys->x509_cred );
521 free( p_server_sys );
524 msg_Dbg( p_this, "Ciphers parameters computed" );
526 gnutls_certificate_set_dh_params( p_server_sys->x509_cred,
527 p_server_sys->dh_params);
529 p_server = (tls_server_t *)malloc( sizeof(struct tls_server_t) );
530 if( p_server == NULL )
532 free( p_server_sys );
536 p_server->p_tls = p_this;
537 p_server->p_sys = p_server_sys;
538 p_server->pf_delete = gnutls_ServerDelete;
539 p_server->pf_add_CA = gnutls_ServerAddCA;
540 p_server->pf_add_CRL = gnutls_ServerAddCRL;
541 p_server->pf_session_prepare = gnutls_ServerSessionPrepare;
547 /*****************************************************************************
548 * gcrypt thread option VLC implementation:
549 *****************************************************************************/
550 vlc_object_t *__p_gcry_data;
552 static int gcry_vlc_mutex_init (void **p_sys)
555 vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc (sizeof (vlc_mutex_t));
560 i_val = vlc_mutex_init( __p_gcry_data, p_lock);
568 static int gcry_vlc_mutex_destroy (void **p_sys)
571 vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
573 i_val = vlc_mutex_destroy (p_lock);
578 static int gcry_vlc_mutex_lock (void **p_sys)
580 return vlc_mutex_lock ((vlc_mutex_t *)*p_sys);
583 static int gcry_vlc_mutex_unlock (void **lock)
585 return vlc_mutex_unlock ((vlc_mutex_t *)*lock);
588 static struct gcry_thread_cbs gcry_threads_vlc =
590 GCRY_THREAD_OPTION_USER,
593 gcry_vlc_mutex_destroy,
595 gcry_vlc_mutex_unlock
599 /*****************************************************************************
600 * Module initialization
601 *****************************************************************************/
603 Open( vlc_object_t *p_this )
605 tls_t *p_tls = (tls_t *)p_this;
607 vlc_value_t lock, count;
609 var_Create( p_this->p_libvlc, "tls_mutex", VLC_VAR_MUTEX );
610 var_Get( p_this->p_libvlc, "tls_mutex", &lock );
611 vlc_mutex_lock( lock.p_address );
613 /* Initialize GnuTLS only once */
614 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
615 var_Get( p_this->p_libvlc, "gnutls_count", &count);
617 if( count.i_int == 0)
619 __p_gcry_data = VLC_OBJECT( p_this->p_vlc );
621 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
622 if( gnutls_global_init( ) )
624 msg_Warn( p_this, "cannot initialize GNUTLS" );
625 vlc_mutex_unlock( lock.p_address );
628 if( gnutls_check_version( "1.0.0" ) == NULL )
630 gnutls_global_deinit( );
631 vlc_mutex_unlock( lock.p_address );
632 msg_Err( p_this, "unsupported GNUTLS version" );
635 msg_Dbg( p_this, "GNUTLS initialized" );
639 var_Set( p_this->p_libvlc, "gnutls_count", count);
640 vlc_mutex_unlock( lock.p_address );
642 p_tls->pf_server_create = gnutls_ServerCreate;
643 p_tls->pf_client_create = gnutls_ClientCreate;
648 /*****************************************************************************
649 * Module deinitialization
650 *****************************************************************************/
652 Close( vlc_object_t *p_this )
654 /*tls_t *p_tls = (tls_t *)p_this;
655 tls_sys_t *p_sys = (tls_sys_t *)(p_this->p_sys);*/
657 vlc_value_t lock, count;
659 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
660 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
661 vlc_mutex_lock( lock.p_address );
663 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
664 var_Get( p_this->p_libvlc, "gnutls_count", &count);
666 var_Set( p_this->p_libvlc, "gnutls_count", count);
668 if( count.i_int == 0 )
670 gnutls_global_deinit( );
671 msg_Dbg( p_this, "GNUTLS deinitialized" );
674 vlc_mutex_unlock( lock.p_address);