PKCS #11 PIN handling fixes.
[gnutls.git] / lib / gnutls_supplemental.c
blob8fa2dfb17414a181872eda6f311211886d7a4243
1 /*
2 * Copyright (C) 2007-2012 Free Software Foundation, Inc.
4 * Author: Simon Josefsson
6 * This file is part of GnuTLS.
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 3 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 License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* This file contains support functions for 'TLS Handshake Message for
24 * Supplemental Data' (RFC 4680).
26 * The idea here is simple. gnutls_handshake() in gnuts_handshake.c
27 * will call _gnutls_gen_supplemental and _gnutls_parse_supplemental
28 * when some extension requested that supplemental data be sent or
29 * received. Extension request this by setting the flags
30 * do_recv_supplemental or do_send_supplemental in the session.
32 * The functions in this file iterate through the _gnutls_supplemental
33 * array, and calls the send/recv functions for each respective data
34 * type.
36 * The receive function of each data type is responsible for decoding
37 * its own data. If the extension did not expect to receive
38 * supplemental data, it should return GNUTLS_E_UNEXPECTED_PACKET.
39 * Otherwise, it just parse the data as normal.
41 * The send function needs to append the 2-byte data format type, and
42 * append the 2-byte length of its data, and the data. If it doesn't
43 * want to send any data, it is fine to return without doing anything.
46 #include "gnutls_int.h"
47 #include "gnutls_supplemental.h"
48 #include "gnutls_errors.h"
49 #include "gnutls_num.h"
51 typedef int (*supp_recv_func) (gnutls_session_t session,
52 const uint8_t * data, size_t data_size);
53 typedef int (*supp_send_func) (gnutls_session_t session,
54 gnutls_buffer_st * buf);
56 typedef struct
58 const char *name;
59 gnutls_supplemental_data_format_type_t type;
60 supp_recv_func supp_recv_func;
61 supp_send_func supp_send_func;
62 } gnutls_supplemental_entry;
64 gnutls_supplemental_entry _gnutls_supplemental[] = {
65 {0, 0, 0, 0}
68 /**
69 * gnutls_supplemental_get_name:
70 * @type: is a supplemental data format type
72 * Convert a #gnutls_supplemental_data_format_type_t value to a
73 * string.
75 * Returns: a string that contains the name of the specified
76 * supplemental data format type, or %NULL for unknown types.
77 **/
78 const char *
79 gnutls_supplemental_get_name (gnutls_supplemental_data_format_type_t type)
81 gnutls_supplemental_entry *p;
83 for (p = _gnutls_supplemental; p->name != NULL; p++)
84 if (p->type == type)
85 return p->name;
87 return NULL;
90 static supp_recv_func
91 get_supp_func_recv (gnutls_supplemental_data_format_type_t type)
93 gnutls_supplemental_entry *p;
95 for (p = _gnutls_supplemental; p->name != NULL; p++)
96 if (p->type == type)
97 return p->supp_recv_func;
99 return NULL;
103 _gnutls_gen_supplemental (gnutls_session_t session, gnutls_buffer_st * buf)
105 gnutls_supplemental_entry *p;
106 int ret;
108 /* Make room for 3 byte length field. */
109 ret = _gnutls_buffer_append_data (buf, "\0\0\0", 3);
110 if (ret < 0)
112 gnutls_assert ();
113 return ret;
116 for (p = _gnutls_supplemental; p->name; p++)
118 supp_send_func supp_send = p->supp_send_func;
119 size_t sizepos = buf->length;
121 /* Make room for supplement type and length byte length field. */
122 ret = _gnutls_buffer_append_data (buf, "\0\0\0\0", 4);
123 if (ret < 0)
125 gnutls_assert ();
126 return ret;
129 ret = supp_send (session, buf);
130 if (ret < 0)
132 gnutls_assert ();
133 return ret;
136 /* If data were added, store type+length, otherwise reset. */
137 if (buf->length > sizepos + 4)
139 buf->data[sizepos] = 0;
140 buf->data[sizepos + 1] = p->type;
141 buf->data[sizepos + 2] = ((buf->length - sizepos - 4) >> 8) & 0xFF;
142 buf->data[sizepos + 3] = (buf->length - sizepos - 4) & 0xFF;
144 else
145 buf->length -= 4;
148 buf->data[0] = ((buf->length - 3) >> 16) & 0xFF;
149 buf->data[1] = ((buf->length - 3) >> 8) & 0xFF;
150 buf->data[2] = (buf->length - 3) & 0xFF;
152 _gnutls_debug_log ("EXT[%p]: Sending %d bytes of supplemental data\n",
153 session, (int) buf->length);
155 return buf->length;
159 _gnutls_parse_supplemental (gnutls_session_t session,
160 const uint8_t * data, int datalen)
162 const uint8_t *p = data;
163 ssize_t dsize = datalen;
164 size_t total_size;
166 DECR_LEN (dsize, 3);
167 total_size = _gnutls_read_uint24 (p);
168 p += 3;
170 if (dsize != (ssize_t) total_size)
172 gnutls_assert ();
173 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
178 uint16_t supp_data_type;
179 uint16_t supp_data_length;
180 supp_recv_func recv_func;
182 DECR_LEN (dsize, 2);
183 supp_data_type = _gnutls_read_uint16 (p);
184 p += 2;
186 DECR_LEN (dsize, 2);
187 supp_data_length = _gnutls_read_uint16 (p);
188 p += 2;
190 _gnutls_debug_log ("EXT[%p]: Got supplemental type=%02x length=%d\n",
191 session, supp_data_type, supp_data_length);
193 recv_func = get_supp_func_recv (supp_data_type);
194 if (recv_func)
196 int ret = recv_func (session, p, supp_data_length);
197 if (ret < 0)
199 gnutls_assert ();
200 return ret;
203 else
205 gnutls_assert ();
206 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
209 DECR_LEN (dsize, supp_data_length);
210 p += supp_data_length;
212 while (dsize > 0);
214 return 0;