1 /*-
2 * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #pragma once
8
9 #include <sys/param.h>
10
11 #include <assert.h>
12 #include <signal.h>
13 #include <stdbool.h>
14 #ifdef __APPLE__
15 #define __STDC_WANT_LIB_EXT1__ 1 /* memset_s */
16 #endif
17 /* explicit_bzero is in one of these... */
18 #include <string.h>
19 #include <strings.h>
20 #include "libder.h"
21
22 /* FreeBSD's sys/cdefs.h */
23 #ifndef __DECONST
24 #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
25 #endif
26 #ifndef __unused
27 #define __unused __attribute__((__unused__))
28 #endif
29
30 /* FreeBSD's sys/params.h */
31 #ifndef nitems
32 #define nitems(x) (sizeof((x)) / sizeof((x)[0]))
33 #endif
34 #ifndef MIN
35 #define MIN(a,b) (((a)<(b))?(a):(b))
36 #endif
37 #ifndef MAX
38 #define MAX(a,b) (((a)>(b))?(a):(b))
39 #endif
40
41 struct libder_ctx;
42 struct libder_object;
43
44 struct libder_ctx {
45 uint64_t normalize;
46 size_t buffer_size;
47 enum libder_error error;
48 int verbose;
49 bool strict;
50 volatile sig_atomic_t abort;
51 };
52
53 struct libder_tag {
54 union {
55 uint8_t tag_short;
56 uint8_t *tag_long;
57 };
58 size_t tag_size;
59 enum libder_ber_class tag_class;
60 bool tag_constructed;
61 bool tag_encoded;
62 };
63
64 struct libder_object {
65 struct libder_tag *type;
66 size_t length;
67 size_t nchildren;
68 size_t disk_size;
69 uint8_t *payload; /* NULL for sequences */
70 struct libder_object *children;
71 struct libder_object *parent;
72 struct libder_object *next;
73 };
74
75 static inline sig_atomic_t
libder_check_abort(struct libder_ctx * ctx)76 libder_check_abort(struct libder_ctx *ctx)
77 {
78
79 return (ctx->abort);
80 }
81
82 static inline void
libder_clear_abort(struct libder_ctx * ctx)83 libder_clear_abort(struct libder_ctx *ctx)
84 {
85
86 ctx->abort = 1;
87 }
88
89 #define LIBDER_PRIVATE __attribute__((__visibility__("hidden")))
90
91 #define DER_NORMALIZING(ctx, bit) \
92 (((ctx)->normalize & (LIBDER_NORMALIZE_ ## bit)) != 0)
93
94 static inline bool
libder_normalizing_type(const struct libder_ctx * ctx,const struct libder_tag * type)95 libder_normalizing_type(const struct libder_ctx *ctx, const struct libder_tag *type)
96 {
97 uint8_t tagval;
98
99 assert(!type->tag_constructed);
100 assert(!type->tag_encoded);
101 assert(type->tag_class == BC_UNIVERSAL);
102 assert(type->tag_short < 0x1f);
103
104 tagval = type->tag_short;
105 return ((ctx->normalize & LIBDER_NORMALIZE_TYPE_FLAG(tagval)) != 0);
106 }
107
108 /* All of the lower bits set. */
109 #define BER_TYPE_LONG_MASK 0x1f
110
111 /*
112 * Check if the type matches one of our universal types.
113 */
114 static inline bool
libder_type_is(const struct libder_tag * type,uint8_t utype)115 libder_type_is(const struct libder_tag *type, uint8_t utype)
116 {
117
118 if (type->tag_class != BC_UNIVERSAL || type->tag_encoded)
119 return (false);
120 if ((utype & BER_TYPE_CONSTRUCTED_MASK) != type->tag_constructed)
121 return (false);
122
123 utype &= ~BER_TYPE_CONSTRUCTED_MASK;
124 return (utype == type->tag_short);
125 }
126
127 /*
128 * We'll use this one a decent amount, so we'll keep it inline. There's also
129 * an _abi version that we expose as public interface via a 'libder_type_simple'
130 * macro.
131 */
132 #undef libder_type_simple
133
134 static inline uint8_t
libder_type_simple(const struct libder_tag * type)135 libder_type_simple(const struct libder_tag *type)
136 {
137 uint8_t encoded = type->tag_class << 6;
138
139 assert(!type->tag_encoded);
140 if (type->tag_constructed)
141 encoded |= BER_TYPE_CONSTRUCTED_MASK;
142
143 encoded |= type->tag_short;
144 return (encoded);
145 }
146
147 static inline void
libder_bzero(uint8_t * buf,size_t bufsz)148 libder_bzero(uint8_t *buf, size_t bufsz)
149 {
150
151 #ifdef __APPLE__
152 memset_s(buf, bufsz, 0, bufsz);
153 #else
154 explicit_bzero(buf, bufsz);
155 #endif
156 }
157
158 size_t libder_get_buffer_size(struct libder_ctx *);
159 void libder_set_error(struct libder_ctx *, int, const char *, int);
160
161 #define libder_set_error(ctx, error) \
162 libder_set_error((ctx), (error), __FILE__, __LINE__)
163
164 struct libder_object *libder_obj_alloc_internal(struct libder_ctx *,
165 struct libder_tag *, uint8_t *, size_t, uint32_t);
166 #define LDO_OWNTAG 0x0001 /* Object owns passed in tag */
167
168 size_t libder_size_length(size_t);
169 bool libder_is_valid_obj(struct libder_ctx *,
170 const struct libder_tag *, const uint8_t *, size_t, bool);
171 size_t libder_obj_disk_size(struct libder_object *, bool);
172 bool libder_obj_may_coalesce_children(const struct libder_object *);
173 bool libder_obj_coalesce_children(struct libder_object *, struct libder_ctx *);
174 bool libder_obj_normalize(struct libder_object *, struct libder_ctx *);
175
176 struct libder_tag *libder_type_alloc(void);
177 void libder_type_release(struct libder_tag *);
178 void libder_normalize_type(struct libder_ctx *, struct libder_tag *);
179