• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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