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/buf.h>
     16 #include <openssl/mem.h>
     17 #include <openssl/bytestring.h>
     18 
     19 #include <assert.h>
     20 #include <string.h>
     21 
     22 #include "internal.h"
     23 
     24 
     25 void CBS_init(CBS *cbs, const uint8_t *data, size_t len) {
     26   cbs->data = data;
     27   cbs->len = len;
     28 }
     29 
     30 static int cbs_get(CBS *cbs, const uint8_t **p, size_t n) {
     31   if (cbs->len < n) {
     32     return 0;
     33   }
     34 
     35   *p = cbs->data;
     36   cbs->data += n;
     37   cbs->len -= n;
     38   return 1;
     39 }
     40 
     41 int CBS_skip(CBS *cbs, size_t len) {
     42   const uint8_t *dummy;
     43   return cbs_get(cbs, &dummy, len);
     44 }
     45 
     46 const uint8_t *CBS_data(const CBS *cbs) {
     47   return cbs->data;
     48 }
     49 
     50 size_t CBS_len(const CBS *cbs) {
     51   return cbs->len;
     52 }
     53 
     54 int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) {
     55   OPENSSL_free(*out_ptr);
     56   *out_ptr = NULL;
     57   *out_len = 0;
     58 
     59   if (cbs->len == 0) {
     60     return 1;
     61   }
     62   *out_ptr = BUF_memdup(cbs->data, cbs->len);
     63   if (*out_ptr == NULL) {
     64     return 0;
     65   }
     66   *out_len = cbs->len;
     67   return 1;
     68 }
     69 
     70 int CBS_strdup(const CBS *cbs, char **out_ptr) {
     71   if (*out_ptr != NULL) {
     72     OPENSSL_free(*out_ptr);
     73   }
     74   *out_ptr = BUF_strndup((const char*)cbs->data, cbs->len);
     75   return (*out_ptr != NULL);
     76 }
     77 
     78 int CBS_contains_zero_byte(const CBS *cbs) {
     79   return memchr(cbs->data, 0, cbs->len) != NULL;
     80 }
     81 
     82 int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) {
     83   if (len != cbs->len) {
     84     return 0;
     85   }
     86   return CRYPTO_memcmp(cbs->data, data, len) == 0;
     87 }
     88 
     89 static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) {
     90   uint32_t result = 0;
     91   size_t i;
     92   const uint8_t *data;
     93 
     94   if (!cbs_get(cbs, &data, len)) {
     95     return 0;
     96   }
     97   for (i = 0; i < len; i++) {
     98     result <<= 8;
     99     result |= data[i];
    100   }
    101   *out = result;
    102   return 1;
    103 }
    104 
    105 int CBS_get_u8(CBS *cbs, uint8_t *out) {
    106   const uint8_t *v;
    107   if (!cbs_get(cbs, &v, 1)) {
    108     return 0;
    109   }
    110   *out = *v;
    111   return 1;
    112 }
    113 
    114 int CBS_get_u16(CBS *cbs, uint16_t *out) {
    115   uint32_t v;
    116   if (!cbs_get_u(cbs, &v, 2)) {
    117     return 0;
    118   }
    119   *out = v;
    120   return 1;
    121 }
    122 
    123 int CBS_get_u24(CBS *cbs, uint32_t *out) {
    124   return cbs_get_u(cbs, out, 3);
    125 }
    126 
    127 int CBS_get_u32(CBS *cbs, uint32_t *out) {
    128   return cbs_get_u(cbs, out, 4);
    129 }
    130 
    131 int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) {
    132   const uint8_t *v;
    133   if (!cbs_get(cbs, &v, len)) {
    134     return 0;
    135   }
    136   CBS_init(out, v, len);
    137   return 1;
    138 }
    139 
    140 static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) {
    141   uint32_t len;
    142   if (!cbs_get_u(cbs, &len, len_len)) {
    143     return 0;
    144   }
    145   return CBS_get_bytes(cbs, out, len);
    146 }
    147 
    148 int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) {
    149   return cbs_get_length_prefixed(cbs, out, 1);
    150 }
    151 
    152 int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) {
    153   return cbs_get_length_prefixed(cbs, out, 2);
    154 }
    155 
    156 int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
    157   return cbs_get_length_prefixed(cbs, out, 3);
    158 }
    159 
    160 static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
    161                                     size_t *out_header_len, int ber_ok) {
    162   uint8_t tag, length_byte;
    163   CBS header = *cbs;
    164   CBS throwaway;
    165 
    166   if (out == NULL) {
    167     out = &throwaway;
    168   }
    169 
    170   if (!CBS_get_u8(&header, &tag) ||
    171       !CBS_get_u8(&header, &length_byte)) {
    172     return 0;
    173   }
    174 
    175   if ((tag & 0x1f) == 0x1f) {
    176     /* Long form tags are not supported. */
    177     return 0;
    178   }
    179 
    180   if (out_tag != NULL) {
    181     *out_tag = tag;
    182   }
    183 
    184   size_t len;
    185   if ((length_byte & 0x80) == 0) {
    186     /* Short form length. */
    187     len = ((size_t) length_byte) + 2;
    188     if (out_header_len != NULL) {
    189       *out_header_len = 2;
    190     }
    191   } else {
    192     /* Long form length. */
    193     const size_t num_bytes = length_byte & 0x7f;
    194     uint32_t len32;
    195 
    196     if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
    197       /* indefinite length */
    198       if (out_header_len != NULL) {
    199         *out_header_len = 2;
    200       }
    201       return CBS_get_bytes(cbs, out, 2);
    202     }
    203 
    204     if (num_bytes == 0 || num_bytes > 4) {
    205       return 0;
    206     }
    207     if (!cbs_get_u(&header, &len32, num_bytes)) {
    208       return 0;
    209     }
    210     if (len32 < 128) {
    211       /* Length should have used short-form encoding. */
    212       return 0;
    213     }
    214     if ((len32 >> ((num_bytes-1)*8)) == 0) {
    215       /* Length should have been at least one byte shorter. */
    216       return 0;
    217     }
    218     len = len32;
    219     if (len + 2 + num_bytes < len) {
    220       /* Overflow. */
    221       return 0;
    222     }
    223     len += 2 + num_bytes;
    224     if (out_header_len != NULL) {
    225       *out_header_len = 2 + num_bytes;
    226     }
    227   }
    228 
    229   return CBS_get_bytes(cbs, out, len);
    230 }
    231 
    232 int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
    233                                     size_t *out_header_len) {
    234   return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len,
    235                                   0 /* DER only */);
    236 }
    237 
    238 int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
    239                                  size_t *out_header_len) {
    240   return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len,
    241                                   1 /* BER allowed */);
    242 }
    243 
    244 static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value,
    245                         int skip_header) {
    246   size_t header_len;
    247   unsigned tag;
    248   CBS throwaway;
    249 
    250   if (out == NULL) {
    251     out = &throwaway;
    252   }
    253 
    254   if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
    255       tag != tag_value) {
    256     return 0;
    257   }
    258 
    259   if (skip_header && !CBS_skip(out, header_len)) {
    260     assert(0);
    261     return 0;
    262   }
    263 
    264   return 1;
    265 }
    266 
    267 int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) {
    268   return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
    269 }
    270 
    271 int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) {
    272   return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
    273 }
    274 
    275 int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) {
    276   if (CBS_len(cbs) < 1) {
    277     return 0;
    278   }
    279   return CBS_data(cbs)[0] == tag_value;
    280 }
    281 
    282 int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
    283   CBS bytes;
    284   const uint8_t *data;
    285   size_t i, len;
    286 
    287   if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) {
    288     return 0;
    289   }
    290 
    291   *out = 0;
    292   data = CBS_data(&bytes);
    293   len = CBS_len(&bytes);
    294 
    295   if (len == 0) {
    296     /* An INTEGER is encoded with at least one octet. */
    297     return 0;
    298   }
    299 
    300   if ((data[0] & 0x80) != 0) {
    301     /* Negative number. */
    302     return 0;
    303   }
    304 
    305   if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0) {
    306     /* Extra leading zeros. */
    307     return 0;
    308   }
    309 
    310   for (i = 0; i < len; i++) {
    311     if ((*out >> 56) != 0) {
    312       /* Too large to represent as a uint64_t. */
    313       return 0;
    314     }
    315     *out <<= 8;
    316     *out |= data[i];
    317   }
    318 
    319   return 1;
    320 }
    321 
    322 int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
    323   if (CBS_peek_asn1_tag(cbs, tag)) {
    324     if (!CBS_get_asn1(cbs, out, tag)) {
    325       return 0;
    326     }
    327     *out_present = 1;
    328   } else {
    329     *out_present = 0;
    330   }
    331   return 1;
    332 }
    333 
    334 int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
    335                                        unsigned tag) {
    336   CBS child;
    337   int present;
    338   if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
    339     return 0;
    340   }
    341   if (present) {
    342     if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
    343         CBS_len(&child) != 0) {
    344       return 0;
    345     }
    346   } else {
    347     CBS_init(out, NULL, 0);
    348   }
    349   if (out_present) {
    350     *out_present = present;
    351   }
    352   return 1;
    353 }
    354 
    355 int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
    356                                  uint64_t default_value) {
    357   CBS child;
    358   int present;
    359   if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
    360     return 0;
    361   }
    362   if (present) {
    363     if (!CBS_get_asn1_uint64(&child, out) ||
    364         CBS_len(&child) != 0) {
    365       return 0;
    366     }
    367   } else {
    368     *out = default_value;
    369   }
    370   return 1;
    371 }
    372 
    373 int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
    374                                int default_value) {
    375   CBS child, child2;
    376   int present;
    377   if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
    378     return 0;
    379   }
    380   if (present) {
    381     uint8_t boolean;
    382 
    383     if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
    384         CBS_len(&child2) != 1 ||
    385         CBS_len(&child) != 0) {
    386       return 0;
    387     }
    388 
    389     boolean = CBS_data(&child2)[0];
    390     if (boolean == 0) {
    391       *out = 0;
    392     } else if (boolean == 0xff) {
    393       *out = 1;
    394     } else {
    395       return 0;
    396     }
    397   } else {
    398     *out = default_value;
    399   }
    400   return 1;
    401 }
    402