d4f964922d2a1e0acd74e54ce774e1914b6d81b7
[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 /*
13  * Allocate bytes in the WPACKET for the output. This reserves the bytes
14  * and count them as "written", but doesn't actually do the writing.
15  */
16 int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
17 {
18     if (pkt->subs == NULL || len == 0)
19         return 0;
20
21     if (SIZE_MAX - pkt->written < len)
22         return 0;
23
24     if (pkt->maxsize > 0 && pkt->written + len > pkt->maxsize)
25         return 0;
26
27     if (pkt->buf->length - pkt->written < len) {
28         size_t newlen;
29
30         if (pkt->buf->length > SIZE_MAX / 2)
31             newlen = SIZE_MAX;
32         else
33             newlen = pkt->buf->length * 2;
34         if (BUF_MEM_grow(pkt->buf, newlen) == 0)
35             return 0;
36     }
37     pkt->written += len;
38     *allocbytes = pkt->curr;
39     pkt->curr += len;
40
41     return 1;
42 }
43
44 /*
45  * Initialise a WPACKET with the buffer in |buf|. The buffer must exist
46  * for the whole time that the WPACKET is being used. Additionally |lenbytes| of
47  * data is preallocated at the start of the buffer to store the length of the
48  * WPACKET once we know it.
49  */
50 int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
51 {
52     /* Sanity check */
53     if (buf == NULL)
54         return 0;
55
56     pkt->buf = buf;
57     pkt->curr = (unsigned char *)buf->data;
58     pkt->written = 0;
59     pkt->maxsize = 0;
60
61     pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
62     if (pkt->subs == NULL)
63         return 0;
64
65     if (lenbytes == 0)
66         return 1;
67
68     pkt->subs->pwritten = lenbytes;
69     pkt->subs->lenbytes = lenbytes;
70
71     if (!WPACKET_allocate_bytes(pkt, lenbytes, &(pkt->subs->packet_len))) {
72         OPENSSL_free(pkt->subs);
73         pkt->subs = NULL;
74         return 0;
75     }
76
77     return 1;
78 }
79
80 /*
81  * Same as WPACKET_init_len except there is no preallocation of the WPACKET
82  * length.
83  */
84 int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
85 {
86     return WPACKET_init_len(pkt, buf, 0);
87 }
88
89 /*
90  * Set the WPACKET length, and the location for where we should write that
91  * length. Normally this will be at the start of the WPACKET, and therefore
92  * the WPACKET would have been initialised via WPACKET_init_len(). However there
93  * is the possibility that the length needs to be written to some other location
94  * other than the start of the WPACKET. In that case init via WPACKET_init() and
95  * then set the location for the length using this function.
96  */
97 int WPACKET_set_packet_len(WPACKET *pkt, unsigned char *packet_len,
98                            size_t lenbytes)
99 {
100     /* We only allow this to be set once */
101     if (pkt->subs == NULL)
102         return 0;
103
104     pkt->subs->lenbytes = lenbytes;
105     pkt->subs->packet_len = packet_len;
106
107     return 1;
108 }
109
110 int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
111 {
112     if (pkt->subs == NULL)
113         return 0;
114
115     pkt->subs->flags = flags;
116
117     return 1;
118 }
119
120
121 /*
122  * Internal helper function used by WPACKET_close() and WPACKET_finish() to
123  * close a sub-packet and write out its length if necessary.
124  */
125 static int wpacket_intern_close(WPACKET *pkt)
126 {
127     size_t packlen;
128     WPACKET_SUB *sub = pkt->subs;
129
130     packlen = pkt->written - sub->pwritten;
131     if (packlen == 0
132             && sub->flags & OPENSSL_WPACKET_FLAGS_NON_ZERO_LENGTH)
133         return 0;
134
135     if (packlen == 0
136             && sub->flags & OPENSSL_WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
137         /* Deallocate any bytes allocated for the length of the WPACKET */
138         if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
139             pkt->written -= sub->lenbytes;
140             pkt->curr -= sub->lenbytes;
141         }
142
143         /* Don't write out the packet length */
144         sub->packet_len = NULL;
145     }
146
147     /* Write out the WPACKET length if needed */
148     if (sub->packet_len != NULL) {
149         size_t lenbytes;
150
151         lenbytes = sub->lenbytes;
152
153         for (; lenbytes > 0; lenbytes--) {
154             sub->packet_len[lenbytes - 1]
155                 = (unsigned char)(packlen & 0xff);
156             packlen >>= 8;
157         }
158         if (packlen > 0) {
159             /*
160              * We've extended beyond the max allowed for the number of len bytes
161              */
162             return 0;
163         }
164     }
165
166     pkt->subs = sub->parent;
167     OPENSSL_free(sub);
168
169     return 1;
170 }
171
172 /*
173  * Closes the most recent sub-packet. It also writes out the length of the
174  * packet to the required location (normally the start of the WPACKET) if
175  * appropriate. The top level WPACKET should be closed using WPACKET_finish()
176  * instead of this function.
177  */
178 int WPACKET_close(WPACKET *pkt)
179 {
180     if (pkt->subs == NULL || pkt->subs->parent == NULL)
181         return 0;
182
183     return wpacket_intern_close(pkt);
184 }
185
186 /*
187  * The same as WPACKET_close() but only for the top most WPACKET. Additionally
188  * frees memory resources for this WPACKET.
189  */
190 int WPACKET_finish(WPACKET *pkt)
191 {
192     int ret;
193
194     if (pkt->subs == NULL || pkt->subs->parent != NULL)
195         return 0;
196
197     ret = wpacket_intern_close(pkt);
198
199     /* We free up memory no matter whether |ret| is zero or not */
200     OPENSSL_free(pkt->subs);
201     pkt->subs = NULL;
202     return ret;
203 }
204
205 /*
206  * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated
207  * at the start of the sub-packet to store its length once we know it.
208  */
209 int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
210 {
211     WPACKET_SUB *sub;
212
213     if (pkt->subs == NULL)
214         return 0;
215
216     sub = OPENSSL_zalloc(sizeof(*sub));
217     if (sub == NULL)
218         return 0;
219
220     sub->parent = pkt->subs;
221     pkt->subs = sub;
222     sub->pwritten = pkt->written + lenbytes;
223     sub->lenbytes = lenbytes;
224
225     if (lenbytes == 0) {
226         sub->packet_len = NULL;
227         return 1;
228     }
229
230     if (!WPACKET_allocate_bytes(pkt, lenbytes, &sub->packet_len)) {
231         return 0;
232     }
233
234     return 1;
235 }
236
237 /*
238  * Same as WPACKET_get_sub_packet_len() except no bytes are pre-allocated for
239  * the sub-packet length.
240  */
241 int WPACKET_start_sub_packet(WPACKET *pkt)
242 {
243     return WPACKET_start_sub_packet_len(pkt, 0);
244 }
245
246 /*
247  * Write the value stored in |val| into the WPACKET. The value will consome
248  * |bytes| amount of storage. An error will occur if |val| cannot be accommdated
249  * in |bytes| storage, e.g. attempting to write the value 256 into 1 byte will
250  * fail.
251  */
252 int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t bytes)
253 {
254     unsigned char *data;
255
256     if (bytes > sizeof(unsigned int)
257             || !WPACKET_allocate_bytes(pkt, bytes, &data))
258         return 0;
259
260     data += bytes - 1;
261     for (; bytes > 0; bytes--) {
262         *data = (unsigned char)(val & 0xff);
263         data--;
264         val >>= 8;
265     }
266
267     /* Check whether we could fit the value in the assigned number of bytes */
268     if (val > 0)
269         return 0;
270
271     return 1;
272 }
273
274 /*
275  * Set a maximum size that we will not allow the WPACKET to grow beyond. If not
276  * set then there is no maximum.
277  */
278 int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
279 {
280     pkt->maxsize = maxsize;
281
282     return 1;
283 }
284
285 /*
286  * Copy |len| bytes of data from |*src| into the WPACKET.
287  */
288 int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
289 {
290     unsigned char *dest;
291
292     if (len == 0)
293         return 1;
294
295     if (!WPACKET_allocate_bytes(pkt, len, &dest))
296         return 0;
297
298     memcpy(dest, src, len);
299
300     return 1;
301 }
302
303 /*
304  * Return the total number of bytes written so far to the underlying buffer.
305  * This might includes bytes written by a parent WPACKET.
306  */
307 int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
308 {
309     if (pkt->subs == NULL || written == NULL)
310         return 0;
311
312     *written = pkt->written;
313
314     return 1;
315 }
316
317 /*
318  * Returns the length of the last sub-packet. This excludes any bytes allocated
319  * for the length itself.
320  */
321 int WPACKET_get_length(WPACKET *pkt, size_t *len)
322 {
323     if (pkt->subs == NULL || len == NULL)
324         return 0;
325
326     *len = pkt->written - pkt->subs->pwritten;
327
328     return 1;
329 }