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