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