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 }