1 /* $OpenBSD: bs_cbb.c,v 1.28 2022/07/07 17:12:15 tb 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
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "bytestring.h"
22
23 #define CBB_INITIAL_SIZE 64
24
25 static int
cbb_init(CBB * cbb,uint8_t * buf,size_t cap)26 cbb_init(CBB *cbb, uint8_t *buf, size_t cap)
27 {
28 struct cbb_buffer_st *base;
29
30 if ((base = calloc(1, sizeof(struct cbb_buffer_st))) == NULL)
31 return 0;
32
33 base->buf = buf;
34 base->len = 0;
35 base->cap = cap;
36 base->can_resize = 1;
37
38 cbb->base = base;
39 cbb->is_top_level = 1;
40
41 return 1;
42 }
43
44 int
CBB_init(CBB * cbb,size_t initial_capacity)45 CBB_init(CBB *cbb, size_t initial_capacity)
46 {
47 uint8_t *buf = NULL;
48
49 memset(cbb, 0, sizeof(*cbb));
50
51 if (initial_capacity == 0)
52 initial_capacity = CBB_INITIAL_SIZE;
53
54 if ((buf = calloc(1, initial_capacity)) == NULL)
55 return 0;
56
57 if (!cbb_init(cbb, buf, initial_capacity)) {
58 free(buf);
59 return 0;
60 }
61
62 return 1;
63 }
64
65 int
CBB_init_fixed(CBB * cbb,uint8_t * buf,size_t len)66 CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len)
67 {
68 memset(cbb, 0, sizeof(*cbb));
69
70 if (!cbb_init(cbb, buf, len))
71 return 0;
72
73 cbb->base->can_resize = 0;
74
75 return 1;
76 }
77
78 void
CBB_cleanup(CBB * cbb)79 CBB_cleanup(CBB *cbb)
80 {
81 if (cbb->base) {
82 if (cbb->base->can_resize)
83 freezero(cbb->base->buf, cbb->base->cap);
84 free(cbb->base);
85 }
86 cbb->base = NULL;
87 cbb->child = NULL;
88 }
89
90 static int
cbb_buffer_add(struct cbb_buffer_st * base,uint8_t ** out,size_t len)91 cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, size_t len)
92 {
93 size_t newlen;
94
95 if (base == NULL)
96 return 0;
97
98 newlen = base->len + len;
99 if (newlen < base->len)
100 /* Overflow */
101 return 0;
102
103 if (newlen > base->cap) {
104 size_t newcap = base->cap * 2;
105 uint8_t *newbuf;
106
107 if (!base->can_resize)
108 return 0;
109
110 if (newcap < base->cap || newcap < newlen)
111 newcap = newlen;
112
113 newbuf = recallocarray(base->buf, base->cap, newcap, 1);
114 if (newbuf == NULL)
115 return 0;
116
117 base->buf = newbuf;
118 base->cap = newcap;
119 }
120
121 if (out)
122 *out = base->buf + base->len;
123
124 base->len = newlen;
125 return 1;
126 }
127
128 static int
cbb_add_u(CBB * cbb,uint32_t v,size_t len_len)129 cbb_add_u(CBB *cbb, uint32_t v, size_t len_len)
130 {
131 uint8_t *buf;
132 size_t i;
133
134 if (len_len == 0)
135 return 1;
136
137 if (len_len > 4)
138 return 0;
139
140 if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &buf, len_len))
141 return 0;
142
143 for (i = len_len - 1; i < len_len; i--) {
144 buf[i] = v;
145 v >>= 8;
146 }
147 return 1;
148 }
149
150 int
CBB_finish(CBB * cbb,uint8_t ** out_data,size_t * out_len)151 CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len)
152 {
153 if (!cbb->is_top_level)
154 return 0;
155
156 if (!CBB_flush(cbb))
157 return 0;
158
159 if (cbb->base->can_resize && (out_data == NULL || out_len == NULL))
160 /*
161 * |out_data| and |out_len| can only be NULL if the CBB is
162 * fixed.
163 */
164 return 0;
165
166 if (out_data != NULL && *out_data != NULL)
167 return 0;
168
169 if (out_data != NULL)
170 *out_data = cbb->base->buf;
171
172 if (out_len != NULL)
173 *out_len = cbb->base->len;
174
175 cbb->base->buf = NULL;
176 CBB_cleanup(cbb);
177 return 1;
178 }
179
180 /*
181 * CBB_flush recurses and then writes out any pending length prefix. The current
182 * length of the underlying base is taken to be the length of the
183 * length-prefixed data.
184 */
185 int
CBB_flush(CBB * cbb)186 CBB_flush(CBB *cbb)
187 {
188 size_t child_start, i, len;
189
190 if (cbb->base == NULL)
191 return 0;
192
193 if (cbb->child == NULL || cbb->pending_len_len == 0)
194 return 1;
195
196 child_start = cbb->offset + cbb->pending_len_len;
197
198 if (!CBB_flush(cbb->child) || child_start < cbb->offset ||
199 cbb->base->len < child_start)
200 return 0;
201
202 len = cbb->base->len - child_start;
203
204 if (cbb->pending_is_asn1) {
205 /*
206 * For ASN.1, we assumed that we were using short form which
207 * only requires a single byte for the length octet.
208 *
209 * If it turns out that we need long form, we have to move
210 * the contents along in order to make space for more length
211 * octets.
212 */
213 size_t len_len = 1; /* total number of length octets */
214 uint8_t initial_length_byte;
215
216 /* We already wrote 1 byte for the length. */
217 if (cbb->pending_len_len != 1)
218 return 0;
219
220 /* Check for long form */
221 if (len > 0xfffffffe)
222 return 0; /* 0xffffffff is reserved */
223 else if (len > 0xffffff)
224 len_len = 5;
225 else if (len > 0xffff)
226 len_len = 4;
227 else if (len > 0xff)
228 len_len = 3;
229 else if (len > 0x7f)
230 len_len = 2;
231
232 if (len_len == 1) {
233 /* For short form, the initial byte is the length. */
234 initial_length_byte = len;
235 len = 0;
236
237 } else {
238 /*
239 * For long form, the initial byte is the number of
240 * subsequent length octets (plus bit 8 set).
241 */
242 initial_length_byte = 0x80 | (len_len - 1);
243
244 /*
245 * We need to move the contents along in order to make
246 * space for the long form length octets.
247 */
248 size_t extra_bytes = len_len - 1;
249 if (!cbb_buffer_add(cbb->base, NULL, extra_bytes))
250 return 0;
251
252 memmove(cbb->base->buf + child_start + extra_bytes,
253 cbb->base->buf + child_start, len);
254 }
255 cbb->base->buf[cbb->offset++] = initial_length_byte;
256 cbb->pending_len_len = len_len - 1;
257 }
258
259 for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) {
260 cbb->base->buf[cbb->offset + i] = len;
261 len >>= 8;
262 }
263 if (len != 0)
264 return 0;
265
266 cbb->child->base = NULL;
267 cbb->child = NULL;
268 cbb->pending_len_len = 0;
269 cbb->pending_is_asn1 = 0;
270 cbb->offset = 0;
271
272 return 1;
273 }
274
275 void
CBB_discard_child(CBB * cbb)276 CBB_discard_child(CBB *cbb)
277 {
278 if (cbb->child == NULL)
279 return;
280
281 cbb->base->len = cbb->offset;
282
283 cbb->child->base = NULL;
284 cbb->child = NULL;
285 cbb->pending_len_len = 0;
286 cbb->pending_is_asn1 = 0;
287 cbb->offset = 0;
288 }
289
290 static int
cbb_add_length_prefixed(CBB * cbb,CBB * out_contents,size_t len_len)291 cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, size_t len_len)
292 {
293 uint8_t *prefix_bytes;
294
295 if (!CBB_flush(cbb))
296 return 0;
297
298 cbb->offset = cbb->base->len;
299 if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len))
300 return 0;
301
302 memset(prefix_bytes, 0, len_len);
303 memset(out_contents, 0, sizeof(CBB));
304 out_contents->base = cbb->base;
305 cbb->child = out_contents;
306 cbb->pending_len_len = len_len;
307 cbb->pending_is_asn1 = 0;
308
309 return 1;
310 }
311
312 int
CBB_add_u8_length_prefixed(CBB * cbb,CBB * out_contents)313 CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents)
314 {
315 return cbb_add_length_prefixed(cbb, out_contents, 1);
316 }
317
318 int
CBB_add_u16_length_prefixed(CBB * cbb,CBB * out_contents)319 CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents)
320 {
321 return cbb_add_length_prefixed(cbb, out_contents, 2);
322 }
323
324 int
CBB_add_u24_length_prefixed(CBB * cbb,CBB * out_contents)325 CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents)
326 {
327 return cbb_add_length_prefixed(cbb, out_contents, 3);
328 }
329
330 int
CBB_add_asn1(CBB * cbb,CBB * out_contents,unsigned int tag)331 CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned int tag)
332 {
333 if (tag > UINT8_MAX)
334 return 0;
335
336 /* Long form identifier octets are not supported. */
337 if ((tag & 0x1f) == 0x1f)
338 return 0;
339
340 /* Short-form identifier octet only needs a single byte */
341 if (!CBB_flush(cbb) || !CBB_add_u8(cbb, tag))
342 return 0;
343
344 /*
345 * Add 1 byte to cover the short-form length octet case. If it turns
346 * out we need long-form, it will be extended later.
347 */
348 cbb->offset = cbb->base->len;
349 if (!CBB_add_u8(cbb, 0))
350 return 0;
351
352 memset(out_contents, 0, sizeof(CBB));
353 out_contents->base = cbb->base;
354 cbb->child = out_contents;
355 cbb->pending_len_len = 1;
356 cbb->pending_is_asn1 = 1;
357
358 return 1;
359 }
360
361 int
CBB_add_bytes(CBB * cbb,const uint8_t * data,size_t len)362 CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len)
363 {
364 uint8_t *dest;
365
366 if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &dest, len))
367 return 0;
368
369 memcpy(dest, data, len);
370 return 1;
371 }
372
373 int
CBB_add_space(CBB * cbb,uint8_t ** out_data,size_t len)374 CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len)
375 {
376 if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, out_data, len))
377 return 0;
378
379 memset(*out_data, 0, len);
380 return 1;
381 }
382
383 int
CBB_add_u8(CBB * cbb,size_t value)384 CBB_add_u8(CBB *cbb, size_t value)
385 {
386 if (value > UINT8_MAX)
387 return 0;
388
389 return cbb_add_u(cbb, (uint32_t)value, 1);
390 }
391
392 int
CBB_add_u16(CBB * cbb,size_t value)393 CBB_add_u16(CBB *cbb, size_t value)
394 {
395 if (value > UINT16_MAX)
396 return 0;
397
398 return cbb_add_u(cbb, (uint32_t)value, 2);
399 }
400
401 int
CBB_add_u24(CBB * cbb,size_t value)402 CBB_add_u24(CBB *cbb, size_t value)
403 {
404 if (value > 0xffffffUL)
405 return 0;
406
407 return cbb_add_u(cbb, (uint32_t)value, 3);
408 }
409
410 int
CBB_add_u32(CBB * cbb,size_t value)411 CBB_add_u32(CBB *cbb, size_t value)
412 {
413 if (value > 0xffffffffUL)
414 return 0;
415
416 return cbb_add_u(cbb, (uint32_t)value, 4);
417 }
418
419 int
CBB_add_u64(CBB * cbb,uint64_t value)420 CBB_add_u64(CBB *cbb, uint64_t value)
421 {
422 uint32_t a, b;
423
424 a = value >> 32;
425 b = value & 0xffffffff;
426
427 if (!CBB_add_u32(cbb, a))
428 return 0;
429 return CBB_add_u32(cbb, b);
430 }
431
432 int
CBB_add_asn1_uint64(CBB * cbb,uint64_t value)433 CBB_add_asn1_uint64(CBB *cbb, uint64_t value)
434 {
435 CBB child;
436 size_t i;
437 int started = 0;
438
439 if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER))
440 return 0;
441
442 for (i = 0; i < 8; i++) {
443 uint8_t byte = (value >> 8 * (7 - i)) & 0xff;
444
445 /*
446 * ASN.1 restriction: first 9 bits cannot be all zeroes or
447 * all ones. Since this function only encodes unsigned
448 * integers, the only concerns are not encoding leading
449 * zeros and adding a padding byte if necessary.
450 *
451 * In practice, this means:
452 * 1) Skip leading octets of all zero bits in the value
453 * 2) After skipping the leading zero octets, if the next 9
454 * bits are all ones, add an all zero prefix octet (and
455 * set the high bit of the prefix octet if negative).
456 *
457 * Additionally, for an unsigned value, add an all zero
458 * prefix if the high bit of the first octet would be one.
459 */
460 if (!started) {
461 if (byte == 0)
462 /* Don't encode leading zeros. */
463 continue;
464
465 /*
466 * If the high bit is set, add a padding byte to make it
467 * unsigned.
468 */
469 if ((byte & 0x80) && !CBB_add_u8(&child, 0))
470 return 0;
471
472 started = 1;
473 }
474 if (!CBB_add_u8(&child, byte))
475 return 0;
476 }
477
478 /* 0 is encoded as a single 0, not the empty string. */
479 if (!started && !CBB_add_u8(&child, 0))
480 return 0;
481
482 return CBB_flush(cbb);
483 }
484