From 0dd2458b1fd4b3476ee62d5bf5d66d1a1c4064a0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Denis-Courmont?= Date: Thu, 4 Nov 2004 22:01:48 +0000 Subject: [PATCH] Initial partial SSL/TLS support (to be continued) --- include/vlc_tls.h | 68 ++++++++ src/misc/tls.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 501 insertions(+) create mode 100644 include/vlc_tls.h create mode 100644 src/misc/tls.c diff --git a/include/vlc_tls.h b/include/vlc_tls.h new file mode 100644 index 0000000000..01e56336ae --- /dev/null +++ b/include/vlc_tls.h @@ -0,0 +1,68 @@ +/***************************************************************************** + * tls.c + ***************************************************************************** + * Copyright (C) 2004 VideoLAN + * $Id: httpd.c 8263 2004-07-24 09:06:58Z courmisch $ + * + * Authors: Remi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + + +/***************************************************************************** + * tls_ServerCreate: + ***************************************************************************** + * Allocates a whole server's TLS credentials. + * Returns NULL on error. + *****************************************************************************/ +VLC_EXPORT( tls_server_t *, tls_ServerCreate, ( vlc_object_t *, const char *, const char * ) ); + + +/***************************************************************************** + * tls_ServerAddCA: + ***************************************************************************** + * Adds one or more certificate authorities. + * Returns -1 on error, 0 on success. + *****************************************************************************/ +VLC_EXPORT( int, tls_ServerAddCA, ( tls_server_t *, const char * ) ); + + +/***************************************************************************** + * tls_ServerAddCRL: + ***************************************************************************** + * Adds a certificates revocation list to be sent to TLS clients. + * Returns -1 on error, 0 on success. + *****************************************************************************/ +VLC_EXPORT( int, tls_ServerAddCRL, ( tls_server_t *, const char * ) ); + + +VLC_EXPORT( void, tls_ServerDelete, ( tls_server_t * ) ); + + +tls_session_t * +tls_ServerSessionPrepare( const tls_server_t *p_server ); + +tls_session_t * +tls_SessionHandshake( tls_session_t *p_session, int fd ); + +void +tls_SessionClose( tls_session_t *p_session ); + +int +tls_Send( tls_session_t *p_session, const char *buf, int i_length ); + +int +tls_Recv( tls_session_t *p_session, char *buf, int i_length ); diff --git a/src/misc/tls.c b/src/misc/tls.c new file mode 100644 index 0000000000..48f92387db --- /dev/null +++ b/src/misc/tls.c @@ -0,0 +1,433 @@ +/***************************************************************************** + * tls.c + ***************************************************************************** + * Copyright (C) 2004 VideoLAN + * $Id: httpd.c 8263 2004-07-24 09:06:58Z courmisch $ + * + * Authors: Remi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include +#include +#include + +#include "vlc_tls.h" + + +#define HAVE_GNUTLS 1 +/* + * TODO: + * - libgcrypt thread-safety !!! + * - fix FIXMEs, + * - gnutls version check, + * - client side stuff, + * - server-side client cert validation, + * - client-side server cert validation (?). + */ + +/* FIXME: proper configure check */ +//#define HAVE_GNUTLS 1 + +#ifdef HAVE_GNUTLS +# include + +# define DH_BITS 1024 + + +struct tls_server_t +{ + gnutls_certificate_credentials x509_cred; + gnutls_dh_params dh_params; + vlc_object_t *p_this; +}; + +struct tls_session_t +{ + gnutls_session session; + vlc_object_t *p_this; +}; + +/* FIXME: is this legal in the VLC? */ +unsigned i_servernum = 0; + + +static int +tls_Init( vlc_object_t *p_this ) +{ + vlc_value_t lock; + + var_Create( p_this->p_libvlc, "tls_mutex", VLC_VAR_MUTEX ); + var_Get( p_this->p_libvlc, "tls_mutex", &lock ); + vlc_mutex_lock( lock.p_address ); + + /* Initialize GnuTLS only once */ + /* FIXME: should check version number */ + if( i_servernum == 0) + { + if( gnutls_global_init( ) ) + { + msg_Warn( p_this, "cannot initialize GNUTLS" ); + vlc_mutex_unlock( lock.p_address); + return -1; + } + msg_Dbg( p_this, "GNUTLS initialized" ); + } + + i_servernum++; + vlc_mutex_unlock( lock.p_address ); + + return 0; +} + + +static void +tls_CleanUp( vlc_object_t *p_this ) +{ + vlc_value_t lock; + + var_Create( p_this->p_libvlc, "tls_mutex", VLC_VAR_MUTEX ); + var_Get( p_this->p_libvlc, "tls_mutex", &lock ); + vlc_mutex_lock( lock.p_address ); + + i_servernum--; + if( i_servernum == 0 ) + { + gnutls_global_deinit( ); + msg_Dbg( p_this, "GNUTLS deinitialized" ); + } + + vlc_mutex_unlock( lock.p_address); +} + +#endif + + +/***************************************************************************** + * tls_ServerCreate: + ***************************************************************************** + * Allocates a whole server's TLS credentials. + * Returns NULL on error. + *****************************************************************************/ +tls_server_t * +tls_ServerCreate( vlc_object_t *p_this, const char *psz_cert_path, + const char *psz_key_path ) +{ +#if HAVE_GNUTLS + tls_server_t *p_server; + int val; + + msg_Dbg( p_this, "Creating TLS server" ); + if( tls_Init( p_this ) ) + return NULL; + + p_server = (tls_server_t *)malloc( sizeof(struct tls_server_t) ); + + /* FIXME: do not hard-code PEM file paths */ + /* Sets server's credentials */ + val = gnutls_certificate_allocate_credentials( &p_server->x509_cred ); + if( val != 0 ) + { + msg_Err( p_this, "Cannot allocate X509 credentials : %s", + gnutls_strerror( val ) ); + free( p_server ); + return NULL; + } + + val = gnutls_certificate_set_x509_key_file( p_server->x509_cred, + psz_cert_path, psz_key_path, + GNUTLS_X509_FMT_PEM ); + if( val < 0 ) + { + msg_Err( p_this, "Cannot set certificate chain or private key : %s", + gnutls_strerror( val ) ); + gnutls_certificate_free_credentials( p_server->x509_cred ); + free( p_server ); + return NULL; + } + + /* FIXME: regenerate these regularly */ + val = gnutls_dh_params_init( &p_server->dh_params ); + if( val >= 0 ) + { + msg_Dbg( p_this, "Computing Diffie Hellman ciphers parameters" ); + val = gnutls_dh_params_generate2( p_server->dh_params, DH_BITS ); + } + if( val < 0 ) + { + msg_Err( p_this, "Cannot initialize DH cipher suites : %s", + gnutls_strerror( val ) ); + gnutls_certificate_free_credentials( p_server->x509_cred ); + free( p_server ); + return NULL; + } + msg_Dbg( p_this, "Ciphers parameters computed" ); + + gnutls_certificate_set_dh_params( p_server->x509_cred, + p_server->dh_params); + + p_server->p_this = p_this; + return p_server; +#else + return NULL; +#endif +} + + +/***************************************************************************** + * tls_ServerAddCA: + ***************************************************************************** + * Adds one or more certificate authorities. + * TODO: we are not able to check the client credentials yet, so this function + * is pretty useless. + * Returns -1 on error, 0 on success. + *****************************************************************************/ +int +tls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path ) +{ +#if HAVE_GNUTLS + int val; + + assert( p_server != NULL); + val = gnutls_certificate_set_x509_trust_file( p_server->x509_cred, + psz_ca_path, + GNUTLS_X509_FMT_PEM ); + if( val < 0 ) + { + msg_Err( p_server->p_this, "Cannot add trusted CA (%s) : %s", + psz_ca_path, gnutls_strerror( val ) ); + free( p_server ); + return -1; + } + msg_Dbg( p_server->p_this, " %d trusted CA added (%s)", val, + psz_ca_path ); + return 0; +#else + return -1; +#endif +} + + +/***************************************************************************** + * tls_ServerAddCRL: + ***************************************************************************** + * Adds a certificates revocation list to be sent to TLS clients. + * Returns -1 on error, 0 on success. + *****************************************************************************/ +int +tls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path ) +{ +#if HAVE_GNUTLS + int val; + + val = gnutls_certificate_set_x509_crl_file( p_server->x509_cred, + psz_crl_path, + GNUTLS_X509_FMT_PEM ); + if( val < 0 ) + { + msg_Err( p_server->p_this, "Cannot add CRL (%s) : %s", + psz_crl_path, gnutls_strerror( val ) ); + free( p_server ); + return -1; + } + msg_Dbg( p_server->p_this, "%d CRL added (%s)", val, psz_crl_path ); + return 0; +#else + return -1; +#endif +} + + + +/***************************************************************************** + * tls_ServerDelete: + ***************************************************************************** + * Releases data allocated with tls_ServerCreate + *****************************************************************************/ +void +tls_ServerDelete( tls_server_t *p_server ) +{ + assert( p_server != NULL ); + +#if HAVE_GNUTLS + gnutls_certificate_free_credentials( p_server->x509_cred ); + tls_CleanUp( p_server->p_this ); + free( p_server ); +#endif +} + + +/***************************************************************************** + * tls_ServerSessionPrepare: + ***************************************************************************** + * Initializes a server-side TLS session data + *****************************************************************************/ +tls_session_t * +tls_ServerSessionPrepare( const tls_server_t *p_server ) +{ +#if HAVE_GNUTLS + tls_session_t *p_session; + gnutls_session session; + int val; + + assert( p_server != NULL ); + + val = gnutls_init( &session, GNUTLS_SERVER ); + if( val != 0 ) + { + msg_Err( p_server->p_this, "Cannot initialize TLS session : %s", + gnutls_strerror( val ) ); + return NULL; + } + + val = gnutls_set_default_priority( session ); + if( val < 0 ) + { + msg_Err( p_server->p_this, "Cannot set ciphers priorities : %s", + gnutls_strerror( val ) ); + gnutls_deinit( session ); + return NULL; + } + + val = gnutls_credentials_set( session, GNUTLS_CRD_CERTIFICATE, + p_server->x509_cred ); + if( val < 0 ) + { + msg_Err( p_server->p_this, "Cannot set TLS session credentials : %s", + gnutls_strerror( val ) ); + gnutls_deinit( session ); + return NULL; + } + + /* TODO: support for client authentication */ + /*gnutls_certificate_server_set_request( p_session->session, + GNUTLS_CERT_REQUEST ); */ + + gnutls_dh_set_prime_bits( session, DH_BITS ); + + p_session = malloc( sizeof (struct tls_session_t) ); + p_session->session = session; + p_session->p_this = p_server->p_this; + + return p_session; +#else + return NULL; +#endif +} + + +/***************************************************************************** + * tls_SessionHandshake: + ***************************************************************************** + * Establishes TLS session with a peer through socket + * Returns NULL on error (do NOT call tls_SessionClose in case of error or + * re-use the session structure). + *****************************************************************************/ +tls_session_t * +tls_SessionHandshake( tls_session_t *p_session, int fd ) +{ +#if HAVE_GNUTLS + int val; + + assert( p_session != NULL ); + + gnutls_transport_set_ptr( p_session->session, (gnutls_transport_ptr)fd); + val = gnutls_handshake( p_session->session); + if( val < 0 ) + { + gnutls_deinit( p_session->session ); + msg_Err( p_session->p_this, "TLS handshake failed : %s", + gnutls_strerror( val ) ); + free( p_session ); + return NULL; + } + return p_session; +#else + return NULL; +#endif +} + + +/***************************************************************************** + * tls_ServerCreate: + ***************************************************************************** + * Terminates a TLS session and releases session data. + *****************************************************************************/ +void +tls_SessionClose( tls_session_t *p_session ) +{ + assert( p_session != NULL ); + +#if HAVE_GNUTLS + gnutls_bye( p_session->session, GNUTLS_SHUT_WR ); + gnutls_deinit (p_session->session ); + free( p_session ); +#endif +} + + +/***************************************************************************** + * tls_Send: + ***************************************************************************** + * Sends data through a TLS session. + *****************************************************************************/ +int +tls_Send( tls_session_t *p_session, const char *buf, int i_length ) +{ +#if HAVE_GNUTLS + int val; + + assert( p_session != NULL ); + + val = gnutls_record_send( p_session->session, buf, i_length ); + if( val < 0 ) + { + /*msg_Warn( p_session->p_this, "TLS problem : %s", + gnutls_strerror( val ) );*/ + return -1; + } + return val; +#else + return -1; +#endif +} + + +/***************************************************************************** + * tls_Recv: + ***************************************************************************** + * Receives data through a TLS session + *****************************************************************************/ +int +tls_Recv( tls_session_t *p_session, char *buf, int i_length ) +{ +#if HAVE_GNUTLS + int val; + + assert( p_session != NULL ); + + val = gnutls_record_recv( p_session->session, buf, i_length ); + if( val < 0 ) + { + /*msg_Warn( p_session->p_this, "TLS problem : %s", + gnutls_strerror( val ) );*/ + return -1; + } + return val; +#else + return -1; +#endif +} -- 2.39.2