/ external / libder / libder / libder_type.c
libder_type.c
  1  /*-
  2   * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org>
  3   *
  4   * SPDX-License-Identifier: BSD-2-Clause
  5   */
  6  
  7  #include <stdint.h>
  8  #include <stdlib.h>
  9  #include <string.h>
 10  
 11  #include "libder_private.h"
 12  
 13  uint8_t
 14  libder_type_simple_abi(const struct libder_tag *type)
 15  {
 16  
 17  	return (libder_type_simple(type));
 18  }
 19  
 20  /*
 21   * We'll likely expose this in the form of libder_type_import(), which validates
 22   * and allocates a tag.
 23   */
 24  LIBDER_PRIVATE struct libder_tag *
 25  libder_type_alloc(void)
 26  {
 27  
 28  	return (calloc(1, sizeof(struct libder_tag)));
 29  }
 30  
 31  struct libder_tag *
 32  libder_type_dup(struct libder_ctx *ctx, const struct libder_tag *dtype)
 33  {
 34  	struct libder_tag *type;
 35  
 36  	type = libder_type_alloc();
 37  	if (type == NULL) {
 38  		libder_set_error(ctx, LDE_NOMEM);
 39  		return (NULL);
 40  	}
 41  
 42  	memcpy(type, dtype, sizeof(*dtype));
 43  
 44  	if (type->tag_encoded) {
 45  		uint8_t *tdata;
 46  
 47  		/* Deep copy the tag data. */
 48  		tdata = malloc(type->tag_size);
 49  		if (tdata == NULL) {
 50  			libder_set_error(ctx, LDE_NOMEM);
 51  
 52  			/*
 53  			 * Don't accidentally free the caller's buffer; it may
 54  			 * be an external user of the API.
 55  			 */
 56  			type->tag_long = NULL;
 57  			type->tag_size = 0;
 58  			libder_type_free(type);
 59  			return (NULL);
 60  		}
 61  
 62  		memcpy(tdata, dtype->tag_long, dtype->tag_size);
 63  		type->tag_long = tdata;
 64  	}
 65  
 66  	return (type);
 67  }
 68  
 69  struct libder_tag *
 70  libder_type_alloc_simple(struct libder_ctx *ctx, uint8_t typeval)
 71  {
 72  	struct libder_tag *type;
 73  
 74  	type = libder_type_alloc();
 75  	if (type == NULL) {
 76  		libder_set_error(ctx, LDE_NOMEM);
 77  		return (NULL);
 78  	}
 79  
 80  	type->tag_size = sizeof(typeval);
 81  	type->tag_class = BER_TYPE_CLASS(typeval);
 82  	type->tag_constructed = BER_TYPE_CONSTRUCTED(typeval);
 83  	type->tag_short = BER_TYPE(typeval);
 84  	return (type);
 85  }
 86  
 87  LIBDER_PRIVATE void
 88  libder_type_release(struct libder_tag *type)
 89  {
 90  
 91  	if (type->tag_encoded) {
 92  		free(type->tag_long);
 93  		type->tag_long = NULL;
 94  
 95  		/*
 96  		 * Leaving type->tag_encoded set in case it helps us catch some
 97  		 * bogus re-use of the type; we'd surface that as a null ptr
 98  		 * deref as they think they should be using tag_long.
 99  		 */
100  	}
101  }
102  
103  void
104  libder_type_free(struct libder_tag *type)
105  {
106  
107  	if (type == NULL)
108  		return;
109  
110  	libder_type_release(type);
111  	free(type);
112  }
113  
114  LIBDER_PRIVATE void
115  libder_normalize_type(struct libder_ctx *ctx, struct libder_tag *type)
116  {
117  	uint8_t tagval;
118  	size_t offset;
119  
120  	if (!type->tag_encoded || !DER_NORMALIZING(ctx, TAGS))
121  		return;
122  
123  	/*
124  	 * Strip any leading 0's off -- not possible in strict mode.
125  	 */
126  	for (offset = 0; offset < type->tag_size - 1; offset++) {
127  		if ((type->tag_long[offset] & 0x7f) != 0)
128  			break;
129  	}
130  
131  	assert(offset == 0 || !ctx->strict);
132  	if (offset != 0) {
133  		type->tag_size -= offset;
134  		memmove(&type->tag_long[0], &type->tag_long[offset],
135  		    type->tag_size);
136  	}
137  
138  	/*
139  	 * We might be able to strip it down to a unencoded tag_short, if only
140  	 * the lower 5 bits are in use.
141  	 */
142  	if (type->tag_size != 1 || (type->tag_long[0] & ~0x1e) != 0)
143  		return;
144  
145  	tagval = type->tag_long[0];
146  
147  	free(type->tag_long);
148  	type->tag_short = tagval;
149  	type->tag_encoded = false;
150  }