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