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
CBB_zero(CBB * cbb)23 void CBB_zero(CBB *cbb) {
24 memset(cbb, 0, sizeof(CBB));
25 }
26
cbb_init(CBB * cbb,uint8_t * buf,size_t cap)27 static 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
CBB_init(CBB * cbb,size_t initial_capacity)46 int 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
CBB_init_fixed(CBB * cbb,uint8_t * buf,size_t len)62 int 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
CBB_cleanup(CBB * cbb)73 void 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
cbb_buffer_reserve(struct cbb_buffer_st * base,uint8_t ** out,size_t len)87 static 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
cbb_buffer_add(struct cbb_buffer_st * base,uint8_t ** out,size_t len)128 static 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
cbb_buffer_add_u(struct cbb_buffer_st * base,uint32_t v,size_t len_len)138 static 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
CBB_finish(CBB * cbb,uint8_t ** out_data,size_t * out_len)157 int 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. */
CBB_flush(CBB * cbb)185 int 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
CBB_data(const CBB * cbb)264 const 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
CBB_len(const CBB * cbb)269 size_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
cbb_add_length_prefixed(CBB * cbb,CBB * out_contents,size_t len_len)276 static 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
CBB_add_u8_length_prefixed(CBB * cbb,CBB * out_contents)300 int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) {
301 return cbb_add_length_prefixed(cbb, out_contents, 1);
302 }
303
CBB_add_u16_length_prefixed(CBB * cbb,CBB * out_contents)304 int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) {
305 return cbb_add_length_prefixed(cbb, out_contents, 2);
306 }
307
CBB_add_u24_length_prefixed(CBB * cbb,CBB * out_contents)308 int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
309 return cbb_add_length_prefixed(cbb, out_contents, 3);
310 }
311
CBB_add_asn1(CBB * cbb,CBB * out_contents,uint8_t tag)312 int 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
CBB_add_bytes(CBB * cbb,const uint8_t * data,size_t len)338 int 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
CBB_add_space(CBB * cbb,uint8_t ** out_data,size_t len)349 int 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
CBB_reserve(CBB * cbb,uint8_t ** out_data,size_t len)357 int 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
CBB_did_write(CBB * cbb,size_t len)365 int 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
CBB_add_u8(CBB * cbb,uint8_t value)376 int 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
CBB_add_u16(CBB * cbb,uint16_t value)384 int 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
CBB_add_u24(CBB * cbb,uint32_t value)392 int 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
CBB_discard_child(CBB * cbb)400 void 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
CBB_add_asn1_uint64(CBB * cbb,uint64_t value)411 int 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