xref: /freebsd/contrib/libder/libder/libder_obj.c (revision 35c0a8c449fd2b7f75029ebed5e10852240f0865)
1 /*-
2  * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "libder_private.h"
12 
13 #undef	DER_CHILDREN
14 #undef	DER_NEXT
15 
16 #define	DER_CHILDREN(obj)	((obj)->children)
17 #define	DER_NEXT(obj)		((obj)->next)
18 
19 static uint8_t *
libder_obj_alloc_copy_payload(struct libder_ctx * ctx,const uint8_t * payload_in,size_t length)20 libder_obj_alloc_copy_payload(struct libder_ctx *ctx, const uint8_t *payload_in,
21     size_t length)
22 {
23 	uint8_t *payload;
24 
25 	if ((length == 0 && payload_in != NULL) ||
26 	    (length != 0 && payload_in == NULL)) {
27 		libder_set_error(ctx, LDE_INVAL);
28 		return (NULL);
29 	}
30 
31 	if (length > 0) {
32 		payload = malloc(length);
33 		if (payload == NULL) {
34 			libder_set_error(ctx, LDE_NOMEM);
35 			return (NULL);
36 		}
37 
38 		memcpy(payload, payload_in, length);
39 	} else {
40 		payload = NULL;
41 	}
42 
43 	return (payload);
44 }
45 
46 static bool
libder_obj_alloc_check(struct libder_ctx * ctx,struct libder_tag * type,const uint8_t * payload_in,size_t length)47 libder_obj_alloc_check(struct libder_ctx *ctx, struct libder_tag *type,
48     const uint8_t *payload_in, size_t length)
49 {
50 	/*
51 	 * In addition to our normal constraints, constructed objects coming in
52 	 * from lib users should not have payloads.
53 	 */
54 	if (!libder_is_valid_obj(ctx, type, payload_in, length, false) ||
55 	    (type->tag_constructed && length != 0)) {
56 		libder_set_error(ctx, LDE_BADOBJECT);
57 		return (false);
58 	}
59 
60 	return (true);
61 }
62 
63 struct libder_object *
libder_obj_alloc(struct libder_ctx * ctx,struct libder_tag * type,const uint8_t * payload_in,size_t length)64 libder_obj_alloc(struct libder_ctx *ctx, struct libder_tag *type,
65     const uint8_t *payload_in, size_t length)
66 {
67 	struct libder_object *obj;
68 	uint8_t *payload;
69 
70 	if (!libder_obj_alloc_check(ctx, type, payload_in, length))
71 		return (NULL);
72 
73 	payload = libder_obj_alloc_copy_payload(ctx, payload_in, length);
74 
75 	obj = libder_obj_alloc_internal(ctx, type, payload, length, 0);
76 	if (obj == NULL) {
77 		if (length != 0) {
78 			libder_bzero(payload, length);
79 			free(payload);
80 		}
81 
82 		libder_set_error(ctx, LDE_NOMEM);
83 	}
84 
85 	return (obj);
86 }
87 
88 struct libder_object *
libder_obj_alloc_simple(struct libder_ctx * ctx,uint8_t stype,const uint8_t * payload_in,size_t length)89 libder_obj_alloc_simple(struct libder_ctx *ctx, uint8_t stype,
90     const uint8_t *payload_in, size_t length)
91 {
92 	struct libder_object *obj;
93 	struct libder_tag *type;
94 	uint8_t *payload;
95 
96 	type = libder_type_alloc_simple(ctx, stype);
97 	if (type == NULL)
98 		return (NULL);
99 
100 	if (!libder_obj_alloc_check(ctx, type, payload_in, length)) {
101 		libder_type_free(type);
102 		return (NULL);
103 	}
104 
105 	payload = libder_obj_alloc_copy_payload(ctx, payload_in, length);
106 
107 	obj = libder_obj_alloc_internal(ctx, type, payload, length, LDO_OWNTAG);
108 	if (obj == NULL) {
109 		if (length != 0) {
110 			libder_bzero(payload, length);
111 			free(payload);
112 		}
113 
114 		libder_type_free(type);
115 		libder_set_error(ctx, LDE_NOMEM);
116 	}
117 
118 	return (obj);
119 }
120 
121 /*
122  * Returns an obj on success, NULL if out of memory.  `obj` takes ownership of
123  * the payload on success.
124  */
125 LIBDER_PRIVATE struct libder_object *
libder_obj_alloc_internal(struct libder_ctx * ctx,struct libder_tag * type,uint8_t * payload,size_t length,uint32_t flags)126 libder_obj_alloc_internal(struct libder_ctx *ctx, struct libder_tag *type,
127     uint8_t *payload, size_t length, uint32_t flags)
128 {
129 	struct libder_object *obj;
130 
131 	assert((flags & ~(LDO_OWNTAG)) == 0);
132 
133 	if (length != 0)
134 		assert(payload != NULL);
135 	else
136 		assert(payload == NULL);
137 
138 	obj = malloc(sizeof(*obj));
139 	if (obj == NULL)
140 		return (NULL);
141 
142 	if ((flags & LDO_OWNTAG) != 0) {
143 		obj->type = type;
144 	} else {
145 		/*
146 		 * Deep copies the tag data, so that the caller can predict what
147 		 * it can do with the buffer.
148 		 */
149 		obj->type = libder_type_dup(ctx, type);
150 		if (obj->type == NULL) {
151 			free(obj);
152 			return (NULL);
153 		}
154 	}
155 
156 	obj->length = length;
157 	obj->payload = payload;
158 	obj->children = obj->next = obj->parent = NULL;
159 	obj->nchildren = 0;
160 
161 	return (obj);
162 }
163 
164 LIBDER_PRIVATE size_t
libder_size_length(size_t sz)165 libder_size_length(size_t sz)
166 {
167 	size_t nbytes;
168 
169 	/*
170 	 * With DER, we use the smallest encoding necessary: less than 0x80
171 	 * can be encoded in one byte.
172 	 */
173 	if (sz < 0x80)
174 		return (1);
175 
176 	/*
177 	 * We can support up to 0x7f size bytes, but we don't really have a way
178 	 * to represent that right now.  It's a good thing this function only
179 	 * takes a size_t, otherwise this would be a bit wrong.
180 	 */
181 	for (nbytes = 1; nbytes < sizeof(size_t); nbytes++) {
182 		if ((sz & ~((1ULL << 8 * nbytes) - 1)) == 0)
183 			break;
184 	}
185 
186 	/* Add one for the lead byte describing the length of the length. */
187 	return (nbytes + 1);
188 }
189 
190 /*
191  * Returns the size on-disk.  If an object has children, we encode the size as
192  * the sum of their lengths recursively.  Otherwise, we use the object's size.
193  *
194  * Returns 0 if the object size would overflow a size_t... perhaps we could
195  * lift this restriction later.
196  *
197  * Note that the size of the object will be set/updated to simplify later write
198  * calculations.
199  */
200 LIBDER_PRIVATE size_t
libder_obj_disk_size(struct libder_object * obj,bool include_header)201 libder_obj_disk_size(struct libder_object *obj, bool include_header)
202 {
203 	struct libder_object *walker;
204 	size_t disk_size, header_size;
205 
206 	disk_size = obj->length;
207 	if (obj->children != NULL) {
208 		/* We should have rejected these. */
209 		assert(obj->length == 0);
210 
211 		DER_FOREACH_CHILD(walker, obj) {
212 			size_t child_size;
213 
214 			child_size = libder_obj_disk_size(walker, true);
215 			if (SIZE_MAX - child_size < disk_size)
216 				return (0);	/* Overflow */
217 			disk_size += child_size;
218 		}
219 	}
220 
221 	obj->disk_size = disk_size;
222 
223 	/*
224 	 * Children always include the header above, we only include the header
225 	 * at the root if we're calculating how much space we need in total.
226 	 */
227 	if (include_header) {
228 		/* Size of the length + the tag (arbitrary length) */
229 		header_size = libder_size_length(disk_size) + obj->type->tag_size;
230 		if (obj->type->tag_encoded)
231 			header_size++;	/* Lead byte */
232 		if (SIZE_MAX - header_size < disk_size)
233 			return (0);
234 
235 		disk_size += header_size;
236 	}
237 
238 	return (disk_size);
239 }
240 
241 void
libder_obj_free(struct libder_object * obj)242 libder_obj_free(struct libder_object *obj)
243 {
244 	struct libder_object *child, *tmp;
245 
246 	if (obj == NULL)
247 		return;
248 
249 	DER_FOREACH_CHILD_SAFE(child, obj, tmp)
250 		libder_obj_free(child);
251 
252 	if (obj->payload != NULL) {
253 		libder_bzero(obj->payload, obj->length);
254 		free(obj->payload);
255 	}
256 
257 	libder_type_free(obj->type);
258 	free(obj);
259 }
260 
261 static void
libder_obj_unlink(struct libder_object * obj)262 libder_obj_unlink(struct libder_object *obj)
263 {
264 	struct libder_object *child, *parent, *prev;
265 
266 	parent = obj->parent;
267 	if (parent == NULL)
268 		return;
269 
270 	prev = NULL;
271 	assert(parent->nchildren > 0);
272 	DER_FOREACH_CHILD(child, parent) {
273 		if (child == obj) {
274 			if (prev == NULL)
275 				parent->children = child->next;
276 			else
277 				prev->next = child->next;
278 			parent->nchildren--;
279 			child->parent = NULL;
280 			return;
281 		}
282 
283 		prev = child;
284 	}
285 
286 	assert(0 && "Internal inconsistency: parent set, but child not found");
287 }
288 
289 bool
libder_obj_append(struct libder_object * parent,struct libder_object * child)290 libder_obj_append(struct libder_object *parent, struct libder_object *child)
291 {
292 	struct libder_object *end, *walker;
293 
294 	if (!parent->type->tag_constructed)
295 		return (false);
296 
297 	/* XXX Type check */
298 
299 	if (child->parent != NULL)
300 		libder_obj_unlink(child);
301 
302 	if (parent->nchildren == 0) {
303 		parent->children = child;
304 		parent->nchildren++;
305 		return (true);
306 	}
307 
308 	/* Walk the chain */
309 	DER_FOREACH_CHILD(walker, parent) {
310 		end = walker;
311 	}
312 
313 	assert(end != NULL);
314 	end->next = child;
315 	parent->nchildren++;
316 	child->parent = parent;
317 	return (true);
318 }
319 
320 struct libder_object *
libder_obj_child(const struct libder_object * obj,size_t idx)321 libder_obj_child(const struct libder_object *obj, size_t idx)
322 {
323 	struct libder_object *cur;
324 
325 	DER_FOREACH_CHILD(cur, obj) {
326 		if (idx-- == 0)
327 			return (cur);
328 	}
329 
330 	return (NULL);
331 }
332 
333 struct libder_object *
libder_obj_children(const struct libder_object * obj)334 libder_obj_children(const struct libder_object *obj)
335 {
336 
337 	return (obj->children);
338 }
339 
340 struct libder_object *
libder_obj_next(const struct libder_object * obj)341 libder_obj_next(const struct libder_object *obj)
342 {
343 
344 	return (obj->next);
345 }
346 
347 struct libder_tag *
libder_obj_type(const struct libder_object * obj)348 libder_obj_type(const struct libder_object *obj)
349 {
350 
351 	return (obj->type);
352 }
353 
354 uint8_t
libder_obj_type_simple(const struct libder_object * obj)355 libder_obj_type_simple(const struct libder_object *obj)
356 {
357 	struct libder_tag *type = obj->type;
358 	uint8_t simple = type->tag_class << 6;
359 
360 	if (type->tag_constructed)
361 		simple |= BER_TYPE_CONSTRUCTED_MASK;
362 
363 	if (type->tag_encoded)
364 		simple |= 0x1f;	/* Encode the "long tag" tag. */
365 	else
366 		simple |= type->tag_short;
367 	return (simple);
368 }
369 
370 const uint8_t *
libder_obj_data(const struct libder_object * obj,size_t * osz)371 libder_obj_data(const struct libder_object *obj, size_t *osz)
372 {
373 
374 	if (obj->type->tag_constructed)
375 		return (NULL);
376 
377 	*osz = obj->length;
378 	return (obj->payload);
379 }
380 
381 static const char *
libder_type_name(const struct libder_tag * type)382 libder_type_name(const struct libder_tag *type)
383 {
384 	static char namebuf[128];
385 
386 	if (type->tag_encoded) {
387 		return ("{ ... }");
388 	}
389 
390 	if (type->tag_class != BC_UNIVERSAL)
391 		goto fallback;
392 
393 #define	UTYPE(val)	case val: return (&(#val)[3])
394 	switch (type->tag_short) {
395 	UTYPE(BT_RESERVED);
396 	UTYPE(BT_BOOLEAN);
397 	UTYPE(BT_INTEGER);
398 	UTYPE(BT_BITSTRING);
399 	UTYPE(BT_OCTETSTRING);
400 	UTYPE(BT_NULL);
401 	UTYPE(BT_OID);
402 	UTYPE(BT_OBJDESC);
403 	UTYPE(BT_EXTERNAL);
404 	UTYPE(BT_REAL);
405 	UTYPE(BT_ENUMERATED);
406 	UTYPE(BT_PDV);
407 	UTYPE(BT_UTF8STRING);
408 	UTYPE(BT_RELOID);
409 	UTYPE(BT_NUMERICSTRING);
410 	UTYPE(BT_STRING);
411 	UTYPE(BT_TELEXSTRING);
412 	UTYPE(BT_VIDEOTEXSTRING);
413 	UTYPE(BT_IA5STRING);
414 	UTYPE(BT_UTCTIME);
415 	UTYPE(BT_GENTIME);
416 	UTYPE(BT_GFXSTRING);
417 	UTYPE(BT_VISSTRING);
418 	UTYPE(BT_GENSTRING);
419 	UTYPE(BT_UNIVSTRING);
420 	UTYPE(BT_CHARSTRING);
421 	UTYPE(BT_BMPSTRING);
422 	case BT_SEQUENCE & ~BER_TYPE_CONSTRUCTED_MASK:
423 	case BT_SEQUENCE: return "SEQUENCE";
424 	case BT_SET & ~BER_TYPE_CONSTRUCTED_MASK:
425 	case BT_SET: return "SET";
426 	}
427 
428 fallback:
429 	snprintf(namebuf, sizeof(namebuf), "%.02x", libder_type_simple(type));
430 	return (&namebuf[0]);
431 }
432 
433 static void
libder_obj_dump_internal(const struct libder_object * obj,FILE * fp,int lvl)434 libder_obj_dump_internal(const struct libder_object *obj, FILE *fp, int lvl)
435 {
436 	static char spacer[4096];
437 	const struct libder_object *child;
438 
439 	/* Primitive, goofy, but functional. */
440 	if (spacer[0] == '\0')
441 		memset(spacer, '\t', sizeof(spacer));
442 
443 	if (lvl >= (int)sizeof(spacer)) {
444 		/* Too large, truncate the display. */
445 		fprintf(fp, "%.*s...\n", (int)sizeof(spacer), spacer);
446 		return;
447 	}
448 
449 	if (obj->children == NULL) {
450 		size_t col = lvl * 8;
451 
452 		col += fprintf(fp, "%.*sOBJECT[type=%s, size=%zx]%s",
453 		    lvl, spacer, libder_type_name(obj->type),
454 		    obj->length, obj->length != 0 ? ": " : "");
455 
456 		if (obj->length != 0) {
457 			uint8_t printb;
458 
459 #define	LIBDER_CONTENTS_WRAP	80
460 			for (size_t i = 0; i < obj->length; i++) {
461 				if (col + 3 >= LIBDER_CONTENTS_WRAP) {
462 					fprintf(fp, "\n%.*s    ", lvl, spacer);
463 					col = (lvl * 8) + 4;
464 				}
465 
466 				if (obj->payload == NULL)
467 					printb = 0;
468 				else
469 					printb = obj->payload[i];
470 
471 				col += fprintf(fp, "%.02x ", printb);
472 			}
473 		}
474 
475 		fprintf(fp, "\n");
476 
477 		return;
478 	}
479 
480 	fprintf(fp, "%.*sOBJECT[type=%s]\n", lvl, spacer,
481 	    libder_type_name(obj->type));
482 	DER_FOREACH_CHILD(child, obj)
483 		libder_obj_dump_internal(child, fp, lvl + 1);
484 }
485 
486 void
libder_obj_dump(const struct libder_object * root,FILE * fp)487 libder_obj_dump(const struct libder_object *root, FILE *fp)
488 {
489 
490 	libder_obj_dump_internal(root, fp, 0);
491 }
492 
493 LIBDER_PRIVATE bool
libder_is_valid_obj(struct libder_ctx * ctx,const struct libder_tag * type,const uint8_t * payload,size_t payloadsz,bool varlen)494 libder_is_valid_obj(struct libder_ctx *ctx, const struct libder_tag *type,
495     const uint8_t *payload, size_t payloadsz, bool varlen)
496 {
497 
498 	if (payload != NULL) {
499 		assert(payloadsz > 0);
500 		assert(!varlen);
501 	} else {
502 		assert(payloadsz == 0);
503 	}
504 
505 	/* No rules for non-universal types. */
506 	if (type->tag_class != BC_UNIVERSAL || type->tag_encoded)
507 		return (true);
508 
509 	if (ctx->strict && type->tag_constructed) {
510 		/* Types that don't allow constructed */
511 		switch (libder_type_simple(type) & ~BER_TYPE_CONSTRUCTED_MASK) {
512 		case BT_BOOLEAN:
513 		case BT_INTEGER:
514 		case BT_REAL:
515 		case BT_NULL:
516 			libder_set_error(ctx, LDE_STRICT_PRIMITIVE);
517 			return (false);
518 		default:
519 			break;
520 		}
521 	} else if (ctx->strict) {
522 		/* Types that cannot be primitive */
523 		switch (libder_type_simple(type) | BER_TYPE_CONSTRUCTED_MASK) {
524 		case BT_SEQUENCE:
525 		case BT_SET:
526 			libder_set_error(ctx, LDE_STRICT_CONSTRUCTED);
527 			return (false);
528 		default:
529 			break;
530 		}
531 	}
532 
533 	/* Further validation */
534 	switch (libder_type_simple(type)) {
535 	case BT_BOOLEAN:
536 		if (ctx->strict && payloadsz != 1) {
537 			libder_set_error(ctx, LDE_STRICT_BOOLEAN);
538 			return (false);
539 		}
540 		break;
541 	case BT_NULL:
542 		if (ctx->strict && (payloadsz != 0 || varlen)) {
543 			libder_set_error(ctx, LDE_STRICT_NULL);
544 			return (false);
545 		}
546 		break;
547 	case BT_BITSTRING:	/* Primitive */
548 		/*
549 		 * Bit strings require more invasive parsing later during child
550 		 * coalescing or normalization, so we alway strictly enforce
551 		 * their form.
552 		 */
553 		if (payloadsz == 1 && payload[0] != 0)
554 			return (false);
555 
556 		/* We can't have more than seven unused bits. */
557 		return (payloadsz < 2 || payload[0] < 8);
558 	case BT_RESERVED:
559 		if (payloadsz != 0) {
560 			libder_set_error(ctx, LDE_STRICT_EOC);
561 			return (false);
562 		}
563 		break;
564 	default:
565 		break;
566 	}
567 
568 	return (true);
569 }
570 
571 LIBDER_PRIVATE bool
libder_obj_may_coalesce_children(const struct libder_object * obj)572 libder_obj_may_coalesce_children(const struct libder_object *obj)
573 {
574 
575 	/* No clue about non-universal types. */
576 	if (obj->type->tag_class != BC_UNIVERSAL || obj->type->tag_encoded)
577 		return (false);
578 
579 	/* Constructed types don't have children. */
580 	if (!obj->type->tag_constructed)
581 		return (false);
582 
583 	/* Strip the constructed bit off. */
584 	switch (libder_type_simple(obj->type)) {
585 	case BT_OCTETSTRING:	/* Raw data types */
586 	case BT_BITSTRING:
587 		return (true);
588 	case BT_UTF8STRING:	/* String types */
589 	case BT_NUMERICSTRING:
590 	case BT_STRING:
591 	case BT_TELEXSTRING:
592 	case BT_VIDEOTEXSTRING:
593 	case BT_IA5STRING:
594 	case BT_GFXSTRING:
595 	case BT_VISSTRING:
596 	case BT_GENSTRING:
597 	case BT_UNIVSTRING:
598 	case BT_CHARSTRING:
599 	case BT_BMPSTRING:
600 		return (true);
601 	case BT_UTCTIME:	/* Time types */
602 	case BT_GENTIME:
603 		return (true);
604 	default:
605 		return (false);
606 	}
607 }
608 
609 static size_t
libder_merge_bitstrings(uint8_t * buf,size_t offset,size_t bufsz,const struct libder_object * child)610 libder_merge_bitstrings(uint8_t *buf, size_t offset, size_t bufsz,
611     const struct libder_object *child)
612 {
613 	const uint8_t *rhs = child->payload;
614 	size_t rsz = child->disk_size, startoff = offset;
615 	uint8_t rhsunused, unused;
616 
617 	rhsunused = (rhs != NULL ? rhs[0] : 0);
618 
619 	/* We have no unused bits if the buffer's empty as of yet. */
620 	if (offset == 0)
621 		unused = 0;
622 	else
623 		unused = buf[0];
624 
625 	/* Shave the lead byte off if we have one. */
626 	if (rsz > 1) {
627 		if (rhs != NULL)
628 			rhs++;
629 		rsz--;
630 	}
631 
632 	if (unused == 0) {
633 		size_t extra = 0;
634 
635 		/*
636 		 * In all cases we'll just write the unused byte separately,
637 		 * since we're copying way past it in the common case and can't
638 		 * just overwrite it as part of the memcpy().
639 		 */
640 		if (offset == 0) {
641 			offset = 1;
642 			extra++;
643 		}
644 
645 		assert(rhsunused < 8);
646 		assert(offset + rsz <= bufsz);
647 
648 		buf[0] = rhsunused;
649 		if (rhs == NULL)
650 			memset(&buf[offset], 0, rsz);
651 		else
652 			memcpy(&buf[offset], rhs, rsz);
653 
654 		return (rsz + extra);
655 	}
656 
657 	for (size_t i = 0; i < rsz; i++) {
658 		uint8_t bits, next;
659 
660 		if (rhs == NULL)
661 			next = 0;
662 		else
663 			next = rhs[i];
664 
665 		/* Rotate the leading bits into the byte before it. */
666 		assert(unused < 8);
667 		bits = next >> (8 - unused);
668 		buf[offset - 1] |= bits;
669 
670 		next <<= unused;
671 
672 		/*
673 		 * Copy the new valid bits in; we shift over the old unused
674 		 * amount up until the very last bit, then we have to recalculate
675 		 * because we may be dropping it entirely.
676 		 */
677 		if (i == rsz - 1) {
678 			assert(rhsunused < 8);
679 
680 			/*
681 			 * Figure out how many unused bits we have between the two
682 			 * buffers, sum % 8 is the new # unused bits.  It will be
683 			 * somewhere in the range of [0, 14], and if it's at or
684 			 * higher than a single byte then that's a clear indicator
685 			 * that we shifted some unused bits into the previous byte and
686 			 * can just halt here.
687 			 */
688 			unused += rhsunused;
689 			buf[0] = unused % 8;
690 			if (unused >= 8)
691 				break;
692 		}
693 
694 		assert(offset < bufsz);
695 		buf[offset++] = next;
696 	}
697 
698 	return (offset - startoff);
699 }
700 
701 LIBDER_PRIVATE bool
libder_obj_coalesce_children(struct libder_object * obj,struct libder_ctx * ctx)702 libder_obj_coalesce_children(struct libder_object *obj, struct libder_ctx *ctx)
703 {
704 	struct libder_object *child, *last_child, *tmp;
705 	size_t new_size = 0, offset = 0;
706 	uint8_t *coalesced_data;
707 	uint8_t type;
708 	bool need_payload = false, strict_violation = false;
709 
710 	if (obj->nchildren == 0 || !libder_obj_may_coalesce_children(obj))
711 		return (true);
712 
713 	assert(obj->type->tag_class == BC_UNIVERSAL);
714 	assert(obj->type->tag_constructed);
715 	assert(!obj->type->tag_encoded);
716 	type = obj->type->tag_short;
717 
718 	last_child = NULL;
719 	DER_FOREACH_CHILD(child, obj) {
720 		/* Sanity check and coalesce our children. */
721 		if (child->type->tag_class != BC_UNIVERSAL ||
722 		    child->type->tag_short != obj->type->tag_short) {
723 			libder_set_error(ctx, LDE_COALESCE_BADCHILD);
724 			return (false);
725 		}
726 
727 		/* Recursively coalesce everything. */
728 		if (!libder_obj_coalesce_children(child, ctx))
729 			return (false);
730 
731 		/*
732 		 * The child node will be disappearing anyways, so we stash the
733 		 * disk size sans header in its disk_size to reuse in the later
734 		 * loop.
735 		 */
736 		child->disk_size = libder_obj_disk_size(child, false);
737 
738 		/*
739 		 * We strip the lead byte off of every element, and add it back
740 		 * in pre-allocation.
741 		 */
742 		if (type == BT_BITSTRING && child->disk_size > 1)
743 			child->disk_size--;
744 		if (child->disk_size > 0)
745 			last_child = child;
746 
747 		new_size += child->disk_size;
748 
749 		if (child->payload != NULL)
750 			need_payload = true;
751 	}
752 
753 	if (new_size != 0 && need_payload) {
754 		if (type == BT_BITSTRING)
755 			new_size++;
756 		coalesced_data = malloc(new_size);
757 		if (coalesced_data == NULL) {
758 			libder_set_error(ctx, LDE_NOMEM);
759 			return (false);
760 		}
761 	} else {
762 		/*
763 		 * This would perhaps be a bit weird, but that's normalization
764 		 * for you.  We shouldn't really have a UTF-8 string that's
765 		 * composed of a series of zero-length UTF-8 strings, but
766 		 * weirder things have happened.
767 		 */
768 		coalesced_data = NULL;
769 	}
770 
771 	/* Avoid leaking any children as we coalesce. */
772 	DER_FOREACH_CHILD_SAFE(child, obj, tmp) {
773 		if (child->disk_size != 0)
774 			assert(coalesced_data != NULL || !need_payload);
775 
776 		/*
777 		 * Just free everything when we violate strict rules.
778 		 */
779 		if (strict_violation)
780 			goto violated;
781 
782 		if (child->disk_size != 0 && need_payload) {
783 			assert(coalesced_data != NULL);
784 			assert(offset + child->disk_size <= new_size);
785 
786 			/*
787 			 * Bit strings are special, in that the first byte
788 			 * contains the number of unused bits at the end.  We
789 			 * need to trim that off when concatenating bit strings
790 			 */
791 			if (type == BT_BITSTRING) {
792 				if (ctx->strict && child != last_child &&
793 				    child->disk_size > 1 && child->payload != NULL) {
794 					/*
795 					 * Each child must have a multiple of 8,
796 					 * up until the final one.
797 					 */
798 					if (child->payload[0] != 0) {
799 						libder_set_error(ctx, LDE_STRICT_BITSTRING);
800 						strict_violation = true;
801 						goto violated;
802 					}
803 				}
804 
805 				offset += libder_merge_bitstrings(coalesced_data,
806 				    offset, new_size, child);
807 			} else {
808 				/*
809 				 * Write zeroes out if we don't have a payload.
810 				 */
811 				if (child->payload == NULL) {
812 					memset(&coalesced_data[offset], 0, child->disk_size);
813 					offset += child->disk_size;
814 				} else {
815 					memcpy(&coalesced_data[offset], child->payload,
816 					    child->disk_size);
817 					offset += child->disk_size;
818 				}
819 			}
820 		}
821 
822 violated:
823 		libder_obj_free(child);
824 	}
825 
826 	assert(offset <= new_size);
827 
828 	/* Zap the children, we've absorbed their bodies. */
829 	obj->children = NULL;
830 
831 	if (strict_violation) {
832 		if (coalesced_data != NULL) {
833 			libder_bzero(coalesced_data, offset);
834 			free(coalesced_data);
835 		}
836 
837 		return (false);
838 	}
839 
840 	/* Finally, swap out the payload. */
841 	if (obj->payload != NULL) {
842 		libder_bzero(obj->payload, obj->length);
843 		free(obj->payload);
844 	}
845 
846 	obj->length = offset;
847 	obj->payload = coalesced_data;
848 	obj->type->tag_constructed = false;
849 
850 	return (true);
851 }
852 
853 static bool
libder_obj_normalize_bitstring(struct libder_object * obj)854 libder_obj_normalize_bitstring(struct libder_object *obj)
855 {
856 	uint8_t *payload = obj->payload;
857 	size_t length = obj->length;
858 	uint8_t unused;
859 
860 	if (payload == NULL || length < 2)
861 		return (true);
862 
863 	unused = payload[0];
864 	if (unused == 0)
865 		return (true);
866 
867 	/* Clear the unused bits completely. */
868 	payload[length - 1] &= ~((1 << unused) - 1);
869 	return (true);
870 }
871 
872 static bool
libder_obj_normalize_boolean(struct libder_object * obj)873 libder_obj_normalize_boolean(struct libder_object *obj)
874 {
875 	uint8_t *payload = obj->payload;
876 	size_t length = obj->length;
877 	int sense = 0;
878 
879 	assert(length > 0);
880 
881 	/*
882 	 * Booleans must be collapsed down to a single byte, 0x00 or 0xff,
883 	 * indicating false or true respectively.
884 	 */
885 	if (length == 1 && (payload[0] == 0x00 || payload[0] == 0xff))
886 		return (true);
887 
888 	for (size_t bpos = 0; bpos < length; bpos++) {
889 		sense |= payload[bpos];
890 		if (sense != 0)
891 			break;
892 	}
893 
894 	payload[0] = sense != 0 ? 0xff : 0x00;
895 	obj->length = 1;
896 	return (true);
897 }
898 
899 static bool
libder_obj_normalize_integer(struct libder_object * obj)900 libder_obj_normalize_integer(struct libder_object *obj)
901 {
902 	uint8_t *payload = obj->payload;
903 	size_t length = obj->length;
904 	size_t strip = 0;
905 
906 	/*
907 	 * Strip any leading sign-extended looking bytes, but note that
908 	 * we can't strip a leading byte unless it matches the sign bit
909 	 * on the next byte.
910 	 */
911 	for (size_t bpos = 0; bpos < length - 1; bpos++) {
912 		if (payload[bpos] != 0 && payload[bpos] != 0xff)
913 			break;
914 
915 		if (payload[bpos] == 0xff) {
916 			/* Only if next byte indicates signed. */
917 			if ((payload[bpos + 1] & 0x80) == 0)
918 				break;
919 		} else {
920 			/* Only if next byte indicates unsigned. */
921 			if ((payload[bpos + 1] & 0x80) != 0)
922 				break;
923 		}
924 
925 		strip++;
926 	}
927 
928 	if (strip != 0) {
929 		payload += strip;
930 		length -= strip;
931 
932 		memmove(&obj->payload[0], payload, length);
933 		obj->length = length;
934 	}
935 
936 	return (true);
937 }
938 
939 static int
libder_obj_tag_compare(const struct libder_tag * lhs,const struct libder_tag * rhs)940 libder_obj_tag_compare(const struct libder_tag *lhs, const struct libder_tag *rhs)
941 {
942 	const uint8_t *lbits, *rbits;
943 	size_t delta, end, lsz, rsz;
944 	uint8_t lbyte, rbyte;
945 
946 	/* Highest bits: tag class, libder_ber_class has the same bit ordering. */
947 	if (lhs->tag_class < rhs->tag_class)
948 		return (-1);
949 	if (lhs->tag_class > rhs->tag_class)
950 		return (1);
951 
952 	/* Next bit: constructed vs. primitive */
953 	if (!lhs->tag_constructed && rhs->tag_constructed)
954 		return (-1);
955 	if (lhs->tag_constructed && rhs->tag_constructed)
956 		return (1);
957 
958 	/*
959 	 * Finally: tag data; we can use the size as a first-order heuristic
960 	 * because we store tags in the shortest possible representation.
961 	 */
962 	if (lhs->tag_size < rhs->tag_size)
963 		return (-1);
964 	else if (lhs->tag_size > rhs->tag_size)
965 		return (1);
966 
967 	if (!lhs->tag_encoded) {
968 		lbits = (const void *)&lhs->tag_short;
969 		lsz = sizeof(uint64_t);
970 	} else {
971 		lbits = lhs->tag_long;
972 		lsz = lhs->tag_size;
973 	}
974 
975 	if (!rhs->tag_encoded) {
976 		rbits = (const void *)&rhs->tag_short;
977 		rsz = sizeof(uint64_t);
978 	} else {
979 		rbits = rhs->tag_long;
980 		rsz = rhs->tag_size;
981 	}
982 
983 	delta = 0;
984 	end = MAX(lsz, rsz);
985 	if (lsz > rsz)
986 		delta = lsz - rsz;
987 	else if (lsz < rsz)
988 		delta = rsz - lsz;
989 	for (size_t i = 0; i < end; i++) {
990 		/* Zero-extend the short one the difference. */
991 		if (lsz < rsz && i < delta)
992 			lbyte = 0;
993 		else
994 			lbyte = lbits[i - delta];
995 
996 		if (lsz > rsz && i < delta)
997 			rbyte = 0;
998 		else
999 			rbyte = rbits[i - delta];
1000 
1001 		if (lbyte < rbyte)
1002 			return (-1);
1003 		else if (lbyte > rbyte)
1004 			return (-1);
1005 	}
1006 
1007 	return (0);
1008 }
1009 
1010 /*
1011  * Similar to strcmp(), returns -1, 0, or 1.
1012  */
1013 static int
libder_obj_compare(const struct libder_object * lhs,const struct libder_object * rhs)1014 libder_obj_compare(const struct libder_object *lhs, const struct libder_object *rhs)
1015 {
1016 	size_t end;
1017 	int cmp;
1018 	uint8_t lbyte, rbyte;
1019 
1020 	cmp = libder_obj_tag_compare(lhs->type, rhs->type);
1021 	if (cmp != 0)
1022 		return (cmp);
1023 
1024 	/*
1025 	 * We'll compare up to the longer of the two; the shorter payload is
1026 	 * zero-extended at the end for comparison purposes.
1027 	 */
1028 	end = MAX(lhs->length, rhs->length);
1029 	for (size_t pos = 0; pos < end; pos++) {
1030 		if (lhs->payload != NULL && pos < lhs->length)
1031 			lbyte = lhs->payload[pos];
1032 		else
1033 			lbyte = 0;
1034 		if (rhs->payload != NULL && pos < rhs->length)
1035 			rbyte = rhs->payload[pos];
1036 		else
1037 			rbyte = 0;
1038 
1039 		if (lbyte < rbyte)
1040 			return (-1);
1041 		else if (lbyte > rbyte)
1042 			return (1);
1043 	}
1044 
1045 	return (0);
1046 }
1047 
1048 static int
libder_obj_normalize_set_cmp(const void * lhs_entry,const void * rhs_entry)1049 libder_obj_normalize_set_cmp(const void *lhs_entry, const void *rhs_entry)
1050 {
1051 	const struct libder_object *lhs =
1052 	    *__DECONST(const struct libder_object **, lhs_entry);
1053 	const struct libder_object *rhs =
1054 	    *__DECONST(const struct libder_object **, rhs_entry);
1055 
1056 	return (libder_obj_compare(lhs, rhs));
1057 }
1058 
1059 static bool
libder_obj_normalize_set(struct libder_object * obj,struct libder_ctx * ctx)1060 libder_obj_normalize_set(struct libder_object *obj, struct libder_ctx *ctx)
1061 {
1062 	struct libder_object **sorting;
1063 	struct libder_object *child;
1064 	size_t offset = 0;
1065 
1066 	if (obj->nchildren < 2)
1067 		return (true);
1068 
1069 	/*
1070 	 * Kind of goofy, but we'll just take advantage of a standardized
1071 	 * qsort() rather than rolling our own sort -- we have no idea how large
1072 	 * of a dataset we're working with.
1073 	 */
1074 	sorting = calloc(obj->nchildren, sizeof(*sorting));
1075 	if (sorting == NULL) {
1076 		libder_set_error(ctx, LDE_NOMEM);
1077 		return (false);
1078 	}
1079 
1080 	DER_FOREACH_CHILD(child, obj) {
1081 		sorting[offset++] = child;
1082 	}
1083 
1084 	assert(offset == obj->nchildren);
1085 	qsort(sorting, offset, sizeof(*sorting), libder_obj_normalize_set_cmp);
1086 
1087 	obj->children = sorting[0];
1088 	sorting[offset - 1]->next = NULL;
1089 	for (size_t i = 0; i < offset - 1; i++) {
1090 		sorting[i]->next = sorting[i + 1];
1091 	}
1092 
1093 	free(sorting);
1094 
1095 	return (true);
1096 }
1097 
1098 LIBDER_PRIVATE bool
libder_obj_normalize(struct libder_object * obj,struct libder_ctx * ctx)1099 libder_obj_normalize(struct libder_object *obj, struct libder_ctx *ctx)
1100 {
1101 	uint8_t *payload = obj->payload;
1102 	size_t length = obj->length;
1103 
1104 	if (obj->type->tag_constructed) {
1105 		/*
1106 		 * For constructed types, we'll see if we can coalesce their
1107 		 * children into them, then we'll proceed with whatever normalization
1108 		 * rules we can apply to the children.
1109 		 */
1110 		if (DER_NORMALIZING(ctx, CONSTRUCTED) && !libder_obj_coalesce_children(obj, ctx))
1111 			return (false);
1112 
1113 		/*
1114 		 * We may not be a constructed object anymore after the above coalescing
1115 		 * happened, so we check it again here.  Constructed objects need not go
1116 		 * any further, but the now-primitive coalesced types still need to be
1117 		 * normalized.
1118 		 */
1119 		if (obj->type->tag_constructed) {
1120 			struct libder_object *child;
1121 
1122 			DER_FOREACH_CHILD(child, obj) {
1123 				if (!libder_obj_normalize(child, ctx))
1124 					return (false);
1125 			}
1126 
1127 			/* Sets must be sorted. */
1128 			if (obj->type->tag_short != BT_SET)
1129 				return (true);
1130 
1131 			return (libder_obj_normalize_set(obj, ctx));
1132 		}
1133 	}
1134 
1135 	/* We only have normalization rules for universal types. */
1136 	if (obj->type->tag_class != BC_UNIVERSAL || obj->type->tag_encoded)
1137 		return (true);
1138 
1139 	if (!libder_normalizing_type(ctx, obj->type))
1140 		return (true);
1141 
1142 	/*
1143 	 * We are clear to normalize this object, check for some easy cases that
1144 	 * don't need normalization.
1145 	 */
1146 	switch (libder_type_simple(obj->type)) {
1147 	case BT_BITSTRING:
1148 	case BT_BOOLEAN:
1149 	case BT_INTEGER:
1150 		/*
1151 		 * If we have a zero payload, then we need to encode them as a
1152 		 * single zero byte.
1153 		 */
1154 		if (payload == NULL) {
1155 			if (length != 1)
1156 				obj->length = 1;
1157 
1158 			return (true);
1159 		}
1160 
1161 		break;
1162 	case BT_NULL:
1163 		if (payload != NULL) {
1164 			free(payload);
1165 
1166 			obj->payload = NULL;
1167 			obj->length = 0;
1168 		}
1169 
1170 		return (true);
1171 	default:
1172 		/*
1173 		 * If we don't have a payload, we'll just leave it alone.
1174 		 */
1175 		if (payload == NULL)
1176 			return (true);
1177 		break;
1178 	}
1179 
1180 	switch (libder_type_simple(obj->type)) {
1181 	case BT_BITSTRING:
1182 		return (libder_obj_normalize_bitstring(obj));
1183 	case BT_BOOLEAN:
1184 		return (libder_obj_normalize_boolean(obj));
1185 	case BT_INTEGER:
1186 		return (libder_obj_normalize_integer(obj));
1187 	default:
1188 		break;
1189 	}
1190 
1191 	return (true);
1192 }
1193