Line data Source code
1 : /*
2 : * Copyright (C) 2017-2018 Red Hat, Inc.
3 : *
4 : * Author: Nikos Mavrogiannopoulos
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 License
19 : * along with this program. If not, see <https://www.gnu.org/licenses/>
20 : *
21 : */
22 :
23 : #include "gnutls_int.h"
24 : #include "hello_ext.h"
25 : #include "errors.h"
26 : #include "extv.h"
27 :
28 : /* Iterates through all extensions found, and calls the cb()
29 : * function with their data */
30 102339 : int _gnutls_extv_parse(void *ctx,
31 : gnutls_ext_raw_process_func cb,
32 : const uint8_t * data, int data_size)
33 : {
34 102339 : int next, ret;
35 102339 : int pos = 0;
36 102339 : uint16_t tls_id;
37 102339 : const uint8_t *sdata;
38 102339 : uint16_t size;
39 :
40 102339 : if (data_size == 0)
41 : return 0;
42 :
43 93817 : DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
44 93809 : next = _gnutls_read_uint16(data);
45 93809 : pos += 2;
46 :
47 93809 : DECR_LENGTH_RET(data_size, next, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
48 :
49 93524 : if (next == 0 && data_size == 0) /* field is present, but has zero length? Ignore it. */
50 : return 0;
51 92284 : else if (data_size > 0) /* forbid unaccounted data */
52 119 : return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
53 :
54 1400200 : do {
55 1400200 : DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
56 1400190 : tls_id = _gnutls_read_uint16(&data[pos]);
57 1400190 : pos += 2;
58 :
59 1400190 : DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
60 1400180 : size = _gnutls_read_uint16(&data[pos]);
61 1400180 : pos += 2;
62 :
63 1400180 : DECR_LENGTH_RET(next, size, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
64 1400100 : sdata = &data[pos];
65 1400100 : pos += size;
66 :
67 1400100 : ret = cb(ctx, tls_id, sdata, size);
68 1400100 : if (ret < 0)
69 2417 : return gnutls_assert_val(ret);
70 : }
71 1398200 : while (next > 2);
72 :
73 : /* forbid leftovers */
74 90211 : if (next > 0)
75 21 : return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
76 :
77 : return 0;
78 : }
79 :
80 : #define HANDSHAKE_SESSION_ID_POS (34)
81 : /**
82 : * gnutls_ext_raw_parse:
83 : * @ctx: a pointer to pass to callback function
84 : * @cb: callback function to process each extension found
85 : * @data: TLS extension data
86 : * @flags: should be zero or %GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO or %GNUTLS_EXT_RAW_FLAG_DTLS_CLIENT_HELLO
87 : *
88 : * This function iterates through the TLS extensions as passed in
89 : * @data, passing the individual extension data to callback. The
90 : * @data must conform to Extension extensions<0..2^16-1> format.
91 : *
92 : * If flags is %GNUTLS_EXT_RAW_TLS_FLAG_CLIENT_HELLO then this function
93 : * will parse the extension data from the position, as if the packet in
94 : * @data is a client hello (without record or handshake headers) -
95 : * as provided by gnutls_handshake_set_hook_function().
96 : *
97 : * The return value of the callback will be propagated.
98 : *
99 : * Returns: %GNUTLS_E_SUCCESS on success, or an error code. On unknown
100 : * flags it returns %GNUTLS_E_INVALID_REQUEST.
101 : *
102 : * Since: 3.6.3
103 : **/
104 163 : int gnutls_ext_raw_parse(void *ctx, gnutls_ext_raw_process_func cb,
105 : const gnutls_datum_t *data, unsigned int flags)
106 : {
107 163 : if (flags & GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO) {
108 44 : size_t size = data->size;
109 44 : size_t len;
110 44 : uint8_t *p = data->data;
111 :
112 44 : DECR_LEN(size, HANDSHAKE_SESSION_ID_POS);
113 :
114 41 : if (p[0] != 0x03)
115 20 : return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
116 :
117 21 : p += HANDSHAKE_SESSION_ID_POS;
118 :
119 : /* skip session id */
120 21 : DECR_LEN(size, 1);
121 20 : len = p[0];
122 20 : p++;
123 20 : DECR_LEN(size, len);
124 19 : p += len;
125 :
126 : /* CipherSuites */
127 19 : DECR_LEN(size, 2);
128 18 : len = _gnutls_read_uint16(p);
129 18 : p += 2;
130 18 : DECR_LEN(size, len);
131 16 : p += len;
132 :
133 : /* legacy_compression_methods */
134 16 : DECR_LEN(size, 1);
135 15 : len = p[0];
136 15 : p++;
137 15 : DECR_LEN(size, len);
138 14 : p += len;
139 :
140 14 : if (size == 0)
141 1 : return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
142 :
143 13 : return _gnutls_extv_parse(ctx, cb, p, size);
144 119 : } else if (flags & GNUTLS_EXT_RAW_FLAG_DTLS_CLIENT_HELLO) {
145 41 : size_t size = data->size;
146 41 : size_t len;
147 41 : uint8_t *p = data->data;
148 :
149 41 : DECR_LEN(size, HANDSHAKE_SESSION_ID_POS);
150 :
151 38 : if (p[0] != 254)
152 20 : return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
153 :
154 18 : p += HANDSHAKE_SESSION_ID_POS;
155 :
156 : /* skip session id */
157 18 : DECR_LEN(size, 1);
158 17 : len = p[0];
159 17 : p++;
160 17 : DECR_LEN(size, len);
161 16 : p += len;
162 :
163 : /* skip cookie */
164 16 : DECR_LEN(size, 1);
165 15 : len = p[0];
166 15 : p++;
167 15 : DECR_LEN(size, len);
168 14 : p += len;
169 :
170 : /* CipherSuites */
171 14 : DECR_LEN(size, 2);
172 13 : len = _gnutls_read_uint16(p);
173 13 : p += 2;
174 13 : DECR_LEN(size, len);
175 12 : p += len;
176 :
177 : /* legacy_compression_methods */
178 12 : DECR_LEN(size, 1);
179 11 : len = p[0];
180 11 : p++;
181 11 : DECR_LEN(size, len);
182 10 : p += len;
183 :
184 10 : if (size == 0)
185 1 : return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
186 :
187 9 : return _gnutls_extv_parse(ctx, cb, p, size);
188 : }
189 :
190 78 : if (flags != 0)
191 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
192 :
193 78 : return _gnutls_extv_parse(ctx, cb, data->data, data->size);
194 : }
195 :
196 : /* Returns:
197 : * * On success the number of bytes appended (always positive), or zero if not sent
198 : * * On failure, a negative error code.
199 : */
200 635770 : int _gnutls_extv_append(gnutls_buffer_st *buf,
201 : uint16_t tls_id,
202 : void *ctx,
203 : int (*cb)(void *ctx, gnutls_buffer_st *buf))
204 : {
205 635770 : int size_pos, appended, ret;
206 635770 : size_t size_prev;
207 :
208 635770 : ret = _gnutls_buffer_append_prefix(buf, 16, tls_id);
209 635770 : if (ret < 0)
210 0 : return gnutls_assert_val(ret);
211 :
212 635770 : size_pos = buf->length;
213 635770 : ret = _gnutls_buffer_append_prefix(buf, 16, 0);
214 635770 : if (ret < 0)
215 0 : return gnutls_assert_val(ret);
216 :
217 635770 : size_prev = buf->length;
218 635770 : ret = cb(ctx, buf);
219 635770 : if (ret < 0 && ret != GNUTLS_E_INT_RET_0) {
220 162 : return gnutls_assert_val(ret);
221 : }
222 :
223 : /* returning GNUTLS_E_INT_RET_0 means to send an empty
224 : * extension of this type.
225 : */
226 635614 : appended = buf->length - size_prev;
227 :
228 635614 : if (appended > 0 || ret == GNUTLS_E_INT_RET_0) {
229 75495 : if (ret == GNUTLS_E_INT_RET_0)
230 17283 : appended = 0;
231 :
232 : /* write the real size */
233 150990 : _gnutls_write_uint16(appended,
234 75495 : &buf->data[size_pos]);
235 560119 : } else if (appended == 0) {
236 560119 : buf->length -= 4; /* reset type and size */
237 560119 : return 0;
238 : }
239 :
240 75495 : return appended + 4;
241 : }
242 :
|