]>
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 | ||
10 | #include "packet_locl.h" | |
11 | ||
12 | /* | |
0217dd19 | 13 | * Allocate bytes in the WPACKET for the output. This reserves the bytes |
b7273855 MC |
14 | * and count them as "written", but doesn't actually do the writing. |
15 | */ | |
0217dd19 | 16 | int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes) |
b7273855 | 17 | { |
0217dd19 MC |
18 | if (pkt->subs == NULL || len == 0) |
19 | return 0; | |
b7273855 | 20 | |
0217dd19 | 21 | if (SIZE_MAX - pkt->written < len) |
b7273855 MC |
22 | return 0; |
23 | ||
0217dd19 | 24 | if (pkt->maxsize > 0 && pkt->written + len > pkt->maxsize) |
b7273855 MC |
25 | return 0; |
26 | ||
0217dd19 | 27 | if (pkt->buf->length - pkt->written < len) { |
b7273855 MC |
28 | size_t newlen; |
29 | ||
0217dd19 | 30 | if (pkt->buf->length > SIZE_MAX / 2) |
b7273855 MC |
31 | newlen = SIZE_MAX; |
32 | else | |
0217dd19 MC |
33 | newlen = pkt->buf->length * 2; |
34 | if (BUF_MEM_grow(pkt->buf, newlen) == 0) | |
35 | return 0; | |
b7273855 | 36 | } |
0217dd19 MC |
37 | pkt->written += len; |
38 | *allocbytes = pkt->curr; | |
39 | pkt->curr += len; | |
b7273855 | 40 | |
0217dd19 | 41 | return 1; |
b7273855 MC |
42 | } |
43 | ||
44 | /* | |
ae2f7b37 MC |
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 | |
b7273855 | 47 | * data is preallocated at the start of the buffer to store the length of the |
ae2f7b37 | 48 | * WPACKET once we know it. |
b7273855 | 49 | */ |
ae2f7b37 | 50 | int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes) |
b7273855 | 51 | { |
b7273855 MC |
52 | /* Sanity check */ |
53 | if (buf == NULL) | |
54 | return 0; | |
55 | ||
0217dd19 MC |
56 | pkt->buf = buf; |
57 | pkt->curr = (unsigned char *)buf->data; | |
58 | pkt->written = 0; | |
59 | pkt->maxsize = 0; | |
b7273855 | 60 | |
0217dd19 MC |
61 | pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs)); |
62 | if (pkt->subs == NULL) | |
63 | return 0; | |
b7273855 | 64 | |
0217dd19 | 65 | if (lenbytes == 0) |
b7273855 | 66 | return 1; |
b7273855 | 67 | |
0217dd19 MC |
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; | |
b7273855 MC |
74 | return 0; |
75 | } | |
76 | ||
77 | return 1; | |
78 | } | |
79 | ||
80 | /* | |
ae2f7b37 | 81 | * Same as WPACKET_init_len except there is no preallocation of the WPACKET |
b7273855 MC |
82 | * length. |
83 | */ | |
ae2f7b37 | 84 | int WPACKET_init(WPACKET *pkt, BUF_MEM *buf) |
b7273855 | 85 | { |
ae2f7b37 | 86 | return WPACKET_init_len(pkt, buf, 0); |
b7273855 MC |
87 | } |
88 | ||
89 | /* | |
ae2f7b37 MC |
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 | |
b7273855 | 93 | * is the possibility that the length needs to be written to some other location |
ae2f7b37 | 94 | * other than the start of the WPACKET. In that case init via WPACKET_init() and |
b7273855 MC |
95 | * then set the location for the length using this function. |
96 | */ | |
ae2f7b37 | 97 | int WPACKET_set_packet_len(WPACKET *pkt, unsigned char *packet_len, |
b7273855 MC |
98 | size_t lenbytes) |
99 | { | |
100 | /* We only allow this to be set once */ | |
0217dd19 | 101 | if (pkt->subs == NULL) |
b7273855 MC |
102 | return 0; |
103 | ||
0217dd19 MC |
104 | pkt->subs->lenbytes = lenbytes; |
105 | pkt->subs->packet_len = packet_len; | |
b7273855 MC |
106 | |
107 | return 1; | |
108 | } | |
109 | ||
ae2f7b37 | 110 | int WPACKET_set_flags(WPACKET *pkt, unsigned int flags) |
b7273855 | 111 | { |
0217dd19 MC |
112 | if (pkt->subs == NULL) |
113 | return 0; | |
114 | ||
115 | pkt->subs->flags = flags; | |
b7273855 MC |
116 | |
117 | return 1; | |
118 | } | |
119 | ||
0217dd19 | 120 | |
b7273855 | 121 | /* |
0217dd19 MC |
122 | * Internal helper function used by WPACKET_close() and WPACKET_finish() to |
123 | * close a sub-packet and write out its length if necessary. | |
b7273855 | 124 | */ |
0217dd19 | 125 | static int wpacket_intern_close(WPACKET *pkt) |
b7273855 MC |
126 | { |
127 | size_t packlen; | |
0217dd19 | 128 | WPACKET_SUB *sub = pkt->subs; |
b7273855 | 129 | |
0217dd19 MC |
130 | packlen = pkt->written - sub->pwritten; |
131 | if (packlen == 0 | |
132 | && sub->flags & OPENSSL_WPACKET_FLAGS_NON_ZERO_LENGTH) | |
b7273855 MC |
133 | return 0; |
134 | ||
135 | if (packlen == 0 | |
0217dd19 | 136 | && sub->flags & OPENSSL_WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) { |
ae2f7b37 | 137 | /* Deallocate any bytes allocated for the length of the WPACKET */ |
0217dd19 MC |
138 | if ((pkt->curr - sub->lenbytes) == sub->packet_len) { |
139 | pkt->written -= sub->lenbytes; | |
140 | pkt->curr -= sub->lenbytes; | |
b7273855 MC |
141 | } |
142 | ||
143 | /* Don't write out the packet length */ | |
0217dd19 | 144 | sub->packet_len = NULL; |
b7273855 MC |
145 | } |
146 | ||
ae2f7b37 | 147 | /* Write out the WPACKET length if needed */ |
0217dd19 | 148 | if (sub->packet_len != NULL) { |
b7273855 MC |
149 | size_t lenbytes; |
150 | ||
0217dd19 | 151 | lenbytes = sub->lenbytes; |
b7273855 MC |
152 | |
153 | for (; lenbytes > 0; lenbytes--) { | |
0217dd19 MC |
154 | sub->packet_len[lenbytes - 1] |
155 | = (unsigned char)(packlen & 0xff); | |
b7273855 MC |
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 | ||
0217dd19 MC |
166 | pkt->subs = sub->parent; |
167 | OPENSSL_free(sub); | |
b7273855 MC |
168 | |
169 | return 1; | |
170 | } | |
171 | ||
172 | /* | |
0217dd19 MC |
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. | |
b7273855 | 177 | */ |
0217dd19 | 178 | int WPACKET_close(WPACKET *pkt) |
b7273855 | 179 | { |
0217dd19 | 180 | if (pkt->subs == NULL || pkt->subs->parent == NULL) |
b7273855 MC |
181 | return 0; |
182 | ||
0217dd19 | 183 | return wpacket_intern_close(pkt); |
b7273855 MC |
184 | } |
185 | ||
186 | /* | |
0217dd19 MC |
187 | * The same as WPACKET_close() but only for the top most WPACKET. Additionally |
188 | * frees memory resources for this WPACKET. | |
b7273855 | 189 | */ |
0217dd19 | 190 | int WPACKET_finish(WPACKET *pkt) |
b7273855 | 191 | { |
0217dd19 MC |
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; | |
b7273855 MC |
203 | } |
204 | ||
205 | /* | |
0217dd19 MC |
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. | |
b7273855 | 208 | */ |
0217dd19 | 209 | int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes) |
b7273855 | 210 | { |
0217dd19 | 211 | WPACKET_SUB *sub; |
b7273855 | 212 | |
0217dd19 | 213 | if (pkt->subs == NULL) |
b7273855 MC |
214 | return 0; |
215 | ||
0217dd19 MC |
216 | sub = OPENSSL_zalloc(sizeof(*sub)); |
217 | if (sub == NULL) | |
b7273855 MC |
218 | return 0; |
219 | ||
0217dd19 MC |
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 | } | |
b7273855 MC |
233 | |
234 | return 1; | |
235 | } | |
236 | ||
0217dd19 MC |
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 | ||
b7273855 | 246 | /* |
ae2f7b37 | 247 | * Write the value stored in |val| into the WPACKET. The value will consome |
b7273855 MC |
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 | */ | |
ae2f7b37 | 252 | int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t bytes) |
b7273855 MC |
253 | { |
254 | unsigned char *data; | |
255 | ||
256 | if (bytes > sizeof(unsigned int) | |
ae2f7b37 | 257 | || !WPACKET_allocate_bytes(pkt, bytes, &data)) |
b7273855 MC |
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 | /* | |
ae2f7b37 | 275 | * Set a maximum size that we will not allow the WPACKET to grow beyond. If not |
b7273855 MC |
276 | * set then there is no maximum. |
277 | */ | |
ae2f7b37 | 278 | int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize) |
b7273855 | 279 | { |
0217dd19 | 280 | pkt->maxsize = maxsize; |
b7273855 MC |
281 | |
282 | return 1; | |
283 | } | |
284 | ||
285 | /* | |
ae2f7b37 | 286 | * Copy |len| bytes of data from |*src| into the WPACKET. |
b7273855 | 287 | */ |
ae2f7b37 | 288 | int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len) |
b7273855 MC |
289 | { |
290 | unsigned char *dest; | |
291 | ||
292 | if (len == 0) | |
293 | return 1; | |
294 | ||
ae2f7b37 | 295 | if (!WPACKET_allocate_bytes(pkt, len, &dest)) |
b7273855 MC |
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. | |
ae2f7b37 | 305 | * This might includes bytes written by a parent WPACKET. |
b7273855 | 306 | */ |
ae2f7b37 | 307 | int WPACKET_get_total_written(WPACKET *pkt, size_t *written) |
b7273855 | 308 | { |
0217dd19 | 309 | if (pkt->subs == NULL || written == NULL) |
b7273855 MC |
310 | return 0; |
311 | ||
0217dd19 | 312 | *written = pkt->written; |
b7273855 MC |
313 | |
314 | return 1; | |
315 | } | |
316 | ||
317 | /* | |
0217dd19 | 318 | * Returns the length of the last sub-packet. This excludes any bytes allocated |
b7273855 MC |
319 | * for the length itself. |
320 | */ | |
ae2f7b37 | 321 | int WPACKET_get_length(WPACKET *pkt, size_t *len) |
b7273855 | 322 | { |
0217dd19 | 323 | if (pkt->subs == NULL || len == NULL) |
b7273855 MC |
324 | return 0; |
325 | ||
0217dd19 | 326 | *len = pkt->written - pkt->subs->pwritten; |
b7273855 MC |
327 | |
328 | return 1; | |
329 | } |