Use libtasn1 v2.4.
[gnutls.git] / lib / gnutls_supplemental.c
blob9ee172b680a7c435a8cb118a9f1e124ee89ae75c
1 /*
2 * Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc.
4 * Author: Simon Josefsson
6 * This file is part of GNUTLS.
8 * The GNUTLS library 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.
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.
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
25 /* This file contains support functions for 'TLS Handshake Message for
26 * Supplemental Data' (RFC 4680).
28 * The idea here is simple. gnutls_handshake() in gnuts_handshake.c
29 * will call _gnutls_gen_supplemental and _gnutls_parse_supplemental
30 * when some extension requested that supplemental data be sent or
31 * received. Extension request this by setting the flags
32 * do_recv_supplemental or do_send_supplemental in the session.
34 * The functions in this file iterate through the _gnutls_supplemental
35 * array, and calls the send/recv functions for each respective data
36 * type.
38 * The receive function of each data type is responsible for decoding
39 * its own data. If the extension did not expect to receive
40 * supplemental data, it should return GNUTLS_E_UNEXPECTED_PACKET.
41 * Otherwise, it just parse the data as normal.
43 * The send function needs to append the 2-byte data format type, and
44 * append the 2-byte length of its data, and the data. If it doesn't
45 * want to send any data, it is fine to return without doing anything.
48 #include "gnutls_int.h"
49 #include "gnutls_supplemental.h"
50 #include "gnutls_errors.h"
51 #include "gnutls_num.h"
53 typedef int (*supp_recv_func) (gnutls_session_t session,
54 const opaque * data, size_t data_size);
55 typedef int (*supp_send_func) (gnutls_session_t session, gnutls_buffer * buf);
57 typedef struct
59 const char *name;
60 gnutls_supplemental_data_format_type_t type;
61 supp_recv_func supp_recv_func;
62 supp_send_func supp_send_func;
63 } gnutls_supplemental_entry;
65 gnutls_supplemental_entry _gnutls_supplemental[] = {
66 {0, 0, 0, 0}
69 const char *
70 gnutls_supplemental_get_name (gnutls_supplemental_data_format_type_t type)
72 gnutls_supplemental_entry *p;
74 for (p = _gnutls_supplemental; p->name != NULL; p++)
75 if (p->type == type)
76 return p->name;
78 return NULL;
81 static supp_recv_func
82 get_supp_func_recv (gnutls_supplemental_data_format_type_t type)
84 gnutls_supplemental_entry *p;
86 for (p = _gnutls_supplemental; p->name != NULL; p++)
87 if (p->type == type)
88 return p->supp_recv_func;
90 return NULL;
93 int
94 _gnutls_gen_supplemental (gnutls_session_t session, gnutls_buffer * buf)
96 gnutls_supplemental_entry *p;
97 int ret;
99 /* Make room for 3 byte length field. */
100 ret = _gnutls_buffer_append (buf, "\0\0\0", 3);
101 if (ret < 0)
103 gnutls_assert ();
104 return ret;
107 for (p = _gnutls_supplemental; p->name; p++)
109 supp_send_func supp_send = p->supp_send_func;
110 size_t sizepos = buf->length;
112 /* Make room for supplement type and length byte length field. */
113 ret = _gnutls_buffer_append (buf, "\0\0\0\0", 4);
114 if (ret < 0)
116 gnutls_assert ();
117 return ret;
120 ret = supp_send (session, buf);
121 if (ret < 0)
123 gnutls_assert ();
124 return ret;
127 /* If data were added, store type+length, otherwise reset. */
128 if (buf->length > sizepos + 4)
130 buf->data[sizepos] = 0;
131 buf->data[sizepos + 1] = p->type;
132 buf->data[sizepos + 2] = ((buf->length - sizepos - 4) >> 8) & 0xFF;
133 buf->data[sizepos + 3] = (buf->length - sizepos - 4) & 0xFF;
135 else
136 buf->length -= 4;
139 buf->data[0] = ((buf->length - 3) >> 16) & 0xFF;
140 buf->data[1] = ((buf->length - 3) >> 8) & 0xFF;
141 buf->data[2] = (buf->length - 3) & 0xFF;
143 _gnutls_debug_log ("EXT[%p]: Sending %d bytes of supplemental data\n",
144 session, (int) buf->length);
146 return buf->length;
150 _gnutls_parse_supplemental (gnutls_session_t session,
151 const uint8_t * data, int datalen)
153 const opaque *p = data;
154 ssize_t dsize = datalen;
155 size_t total_size;
157 DECR_LEN (dsize, 3);
158 total_size = _gnutls_read_uint24 (p);
159 p += 3;
161 if (dsize != (ssize_t) total_size)
163 gnutls_assert ();
164 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
169 uint16_t supp_data_type;
170 uint16_t supp_data_length;
171 supp_recv_func recv_func;
173 DECR_LEN (dsize, 2);
174 supp_data_type = _gnutls_read_uint16 (p);
175 p += 2;
177 DECR_LEN (dsize, 2);
178 supp_data_length = _gnutls_read_uint16 (p);
179 p += 2;
181 _gnutls_debug_log ("EXT[%p]: Got supplemental type=%02x length=%d\n",
182 session, supp_data_type, supp_data_length);
184 recv_func = get_supp_func_recv (supp_data_type);
185 if (recv_func)
187 int ret = recv_func (session, p, supp_data_length);
188 if (ret < 0)
190 gnutls_assert ();
191 return ret;
194 else
196 gnutls_assert ();
197 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
200 DECR_LEN (dsize, supp_data_length);
201 p += supp_data_length;
203 while (dsize > 0);
205 return 0;