Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_extensions.c
1 /*
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
3  * Free Software Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos, Simon Josefsson
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 /* Functions that relate to the TLS hello extension parsing.
27  * Hello extensions are packets appended in the TLS hello packet, and
28  * allow for extra functionality.
29  */
30
31 #include "gnutls_int.h"
32 #include "gnutls_extensions.h"
33 #include "gnutls_errors.h"
34 #include "ext_max_record.h"
35 #include <ext_cert_type.h>
36 #include <ext_server_name.h>
37 #include <ext_srp.h>
38 #include <ext_session_ticket.h>
39 #include <ext_safe_renegotiation.h>
40 #include <ext_signature.h>
41 #include <ext_safe_renegotiation.h>
42 #include <gnutls_num.h>
43
44
45 static void _gnutls_ext_unset_resumed_session_data (gnutls_session_t session,
46                                                     uint16_t type);
47
48
49 static size_t extfunc_size = 0;
50 static extension_entry_st *extfunc = NULL;
51
52 static gnutls_ext_parse_type_t
53 _gnutls_ext_parse_type (uint16_t type)
54 {
55   size_t i;
56
57   for (i = 0; i < extfunc_size; i++)
58     {
59       if (extfunc[i].type == type)
60         return extfunc[i].parse_type;
61     }
62
63   return GNUTLS_EXT_NONE;
64 }
65
66 static gnutls_ext_recv_func
67 _gnutls_ext_func_recv (uint16_t type, gnutls_ext_parse_type_t parse_type)
68 {
69   size_t i;
70
71   for (i = 0; i < extfunc_size; i++)
72     if (extfunc[i].type == type)
73       if (parse_type == GNUTLS_EXT_ANY || extfunc[i].parse_type == parse_type)
74         return extfunc[i].recv_func;
75
76   return NULL;
77 }
78
79 static gnutls_ext_deinit_data_func
80 _gnutls_ext_func_deinit (uint16_t type)
81 {
82   size_t i;
83
84   for (i = 0; i < extfunc_size; i++)
85     if (extfunc[i].type == type)
86       return extfunc[i].deinit_func;
87
88   return NULL;
89 }
90
91 static gnutls_ext_unpack_func
92 _gnutls_ext_func_unpack (uint16_t type)
93 {
94   size_t i;
95
96   for (i = 0; i < extfunc_size; i++)
97     if (extfunc[i].type == type)
98       return extfunc[i].unpack_func;
99
100   return NULL;
101 }
102
103
104 static const char *
105 _gnutls_extension_get_name (uint16_t type)
106 {
107   size_t i;
108
109   for (i = 0; i < extfunc_size; i++)
110     if (extfunc[i].type == type)
111       return extfunc[i].name;
112
113   return NULL;
114 }
115
116 /* Checks if the extension we just received is one of the 
117  * requested ones. Otherwise it's a fatal error.
118  */
119 static int
120 _gnutls_extension_list_check (gnutls_session_t session, uint16_t type)
121 {
122   if (session->security_parameters.entity == GNUTLS_CLIENT)
123     {
124       int i;
125
126       for (i = 0; i < session->internals.extensions_sent_size; i++)
127         {
128           if (type == session->internals.extensions_sent[i])
129             return 0;           /* ok found */
130         }
131
132       return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION;
133     }
134
135   return 0;
136 }
137
138 int
139 _gnutls_parse_extensions (gnutls_session_t session,
140                           gnutls_ext_parse_type_t parse_type,
141                           const opaque * data, int data_size)
142 {
143   int next, ret;
144   int pos = 0;
145   uint16_t type;
146   const opaque *sdata;
147   gnutls_ext_recv_func ext_recv;
148   uint16_t size;
149
150 #ifdef DEBUG
151   int i;
152
153   if (session->security_parameters.entity == GNUTLS_CLIENT)
154     for (i = 0; i < session->internals.extensions_sent_size; i++)
155       {
156         _gnutls_debug_log ("EXT[%d]: expecting extension '%s'\n",
157                            session,
158                            _gnutls_extension_get_name
159                            (session->internals.extensions_sent[i]));
160       }
161 #endif
162
163   DECR_LENGTH_RET (data_size, 2, 0);
164   next = _gnutls_read_uint16 (data);
165   pos += 2;
166
167   DECR_LENGTH_RET (data_size, next, 0);
168
169   do
170     {
171       DECR_LENGTH_RET (next, 2, 0);
172       type = _gnutls_read_uint16 (&data[pos]);
173       pos += 2;
174
175 #if 0
176       _gnutls_debug_log ("EXT[%p]: Found extension '%s/%d'\n", session,
177                          _gnutls_extension_get_name (type), type);
178 #endif
179
180       if ((ret = _gnutls_extension_list_check (session, type)) < 0)
181         {
182           gnutls_assert ();
183           return ret;
184         }
185
186       DECR_LENGTH_RET (next, 2, 0);
187       size = _gnutls_read_uint16 (&data[pos]);
188       pos += 2;
189
190       DECR_LENGTH_RET (next, size, 0);
191       sdata = &data[pos];
192       pos += size;
193
194       ext_recv = _gnutls_ext_func_recv (type, parse_type);
195       if (ext_recv == NULL)
196         continue;
197
198       _gnutls_debug_log ("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n",
199                          session, _gnutls_extension_get_name (type), type,
200                          size);
201
202       if ((ret = ext_recv (session, sdata, size)) < 0)
203         {
204           gnutls_assert ();
205           return ret;
206         }
207
208     }
209   while (next > 2);
210
211   return 0;
212
213 }
214
215 /* Adds the extension we want to send in the extensions list.
216  * This list is used to check whether the (later) received
217  * extensions are the ones we requested.
218  */
219 void
220 _gnutls_extension_list_add (gnutls_session_t session, uint16_t type)
221 {
222
223   if (session->security_parameters.entity == GNUTLS_CLIENT)
224     {
225       if (session->internals.extensions_sent_size < MAX_EXT_TYPES)
226         {
227           session->internals.extensions_sent[session->internals.
228                                              extensions_sent_size] = type;
229           session->internals.extensions_sent_size++;
230         }
231       else
232         {
233           _gnutls_debug_log ("extensions: Increase MAX_EXT_TYPES\n");
234         }
235     }
236 }
237
238 int
239 _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
240                         size_t data_size, gnutls_ext_parse_type_t parse_type)
241 {
242   int size;
243   uint16_t pos = 0;
244   opaque *sdata;
245   size_t sdata_size;
246   size_t i;
247
248   if (data_size < 2)
249     {
250       gnutls_assert ();
251       return GNUTLS_E_INTERNAL_ERROR;
252     }
253
254   /* allocate enough data for each extension.
255    */
256   sdata_size = data_size;
257   sdata = gnutls_malloc (sdata_size);
258   if (sdata == NULL)
259     {
260       gnutls_assert ();
261       return GNUTLS_E_MEMORY_ERROR;
262     }
263
264   pos += 2;
265   for (i = 0; i < extfunc_size; i++)
266     {
267       extension_entry_st *p = &extfunc[i];
268
269       if (p->send_func == NULL)
270         continue;
271
272       if (parse_type != GNUTLS_EXT_ANY && p->parse_type != parse_type)
273         continue;
274
275       size = p->send_func (session, sdata, sdata_size);
276       if (size > 0 || size == GNUTLS_E_INT_RET_0)
277         {
278           if (size == GNUTLS_E_INT_RET_0)
279             size = 0;
280
281           if (data_size < pos + (size_t) size + 4)
282             {
283               gnutls_assert ();
284               gnutls_free (sdata);
285               return GNUTLS_E_INTERNAL_ERROR;
286             }
287
288           /* write extension type */
289           _gnutls_write_uint16 (p->type, &data[pos]);
290           pos += 2;
291
292           /* write size */
293           _gnutls_write_uint16 (size, &data[pos]);
294           pos += 2;
295
296           memcpy (&data[pos], sdata, size);
297           pos += size;
298
299           /* add this extension to the extension list
300            */
301           _gnutls_extension_list_add (session, p->type);
302
303           _gnutls_debug_log ("EXT[%p]: Sending extension %s (%d bytes)\n",
304                              session, p->name, size);
305         }
306       else if (size < 0)
307         {
308           gnutls_assert ();
309           gnutls_free (sdata);
310           return size;
311         }
312     }
313
314   size = pos;
315   pos -= 2;                     /* remove the size of the size header! */
316
317   _gnutls_write_uint16 (pos, data);
318
319   if (size == 2)
320     {                           /* empty */
321       size = 0;
322     }
323
324   gnutls_free (sdata);
325   return size;
326
327 }
328
329 int
330 _gnutls_ext_init (void)
331 {
332   int ret;
333
334   ret = _gnutls_ext_register (&ext_mod_max_record_size);
335   if (ret != GNUTLS_E_SUCCESS)
336     return ret;
337
338   ret = _gnutls_ext_register (&ext_mod_cert_type);
339   if (ret != GNUTLS_E_SUCCESS)
340     return ret;
341
342
343   ret = _gnutls_ext_register (&ext_mod_server_name);
344   if (ret != GNUTLS_E_SUCCESS)
345     return ret;
346
347   ret = _gnutls_ext_register (&ext_mod_sr);
348   if (ret != GNUTLS_E_SUCCESS)
349     return ret;
350
351 #ifdef ENABLE_SRP
352   ret = _gnutls_ext_register (&ext_mod_srp);
353   if (ret != GNUTLS_E_SUCCESS)
354     return ret;
355 #endif
356
357 #ifdef ENABLE_SESSION_TICKET
358   ret = _gnutls_ext_register (&ext_mod_session_ticket);
359   if (ret != GNUTLS_E_SUCCESS)
360     return ret;
361 #endif
362
363   ret = _gnutls_ext_register (&ext_mod_sig);
364   if (ret != GNUTLS_E_SUCCESS)
365     return ret;
366
367   return GNUTLS_E_SUCCESS;
368 }
369
370 void
371 _gnutls_ext_deinit (void)
372 {
373   gnutls_free (extfunc);
374   extfunc = NULL;
375   extfunc_size = 0;
376 }
377
378 int
379 _gnutls_ext_register (extension_entry_st * mod)
380 {
381   extension_entry_st *p;
382
383   p = gnutls_realloc (extfunc, sizeof (*extfunc) * (extfunc_size + 1));
384   if (!p)
385     {
386       gnutls_assert ();
387       return GNUTLS_E_MEMORY_ERROR;
388     }
389
390   extfunc = p;
391
392   memcpy (&extfunc[extfunc_size], mod, sizeof (*mod));
393
394   extfunc_size++;
395
396   return GNUTLS_E_SUCCESS;
397 }
398
399 /**
400  * gnutls_ext_register:
401  * @type: the 16-bit integer referring to the extension type
402  * @name: human printable name of the extension used for debugging
403  * @parse_type: either #GNUTLS_EXT_TLS or %GNUTLS_EXT_APPLICATION.
404  * @recv_func: a function to receive extension data
405  * @send_func: a function to send extension data
406  *
407  * This function is used to register a new TLS extension handler.
408  *
409  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
410  *
411  * Deprecated in: 2.12.0
412  */
413 int
414 gnutls_ext_register (int type,
415                      const char *name,
416                      gnutls_ext_parse_type_t parse_type,
417                      gnutls_ext_recv_func recv_func,
418                      gnutls_ext_send_func send_func)
419 {
420   extension_entry_st ee;
421
422   memset (&ee, 0, sizeof (ee));
423
424   ee.type = type;
425   ee.name = name;
426   ee.parse_type = parse_type;
427   ee.recv_func = recv_func;
428   ee.send_func = send_func;
429   /* FIXME: Why is this exported? Should it be removed? */
430   return _gnutls_ext_register (&ee);
431 }
432
433 int
434 _gnutls_ext_pack (gnutls_session_t session, gnutls_buffer_st * packed)
435 {
436   int i, ret;
437   extension_priv_data_t data;
438   int cur_size;
439   int size_offset;
440   int total_exts_pos;
441   int exts = 0;
442
443   total_exts_pos = packed->length;
444   BUFFER_APPEND_NUM (packed, 0);
445
446   for (i = 0; i < extfunc_size; i++)
447     {
448       ret = _gnutls_ext_get_session_data (session, extfunc[i].type, &data);
449       if (ret >= 0 && extfunc[i].pack_func != NULL)
450         {
451           BUFFER_APPEND_NUM (packed, extfunc[i].type);
452
453           size_offset = packed->length;
454           BUFFER_APPEND_NUM (packed, 0);
455
456           cur_size = packed->length;
457
458           ret = extfunc[i].pack_func (data, packed);
459           if (ret < 0)
460             {
461               gnutls_assert ();
462               return ret;
463             }
464
465           exts++;
466           /* write the actual size */
467           _gnutls_write_uint32 (packed->length - cur_size,
468                                 packed->data + size_offset);
469         }
470     }
471
472   _gnutls_write_uint32 (exts, packed->data + total_exts_pos);
473
474   return 0;
475
476 }
477
478 void
479 _gnutls_ext_restore_resumed_session (gnutls_session_t session)
480 {
481   int i;
482
483
484   /* clear everything except MANDATORY extensions */
485   for (i = 0; i < MAX_EXT_TYPES; i++)
486     {
487       if (session->internals.extension_int_data[i].set != 0 &&
488           _gnutls_ext_parse_type (session->internals.
489                                   extension_int_data[i].type) !=
490           GNUTLS_EXT_MANDATORY)
491         {
492           _gnutls_ext_unset_session_data (session,
493                                           session->
494                                           internals.extension_int_data[i].
495                                           type);
496         }
497     }
498
499   /* copy resumed to main */
500   for (i = 0; i < MAX_EXT_TYPES; i++)
501     {
502       if (session->internals.resumed_extension_int_data[i].set != 0 &&
503           _gnutls_ext_parse_type (session->
504                                   internals.resumed_extension_int_data[i].
505                                   type) != GNUTLS_EXT_MANDATORY)
506         {
507           _gnutls_ext_set_session_data (session,
508                                         session->
509                                         internals.resumed_extension_int_data
510                                         [i].type,
511                                         session->
512                                         internals.resumed_extension_int_data
513                                         [i].priv);
514           session->internals.resumed_extension_int_data[i].set = 0;
515         }
516     }
517
518 }
519
520
521 static void
522 _gnutls_ext_set_resumed_session_data (gnutls_session_t session, uint16_t type,
523                                       extension_priv_data_t data)
524 {
525   int i;
526
527   for (i = 0; i < MAX_EXT_TYPES; i++)
528     {
529       if (session->internals.resumed_extension_int_data[i].type == type
530           || session->internals.resumed_extension_int_data[i].set == 0)
531         {
532
533           if (session->internals.resumed_extension_int_data[i].set != 0)
534             _gnutls_ext_unset_resumed_session_data (session, type);
535
536           session->internals.resumed_extension_int_data[i].type = type;
537           session->internals.resumed_extension_int_data[i].priv = data;
538           session->internals.resumed_extension_int_data[i].set = 1;
539           return;
540         }
541     }
542 }
543
544 int
545 _gnutls_ext_unpack (gnutls_session_t session, gnutls_buffer_st * packed)
546 {
547   int i, ret;
548   extension_priv_data_t data;
549   gnutls_ext_unpack_func unpack;
550   int max_exts = 0;
551   uint16_t type;
552   int size_for_type, cur_pos;
553
554
555   BUFFER_POP_NUM (packed, max_exts);
556   for (i = 0; i < max_exts; i++)
557     {
558       BUFFER_POP_NUM (packed, type);
559       BUFFER_POP_NUM (packed, size_for_type);
560
561       cur_pos = packed->length;
562
563       unpack = _gnutls_ext_func_unpack (type);
564       if (unpack == NULL)
565         {
566           gnutls_assert ();
567           return GNUTLS_E_PARSING_ERROR;
568         }
569
570       ret = unpack (packed, &data);
571       if (ret < 0)
572         {
573           gnutls_assert ();
574           return ret;
575         }
576
577       /* verify that unpack read the correct bytes */
578       cur_pos = cur_pos - packed->length;
579       if (cur_pos /* read length */  != size_for_type)
580         {
581           gnutls_assert ();
582           return GNUTLS_E_PARSING_ERROR;
583         }
584
585       _gnutls_ext_set_resumed_session_data (session, type, data);
586     }
587
588   return 0;
589
590 error:
591   return ret;
592 }
593
594 void
595 _gnutls_ext_unset_session_data (gnutls_session_t session, uint16_t type)
596 {
597   gnutls_ext_deinit_data_func deinit;
598   extension_priv_data_t data;
599   int ret, i;
600
601   deinit = _gnutls_ext_func_deinit (type);
602   ret = _gnutls_ext_get_session_data (session, type, &data);
603
604   if (ret >= 0 && deinit != NULL)
605     {
606       deinit (data);
607     }
608
609   for (i = 0; i < MAX_EXT_TYPES; i++)
610     {
611       if (session->internals.extension_int_data[i].type == type)
612         {
613           session->internals.extension_int_data[i].set = 0;
614           return;
615         }
616     }
617
618 }
619
620 static void
621 _gnutls_ext_unset_resumed_session_data (gnutls_session_t session,
622                                         uint16_t type)
623 {
624   gnutls_ext_deinit_data_func deinit;
625   extension_priv_data_t data;
626   int ret, i;
627
628   deinit = _gnutls_ext_func_deinit (type);
629   ret = _gnutls_ext_get_resumed_session_data (session, type, &data);
630
631   if (ret >= 0 && deinit != NULL)
632     {
633       deinit (data);
634     }
635
636   for (i = 0; i < MAX_EXT_TYPES; i++)
637     {
638       if (session->internals.resumed_extension_int_data[i].type == type)
639         {
640           session->internals.resumed_extension_int_data[i].set = 0;
641           return;
642         }
643     }
644
645 }
646
647 /* Deinitializes all data that are associated with TLS extensions.
648  */
649 void
650 _gnutls_ext_free_session_data (gnutls_session_t session)
651 {
652   int i;
653
654   for (i = 0; i < extfunc_size; i++)
655     {
656       _gnutls_ext_unset_session_data (session, extfunc[i].type);
657     }
658
659   for (i = 0; i < extfunc_size; i++)
660     {
661       _gnutls_ext_unset_resumed_session_data (session, extfunc[i].type);
662     }
663
664 }
665
666 /* This function allows and extension to store data in the current session
667  * and retrieve them later on. We use functions instead of a pointer to a
668  * private pointer, to allow API additions by individual extensions.
669  */
670 void
671 _gnutls_ext_set_session_data (gnutls_session_t session, uint16_t type,
672                               extension_priv_data_t data)
673 {
674   int i;
675   gnutls_ext_deinit_data_func deinit;
676
677   deinit = _gnutls_ext_func_deinit (type);
678
679   for (i = 0; i < MAX_EXT_TYPES; i++)
680     {
681       if (session->internals.extension_int_data[i].type == type
682           || session->internals.extension_int_data[i].set == 0)
683         {
684           if (session->internals.extension_int_data[i].set != 0)
685             {
686               if (deinit)
687                 deinit (session->internals.extension_int_data[i].priv);
688             }
689           session->internals.extension_int_data[i].type = type;
690           session->internals.extension_int_data[i].priv = data;
691           session->internals.extension_int_data[i].set = 1;
692           return;
693         }
694     }
695 }
696
697 int
698 _gnutls_ext_get_session_data (gnutls_session_t session,
699                               uint16_t type, extension_priv_data_t * data)
700 {
701   int i;
702
703   for (i = 0; i < MAX_EXT_TYPES; i++)
704     {
705       if (session->internals.extension_int_data[i].set != 0 &&
706           session->internals.extension_int_data[i].type == type)
707         {
708           *data = session->internals.extension_int_data[i].priv;
709           return 0;
710         }
711     }
712   return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
713 }
714
715 int
716 _gnutls_ext_get_resumed_session_data (gnutls_session_t session,
717                                       uint16_t type,
718                                       extension_priv_data_t * data)
719 {
720   int i;
721
722   for (i = 0; i < MAX_EXT_TYPES; i++)
723     {
724       if (session->internals.resumed_extension_int_data[i].set != 0 &&
725           session->internals.resumed_extension_int_data[i].type == type)
726         {
727           *data = session->internals.resumed_extension_int_data[i].priv;
728           return 0;
729         }
730     }
731   return GNUTLS_E_INVALID_REQUEST;
732 }