Tizen 2.0 Release
[external/libgnutls26.git] / lib / ext_session_ticket.c
1 /*
2  * Copyright (C) 2009, 2010 Free Software Foundation, Inc.
3  *
4  * Author: Daiki Ueno
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21  * USA
22  *
23  */
24
25 #include <gnutls_int.h>
26 #include <gnutls_errors.h>
27 #include <gnutls_datum.h>
28 #include <gnutls_algorithms.h>
29 #include <gnutls_handshake.h>
30 #include <gnutls_num.h>
31 #include <gnutls_constate.h>
32 #include <gnutls_session_pack.h>
33 #include <random.h>
34 #include <ext_session_ticket.h>
35 #include <gnutls_mbuffers.h>
36 #include <gnutls_extensions.h>
37 #include <gnutls_constate.h>
38 #include <system.h>
39
40 #ifdef ENABLE_SESSION_TICKET
41
42 #define KEY_NAME_SIZE SESSION_TICKET_KEY_NAME_SIZE
43 #define KEY_SIZE SESSION_TICKET_KEY_SIZE
44 #define IV_SIZE SESSION_TICKET_IV_SIZE
45 #define MAC_SECRET_SIZE SESSION_TICKET_MAC_SECRET_SIZE
46
47 #define MAC_SIZE 32
48
49 static int session_ticket_recv_params (gnutls_session_t session,
50                                        const opaque * data, size_t data_size);
51 static int session_ticket_send_params (gnutls_session_t session,
52                                        opaque * data, size_t data_size);
53 static int session_ticket_unpack (gnutls_buffer_st * ps,
54                                   extension_priv_data_t * _priv);
55 static int session_ticket_pack (extension_priv_data_t _priv,
56                                 gnutls_buffer_st * ps);
57 static void session_ticket_deinit_data (extension_priv_data_t priv);
58
59 extension_entry_st ext_mod_session_ticket = {
60   .name = "SESSION TICKET",
61   .type = GNUTLS_EXTENSION_SESSION_TICKET,
62   .parse_type = GNUTLS_EXT_TLS,
63
64   .recv_func = session_ticket_recv_params,
65   .send_func = session_ticket_send_params,
66   .pack_func = session_ticket_pack,
67   .unpack_func = session_ticket_unpack,
68   .deinit_func = session_ticket_deinit_data,
69 };
70
71 struct gnutls_session_ticket_key_st
72 {
73   opaque key_name[SESSION_TICKET_KEY_NAME_SIZE];
74   opaque key[SESSION_TICKET_KEY_SIZE];
75   opaque mac_secret[SESSION_TICKET_MAC_SECRET_SIZE];
76 };
77
78 typedef struct
79 {
80   int session_ticket_enable;
81   int session_ticket_renew;
82   opaque session_ticket_IV[SESSION_TICKET_IV_SIZE];
83
84   opaque *session_ticket;
85   int session_ticket_len;
86
87   struct gnutls_session_ticket_key_st key;
88 } session_ticket_ext_st;
89
90 struct ticket
91 {
92   opaque key_name[KEY_NAME_SIZE];
93   opaque IV[IV_SIZE];
94   opaque *encrypted_state;
95   uint16_t encrypted_state_len;
96   opaque mac[MAC_SIZE];
97 };
98
99 static int
100 digest_ticket (const gnutls_datum_t * key, struct ticket *ticket,
101                opaque * digest)
102 {
103   digest_hd_st digest_hd;
104   uint16_t length16;
105   int ret;
106
107   ret = _gnutls_hmac_init (&digest_hd, GNUTLS_MAC_SHA256, key->data,
108                            key->size);
109   if (ret < 0)
110     {
111       gnutls_assert ();
112       return ret;
113     }
114   _gnutls_hmac (&digest_hd, ticket->key_name, KEY_NAME_SIZE);
115   _gnutls_hmac (&digest_hd, ticket->IV, IV_SIZE);
116   length16 = _gnutls_conv_uint16 (ticket->encrypted_state_len);
117   _gnutls_hmac (&digest_hd, &length16, 2);
118   _gnutls_hmac (&digest_hd, ticket->encrypted_state,
119                 ticket->encrypted_state_len);
120   _gnutls_hmac_deinit (&digest_hd, digest);
121
122   return 0;
123 }
124
125 static int
126 decrypt_ticket (gnutls_session_t session, session_ticket_ext_st * priv,
127                 struct ticket *ticket)
128 {
129   cipher_hd_st cipher_hd;
130   gnutls_datum_t key, IV, mac_secret, state;
131   opaque final[MAC_SECRET_SIZE];
132   time_t timestamp = gnutls_time (0);
133   int ret;
134
135   /* Check the integrity of ticket using HMAC-SHA-256. */
136   mac_secret.data = (void *) priv->key.mac_secret;
137   mac_secret.size = MAC_SECRET_SIZE;
138   ret = digest_ticket (&mac_secret, ticket, final);
139   if (ret < 0)
140     {
141       gnutls_assert ();
142       return ret;
143     }
144
145   if (memcmp (ticket->mac, final, MAC_SIZE))
146     {
147       gnutls_assert ();
148       return GNUTLS_E_DECRYPTION_FAILED;
149     }
150
151   /* Decrypt encrypted_state using 128-bit AES in CBC mode. */
152   key.data = (void *) priv->key.key;
153   key.size = KEY_SIZE;
154   IV.data = ticket->IV;
155   IV.size = IV_SIZE;
156   ret =
157     _gnutls_cipher_init (&cipher_hd, GNUTLS_CIPHER_AES_128_CBC, &key, &IV);
158   if (ret < 0)
159     {
160       gnutls_assert ();
161       return ret;
162     }
163   ret = _gnutls_cipher_decrypt (&cipher_hd, ticket->encrypted_state,
164                                 ticket->encrypted_state_len);
165   _gnutls_cipher_deinit (&cipher_hd);
166   if (ret < 0)
167     {
168       gnutls_assert ();
169       return ret;
170     }
171
172   /* Unpack security parameters. */
173   state.data = ticket->encrypted_state;
174   state.size = ticket->encrypted_state_len;
175   ret = _gnutls_session_unpack (session, &state);
176   if (ret < 0)
177     {
178       gnutls_assert ();
179       return ret;
180     }
181
182   if (timestamp - session->internals.resumed_security_parameters.timestamp >
183       session->internals.expire_time
184       || session->internals.resumed_security_parameters.timestamp > timestamp)
185     {
186       gnutls_assert ();
187       return GNUTLS_E_EXPIRED;
188     }
189
190   session->internals.resumed = RESUME_TRUE;
191
192   return 0;
193 }
194
195 static int
196 encrypt_ticket (gnutls_session_t session, session_ticket_ext_st * priv,
197                 struct ticket *ticket)
198 {
199   cipher_hd_st cipher_hd;
200   gnutls_datum_t key, IV, mac_secret, state, encrypted_state;
201   int blocksize;
202   int ret;
203
204   /* Pack security parameters. */
205   ret = _gnutls_session_pack (session, &state);
206   if (ret < 0)
207     {
208       gnutls_assert ();
209       return ret;
210     }
211   blocksize = gnutls_cipher_get_block_size (GNUTLS_CIPHER_AES_128_CBC);
212
213   encrypted_state.size =
214     ((state.size + blocksize - 1) / blocksize) * blocksize;
215   encrypted_state.data = gnutls_malloc (encrypted_state.size);
216   if (!encrypted_state.data)
217     {
218       gnutls_assert ();
219       _gnutls_free_datum (&state);
220       return GNUTLS_E_MEMORY_ERROR;
221     }
222   memset (encrypted_state.data, 0, encrypted_state.size);
223   memcpy (encrypted_state.data, state.data, state.size);
224   _gnutls_free_datum (&state);
225
226   /* Encrypt state using 128-bit AES in CBC mode. */
227   key.data = (void *) priv->key.key;
228   key.size = KEY_SIZE;
229   IV.data = priv->session_ticket_IV;
230   IV.size = IV_SIZE;
231   ret =
232     _gnutls_cipher_init (&cipher_hd, GNUTLS_CIPHER_AES_128_CBC, &key, &IV);
233   if (ret < 0)
234     {
235       gnutls_assert ();
236       _gnutls_free_datum (&encrypted_state);
237       return ret;
238     }
239
240   ret = _gnutls_cipher_encrypt (&cipher_hd, encrypted_state.data,
241                                 encrypted_state.size);
242   _gnutls_cipher_deinit (&cipher_hd);
243   if (ret < 0)
244     {
245       gnutls_assert ();
246       _gnutls_free_datum (&encrypted_state);
247       return ret;
248     }
249
250   /* Fill the ticket structure to compute MAC. */
251   memcpy (ticket->key_name, priv->key.key_name, KEY_NAME_SIZE);
252   memcpy (ticket->IV, IV.data, IV.size);
253   ticket->encrypted_state_len = encrypted_state.size;
254   ticket->encrypted_state = encrypted_state.data;
255
256   mac_secret.data = priv->key.mac_secret;
257   mac_secret.size = MAC_SECRET_SIZE;
258   ret = digest_ticket (&mac_secret, ticket, ticket->mac);
259   if (ret < 0)
260     {
261       gnutls_assert ();
262       _gnutls_free_datum (&encrypted_state);
263       return ret;
264     }
265
266   return 0;
267 }
268
269 static int
270 session_ticket_recv_params (gnutls_session_t session,
271                             const opaque * data, size_t _data_size)
272 {
273   ssize_t data_size = _data_size;
274   session_ticket_ext_st *priv = NULL;
275   extension_priv_data_t epriv;
276   int ret;
277
278   ret =
279     _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SESSION_TICKET,
280                                   &epriv);
281   if (ret < 0)
282     {
283       return 0;
284     }
285   priv = epriv.ptr;
286
287   if (!priv->session_ticket_enable)
288     return 0;
289
290   if (session->security_parameters.entity == GNUTLS_SERVER)
291     {
292       struct ticket ticket;
293       const opaque *encrypted_state;
294       int ret;
295
296       /* The client requested a new session ticket. */
297       if (data_size == 0)
298         {
299           priv->session_ticket_renew = 1;
300           return 0;
301         }
302
303       DECR_LEN (data_size, KEY_NAME_SIZE);
304       memcpy (ticket.key_name, data, KEY_NAME_SIZE);
305       data += KEY_NAME_SIZE;
306
307       /* If the key name of the ticket does not match the one that we
308          hold, issue a new ticket. */
309       if (memcmp (ticket.key_name, priv->key.key_name, KEY_NAME_SIZE))
310         {
311           priv->session_ticket_renew = 1;
312           return 0;
313         }
314
315       DECR_LEN (data_size, IV_SIZE);
316       memcpy (ticket.IV, data, IV_SIZE);
317       data += IV_SIZE;
318
319       DECR_LEN (data_size, 2);
320       ticket.encrypted_state_len = _gnutls_read_uint16 (data);
321       data += 2;
322
323       encrypted_state = data;
324
325       DECR_LEN (data_size, ticket.encrypted_state_len);
326       data += ticket.encrypted_state_len;
327
328       DECR_LEN (data_size, MAC_SIZE);
329       memcpy (ticket.mac, data, MAC_SIZE);
330
331       ticket.encrypted_state = gnutls_malloc (ticket.encrypted_state_len);
332       if (!ticket.encrypted_state)
333         {
334           gnutls_assert ();
335           return GNUTLS_E_MEMORY_ERROR;
336         }
337       memcpy (ticket.encrypted_state, encrypted_state,
338               ticket.encrypted_state_len);
339
340       ret = decrypt_ticket (session, priv, &ticket);
341       gnutls_free (ticket.encrypted_state);
342       if (ret < 0)
343         {
344           priv->session_ticket_renew = 1;
345           return 0;
346         }
347     }
348   else                          /* Client */
349     {
350       if (data_size == 0)
351         {
352           priv->session_ticket_renew = 1;
353           return 0;
354         }
355     }
356
357   return 0;
358 }
359
360 /* returns a positive number if we send the extension data, zero if we
361    do not want to send it, and a negative number on failure.
362  */
363 static int
364 session_ticket_send_params (gnutls_session_t session,
365                             opaque * data, size_t _data_size)
366 {
367   ssize_t data_size = _data_size;
368   session_ticket_ext_st *priv = NULL;
369   extension_priv_data_t epriv;
370   int ret;
371
372   ret =
373     _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SESSION_TICKET,
374                                   &epriv);
375   if (ret >= 0)
376     priv = epriv.ptr;
377
378   if (priv == NULL || !priv->session_ticket_enable)
379     return 0;
380
381   if (session->security_parameters.entity == GNUTLS_SERVER)
382     {
383       if (priv && priv->session_ticket_renew)
384         {
385           return GNUTLS_E_INT_RET_0;
386         }
387     }
388   else
389     {
390       ret =
391         _gnutls_ext_get_resumed_session_data (session,
392                                               GNUTLS_EXTENSION_SESSION_TICKET,
393                                               &epriv);
394       if (ret >= 0)
395         priv = epriv.ptr;
396
397       /* no previous data. Just advertize it */
398       if (ret < 0)
399         return GNUTLS_E_INT_RET_0;
400
401       /* previous data had session tickets disabled. Don't advertize. Ignore. */
402       if (!priv->session_ticket_enable)
403         return 0;
404
405       if (priv->session_ticket_len > 0)
406         {
407           DECR_LENGTH_RET (data_size, priv->session_ticket_len,
408                            GNUTLS_E_SHORT_MEMORY_BUFFER);
409           memcpy (data, priv->session_ticket, priv->session_ticket_len);
410
411           return priv->session_ticket_len;
412         }
413     }
414   return 0;
415 }
416
417
418 static void
419 session_ticket_deinit_data (extension_priv_data_t epriv)
420 {
421   session_ticket_ext_st *priv = epriv.ptr;
422
423   gnutls_free (priv->session_ticket);
424   gnutls_free (priv);
425 }
426
427 static int
428 session_ticket_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
429 {
430   session_ticket_ext_st *priv = epriv.ptr;
431   int ret;
432
433   BUFFER_APPEND_PFX (ps, priv->session_ticket, priv->session_ticket_len);
434   BUFFER_APPEND_NUM (ps, priv->session_ticket_enable);
435
436   return 0;
437 }
438
439 static int
440 session_ticket_unpack (gnutls_buffer_st * ps, extension_priv_data_t * _priv)
441 {
442   session_ticket_ext_st *priv = NULL;
443   int ret;
444   extension_priv_data_t epriv;
445   gnutls_datum ticket;
446
447   priv = gnutls_calloc (1, sizeof (*priv));
448   if (priv == NULL)
449     {
450       gnutls_assert ();
451       return GNUTLS_E_MEMORY_ERROR;
452     }
453
454   BUFFER_POP_DATUM (ps, &ticket);
455   priv->session_ticket = ticket.data;
456   priv->session_ticket_len = ticket.size;
457   BUFFER_POP_NUM (ps, priv->session_ticket_enable);
458
459   epriv.ptr = priv;
460   *_priv = epriv;
461
462   return 0;
463
464 error:
465   gnutls_free (priv);
466   return ret;
467 }
468
469
470
471 /**
472  * gnutls_session_ticket_key_generate:
473  * @key: is a pointer to a #gnutls_datum_t which will contain a newly
474  * created key.
475  *
476  * Generate a random key to encrypt security parameters within
477  * SessionTicket.
478  *
479  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
480  * error code.
481  *
482  * Since: 2.10.0
483  **/
484 int
485 gnutls_session_ticket_key_generate (gnutls_datum_t * key)
486 {
487   int ret;
488
489   key->size = sizeof (struct gnutls_session_ticket_key_st);
490   key->data = gnutls_malloc (key->size);
491   if (!key->data)
492     {
493       gnutls_assert ();
494       return GNUTLS_E_MEMORY_ERROR;
495     }
496
497   ret = _gnutls_rnd (GNUTLS_RND_RANDOM, key->data, key->size);
498   if (ret < 0)
499     {
500       gnutls_assert ();
501       _gnutls_free_datum (key);
502       return ret;
503     }
504
505   return 0;
506 }
507
508 /**
509  * gnutls_session_ticket_enable_client:
510  * @session: is a #gnutls_session_t structure.
511  *
512  * Request that the client should attempt session resumption using
513  * SessionTicket.
514  *
515  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
516  * error code.
517  *
518  * Since: 2.10.0
519  **/
520 int
521 gnutls_session_ticket_enable_client (gnutls_session_t session)
522 {
523   session_ticket_ext_st *priv = NULL;
524   extension_priv_data_t epriv;
525
526   if (!session)
527     {
528       gnutls_assert ();
529       return GNUTLS_E_INVALID_REQUEST;
530     }
531
532   priv = gnutls_calloc (1, sizeof (*priv));
533   if (priv == NULL)
534     {
535       gnutls_assert ();
536       return GNUTLS_E_MEMORY_ERROR;
537     }
538   priv->session_ticket_enable = 1;
539   epriv.ptr = priv;
540
541   _gnutls_ext_set_session_data (session,
542                                 GNUTLS_EXTENSION_SESSION_TICKET, epriv);
543
544   return 0;
545 }
546
547 /**
548  * gnutls_session_ticket_enable_server:
549  * @session: is a #gnutls_session_t structure.
550  * @key: key to encrypt session parameters.
551  *
552  * Request that the server should attempt session resumption using
553  * SessionTicket.  @key must be initialized with
554  * gnutls_session_ticket_key_generate().
555  *
556  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
557  * error code.
558  *
559  * Since: 2.10.0
560  **/
561 int
562 gnutls_session_ticket_enable_server (gnutls_session_t session,
563                                      const gnutls_datum_t * key)
564 {
565   int ret;
566   session_ticket_ext_st *priv = NULL;
567   extension_priv_data_t epriv;
568
569   if (!session || !key
570       || key->size != sizeof (struct gnutls_session_ticket_key_st))
571     {
572       gnutls_assert ();
573       return GNUTLS_E_INVALID_REQUEST;
574     }
575
576   priv = gnutls_calloc (1, sizeof (*priv));
577   if (priv == NULL)
578     {
579       gnutls_assert ();
580       return GNUTLS_E_MEMORY_ERROR;
581     }
582   epriv.ptr = priv;
583
584   ret = _gnutls_rnd (GNUTLS_RND_RANDOM, priv->session_ticket_IV, IV_SIZE);
585   if (ret < 0)
586     {
587       gnutls_assert ();
588       return ret;
589     }
590
591   memcpy (&priv->key, key->data, key->size);
592   priv->session_ticket_enable = 1;
593
594   _gnutls_ext_set_session_data (session,
595                                 GNUTLS_EXTENSION_SESSION_TICKET, epriv);
596
597   return 0;
598 }
599
600 int
601 _gnutls_send_new_session_ticket (gnutls_session_t session, int again)
602 {
603   mbuffer_st *bufel = NULL;
604   uint8_t *data = NULL, *p;
605   int data_size = 0;
606   int ret;
607   struct ticket ticket;
608   uint16_t ticket_len;
609   session_ticket_ext_st *priv = NULL;
610   extension_priv_data_t epriv;
611   uint16_t epoch_saved = session->security_parameters.epoch_write;
612
613   if (again == 0)
614     {
615       ret =
616         _gnutls_ext_get_session_data (session,
617                                       GNUTLS_EXTENSION_SESSION_TICKET,
618                                       &epriv);
619       if (ret < 0)
620         return 0;
621       priv = epriv.ptr;
622
623       if (!priv->session_ticket_renew)
624         return 0;
625
626       /* XXX: Temporarily set write algorithms to be used.
627          _gnutls_write_connection_state_init() does this job, but it also
628          triggers encryption, while NewSessionTicket should not be
629          encrypted in the record layer. */
630       ret =
631         _gnutls_epoch_set_keys (session,
632                                 session->security_parameters.epoch_next);
633       if (ret < 0)
634         {
635           gnutls_assert ();
636           return ret;
637         }
638
639       session->security_parameters.epoch_write =
640         session->security_parameters.epoch_next;
641
642       ret = encrypt_ticket (session, priv, &ticket);
643       session->security_parameters.epoch_write = epoch_saved;
644       if (ret < 0)
645         {
646           gnutls_assert ();
647           return ret;
648         }
649
650       ticket_len = KEY_NAME_SIZE + IV_SIZE + 2 + ticket.encrypted_state_len
651         + MAC_SIZE;
652
653       bufel =
654         _gnutls_handshake_alloc (4 + 2 + ticket_len, 4 + 2 + ticket_len);
655       if (!bufel)
656         {
657           gnutls_assert ();
658           gnutls_free (ticket.encrypted_state);
659           return GNUTLS_E_MEMORY_ERROR;
660         }
661
662       data = _mbuffer_get_udata_ptr (bufel);
663       p = data;
664
665       _gnutls_write_uint32 (session->internals.expire_time, p);
666       p += 4;
667
668       _gnutls_write_uint16 (ticket_len, p);
669       p += 2;
670
671       memcpy (p, ticket.key_name, KEY_NAME_SIZE);
672       p += KEY_NAME_SIZE;
673
674       memcpy (p, ticket.IV, IV_SIZE);
675       p += IV_SIZE;
676
677       _gnutls_write_uint16 (ticket.encrypted_state_len, p);
678       p += 2;
679
680       memcpy (p, ticket.encrypted_state, ticket.encrypted_state_len);
681       gnutls_free (ticket.encrypted_state);
682       p += ticket.encrypted_state_len;
683
684       memcpy (p, ticket.mac, MAC_SIZE);
685       p += MAC_SIZE;
686
687       data_size = p - data;
688     }
689   ret = _gnutls_send_handshake (session, data_size ? bufel : NULL,
690                                 GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
691
692   return ret;
693 }
694
695 int
696 _gnutls_recv_new_session_ticket (gnutls_session_t session)
697 {
698   uint8_t *data = NULL, *p;
699   int data_size;
700   uint16_t ticket_len;
701   int ret;
702   session_ticket_ext_st *priv = NULL;
703   extension_priv_data_t epriv;
704
705   ret =
706     _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SESSION_TICKET,
707                                   &epriv);
708   if (ret < 0)
709     {
710       gnutls_assert ();
711       return 0;
712     }
713   priv = epriv.ptr;
714
715   if (!priv->session_ticket_renew)
716     return 0;
717
718   ret = _gnutls_recv_handshake (session, &data, &data_size,
719                                 GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
720                                 MANDATORY_PACKET);
721   if (ret < 0)
722     {
723       gnutls_assert ();
724       return ret;
725     }
726
727   p = data;
728   DECR_LENGTH_COM (data_size, 4, goto error);
729   _gnutls_read_uint32 (p);
730   p += 4;
731
732   DECR_LENGTH_COM (data_size, 2, goto error);
733   ticket_len = _gnutls_read_uint16 (p);
734   p += 2;
735
736   DECR_LENGTH_COM (data_size, ticket_len, goto error);
737   priv->session_ticket = gnutls_realloc (priv->session_ticket, ticket_len);
738   if (!priv->session_ticket)
739     {
740       gnutls_assert ();
741       gnutls_free (data);
742       return GNUTLS_E_MEMORY_ERROR;
743     }
744   memcpy (priv->session_ticket, p, ticket_len);
745   gnutls_free (data);
746   priv->session_ticket_len = ticket_len;
747
748   /* Discard the current session ID.  (RFC5077 3.4) */
749   ret = _gnutls_generate_session_id (session->security_parameters.session_id,
750                                      &session->
751                                      security_parameters.session_id_size);
752   if (ret < 0)
753     {
754       gnutls_assert ();
755       gnutls_free (priv->session_ticket);
756       priv->session_ticket = NULL;
757       return GNUTLS_E_INTERNAL_ERROR;
758     }
759   return 0;
760
761 error:
762   gnutls_free (data);
763   return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
764 }
765
766 #endif