/src/gnutls/lib/hello_ext.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright (C) 2001-2018 Free Software Foundation, Inc.  | 
3  |  |  * Copyright (C) 2015-2018 Red Hat, 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 License  | 
20  |  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>  | 
21  |  |  *  | 
22  |  |  */  | 
23  |  |  | 
24  |  | /* Functions that relate to the TLS hello extension parsing.  | 
25  |  |  * Hello extensions are packets appended in the TLS hello packet, and  | 
26  |  |  * allow for extra functionality.  | 
27  |  |  */  | 
28  |  |  | 
29  |  | #include "gnutls_int.h"  | 
30  |  | #include "hello_ext.h"  | 
31  |  | #include "errors.h"  | 
32  |  | #include "ext/max_record.h"  | 
33  |  | #include "ext/server_name.h"  | 
34  |  | #include "ext/srp.h"  | 
35  |  | #include "ext/heartbeat.h"  | 
36  |  | #include "ext/session_ticket.h"  | 
37  |  | #include "ext/safe_renegotiation.h"  | 
38  |  | #include "ext/signature.h"  | 
39  |  | #include "ext/safe_renegotiation.h"  | 
40  |  | #include "ext/supported_groups.h"  | 
41  |  | #include "ext/ec_point_formats.h"  | 
42  |  | #include "ext/status_request.h"  | 
43  |  | #include "ext/ext_master_secret.h"  | 
44  |  | #include "ext/supported_versions.h"  | 
45  |  | #include "ext/post_handshake.h"  | 
46  |  | #include "ext/srtp.h"  | 
47  |  | #include "ext/alpn.h"  | 
48  |  | #include "ext/dumbfw.h"  | 
49  |  | #include "ext/key_share.h"  | 
50  |  | #include "ext/pre_shared_key.h"  | 
51  |  | #include "ext/psk_ke_modes.h"  | 
52  |  | #include "ext/etm.h"  | 
53  |  | #include "ext/cookie.h"  | 
54  |  | #include "ext/early_data.h"  | 
55  |  | #include "ext/record_size_limit.h"  | 
56  |  | #include "extv.h"  | 
57  |  | #include "num.h"  | 
58  |  | #include "ext/client_cert_type.h"  | 
59  |  | #include "ext/server_cert_type.h"  | 
60  |  | #include "ext/compress_certificate.h"  | 
61  |  | #include "intprops.h"  | 
62  |  |  | 
63  |  | static void unset_ext_data(gnutls_session_t session,  | 
64  |  |          const struct hello_ext_entry_st *, unsigned idx);  | 
65  |  |  | 
66  |  | static void unset_resumed_ext_data(gnutls_session_t session,  | 
67  |  |            const struct hello_ext_entry_st *,  | 
68  |  |            unsigned idx);  | 
69  |  |  | 
70  |  | static hello_ext_entry_st const *extfunc[MAX_EXT_TYPES + 1] = { | 
71  |  |   [GNUTLS_EXTENSION_EXT_MASTER_SECRET] = &ext_mod_ext_master_secret,  | 
72  |  |   [GNUTLS_EXTENSION_SUPPORTED_VERSIONS] = &ext_mod_supported_versions,  | 
73  |  |   [GNUTLS_EXTENSION_POST_HANDSHAKE] = &ext_mod_post_handshake,  | 
74  |  |   [GNUTLS_EXTENSION_ETM] = &ext_mod_etm,  | 
75  |  | #ifdef ENABLE_OCSP  | 
76  |  |   [GNUTLS_EXTENSION_STATUS_REQUEST] = &ext_mod_status_request,  | 
77  |  | #endif  | 
78  |  |   [GNUTLS_EXTENSION_SERVER_NAME] = &ext_mod_server_name,  | 
79  |  |   [GNUTLS_EXTENSION_SAFE_RENEGOTIATION] = &ext_mod_sr,  | 
80  |  | #ifdef ENABLE_SRP  | 
81  |  |   [GNUTLS_EXTENSION_SRP] = &ext_mod_srp,  | 
82  |  | #endif  | 
83  |  | #ifdef ENABLE_HEARTBEAT  | 
84  |  |   [GNUTLS_EXTENSION_HEARTBEAT] = &ext_mod_heartbeat,  | 
85  |  | #endif  | 
86  |  |   [GNUTLS_EXTENSION_SESSION_TICKET] = &ext_mod_session_ticket,  | 
87  |  |   [GNUTLS_EXTENSION_CLIENT_CERT_TYPE] = &ext_mod_client_cert_type,  | 
88  |  |   [GNUTLS_EXTENSION_SERVER_CERT_TYPE] = &ext_mod_server_cert_type,  | 
89  |  |   [GNUTLS_EXTENSION_SUPPORTED_GROUPS] = &ext_mod_supported_groups,  | 
90  |  |   [GNUTLS_EXTENSION_SUPPORTED_EC_POINT_FORMATS] =  | 
91  |  |     &ext_mod_supported_ec_point_formats,  | 
92  |  |   [GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS] = &ext_mod_sig,  | 
93  |  |   [GNUTLS_EXTENSION_KEY_SHARE] = &ext_mod_key_share,  | 
94  |  |   [GNUTLS_EXTENSION_COOKIE] = &ext_mod_cookie,  | 
95  |  |   [GNUTLS_EXTENSION_EARLY_DATA] = &ext_mod_early_data,  | 
96  |  | #ifdef ENABLE_DTLS_SRTP  | 
97  |  |   [GNUTLS_EXTENSION_SRTP] = &ext_mod_srtp,  | 
98  |  | #endif  | 
99  |  | #ifdef ENABLE_ALPN  | 
100  |  |   [GNUTLS_EXTENSION_ALPN] = &ext_mod_alpn,  | 
101  |  | #endif  | 
102  |  |   [GNUTLS_EXTENSION_RECORD_SIZE_LIMIT] = &ext_mod_record_size_limit,  | 
103  |  |   [GNUTLS_EXTENSION_MAX_RECORD_SIZE] = &ext_mod_max_record_size,  | 
104  |  |   [GNUTLS_EXTENSION_PSK_KE_MODES] = &ext_mod_psk_ke_modes,  | 
105  |  |   [GNUTLS_EXTENSION_COMPRESS_CERTIFICATE] = &ext_mod_compress_certificate,  | 
106  |  |   [GNUTLS_EXTENSION_PRE_SHARED_KEY] = &ext_mod_pre_shared_key,  | 
107  |  |   /* This must be the last extension registered.  | 
108  |  |    */  | 
109  |  |   [GNUTLS_EXTENSION_DUMBFW] = &ext_mod_dumbfw,  | 
110  |  | };  | 
111  |  |  | 
112  |  | static const hello_ext_entry_st *gid_to_ext_entry(gnutls_session_t session,  | 
113  |  |               extensions_t id)  | 
114  | 0  | { | 
115  | 0  |   unsigned i;  | 
116  |  | 
  | 
117  | 0  |   assert(id < MAX_EXT_TYPES);  | 
118  |  |  | 
119  | 0  |   for (i = 0; i < session->internals.rexts_size; i++) { | 
120  | 0  |     if (session->internals.rexts[i].gid == id) { | 
121  | 0  |       return &session->internals.rexts[i];  | 
122  | 0  |     }  | 
123  | 0  |   }  | 
124  |  |  | 
125  | 0  |   return extfunc[id];  | 
126  | 0  | }  | 
127  |  |  | 
128  |  | static const hello_ext_entry_st *  | 
129  |  | tls_id_to_ext_entry(gnutls_session_t session, uint16_t tls_id,  | 
130  |  |         gnutls_ext_parse_type_t parse_point)  | 
131  | 0  | { | 
132  | 0  |   unsigned i;  | 
133  | 0  |   const hello_ext_entry_st *e;  | 
134  |  | 
  | 
135  | 0  |   for (i = 0; i < session->internals.rexts_size; i++) { | 
136  | 0  |     if (session->internals.rexts[i].tls_id == tls_id) { | 
137  | 0  |       e = &session->internals.rexts[i];  | 
138  | 0  |       goto done;  | 
139  | 0  |     }  | 
140  | 0  |   }  | 
141  |  |  | 
142  | 0  |   for (i = 0; i < MAX_EXT_TYPES; i++) { | 
143  | 0  |     if (!extfunc[i])  | 
144  | 0  |       continue;  | 
145  |  |  | 
146  | 0  |     if (extfunc[i]->tls_id == tls_id) { | 
147  | 0  |       e = extfunc[i];  | 
148  | 0  |       goto done;  | 
149  | 0  |     }  | 
150  | 0  |   }  | 
151  |  |  | 
152  | 0  |   return NULL;  | 
153  | 0  | done:  | 
154  | 0  |   if (parse_point == GNUTLS_EXT_ANY ||  | 
155  | 0  |       (IS_SERVER(session) && e->server_parse_point == parse_point) ||  | 
156  | 0  |       (!IS_SERVER(session) && e->client_parse_point == parse_point)) { | 
157  | 0  |     return e;  | 
158  | 0  |   } else { | 
159  | 0  |     return NULL;  | 
160  | 0  |   }  | 
161  | 0  | }  | 
162  |  |  | 
163  |  | /**  | 
164  |  |  * gnutls_ext_get_name:  | 
165  |  |  * @ext: is a TLS extension numeric ID  | 
166  |  |  *  | 
167  |  |  * Convert a TLS extension numeric ID to a printable string.  | 
168  |  |  *  | 
169  |  |  * Returns: a pointer to a string that contains the name of the  | 
170  |  |  *   specified cipher, or %NULL.  | 
171  |  |  **/  | 
172  |  | const char *gnutls_ext_get_name(unsigned int ext)  | 
173  | 0  | { | 
174  | 0  |   size_t i;  | 
175  |  | 
  | 
176  | 0  |   for (i = 0; i < MAX_EXT_TYPES; i++) { | 
177  | 0  |     if (!extfunc[i])  | 
178  | 0  |       continue;  | 
179  |  |  | 
180  | 0  |     if (extfunc[i]->tls_id == ext)  | 
181  | 0  |       return extfunc[i]->name;  | 
182  | 0  |   }  | 
183  |  |  | 
184  | 0  |   return NULL;  | 
185  | 0  | }  | 
186  |  |  | 
187  |  | /* Returns %GNUTLS_EXTENSION_INVALID on error  | 
188  |  |  */  | 
189  |  | static unsigned tls_id_to_gid(gnutls_session_t session, unsigned tls_id)  | 
190  | 0  | { | 
191  | 0  |   unsigned i;  | 
192  |  | 
  | 
193  | 0  |   for (i = 0; i < session->internals.rexts_size; i++) { | 
194  | 0  |     if (session->internals.rexts[i].tls_id == tls_id)  | 
195  | 0  |       return session->internals.rexts[i].gid;  | 
196  | 0  |   }  | 
197  |  |  | 
198  | 0  |   for (i = 0; i < MAX_EXT_TYPES; i++) { | 
199  | 0  |     if (!extfunc[i])  | 
200  | 0  |       continue;  | 
201  |  |  | 
202  | 0  |     if (extfunc[i]->tls_id == tls_id)  | 
203  | 0  |       return extfunc[i]->gid;  | 
204  | 0  |   }  | 
205  |  |  | 
206  | 0  |   return GNUTLS_EXTENSION_INVALID;  | 
207  | 0  | }  | 
208  |  |  | 
209  |  | typedef struct hello_ext_ctx_st { | 
210  |  |   gnutls_session_t session;  | 
211  |  |   gnutls_ext_flags_t msg;  | 
212  |  |   gnutls_ext_parse_type_t parse_point;  | 
213  |  |   const hello_ext_entry_st *ext; /* used during send */  | 
214  |  |   unsigned seen_pre_shared_key;  | 
215  |  | } hello_ext_ctx_st;  | 
216  |  |  | 
217  |  | static int hello_ext_parse(void *_ctx, unsigned tls_id, const uint8_t *data,  | 
218  |  |          unsigned data_size)  | 
219  | 0  | { | 
220  | 0  |   hello_ext_ctx_st *ctx = _ctx;  | 
221  | 0  |   gnutls_session_t session = ctx->session;  | 
222  | 0  |   const hello_ext_entry_st *ext;  | 
223  | 0  |   int ret;  | 
224  |  | 
  | 
225  | 0  |   if (tls_id == PRE_SHARED_KEY_TLS_ID) { | 
226  | 0  |     ctx->seen_pre_shared_key = 1;  | 
227  | 0  |   } else if (ctx->seen_pre_shared_key &&  | 
228  | 0  |        session->security_parameters.entity == GNUTLS_SERVER) { | 
229  |  |     /* the pre-shared key extension must always be the last one,  | 
230  |  |      * draft-ietf-tls-tls13-28: 4.2.11 */  | 
231  | 0  |     return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);  | 
232  | 0  |   }  | 
233  |  |  | 
234  | 0  |   ext = tls_id_to_ext_entry(session, tls_id, ctx->parse_point);  | 
235  | 0  |   if (ext == NULL || ext->recv_func == NULL) { | 
236  | 0  |     goto ignore;  | 
237  | 0  |   }  | 
238  |  |  | 
239  |  |   /* we do not hard fail when extensions defined for TLS are used for  | 
240  |  |    * DTLS and vice-versa. They may extend their role in the future. */  | 
241  | 0  |   if (IS_DTLS(session)) { | 
242  | 0  |     if (!(ext->validity & GNUTLS_EXT_FLAG_DTLS)) { | 
243  | 0  |       gnutls_assert();  | 
244  | 0  |       goto ignore;  | 
245  | 0  |     }  | 
246  | 0  |   } else { | 
247  | 0  |     if (!(ext->validity & GNUTLS_EXT_FLAG_TLS)) { | 
248  | 0  |       gnutls_assert();  | 
249  | 0  |       goto ignore;  | 
250  | 0  |     }  | 
251  | 0  |   }  | 
252  |  |  | 
253  | 0  |   if (session->security_parameters.entity == GNUTLS_CLIENT) { | 
254  | 0  |     if (!(ext->validity & GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST) &&  | 
255  | 0  |         !_gnutls_hello_ext_is_present(session, ext->gid)) { | 
256  | 0  |       _gnutls_debug_log(  | 
257  | 0  |         "EXT[%p]: Received unexpected extension '%s/%d'\n",  | 
258  | 0  |         session, ext->name, (int)tls_id);  | 
259  | 0  |       return gnutls_assert_val(  | 
260  | 0  |         GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);  | 
261  | 0  |     }  | 
262  | 0  |   }  | 
263  |  |  | 
264  | 0  |   if ((ext->validity & ctx->msg) == 0) { | 
265  | 0  |     _gnutls_debug_log(  | 
266  | 0  |       "EXT[%p]: Received unexpected extension (%s/%d) for '%s'\n",  | 
267  | 0  |       session, ext->name, (int)tls_id,  | 
268  | 0  |       ext_msg_validity_to_str(ctx->msg));  | 
269  | 0  |     return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);  | 
270  | 0  |   }  | 
271  |  |  | 
272  | 0  |   if (session->security_parameters.entity == GNUTLS_SERVER) { | 
273  | 0  |     ret = _gnutls_hello_ext_save(session, ext->gid, 1);  | 
274  | 0  |     if (ret == 0)  | 
275  | 0  |       return gnutls_assert_val(  | 
276  | 0  |         GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);  | 
277  | 0  |   }  | 
278  |  |  | 
279  | 0  |   _gnutls_handshake_log("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n", | 
280  | 0  |             session, ext->name, (int)tls_id, data_size);  | 
281  |  | 
  | 
282  | 0  |   _gnutls_ext_set_msg(session, ctx->msg);  | 
283  | 0  |   if ((ret = ext->recv_func(session, data, data_size)) < 0) { | 
284  | 0  |     gnutls_assert();  | 
285  | 0  |     return ret;  | 
286  | 0  |   }  | 
287  |  |  | 
288  | 0  |   return 0;  | 
289  |  |  | 
290  | 0  | ignore:  | 
291  | 0  |   if (ext) { | 
292  | 0  |     _gnutls_handshake_log("EXT[%p]: Ignoring extension '%s/%d'\n", | 
293  | 0  |               session, ext->name, (int)tls_id);  | 
294  | 0  |   }  | 
295  | 0  |   return 0;  | 
296  | 0  | }  | 
297  |  |  | 
298  |  | int _gnutls_parse_hello_extensions(gnutls_session_t session,  | 
299  |  |            gnutls_ext_flags_t msg,  | 
300  |  |            gnutls_ext_parse_type_t parse_point,  | 
301  |  |            const uint8_t *data, int data_size)  | 
302  | 0  | { | 
303  | 0  |   int ret;  | 
304  | 0  |   hello_ext_ctx_st ctx;  | 
305  |  | 
  | 
306  | 0  |   msg &= GNUTLS_EXT_FLAG_SET_ONLY_FLAGS_MASK;  | 
307  |  | 
  | 
308  | 0  |   ctx.session = session;  | 
309  | 0  |   ctx.msg = msg;  | 
310  | 0  |   ctx.parse_point = parse_point;  | 
311  | 0  |   ctx.seen_pre_shared_key = 0;  | 
312  |  | 
  | 
313  | 0  |   ret = _gnutls_extv_parse(&ctx, hello_ext_parse, data, data_size);  | 
314  | 0  |   if (ret < 0)  | 
315  | 0  |     return gnutls_assert_val(ret);  | 
316  |  |  | 
317  | 0  |   return 0;  | 
318  | 0  | }  | 
319  |  |  | 
320  |  | static int hello_ext_send(void *_ctx, gnutls_buffer_st *buf)  | 
321  | 0  | { | 
322  | 0  |   hello_ext_ctx_st *ctx = _ctx;  | 
323  | 0  |   int ret;  | 
324  | 0  |   const hello_ext_entry_st *p = ctx->ext;  | 
325  | 0  |   gnutls_session_t session = ctx->session;  | 
326  | 0  |   int appended;  | 
327  | 0  |   size_t size_prev;  | 
328  |  | 
  | 
329  | 0  |   if (unlikely(p->send_func == NULL))  | 
330  | 0  |     return 0;  | 
331  |  |  | 
332  | 0  |   if (ctx->parse_point != GNUTLS_EXT_ANY &&  | 
333  | 0  |       ((IS_SERVER(session) && p->server_parse_point != ctx->parse_point) ||  | 
334  | 0  |        (!IS_SERVER(session) &&  | 
335  | 0  |         p->client_parse_point != ctx->parse_point))) { | 
336  | 0  |     return 0;  | 
337  | 0  |   }  | 
338  |  |  | 
339  | 0  |   if (IS_DTLS(session)) { | 
340  | 0  |     if (!(p->validity & GNUTLS_EXT_FLAG_DTLS)) { | 
341  | 0  |       gnutls_assert();  | 
342  | 0  |       goto skip;  | 
343  | 0  |     }  | 
344  | 0  |   } else { | 
345  | 0  |     if (!(p->validity & GNUTLS_EXT_FLAG_TLS)) { | 
346  | 0  |       gnutls_assert();  | 
347  | 0  |       goto skip;  | 
348  | 0  |     }  | 
349  | 0  |   }  | 
350  |  |  | 
351  | 0  |   if ((ctx->msg & p->validity) == 0) { | 
352  | 0  |     goto skip;  | 
353  | 0  |   } else { | 
354  | 0  |     _gnutls_handshake_log(  | 
355  | 0  |       "EXT[%p]: Preparing extension (%s/%d) for '%s'\n",  | 
356  | 0  |       session, p->name, (int)p->tls_id,  | 
357  | 0  |       ext_msg_validity_to_str(ctx->msg));  | 
358  | 0  |   }  | 
359  |  |  | 
360  |  |   /* ensure we don't send something twice (i.e, overridden extensions in  | 
361  |  |    * client), and ensure we are sending only what we received in server. */  | 
362  | 0  |   ret = _gnutls_hello_ext_is_present(session, p->gid);  | 
363  |  | 
  | 
364  | 0  |   if (session->security_parameters.entity == GNUTLS_SERVER) { | 
365  |  |     /* if client didn't advertise and the override flag is not present */  | 
366  | 0  |     if (!(p->validity & GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST) &&  | 
367  | 0  |         ret == 0)  | 
368  | 0  |       return 0;  | 
369  | 0  |   } else { | 
370  | 0  |     if (ret != 0) /* already sent */  | 
371  | 0  |       return 0;  | 
372  | 0  |   }  | 
373  |  |  | 
374  | 0  |   size_prev = buf->length;  | 
375  |  | 
  | 
376  | 0  |   _gnutls_ext_set_msg(session, ctx->msg);  | 
377  | 0  |   ret = p->send_func(session, buf);  | 
378  | 0  |   if (ret < 0 && ret != GNUTLS_E_INT_RET_0) { | 
379  | 0  |     return gnutls_assert_val(ret);  | 
380  | 0  |   }  | 
381  |  |  | 
382  | 0  |   appended = buf->length - size_prev;  | 
383  |  |  | 
384  |  |   /* add this extension to the extension list, to know which extensions  | 
385  |  |    * to expect.  | 
386  |  |    */  | 
387  | 0  |   if ((appended > 0 || ret == GNUTLS_E_INT_RET_0) &&  | 
388  | 0  |       session->security_parameters.entity == GNUTLS_CLIENT) { | 
389  | 0  |     _gnutls_hello_ext_save(session, p->gid, 0);  | 
390  | 0  |   }  | 
391  |  | 
  | 
392  | 0  |   return ret;  | 
393  |  |  | 
394  | 0  | skip:  | 
395  | 0  |   _gnutls_handshake_log(  | 
396  | 0  |     "EXT[%p]: Not sending extension (%s/%d) for '%s'\n", session,  | 
397  | 0  |     p->name, (int)p->tls_id, ext_msg_validity_to_str(ctx->msg));  | 
398  | 0  |   return 0;  | 
399  | 0  | }  | 
400  |  |  | 
401  |  | static inline void swap_exts(extensions_t *exts, size_t index1, size_t index2)  | 
402  | 0  | { | 
403  | 0  |   extensions_t temp = exts[index1];  | 
404  | 0  |   exts[index1] = exts[index2];  | 
405  | 0  |   exts[index2] = temp;  | 
406  | 0  | }  | 
407  |  |  | 
408  |  | static int shuffle_exts(extensions_t *exts, size_t size)  | 
409  | 0  | { | 
410  | 0  |   uint8_t permutation[MAX_EXT_TYPES];  | 
411  | 0  |   size_t i;  | 
412  | 0  |   int ret;  | 
413  |  | 
  | 
414  | 0  |   assert(size <= MAX_EXT_TYPES);  | 
415  |  |  | 
416  | 0  |   if (unlikely(size == 0))  | 
417  | 0  |     return 0;  | 
418  |  |  | 
419  |  |   /* Generate random permutation, assuming MAX_EXT_TYPES <=  | 
420  |  |    * UINT8_MAX.  | 
421  |  |    */  | 
422  | 0  |   ret = gnutls_rnd(GNUTLS_RND_RANDOM, permutation, size);  | 
423  | 0  |   if (ret < 0)  | 
424  | 0  |     return gnutls_assert_val(ret);  | 
425  |  |  | 
426  | 0  |   for (i = size - 1; i > 0; i--) { | 
427  | 0  |     extensions_t j = permutation[i] % (i + 1);  | 
428  | 0  |     swap_exts(exts, i, j);  | 
429  | 0  |   }  | 
430  |  | 
  | 
431  | 0  |   return 0;  | 
432  | 0  | }  | 
433  |  |  | 
434  |  | int _gnutls_gen_hello_extensions(gnutls_session_t session,  | 
435  |  |          gnutls_buffer_st *buf, gnutls_ext_flags_t msg,  | 
436  |  |          gnutls_ext_parse_type_t parse_point)  | 
437  | 0  | { | 
438  | 0  |   int pos, ret;  | 
439  | 0  |   size_t i;  | 
440  | 0  |   hello_ext_ctx_st ctx;  | 
441  |  | 
  | 
442  | 0  |   msg &= GNUTLS_EXT_FLAG_SET_ONLY_FLAGS_MASK;  | 
443  |  | 
  | 
444  | 0  |   ctx.session = session;  | 
445  | 0  |   ctx.msg = msg;  | 
446  | 0  |   ctx.parse_point = parse_point;  | 
447  |  | 
  | 
448  | 0  |   ret = _gnutls_extv_append_init(buf);  | 
449  | 0  |   if (ret < 0)  | 
450  | 0  |     return gnutls_assert_val(ret);  | 
451  |  |  | 
452  | 0  |   pos = ret;  | 
453  | 0  |   _gnutls_ext_set_extensions_offset(session, pos);  | 
454  |  | 
  | 
455  | 0  |   for (i = 0; i < session->internals.rexts_size; i++) { | 
456  | 0  |     ctx.ext = &session->internals.rexts[i];  | 
457  | 0  |     ret = _gnutls_extv_append(buf,  | 
458  | 0  |             session->internals.rexts[i].tls_id,  | 
459  | 0  |             &ctx, hello_ext_send);  | 
460  | 0  |     if (ret < 0)  | 
461  | 0  |       return gnutls_assert_val(ret);  | 
462  |  |  | 
463  | 0  |     if (ret > 0)  | 
464  | 0  |       _gnutls_handshake_log(  | 
465  | 0  |         "EXT[%p]: Sending extension %s/%d (%d bytes)\n",  | 
466  | 0  |         session, ctx.ext->name, (int)ctx.ext->tls_id,  | 
467  | 0  |         ret - 4);  | 
468  | 0  |   }  | 
469  |  |  | 
470  | 0  |   if (msg & GNUTLS_EXT_FLAG_CLIENT_HELLO &&  | 
471  | 0  |       !session->internals.client_hello_exts_set) { | 
472  |  |     /* Initializing extensions array */  | 
473  | 0  |     for (i = 0; i < MAX_EXT_TYPES; i++) { | 
474  | 0  |       session->internals.client_hello_exts[i] = i;  | 
475  | 0  |     }  | 
476  |  | 
  | 
477  | 0  |     if (!session->internals.priorities->no_shuffle_extensions) { | 
478  |  |       /* Ordering padding and pre_shared_key as last extensions */  | 
479  | 0  |       swap_exts(session->internals.client_hello_exts,  | 
480  | 0  |           MAX_EXT_TYPES - 2, GNUTLS_EXTENSION_DUMBFW);  | 
481  | 0  |       swap_exts(session->internals.client_hello_exts,  | 
482  | 0  |           MAX_EXT_TYPES - 1,  | 
483  | 0  |           GNUTLS_EXTENSION_PRE_SHARED_KEY);  | 
484  |  | 
  | 
485  | 0  |       ret = shuffle_exts(session->internals.client_hello_exts,  | 
486  | 0  |              MAX_EXT_TYPES - 2);  | 
487  | 0  |       if (ret < 0)  | 
488  | 0  |         return gnutls_assert_val(ret);  | 
489  | 0  |     }  | 
490  | 0  |     session->internals.client_hello_exts_set = true;  | 
491  | 0  |   }  | 
492  |  |  | 
493  |  |   /* hello_ext_send() ensures we don't send duplicates, in case  | 
494  |  |    * of overridden extensions */  | 
495  | 0  |   for (i = 0; i < MAX_EXT_TYPES; i++) { | 
496  | 0  |     size_t ii;  | 
497  |  | 
  | 
498  | 0  |     if (msg & GNUTLS_EXT_FLAG_CLIENT_HELLO)  | 
499  | 0  |       ii = session->internals.client_hello_exts[i];  | 
500  | 0  |     else  | 
501  | 0  |       ii = i;  | 
502  |  | 
  | 
503  | 0  |     if (!extfunc[ii])  | 
504  | 0  |       continue;  | 
505  |  |  | 
506  | 0  |     ctx.ext = extfunc[ii];  | 
507  | 0  |     ret = _gnutls_extv_append(buf, extfunc[ii]->tls_id, &ctx,  | 
508  | 0  |             hello_ext_send);  | 
509  | 0  |     if (ret < 0)  | 
510  | 0  |       return gnutls_assert_val(ret);  | 
511  |  |  | 
512  | 0  |     if (ret > 0)  | 
513  | 0  |       _gnutls_handshake_log(  | 
514  | 0  |         "EXT[%p]: Sending extension %s/%d (%d bytes)\n",  | 
515  | 0  |         session, ctx.ext->name, (int)ctx.ext->tls_id,  | 
516  | 0  |         ret - 4);  | 
517  | 0  |   }  | 
518  |  |  | 
519  | 0  |   ret = _gnutls_extv_append_final(buf, pos, !(msg & GNUTLS_EXT_FLAG_EE));  | 
520  | 0  |   if (ret < 0)  | 
521  | 0  |     return gnutls_assert_val(ret);  | 
522  |  |  | 
523  | 0  |   return 0;  | 
524  | 0  | }  | 
525  |  |  | 
526  |  | /* Global deinit and init of global extensions */  | 
527  |  | int _gnutls_hello_ext_init(void)  | 
528  | 2  | { | 
529  | 2  |   return GNUTLS_E_SUCCESS;  | 
530  | 2  | }  | 
531  |  |  | 
532  |  | void _gnutls_hello_ext_deinit(void)  | 
533  | 0  | { | 
534  | 0  |   unsigned i;  | 
535  |  | 
  | 
536  | 0  |   for (i = 0; i < MAX_EXT_TYPES; i++) { | 
537  | 0  |     if (!extfunc[i])  | 
538  | 0  |       continue;  | 
539  |  |  | 
540  | 0  |     if (extfunc[i]->free_struct != 0) { | 
541  | 0  |       gnutls_free(((hello_ext_entry_st *)extfunc[i])->name);  | 
542  | 0  |       gnutls_free(extfunc[i]);  | 
543  | 0  |     }  | 
544  | 0  |   }  | 
545  | 0  | }  | 
546  |  |  | 
547  |  | /* Packing of extension data (for use in resumption) */  | 
548  |  | static int pack_extension(gnutls_session_t session,  | 
549  |  |         const hello_ext_entry_st *extp,  | 
550  |  |         gnutls_buffer_st *packed)  | 
551  | 0  | { | 
552  | 0  |   int ret;  | 
553  | 0  |   int size_offset;  | 
554  | 0  |   int cur_size;  | 
555  | 0  |   gnutls_ext_priv_data_t data;  | 
556  | 0  |   int rval = 0;  | 
557  |  | 
  | 
558  | 0  |   ret = _gnutls_hello_ext_get_priv(session, extp->gid, &data);  | 
559  | 0  |   if (ret >= 0 && extp->pack_func != NULL) { | 
560  | 0  |     BUFFER_APPEND_NUM(packed, extp->gid);  | 
561  |  | 
  | 
562  | 0  |     size_offset = packed->length;  | 
563  | 0  |     BUFFER_APPEND_NUM(packed, 0);  | 
564  |  | 
  | 
565  | 0  |     cur_size = packed->length;  | 
566  |  | 
  | 
567  | 0  |     ret = extp->pack_func(data, packed);  | 
568  | 0  |     if (ret < 0) { | 
569  | 0  |       gnutls_assert();  | 
570  | 0  |       return ret;  | 
571  | 0  |     }  | 
572  |  |  | 
573  | 0  |     rval = 1;  | 
574  |  |     /* write the actual size */  | 
575  | 0  |     _gnutls_write_uint32(packed->length - cur_size,  | 
576  | 0  |              packed->data + size_offset);  | 
577  | 0  |   }  | 
578  |  |  | 
579  | 0  |   return rval;  | 
580  | 0  | }  | 
581  |  |  | 
582  |  | int _gnutls_hello_ext_pack(gnutls_session_t session, gnutls_buffer_st *packed)  | 
583  | 0  | { | 
584  | 0  |   unsigned int i;  | 
585  | 0  |   int ret;  | 
586  | 0  |   int total_exts_pos;  | 
587  | 0  |   int n_exts = 0;  | 
588  | 0  |   const struct hello_ext_entry_st *ext;  | 
589  |  | 
  | 
590  | 0  |   total_exts_pos = packed->length;  | 
591  | 0  |   BUFFER_APPEND_NUM(packed, 0);  | 
592  |  | 
  | 
593  | 0  |   for (i = 0; i <= GNUTLS_EXTENSION_MAX_VALUE; i++) { | 
594  | 0  |     if (session->internals.used_exts & ((ext_track_t)1 << i)) { | 
595  | 0  |       ext = gid_to_ext_entry(session, i);  | 
596  | 0  |       if (ext == NULL)  | 
597  | 0  |         continue;  | 
598  |  |  | 
599  | 0  |       ret = pack_extension(session, ext, packed);  | 
600  | 0  |       if (ret < 0)  | 
601  | 0  |         return gnutls_assert_val(ret);  | 
602  |  |  | 
603  | 0  |       if (ret > 0)  | 
604  | 0  |         n_exts++;  | 
605  | 0  |     }  | 
606  | 0  |   }  | 
607  |  |  | 
608  | 0  |   _gnutls_write_uint32(n_exts, packed->data + total_exts_pos);  | 
609  |  | 
  | 
610  | 0  |   return 0;  | 
611  | 0  | }  | 
612  |  |  | 
613  |  | int _gnutls_ext_set_full_client_hello(gnutls_session_t session,  | 
614  |  |               handshake_buffer_st *recv_buf)  | 
615  | 0  | { | 
616  | 0  |   int ret;  | 
617  | 0  |   gnutls_buffer_st *buf = &session->internals.full_client_hello;  | 
618  |  | 
  | 
619  | 0  |   _gnutls_buffer_clear(buf);  | 
620  |  | 
  | 
621  | 0  |   if ((ret = _gnutls_buffer_append_prefix(buf, 8, recv_buf->htype)) < 0)  | 
622  | 0  |     return gnutls_assert_val(ret);  | 
623  | 0  |   if ((ret = _gnutls_buffer_append_prefix(buf, 24,  | 
624  | 0  |             recv_buf->data.length)) < 0)  | 
625  | 0  |     return gnutls_assert_val(ret);  | 
626  | 0  |   if ((ret = _gnutls_buffer_append_data(buf, recv_buf->data.data,  | 
627  | 0  |                 recv_buf->data.length)) < 0)  | 
628  | 0  |     return gnutls_assert_val(ret);  | 
629  |  |  | 
630  | 0  |   return 0;  | 
631  | 0  | }  | 
632  |  |  | 
633  |  | unsigned _gnutls_ext_get_full_client_hello(gnutls_session_t session,  | 
634  |  |              gnutls_datum_t *d)  | 
635  | 0  | { | 
636  | 0  |   gnutls_buffer_st *buf = &session->internals.full_client_hello;  | 
637  |  | 
  | 
638  | 0  |   if (!buf->length)  | 
639  | 0  |     return 0;  | 
640  |  |  | 
641  | 0  |   d->data = buf->data;  | 
642  | 0  |   d->size = buf->length;  | 
643  |  | 
  | 
644  | 0  |   return 1;  | 
645  | 0  | }  | 
646  |  |  | 
647  |  | static void _gnutls_ext_set_resumed_session_data(gnutls_session_t session,  | 
648  |  |              extensions_t id,  | 
649  |  |              gnutls_ext_priv_data_t data)  | 
650  | 0  | { | 
651  | 0  |   const struct hello_ext_entry_st *ext;  | 
652  |  |  | 
653  |  |   /* If this happens we need to increase the max */  | 
654  | 0  |   assert(id < MAX_EXT_TYPES);  | 
655  |  |  | 
656  | 0  |   ext = gid_to_ext_entry(session, id);  | 
657  | 0  |   assert(ext != NULL);  | 
658  |  |  | 
659  | 0  |   if (session->internals.ext_data[id].resumed_set != 0)  | 
660  | 0  |     unset_resumed_ext_data(session, ext, id);  | 
661  |  | 
  | 
662  | 0  |   session->internals.ext_data[id].resumed_priv = data;  | 
663  | 0  |   session->internals.ext_data[id].resumed_set = 1;  | 
664  | 0  |   return;  | 
665  | 0  | }  | 
666  |  |  | 
667  |  | int _gnutls_hello_ext_unpack(gnutls_session_t session, gnutls_buffer_st *packed)  | 
668  | 0  | { | 
669  | 0  |   int i, ret;  | 
670  | 0  |   gnutls_ext_priv_data_t data;  | 
671  | 0  |   int max_exts = 0;  | 
672  | 0  |   extensions_t id;  | 
673  | 0  |   int size_for_id, cur_pos;  | 
674  | 0  |   const struct hello_ext_entry_st *ext;  | 
675  |  | 
  | 
676  | 0  |   BUFFER_POP_NUM(packed, max_exts);  | 
677  | 0  |   for (i = 0; i < max_exts; i++) { | 
678  | 0  |     BUFFER_POP_NUM(packed, id);  | 
679  | 0  |     BUFFER_POP_NUM(packed, size_for_id);  | 
680  |  | 
  | 
681  | 0  |     cur_pos = packed->length;  | 
682  |  | 
  | 
683  | 0  |     ext = gid_to_ext_entry(session, id);  | 
684  | 0  |     if (ext == NULL || ext->unpack_func == NULL) { | 
685  | 0  |       gnutls_assert();  | 
686  | 0  |       return GNUTLS_E_PARSING_ERROR;  | 
687  | 0  |     }  | 
688  |  |  | 
689  | 0  |     ret = ext->unpack_func(packed, &data);  | 
690  | 0  |     if (ret < 0) { | 
691  | 0  |       gnutls_assert();  | 
692  | 0  |       return ret;  | 
693  | 0  |     }  | 
694  |  |  | 
695  |  |     /* verify that unpack read the correct bytes */  | 
696  | 0  |     cur_pos = cur_pos - packed->length;  | 
697  | 0  |     if (cur_pos /* read length */ != size_for_id) { | 
698  | 0  |       gnutls_assert();  | 
699  | 0  |       return GNUTLS_E_PARSING_ERROR;  | 
700  | 0  |     }  | 
701  |  |  | 
702  | 0  |     _gnutls_ext_set_resumed_session_data(session, id, data);  | 
703  | 0  |   }  | 
704  |  |  | 
705  | 0  |   return 0;  | 
706  |  |  | 
707  | 0  | error:  | 
708  | 0  |   return ret;  | 
709  | 0  | }  | 
710  |  |  | 
711  |  | static void unset_ext_data(gnutls_session_t session,  | 
712  |  |          const struct hello_ext_entry_st *ext, unsigned idx)  | 
713  | 0  | { | 
714  | 0  |   if (session->internals.ext_data[idx].set == 0)  | 
715  | 0  |     return;  | 
716  |  |  | 
717  | 0  |   if (ext && ext->deinit_func &&  | 
718  | 0  |       session->internals.ext_data[idx].priv != NULL)  | 
719  | 0  |     ext->deinit_func(session->internals.ext_data[idx].priv);  | 
720  | 0  |   session->internals.ext_data[idx].set = 0;  | 
721  | 0  | }  | 
722  |  |  | 
723  |  | void _gnutls_hello_ext_unset_priv(gnutls_session_t session, extensions_t id)  | 
724  | 0  | { | 
725  | 0  |   const struct hello_ext_entry_st *ext;  | 
726  |  | 
  | 
727  | 0  |   ext = gid_to_ext_entry(session, id);  | 
728  | 0  |   if (ext)  | 
729  | 0  |     unset_ext_data(session, ext, id);  | 
730  | 0  | }  | 
731  |  |  | 
732  |  | static void unset_resumed_ext_data(gnutls_session_t session,  | 
733  |  |            const struct hello_ext_entry_st *ext,  | 
734  |  |            unsigned idx)  | 
735  | 0  | { | 
736  | 0  |   if (session->internals.ext_data[idx].resumed_set == 0)  | 
737  | 0  |     return;  | 
738  |  |  | 
739  | 0  |   if (ext && ext->deinit_func &&  | 
740  | 0  |       session->internals.ext_data[idx].resumed_priv) { | 
741  | 0  |     ext->deinit_func(session->internals.ext_data[idx].resumed_priv);  | 
742  | 0  |   }  | 
743  | 0  |   session->internals.ext_data[idx].resumed_set = 0;  | 
744  | 0  | }  | 
745  |  |  | 
746  |  | /* Deinitializes all data that are associated with TLS extensions.  | 
747  |  |  */  | 
748  |  | void _gnutls_hello_ext_priv_deinit(gnutls_session_t session)  | 
749  | 0  | { | 
750  | 0  |   unsigned int i;  | 
751  | 0  |   const struct hello_ext_entry_st *ext;  | 
752  |  | 
  | 
753  | 0  |   for (i = 0; i < MAX_EXT_TYPES; i++) { | 
754  | 0  |     if (!session->internals.ext_data[i].set &&  | 
755  | 0  |         !session->internals.ext_data[i].resumed_set)  | 
756  | 0  |       continue;  | 
757  |  |  | 
758  | 0  |     ext = gid_to_ext_entry(session, i);  | 
759  | 0  |     if (ext) { | 
760  | 0  |       unset_ext_data(session, ext, i);  | 
761  | 0  |       unset_resumed_ext_data(session, ext, i);  | 
762  | 0  |     }  | 
763  | 0  |   }  | 
764  | 0  | }  | 
765  |  |  | 
766  |  | /* This function allows an extension to store data in the current session  | 
767  |  |  * and retrieve them later on. We use functions instead of a pointer to a  | 
768  |  |  * private pointer, to allow API additions by individual extensions.  | 
769  |  |  */  | 
770  |  | void _gnutls_hello_ext_set_priv(gnutls_session_t session, extensions_t id,  | 
771  |  |         gnutls_ext_priv_data_t data)  | 
772  | 0  | { | 
773  | 0  |   const struct hello_ext_entry_st *ext;  | 
774  |  | 
  | 
775  | 0  |   assert(id < MAX_EXT_TYPES);  | 
776  |  |  | 
777  | 0  |   ext = gid_to_ext_entry(session, id);  | 
778  | 0  |   assert(ext != NULL);  | 
779  |  |  | 
780  | 0  |   if (session->internals.ext_data[id].set != 0) { | 
781  | 0  |     unset_ext_data(session, ext, id);  | 
782  | 0  |   }  | 
783  | 0  |   session->internals.ext_data[id].priv = data;  | 
784  | 0  |   session->internals.ext_data[id].set = 1;  | 
785  |  | 
  | 
786  | 0  |   return;  | 
787  | 0  | }  | 
788  |  |  | 
789  |  | int _gnutls_hello_ext_get_priv(gnutls_session_t session, extensions_t id,  | 
790  |  |              gnutls_ext_priv_data_t *data)  | 
791  | 0  | { | 
792  | 0  |   if (session->internals.ext_data[id].set != 0) { | 
793  | 0  |     *data = session->internals.ext_data[id].priv;  | 
794  | 0  |     return 0;  | 
795  | 0  |   }  | 
796  |  |  | 
797  | 0  |   return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;  | 
798  | 0  | }  | 
799  |  |  | 
800  |  | int _gnutls_hello_ext_get_resumed_priv(gnutls_session_t session,  | 
801  |  |                extensions_t id,  | 
802  |  |                gnutls_ext_priv_data_t *data)  | 
803  | 0  | { | 
804  | 0  |   if (session->internals.ext_data[id].resumed_set != 0) { | 
805  | 0  |     *data = session->internals.ext_data[id].resumed_priv;  | 
806  | 0  |     return 0;  | 
807  | 0  |   }  | 
808  |  |  | 
809  | 0  |   return GNUTLS_E_INVALID_REQUEST;  | 
810  | 0  | }  | 
811  |  |  | 
812  |  | /**  | 
813  |  |  * gnutls_ext_register:  | 
814  |  |  * @name: the name of the extension to register  | 
815  |  |  * @id: the numeric TLS id of the extension  | 
816  |  |  * @parse_point: the parse type of the extension (see gnutls_ext_parse_type_t)  | 
817  |  |  * @recv_func: a function to receive the data  | 
818  |  |  * @send_func: a function to send the data  | 
819  |  |  * @deinit_func: a function deinitialize any private data  | 
820  |  |  * @pack_func: a function which serializes the extension's private data (used on session packing for resumption)  | 
821  |  |  * @unpack_func: a function which will deserialize the extension's private data  | 
822  |  |  *  | 
823  |  |  * This function will register a new extension type. The extension will remain  | 
824  |  |  * registered until gnutls_global_deinit() is called. If the extension type  | 
825  |  |  * is already registered then %GNUTLS_E_ALREADY_REGISTERED will be returned.  | 
826  |  |  *  | 
827  |  |  * Each registered extension can store temporary data into the gnutls_session_t  | 
828  |  |  * structure using gnutls_ext_set_data(), and they can be retrieved using  | 
829  |  |  * gnutls_ext_get_data().  | 
830  |  |  *  | 
831  |  |  * Any extensions registered with this function are valid for the client  | 
832  |  |  * and TLS1.2 server hello (or encrypted extensions for TLS1.3).  | 
833  |  |  *  | 
834  |  |  * This function is not thread safe.  | 
835  |  |  *  | 
836  |  |  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.  | 
837  |  |  *  | 
838  |  |  * Since: 3.4.0  | 
839  |  |  **/  | 
840  |  | int gnutls_ext_register(const char *name, int id,  | 
841  |  |       gnutls_ext_parse_type_t parse_point,  | 
842  |  |       gnutls_ext_recv_func recv_func,  | 
843  |  |       gnutls_ext_send_func send_func,  | 
844  |  |       gnutls_ext_deinit_data_func deinit_func,  | 
845  |  |       gnutls_ext_pack_func pack_func,  | 
846  |  |       gnutls_ext_unpack_func unpack_func)  | 
847  | 0  | { | 
848  | 0  |   hello_ext_entry_st *tmp_mod;  | 
849  | 0  |   unsigned i;  | 
850  | 0  |   unsigned gid = GNUTLS_EXTENSION_MAX + 1;  | 
851  |  | 
  | 
852  | 0  |   for (i = 0; i < MAX_EXT_TYPES; i++) { | 
853  | 0  |     if (!extfunc[i])  | 
854  | 0  |       continue;  | 
855  |  |  | 
856  | 0  |     if (extfunc[i]->tls_id == id)  | 
857  | 0  |       return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);  | 
858  |  |  | 
859  | 0  |     if (extfunc[i]->gid >= gid)  | 
860  | 0  |       gid = extfunc[i]->gid + 1;  | 
861  | 0  |   }  | 
862  |  |  | 
863  | 0  |   assert(gid < sizeof(extfunc) / sizeof(extfunc[0]));  | 
864  | 0  |   if (gid > GNUTLS_EXTENSION_MAX_VALUE)  | 
865  | 0  |     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);  | 
866  |  |  | 
867  | 0  |   tmp_mod = gnutls_calloc(1, sizeof(*tmp_mod));  | 
868  | 0  |   if (tmp_mod == NULL)  | 
869  | 0  |     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);  | 
870  |  |  | 
871  | 0  |   tmp_mod->name = gnutls_strdup(name);  | 
872  | 0  |   tmp_mod->free_struct = 1;  | 
873  | 0  |   tmp_mod->tls_id = id;  | 
874  | 0  |   tmp_mod->gid = gid;  | 
875  | 0  |   tmp_mod->client_parse_point = parse_point;  | 
876  | 0  |   tmp_mod->server_parse_point = parse_point;  | 
877  | 0  |   tmp_mod->recv_func = recv_func;  | 
878  | 0  |   tmp_mod->send_func = send_func;  | 
879  | 0  |   tmp_mod->deinit_func = deinit_func;  | 
880  | 0  |   tmp_mod->pack_func = pack_func;  | 
881  | 0  |   tmp_mod->unpack_func = unpack_func;  | 
882  | 0  |   tmp_mod->validity = GNUTLS_EXT_FLAG_CLIENT_HELLO |  | 
883  | 0  |           GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |  | 
884  | 0  |           GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_DTLS |  | 
885  | 0  |           GNUTLS_EXT_FLAG_TLS;  | 
886  |  | 
  | 
887  | 0  |   assert(extfunc[gid] == NULL);  | 
888  | 0  |   extfunc[gid] = tmp_mod;  | 
889  |  | 
  | 
890  | 0  |   return 0;  | 
891  | 0  | }  | 
892  |  |  | 
893  |  | #define VALIDITY_MASK                                                        \  | 
894  | 0  |   (GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO | \  | 
895  | 0  |    GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | GNUTLS_EXT_FLAG_EE |           \  | 
896  | 0  |    GNUTLS_EXT_FLAG_HRR)  | 
897  |  |  | 
898  |  | /**  | 
899  |  |  * gnutls_session_ext_register:  | 
900  |  |  * @session: the session for which this extension will be set  | 
901  |  |  * @name: the name of the extension to register  | 
902  |  |  * @id: the numeric id of the extension  | 
903  |  |  * @parse_point: the parse type of the extension (see gnutls_ext_parse_type_t)  | 
904  |  |  * @recv_func: a function to receive the data  | 
905  |  |  * @send_func: a function to send the data  | 
906  |  |  * @deinit_func: a function deinitialize any private data  | 
907  |  |  * @pack_func: a function which serializes the extension's private data (used on session packing for resumption)  | 
908  |  |  * @unpack_func: a function which will deserialize the extension's private data  | 
909  |  |  * @flags: must be zero or flags from %gnutls_ext_flags_t  | 
910  |  |  *  | 
911  |  |  * This function will register a new extension type. The extension will be  | 
912  |  |  * only usable within the registered session. If the extension type  | 
913  |  |  * is already registered then %GNUTLS_E_ALREADY_REGISTERED will be returned,  | 
914  |  |  * unless the flag %GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL is specified. The latter  | 
915  |  |  * flag when specified can be used to override certain extensions introduced  | 
916  |  |  * after 3.6.0. It is expected to be used by applications which handle  | 
917  |  |  * custom extensions that are not currently supported in GnuTLS, but direct  | 
918  |  |  * support for them may be added in the future.  | 
919  |  |  *  | 
920  |  |  * Each registered extension can store temporary data into the gnutls_session_t  | 
921  |  |  * structure using gnutls_ext_set_data(), and they can be retrieved using  | 
922  |  |  * gnutls_ext_get_data().  | 
923  |  |  *  | 
924  |  |  * The validity of the extension registered can be given by the appropriate flags  | 
925  |  |  * of %gnutls_ext_flags_t. If no validity is given, then the registered extension  | 
926  |  |  * will be valid for client and TLS1.2 server hello (or encrypted extensions for TLS1.3).  | 
927  |  |  *  | 
928  |  |  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.  | 
929  |  |  *  | 
930  |  |  * Since: 3.5.5  | 
931  |  |  **/  | 
932  |  | int gnutls_session_ext_register(gnutls_session_t session, const char *name,  | 
933  |  |         int id, gnutls_ext_parse_type_t parse_point,  | 
934  |  |         gnutls_ext_recv_func recv_func,  | 
935  |  |         gnutls_ext_send_func send_func,  | 
936  |  |         gnutls_ext_deinit_data_func deinit_func,  | 
937  |  |         gnutls_ext_pack_func pack_func,  | 
938  |  |         gnutls_ext_unpack_func unpack_func,  | 
939  |  |         unsigned flags)  | 
940  | 0  | { | 
941  | 0  |   hello_ext_entry_st tmp_mod;  | 
942  | 0  |   hello_ext_entry_st *exts;  | 
943  | 0  |   unsigned i;  | 
944  | 0  |   unsigned gid = GNUTLS_EXTENSION_MAX + 1;  | 
945  |  |  | 
946  |  |   /* reject handling any extensions which modify the TLS handshake  | 
947  |  |    * in any way, or are mapped to an exported API. */  | 
948  | 0  |   for (i = 0; i < GNUTLS_EXTENSION_MAX; i++) { | 
949  | 0  |     if (!extfunc[i])  | 
950  | 0  |       continue;  | 
951  |  |  | 
952  | 0  |     if (extfunc[i]->tls_id == id) { | 
953  | 0  |       if (!(flags & GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL)) { | 
954  | 0  |         return gnutls_assert_val(  | 
955  | 0  |           GNUTLS_E_ALREADY_REGISTERED);  | 
956  | 0  |       } else if (extfunc[i]->cannot_be_overriden) { | 
957  | 0  |         return gnutls_assert_val(  | 
958  | 0  |           GNUTLS_E_ALREADY_REGISTERED);  | 
959  | 0  |       }  | 
960  | 0  |       break;  | 
961  | 0  |     }  | 
962  |  |  | 
963  | 0  |     if (extfunc[i]->gid >= gid)  | 
964  | 0  |       gid = extfunc[i]->gid + 1;  | 
965  | 0  |   }  | 
966  |  |  | 
967  | 0  |   for (i = 0; i < session->internals.rexts_size; i++) { | 
968  | 0  |     if (session->internals.rexts[i].tls_id == id) { | 
969  | 0  |       return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);  | 
970  | 0  |     }  | 
971  |  |  | 
972  | 0  |     if (session->internals.rexts[i].gid >= gid)  | 
973  | 0  |       gid = session->internals.rexts[i].gid + 1;  | 
974  | 0  |   }  | 
975  |  |  | 
976  | 0  |   if (gid > GNUTLS_EXTENSION_MAX_VALUE)  | 
977  | 0  |     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);  | 
978  |  |  | 
979  | 0  |   memset(&tmp_mod, 0, sizeof(hello_ext_entry_st));  | 
980  | 0  |   tmp_mod.name = gnutls_strdup(name);  | 
981  | 0  |   tmp_mod.free_struct = 1;  | 
982  | 0  |   tmp_mod.tls_id = id;  | 
983  | 0  |   tmp_mod.gid = gid;  | 
984  | 0  |   tmp_mod.client_parse_point = parse_point;  | 
985  | 0  |   tmp_mod.server_parse_point = parse_point;  | 
986  | 0  |   tmp_mod.recv_func = recv_func;  | 
987  | 0  |   tmp_mod.send_func = send_func;  | 
988  | 0  |   tmp_mod.deinit_func = deinit_func;  | 
989  | 0  |   tmp_mod.pack_func = pack_func;  | 
990  | 0  |   tmp_mod.unpack_func = unpack_func;  | 
991  | 0  |   tmp_mod.validity = flags;  | 
992  |  | 
  | 
993  | 0  |   if ((tmp_mod.validity & VALIDITY_MASK) == 0) { | 
994  | 0  |     tmp_mod.validity = GNUTLS_EXT_FLAG_CLIENT_HELLO |  | 
995  | 0  |            GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |  | 
996  | 0  |            GNUTLS_EXT_FLAG_EE;  | 
997  | 0  |   }  | 
998  |  | 
  | 
999  | 0  |   if ((tmp_mod.validity & (GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_TLS)) ==  | 
1000  | 0  |       0) { | 
1001  | 0  |     if (IS_DTLS(session))  | 
1002  | 0  |       tmp_mod.validity |= GNUTLS_EXT_FLAG_DTLS;  | 
1003  | 0  |     else  | 
1004  | 0  |       tmp_mod.validity |= GNUTLS_EXT_FLAG_TLS;  | 
1005  | 0  |   }  | 
1006  |  | 
  | 
1007  | 0  |   if (unlikely(INT_ADD_OVERFLOW(session->internals.rexts_size, 1))) { | 
1008  | 0  |     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);  | 
1009  | 0  |   }  | 
1010  |  |  | 
1011  | 0  |   exts = _gnutls_reallocarray(session->internals.rexts,  | 
1012  | 0  |             session->internals.rexts_size + 1,  | 
1013  | 0  |             sizeof(*exts));  | 
1014  | 0  |   if (exts == NULL) { | 
1015  | 0  |     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);  | 
1016  | 0  |   }  | 
1017  |  |  | 
1018  | 0  |   session->internals.rexts = exts;  | 
1019  |  | 
  | 
1020  | 0  |   memcpy(&session->internals.rexts[session->internals.rexts_size],  | 
1021  | 0  |          &tmp_mod, sizeof(hello_ext_entry_st));  | 
1022  | 0  |   session->internals.rexts_size++;  | 
1023  |  | 
  | 
1024  | 0  |   return 0;  | 
1025  | 0  | }  | 
1026  |  |  | 
1027  |  | /**  | 
1028  |  |  * gnutls_ext_set_data:  | 
1029  |  |  * @session: a #gnutls_session_t opaque pointer  | 
1030  |  |  * @tls_id: the numeric id of the extension  | 
1031  |  |  * @data: the private data to set  | 
1032  |  |  *  | 
1033  |  |  * This function allows an extension handler to store data in the current session  | 
1034  |  |  * and retrieve them later on. The set data will be deallocated using  | 
1035  |  |  * the gnutls_ext_deinit_data_func.  | 
1036  |  |  *  | 
1037  |  |  * Since: 3.4.0  | 
1038  |  |  **/  | 
1039  |  | void gnutls_ext_set_data(gnutls_session_t session, unsigned tls_id,  | 
1040  |  |        gnutls_ext_priv_data_t data)  | 
1041  | 0  | { | 
1042  | 0  |   unsigned id = tls_id_to_gid(session, tls_id);  | 
1043  | 0  |   if (id == GNUTLS_EXTENSION_INVALID)  | 
1044  | 0  |     return;  | 
1045  |  |  | 
1046  | 0  |   _gnutls_hello_ext_set_priv(session, id, data);  | 
1047  | 0  | }  | 
1048  |  |  | 
1049  |  | /**  | 
1050  |  |  * gnutls_ext_get_data:  | 
1051  |  |  * @session: a #gnutls_session_t opaque pointer  | 
1052  |  |  * @tls_id: the numeric id of the extension  | 
1053  |  |  * @data: a pointer to the private data to retrieve  | 
1054  |  |  *  | 
1055  |  |  * This function retrieves any data previously stored with gnutls_ext_set_data().  | 
1056  |  |  *  | 
1057  |  |  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.  | 
1058  |  |  *  | 
1059  |  |  * Since: 3.4.0  | 
1060  |  |  **/  | 
1061  |  | int gnutls_ext_get_data(gnutls_session_t session, unsigned tls_id,  | 
1062  |  |       gnutls_ext_priv_data_t *data)  | 
1063  | 0  | { | 
1064  | 0  |   unsigned id = tls_id_to_gid(session, tls_id);  | 
1065  | 0  |   if (id == GNUTLS_EXTENSION_INVALID)  | 
1066  | 0  |     return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);  | 
1067  |  |  | 
1068  | 0  |   return _gnutls_hello_ext_get_priv(session, id, data);  | 
1069  | 0  | }  | 
1070  |  |  | 
1071  |  | /**  | 
1072  |  |  * gnutls_ext_get_current_msg:  | 
1073  |  |  * @session: a #gnutls_session_t opaque pointer  | 
1074  |  |  *  | 
1075  |  |  * This function allows an extension handler to obtain the message  | 
1076  |  |  * this extension is being called from. The returned value is a single  | 
1077  |  |  * entry of the %gnutls_ext_flags_t enumeration. That is, if an  | 
1078  |  |  * extension was registered with the %GNUTLS_EXT_FLAG_HRR and  | 
1079  |  |  * %GNUTLS_EXT_FLAG_EE flags, the value when called during parsing of the  | 
1080  |  |  * encrypted extensions message will be %GNUTLS_EXT_FLAG_EE.  | 
1081  |  |  *  | 
1082  |  |  * If not called under an extension handler, its value is undefined.  | 
1083  |  |  *  | 
1084  |  |  * Since: 3.6.3  | 
1085  |  |  **/  | 
1086  |  | unsigned gnutls_ext_get_current_msg(gnutls_session_t session)  | 
1087  | 0  | { | 
1088  | 0  |   return _gnutls_ext_get_msg(session);  | 
1089  | 0  | }  | 
1090  |  |  | 
1091  |  | /**  | 
1092  |  |  * gnutls_ext_get_name2:  | 
1093  |  |  * @session: a #gnutls_session_t opaque pointer  | 
1094  |  |  * @tls_id: is a TLS extension numeric ID  | 
1095  |  |  * @parse_point: the parse type of the extension  | 
1096  |  |  *  | 
1097  |  |  * Convert a TLS extension numeric ID to a printable string.  | 
1098  |  |  *  | 
1099  |  |  * Returns: a pointer to a string that contains the name of the  | 
1100  |  |  *   specified cipher, or %NULL.  | 
1101  |  |  **/  | 
1102  |  | const char *gnutls_ext_get_name2(gnutls_session_t session, unsigned int tls_id,  | 
1103  |  |          gnutls_ext_parse_type_t parse_point)  | 
1104  | 0  | { | 
1105  | 0  |   const struct hello_ext_entry_st *ext;  | 
1106  |  | 
  | 
1107  | 0  |   ext = tls_id_to_ext_entry(session, tls_id, parse_point);  | 
1108  | 0  |   if (ext)  | 
1109  | 0  |     return ext->name;  | 
1110  |  |  | 
1111  | 0  |   return NULL;  | 
1112  | 0  | }  |