27462e947e3a2aaed01c794f45290b0427a94af3
[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 <assert.h>
11 #include "packet_locl.h"
12
13 #define DEFAULT_BUF_SIZE    256
14
15 int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
16 {
17     if (!WPACKET_reserve_bytes(pkt, len, allocbytes))
18         return 0;
19
20     pkt->written += len;
21     pkt->curr += len;
22     return 1;
23 }
24
25 int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len,
26                                  unsigned char **allocbytes, size_t lenbytes)
27 {
28     if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
29             || !WPACKET_allocate_bytes(pkt, len, allocbytes)
30             || !WPACKET_close(pkt))
31         return 0;
32
33     return 1;
34 }
35
36 int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
37 {
38     /* Internal API, so should not fail */
39     assert(pkt->subs != NULL && len != 0);
40     if (pkt->subs == NULL || len == 0)
41         return 0;
42
43     if (pkt->maxsize - pkt->written < len)
44         return 0;
45
46     if (pkt->buf->length - pkt->written < len) {
47         size_t newlen;
48         size_t reflen;
49
50         reflen = (len > pkt->buf->length) ? len : pkt->buf->length;
51
52         if (reflen > SIZE_MAX / 2) {
53             newlen = SIZE_MAX;
54         } else {
55             newlen = reflen * 2;
56             if (newlen < DEFAULT_BUF_SIZE)
57                 newlen = DEFAULT_BUF_SIZE;
58         }
59         if (BUF_MEM_grow(pkt->buf, newlen) == 0)
60             return 0;
61     }
62     *allocbytes = (unsigned char *)pkt->buf->data + pkt->curr;
63
64     return 1;
65 }
66
67 int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len,
68                                 unsigned char **allocbytes, size_t lenbytes)
69 {
70     if (!WPACKET_reserve_bytes(pkt, lenbytes + len, allocbytes))
71         return 0;
72
73     *allocbytes += lenbytes;
74
75     return 1;
76 }
77
78 static size_t maxmaxsize(size_t lenbytes)
79 {
80     if (lenbytes >= sizeof(size_t) || lenbytes == 0)
81         return SIZE_MAX;
82
83     return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
84 }
85
86 int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
87 {
88     unsigned char *lenchars;
89
90     /* Internal API, so should not fail */
91     assert(buf != NULL);
92     if (buf == NULL)
93         return 0;
94
95     pkt->buf = buf;
96     pkt->curr = 0;
97     pkt->written = 0;
98     pkt->maxsize = maxmaxsize(lenbytes);
99
100     pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
101     if (pkt->subs == NULL)
102         return 0;
103
104     if (lenbytes == 0)
105         return 1;
106
107     pkt->subs->pwritten = lenbytes;
108     pkt->subs->lenbytes = lenbytes;
109
110     if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) {
111         OPENSSL_free(pkt->subs);
112         pkt->subs = NULL;
113         return 0;
114     }
115     pkt->subs->packet_len = lenchars - (unsigned char *)pkt->buf->data;
116
117     return 1;
118 }
119
120 int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
121 {
122     return WPACKET_init_len(pkt, buf, 0);
123 }
124
125 int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
126 {
127     /* Internal API, so should not fail */
128     assert(pkt->subs != NULL);
129     if (pkt->subs == NULL)
130         return 0;
131
132     pkt->subs->flags = flags;
133
134     return 1;
135 }
136
137 /* Store the |value| of length |len| at location |data| */
138 static int put_value(unsigned char *data, size_t value, size_t len)
139 {
140     for (data += len - 1; len > 0; len--) {
141         *data = (unsigned char)(value & 0xff);
142         data--;
143         value >>= 8;
144     }
145
146     /* Check whether we could fit the value in the assigned number of bytes */
147     if (value > 0)
148         return 0;
149
150     return 1;
151 }
152
153
154 /*
155  * Internal helper function used by WPACKET_close() and WPACKET_finish() to
156  * close a sub-packet and write out its length if necessary.
157  */
158 static int wpacket_intern_close(WPACKET *pkt)
159 {
160     WPACKET_SUB *sub = pkt->subs;
161     size_t packlen = pkt->written - sub->pwritten;
162
163     if (packlen == 0
164             && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0)
165         return 0;
166
167     if (packlen == 0
168             && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
169         /* Deallocate any bytes allocated for the length of the WPACKET */
170         if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
171             pkt->written -= sub->lenbytes;
172             pkt->curr -= sub->lenbytes;
173         }
174
175         /* Don't write out the packet length */
176         sub->packet_len = 0;
177         sub->lenbytes = 0;
178     }
179
180     /* Write out the WPACKET length if needed */
181     if (sub->lenbytes > 0
182                 && !put_value((unsigned char *)&pkt->buf->data[sub->packet_len],
183                               packlen, sub->lenbytes))
184             return 0;
185
186     pkt->subs = sub->parent;
187     OPENSSL_free(sub);
188
189     return 1;
190 }
191
192 int WPACKET_close(WPACKET *pkt)
193 {
194     /*
195      * Internal API, so should not fail - but we do negative testing of this
196      * so no assert (otherwise the tests fail)
197      */
198     if (pkt->subs == NULL || pkt->subs->parent == NULL)
199         return 0;
200
201     return wpacket_intern_close(pkt);
202 }
203
204 int WPACKET_finish(WPACKET *pkt)
205 {
206     int ret;
207
208     /*
209      * Internal API, so should not fail - but we do negative testing of this
210      * so no assert (otherwise the tests fail)
211      */
212     if (pkt->subs == NULL || pkt->subs->parent != NULL)
213         return 0;
214
215     ret = wpacket_intern_close(pkt);
216     if (ret) {
217         OPENSSL_free(pkt->subs);
218         pkt->subs = NULL;
219     }
220
221     return ret;
222 }
223
224 int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes)
225 {
226     WPACKET_SUB *sub;
227     unsigned char *lenchars;
228
229     /* Internal API, so should not fail */
230     assert(pkt->subs != NULL);
231     if (pkt->subs == NULL)
232         return 0;
233
234     sub = OPENSSL_zalloc(sizeof(*sub));
235     if (sub == NULL)
236         return 0;
237
238     sub->parent = pkt->subs;
239     pkt->subs = sub;
240     sub->pwritten = pkt->written + lenbytes;
241     sub->lenbytes = lenbytes;
242
243     if (lenbytes == 0) {
244         sub->packet_len = 0;
245         return 1;
246     }
247
248     if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
249         return 0;
250     /* Convert to an offset in case the underlying BUF_MEM gets realloc'd */
251     sub->packet_len = lenchars - (unsigned char *)pkt->buf->data;
252
253     return 1;
254 }
255
256 int WPACKET_start_sub_packet(WPACKET *pkt)
257 {
258     return WPACKET_start_sub_packet_len__(pkt, 0);
259 }
260
261 int WPACKET_put_bytes__(WPACKET *pkt, unsigned int val, size_t size)
262 {
263     unsigned char *data;
264
265     /* Internal API, so should not fail */
266     assert(size <= sizeof(unsigned int));
267
268     if (size > sizeof(unsigned int)
269             || !WPACKET_allocate_bytes(pkt, size, &data)
270             || !put_value(data, val, size))
271         return 0;
272
273     return 1;
274 }
275
276 int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
277 {
278     WPACKET_SUB *sub;
279     size_t lenbytes;
280
281     /* Internal API, so should not fail */
282     assert(pkt->subs != NULL);
283     if (pkt->subs == NULL)
284         return 0;
285
286     /* Find the WPACKET_SUB for the top level */
287     for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent)
288         continue;
289
290     lenbytes = sub->lenbytes;
291     if (lenbytes == 0)
292         lenbytes = sizeof(pkt->maxsize);
293
294     if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written)
295         return 0;
296
297     pkt->maxsize = maxsize;
298
299     return 1;
300 }
301
302 int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
303 {
304     unsigned char *dest;
305
306     if (len == 0)
307         return 1;
308
309     if (!WPACKET_allocate_bytes(pkt, len, &dest))
310         return 0;
311
312     memcpy(dest, src, len);
313
314     return 1;
315 }
316
317 int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len,
318                          size_t lenbytes)
319 {
320     if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
321             || !WPACKET_memcpy(pkt, src, len)
322             || !WPACKET_close(pkt))
323         return 0;
324
325     return 1;
326 }
327
328 int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
329 {
330     /* Internal API, so should not fail */
331     assert(written != NULL);
332     if (written == NULL)
333         return 0;
334
335     *written = pkt->written;
336
337     return 1;
338 }
339
340 int WPACKET_get_length(WPACKET *pkt, size_t *len)
341 {
342     /* Internal API, so should not fail */
343     assert(pkt->subs != NULL && len != NULL);
344     if (pkt->subs == NULL || len == NULL)
345         return 0;
346
347     *len = pkt->written - pkt->subs->pwritten;
348
349     return 1;
350 }
351
352 void WPACKET_cleanup(WPACKET *pkt)
353 {
354     WPACKET_SUB *sub, *parent;
355
356     for (sub = pkt->subs; sub != NULL; sub = parent) {
357         parent = sub->parent;
358         OPENSSL_free(sub);
359     }
360     pkt->subs = NULL;
361 }