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
libder_type_simple_abi(const struct libder_tag * type)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 *
libder_type_alloc(void)25 libder_type_alloc(void)
26 {
27
28 return (calloc(1, sizeof(struct libder_tag)));
29 }
30
31 struct libder_tag *
libder_type_dup(struct libder_ctx * ctx,const struct libder_tag * dtype)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 *
libder_type_alloc_simple(struct libder_ctx * ctx,uint8_t typeval)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
libder_type_release(struct libder_tag * type)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
libder_type_free(struct libder_tag * type)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
libder_normalize_type(struct libder_ctx * ctx,struct libder_tag * type)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 }
151