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