Various bug fixes and tweaks to WPACKET implementation
[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 }