gnutls.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:16k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * tls.c
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 VideoLAN
  5.  * $Id: httpd.c 8263 2004-07-24 09:06:58Z courmisch $
  6.  *
  7.  * Authors: Remi Denis-Courmont <courmisch@via.ecp.fr>
  8.  *
  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.
  13.  *
  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.
  18.  *
  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.  *****************************************************************************/
  23. /*
  24.  * TODO:
  25.  * - fix FIXMEs,
  26.  * - client side stuff,
  27.  * - server-side client cert validation,
  28.  * - client-side server cert validation (?).
  29.  */
  30. /*****************************************************************************
  31.  * Preamble
  32.  *****************************************************************************/
  33. #include <stdlib.h>
  34. #include <errno.h>
  35. #include <vlc/vlc.h>
  36. #include "vlc_tls.h"
  37. #include <gcrypt.h>
  38. #include <gnutls/gnutls.h>
  39. #define DH_BITS 1024
  40. /*****************************************************************************
  41.  * Module descriptor
  42.  *****************************************************************************/
  43. static int  Open ( vlc_object_t * );
  44. static void Close( vlc_object_t * );
  45. #define DH_BITS_TEXT N_("Diffie-Hellman prime bits")
  46. #define DH_BITS_LONGTEXT N_( 
  47.     "Allows you to modify the Diffie-Hellman prime's number of bits " 
  48.     "(used for TLS or SSL-based server-side encryption)." )
  49. vlc_module_begin();
  50.     set_description( _("GnuTLS TLS encryption layer") );
  51.     set_capability( "tls", 1 );
  52.     set_callbacks( Open, Close );
  53.     add_integer( "dh-bits", DH_BITS, NULL, DH_BITS_TEXT,
  54.                  DH_BITS_LONGTEXT, VLC_TRUE );
  55. vlc_module_end();
  56. typedef struct tls_server_sys_t
  57. {
  58.     gnutls_certificate_credentials x509_cred;
  59.     gnutls_dh_params dh_params;
  60. } tls_server_sys_t;
  61. /*****************************************************************************
  62.  * tls_Send:
  63.  *****************************************************************************
  64.  * Sends data through a TLS session.
  65.  *****************************************************************************/
  66. static int
  67. gnutls_Send( tls_session_t *p_session, const char *buf, int i_length )
  68. {
  69.     int val;
  70.     val = gnutls_record_send( *(gnutls_session *)(p_session->p_sys),
  71.                               buf, i_length );
  72.     return val < 0 ? -1 : val;
  73. }
  74. /*****************************************************************************
  75.  * tls_Recv:
  76.  *****************************************************************************
  77.  * Receives data through a TLS session
  78.  *****************************************************************************/
  79. static int
  80. gnutls_Recv( tls_session_t *p_session, char *buf, int i_length )
  81. {
  82.     int val;
  83.     val = gnutls_record_recv( *(gnutls_session *)(p_session->p_sys),
  84.                               buf, i_length );
  85.     return val < 0 ? -1 : val;
  86. }
  87. /*****************************************************************************
  88.  * tls_SessionHandshake:
  89.  *****************************************************************************
  90.  * Establishes TLS session with a peer through socket <fd>
  91.  * Returns NULL on error (do NOT call tls_SessionClose in case of error or
  92.  * re-use the session structure).
  93.  *****************************************************************************/
  94. static tls_session_t *
  95. gnutls_SessionHandshake( tls_session_t *p_session, int fd )
  96. {
  97.     int val;
  98.     gnutls_session *p_sys;
  99.     p_sys = (gnutls_session *)(p_session->p_sys);
  100.     gnutls_transport_set_ptr( *p_sys, (gnutls_transport_ptr)fd);
  101.     val = gnutls_handshake( *p_sys );
  102.     if( val < 0 )
  103.     {
  104.         gnutls_deinit( *p_sys );
  105.         msg_Err( p_session->p_tls, "TLS handshake failed : %s",
  106.                  gnutls_strerror( val ) );
  107.         free( p_sys );
  108.         free( p_session );
  109.         return NULL;
  110.     }
  111.     return p_session;
  112. }
  113. /*****************************************************************************
  114.  * tls_ServerCreate:
  115.  *****************************************************************************
  116.  * Terminates a TLS session and releases session data.
  117.  *****************************************************************************/
  118. static void
  119. gnutls_SessionClose( tls_session_t *p_session )
  120. {
  121.     gnutls_session *p_sys;
  122.     p_sys = (gnutls_session *)(p_session->p_sys);
  123.     gnutls_bye( *p_sys, GNUTLS_SHUT_WR );
  124.     gnutls_deinit ( *p_sys );
  125.     free( p_sys );
  126.     free( p_session );
  127. }
  128. /*****************************************************************************
  129.  * tls_ServerSessionPrepare:
  130.  *****************************************************************************
  131.  * Initializes a server-side TLS session data
  132.  *****************************************************************************/
  133. static tls_session_t *
  134. gnutls_ServerSessionPrepare( tls_server_t *p_server )
  135. {
  136.     tls_session_t *p_session;
  137.     gnutls_session *p_sys;
  138.     int val;
  139.     vlc_value_t bits;
  140.     p_sys = (gnutls_session *)malloc( sizeof(gnutls_session) );
  141.     if( p_sys == NULL )
  142.         return NULL;
  143.     val = gnutls_init( p_sys, GNUTLS_SERVER );
  144.     if( val != 0 )
  145.     {
  146.         msg_Err( p_server->p_tls, "Cannot initialize TLS session : %s",
  147.                  gnutls_strerror( val ) );
  148.         free( p_sys );
  149.         return NULL;
  150.     }
  151.    
  152.     val = gnutls_set_default_priority( *p_sys );
  153.     if( val < 0 )
  154.     {
  155.         msg_Err( p_server->p_tls, "Cannot set ciphers priorities : %s",
  156.                  gnutls_strerror( val ) );
  157.         gnutls_deinit( *p_sys );
  158.         free( p_sys );
  159.         return NULL;
  160.     }
  161.     val = gnutls_credentials_set( *p_sys, GNUTLS_CRD_CERTIFICATE,
  162.                                   ((tls_server_sys_t *)(p_server->p_sys))
  163.                                   ->x509_cred );
  164.     if( val < 0 )
  165.     {
  166.         msg_Err( p_server->p_tls, "Cannot set TLS session credentials : %s",
  167.                  gnutls_strerror( val ) );
  168.         gnutls_deinit( *p_sys );
  169.         free( p_sys );
  170.         return NULL;
  171.     }
  172.     /* TODO: support for client authentication */
  173.     /*gnutls_certificate_server_set_request( p_session->session,
  174.                                            GNUTLS_CERT_REQUEST ); */
  175.     if( var_Get( p_server->p_tls, "dh-bits", &bits ) != VLC_SUCCESS )
  176.     {
  177.         var_Create( p_server->p_tls, "dh-bits",
  178.                     VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  179.         var_Get( p_server->p_tls, "dh-bits", &bits );
  180.     }
  181.     gnutls_dh_set_prime_bits( *p_sys, bits.i_int );
  182.     p_session = malloc( sizeof (struct tls_session_t) );
  183.     if( p_session == NULL )
  184.     {
  185.         gnutls_deinit( *p_sys );
  186.         free( p_sys );
  187.         return NULL;
  188.     }
  189.     p_session->p_tls = p_server->p_tls;
  190.     p_session->p_server = p_server;
  191.     p_session->p_sys = p_sys;
  192.     p_session->pf_handshake =gnutls_SessionHandshake;
  193.     p_session->pf_close = gnutls_SessionClose;
  194.     p_session->pf_send = gnutls_Send;
  195.     p_session->pf_recv = gnutls_Recv;
  196.     return p_session;
  197. }
  198. /*****************************************************************************
  199.  * tls_ServerDelete:
  200.  *****************************************************************************
  201.  * Releases data allocated with tls_ServerCreate
  202.  *****************************************************************************/
  203. static void
  204. gnutls_ServerDelete( tls_server_t *p_server )
  205. {
  206.     gnutls_certificate_free_credentials(
  207.                                        ((tls_server_sys_t *)(p_server->p_sys))
  208.                                          ->x509_cred );
  209.     free( p_server->p_sys );
  210.     free( p_server );
  211. }
  212. /*****************************************************************************
  213.  * tls_ServerAddCA:
  214.  *****************************************************************************
  215.  * Adds one or more certificate authorities.
  216.  * TODO: we are not able to check the client credentials yet, so this function
  217.  * is pretty useless.
  218.  * Returns -1 on error, 0 on success.
  219.  *****************************************************************************/
  220. static int
  221. gnutls_ServerAddCA( tls_server_t *p_server, const char *psz_ca_path )
  222. {
  223.     int val;
  224.     val = gnutls_certificate_set_x509_trust_file( ((tls_server_sys_t *)
  225.                                                   (p_server->p_sys))
  226.                                                     ->x509_cred,
  227.                                                   psz_ca_path,
  228.                                                   GNUTLS_X509_FMT_PEM );
  229.     if( val < 0 )
  230.     {
  231.         msg_Err( p_server->p_tls, "Cannot add trusted CA (%s) : %s",
  232.                  psz_ca_path, gnutls_strerror( val ) );
  233.         gnutls_ServerDelete( p_server );
  234.         return VLC_EGENERIC;
  235.     }
  236.     msg_Dbg( p_server->p_tls, " %d trusted CA added (%s)", val,
  237.              psz_ca_path );
  238.     return VLC_SUCCESS;
  239. }
  240. /*****************************************************************************
  241.  * tls_ServerAddCRL:
  242.  *****************************************************************************
  243.  * Adds a certificates revocation list to be sent to TLS clients.
  244.  * Returns -1 on error, 0 on success.
  245.  *****************************************************************************/
  246. static int
  247. gnutls_ServerAddCRL( tls_server_t *p_server, const char *psz_crl_path )
  248. {
  249.     int val;
  250.     val = gnutls_certificate_set_x509_crl_file( ((tls_server_sys_t *)
  251.                                                 (p_server->p_sys))->x509_cred,
  252.                                                 psz_crl_path,
  253.                                                 GNUTLS_X509_FMT_PEM );
  254.     if( val < 0 )
  255.     {
  256.         msg_Err( p_server->p_tls, "Cannot add CRL (%s) : %s",
  257.                  psz_crl_path, gnutls_strerror( val ) );
  258.         gnutls_ServerDelete( p_server );
  259.         return VLC_EGENERIC;
  260.     }
  261.     msg_Dbg( p_server->p_tls, "%d CRL added (%s)", val, psz_crl_path );
  262.     return VLC_SUCCESS;
  263. }
  264.     
  265. /*****************************************************************************
  266.  * tls_ServerCreate:
  267.  *****************************************************************************
  268.  * Allocates a whole server's TLS credentials.
  269.  * Returns NULL on error.
  270.  *****************************************************************************/
  271. static tls_server_t *
  272. gnutls_ServerCreate( tls_t *p_this, const char *psz_cert_path,
  273.                   const char *psz_key_path )
  274. {
  275.     tls_server_t *p_server;
  276.     tls_server_sys_t *p_server_sys;
  277.     int val;
  278.     msg_Dbg( p_this, "Creating TLS server" );
  279.     p_server_sys = (tls_server_sys_t *)malloc( sizeof(struct tls_server_sys_t) );
  280.     if( p_server_sys == NULL )
  281.         return NULL;
  282.     /* Sets server's credentials */
  283.     val = gnutls_certificate_allocate_credentials( &p_server_sys->x509_cred );
  284.     if( val != 0 )
  285.     {
  286.         msg_Err( p_this, "Cannot allocate X509 credentials : %s",
  287.                  gnutls_strerror( val ) );
  288.         free( p_server_sys );
  289.         return NULL;
  290.     }
  291.     val = gnutls_certificate_set_x509_key_file( p_server_sys->x509_cred,
  292.                                                 psz_cert_path, psz_key_path,
  293.                                                 GNUTLS_X509_FMT_PEM );
  294.     if( val < 0 )
  295.     {
  296.         msg_Err( p_this, "Cannot set certificate chain or private key : %s",
  297.                  gnutls_strerror( val ) );
  298.         gnutls_certificate_free_credentials( p_server_sys->x509_cred );
  299.         free( p_server_sys );
  300.         return NULL;
  301.     }
  302.     /* FIXME: regenerate these regularly */
  303.     val = gnutls_dh_params_init( &p_server_sys->dh_params );
  304.     if( val >= 0 )
  305.     {
  306.         vlc_value_t bits;
  307.         if( var_Get( p_this, "dh-bits", &bits ) != VLC_SUCCESS )
  308.         {
  309.             var_Create( p_this, "dh-bits",
  310.                         VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  311.             var_Get( p_this, "dh-bits", &bits );
  312.         }
  313.         msg_Dbg( p_this, "Computing Diffie Hellman ciphers parameters" );
  314.         val = gnutls_dh_params_generate2( p_server_sys->dh_params,
  315.                                           bits.i_int );
  316.     }
  317.     if( val < 0 )
  318.     {
  319.         msg_Err( p_this, "Cannot initialize DH cipher suites : %s",
  320.                  gnutls_strerror( val ) );
  321.         gnutls_certificate_free_credentials( p_server_sys->x509_cred );
  322.         free( p_server_sys );
  323.         return NULL;
  324.     }
  325.     msg_Dbg( p_this, "Ciphers parameters computed" );
  326.     gnutls_certificate_set_dh_params( p_server_sys->x509_cred,
  327.                                       p_server_sys->dh_params);
  328.     p_server = (tls_server_t *)malloc( sizeof(struct tls_server_t) );
  329.     if( p_server == NULL )
  330.     {
  331.         free( p_server_sys );
  332.         return NULL;
  333.     }
  334.     p_server->p_tls = p_this;
  335.     p_server->p_sys = p_server_sys;
  336.     p_server->pf_delete = gnutls_ServerDelete;
  337.     p_server->pf_add_CA = gnutls_ServerAddCA;
  338.     p_server->pf_add_CRL = gnutls_ServerAddCRL;
  339.     p_server->pf_session_prepare = gnutls_ServerSessionPrepare;
  340.     return p_server;
  341. }
  342. /*
  343.  * gcrypt thread option VLC implementation
  344.  */
  345. vlc_object_t *__p_gcry_data;
  346. static int gcry_vlc_mutex_init (void **p_sys)
  347. {
  348.     int i_val;
  349.     vlc_mutex_t *p_lock = (vlc_mutex_t *)malloc (sizeof (vlc_mutex_t));
  350.     if( p_lock == NULL)
  351.         return ENOMEM;
  352.     i_val = vlc_mutex_init( __p_gcry_data, p_lock);
  353.     if (i_val)
  354.         free (p_lock);
  355.     else
  356.         *p_sys = p_lock;
  357.     return i_val;
  358. }
  359. static int gcry_vlc_mutex_destroy (void **p_sys)
  360. {
  361.     int i_val;
  362.     vlc_mutex_t *p_lock = (vlc_mutex_t *)*p_sys;
  363.     i_val = vlc_mutex_destroy (p_lock);
  364.     free (p_lock);
  365.     return i_val;
  366. }
  367. static int gcry_vlc_mutex_lock (void **p_sys)
  368. {
  369.     return vlc_mutex_lock ((vlc_mutex_t *)*p_sys);
  370. }
  371. static int gcry_vlc_mutex_unlock (void **lock)
  372. {
  373.     return vlc_mutex_unlock ((vlc_mutex_t *)*lock);
  374. }
  375. static struct gcry_thread_cbs gcry_threads_vlc =
  376. {
  377.     GCRY_THREAD_OPTION_USER,
  378.     NULL,
  379.     gcry_vlc_mutex_init,
  380.     gcry_vlc_mutex_destroy,
  381.     gcry_vlc_mutex_lock,
  382.     gcry_vlc_mutex_unlock
  383. };
  384. static int
  385. Open( vlc_object_t *p_this )
  386. {
  387.     tls_t *p_tls = (tls_t *)p_this;
  388.     vlc_value_t lock, count;
  389.     var_Create( p_this->p_libvlc, "tls_mutex", VLC_VAR_MUTEX );
  390.     var_Get( p_this->p_libvlc, "tls_mutex", &lock );
  391.     vlc_mutex_lock( lock.p_address );
  392.     /* Initialize GnuTLS only once */
  393.     var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
  394.     var_Get( p_this->p_libvlc, "gnutls_count", &count);
  395.     if( count.i_int == 0)
  396.     {
  397.         __p_gcry_data = VLC_OBJECT( p_this->p_vlc );
  398.         gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_vlc);
  399.         if( gnutls_global_init( ) )
  400.         {
  401.             msg_Warn( p_this, "cannot initialize GNUTLS" );
  402.             vlc_mutex_unlock( lock.p_address );
  403.             return VLC_EGENERIC;
  404.         }
  405.         if( gnutls_check_version( "1.0.0" ) == NULL )
  406.         {
  407.             gnutls_global_deinit( );
  408.             vlc_mutex_unlock( lock.p_address );
  409.             msg_Err( p_this, "unsupported GNUTLS version" );
  410.             return VLC_EGENERIC;
  411.         }
  412.         msg_Dbg( p_this, "GNUTLS initialized" );
  413.     }
  414.     count.i_int++;
  415.     var_Set( p_this->p_libvlc, "gnutls_count", count);
  416.     vlc_mutex_unlock( lock.p_address );
  417.     p_tls->pf_server_create = gnutls_ServerCreate;
  418.     return VLC_SUCCESS;
  419. }
  420. static void
  421. Close( vlc_object_t *p_this )
  422. {
  423.     /*tls_t *p_tls = (tls_t *)p_this;
  424.     tls_sys_t *p_sys = (tls_sys_t *)(p_this->p_sys);*/
  425.     vlc_value_t lock, count;
  426.     var_Create( p_this->p_libvlc, "gnutls_mutex", VLC_VAR_MUTEX );
  427.     var_Get( p_this->p_libvlc, "gnutls_mutex", &lock );
  428.     vlc_mutex_lock( lock.p_address );
  429.     var_Create( p_this->p_libvlc, "gnutls_count", VLC_VAR_INTEGER );
  430.     var_Get( p_this->p_libvlc, "gnutls_count", &count);
  431.     count.i_int--;
  432.     var_Set( p_this->p_libvlc, "gnutls_count", count);
  433.     if( count.i_int == 0 )
  434.     {
  435.         gnutls_global_deinit( );
  436.         msg_Dbg( p_this, "GNUTLS deinitialized" );
  437.     }
  438.     vlc_mutex_unlock( lock.p_address);
  439. }