Home | History | Annotate | Download | only in bytestring
      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 
     19 #include <openssl/mem.h>
     20 
     21 
     22 static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) {
     23   struct cbb_buffer_st *base;
     24 
     25   base = OPENSSL_malloc(sizeof(struct cbb_buffer_st));
     26   if (base == NULL) {
     27     OPENSSL_free(buf);
     28     return 0;
     29   }
     30 
     31   base->buf = buf;
     32   base->len = 0;
     33   base->cap = cap;
     34   base->can_resize = 1;
     35 
     36   memset(cbb, 0, sizeof(CBB));
     37   cbb->base = base;
     38   cbb->is_top_level = 1;
     39   return 1;
     40 }
     41 
     42 int CBB_init(CBB *cbb, size_t initial_capacity) {
     43   uint8_t *buf;
     44 
     45   buf = OPENSSL_malloc(initial_capacity);
     46   if (initial_capacity > 0 && buf == NULL) {
     47     return 0;
     48   }
     49 
     50   return cbb_init(cbb, buf, initial_capacity);
     51 }
     52 
     53 int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len) {
     54   if (!cbb_init(cbb, buf, len)) {
     55     return 0;
     56   }
     57 
     58   cbb->base->can_resize = 0;
     59   return 1;
     60 }
     61 
     62 void CBB_cleanup(CBB *cbb) {
     63   if (cbb->base) {
     64     if (cbb->base->buf && cbb->base->can_resize) {
     65       OPENSSL_free(cbb->base->buf);
     66     }
     67     OPENSSL_free(cbb->base);
     68   }
     69   cbb->base = NULL;
     70 }
     71 
     72 static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out,
     73                           size_t len) {
     74   size_t newlen;
     75 
     76   if (base == NULL) {
     77     return 0;
     78   }
     79 
     80   newlen = base->len + len;
     81   if (newlen < base->len) {
     82     /* Overflow */
     83     return 0;
     84   }
     85 
     86   if (newlen > base->cap) {
     87     size_t newcap = base->cap * 2;
     88     uint8_t *newbuf;
     89 
     90     if (!base->can_resize) {
     91       return 0;
     92     }
     93 
     94     if (newcap < base->cap || newcap < newlen) {
     95       newcap = newlen;
     96     }
     97     newbuf = OPENSSL_realloc(base->buf, newcap);
     98     if (newbuf == NULL) {
     99       return 0;
    100     }
    101 
    102     base->buf = newbuf;
    103     base->cap = newcap;
    104   }
    105 
    106   if (out) {
    107     *out = base->buf + base->len;
    108   }
    109   base->len = newlen;
    110   return 1;
    111 }
    112 
    113 static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v,
    114                             size_t len_len) {
    115   uint8_t *buf;
    116   size_t i;
    117 
    118   if (len_len == 0) {
    119     return 1;
    120   }
    121   if (!cbb_buffer_add(base, &buf, len_len)) {
    122     return 0;
    123   }
    124 
    125   for (i = len_len - 1; i < len_len; i--) {
    126     buf[i] = v;
    127     v >>= 8;
    128   }
    129   return 1;
    130 }
    131 
    132 int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) {
    133   if (!cbb->is_top_level) {
    134     return 0;
    135   }
    136 
    137   if (!CBB_flush(cbb)) {
    138     return 0;
    139   }
    140 
    141   if (cbb->base->can_resize && (out_data == NULL || out_len == NULL)) {
    142     /* |out_data| and |out_len| can only be NULL if the CBB is fixed. */
    143     return 0;
    144   }
    145 
    146   if (out_data != NULL) {
    147     *out_data = cbb->base->buf;
    148   }
    149   if (out_len != NULL) {
    150     *out_len = cbb->base->len;
    151   }
    152   cbb->base->buf = NULL;
    153   CBB_cleanup(cbb);
    154   return 1;
    155 }
    156 
    157 /* CBB_flush recurses and then writes out any pending length prefix. The
    158  * current length of the underlying base is taken to be the length of the
    159  * length-prefixed data. */
    160 int CBB_flush(CBB *cbb) {
    161   size_t child_start, i, len;
    162 
    163   if (cbb->base == NULL) {
    164     return 0;
    165   }
    166 
    167   if (cbb->child == NULL || cbb->pending_len_len == 0) {
    168     return 1;
    169   }
    170 
    171   child_start = cbb->offset + cbb->pending_len_len;
    172 
    173   if (!CBB_flush(cbb->child) ||
    174       child_start < cbb->offset ||
    175       cbb->base->len < child_start) {
    176     return 0;
    177   }
    178 
    179   len = cbb->base->len - child_start;
    180 
    181   if (cbb->pending_is_asn1) {
    182     /* For ASN.1 we assume that we'll only need a single byte for the length.
    183      * If that turned out to be incorrect, we have to move the contents along
    184      * in order to make space. */
    185     size_t len_len;
    186     uint8_t initial_length_byte;
    187 
    188     assert (cbb->pending_len_len == 1);
    189 
    190     if (len > 0xfffffffe) {
    191       /* Too large. */
    192       return 0;
    193     } else if (len > 0xffffff) {
    194       len_len = 5;
    195       initial_length_byte = 0x80 | 4;
    196     } else if (len > 0xffff) {
    197       len_len = 4;
    198       initial_length_byte = 0x80 | 3;
    199     } else if (len > 0xff) {
    200       len_len = 3;
    201       initial_length_byte = 0x80 | 2;
    202     } else if (len > 0x7f) {
    203       len_len = 2;
    204       initial_length_byte = 0x80 | 1;
    205     } else {
    206       len_len = 1;
    207       initial_length_byte = len;
    208       len = 0;
    209     }
    210 
    211     if (len_len != 1) {
    212       /* We need to move the contents along in order to make space. */
    213       size_t extra_bytes = len_len - 1;
    214       if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) {
    215         return 0;
    216       }
    217       memmove(cbb->base->buf + child_start + extra_bytes,
    218               cbb->base->buf + child_start, len);
    219     }
    220     cbb->base->buf[cbb->offset++] = initial_length_byte;
    221     cbb->pending_len_len = len_len - 1;
    222   }
    223 
    224   for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) {
    225     cbb->base->buf[cbb->offset + i] = len;
    226     len >>= 8;
    227   }
    228   if (len != 0) {
    229     return 0;
    230   }
    231 
    232   cbb->child->base = NULL;
    233   cbb->child = NULL;
    234   cbb->pending_len_len = 0;
    235   cbb->pending_is_asn1 = 0;
    236   cbb->offset = 0;
    237 
    238   return 1;
    239 }
    240 
    241 
    242 static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents,
    243                                    size_t len_len) {
    244   uint8_t *prefix_bytes;
    245 
    246   if (!CBB_flush(cbb)) {
    247     return 0;
    248   }
    249 
    250   cbb->offset = cbb->base->len;
    251   if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len)) {
    252     return 0;
    253   }
    254 
    255   memset(prefix_bytes, 0, len_len);
    256   memset(out_contents, 0, sizeof(CBB));
    257   out_contents->base = cbb->base;
    258   cbb->child = out_contents;
    259   cbb->pending_len_len = len_len;
    260   cbb->pending_is_asn1 = 0;
    261 
    262   return 1;
    263 }
    264 
    265 int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) {
    266   return cbb_add_length_prefixed(cbb, out_contents, 1);
    267 }
    268 
    269 int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) {
    270   return cbb_add_length_prefixed(cbb, out_contents, 2);
    271 }
    272 
    273 int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
    274   return cbb_add_length_prefixed(cbb, out_contents, 3);
    275 }
    276 
    277 int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) {
    278   if (!CBB_flush(cbb) ||
    279       !CBB_add_u8(cbb, tag)) {
    280     return 0;
    281   }
    282 
    283   cbb->offset = cbb->base->len;
    284   if (!CBB_add_u8(cbb, 0)) {
    285     return 0;
    286   }
    287 
    288   memset(out_contents, 0, sizeof(CBB));
    289   out_contents->base = cbb->base;
    290   cbb->child = out_contents;
    291   cbb->pending_len_len = 1;
    292   cbb->pending_is_asn1 = 1;
    293 
    294   return 1;
    295 }
    296 
    297 int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) {
    298   uint8_t *dest;
    299 
    300   if (!CBB_flush(cbb) ||
    301       !cbb_buffer_add(cbb->base, &dest, len)) {
    302     return 0;
    303   }
    304   memcpy(dest, data, len);
    305   return 1;
    306 }
    307 
    308 int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len) {
    309   if (!CBB_flush(cbb) ||
    310       !cbb_buffer_add(cbb->base, out_data, len)) {
    311     return 0;
    312   }
    313   return 1;
    314 }
    315 
    316 int CBB_add_u8(CBB *cbb, uint8_t value) {
    317   if (!CBB_flush(cbb)) {
    318     return 0;
    319   }
    320 
    321   return cbb_buffer_add_u(cbb->base, value, 1);
    322 }
    323 
    324 int CBB_add_u16(CBB *cbb, uint16_t value) {
    325   if (!CBB_flush(cbb)) {
    326     return 0;
    327   }
    328 
    329   return cbb_buffer_add_u(cbb->base, value, 2);
    330 }
    331 
    332 int CBB_add_u24(CBB *cbb, uint32_t value) {
    333   if (!CBB_flush(cbb)) {
    334     return 0;
    335   }
    336 
    337   return cbb_buffer_add_u(cbb->base, value, 3);
    338 }
    339