• 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/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  
CBS_init(CBS * cbs,const uint8_t * data,size_t len)25  void CBS_init(CBS *cbs, const uint8_t *data, size_t len) {
26    cbs->data = data;
27    cbs->len = len;
28  }
29  
cbs_get(CBS * cbs,const uint8_t ** p,size_t n)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  
CBS_skip(CBS * cbs,size_t len)41  int CBS_skip(CBS *cbs, size_t len) {
42    const uint8_t *dummy;
43    return cbs_get(cbs, &dummy, len);
44  }
45  
CBS_data(const CBS * cbs)46  const uint8_t *CBS_data(const CBS *cbs) {
47    return cbs->data;
48  }
49  
CBS_len(const CBS * cbs)50  size_t CBS_len(const CBS *cbs) {
51    return cbs->len;
52  }
53  
CBS_stow(const CBS * cbs,uint8_t ** out_ptr,size_t * out_len)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  
CBS_strdup(const CBS * cbs,char ** out_ptr)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  
CBS_contains_zero_byte(const CBS * cbs)78  int CBS_contains_zero_byte(const CBS *cbs) {
79    return memchr(cbs->data, 0, cbs->len) != NULL;
80  }
81  
CBS_mem_equal(const CBS * cbs,const uint8_t * data,size_t len)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  
cbs_get_u(CBS * cbs,uint32_t * out,size_t len)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  
CBS_get_u8(CBS * cbs,uint8_t * out)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  
CBS_get_u16(CBS * cbs,uint16_t * out)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  
CBS_get_u24(CBS * cbs,uint32_t * out)123  int CBS_get_u24(CBS *cbs, uint32_t *out) {
124    return cbs_get_u(cbs, out, 3);
125  }
126  
CBS_get_u32(CBS * cbs,uint32_t * out)127  int CBS_get_u32(CBS *cbs, uint32_t *out) {
128    return cbs_get_u(cbs, out, 4);
129  }
130  
CBS_get_bytes(CBS * cbs,CBS * out,size_t len)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  
CBS_copy_bytes(CBS * cbs,uint8_t * out,size_t len)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  
cbs_get_length_prefixed(CBS * cbs,CBS * out,size_t len_len)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  
CBS_get_u8_length_prefixed(CBS * cbs,CBS * out)157  int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) {
158    return cbs_get_length_prefixed(cbs, out, 1);
159  }
160  
CBS_get_u16_length_prefixed(CBS * cbs,CBS * out)161  int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) {
162    return cbs_get_length_prefixed(cbs, out, 2);
163  }
164  
CBS_get_u24_length_prefixed(CBS * cbs,CBS * out)165  int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
166    return cbs_get_length_prefixed(cbs, out, 3);
167  }
168  
cbs_get_any_asn1_element(CBS * cbs,CBS * out,unsigned * out_tag,size_t * out_header_len,int ber_ok)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  
CBS_get_any_asn1_element(CBS * cbs,CBS * out,unsigned * out_tag,size_t * out_header_len)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  
CBS_get_any_ber_asn1_element(CBS * cbs,CBS * out,unsigned * out_tag,size_t * out_header_len)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  
cbs_get_asn1(CBS * cbs,CBS * out,unsigned tag_value,int skip_header)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  
CBS_get_asn1(CBS * cbs,CBS * out,unsigned tag_value)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  
CBS_get_asn1_element(CBS * cbs,CBS * out,unsigned tag_value)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  
CBS_peek_asn1_tag(const CBS * cbs,unsigned tag_value)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  
CBS_get_asn1_uint64(CBS * cbs,uint64_t * out)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  
CBS_get_optional_asn1(CBS * cbs,CBS * out,int * out_present,unsigned tag)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  
CBS_get_optional_asn1_octet_string(CBS * cbs,CBS * out,int * out_present,unsigned tag)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  
CBS_get_optional_asn1_uint64(CBS * cbs,uint64_t * out,unsigned tag,uint64_t default_value)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  
CBS_get_optional_asn1_bool(CBS * cbs,int * out,unsigned tag,int default_value)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