]> git.ipfire.org Git - thirdparty/openssl.git/blob - ssl/packet.c
Various bug fixes and tweaks to WPACKET implementation
[thirdparty/openssl.git] / ssl / packet.c
1 /*
2 * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include "packet_locl.h"
11
12 #define DEFAULT_BUF_SIZE 256
13
14 /*
15 * Allocate bytes in the WPACKET for the output. This reserves the bytes
16 * and count them as "written", but doesn't actually do the writing.
17 */
18 int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
19 {
20 if (pkt->subs == NULL || len == 0)
21 return 0;
22
23 if (SIZE_MAX - pkt->written < len)
24 return 0;
25
26 if (pkt->written + len > pkt->maxsize)
27 return 0;
28
29 if (pkt->buf->length - pkt->written < len) {
30 size_t newlen;
31
32 if (pkt->buf->length > SIZE_MAX / 2) {
33 newlen = SIZE_MAX;
34 } else {
35 if (pkt->buf->length == 0)
36 newlen = DEFAULT_BUF_SIZE;
37 else
38 newlen = pkt->buf->length * 2;
39 }
40 if (BUF_MEM_grow(pkt->buf, newlen) == 0)
41 return 0;
42 if (pkt->curr == NULL) {
43 /*
44 * Can happen if initialised with a BUF_MEM that hasn't been
45 * pre-allocated.
46 */
47 pkt->curr = (unsigned char *)pkt->buf->data;
48 }
49 }
50 pkt->written += len;
51 *allocbytes = pkt->curr;
52 pkt->curr += len;
53
54 return 1;
55 }
56
57 static size_t maxmaxsize(size_t lenbytes)
58 {
59 if (lenbytes >= sizeof(size_t) || lenbytes == 0)
60 return SIZE_MAX;
61 else
62 return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
63 }
64
65 /*
66 * Initialise a WPACKET with the buffer in |buf|. The buffer must exist
67 * for the whole time that the WPACKET is being used. Additionally |lenbytes| of
68 * data is preallocated at the start of the buffer to store the length of the
69 * WPACKET once we know it.
70 */
71 int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
72 {
73 /* Sanity check */
74 if (buf == NULL)
75 return 0;
76
77 pkt->buf = buf;
78 pkt->curr = (unsigned char *)buf->data;
79 pkt->written = 0;
80 pkt->maxsize = maxmaxsize(lenbytes);
81
82 pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
83 if (pkt->subs == NULL)
84 return 0;
85
86 if (lenbytes == 0)
87 return 1;
88
89 pkt->subs->pwritten = lenbytes;
90 pkt->subs->lenbytes = lenbytes;
91
92 if (!WPACKET_allocate_bytes(pkt, lenbytes, &(pkt->subs->packet_len))) {
93 OPENSSL_free(pkt->subs);
94 pkt->subs = NULL;
95 return 0;
96 }
97
98 return 1;
99 }
100
101 /*
102 * Same as WPACKET_init_len except there is no preallocation of the WPACKET
103 * length.
104 */
105 int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
106 {
107 return WPACKET_init_len(pkt, buf, 0);
108 }
109
110 /*
111 * Set the WPACKET length, and the location for where we should write that
112 * length. Normally this will be at the start of the WPACKET, and therefore
113 * the WPACKET would have been initialised via WPACKET_init_len(). However there
114 * is the possibility that the length needs to be written to some other location
115 * other than the start of the WPACKET. In that case init via WPACKET_init() and
116 * then set the location for the length using this function.
117 */
118 int WPACKET_set_packet_len(WPACKET *pkt, unsigned char *packet_len,
119 size_t lenbytes)
120 {
121 size_t maxmax;
122
123 /* We only allow this to be set once */
124 if (pkt->subs == NULL || pkt->subs->lenbytes != 0)
125 return 0;
126
127 pkt->subs->lenbytes = lenbytes;
128 pkt->subs->packet_len = packet_len;
129
130 maxmax = maxmaxsize(lenbytes);
131 if (pkt->maxsize > maxmax)
132 pkt->maxsize = maxmax;
133
134 return 1;
135 }
136
137 int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
138 {
139 if (pkt->subs == NULL)
140 return 0;
141
142 pkt->subs->flags = flags;
143
144 return 1;
145 }
146
147
148 /*
149 * Internal helper function used by WPACKET_close() and WPACKET_finish() to
150 * close a sub-packet and write out its length if necessary.
151 */
152 static int wpacket_intern_close(WPACKET *pkt)
153 {
154 size_t packlen;
155 WPACKET_SUB *sub = pkt->subs;
156
157 packlen = pkt->written - sub->pwritten;
158 if (packlen == 0
159 && sub->flags & OPENSSL_WPACKET_FLAGS_NON_ZERO_LENGTH)
160 return 0;
161
162 if (packlen == 0
163 && sub->flags & OPENSSL_WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
164 /* Deallocate any bytes allocated for the length of the WPACKET */
165 if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
166 pkt->written -= sub->lenbytes;
167 pkt->curr -= sub->lenbytes;
168 }
169
170 /* Don't write out the packet length */
171 sub->packet_len = NULL;
172 }
173
174 /* Write out the WPACKET length if needed */
175 if (sub->packet_len != NULL) {
176 size_t lenbytes;
177
178 lenbytes = sub->lenbytes;
179
180 for (; lenbytes > 0; lenbytes--) {
181 sub->packet_len[lenbytes - 1]
182 = (unsigned char)(packlen & 0xff);
183 packlen >>= 8;
184 }
185 if (packlen > 0) {
186 /*
187 * We've extended beyond the max allowed for the number of len bytes
188 */
189 return 0;
190 }
191 }
192
193 pkt->subs = sub->parent;
194 OPENSSL_free(sub);
195
196 return 1;
197 }
198
199 /*
200 * Closes the most recent sub-packet. It also writes out the length of the
201 * packet to the required location (normally the start of the WPACKET) if
202 * appropriate. The top level WPACKET should be closed using WPACKET_finish()
203 * instead of this function.
204 */
205 int WPACKET_close(WPACKET *pkt)
206 {
207 if (pkt->subs == NULL || pkt->subs->parent == NULL)
208 return 0;
209
210 return wpacket_intern_close(pkt);
211 }
212
213 /*
214 * The same as WPACKET_close() but only for the top most WPACKET. Additionally
215 * frees memory resources for this WPACKET.
216 */
217 int WPACKET_finish(WPACKET *pkt)
218 {
219 int ret;
220
221 if (pkt->subs == NULL || pkt->subs->parent != NULL)
222 return 0;
223
224 ret = wpacket_intern_close(pkt);
225
226 if (ret) {
227 OPENSSL_free(pkt->subs);
228 pkt->subs = NULL;
229 }
230 return ret;
231 }
232
233 /*
234 * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated
235 * at the start of the sub-packet to store its length once we know it.
236 */
237 int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
238 {
239 WPACKET_SUB *sub;
240
241 if (pkt->subs == NULL)
242 return 0;
243
244 sub = OPENSSL_zalloc(sizeof(*sub));
245 if (sub == NULL)
246 return 0;
247
248 sub->parent = pkt->subs;
249 pkt->subs = sub;
250 sub->pwritten = pkt->written + lenbytes;
251 sub->lenbytes = lenbytes;
252
253 if (lenbytes == 0) {
254 sub->packet_len = NULL;
255 return 1;
256 }
257
258 if (!WPACKET_allocate_bytes(pkt, lenbytes, &sub->packet_len)) {
259 return 0;
260 }
261
262 return 1;
263 }
264
265 /*
266 * Same as WPACKET_get_sub_packet_len() except no bytes are pre-allocated for
267 * the sub-packet length.
268 */
269 int WPACKET_start_sub_packet(WPACKET *pkt)
270 {
271 return WPACKET_start_sub_packet_len(pkt, 0);
272 }
273
274 /*
275 * Write the value stored in |val| into the WPACKET. The value will consome
276 * |bytes| amount of storage. An error will occur if |val| cannot be accommdated
277 * in |bytes| storage, e.g. attempting to write the value 256 into 1 byte will
278 * fail.
279 */
280 int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t bytes)
281 {
282 unsigned char *data;
283
284 if (bytes > sizeof(unsigned int)
285 || !WPACKET_allocate_bytes(pkt, bytes, &data))
286 return 0;
287
288 data += bytes - 1;
289 for (; bytes > 0; bytes--) {
290 *data = (unsigned char)(val & 0xff);
291 data--;
292 val >>= 8;
293 }
294
295 /* Check whether we could fit the value in the assigned number of bytes */
296 if (val > 0)
297 return 0;
298
299 return 1;
300 }
301
302 /* Set a maximum size that we will not allow the WPACKET to grow beyond */
303 int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
304 {
305 WPACKET_SUB *sub;
306 size_t lenbytes;
307
308 if (pkt->subs == NULL)
309 return 0;
310
311 /* Find the WPACKET_SUB for the top level */
312 for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent);
313
314 lenbytes = sub->lenbytes;
315 if (lenbytes == 0)
316 lenbytes = sizeof(pkt->maxsize);
317
318 if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written)
319 return 0;
320
321 pkt->maxsize = maxsize;
322
323 return 1;
324 }
325
326 /*
327 * Copy |len| bytes of data from |*src| into the WPACKET.
328 */
329 int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
330 {
331 unsigned char *dest;
332
333 if (len == 0)
334 return 1;
335
336 if (!WPACKET_allocate_bytes(pkt, len, &dest))
337 return 0;
338
339 memcpy(dest, src, len);
340
341 return 1;
342 }
343
344 /*
345 * Copy |len| bytes of data from |*src| into the WPACKET and prefix with its
346 * length (consuming |lenbytes| of data for the length)
347 */
348 int WPACKET_sub_memcpy(WPACKET *pkt, const void *src, size_t len, size_t lenbytes)
349 {
350 if (!WPACKET_start_sub_packet_len(pkt, lenbytes)
351 || !WPACKET_memcpy(pkt, src, len)
352 || !WPACKET_close(pkt))
353 return 0;
354
355 return 1;
356 }
357
358 /*
359 * Return the total number of bytes written so far to the underlying buffer
360 * including any storage allocated for length bytes
361 */
362 int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
363 {
364 if (written == NULL)
365 return 0;
366
367 *written = pkt->written;
368
369 return 1;
370 }
371
372 /*
373 * Returns the length of the last sub-packet. This excludes any bytes allocated
374 * for the length itself.
375 */
376 int WPACKET_get_length(WPACKET *pkt, size_t *len)
377 {
378 if (pkt->subs == NULL || len == NULL)
379 return 0;
380
381 *len = pkt->written - pkt->subs->pwritten;
382
383 return 1;
384 }
385
386 /*
387 * Release resources in a WPACKET if a failure has occurred.
388 */
389 void WPACKET_cleanup(WPACKET *pkt)
390 {
391 WPACKET_SUB *sub, *parent;
392
393 for (sub = pkt->subs; sub != NULL; sub = parent) {
394 parent = sub->parent;
395 OPENSSL_free(sub);
396 }
397 pkt->subs = NULL;
398 }