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