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