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 /*****************************************************************************
79 *****************************************************************************
80 * Sends data through a TLS session.
81 *****************************************************************************/
83 gnutls_Send( tls_session_t *p_session, const char *buf, int i_length )
87 val = gnutls_record_send( *(gnutls_session *)(p_session->p_sys),
89 return val < 0 ? -1 : val;
93 /*****************************************************************************
95 *****************************************************************************
96 * Receives data through a TLS session
97 *****************************************************************************/
99 gnutls_Recv( tls_session_t *p_session, char *buf, int i_length )
103 val = gnutls_record_recv( *(gnutls_session *)(p_session->p_sys),
105 return val < 0 ? -1 : val;
109 /*****************************************************************************
110 * tls_SessionHandshake:
111 *****************************************************************************
112 * Establishes TLS session with a peer through socket <fd>
113 * Returns NULL on error (do NOT call tls_SessionClose in case of error or
114 * re-use the session structure).
115 *****************************************************************************/
116 static tls_session_t *
117 gnutls_SessionHandshake( tls_session_t *p_session, int fd )
120 gnutls_session *p_sys;
122 p_sys = (gnutls_session *)(p_session->p_sys);
124 gnutls_transport_set_ptr( *p_sys, (gnutls_transport_ptr)fd);
125 val = gnutls_handshake( *p_sys );
128 gnutls_deinit( *p_sys );
129 msg_Err( p_session->p_tls, "TLS handshake failed : %s",
130 gnutls_strerror( val ) );
139 /*****************************************************************************
141 *****************************************************************************
142 * Terminates a TLS session and releases session data.
143 *****************************************************************************/
145 gnutls_SessionClose( tls_session_t *p_session )
147 gnutls_session *p_sys;
149 p_sys = (gnutls_session *)(p_session->p_sys);
151 gnutls_bye( *p_sys, GNUTLS_SHUT_WR );
152 gnutls_deinit ( *p_sys );
158 /*****************************************************************************
159 * tls_ServerSessionPrepare:
160 *****************************************************************************
161 * Initializes a server-side TLS session data
162 *****************************************************************************/
163 static tls_session_t *
164 gnutls_ServerSessionPrepare( tls_server_t *p_server )
166 tls_session_t *p_session;
167 gnutls_session *p_sys;
171 p_sys = (gnutls_session *)malloc( sizeof(gnutls_session) );
175 val = gnutls_init( p_sys, GNUTLS_SERVER );
178 msg_Err( p_server->p_tls, "Cannot initialize TLS session : %s",
179 gnutls_strerror( val ) );
184 val = gnutls_set_default_priority( *p_sys );
187 msg_Err( p_server->p_tls, "Cannot set ciphers priorities : %s",
188 gnutls_strerror( val ) );
189 gnutls_deinit( *p_sys );
194 val = gnutls_credentials_set( *p_sys, GNUTLS_CRD_CERTIFICATE,
195 ((tls_server_sys_t *)(p_server->p_sys))
199 msg_Err( p_server->p_tls, "Cannot set TLS session credentials : %s",
200 gnutls_strerror( val ) );
201 gnutls_deinit( *p_sys );
206 /* TODO: support for client authentication */
207 /*gnutls_certificate_server_set_request( p_session->session,
208 GNUTLS_CERT_REQUEST ); */
210 if( var_Get( p_server->p_tls, "dh-bits", &bits ) != VLC_SUCCESS )
212 var_Create( p_server->p_tls, "dh-bits",
213 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
214 var_Get( p_server->p_tls, "dh-bits", &bits );
217 gnutls_dh_set_prime_bits( *p_sys, bits.i_int );
219 p_session = malloc( sizeof (struct tls_session_t) );
220 if( p_session == NULL )
222 gnutls_deinit( *p_sys );
227 p_session->p_tls = p_server->p_tls;
228 p_session->p_server = p_server;
229 p_session->p_sys = p_sys;
230 p_session->pf_handshake =gnutls_SessionHandshake;
231 p_session->pf_close = gnutls_SessionClose;
232 p_session->pf_send = gnutls_Send;
233 p_session->pf_recv = gnutls_Recv;
239 /*****************************************************************************
241 *****************************************************************************
242 * Releases data allocated with tls_ServerCreate
243 *****************************************************************************/
245 gnutls_ServerDelete( tls_server_t *p_server )
247 gnutls_certificate_free_credentials(
248 ((tls_server_sys_t *)(p_server->p_sys))
250 free( p_server->p_sys );
255 /*****************************************************************************
257 *****************************************************************************
258 * Adds one or more certificate authorities.
259 * TODO: we are not able to check the client credentials yet, so this function
261 * Returns -1 on error, 0 on success.
262 *****************************************************************************/
264 gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
268 val = gnutls_certificate_set_x509_trust_file( ((tls_server_sys_t *)
272 GNUTLS_X509_FMT_PEM );
275 msg_Err( p_server->p_tls, "Cannot add trusted CA (%s) : %s",
276 psz_ca_path, gnutls_strerror( val ) );
277 gnutls_ServerDelete( p_server );
280 msg_Dbg( p_server->p_tls, " %d trusted CA added (%s)", val,
286 /*****************************************************************************
288 *****************************************************************************
289 * Adds a certificates revocation list to be sent to TLS clients.
290 * Returns -1 on error, 0 on success.
291 *****************************************************************************/
293 gnutls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path )
297 val = gnutls_certificate_set_x509_crl_file( ((tls_server_sys_t *)
298 (p_server->p_sys))->x509_cred,
300 GNUTLS_X509_FMT_PEM );
303 msg_Err( p_server->p_tls, "Cannot add CRL (%s) : %s",
304 psz_crl_path, gnutls_strerror( val ) );
305 gnutls_ServerDelete( p_server );
308 msg_Dbg( p_server->p_tls, "%d CRL added (%s)", val, psz_crl_path );
313 /*****************************************************************************
315 *****************************************************************************
316 * Allocates a whole server's TLS credentials.
317 * Returns NULL on error.
318 *****************************************************************************/
319 static tls_server_t *
320 gnutls_ServerCreate( tls_t *p_this, const char *psz_cert_path,
321 const char *psz_key_path )
323 tls_server_t *p_server;
324 tls_server_sys_t *p_server_sys;
327 msg_Dbg( p_this, "Creating TLS server" );
329 p_server_sys = (tls_server_sys_t *)malloc( sizeof(struct tls_server_sys_t) );
330 if( p_server_sys == NULL )
333 /* Sets server's credentials */
334 val = gnutls_certificate_allocate_credentials( &p_server_sys->x509_cred );
337 msg_Err( p_this, "Cannot allocate X509 credentials : %s",
338 gnutls_strerror( val ) );
339 free( p_server_sys );
343 val = gnutls_certificate_set_x509_key_file( p_server_sys->x509_cred,
344 psz_cert_path, psz_key_path,
345 GNUTLS_X509_FMT_PEM );
348 msg_Err( p_this, "Cannot set certificate chain or private key : %s",
349 gnutls_strerror( val ) );
350 gnutls_certificate_free_credentials( p_server_sys->x509_cred );
351 free( p_server_sys );
355 /* FIXME: regenerate these regularly */
356 val = gnutls_dh_params_init( &p_server_sys->dh_params );
361 if( var_Get( p_this, "dh-bits", &bits ) != VLC_SUCCESS )
363 var_Create( p_this, "dh-bits",
364 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
365 var_Get( p_this, "dh-bits", &bits );
368 msg_Dbg( p_this, "Computing Diffie Hellman ciphers parameters" );
369 val = gnutls_dh_params_generate2( p_server_sys->dh_params,
374 msg_Err( p_this, "Cannot initialize DH cipher suites : %s",
375 gnutls_strerror( val ) );
376 gnutls_certificate_free_credentials( p_server_sys->x509_cred );
377 free( p_server_sys );
380 msg_Dbg( p_this, "Ciphers parameters computed" );
382 gnutls_certificate_set_dh_params( p_server_sys->x509_cred,
383 p_server_sys->dh_params);
385 p_server = (tls_server_t *)malloc( sizeof(struct tls_server_t) );
386 if( p_server == NULL )
388 free( p_server_sys );
392 p_server->p_tls = p_this;
393 p_server->p_sys = p_server_sys;
394 p_server->pf_delete = gnutls_ServerDelete;
395 p_server->pf_add_CA = gnutls_ServerAddCA;
396 p_server->pf_add_CRL = gnutls_ServerAddCRL;
397 p_server->pf_session_prepare = gnutls_ServerSessionPrepare;
404 * gcrypt thread option VLC implementation
406 vlc_object_t *__p_gcry_data;
408 static int gcry_vlc_mutex_init (void **p_sys)
411 vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc (sizeof (vlc_mutex_t));
416 i_val = vlc_mutex_init( __p_gcry_data, p_lock);
424 static int gcry_vlc_mutex_destroy (void **p_sys)
427 vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
429 i_val = vlc_mutex_destroy (p_lock);
434 static int gcry_vlc_mutex_lock (void **p_sys)
436 return vlc_mutex_lock ((vlc_mutex_t *)*p_sys);
439 static int gcry_vlc_mutex_unlock (void **lock)
441 return vlc_mutex_unlock ((vlc_mutex_t *)*lock);
444 static struct gcry_thread_cbs gcry_threads_vlc =
446 GCRY_THREAD_OPTION_USER,
449 gcry_vlc_mutex_destroy,
451 gcry_vlc_mutex_unlock
456 Open( vlc_object_t *p_this )
458 tls_t *p_tls = (tls_t *)p_this;
460 vlc_value_t lock, count;
462 var_Create( p_this->p_libvlc, "tls_mutex", VLC_VAR_MUTEX );
463 var_Get( p_this->p_libvlc, "tls_mutex", &lock );
464 vlc_mutex_lock( lock.p_address );
466 /* Initialize GnuTLS only once */
467 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
468 var_Get( p_this->p_libvlc, "gnutls_count", &count);
470 if( count.i_int == 0)
472 __p_gcry_data = VLC_OBJECT( p_this->p_vlc );
474 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
475 if( gnutls_global_init( ) )
477 msg_Warn( p_this, "cannot initialize GNUTLS" );
478 vlc_mutex_unlock( lock.p_address );
481 if( gnutls_check_version( "1.0.0" ) == NULL )
483 gnutls_global_deinit( );
484 vlc_mutex_unlock( lock.p_address );
485 msg_Err( p_this, "unsupported GNUTLS version" );
488 msg_Dbg( p_this, "GNUTLS initialized" );
492 var_Set( p_this->p_libvlc, "gnutls_count", count);
493 vlc_mutex_unlock( lock.p_address );
495 p_tls->pf_server_create = gnutls_ServerCreate;
501 Close( vlc_object_t *p_this )
503 /*tls_t *p_tls = (tls_t *)p_this;
504 tls_sys_t *p_sys = (tls_sys_t *)(p_this->p_sys);*/
506 vlc_value_t lock, count;
508 var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
509 var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
510 vlc_mutex_lock( lock.p_address );
512 var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
513 var_Get( p_this->p_libvlc, "gnutls_count", &count);
515 var_Set( p_this->p_libvlc, "gnutls_count", count);
517 if( count.i_int == 0 )
519 gnutls_global_deinit( );
520 msg_Dbg( p_this, "GNUTLS deinitialized" );
523 vlc_mutex_unlock( lock.p_address);