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