gnutls_extensions.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation
00003  *
00004  * Author: Nikos Mavrogiannopoulos
00005  *
00006  * This file is part of GNUTLS.
00007  *
00008  * The GNUTLS library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00021  * USA
00022  *
00023  */
00024 
00025 /* Functions that relate to the TLS hello extension parsing.
00026  * Hello extensions are packets appended in the TLS hello packet, and
00027  * allow for extra functionality.
00028  */
00029 
00030 #include "MHD_config.h"
00031 #include "gnutls_int.h"
00032 #include "gnutls_extensions.h"
00033 #include "gnutls_errors.h"
00034 #include "ext_max_record.h"
00035 #include <ext_cert_type.h>
00036 #include <ext_server_name.h>
00037 #include <gnutls_num.h>
00038 
00039 /* Key Exchange Section */
00040 #define GNUTLS_EXTENSION_ENTRY(type, parse_type, ext_func_recv, ext_func_send) \
00041         { #type, type, parse_type, ext_func_recv, ext_func_send }
00042 
00043 
00044 #define MAX_EXT_SIZE 10
00045 const int MHD_gtls_extensions_size = MAX_EXT_SIZE;
00046 
00047 MHD_gtls_extension_entry MHD_gtls_extensions[MAX_EXT_SIZE] = {
00048   GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_MAX_RECORD_SIZE,
00049                           EXTENSION_TLS,
00050                           MHD_gtls_max_record_recv_params,
00051                           MHD_gtls_max_record_send_params),
00052   GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_CERT_TYPE,
00053                           EXTENSION_TLS,
00054                           MHD_gtls_cert_type_recv_params,
00055                           MHD_gtls_cert_type_send_params),
00056   GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SERVER_NAME,
00057                           EXTENSION_APPLICATION,
00058                           MHD_gtls_server_name_recv_params,
00059                           MHD_gtls_server_name_send_params),
00060   {0, 0, 0, 0}
00061 };
00062 
00063 #define GNUTLS_EXTENSION_LOOP2(b) \
00064         MHD_gtls_extension_entry *p; \
00065                 for(p = MHD_gtls_extensions; p->name != NULL; p++) { b ; }
00066 
00067 #define GNUTLS_EXTENSION_LOOP(a) \
00068                         GNUTLS_EXTENSION_LOOP2( if(p->type == type) { a; break; } )
00069 
00070 
00071 /* EXTENSION functions */
00072 
00073 MHD_gtls_ext_recv_func
00074 MHD_gtls_ext_func_recv (uint16_t type, MHD_gtls_ext_parse_type_t parse_type)
00075 {
00076   MHD_gtls_ext_recv_func ret = NULL;
00077   GNUTLS_EXTENSION_LOOP (if
00078                          (parse_type == EXTENSION_ANY
00079                           || p->parse_type == parse_type) ret =
00080                          p->MHD_gnutls_ext_func_recv);
00081   return ret;
00082 
00083 }
00084 
00085 MHD_gtls_ext_send_func
00086 MHD_gtls_ext_func_send (uint16_t type)
00087 {
00088   MHD_gtls_ext_send_func ret = NULL;
00089   GNUTLS_EXTENSION_LOOP (ret = p->MHD_gnutls_ext_func_send);
00090   return ret;
00091 
00092 }
00093 
00094 const char *
00095 MHD_gtls_extension_get_name (uint16_t type)
00096 {
00097   const char *ret = NULL;
00098 
00099   /* avoid prefix */
00100   GNUTLS_EXTENSION_LOOP (ret = p->name + sizeof ("GNUTLS_EXTENSION_") - 1);
00101 
00102   return ret;
00103 }
00104 
00105 /* Checks if the extension we just received is one of the
00106  * requested ones. Otherwise it's a fatal error.
00107  */
00108 static int
00109 MHD__gnutls_extension_list_check (MHD_gtls_session_t session, uint16_t type)
00110 {
00111 #if MHD_DEBUG_TLS
00112   if (session->security_parameters.entity == GNUTLS_CLIENT)
00113     {
00114       int i;
00115       for (i = 0; i < session->internals.extensions_sent_size; i++)
00116         {
00117           if (type == session->internals.extensions_sent[i])
00118             return 0;           /* ok found */
00119         }
00120       return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION;
00121     }
00122 #endif
00123   return 0;
00124 }
00125 
00126 int
00127 MHD_gtls_parse_extensions (MHD_gtls_session_t session,
00128                            MHD_gtls_ext_parse_type_t parse_type,
00129                            const opaque * data, int data_size)
00130 {
00131   int next, ret;
00132   int pos = 0;
00133   uint16_t type;
00134   const opaque *sdata;
00135   MHD_gtls_ext_recv_func ext_recv;
00136   uint16_t size;
00137 
00138 #if MHD_DEBUG_TLS
00139   int i;
00140   if (session->security_parameters.entity == GNUTLS_CLIENT)
00141     for (i = 0; i < session->internals.extensions_sent_size; i++)
00142       {
00143         MHD__gnutls_debug_log ("EXT[%d]: expecting extension '%s'\n",
00144                                session,
00145                                MHD_gtls_extension_get_name
00146                                (session->internals.extensions_sent[i]));
00147       }
00148 #endif
00149 
00150   DECR_LENGTH_RET (data_size, 2, 0);
00151   next = MHD_gtls_read_uint16 (data);
00152   pos += 2;
00153 
00154   DECR_LENGTH_RET (data_size, next, 0);
00155 
00156   do
00157     {
00158       DECR_LENGTH_RET (next, 2, 0);
00159       type = MHD_gtls_read_uint16 (&data[pos]);
00160       pos += 2;
00161 
00162       MHD__gnutls_debug_log ("EXT[%x]: Received extension '%s/%d'\n", session,
00163                              MHD_gtls_extension_get_name (type), type);
00164 
00165       if ((ret = MHD__gnutls_extension_list_check (session, type)) < 0)
00166         {
00167           MHD_gnutls_assert ();
00168           return ret;
00169         }
00170 
00171       DECR_LENGTH_RET (next, 2, 0);
00172       size = MHD_gtls_read_uint16 (&data[pos]);
00173       pos += 2;
00174 
00175       DECR_LENGTH_RET (next, size, 0);
00176       sdata = &data[pos];
00177       pos += size;
00178 
00179       ext_recv = MHD_gtls_ext_func_recv (type, parse_type);
00180       if (ext_recv == NULL)
00181         continue;
00182       if ((ret = ext_recv (session, sdata, size)) < 0)
00183         {
00184           MHD_gnutls_assert ();
00185           return ret;
00186         }
00187 
00188     }
00189   while (next > 2);
00190 
00191   return 0;
00192 
00193 }
00194 
00195 /* Adds the extension we want to send in the extensions list.
00196  * This list is used to check whether the (later) received
00197  * extensions are the ones we requested.
00198  */
00199 static void
00200 MHD__gnutls_extension_list_add (MHD_gtls_session_t session, uint16_t type)
00201 {
00202 #if MHD_DEBUG_TLS
00203   if (session->security_parameters.entity == GNUTLS_CLIENT)
00204     {
00205       if (session->internals.extensions_sent_size < MAX_EXT_TYPES)
00206         {
00207           session->internals.extensions_sent[session->internals.
00208                                              extensions_sent_size] = type;
00209           session->internals.extensions_sent_size++;
00210         }
00211       else
00212         {
00213           MHD__gnutls_debug_log ("extensions: Increase MAX_EXT_TYPES\n");
00214         }
00215     }
00216 #endif
00217 }
00218 
00219 int
00220 MHD_gtls_gen_extensions (MHD_gtls_session_t session, opaque * data,
00221                          size_t data_size)
00222 {
00223   int size;
00224   uint16_t pos = 0;
00225   opaque *sdata;
00226   int sdata_size;
00227   MHD_gtls_ext_send_func ext_send;
00228   MHD_gtls_extension_entry *p;
00229 
00230   if (data_size < 2)
00231     {
00232       MHD_gnutls_assert ();
00233       return GNUTLS_E_INTERNAL_ERROR;
00234     }
00235 
00236   /* allocate enough data for each extension.
00237    */
00238   sdata_size = data_size;
00239   sdata = MHD_gnutls_malloc (sdata_size);
00240   if (sdata == NULL)
00241     {
00242       MHD_gnutls_assert ();
00243       return GNUTLS_E_MEMORY_ERROR;
00244     }
00245 
00246   pos += 2;
00247   for (p = MHD_gtls_extensions; p->name != NULL; p++)
00248     {
00249       ext_send = MHD_gtls_ext_func_send (p->type);
00250       if (ext_send == NULL)
00251         continue;
00252       size = ext_send (session, sdata, sdata_size);
00253       if (size > 0)
00254         {
00255           if (data_size < pos + (size_t) size + 4)
00256             {
00257               MHD_gnutls_assert ();
00258               MHD_gnutls_free (sdata);
00259               return GNUTLS_E_INTERNAL_ERROR;
00260             }
00261 
00262           /* write extension type */
00263           MHD_gtls_write_uint16 (p->type, &data[pos]);
00264           pos += 2;
00265 
00266           /* write size */
00267           MHD_gtls_write_uint16 (size, &data[pos]);
00268           pos += 2;
00269 
00270           memcpy (&data[pos], sdata, size);
00271           pos += size;
00272 
00273           /* add this extension to the extension list
00274            */
00275           MHD__gnutls_extension_list_add (session, p->type);
00276 
00277           MHD__gnutls_debug_log ("EXT[%x]: Sending extension %s\n", session,
00278                                  MHD_gtls_extension_get_name (p->type));
00279         }
00280       else if (size < 0)
00281         {
00282           MHD_gnutls_assert ();
00283           MHD_gnutls_free (sdata);
00284           return size;
00285         }
00286     }
00287 
00288   size = pos;
00289   pos -= 2;                     /* remove the size of the size header! */
00290 
00291   MHD_gtls_write_uint16 (pos, data);
00292 
00293   if (size == 2)
00294     {                           /* empty */
00295       size = 0;
00296     }
00297 
00298   MHD_gnutls_free (sdata);
00299   return size;
00300 
00301 }

Generated on Tue May 19 23:21:08 2009 for GNU libmicrohttpd by  doxygen 1.5.8