xref: /openbsd/lib/libssl/bs_cbs.c (revision cecf84d4)
1 /*	$OpenBSD: bs_cbs.c,v 1.7 2015/04/29 02:11:09 doug Exp $	*/
2 /*
3  * Copyright (c) 2014, Google Inc.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
16 
17 #include <assert.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include <openssl/opensslconf.h>
22 #include <openssl/buffer.h>
23 #include <openssl/crypto.h>
24 
25 #include "bytestring.h"
26 
27 void
28 CBS_init(CBS *cbs, const uint8_t *data, size_t len)
29 {
30 	cbs->data = data;
31 	cbs->len = len;
32 }
33 
34 static int
35 cbs_get(CBS *cbs, const uint8_t **p, size_t n)
36 {
37 	if (cbs->len < n)
38 		return 0;
39 
40 	*p = cbs->data;
41 	cbs->data += n;
42 	cbs->len -= n;
43 	return 1;
44 }
45 
46 int
47 CBS_skip(CBS *cbs, size_t len)
48 {
49 	const uint8_t *dummy;
50 	return cbs_get(cbs, &dummy, len);
51 }
52 
53 const uint8_t *
54 CBS_data(const CBS *cbs)
55 {
56 	return cbs->data;
57 }
58 
59 size_t
60 CBS_len(const CBS *cbs)
61 {
62 	return cbs->len;
63 }
64 
65 int
66 CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len)
67 {
68 	free(*out_ptr);
69 	*out_ptr = NULL;
70 	*out_len = 0;
71 
72 	if (cbs->len == 0)
73 		return 1;
74 
75 	*out_ptr = BUF_memdup(cbs->data, cbs->len);
76 	if (*out_ptr == NULL)
77 		return 0;
78 
79 	*out_len = cbs->len;
80 	return 1;
81 }
82 
83 int
84 CBS_strdup(const CBS *cbs, char **out_ptr)
85 {
86 	free(*out_ptr);
87 	*out_ptr = strndup((const char *)cbs->data, cbs->len);
88 	return (*out_ptr != NULL);
89 }
90 
91 int
92 CBS_contains_zero_byte(const CBS *cbs)
93 {
94 	return memchr(cbs->data, 0, cbs->len) != NULL;
95 }
96 
97 int
98 CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len)
99 {
100 	if (len != cbs->len)
101 		return 0;
102 
103 	return CRYPTO_memcmp(cbs->data, data, len) == 0;
104 }
105 
106 static int
107 cbs_get_u(CBS *cbs, uint32_t *out, size_t len)
108 {
109 	uint32_t result = 0;
110 	size_t i;
111 	const uint8_t *data;
112 
113 	if (len < 1 || len > 4)
114 		return 0;
115 
116 	if (!cbs_get(cbs, &data, len))
117 		return 0;
118 
119 	for (i = 0; i < len; i++) {
120 		result <<= 8;
121 		result |= data[i];
122 	}
123 	*out = result;
124 	return 1;
125 }
126 
127 int
128 CBS_get_u8(CBS *cbs, uint8_t *out)
129 {
130 	const uint8_t *v;
131 
132 	if (!cbs_get(cbs, &v, 1))
133 		return 0;
134 
135 	*out = *v;
136 	return 1;
137 }
138 
139 int
140 CBS_get_u16(CBS *cbs, uint16_t *out)
141 {
142 	uint32_t v;
143 
144 	if (!cbs_get_u(cbs, &v, 2))
145 		return 0;
146 
147 	*out = v;
148 	return 1;
149 }
150 
151 int
152 CBS_get_u24(CBS *cbs, uint32_t *out)
153 {
154 	return cbs_get_u(cbs, out, 3);
155 }
156 
157 int
158 CBS_get_u32(CBS *cbs, uint32_t *out)
159 {
160 	return cbs_get_u(cbs, out, 4);
161 }
162 
163 int
164 CBS_get_bytes(CBS *cbs, CBS *out, size_t len)
165 {
166 	const uint8_t *v;
167 
168 	if (!cbs_get(cbs, &v, len))
169 		return 0;
170 
171 	CBS_init(out, v, len);
172 	return 1;
173 }
174 
175 static int
176 cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len)
177 {
178 	uint32_t len;
179 
180 	if (!cbs_get_u(cbs, &len, len_len))
181 		return 0;
182 
183 	return CBS_get_bytes(cbs, out, len);
184 }
185 
186 int
187 CBS_get_u8_length_prefixed(CBS *cbs, CBS *out)
188 {
189 	return cbs_get_length_prefixed(cbs, out, 1);
190 }
191 
192 int
193 CBS_get_u16_length_prefixed(CBS *cbs, CBS *out)
194 {
195 	return cbs_get_length_prefixed(cbs, out, 2);
196 }
197 
198 int
199 CBS_get_u24_length_prefixed(CBS *cbs, CBS *out)
200 {
201 	return cbs_get_length_prefixed(cbs, out, 3);
202 }
203 
204 int
205 CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
206     size_t *out_header_len)
207 {
208 	uint8_t tag, length_byte;
209 	CBS header = *cbs;
210 	CBS throwaway;
211 
212 	if (out == NULL)
213 		out = &throwaway;
214 
215 	if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte))
216 		return 0;
217 
218 	if ((tag & 0x1f) == 0x1f)
219 		/* Long form tags are not supported. */
220 		return 0;
221 
222 	if (out_tag != NULL)
223 		*out_tag = tag;
224 
225 	size_t len;
226 	if ((length_byte & 0x80) == 0) {
227 		/* Short form length. */
228 		len = ((size_t) length_byte) + 2;
229 		if (out_header_len != NULL)
230 			*out_header_len = 2;
231 
232 	} else {
233 		/* Long form length. */
234 		const size_t num_bytes = length_byte & 0x7f;
235 		uint32_t len32;
236 
237 		if ((tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
238 			/* indefinite length */
239 			if (out_header_len != NULL)
240 				*out_header_len = 2;
241 			return CBS_get_bytes(cbs, out, 2);
242 		}
243 
244 		if (num_bytes == 0 || num_bytes > 4)
245 			return 0;
246 
247 		if (!cbs_get_u(&header, &len32, num_bytes))
248 			return 0;
249 
250 		if (len32 < 128)
251 			/* Length should have used short-form encoding. */
252 			return 0;
253 
254 		if ((len32 >> ((num_bytes - 1) * 8)) == 0)
255 			/* Length should have been at least one byte shorter. */
256 			return 0;
257 
258 		len = len32;
259 		if (len + 2 + num_bytes < len)
260 			/* Overflow. */
261 			return 0;
262 
263 		len += 2 + num_bytes;
264 		if (out_header_len != NULL)
265 			*out_header_len = 2 + num_bytes;
266 	}
267 
268 	return CBS_get_bytes(cbs, out, len);
269 }
270 
271 static int
272 cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, int skip_header)
273 {
274 	size_t header_len;
275 	unsigned tag;
276 	CBS throwaway;
277 
278 	if (out == NULL)
279 		out = &throwaway;
280 
281 	if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
282 	    tag != tag_value || (header_len > 0 &&
283 	    /*
284 	     * This ensures that the tag is either zero length or
285 	     * indefinite-length.
286 	     */
287 	    CBS_len(out) == header_len &&
288 	    CBS_data(out)[header_len - 1] == 0x80))
289 		return 0;
290 
291 	if (skip_header && !CBS_skip(out, header_len)) {
292 		assert(0);
293 		return 0;
294 	}
295 
296 	return 1;
297 }
298 
299 int
300 CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value)
301 {
302 	return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
303 }
304 
305 int
306 CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value)
307 {
308 	return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
309 }
310 
311 int
312 CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value)
313 {
314 	if (CBS_len(cbs) < 1)
315 		return 0;
316 
317 	return CBS_data(cbs)[0] == tag_value;
318 }
319 
320 /* Encoding details are in ASN.1: X.690 section 8.3 */
321 int
322 CBS_get_asn1_uint64(CBS *cbs, uint64_t *out)
323 {
324 	CBS bytes;
325 	const uint8_t *data;
326 	size_t i, len;
327 
328 	if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER))
329 		return 0;
330 
331 	*out = 0;
332 	data = CBS_data(&bytes);
333 	len = CBS_len(&bytes);
334 
335 	if (len == 0)
336 		/* An INTEGER is encoded with at least one content octet. */
337 		return 0;
338 
339 	if ((data[0] & 0x80) != 0)
340 		/* Negative number. */
341 		return 0;
342 
343 	if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0)
344 		/* Violates smallest encoding rule: excessive leading zeros. */
345 		return 0;
346 
347 	for (i = 0; i < len; i++) {
348 		if ((*out >> 56) != 0)
349 			/* Too large to represent as a uint64_t. */
350 			return 0;
351 
352 		*out <<= 8;
353 		*out |= data[i];
354 	}
355 
356 	return 1;
357 }
358 
359 int
360 CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag)
361 {
362 	if (CBS_peek_asn1_tag(cbs, tag)) {
363 		if (!CBS_get_asn1(cbs, out, tag))
364 			return 0;
365 
366 		*out_present = 1;
367 	} else {
368 		*out_present = 0;
369 	}
370 	return 1;
371 }
372 
373 int
374 CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
375     unsigned tag)
376 {
377 	CBS child;
378 	int present;
379 
380 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
381 		return 0;
382 
383 	if (present) {
384 		if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
385 		    CBS_len(&child) != 0)
386 			return 0;
387 	} else {
388 		CBS_init(out, NULL, 0);
389 	}
390 	if (out_present)
391 		*out_present = present;
392 
393 	return 1;
394 }
395 
396 int
397 CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
398     uint64_t default_value)
399 {
400 	CBS child;
401 	int present;
402 
403 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
404 		return 0;
405 
406 	if (present) {
407 		if (!CBS_get_asn1_uint64(&child, out) ||
408 		    CBS_len(&child) != 0)
409 			return 0;
410 	} else {
411 		*out = default_value;
412 	}
413 	return 1;
414 }
415 
416 int
417 CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, int default_value)
418 {
419 	CBS child, child2;
420 	int present;
421 
422 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
423 		return 0;
424 
425 	if (present) {
426 		uint8_t boolean;
427 
428 		if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
429 		    CBS_len(&child2) != 1 || CBS_len(&child) != 0)
430 			return 0;
431 
432 		boolean = CBS_data(&child2)[0];
433 		if (boolean == 0)
434 			*out = 0;
435 		else if (boolean == 0xff)
436 			*out = 1;
437 		else
438 			return 0;
439 
440 	} else {
441 		*out = default_value;
442 	}
443 	return 1;
444 }
445