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 int CBS_copy_bytes(CBS *cbs, uint8_t *out, size_t len) {
    141   const uint8_t *v;
    142   if (!cbs_get(cbs, &v, len)) {
    143     return 0;
    144   }
    145   memcpy(out, v, len);
    146   return 1;
    147 }
    148 
    149 static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) {
    150   uint32_t len;
    151   if (!cbs_get_u(cbs, &len, len_len)) {
    152     return 0;
    153   }
    154   return CBS_get_bytes(cbs, out, len);
    155 }
    156 
    157 int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) {
    158   return cbs_get_length_prefixed(cbs, out, 1);
    159 }
    160 
    161 int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) {
    162   return cbs_get_length_prefixed(cbs, out, 2);
    163 }
    164 
    165 int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
    166   return cbs_get_length_prefixed(cbs, out, 3);
    167 }
    168 
    169 static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
    170                                     size_t *out_header_len, int ber_ok) {
    171   uint8_t tag, length_byte;
    172   CBS header = *cbs;
    173   CBS throwaway;
    174 
    175   if (out == NULL) {
    176     out = &throwaway;
    177   }
    178 
    179   if (!CBS_get_u8(&header, &tag) ||
    180       !CBS_get_u8(&header, &length_byte)) {
    181     return 0;
    182   }
    183 
    184   if ((tag & 0x1f) == 0x1f) {
    185     /* Long form tags are not supported. */
    186     return 0;
    187   }
    188 
    189   if (out_tag != NULL) {
    190     *out_tag = tag;
    191   }
    192 
    193   size_t len;
    194   if ((length_byte & 0x80) == 0) {
    195     /* Short form length. */
    196     len = ((size_t) length_byte) + 2;
    197     if (out_header_len != NULL) {
    198       *out_header_len = 2;
    199     }
    200   } else {
    201     /* Long form length. */
    202     const size_t num_bytes = length_byte & 0x7f;
    203     uint32_t len32;
    204 
    205     if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
    206       /* indefinite length */
    207       if (out_header_len != NULL) {
    208         *out_header_len = 2;
    209       }
    210       return CBS_get_bytes(cbs, out, 2);
    211     }
    212 
    213     if (num_bytes == 0 || num_bytes > 4) {
    214       return 0;
    215     }
    216     if (!cbs_get_u(&header, &len32, num_bytes)) {
    217       return 0;
    218     }
    219     if (len32 < 128) {
    220       /* Length should have used short-form encoding. */
    221       return 0;
    222     }
    223     if ((len32 >> ((num_bytes-1)*8)) == 0) {
    224       /* Length should have been at least one byte shorter. */
    225       return 0;
    226     }
    227     len = len32;
    228     if (len + 2 + num_bytes < len) {
    229       /* Overflow. */
    230       return 0;
    231     }
    232     len += 2 + num_bytes;
    233     if (out_header_len != NULL) {
    234       *out_header_len = 2 + num_bytes;
    235     }
    236   }
    237 
    238   return CBS_get_bytes(cbs, out, len);
    239 }
    240 
    241 int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
    242                                     size_t *out_header_len) {
    243   return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len,
    244                                   0 /* DER only */);
    245 }
    246 
    247 int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
    248                                  size_t *out_header_len) {
    249   return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len,
    250                                   1 /* BER allowed */);
    251 }
    252 
    253 static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value,
    254                         int skip_header) {
    255   size_t header_len;
    256   unsigned tag;
    257   CBS throwaway;
    258 
    259   if (out == NULL) {
    260     out = &throwaway;
    261   }
    262 
    263   if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
    264       tag != tag_value) {
    265     return 0;
    266   }
    267 
    268   if (skip_header && !CBS_skip(out, header_len)) {
    269     assert(0);
    270     return 0;
    271   }
    272 
    273   return 1;
    274 }
    275 
    276 int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) {
    277   return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
    278 }
    279 
    280 int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) {
    281   return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
    282 }
    283 
    284 int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) {
    285   if (CBS_len(cbs) < 1) {
    286     return 0;
    287   }
    288   return CBS_data(cbs)[0] == tag_value;
    289 }
    290 
    291 int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
    292   CBS bytes;
    293   const uint8_t *data;
    294   size_t i, len;
    295 
    296   if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) {
    297     return 0;
    298   }
    299 
    300   *out = 0;
    301   data = CBS_data(&bytes);
    302   len = CBS_len(&bytes);
    303 
    304   if (len == 0) {
    305     /* An INTEGER is encoded with at least one octet. */
    306     return 0;
    307   }
    308 
    309   if ((data[0] & 0x80) != 0) {
    310     /* Negative number. */
    311     return 0;
    312   }
    313 
    314   if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0) {
    315     /* Extra leading zeros. */
    316     return 0;
    317   }
    318 
    319   for (i = 0; i < len; i++) {
    320     if ((*out >> 56) != 0) {
    321       /* Too large to represent as a uint64_t. */
    322       return 0;
    323     }
    324     *out <<= 8;
    325     *out |= data[i];
    326   }
    327 
    328   return 1;
    329 }
    330 
    331 int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
    332   int present = 0;
    333 
    334   if (CBS_peek_asn1_tag(cbs, tag)) {
    335     if (!CBS_get_asn1(cbs, out, tag)) {
    336       return 0;
    337     }
    338     present = 1;
    339   }
    340 
    341   if (out_present != NULL) {
    342     *out_present = present;
    343   }
    344 
    345   return 1;
    346 }
    347 
    348 int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
    349                                        unsigned tag) {
    350   CBS child;
    351   int present;
    352   if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
    353     return 0;
    354   }
    355   if (present) {
    356     if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
    357         CBS_len(&child) != 0) {
    358       return 0;
    359     }
    360   } else {
    361     CBS_init(out, NULL, 0);
    362   }
    363   if (out_present) {
    364     *out_present = present;
    365   }
    366   return 1;
    367 }
    368 
    369 int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
    370                                  uint64_t default_value) {
    371   CBS child;
    372   int present;
    373   if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
    374     return 0;
    375   }
    376   if (present) {
    377     if (!CBS_get_asn1_uint64(&child, out) ||
    378         CBS_len(&child) != 0) {
    379       return 0;
    380     }
    381   } else {
    382     *out = default_value;
    383   }
    384   return 1;
    385 }
    386 
    387 int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
    388                                int default_value) {
    389   CBS child, child2;
    390   int present;
    391   if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
    392     return 0;
    393   }
    394   if (present) {
    395     uint8_t boolean;
    396 
    397     if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
    398         CBS_len(&child2) != 1 ||
    399         CBS_len(&child) != 0) {
    400       return 0;
    401     }
    402 
    403     boolean = CBS_data(&child2)[0];
    404     if (boolean == 0) {
    405       *out = 0;
    406     } else if (boolean == 0xff) {
    407       *out = 1;
    408     } else {
    409       return 0;
    410     }
    411   } else {
    412     *out = default_value;
    413   }
    414   return 1;
    415 }
    416