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