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