summaryrefslogtreecommitdiff
path: root/src/lib/libssl/bs_cbb.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/libssl/bs_cbb.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/src/lib/libssl/bs_cbb.c b/src/lib/libssl/bs_cbb.c
new file mode 100644
index 0000000000..668231c1c7
--- /dev/null
+++ b/src/lib/libssl/bs_cbb.c
@@ -0,0 +1,387 @@
1/* $OpenBSD: bs_cbb.c,v 1.1 2015/02/06 09:36:16 doug Exp $ */
2/*
3 * Copyright (c) 2014, Google Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
16
17#include <assert.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <openssl/opensslconf.h>
22
23#include "bytestring.h"
24
25static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) {
26 struct cbb_buffer_st *base;
27
28 base = malloc(sizeof(struct cbb_buffer_st));
29 if (base == NULL) {
30 free(buf);
31 return 0;
32 }
33
34 base->buf = buf;
35 base->len = 0;
36 base->cap = cap;
37 base->can_resize = 1;
38
39 memset(cbb, 0, sizeof(CBB));
40 cbb->base = base;
41 cbb->is_top_level = 1;
42 return 1;
43}
44
45int CBB_init(CBB *cbb, size_t initial_capacity) {
46 uint8_t *buf;
47
48 buf = malloc(initial_capacity);
49 if (initial_capacity > 0 && buf == NULL) {
50 return 0;
51 }
52
53 return cbb_init(cbb, buf, initial_capacity);
54}
55
56int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len) {
57 if (!cbb_init(cbb, buf, len)) {
58 return 0;
59 }
60
61 cbb->base->can_resize = 0;
62 return 1;
63}
64
65void CBB_cleanup(CBB *cbb) {
66 if (cbb->base) {
67 if (cbb->base->buf && cbb->base->can_resize) {
68 free(cbb->base->buf);
69 }
70 free(cbb->base);
71 }
72 cbb->base = NULL;
73}
74
75static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out,
76 size_t len) {
77 size_t newlen;
78
79 if (base == NULL) {
80 return 0;
81 }
82
83#if 0
84 // XXX Added for boringssl patch testing
85 if (len == 0) {
86 if (out) {
87 *out = NULL;
88 }
89 return 1;
90 }
91#endif
92
93 newlen = base->len + len;
94 if (newlen < base->len) {
95 /* Overflow */
96 return 0;
97 }
98
99 if (newlen > base->cap) {
100 size_t newcap = base->cap * 2;
101 uint8_t *newbuf;
102
103 if (!base->can_resize) {
104 return 0;
105 }
106
107 if (newcap < base->cap || newcap < newlen) {
108 newcap = newlen;
109 }
110 newbuf = realloc(base->buf, newcap);
111 if (newbuf == NULL) {
112 return 0;
113 }
114
115 base->buf = newbuf;
116 base->cap = newcap;
117 }
118
119 if (out) {
120 *out = base->buf + base->len;
121 }
122 base->len = newlen;
123 return 1;
124}
125
126static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v,
127 size_t len_len) {
128 uint8_t *buf;
129 size_t i;
130
131 if (len_len == 0) {
132 return 1;
133 }
134 if (!cbb_buffer_add(base, &buf, len_len)) {
135 return 0;
136 }
137
138 for (i = len_len - 1; i < len_len; i--) {
139 buf[i] = v;
140 v >>= 8;
141 }
142 return 1;
143}
144
145int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) {
146 if (!cbb->is_top_level) {
147 return 0;
148 }
149
150 if (!CBB_flush(cbb)) {
151 return 0;
152 }
153
154 if (cbb->base->can_resize && (out_data == NULL || out_len == NULL)) {
155 /* |out_data| and |out_len| can only be NULL if the CBB is fixed. */
156 return 0;
157 }
158
159 if (out_data != NULL) {
160 *out_data = cbb->base->buf;
161 }
162 if (out_len != NULL) {
163 *out_len = cbb->base->len;
164 }
165 cbb->base->buf = NULL;
166 CBB_cleanup(cbb);
167 return 1;
168}
169
170/* CBB_flush recurses and then writes out any pending length prefix. The
171 * current length of the underlying base is taken to be the length of the
172 * length-prefixed data. */
173int CBB_flush(CBB *cbb) {
174 size_t child_start, i, len;
175
176 if (cbb->base == NULL) {
177 return 0;
178 }
179
180 if (cbb->child == NULL || cbb->pending_len_len == 0) {
181 return 1;
182 }
183
184 child_start = cbb->offset + cbb->pending_len_len;
185
186 if (!CBB_flush(cbb->child) ||
187 child_start < cbb->offset ||
188 cbb->base->len < child_start) {
189 return 0;
190 }
191
192 len = cbb->base->len - child_start;
193
194 if (cbb->pending_is_asn1) {
195 /* For ASN.1 we assume that we'll only need a single byte for the length.
196 * If that turned out to be incorrect, we have to move the contents along
197 * in order to make space. */
198 size_t len_len;
199 uint8_t initial_length_byte;
200
201 assert (cbb->pending_len_len == 1);
202
203 if (len > 0xfffffffe) {
204 /* Too large. */
205 return 0;
206 } else if (len > 0xffffff) {
207 len_len = 5;
208 initial_length_byte = 0x80 | 4;
209 } else if (len > 0xffff) {
210 len_len = 4;
211 initial_length_byte = 0x80 | 3;
212 } else if (len > 0xff) {
213 len_len = 3;
214 initial_length_byte = 0x80 | 2;
215 } else if (len > 0x7f) {
216 len_len = 2;
217 initial_length_byte = 0x80 | 1;
218 } else {
219 len_len = 1;
220 initial_length_byte = len;
221 len = 0;
222 }
223
224 if (len_len != 1) {
225 /* We need to move the contents along in order to make space. */
226 size_t extra_bytes = len_len - 1;
227 if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) {
228 return 0;
229 }
230 memmove(cbb->base->buf + child_start + extra_bytes,
231 cbb->base->buf + child_start, len);
232 }
233 cbb->base->buf[cbb->offset++] = initial_length_byte;
234 cbb->pending_len_len = len_len - 1;
235 }
236
237 for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) {
238 cbb->base->buf[cbb->offset + i] = len;
239 len >>= 8;
240 }
241 if (len != 0) {
242 return 0;
243 }
244
245 cbb->child->base = NULL;
246 cbb->child = NULL;
247 cbb->pending_len_len = 0;
248 cbb->pending_is_asn1 = 0;
249 cbb->offset = 0;
250
251 return 1;
252}
253
254
255static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents,
256 size_t len_len) {
257 uint8_t *prefix_bytes;
258
259 if (!CBB_flush(cbb)) {
260 return 0;
261 }
262
263 cbb->offset = cbb->base->len;
264 if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len)) {
265 return 0;
266 }
267
268 memset(prefix_bytes, 0, len_len);
269 memset(out_contents, 0, sizeof(CBB));
270 out_contents->base = cbb->base;
271 cbb->child = out_contents;
272 cbb->pending_len_len = len_len;
273 cbb->pending_is_asn1 = 0;
274
275 return 1;
276}
277
278int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) {
279 return cbb_add_length_prefixed(cbb, out_contents, 1);
280}
281
282int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) {
283 return cbb_add_length_prefixed(cbb, out_contents, 2);
284}
285
286int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
287 return cbb_add_length_prefixed(cbb, out_contents, 3);
288}
289
290int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) {
291 if (!CBB_flush(cbb) ||
292 !CBB_add_u8(cbb, tag)) {
293 return 0;
294 }
295
296 cbb->offset = cbb->base->len;
297 if (!CBB_add_u8(cbb, 0)) {
298 return 0;
299 }
300
301 memset(out_contents, 0, sizeof(CBB));
302 out_contents->base = cbb->base;
303 cbb->child = out_contents;
304 cbb->pending_len_len = 1;
305 cbb->pending_is_asn1 = 1;
306
307 return 1;
308}
309
310int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) {
311 uint8_t *dest;
312
313 if (!CBB_flush(cbb) ||
314 !cbb_buffer_add(cbb->base, &dest, len)) {
315 return 0;
316 }
317 memcpy(dest, data, len);
318 return 1;
319}
320
321int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len) {
322 if (!CBB_flush(cbb) ||
323 !cbb_buffer_add(cbb->base, out_data, len)) {
324 return 0;
325 }
326 return 1;
327}
328
329int CBB_add_u8(CBB *cbb, uint8_t value) {
330 if (!CBB_flush(cbb)) {
331 return 0;
332 }
333
334 return cbb_buffer_add_u(cbb->base, value, 1);
335}
336
337int CBB_add_u16(CBB *cbb, uint16_t value) {
338 if (!CBB_flush(cbb)) {
339 return 0;
340 }
341
342 return cbb_buffer_add_u(cbb->base, value, 2);
343}
344
345int CBB_add_u24(CBB *cbb, uint32_t value) {
346 if (!CBB_flush(cbb)) {
347 return 0;
348 }
349
350 return cbb_buffer_add_u(cbb->base, value, 3);
351}
352
353int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
354 CBB child;
355 size_t i;
356 int started = 0;
357
358 if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) {
359 return 0;
360 }
361
362 for (i = 0; i < 8; i++) {
363 uint8_t byte = (value >> 8*(7-i)) & 0xff;
364 if (!started) {
365 if (byte == 0) {
366 /* Don't encode leading zeros. */
367 continue;
368 }
369 /* If the high bit is set, add a padding byte to make it
370 * unsigned. */
371 if ((byte & 0x80) && !CBB_add_u8(&child, 0)) {
372 return 0;
373 }
374 started = 1;
375 }
376 if (!CBB_add_u8(&child, byte)) {
377 return 0;
378 }
379 }
380
381 /* 0 is encoded as a single 0, not the empty string. */
382 if (!started && !CBB_add_u8(&child, 0)) {
383 return 0;
384 }
385
386 return CBB_flush(cbb);
387}